From ba6e1490c3b9cff16f534103b24c693ef6ed631e Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Tue, 11 Apr 2023 13:11:14 +0200 Subject: [PATCH] Implement SSH signing retrieval --- gitlab.go | 57 +++++++++++++++++++++++++++++++++++++++++++++++-------- keys.go | 38 +++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 8 deletions(-) diff --git a/gitlab.go b/gitlab.go index d97653a..9497e37 100644 --- a/gitlab.go +++ b/gitlab.go @@ -170,11 +170,13 @@ type GitLabUser struct { Username string Name string State string + Email string } type GitLabUserKey struct { - ID int - Key string + ID int + Key string + UsageType string `json:"usage_type"` } type GitLabRepository struct { @@ -269,7 +271,7 @@ func GitLab_getUsersRepositories(c context.Context, u *User) ([]*GitLabRepositor return repositories, err } -func GitLab_getUserId(c context.Context, u *User) (int, error) { +func GitLab_getUser(c context.Context, u *User) (*GitLabUser, error) { client := gitlaboauth2Config.Client(c, gitlabToken()) val := url.Values{} @@ -277,26 +279,35 @@ func GitLab_getUserId(c context.Context, u *User) (int, error) { req, err := http.NewRequest("GET", gitlabBaseURL+fmt.Sprintf("/api/v4/users?%s", val.Encode()), nil) if err != nil { - return 0, err + return nil, err } resp, err := client.Do(req) if err != nil { - return 0, err + return nil, err } if resp.StatusCode != http.StatusOK { - return 0, fmt.Errorf("Bad status code from the API") + return nil, fmt.Errorf("Bad status code from the API") } var users []*GitLabUser err = json.NewDecoder(resp.Body).Decode(&users) if len(users) == 0 { - return 0, fmt.Errorf("Login not found in GitLab") + return nil, fmt.Errorf("Login not found in GitLab") } - return users[0].ID, nil + return users[0], nil +} + +func GitLab_getUserId(c context.Context, u *User) (int, error) { + user, err := GitLab_getUser(c, u) + if err != nil { + return 0, err + } + + return user.ID, nil } func GitLab_getUserPGPKeys(c context.Context, u *User) ([]byte, error) { @@ -334,3 +345,33 @@ func GitLab_getUserPGPKeys(c context.Context, u *User) ([]byte, error) { return b.Bytes(), nil } + +func GitLab_getUserSSHKeys(c context.Context, u *User) ([]*GitLabUserKey, error) { + userid, err := GitLab_getUserId(c, u) + if err != nil { + return nil, err + } + + client := gitlaboauth2Config.Client(c, gitlabToken()) + + req, err := http.NewRequest("GET", gitlabBaseURL+fmt.Sprintf("/api/v4/users/%d/keys", userid), nil) + if err != nil { + return nil, err + } + + resp, err := client.Do(req) + if err != nil { + return nil, err + } + + if resp.StatusCode != http.StatusOK { + rep, _ := ioutil.ReadAll(resp.Body) + log.Printf("%d %s", resp.StatusCode, rep) + return nil, fmt.Errorf("Bad status code from the API") + } + + var keys []*GitLabUserKey + err = json.NewDecoder(resp.Body).Decode(&keys) + + return keys, err +} diff --git a/keys.go b/keys.go index 9db04d6..1fee668 100644 --- a/keys.go +++ b/keys.go @@ -50,6 +50,44 @@ func declareAPIKeysRoutes(router *gin.RouterGroup) { c.Data(http.StatusOK, "application/pgp-keys", ret) }) + + usersRoutes.GET("/allowed_signers", func(c *gin.Context) { + var u *User + if user, ok := c.Get("user"); ok { + u = user.(*User) + } else { + u = c.MustGet("LoggedUser").(*User) + } + + user, err := GitLab_getUser(c.Request.Context(), u) + if err != nil { + log.Println("Unable to GitLab_getUser:", err) + c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Unable to retrieve your GitLab user. Please try again in a few moment."}) + return + } + + keys, err := GitLab_getUserSSHKeys(c.Request.Context(), u) + if err != nil { + log.Println("Unable to GitLab_getUserSSHKeys:", err) + c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "Unable to retrieve your keys from GitLab. Please try again in a few moment."}) + return + } + + var ret string + for _, k := range keys { + if k.UsageType != "auth_and_signing" && k.UsageType != "signing" { + continue + } + + if len(user.Email) > 0 { + ret += fmt.Sprintf("%s %s\n", user.Email, k.Key) + } else { + ret += fmt.Sprintf("*@epita.fr %s\n", k.Key) + } + } + + c.Data(http.StatusOK, "text/plain", []byte(ret)) + }) } func declareAPIAuthKeysRoutes(router *gin.RouterGroup) {