gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  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 user
  5. import (
  6. "errors"
  7. "fmt"
  8. "net/http"
  9. "strconv"
  10. "strings"
  11. auth_model "code.gitea.io/gitea/models/auth"
  12. "code.gitea.io/gitea/models/db"
  13. api "code.gitea.io/gitea/modules/structs"
  14. "code.gitea.io/gitea/modules/web"
  15. "code.gitea.io/gitea/routers/api/v1/utils"
  16. "code.gitea.io/gitea/services/context"
  17. "code.gitea.io/gitea/services/convert"
  18. )
  19. // ListAccessTokens list all the access tokens
  20. func ListAccessTokens(ctx *context.APIContext) {
  21. // swagger:operation GET /users/{username}/tokens user userGetTokens
  22. // ---
  23. // summary: List the authenticated user's access tokens
  24. // produces:
  25. // - application/json
  26. // parameters:
  27. // - name: username
  28. // in: path
  29. // description: username of to user whose access tokens are to be listed
  30. // type: string
  31. // required: true
  32. // - name: page
  33. // in: query
  34. // description: page number of results to return (1-based)
  35. // type: integer
  36. // - name: limit
  37. // in: query
  38. // description: page size of results
  39. // type: integer
  40. // responses:
  41. // "200":
  42. // "$ref": "#/responses/AccessTokenList"
  43. // "403":
  44. // "$ref": "#/responses/forbidden"
  45. opts := auth_model.ListAccessTokensOptions{UserID: ctx.ContextUser.ID, ListOptions: utils.GetListOptions(ctx)}
  46. tokens, count, err := db.FindAndCount[auth_model.AccessToken](ctx, opts)
  47. if err != nil {
  48. ctx.APIErrorInternal(err)
  49. return
  50. }
  51. apiTokens := make([]*api.AccessToken, len(tokens))
  52. for i := range tokens {
  53. apiTokens[i] = &api.AccessToken{
  54. ID: tokens[i].ID,
  55. Name: tokens[i].Name,
  56. TokenLastEight: tokens[i].TokenLastEight,
  57. Scopes: tokens[i].Scope.StringSlice(),
  58. Created: tokens[i].CreatedUnix.AsTime(),
  59. Updated: tokens[i].UpdatedUnix.AsTime(),
  60. }
  61. }
  62. ctx.SetTotalCountHeader(count)
  63. ctx.JSON(http.StatusOK, &apiTokens)
  64. }
  65. // CreateAccessToken create access tokens
  66. func CreateAccessToken(ctx *context.APIContext) {
  67. // swagger:operation POST /users/{username}/tokens user userCreateToken
  68. // ---
  69. // summary: Create an access token
  70. // consumes:
  71. // - application/json
  72. // produces:
  73. // - application/json
  74. // parameters:
  75. // - name: username
  76. // in: path
  77. // description: username of the user whose token is to be created
  78. // required: true
  79. // type: string
  80. // - name: body
  81. // in: body
  82. // schema:
  83. // "$ref": "#/definitions/CreateAccessTokenOption"
  84. // responses:
  85. // "201":
  86. // "$ref": "#/responses/AccessToken"
  87. // "400":
  88. // "$ref": "#/responses/error"
  89. // "403":
  90. // "$ref": "#/responses/forbidden"
  91. form := web.GetForm(ctx).(*api.CreateAccessTokenOption)
  92. t := &auth_model.AccessToken{
  93. UID: ctx.ContextUser.ID,
  94. Name: form.Name,
  95. }
  96. exist, err := auth_model.AccessTokenByNameExists(ctx, t)
  97. if err != nil {
  98. ctx.APIErrorInternal(err)
  99. return
  100. }
  101. if exist {
  102. ctx.APIError(http.StatusBadRequest, errors.New("access token name has been used already"))
  103. return
  104. }
  105. scope, err := auth_model.AccessTokenScope(strings.Join(form.Scopes, ",")).Normalize()
  106. if err != nil {
  107. ctx.APIError(http.StatusBadRequest, fmt.Errorf("invalid access token scope provided: %w", err))
  108. return
  109. }
  110. if scope == "" {
  111. ctx.APIError(http.StatusBadRequest, "access token must have a scope")
  112. return
  113. }
  114. t.Scope = scope
  115. if err := auth_model.NewAccessToken(ctx, t); err != nil {
  116. ctx.APIErrorInternal(err)
  117. return
  118. }
  119. ctx.JSON(http.StatusCreated, &api.AccessToken{
  120. Name: t.Name,
  121. Token: t.Token,
  122. ID: t.ID,
  123. TokenLastEight: t.TokenLastEight,
  124. Scopes: t.Scope.StringSlice(),
  125. })
  126. }
  127. // DeleteAccessToken delete access tokens
  128. func DeleteAccessToken(ctx *context.APIContext) {
  129. // swagger:operation DELETE /users/{username}/tokens/{token} user userDeleteAccessToken
  130. // ---
  131. // summary: delete an access token
  132. // produces:
  133. // - application/json
  134. // parameters:
  135. // - name: username
  136. // in: path
  137. // description: username of the user whose token is to be deleted
  138. // type: string
  139. // required: true
  140. // - name: token
  141. // in: path
  142. // description: token to be deleted, identified by ID and if not available by name
  143. // type: string
  144. // required: true
  145. // responses:
  146. // "204":
  147. // "$ref": "#/responses/empty"
  148. // "403":
  149. // "$ref": "#/responses/forbidden"
  150. // "404":
  151. // "$ref": "#/responses/notFound"
  152. // "422":
  153. // "$ref": "#/responses/error"
  154. token := ctx.PathParam("id")
  155. tokenID, _ := strconv.ParseInt(token, 0, 64)
  156. if tokenID == 0 {
  157. tokens, err := db.Find[auth_model.AccessToken](ctx, auth_model.ListAccessTokensOptions{
  158. Name: token,
  159. UserID: ctx.ContextUser.ID,
  160. })
  161. if err != nil {
  162. ctx.APIErrorInternal(err)
  163. return
  164. }
  165. switch len(tokens) {
  166. case 0:
  167. ctx.APIErrorNotFound()
  168. return
  169. case 1:
  170. tokenID = tokens[0].ID
  171. default:
  172. ctx.APIError(http.StatusUnprocessableEntity, fmt.Errorf("multiple matches for token name '%s'", token))
  173. return
  174. }
  175. }
  176. if tokenID == 0 {
  177. ctx.APIErrorInternal(nil)
  178. return
  179. }
  180. if err := auth_model.DeleteAccessTokenByID(ctx, tokenID, ctx.ContextUser.ID); err != nil {
  181. if auth_model.IsErrAccessTokenNotExist(err) {
  182. ctx.APIErrorNotFound()
  183. } else {
  184. ctx.APIErrorInternal(err)
  185. }
  186. return
  187. }
  188. ctx.Status(http.StatusNoContent)
  189. }
  190. // CreateOauth2Application is the handler to create a new OAuth2 Application for the authenticated user
  191. func CreateOauth2Application(ctx *context.APIContext) {
  192. // swagger:operation POST /user/applications/oauth2 user userCreateOAuth2Application
  193. // ---
  194. // summary: creates a new OAuth2 application
  195. // produces:
  196. // - application/json
  197. // parameters:
  198. // - name: body
  199. // in: body
  200. // required: true
  201. // schema:
  202. // "$ref": "#/definitions/CreateOAuth2ApplicationOptions"
  203. // responses:
  204. // "201":
  205. // "$ref": "#/responses/OAuth2Application"
  206. // "400":
  207. // "$ref": "#/responses/error"
  208. data := web.GetForm(ctx).(*api.CreateOAuth2ApplicationOptions)
  209. app, err := auth_model.CreateOAuth2Application(ctx, auth_model.CreateOAuth2ApplicationOptions{
  210. Name: data.Name,
  211. UserID: ctx.Doer.ID,
  212. RedirectURIs: data.RedirectURIs,
  213. ConfidentialClient: data.ConfidentialClient,
  214. SkipSecondaryAuthorization: data.SkipSecondaryAuthorization,
  215. })
  216. if err != nil {
  217. ctx.APIError(http.StatusBadRequest, "error creating oauth2 application")
  218. return
  219. }
  220. secret, err := app.GenerateClientSecret(ctx)
  221. if err != nil {
  222. ctx.APIError(http.StatusBadRequest, "error creating application secret")
  223. return
  224. }
  225. app.ClientSecret = secret
  226. ctx.JSON(http.StatusCreated, convert.ToOAuth2Application(app))
  227. }
  228. // ListOauth2Applications list all the Oauth2 application
  229. func ListOauth2Applications(ctx *context.APIContext) {
  230. // swagger:operation GET /user/applications/oauth2 user userGetOauth2Application
  231. // ---
  232. // summary: List the authenticated user's oauth2 applications
  233. // produces:
  234. // - application/json
  235. // parameters:
  236. // - name: page
  237. // in: query
  238. // description: page number of results to return (1-based)
  239. // type: integer
  240. // - name: limit
  241. // in: query
  242. // description: page size of results
  243. // type: integer
  244. // responses:
  245. // "200":
  246. // "$ref": "#/responses/OAuth2ApplicationList"
  247. apps, total, err := db.FindAndCount[auth_model.OAuth2Application](ctx, auth_model.FindOAuth2ApplicationsOptions{
  248. ListOptions: utils.GetListOptions(ctx),
  249. OwnerID: ctx.Doer.ID,
  250. })
  251. if err != nil {
  252. ctx.APIErrorInternal(err)
  253. return
  254. }
  255. apiApps := make([]*api.OAuth2Application, len(apps))
  256. for i := range apps {
  257. apiApps[i] = convert.ToOAuth2Application(apps[i])
  258. apiApps[i].ClientSecret = "" // Hide secret on application list
  259. }
  260. ctx.SetTotalCountHeader(total)
  261. ctx.JSON(http.StatusOK, &apiApps)
  262. }
  263. // DeleteOauth2Application delete OAuth2 Application
  264. func DeleteOauth2Application(ctx *context.APIContext) {
  265. // swagger:operation DELETE /user/applications/oauth2/{id} user userDeleteOAuth2Application
  266. // ---
  267. // summary: delete an OAuth2 Application
  268. // produces:
  269. // - application/json
  270. // parameters:
  271. // - name: id
  272. // in: path
  273. // description: token to be deleted
  274. // type: integer
  275. // format: int64
  276. // required: true
  277. // responses:
  278. // "204":
  279. // "$ref": "#/responses/empty"
  280. // "404":
  281. // "$ref": "#/responses/notFound"
  282. appID := ctx.PathParamInt64("id")
  283. if err := auth_model.DeleteOAuth2Application(ctx, appID, ctx.Doer.ID); err != nil {
  284. if auth_model.IsErrOAuthApplicationNotFound(err) {
  285. ctx.APIErrorNotFound()
  286. } else {
  287. ctx.APIErrorInternal(err)
  288. }
  289. return
  290. }
  291. ctx.Status(http.StatusNoContent)
  292. }
  293. // GetOauth2Application get OAuth2 Application
  294. func GetOauth2Application(ctx *context.APIContext) {
  295. // swagger:operation GET /user/applications/oauth2/{id} user userGetOAuth2Application
  296. // ---
  297. // summary: get an OAuth2 Application
  298. // produces:
  299. // - application/json
  300. // parameters:
  301. // - name: id
  302. // in: path
  303. // description: Application ID to be found
  304. // type: integer
  305. // format: int64
  306. // required: true
  307. // responses:
  308. // "200":
  309. // "$ref": "#/responses/OAuth2Application"
  310. // "404":
  311. // "$ref": "#/responses/notFound"
  312. appID := ctx.PathParamInt64("id")
  313. app, err := auth_model.GetOAuth2ApplicationByID(ctx, appID)
  314. if err != nil {
  315. if auth_model.IsErrOauthClientIDInvalid(err) || auth_model.IsErrOAuthApplicationNotFound(err) {
  316. ctx.APIErrorNotFound()
  317. } else {
  318. ctx.APIErrorInternal(err)
  319. }
  320. return
  321. }
  322. if app.UID != ctx.Doer.ID {
  323. ctx.APIErrorNotFound()
  324. return
  325. }
  326. app.ClientSecret = ""
  327. ctx.JSON(http.StatusOK, convert.ToOAuth2Application(app))
  328. }
  329. // UpdateOauth2Application update OAuth2 Application
  330. func UpdateOauth2Application(ctx *context.APIContext) {
  331. // swagger:operation PATCH /user/applications/oauth2/{id} user userUpdateOAuth2Application
  332. // ---
  333. // summary: update an OAuth2 Application, this includes regenerating the client secret
  334. // produces:
  335. // - application/json
  336. // parameters:
  337. // - name: id
  338. // in: path
  339. // description: application to be updated
  340. // type: integer
  341. // format: int64
  342. // required: true
  343. // - name: body
  344. // in: body
  345. // required: true
  346. // schema:
  347. // "$ref": "#/definitions/CreateOAuth2ApplicationOptions"
  348. // responses:
  349. // "200":
  350. // "$ref": "#/responses/OAuth2Application"
  351. // "404":
  352. // "$ref": "#/responses/notFound"
  353. appID := ctx.PathParamInt64("id")
  354. data := web.GetForm(ctx).(*api.CreateOAuth2ApplicationOptions)
  355. app, err := auth_model.UpdateOAuth2Application(ctx, auth_model.UpdateOAuth2ApplicationOptions{
  356. Name: data.Name,
  357. UserID: ctx.Doer.ID,
  358. ID: appID,
  359. RedirectURIs: data.RedirectURIs,
  360. ConfidentialClient: data.ConfidentialClient,
  361. SkipSecondaryAuthorization: data.SkipSecondaryAuthorization,
  362. })
  363. if err != nil {
  364. if auth_model.IsErrOauthClientIDInvalid(err) || auth_model.IsErrOAuthApplicationNotFound(err) {
  365. ctx.APIErrorNotFound()
  366. } else {
  367. ctx.APIErrorInternal(err)
  368. }
  369. return
  370. }
  371. app.ClientSecret, err = app.GenerateClientSecret(ctx)
  372. if err != nil {
  373. ctx.APIError(http.StatusBadRequest, "error updating application secret")
  374. return
  375. }
  376. ctx.JSON(http.StatusOK, convert.ToOAuth2Application(app))
  377. }