You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

341 lines
11 KiB

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.
4 years ago
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.
4 years ago
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.
4 years ago
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.
4 years ago
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.
4 years ago
Add API endpoint for accessing repo topics (#7963) * Create API endpoints for repo topics. Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Generate swagger Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Add documentation to functions Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Grammar fix Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Fix function comment Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Can't use FindTopics when looking for a single repo topic, as it doesnt use exact match Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Add PUT ​/repos​/{owner}​/{repo}​/topics and remove GET ​/repos​/{owner}​/{repo}​/topics * Ignore if topic is sent twice in same request, refactoring. Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Fix topic dropdown with api changes. Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Style fix Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Update API documentation Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Better way to handle duplicate topics in slice Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Make response element TopicName an array of strings, instead of using an array of TopicName Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Add test cases for API Repo Topics. Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Fix format of tests Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Fix comments Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Fix unit tests after adding some more topics to the test fixture. Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Update models/topic.go Limit multiple if else if ... Co-Authored-By: Antoine GIRARD <sapk@users.noreply.github.com> * Engine as first parameter in function Co-Authored-By: Antoine GIRARD <sapk@users.noreply.github.com> * Replace magic numbers with http status code constants. Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Fix variable scope Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Test one read with login and one with token Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Add some more tests Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Apply suggestions from code review Use empty struct for efficiency Co-Authored-By: Lauris BH <lauris@nix.lv> * Add test case to check access for user with write access Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Fix access, repo admin required to change topics Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Correct first test to be without token Signed-off-by: David Svantesson <davidsvantesson@gmail.com> * Any repo reader should be able to access topics. * No need for string pointer Signed-off-by: David Svantesson <davidsvantesson@gmail.com>
4 years ago
  1. // Copyright 2015 The Gogs Authors. All rights reserved.
  2. // Copyright 2018 The Gitea Authors. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package convert
  6. import (
  7. "fmt"
  8. "code.gitea.io/gitea/models"
  9. "code.gitea.io/gitea/modules/git"
  10. "code.gitea.io/gitea/modules/log"
  11. "code.gitea.io/gitea/modules/structs"
  12. api "code.gitea.io/gitea/modules/structs"
  13. "code.gitea.io/gitea/modules/util"
  14. "code.gitea.io/gitea/modules/webhook"
  15. "github.com/unknwon/com"
  16. )
  17. // ToEmail convert models.EmailAddress to api.Email
  18. func ToEmail(email *models.EmailAddress) *api.Email {
  19. return &api.Email{
  20. Email: email.Email,
  21. Verified: email.IsActivated,
  22. Primary: email.IsPrimary,
  23. }
  24. }
  25. // ToBranch convert a git.Commit and git.Branch to an api.Branch
  26. func ToBranch(repo *models.Repository, b *git.Branch, c *git.Commit, bp *models.ProtectedBranch, user *models.User, isRepoAdmin bool) (*api.Branch, error) {
  27. if bp == nil {
  28. var hasPerm bool
  29. var err error
  30. if user != nil {
  31. hasPerm, err = models.HasAccessUnit(user, repo, models.UnitTypeCode, models.AccessModeWrite)
  32. if err != nil {
  33. return nil, err
  34. }
  35. }
  36. return &api.Branch{
  37. Name: b.Name,
  38. Commit: ToPayloadCommit(repo, c),
  39. Protected: false,
  40. RequiredApprovals: 0,
  41. EnableStatusCheck: false,
  42. StatusCheckContexts: []string{},
  43. UserCanPush: hasPerm,
  44. UserCanMerge: hasPerm,
  45. }, nil
  46. }
  47. branch := &api.Branch{
  48. Name: b.Name,
  49. Commit: ToPayloadCommit(repo, c),
  50. Protected: true,
  51. RequiredApprovals: bp.RequiredApprovals,
  52. EnableStatusCheck: bp.EnableStatusCheck,
  53. StatusCheckContexts: bp.StatusCheckContexts,
  54. }
  55. if isRepoAdmin {
  56. branch.EffectiveBranchProtectionName = bp.BranchName
  57. }
  58. if user != nil {
  59. permission, err := models.GetUserRepoPermission(repo, user)
  60. if err != nil {
  61. return nil, err
  62. }
  63. branch.UserCanPush = bp.CanUserPush(user.ID)
  64. branch.UserCanMerge = bp.IsUserMergeWhitelisted(user.ID, permission)
  65. }
  66. return branch, nil
  67. }
  68. // ToBranchProtection convert a ProtectedBranch to api.BranchProtection
  69. func ToBranchProtection(bp *models.ProtectedBranch) *api.BranchProtection {
  70. pushWhitelistUsernames, err := models.GetUserNamesByIDs(bp.WhitelistUserIDs)
  71. if err != nil {
  72. log.Error("GetUserNamesByIDs (WhitelistUserIDs): %v", err)
  73. }
  74. mergeWhitelistUsernames, err := models.GetUserNamesByIDs(bp.MergeWhitelistUserIDs)
  75. if err != nil {
  76. log.Error("GetUserNamesByIDs (MergeWhitelistUserIDs): %v", err)
  77. }
  78. approvalsWhitelistUsernames, err := models.GetUserNamesByIDs(bp.ApprovalsWhitelistUserIDs)
  79. if err != nil {
  80. log.Error("GetUserNamesByIDs (ApprovalsWhitelistUserIDs): %v", err)
  81. }
  82. pushWhitelistTeams, err := models.GetTeamNamesByID(bp.WhitelistTeamIDs)
  83. if err != nil {
  84. log.Error("GetTeamNamesByID (WhitelistTeamIDs): %v", err)
  85. }
  86. mergeWhitelistTeams, err := models.GetTeamNamesByID(bp.MergeWhitelistTeamIDs)
  87. if err != nil {
  88. log.Error("GetTeamNamesByID (MergeWhitelistTeamIDs): %v", err)
  89. }
  90. approvalsWhitelistTeams, err := models.GetTeamNamesByID(bp.ApprovalsWhitelistTeamIDs)
  91. if err != nil {
  92. log.Error("GetTeamNamesByID (ApprovalsWhitelistTeamIDs): %v", err)
  93. }
  94. return &api.BranchProtection{
  95. BranchName: bp.BranchName,
  96. EnablePush: bp.CanPush,
  97. EnablePushWhitelist: bp.EnableWhitelist,
  98. PushWhitelistUsernames: pushWhitelistUsernames,
  99. PushWhitelistTeams: pushWhitelistTeams,
  100. PushWhitelistDeployKeys: bp.WhitelistDeployKeys,
  101. EnableMergeWhitelist: bp.EnableMergeWhitelist,
  102. MergeWhitelistUsernames: mergeWhitelistUsernames,
  103. MergeWhitelistTeams: mergeWhitelistTeams,
  104. EnableStatusCheck: bp.EnableStatusCheck,
  105. StatusCheckContexts: bp.StatusCheckContexts,
  106. RequiredApprovals: bp.RequiredApprovals,
  107. EnableApprovalsWhitelist: bp.EnableApprovalsWhitelist,
  108. ApprovalsWhitelistUsernames: approvalsWhitelistUsernames,
  109. ApprovalsWhitelistTeams: approvalsWhitelistTeams,
  110. BlockOnRejectedReviews: bp.BlockOnRejectedReviews,
  111. BlockOnOutdatedBranch: bp.BlockOnOutdatedBranch,
  112. DismissStaleApprovals: bp.DismissStaleApprovals,
  113. RequireSignedCommits: bp.RequireSignedCommits,
  114. ProtectedFilePatterns: bp.ProtectedFilePatterns,
  115. Created: bp.CreatedUnix.AsTime(),
  116. Updated: bp.UpdatedUnix.AsTime(),
  117. }
  118. }
  119. // ToTag convert a git.Tag to an api.Tag
  120. func ToTag(repo *models.Repository, t *git.Tag) *api.Tag {
  121. return &api.Tag{
  122. Name: t.Name,
  123. ID: t.ID.String(),
  124. Commit: ToCommitMeta(repo, t),
  125. ZipballURL: util.URLJoin(repo.HTMLURL(), "archive", t.Name+".zip"),
  126. TarballURL: util.URLJoin(repo.HTMLURL(), "archive", t.Name+".tar.gz"),
  127. }
  128. }
  129. // ToVerification convert a git.Commit.Signature to an api.PayloadCommitVerification
  130. func ToVerification(c *git.Commit) *api.PayloadCommitVerification {
  131. verif := models.ParseCommitWithSignature(c)
  132. commitVerification := &api.PayloadCommitVerification{
  133. Verified: verif.Verified,
  134. Reason: verif.Reason,
  135. }
  136. if c.Signature != nil {
  137. commitVerification.Signature = c.Signature.Signature
  138. commitVerification.Payload = c.Signature.Payload
  139. }
  140. if verif.SigningUser != nil {
  141. commitVerification.Signer = &structs.PayloadUser{
  142. Name: verif.SigningUser.Name,
  143. Email: verif.SigningUser.Email,
  144. }
  145. }
  146. return commitVerification
  147. }
  148. // ToPublicKey convert models.PublicKey to api.PublicKey
  149. func ToPublicKey(apiLink string, key *models.PublicKey) *api.PublicKey {
  150. return &api.PublicKey{
  151. ID: key.ID,
  152. Key: key.Content,
  153. URL: apiLink + com.ToStr(key.ID),
  154. Title: key.Name,
  155. Fingerprint: key.Fingerprint,
  156. Created: key.CreatedUnix.AsTime(),
  157. }
  158. }
  159. // ToGPGKey converts models.GPGKey to api.GPGKey
  160. func ToGPGKey(key *models.GPGKey) *api.GPGKey {
  161. subkeys := make([]*api.GPGKey, len(key.SubsKey))
  162. for id, k := range key.SubsKey {
  163. subkeys[id] = &api.GPGKey{
  164. ID: k.ID,
  165. PrimaryKeyID: k.PrimaryKeyID,
  166. KeyID: k.KeyID,
  167. PublicKey: k.Content,
  168. Created: k.CreatedUnix.AsTime(),
  169. Expires: k.ExpiredUnix.AsTime(),
  170. CanSign: k.CanSign,
  171. CanEncryptComms: k.CanEncryptComms,
  172. CanEncryptStorage: k.CanEncryptStorage,
  173. CanCertify: k.CanSign,
  174. }
  175. }
  176. emails := make([]*api.GPGKeyEmail, len(key.Emails))
  177. for i, e := range key.Emails {
  178. emails[i] = ToGPGKeyEmail(e)
  179. }
  180. return &api.GPGKey{
  181. ID: key.ID,
  182. PrimaryKeyID: key.PrimaryKeyID,
  183. KeyID: key.KeyID,
  184. PublicKey: key.Content,
  185. Created: key.CreatedUnix.AsTime(),
  186. Expires: key.ExpiredUnix.AsTime(),
  187. Emails: emails,
  188. SubsKey: subkeys,
  189. CanSign: key.CanSign,
  190. CanEncryptComms: key.CanEncryptComms,
  191. CanEncryptStorage: key.CanEncryptStorage,
  192. CanCertify: key.CanSign,
  193. }
  194. }
  195. // ToGPGKeyEmail convert models.EmailAddress to api.GPGKeyEmail
  196. func ToGPGKeyEmail(email *models.EmailAddress) *api.GPGKeyEmail {
  197. return &api.GPGKeyEmail{
  198. Email: email.Email,
  199. Verified: email.IsActivated,
  200. }
  201. }
  202. // ToHook convert models.Webhook to api.Hook
  203. func ToHook(repoLink string, w *models.Webhook) *api.Hook {
  204. config := map[string]string{
  205. "url": w.URL,
  206. "content_type": w.ContentType.Name(),
  207. }
  208. if w.HookTaskType == models.SLACK {
  209. s := webhook.GetSlackHook(w)
  210. config["channel"] = s.Channel
  211. config["username"] = s.Username
  212. config["icon_url"] = s.IconURL
  213. config["color"] = s.Color
  214. }
  215. return &api.Hook{
  216. ID: w.ID,
  217. Type: w.HookTaskType.Name(),
  218. URL: fmt.Sprintf("%s/settings/hooks/%d", repoLink, w.ID),
  219. Active: w.IsActive,
  220. Config: config,
  221. Events: w.EventsArray(),
  222. Updated: w.UpdatedUnix.AsTime(),
  223. Created: w.CreatedUnix.AsTime(),
  224. }
  225. }
  226. // ToGitHook convert git.Hook to api.GitHook
  227. func ToGitHook(h *git.Hook) *api.GitHook {
  228. return &api.GitHook{
  229. Name: h.Name(),
  230. IsActive: h.IsActive,
  231. Content: h.Content,
  232. }
  233. }
  234. // ToDeployKey convert models.DeployKey to api.DeployKey
  235. func ToDeployKey(apiLink string, key *models.DeployKey) *api.DeployKey {
  236. return &api.DeployKey{
  237. ID: key.ID,
  238. KeyID: key.KeyID,
  239. Key: key.Content,
  240. Fingerprint: key.Fingerprint,
  241. URL: apiLink + com.ToStr(key.ID),
  242. Title: key.Name,
  243. Created: key.CreatedUnix.AsTime(),
  244. ReadOnly: key.Mode == models.AccessModeRead, // All deploy keys are read-only.
  245. }
  246. }
  247. // ToOrganization convert models.User to api.Organization
  248. func ToOrganization(org *models.User) *api.Organization {
  249. return &api.Organization{
  250. ID: org.ID,
  251. AvatarURL: org.AvatarLink(),
  252. UserName: org.Name,
  253. FullName: org.FullName,
  254. Description: org.Description,
  255. Website: org.Website,
  256. Location: org.Location,
  257. Visibility: org.Visibility.String(),
  258. RepoAdminChangeTeamAccess: org.RepoAdminChangeTeamAccess,
  259. }
  260. }
  261. // ToTeam convert models.Team to api.Team
  262. func ToTeam(team *models.Team) *api.Team {
  263. return &api.Team{
  264. ID: team.ID,
  265. Name: team.Name,
  266. Description: team.Description,
  267. IncludesAllRepositories: team.IncludesAllRepositories,
  268. CanCreateOrgRepo: team.CanCreateOrgRepo,
  269. Permission: team.Authorize.String(),
  270. Units: team.GetUnitNames(),
  271. }
  272. }
  273. // ToAnnotatedTag convert git.Tag to api.AnnotatedTag
  274. func ToAnnotatedTag(repo *models.Repository, t *git.Tag, c *git.Commit) *api.AnnotatedTag {
  275. return &api.AnnotatedTag{
  276. Tag: t.Name,
  277. SHA: t.ID.String(),
  278. Object: ToAnnotatedTagObject(repo, c),
  279. Message: t.Message,
  280. URL: util.URLJoin(repo.APIURL(), "git/tags", t.ID.String()),
  281. Tagger: ToCommitUser(t.Tagger),
  282. Verification: ToVerification(c),
  283. }
  284. }
  285. // ToAnnotatedTagObject convert a git.Commit to an api.AnnotatedTagObject
  286. func ToAnnotatedTagObject(repo *models.Repository, commit *git.Commit) *api.AnnotatedTagObject {
  287. return &api.AnnotatedTagObject{
  288. SHA: commit.ID.String(),
  289. Type: string(git.ObjectCommit),
  290. URL: util.URLJoin(repo.APIURL(), "git/commits", commit.ID.String()),
  291. }
  292. }
  293. // ToTopicResponse convert from models.Topic to api.TopicResponse
  294. func ToTopicResponse(topic *models.Topic) *api.TopicResponse {
  295. return &api.TopicResponse{
  296. ID: topic.ID,
  297. Name: topic.Name,
  298. RepoCount: topic.RepoCount,
  299. Created: topic.CreatedUnix.AsTime(),
  300. Updated: topic.UpdatedUnix.AsTime(),
  301. }
  302. }
  303. // ToOAuth2Application convert from models.OAuth2Application to api.OAuth2Application
  304. func ToOAuth2Application(app *models.OAuth2Application) *api.OAuth2Application {
  305. return &api.OAuth2Application{
  306. ID: app.ID,
  307. Name: app.Name,
  308. ClientID: app.ClientID,
  309. ClientSecret: app.ClientSecret,
  310. RedirectURIs: app.RedirectURIs,
  311. Created: app.CreatedUnix.AsTime(),
  312. }
  313. }