Skip to content

Commit

Permalink
Merge branch 'add-ssh-key' of https://github.com/helxplatform/gitea-a…
Browse files Browse the repository at this point in the history
…ssist into develop
  • Loading branch information
frostyfan109 committed Jun 4, 2024
2 parents 7270aa4 + 5246b6c commit 2310728
Showing 1 changed file with 202 additions and 1 deletion.
203 changes: 202 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ type RemoveCollaboratorOptions struct {
CollaboratorName string `json:"collaborator_name"`
}

type CreateSSHOptions struct {
KeyName string `json:"key_name"`
Key string `json:"key"`
Username string `json:"username"`
}

type ForkOptions struct {
Owner string `json:"owner"`
NewOwner string `json:"newOwner"`
Expand Down Expand Up @@ -308,7 +314,7 @@ func findForks(repoURL, username, password string) ([]api.Repository, error) {
}

func getRemoteUrlFromRepo(repo *api.Repository) string {
return repo.CloneURL
return repo.SSHURL
}

func getRemoteUrl(giteaBaseURL, adminUsername, adminPassword, owner string, repo string) (string, error) {
Expand Down Expand Up @@ -1184,6 +1190,200 @@ func handleUser(w http.ResponseWriter, r *http.Request) {
}
}

func getSSHKeysForUser(giteaBaseURL, adminUsername, adminPassword, username string) ([]api.PublicKey, error) {
req, err := http.NewRequest("GET", giteaBaseURL+"/users/"+username+"/keys/", nil)
if err != nil {
return nil, err
}

req.Header.Add("Content-Type", "application/json")
req.SetBasicAuth(string(adminUsername), string(adminPassword))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()

bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
log.Printf("Error reading Gitea response %v", err)
return nil, err
}

var publicKeys []api.PublicKey
err = json.Unmarshal(bodyBytes, &publicKeys)
if err != nil {
log.Printf("Error reading Gitea response %v", err)
return nil, err
}

return publicKeys, nil
}

func handleGetUserSSHKeys(w http.ResponseWriter, r *http.Request) {
username := r.URL.Query().Get("username")
if username == "" {
http.Error(w, "Username must be provided to list SSH keys", http.StatusBadRequest)
return
}

if keys, err := getSSHKeysForUser(access.URL, access.Username, access.Password, username); err == nil {
jsonData, _ := json.Marshal(keys)
w.WriteHeader(http.StatusOK)
w.Write([]byte(jsonData))
} else {
http.Error(w, "Failed to list keys", http.StatusBadRequest)
log.Printf("Failed to list keys %v", err)
}
}

func deleteSSHKeyForUser(giteaBaseURL, adminUsername, adminPassword, username, name string) error {
keys, err := getSSHKeysForUser(giteaBaseURL, adminUsername, adminPassword, username)
if err != nil {
return err
}

var id int64 = -1
for _, key := range keys {
if key.Title == name {
id = key.ID
break
}
}
if id == -1 {
return nil
}

url := fmt.Sprintf("%s/admin/users/%s/keys/%d", giteaBaseURL, username, id)
req, err := http.NewRequest("DELETE", url, nil)
if err != nil {
return err
}

req.Header.Add("Content-Type", "application/json")
req.SetBasicAuth(string(adminUsername), string(adminPassword))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusNoContent && resp.StatusCode != 404 {
return fmt.Errorf("HTTP Error: %d", resp.StatusCode)
}

return nil
}

func handleDeleteUserSSHKey(w http.ResponseWriter, r *http.Request) {
keyName := r.URL.Query().Get("key_name")
username := r.URL.Query().Get("username")
if keyName == "" || username == "" {
http.Error(w, "Key name and username must be provided to delete the SSH key", http.StatusBadRequest)
return
}

if err := deleteSSHKeyForUser(access.URL, access.Username, access.Password, username, keyName); err == nil {
w.WriteHeader(http.StatusOK)
w.Write([]byte("Successfully deleted SSH key"))
} else {
http.Error(w, "Key deletion failed", http.StatusBadRequest)
log.Printf("Key deletion failed %v", err)
}
}

func createSSHKeyForUser(giteaBaseURL, adminUsername, adminPassword, username, key, name string) error {
err := deleteSSHKeyForUser(giteaBaseURL, adminUsername, adminPassword, username, name)
if err != nil {
return err
}

data := api.CreateKeyOption{
Key: key,
Title: name,
ReadOnly: true,
}

jsonData, _ := json.Marshal(data)

req, err := http.NewRequest("POST", giteaBaseURL+"/admin/users/"+username+"/keys", bytes.NewBuffer(jsonData))
if err != nil {
return err
}

req.Header.Add("Content-Type", "application/json")
req.SetBasicAuth(string(adminUsername), string(adminPassword))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusCreated {
return fmt.Errorf("HTTP Error: %d", resp.StatusCode)
}

bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
log.Printf("Error reading Gitea response %v", err)
return err
}

var publicKeyResponse api.PublicKey
err = json.Unmarshal(bodyBytes, &publicKeyResponse)
if err != nil {
log.Printf("Error reading Gitea response %v", err)
return err
}

fmt.Println(publicKeyResponse.ID, publicKeyResponse.Key)

return nil
}

func handleCreateUserSSHKey(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
defer r.Body.Close()

if err != nil {
http.Error(w, "Failed reading request body", http.StatusInternalServerError)
return
}

var options CreateSSHOptions
err = json.Unmarshal(body, &options)
if err != nil {
http.Error(w, "Failed parsing request body", http.StatusBadRequest)
return
}

if options.Key == "" || options.KeyName == "" || options.Username == "" {
http.Error(w, "Key, KeyName, and Username must be provided to create the SSH key", http.StatusBadRequest)
return
}

if err := createSSHKeyForUser(access.URL, access.Username, access.Password, options.Username, options.Key, options.KeyName); err == nil {
w.WriteHeader(http.StatusCreated)
w.Write([]byte("Successfully created SSH key"))
} else {
http.Error(w, "Key creation failed", http.StatusBadRequest)
log.Printf("Key creation failed %v", err)
}
}

func handleUserSsh(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
handleGetUserSSHKeys(w, r)
case http.MethodPost:
handleCreateUserSSHKey(w, r)
case http.MethodDelete:
handleDeleteUserSSHKey(w, r)
default:
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
}

func createRepoForUser(giteaBaseURL, adminUsername, adminPassword, username, name, description string, private bool) (*api.Repository, error) {
data := api.CreateRepoOption{
Name: name,
Expand Down Expand Up @@ -2006,6 +2206,7 @@ func main() {
r := mux.NewRouter()
r.HandleFunc("/onPush", webhookHandler)
r.HandleFunc("/users", handleUser)
r.HandleFunc("/users/ssh", handleUserSsh)
r.HandleFunc("/repos", handleRepo)
r.HandleFunc("/repos/collaborators", handleRepoCollaborator)
r.HandleFunc("/repos/modify", handleModifyRepoFiles).Methods("POST")
Expand Down

0 comments on commit 2310728

Please sign in to comment.