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.

gpg_key.go 8.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. // Copyright 2017 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 user
  5. import (
  6. "fmt"
  7. "net/http"
  8. "code.gitea.io/gitea/models"
  9. "code.gitea.io/gitea/modules/context"
  10. "code.gitea.io/gitea/modules/convert"
  11. api "code.gitea.io/gitea/modules/structs"
  12. "code.gitea.io/gitea/modules/web"
  13. "code.gitea.io/gitea/routers/api/v1/utils"
  14. )
  15. func listGPGKeys(ctx *context.APIContext, uid int64, listOptions models.ListOptions) {
  16. keys, err := models.ListGPGKeys(uid, listOptions)
  17. if err != nil {
  18. ctx.Error(http.StatusInternalServerError, "ListGPGKeys", err)
  19. return
  20. }
  21. apiKeys := make([]*api.GPGKey, len(keys))
  22. for i := range keys {
  23. apiKeys[i] = convert.ToGPGKey(keys[i])
  24. }
  25. total, err := models.CountUserGPGKeys(uid)
  26. if err != nil {
  27. ctx.InternalServerError(err)
  28. return
  29. }
  30. ctx.SetTotalCountHeader(total)
  31. ctx.JSON(http.StatusOK, &apiKeys)
  32. }
  33. //ListGPGKeys get the GPG key list of a user
  34. func ListGPGKeys(ctx *context.APIContext) {
  35. // swagger:operation GET /users/{username}/gpg_keys user userListGPGKeys
  36. // ---
  37. // summary: List the given user's GPG keys
  38. // produces:
  39. // - application/json
  40. // parameters:
  41. // - name: username
  42. // in: path
  43. // description: username of user
  44. // type: string
  45. // required: true
  46. // - name: page
  47. // in: query
  48. // description: page number of results to return (1-based)
  49. // type: integer
  50. // - name: limit
  51. // in: query
  52. // description: page size of results
  53. // type: integer
  54. // responses:
  55. // "200":
  56. // "$ref": "#/responses/GPGKeyList"
  57. user := GetUserByParams(ctx)
  58. if ctx.Written() {
  59. return
  60. }
  61. listGPGKeys(ctx, user.ID, utils.GetListOptions(ctx))
  62. }
  63. //ListMyGPGKeys get the GPG key list of the authenticated user
  64. func ListMyGPGKeys(ctx *context.APIContext) {
  65. // swagger:operation GET /user/gpg_keys user userCurrentListGPGKeys
  66. // ---
  67. // summary: List the authenticated user's GPG keys
  68. // parameters:
  69. // - name: page
  70. // in: query
  71. // description: page number of results to return (1-based)
  72. // type: integer
  73. // - name: limit
  74. // in: query
  75. // description: page size of results
  76. // type: integer
  77. // produces:
  78. // - application/json
  79. // responses:
  80. // "200":
  81. // "$ref": "#/responses/GPGKeyList"
  82. listGPGKeys(ctx, ctx.User.ID, utils.GetListOptions(ctx))
  83. }
  84. //GetGPGKey get the GPG key based on a id
  85. func GetGPGKey(ctx *context.APIContext) {
  86. // swagger:operation GET /user/gpg_keys/{id} user userCurrentGetGPGKey
  87. // ---
  88. // summary: Get a GPG key
  89. // produces:
  90. // - application/json
  91. // parameters:
  92. // - name: id
  93. // in: path
  94. // description: id of key to get
  95. // type: integer
  96. // format: int64
  97. // required: true
  98. // responses:
  99. // "200":
  100. // "$ref": "#/responses/GPGKey"
  101. // "404":
  102. // "$ref": "#/responses/notFound"
  103. key, err := models.GetGPGKeyByID(ctx.ParamsInt64(":id"))
  104. if err != nil {
  105. if models.IsErrGPGKeyNotExist(err) {
  106. ctx.NotFound()
  107. } else {
  108. ctx.Error(http.StatusInternalServerError, "GetGPGKeyByID", err)
  109. }
  110. return
  111. }
  112. ctx.JSON(http.StatusOK, convert.ToGPGKey(key))
  113. }
  114. // CreateUserGPGKey creates new GPG key to given user by ID.
  115. func CreateUserGPGKey(ctx *context.APIContext, form api.CreateGPGKeyOption, uid int64) {
  116. token := models.VerificationToken(ctx.User, 1)
  117. lastToken := models.VerificationToken(ctx.User, 0)
  118. keys, err := models.AddGPGKey(uid, form.ArmoredKey, token, form.Signature)
  119. if err != nil && models.IsErrGPGInvalidTokenSignature(err) {
  120. keys, err = models.AddGPGKey(uid, form.ArmoredKey, lastToken, form.Signature)
  121. }
  122. if err != nil {
  123. HandleAddGPGKeyError(ctx, err, token)
  124. return
  125. }
  126. ctx.JSON(http.StatusCreated, convert.ToGPGKey(keys[0]))
  127. }
  128. // GetVerificationToken returns the current token to be signed for this user
  129. func GetVerificationToken(ctx *context.APIContext) {
  130. // swagger:operation GET /user/gpg_key_token user getVerificationToken
  131. // ---
  132. // summary: Get a Token to verify
  133. // produces:
  134. // - text/plain
  135. // parameters:
  136. // responses:
  137. // "200":
  138. // "$ref": "#/responses/string"
  139. // "404":
  140. // "$ref": "#/responses/notFound"
  141. token := models.VerificationToken(ctx.User, 1)
  142. ctx.PlainText(http.StatusOK, []byte(token))
  143. }
  144. // VerifyUserGPGKey creates new GPG key to given user by ID.
  145. func VerifyUserGPGKey(ctx *context.APIContext) {
  146. // swagger:operation POST /user/gpg_key_verify user userVerifyGPGKey
  147. // ---
  148. // summary: Verify a GPG key
  149. // consumes:
  150. // - application/json
  151. // produces:
  152. // - application/json
  153. // responses:
  154. // "201":
  155. // "$ref": "#/responses/GPGKey"
  156. // "404":
  157. // "$ref": "#/responses/notFound"
  158. // "422":
  159. // "$ref": "#/responses/validationError"
  160. form := web.GetForm(ctx).(*api.VerifyGPGKeyOption)
  161. token := models.VerificationToken(ctx.User, 1)
  162. lastToken := models.VerificationToken(ctx.User, 0)
  163. _, err := models.VerifyGPGKey(ctx.User.ID, form.KeyID, token, form.Signature)
  164. if err != nil && models.IsErrGPGInvalidTokenSignature(err) {
  165. _, err = models.VerifyGPGKey(ctx.User.ID, form.KeyID, lastToken, form.Signature)
  166. }
  167. if err != nil {
  168. if models.IsErrGPGInvalidTokenSignature(err) {
  169. ctx.Error(http.StatusUnprocessableEntity, "GPGInvalidSignature", fmt.Sprintf("The provided GPG key, signature and token do not match or token is out of date. Provide a valid signature for the token: %s", token))
  170. return
  171. }
  172. ctx.Error(http.StatusInternalServerError, "VerifyUserGPGKey", err)
  173. }
  174. key, err := models.GetGPGKeysByKeyID(form.KeyID)
  175. if err != nil {
  176. if models.IsErrGPGKeyNotExist(err) {
  177. ctx.NotFound()
  178. } else {
  179. ctx.Error(http.StatusInternalServerError, "GetGPGKeysByKeyID", err)
  180. }
  181. return
  182. }
  183. ctx.JSON(http.StatusOK, convert.ToGPGKey(key[0]))
  184. }
  185. // swagger:parameters userCurrentPostGPGKey
  186. type swaggerUserCurrentPostGPGKey struct {
  187. // in:body
  188. Form api.CreateGPGKeyOption
  189. }
  190. //CreateGPGKey create a GPG key belonging to the authenticated user
  191. func CreateGPGKey(ctx *context.APIContext) {
  192. // swagger:operation POST /user/gpg_keys user userCurrentPostGPGKey
  193. // ---
  194. // summary: Create a GPG key
  195. // consumes:
  196. // - application/json
  197. // produces:
  198. // - application/json
  199. // responses:
  200. // "201":
  201. // "$ref": "#/responses/GPGKey"
  202. // "404":
  203. // "$ref": "#/responses/notFound"
  204. // "422":
  205. // "$ref": "#/responses/validationError"
  206. form := web.GetForm(ctx).(*api.CreateGPGKeyOption)
  207. CreateUserGPGKey(ctx, *form, ctx.User.ID)
  208. }
  209. //DeleteGPGKey remove a GPG key belonging to the authenticated user
  210. func DeleteGPGKey(ctx *context.APIContext) {
  211. // swagger:operation DELETE /user/gpg_keys/{id} user userCurrentDeleteGPGKey
  212. // ---
  213. // summary: Remove a GPG key
  214. // produces:
  215. // - application/json
  216. // parameters:
  217. // - name: id
  218. // in: path
  219. // description: id of key to delete
  220. // type: integer
  221. // format: int64
  222. // required: true
  223. // responses:
  224. // "204":
  225. // "$ref": "#/responses/empty"
  226. // "403":
  227. // "$ref": "#/responses/forbidden"
  228. // "404":
  229. // "$ref": "#/responses/notFound"
  230. if err := models.DeleteGPGKey(ctx.User, ctx.ParamsInt64(":id")); err != nil {
  231. if models.IsErrGPGKeyAccessDenied(err) {
  232. ctx.Error(http.StatusForbidden, "", "You do not have access to this key")
  233. } else {
  234. ctx.Error(http.StatusInternalServerError, "DeleteGPGKey", err)
  235. }
  236. return
  237. }
  238. ctx.Status(http.StatusNoContent)
  239. }
  240. // HandleAddGPGKeyError handle add GPGKey error
  241. func HandleAddGPGKeyError(ctx *context.APIContext, err error, token string) {
  242. switch {
  243. case models.IsErrGPGKeyAccessDenied(err):
  244. ctx.Error(http.StatusUnprocessableEntity, "GPGKeyAccessDenied", "You do not have access to this GPG key")
  245. case models.IsErrGPGKeyIDAlreadyUsed(err):
  246. ctx.Error(http.StatusUnprocessableEntity, "GPGKeyIDAlreadyUsed", "A key with the same id already exists")
  247. case models.IsErrGPGKeyParsing(err):
  248. ctx.Error(http.StatusUnprocessableEntity, "GPGKeyParsing", err)
  249. case models.IsErrGPGNoEmailFound(err):
  250. ctx.Error(http.StatusNotFound, "GPGNoEmailFound", fmt.Sprintf("None of the emails attached to the GPG key could be found. It may still be added if you provide a valid signature for the token: %s", token))
  251. case models.IsErrGPGInvalidTokenSignature(err):
  252. ctx.Error(http.StatusUnprocessableEntity, "GPGInvalidSignature", fmt.Sprintf("The provided GPG key, signature and token do not match or token is out of date. Provide a valid signature for the token: %s", token))
  253. default:
  254. ctx.Error(http.StatusInternalServerError, "AddGPGKey", err)
  255. }
  256. }