diff options
author | zeripath <art27@cantab.net> | 2019-10-16 14:42:42 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-10-16 14:42:42 +0100 |
commit | fcb535c5c3b6b782d9242028fed4cd8c027c4e41 (patch) | |
tree | 49c49fd1f040b9dcd600ec8e381df80532bc2701 /routers/api | |
parent | 1b72690cb82302b24f41d2beaa5df5592709f4d3 (diff) | |
download | gitea-fcb535c5c3b6b782d9242028fed4cd8c027c4e41.tar.gz gitea-fcb535c5c3b6b782d9242028fed4cd8c027c4e41.zip |
Sign merges, CRUD, Wiki and Repository initialisation with gpg key (#7631)
This PR fixes #7598 by providing a configurable way of signing commits across the Gitea instance. Per repository configurability and import/generation of trusted secure keys is not provided by this PR - from a security PoV that's probably impossible to do properly. Similarly web-signing, that is asking the user to sign something, is not implemented - this could be done at a later stage however.
## Features
- [x] If commit.gpgsign is set in .gitconfig sign commits and files created through repofiles. (merges should already have been signed.)
- [x] Verify commits signed with the default gpg as valid
- [x] Signer, Committer and Author can all be different
- [x] Allow signer to be arbitrarily different - We still require the key to have an activated email on Gitea. A more complete implementation would be to use a keyserver and mark external-or-unactivated with an "unknown" trust level icon.
- [x] Add a signing-key.gpg endpoint to get the default gpg pub key if available
- Rather than add a fake web-flow user I've added this as an endpoint on /api/v1/signing-key.gpg
- [x] Try to match the default key with a user on gitea - this is done at verification time
- [x] Make things configurable?
- app.ini configuration done
- [x] when checking commits are signed need to check if they're actually verifiable too
- [x] Add documentation
I have decided that adjusting the docker to create a default gpg key is not the correct thing to do and therefore have not implemented this.
Diffstat (limited to 'routers/api')
-rw-r--r-- | routers/api/v1/api.go | 2 | ||||
-rw-r--r-- | routers/api/v1/convert/convert.go | 21 | ||||
-rw-r--r-- | routers/api/v1/misc/signing.go | 62 |
3 files changed, 77 insertions, 8 deletions
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 04ff91fbbf..f8ab9025b7 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -507,6 +507,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Get("/swagger", misc.Swagger) } m.Get("/version", misc.Version) + m.Get("/signing-key.gpg", misc.SigningKey) m.Post("/markdown", bind(api.MarkdownOption{}), misc.Markdown) m.Post("/markdown/raw", misc.MarkdownRaw) @@ -771,6 +772,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Delete("", bind(api.DeleteFileOptions{}), repo.DeleteFile) }, reqRepoWriter(models.UnitTypeCode), reqToken()) }, reqRepoReader(models.UnitTypeCode)) + m.Get("/signing-key.gpg", misc.SigningKey) m.Group("/topics", func() { m.Combo("").Get(repo.ListTopics). Put(reqToken(), reqAdmin(), bind(api.RepoTopicOptions{}), repo.UpdateTopics) diff --git a/routers/api/v1/convert/convert.go b/routers/api/v1/convert/convert.go index e0e7f609c7..0262051390 100644 --- a/routers/api/v1/convert/convert.go +++ b/routers/api/v1/convert/convert.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" @@ -84,17 +85,21 @@ func ToCommit(repo *models.Repository, c *git.Commit) *api.PayloadCommit { // ToVerification convert a git.Commit.Signature to an api.PayloadCommitVerification func ToVerification(c *git.Commit) *api.PayloadCommitVerification { verif := models.ParseCommitWithSignature(c) - var signature, payload string + commitVerification := &api.PayloadCommitVerification{ + Verified: verif.Verified, + Reason: verif.Reason, + } if c.Signature != nil { - signature = c.Signature.Signature - payload = c.Signature.Payload + commitVerification.Signature = c.Signature.Signature + commitVerification.Payload = c.Signature.Payload } - return &api.PayloadCommitVerification{ - Verified: verif.Verified, - Reason: verif.Reason, - Signature: signature, - Payload: payload, + if verif.SigningUser != nil { + commitVerification.Signer = &structs.PayloadUser{ + Name: verif.SigningUser.Name, + Email: verif.SigningUser.Email, + } } + return commitVerification } // ToPublicKey convert models.PublicKey to api.PublicKey diff --git a/routers/api/v1/misc/signing.go b/routers/api/v1/misc/signing.go new file mode 100644 index 0000000000..f5428670af --- /dev/null +++ b/routers/api/v1/misc/signing.go @@ -0,0 +1,62 @@ +package misc + +import ( + "fmt" + "net/http" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/log" +) + +// SigningKey returns the public key of the default signing key if it exists +func SigningKey(ctx *context.Context) { + // swagger:operation GET /signing-key.gpg miscellaneous getSigningKey + // --- + // summary: Get default signing-key.gpg + // produces: + // - text/plain + // responses: + // "200": + // description: "GPG armored public key" + // schema: + // type: string + + // swagger:operation GET /repos/{owner}/{repo}/signing-key.gpg repository repoSigningKey + // --- + // summary: Get signing-key.gpg for given repository + // produces: + // - text/plain + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // responses: + // "200": + // description: "GPG armored public key" + // schema: + // type: string + + path := "" + if ctx.Repo != nil && ctx.Repo.Repository != nil { + path = ctx.Repo.Repository.RepoPath() + } + + content, err := models.PublicSigningKey(path) + if err != nil { + ctx.ServerError("gpg export", err) + return + } + _, err = ctx.Write([]byte(content)) + if err != nil { + log.Error("Error writing key content %v", err) + ctx.Error(http.StatusInternalServerError, fmt.Sprintf("%v", err)) + } +} |