本站源代码
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.

304 lines
7.4KB

  1. // Copyright 2019 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package models
  5. import (
  6. "strings"
  7. "code.gitea.io/gitea/modules/git"
  8. "code.gitea.io/gitea/modules/log"
  9. "code.gitea.io/gitea/modules/process"
  10. "code.gitea.io/gitea/modules/setting"
  11. )
  12. type signingMode string
  13. const (
  14. never signingMode = "never"
  15. always signingMode = "always"
  16. pubkey signingMode = "pubkey"
  17. twofa signingMode = "twofa"
  18. parentSigned signingMode = "parentsigned"
  19. baseSigned signingMode = "basesigned"
  20. headSigned signingMode = "headsigned"
  21. commitsSigned signingMode = "commitssigned"
  22. )
  23. func signingModeFromStrings(modeStrings []string) []signingMode {
  24. returnable := make([]signingMode, 0, len(modeStrings))
  25. for _, mode := range modeStrings {
  26. signMode := signingMode(strings.ToLower(mode))
  27. switch signMode {
  28. case never:
  29. return []signingMode{never}
  30. case always:
  31. return []signingMode{always}
  32. case pubkey:
  33. fallthrough
  34. case twofa:
  35. fallthrough
  36. case parentSigned:
  37. fallthrough
  38. case baseSigned:
  39. fallthrough
  40. case headSigned:
  41. fallthrough
  42. case commitsSigned:
  43. returnable = append(returnable, signMode)
  44. }
  45. }
  46. if len(returnable) == 0 {
  47. return []signingMode{never}
  48. }
  49. return returnable
  50. }
  51. func signingKey(repoPath string) string {
  52. if setting.Repository.Signing.SigningKey == "none" {
  53. return ""
  54. }
  55. if setting.Repository.Signing.SigningKey == "default" || setting.Repository.Signing.SigningKey == "" {
  56. // Can ignore the error here as it means that commit.gpgsign is not set
  57. value, _ := git.NewCommand("config", "--get", "commit.gpgsign").RunInDir(repoPath)
  58. sign, valid := git.ParseBool(strings.TrimSpace(value))
  59. if !sign || !valid {
  60. return ""
  61. }
  62. signingKey, _ := git.NewCommand("config", "--get", "user.signingkey").RunInDir(repoPath)
  63. return strings.TrimSpace(signingKey)
  64. }
  65. return setting.Repository.Signing.SigningKey
  66. }
  67. // PublicSigningKey gets the public signing key within a provided repository directory
  68. func PublicSigningKey(repoPath string) (string, error) {
  69. signingKey := signingKey(repoPath)
  70. if signingKey == "" {
  71. return "", nil
  72. }
  73. content, stderr, err := process.GetManager().ExecDir(-1, repoPath,
  74. "gpg --export -a", "gpg", "--export", "-a", signingKey)
  75. if err != nil {
  76. log.Error("Unable to get default signing key in %s: %s, %s, %v", repoPath, signingKey, stderr, err)
  77. return "", err
  78. }
  79. return content, nil
  80. }
  81. // SignInitialCommit determines if we should sign the initial commit to this repository
  82. func SignInitialCommit(repoPath string, u *User) (bool, string) {
  83. rules := signingModeFromStrings(setting.Repository.Signing.InitialCommit)
  84. signingKey := signingKey(repoPath)
  85. if signingKey == "" {
  86. return false, ""
  87. }
  88. for _, rule := range rules {
  89. switch rule {
  90. case never:
  91. return false, ""
  92. case always:
  93. break
  94. case pubkey:
  95. keys, err := ListGPGKeys(u.ID)
  96. if err != nil || len(keys) == 0 {
  97. return false, ""
  98. }
  99. case twofa:
  100. twofa, err := GetTwoFactorByUID(u.ID)
  101. if err != nil || twofa == nil {
  102. return false, ""
  103. }
  104. }
  105. }
  106. return true, signingKey
  107. }
  108. // SignWikiCommit determines if we should sign the commits to this repository wiki
  109. func (repo *Repository) SignWikiCommit(u *User) (bool, string) {
  110. rules := signingModeFromStrings(setting.Repository.Signing.Wiki)
  111. signingKey := signingKey(repo.WikiPath())
  112. if signingKey == "" {
  113. return false, ""
  114. }
  115. for _, rule := range rules {
  116. switch rule {
  117. case never:
  118. return false, ""
  119. case always:
  120. break
  121. case pubkey:
  122. keys, err := ListGPGKeys(u.ID)
  123. if err != nil || len(keys) == 0 {
  124. return false, ""
  125. }
  126. case twofa:
  127. twofa, err := GetTwoFactorByUID(u.ID)
  128. if err != nil || twofa == nil {
  129. return false, ""
  130. }
  131. case parentSigned:
  132. gitRepo, err := git.OpenRepository(repo.WikiPath())
  133. if err != nil {
  134. return false, ""
  135. }
  136. commit, err := gitRepo.GetCommit("HEAD")
  137. if err != nil {
  138. return false, ""
  139. }
  140. if commit.Signature == nil {
  141. return false, ""
  142. }
  143. verification := ParseCommitWithSignature(commit)
  144. if !verification.Verified {
  145. return false, ""
  146. }
  147. }
  148. }
  149. return true, signingKey
  150. }
  151. // SignCRUDAction determines if we should sign a CRUD commit to this repository
  152. func (repo *Repository) SignCRUDAction(u *User, tmpBasePath, parentCommit string) (bool, string) {
  153. rules := signingModeFromStrings(setting.Repository.Signing.CRUDActions)
  154. signingKey := signingKey(repo.RepoPath())
  155. if signingKey == "" {
  156. return false, ""
  157. }
  158. for _, rule := range rules {
  159. switch rule {
  160. case never:
  161. return false, ""
  162. case always:
  163. break
  164. case pubkey:
  165. keys, err := ListGPGKeys(u.ID)
  166. if err != nil || len(keys) == 0 {
  167. return false, ""
  168. }
  169. case twofa:
  170. twofa, err := GetTwoFactorByUID(u.ID)
  171. if err != nil || twofa == nil {
  172. return false, ""
  173. }
  174. case parentSigned:
  175. gitRepo, err := git.OpenRepository(tmpBasePath)
  176. if err != nil {
  177. return false, ""
  178. }
  179. commit, err := gitRepo.GetCommit(parentCommit)
  180. if err != nil {
  181. return false, ""
  182. }
  183. if commit.Signature == nil {
  184. return false, ""
  185. }
  186. verification := ParseCommitWithSignature(commit)
  187. if !verification.Verified {
  188. return false, ""
  189. }
  190. }
  191. }
  192. return true, signingKey
  193. }
  194. // SignMerge determines if we should sign a merge commit to this repository
  195. func (repo *Repository) SignMerge(u *User, tmpBasePath, baseCommit, headCommit string) (bool, string) {
  196. rules := signingModeFromStrings(setting.Repository.Signing.Merges)
  197. signingKey := signingKey(repo.RepoPath())
  198. if signingKey == "" {
  199. return false, ""
  200. }
  201. var gitRepo *git.Repository
  202. var err error
  203. for _, rule := range rules {
  204. switch rule {
  205. case never:
  206. return false, ""
  207. case always:
  208. break
  209. case pubkey:
  210. keys, err := ListGPGKeys(u.ID)
  211. if err != nil || len(keys) == 0 {
  212. return false, ""
  213. }
  214. case twofa:
  215. twofa, err := GetTwoFactorByUID(u.ID)
  216. if err != nil || twofa == nil {
  217. return false, ""
  218. }
  219. case baseSigned:
  220. if gitRepo == nil {
  221. gitRepo, err = git.OpenRepository(tmpBasePath)
  222. if err != nil {
  223. return false, ""
  224. }
  225. }
  226. commit, err := gitRepo.GetCommit(baseCommit)
  227. if err != nil {
  228. return false, ""
  229. }
  230. verification := ParseCommitWithSignature(commit)
  231. if !verification.Verified {
  232. return false, ""
  233. }
  234. case headSigned:
  235. if gitRepo == nil {
  236. gitRepo, err = git.OpenRepository(tmpBasePath)
  237. if err != nil {
  238. return false, ""
  239. }
  240. }
  241. commit, err := gitRepo.GetCommit(headCommit)
  242. if err != nil {
  243. return false, ""
  244. }
  245. verification := ParseCommitWithSignature(commit)
  246. if !verification.Verified {
  247. return false, ""
  248. }
  249. case commitsSigned:
  250. if gitRepo == nil {
  251. gitRepo, err = git.OpenRepository(tmpBasePath)
  252. if err != nil {
  253. return false, ""
  254. }
  255. }
  256. commit, err := gitRepo.GetCommit(headCommit)
  257. if err != nil {
  258. return false, ""
  259. }
  260. verification := ParseCommitWithSignature(commit)
  261. if !verification.Verified {
  262. return false, ""
  263. }
  264. // need to work out merge-base
  265. mergeBaseCommit, _, err := gitRepo.GetMergeBase("", baseCommit, headCommit)
  266. if err != nil {
  267. return false, ""
  268. }
  269. commitList, err := commit.CommitsBeforeUntil(mergeBaseCommit)
  270. if err != nil {
  271. return false, ""
  272. }
  273. for e := commitList.Front(); e != nil; e = e.Next() {
  274. commit = e.Value.(*git.Commit)
  275. verification := ParseCommitWithSignature(commit)
  276. if !verification.Verified {
  277. return false, ""
  278. }
  279. }
  280. }
  281. }
  282. return true, signingKey
  283. }
上海开阖软件有限公司 沪ICP备12045867号-1