gitea源码

keys.go 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Copyright 2018 The Gitea Authors. All rights reserved.
  3. // SPDX-License-Identifier: MIT
  4. package setting
  5. import (
  6. "errors"
  7. "net/http"
  8. asymkey_model "code.gitea.io/gitea/models/asymkey"
  9. "code.gitea.io/gitea/models/db"
  10. user_model "code.gitea.io/gitea/models/user"
  11. "code.gitea.io/gitea/modules/setting"
  12. "code.gitea.io/gitea/modules/templates"
  13. "code.gitea.io/gitea/modules/web"
  14. asymkey_service "code.gitea.io/gitea/services/asymkey"
  15. "code.gitea.io/gitea/services/context"
  16. "code.gitea.io/gitea/services/forms"
  17. )
  18. const (
  19. tplSettingsKeys templates.TplName = "user/settings/keys"
  20. )
  21. // Keys render user's SSH/GPG public keys page
  22. func Keys(ctx *context.Context) {
  23. if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageSSHKeys, setting.UserFeatureManageGPGKeys) {
  24. ctx.NotFound(errors.New("keys setting is not allowed to be changed"))
  25. return
  26. }
  27. ctx.Data["Title"] = ctx.Tr("settings.ssh_gpg_keys")
  28. ctx.Data["PageIsSettingsKeys"] = true
  29. ctx.Data["DisableSSH"] = setting.SSH.Disabled
  30. ctx.Data["BuiltinSSH"] = setting.SSH.StartBuiltinServer
  31. ctx.Data["AllowPrincipals"] = setting.SSH.AuthorizedPrincipalsEnabled
  32. ctx.Data["UserDisabledFeatures"] = user_model.DisabledFeaturesWithLoginType(ctx.Doer)
  33. loadKeysData(ctx)
  34. ctx.HTML(http.StatusOK, tplSettingsKeys)
  35. }
  36. // KeysPost response for change user's SSH/GPG keys
  37. func KeysPost(ctx *context.Context) {
  38. form := web.GetForm(ctx).(*forms.AddKeyForm)
  39. ctx.Data["Title"] = ctx.Tr("settings")
  40. ctx.Data["PageIsSettingsKeys"] = true
  41. ctx.Data["DisableSSH"] = setting.SSH.Disabled
  42. ctx.Data["BuiltinSSH"] = setting.SSH.StartBuiltinServer
  43. ctx.Data["AllowPrincipals"] = setting.SSH.AuthorizedPrincipalsEnabled
  44. ctx.Data["UserDisabledFeatures"] = user_model.DisabledFeaturesWithLoginType(ctx.Doer)
  45. if ctx.HasError() {
  46. loadKeysData(ctx)
  47. ctx.HTML(http.StatusOK, tplSettingsKeys)
  48. return
  49. }
  50. switch form.Type {
  51. case "principal":
  52. content, err := asymkey_model.CheckPrincipalKeyString(ctx, ctx.Doer, form.Content)
  53. if err != nil {
  54. if db.IsErrSSHDisabled(err) {
  55. ctx.Flash.Info(ctx.Tr("settings.ssh_disabled"))
  56. } else {
  57. ctx.Flash.Error(ctx.Tr("form.invalid_ssh_principal", err.Error()))
  58. }
  59. ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
  60. return
  61. }
  62. if _, err = asymkey_service.AddPrincipalKey(ctx, ctx.Doer.ID, content, 0); err != nil {
  63. ctx.Data["HasPrincipalError"] = true
  64. switch {
  65. case asymkey_model.IsErrKeyAlreadyExist(err), asymkey_model.IsErrKeyNameAlreadyUsed(err):
  66. loadKeysData(ctx)
  67. ctx.Data["Err_Content"] = true
  68. ctx.RenderWithErr(ctx.Tr("settings.ssh_principal_been_used"), tplSettingsKeys, &form)
  69. default:
  70. ctx.ServerError("AddPrincipalKey", err)
  71. }
  72. return
  73. }
  74. ctx.Flash.Success(ctx.Tr("settings.add_principal_success", form.Content))
  75. ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
  76. case "gpg":
  77. if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageGPGKeys) {
  78. ctx.NotFound(errors.New("gpg keys setting is not allowed to be visited"))
  79. return
  80. }
  81. token := asymkey_model.VerificationToken(ctx.Doer, 1)
  82. lastToken := asymkey_model.VerificationToken(ctx.Doer, 0)
  83. keys, err := asymkey_model.AddGPGKey(ctx, ctx.Doer.ID, form.Content, token, form.Signature)
  84. if err != nil && asymkey_model.IsErrGPGInvalidTokenSignature(err) {
  85. keys, err = asymkey_model.AddGPGKey(ctx, ctx.Doer.ID, form.Content, lastToken, form.Signature)
  86. }
  87. if err != nil {
  88. ctx.Data["HasGPGError"] = true
  89. switch {
  90. case asymkey_model.IsErrGPGKeyParsing(err):
  91. ctx.Flash.Error(ctx.Tr("form.invalid_gpg_key", err.Error()))
  92. ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
  93. case asymkey_model.IsErrGPGKeyIDAlreadyUsed(err):
  94. loadKeysData(ctx)
  95. ctx.Data["Err_Content"] = true
  96. ctx.RenderWithErr(ctx.Tr("settings.gpg_key_id_used"), tplSettingsKeys, &form)
  97. case asymkey_model.IsErrGPGInvalidTokenSignature(err):
  98. loadKeysData(ctx)
  99. ctx.Data["Err_Content"] = true
  100. ctx.Data["Err_Signature"] = true
  101. keyID := err.(asymkey_model.ErrGPGInvalidTokenSignature).ID
  102. ctx.Data["KeyID"] = keyID
  103. ctx.Data["PaddedKeyID"] = asymkey_model.PaddedKeyID(keyID)
  104. ctx.RenderWithErr(ctx.Tr("settings.gpg_invalid_token_signature"), tplSettingsKeys, &form)
  105. case asymkey_model.IsErrGPGNoEmailFound(err):
  106. loadKeysData(ctx)
  107. ctx.Data["Err_Content"] = true
  108. ctx.Data["Err_Signature"] = true
  109. keyID := err.(asymkey_model.ErrGPGNoEmailFound).ID
  110. ctx.Data["KeyID"] = keyID
  111. ctx.Data["PaddedKeyID"] = asymkey_model.PaddedKeyID(keyID)
  112. ctx.RenderWithErr(ctx.Tr("settings.gpg_no_key_email_found"), tplSettingsKeys, &form)
  113. default:
  114. ctx.ServerError("AddPublicKey", err)
  115. }
  116. return
  117. }
  118. keyIDs := ""
  119. for _, key := range keys {
  120. keyIDs += key.KeyID
  121. keyIDs += ", "
  122. }
  123. if len(keyIDs) > 0 {
  124. keyIDs = keyIDs[:len(keyIDs)-2]
  125. }
  126. ctx.Flash.Success(ctx.Tr("settings.add_gpg_key_success", keyIDs))
  127. ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
  128. case "verify_gpg":
  129. token := asymkey_model.VerificationToken(ctx.Doer, 1)
  130. lastToken := asymkey_model.VerificationToken(ctx.Doer, 0)
  131. keyID, err := asymkey_model.VerifyGPGKey(ctx, ctx.Doer.ID, form.KeyID, token, form.Signature)
  132. if err != nil && asymkey_model.IsErrGPGInvalidTokenSignature(err) {
  133. keyID, err = asymkey_model.VerifyGPGKey(ctx, ctx.Doer.ID, form.KeyID, lastToken, form.Signature)
  134. }
  135. if err != nil {
  136. ctx.Data["HasGPGVerifyError"] = true
  137. switch {
  138. case asymkey_model.IsErrGPGInvalidTokenSignature(err):
  139. loadKeysData(ctx)
  140. ctx.Data["VerifyingID"] = form.KeyID
  141. ctx.Data["Err_Signature"] = true
  142. keyID := err.(asymkey_model.ErrGPGInvalidTokenSignature).ID
  143. ctx.Data["KeyID"] = keyID
  144. ctx.Data["PaddedKeyID"] = asymkey_model.PaddedKeyID(keyID)
  145. ctx.RenderWithErr(ctx.Tr("settings.gpg_invalid_token_signature"), tplSettingsKeys, &form)
  146. default:
  147. ctx.ServerError("VerifyGPG", err)
  148. }
  149. }
  150. ctx.Flash.Success(ctx.Tr("settings.verify_gpg_key_success", keyID))
  151. ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
  152. case "ssh":
  153. if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageSSHKeys) {
  154. ctx.NotFound(errors.New("ssh keys setting is not allowed to be visited"))
  155. return
  156. }
  157. content, err := asymkey_model.CheckPublicKeyString(form.Content)
  158. if err != nil {
  159. if db.IsErrSSHDisabled(err) {
  160. ctx.Flash.Info(ctx.Tr("settings.ssh_disabled"))
  161. } else if asymkey_model.IsErrKeyUnableVerify(err) {
  162. ctx.Flash.Info(ctx.Tr("form.unable_verify_ssh_key"))
  163. } else if err == asymkey_model.ErrKeyIsPrivate {
  164. ctx.Flash.Error(ctx.Tr("form.must_use_public_key"))
  165. } else {
  166. ctx.Flash.Error(ctx.Tr("form.invalid_ssh_key", err.Error()))
  167. }
  168. ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
  169. return
  170. }
  171. if _, err = asymkey_model.AddPublicKey(ctx, ctx.Doer.ID, form.Title, content, 0); err != nil {
  172. ctx.Data["HasSSHError"] = true
  173. switch {
  174. case asymkey_model.IsErrKeyAlreadyExist(err):
  175. loadKeysData(ctx)
  176. ctx.Data["Err_Content"] = true
  177. ctx.RenderWithErr(ctx.Tr("settings.ssh_key_been_used"), tplSettingsKeys, &form)
  178. case asymkey_model.IsErrKeyNameAlreadyUsed(err):
  179. loadKeysData(ctx)
  180. ctx.Data["Err_Title"] = true
  181. ctx.RenderWithErr(ctx.Tr("settings.ssh_key_name_used"), tplSettingsKeys, &form)
  182. case asymkey_model.IsErrKeyUnableVerify(err):
  183. ctx.Flash.Info(ctx.Tr("form.unable_verify_ssh_key"))
  184. ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
  185. default:
  186. ctx.ServerError("AddPublicKey", err)
  187. }
  188. return
  189. }
  190. ctx.Flash.Success(ctx.Tr("settings.add_key_success", form.Title))
  191. ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
  192. case "verify_ssh":
  193. if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageSSHKeys) {
  194. ctx.NotFound(errors.New("ssh keys setting is not allowed to be visited"))
  195. return
  196. }
  197. token := asymkey_model.VerificationToken(ctx.Doer, 1)
  198. lastToken := asymkey_model.VerificationToken(ctx.Doer, 0)
  199. fingerprint, err := asymkey_model.VerifySSHKey(ctx, ctx.Doer.ID, form.Fingerprint, token, form.Signature)
  200. if err != nil && asymkey_model.IsErrSSHInvalidTokenSignature(err) {
  201. fingerprint, err = asymkey_model.VerifySSHKey(ctx, ctx.Doer.ID, form.Fingerprint, lastToken, form.Signature)
  202. }
  203. if err != nil {
  204. ctx.Data["HasSSHVerifyError"] = true
  205. switch {
  206. case asymkey_model.IsErrSSHInvalidTokenSignature(err):
  207. loadKeysData(ctx)
  208. ctx.Data["Err_Signature"] = true
  209. ctx.Data["Fingerprint"] = err.(asymkey_model.ErrSSHInvalidTokenSignature).Fingerprint
  210. ctx.RenderWithErr(ctx.Tr("settings.ssh_invalid_token_signature"), tplSettingsKeys, &form)
  211. default:
  212. ctx.ServerError("VerifySSH", err)
  213. }
  214. }
  215. ctx.Flash.Success(ctx.Tr("settings.verify_ssh_key_success", fingerprint))
  216. ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
  217. default:
  218. ctx.Flash.Warning("Function not implemented")
  219. ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
  220. }
  221. }
  222. // DeleteKey response for delete user's SSH/GPG key
  223. func DeleteKey(ctx *context.Context) {
  224. switch ctx.FormString("type") {
  225. case "gpg":
  226. if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageGPGKeys) {
  227. ctx.NotFound(errors.New("gpg keys setting is not allowed to be visited"))
  228. return
  229. }
  230. if err := asymkey_model.DeleteGPGKey(ctx, ctx.Doer, ctx.FormInt64("id")); err != nil {
  231. ctx.Flash.Error("DeleteGPGKey: " + err.Error())
  232. } else {
  233. ctx.Flash.Success(ctx.Tr("settings.gpg_key_deletion_success"))
  234. }
  235. case "ssh":
  236. if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageSSHKeys) {
  237. ctx.NotFound(errors.New("ssh keys setting is not allowed to be visited"))
  238. return
  239. }
  240. keyID := ctx.FormInt64("id")
  241. external, err := asymkey_model.PublicKeyIsExternallyManaged(ctx, keyID)
  242. if err != nil {
  243. ctx.ServerError("sshKeysExternalManaged", err)
  244. return
  245. }
  246. if external {
  247. ctx.Flash.Error(ctx.Tr("settings.ssh_externally_managed"))
  248. ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
  249. return
  250. }
  251. if err := asymkey_service.DeletePublicKey(ctx, ctx.Doer, keyID); err != nil {
  252. ctx.Flash.Error("DeletePublicKey: " + err.Error())
  253. } else {
  254. ctx.Flash.Success(ctx.Tr("settings.ssh_key_deletion_success"))
  255. }
  256. case "principal":
  257. if err := asymkey_service.DeletePublicKey(ctx, ctx.Doer, ctx.FormInt64("id")); err != nil {
  258. ctx.Flash.Error("DeletePublicKey: " + err.Error())
  259. } else {
  260. ctx.Flash.Success(ctx.Tr("settings.ssh_principal_deletion_success"))
  261. }
  262. default:
  263. ctx.Flash.Warning("Function not implemented")
  264. ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
  265. }
  266. ctx.JSONRedirect(setting.AppSubURL + "/user/settings/keys")
  267. }
  268. func loadKeysData(ctx *context.Context) {
  269. keys, err := db.Find[asymkey_model.PublicKey](ctx, asymkey_model.FindPublicKeyOptions{
  270. OwnerID: ctx.Doer.ID,
  271. NotKeytype: asymkey_model.KeyTypePrincipal,
  272. })
  273. if err != nil {
  274. ctx.ServerError("ListPublicKeys", err)
  275. return
  276. }
  277. ctx.Data["Keys"] = keys
  278. externalKeys, err := asymkey_model.PublicKeysAreExternallyManaged(ctx, keys)
  279. if err != nil {
  280. ctx.ServerError("ListPublicKeys", err)
  281. return
  282. }
  283. ctx.Data["ExternalKeys"] = externalKeys
  284. gpgkeys, err := db.Find[asymkey_model.GPGKey](ctx, asymkey_model.FindGPGKeyOptions{
  285. ListOptions: db.ListOptionsAll,
  286. OwnerID: ctx.Doer.ID,
  287. })
  288. if err != nil {
  289. ctx.ServerError("ListGPGKeys", err)
  290. return
  291. }
  292. if err := asymkey_model.GPGKeyList(gpgkeys).LoadSubKeys(ctx); err != nil {
  293. ctx.ServerError("LoadSubKeys", err)
  294. return
  295. }
  296. ctx.Data["GPGKeys"] = gpgkeys
  297. tokenToSign := asymkey_model.VerificationToken(ctx.Doer, 1)
  298. // generate a new aes cipher using the csrfToken
  299. ctx.Data["TokenToSign"] = tokenToSign
  300. principals, err := db.Find[asymkey_model.PublicKey](ctx, asymkey_model.FindPublicKeyOptions{
  301. ListOptions: db.ListOptionsAll,
  302. OwnerID: ctx.Doer.ID,
  303. KeyTypes: []asymkey_model.KeyType{asymkey_model.KeyTypePrincipal},
  304. })
  305. if err != nil {
  306. ctx.ServerError("ListPrincipalKeys", err)
  307. return
  308. }
  309. ctx.Data["Principals"] = principals
  310. ctx.Data["VerifyingID"] = ctx.FormString("verify_gpg")
  311. ctx.Data["VerifyingFingerprint"] = ctx.FormString("verify_ssh")
  312. ctx.Data["UserDisabledFeatures"] = user_model.DisabledFeaturesWithLoginType(ctx.Doer)
  313. }