2014-11-18 19:07:16 +03:00
// Copyright 2014 The Gogs Authors. All rights reserved.
2018-07-07 04:54:30 +03:00
// Copyright 2018 The Gitea Authors. All rights reserved.
2014-11-18 19:07:16 +03:00
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
2015-12-05 01:16:42 +03:00
package user
2014-11-18 19:07:16 +03:00
import (
2020-04-13 22:02:48 +03:00
"errors"
2020-08-28 11:09:33 +03:00
"fmt"
2019-12-20 20:07:12 +03:00
"net/http"
2020-08-28 11:09:33 +03:00
"strconv"
2019-12-20 20:07:12 +03:00
2016-11-10 19:24:48 +03:00
"code.gitea.io/gitea/models"
2022-01-02 16:12:35 +03:00
"code.gitea.io/gitea/models/auth"
2016-11-10 19:24:48 +03:00
"code.gitea.io/gitea/modules/context"
2020-02-29 09:19:32 +03:00
"code.gitea.io/gitea/modules/convert"
2019-08-23 19:40:30 +03:00
api "code.gitea.io/gitea/modules/structs"
2021-01-26 18:36:53 +03:00
"code.gitea.io/gitea/modules/web"
2020-01-24 22:00:29 +03:00
"code.gitea.io/gitea/routers/api/v1/utils"
2014-11-18 19:07:16 +03:00
)
2016-11-24 10:04:31 +03:00
// ListAccessTokens list all the access tokens
2016-03-14 01:49:16 +03:00
func ListAccessTokens ( ctx * context . APIContext ) {
2017-11-13 10:02:25 +03:00
// swagger:operation GET /users/{username}/tokens user userGetTokens
// ---
// summary: List the authenticated user's access tokens
// produces:
// - application/json
2018-06-12 17:59:22 +03:00
// parameters:
// - name: username
// in: path
// description: username of user
// type: string
// required: true
2020-01-24 22:00:29 +03:00
// - name: page
// in: query
// description: page number of results to return (1-based)
// type: integer
// - name: limit
// in: query
2020-06-09 07:57:38 +03:00
// description: page size of results
2020-01-24 22:00:29 +03:00
// type: integer
2017-11-13 10:02:25 +03:00
// responses:
// "200":
// "$ref": "#/responses/AccessTokenList"
2019-12-20 20:07:12 +03:00
2022-03-22 10:03:22 +03:00
opts := models . ListAccessTokensOptions { UserID : ctx . Doer . ID , ListOptions : utils . GetListOptions ( ctx ) }
2021-08-12 15:43:08 +03:00
count , err := models . CountAccessTokens ( opts )
if err != nil {
ctx . InternalServerError ( err )
return
}
tokens , err := models . ListAccessTokens ( opts )
2014-11-18 19:07:16 +03:00
if err != nil {
2021-08-12 15:43:08 +03:00
ctx . InternalServerError ( err )
2014-11-18 19:07:16 +03:00
return
}
apiTokens := make ( [ ] * api . AccessToken , len ( tokens ) )
for i := range tokens {
2017-02-26 08:25:35 +03:00
apiTokens [ i ] = & api . AccessToken {
2019-05-04 18:45:34 +03:00
ID : tokens [ i ] . ID ,
Name : tokens [ i ] . Name ,
TokenLastEight : tokens [ i ] . TokenLastEight ,
2017-02-26 08:25:35 +03:00
}
2014-11-18 19:07:16 +03:00
}
2021-08-12 15:43:08 +03:00
ctx . SetTotalCountHeader ( count )
2019-12-20 20:07:12 +03:00
ctx . JSON ( http . StatusOK , & apiTokens )
2014-11-18 19:07:16 +03:00
}
2016-11-24 10:04:31 +03:00
// CreateAccessToken create access tokens
2021-01-26 18:36:53 +03:00
func CreateAccessToken ( ctx * context . APIContext ) {
2017-11-13 10:02:25 +03:00
// swagger:operation POST /users/{username}/tokens user userCreateToken
// ---
// summary: Create an access token
// consumes:
// - application/json
// produces:
// - application/json
2018-06-12 17:59:22 +03:00
// parameters:
// - name: username
// in: path
// description: username of user
// type: string
// required: true
2021-08-01 23:44:15 +03:00
// - name: userCreateToken
2018-10-21 06:40:42 +03:00
// in: body
// schema:
2021-08-01 23:44:15 +03:00
// "$ref": "#/definitions/CreateAccessTokenOption"
2017-11-13 10:02:25 +03:00
// responses:
2020-12-24 21:14:01 +03:00
// "201":
2017-11-13 10:02:25 +03:00
// "$ref": "#/responses/AccessToken"
2021-04-11 11:53:23 +03:00
// "400":
// "$ref": "#/responses/error"
2019-12-20 20:07:12 +03:00
2021-01-26 18:36:53 +03:00
form := web . GetForm ( ctx ) . ( * api . CreateAccessTokenOption )
2014-11-18 19:07:16 +03:00
t := & models . AccessToken {
2022-03-22 10:03:22 +03:00
UID : ctx . Doer . ID ,
2014-11-18 19:07:16 +03:00
Name : form . Name ,
}
2020-04-13 22:02:48 +03:00
exist , err := models . AccessTokenByNameExists ( t )
if err != nil {
ctx . InternalServerError ( err )
return
}
if exist {
ctx . Error ( http . StatusBadRequest , "AccessTokenByNameExists" , errors . New ( "access token name has been used already" ) )
return
}
2014-11-18 19:07:16 +03:00
if err := models . NewAccessToken ( t ) ; err != nil {
2019-12-20 20:07:12 +03:00
ctx . Error ( http . StatusInternalServerError , "NewAccessToken" , err )
2014-11-18 19:07:16 +03:00
return
}
2019-12-20 20:07:12 +03:00
ctx . JSON ( http . StatusCreated , & api . AccessToken {
2019-05-12 20:29:07 +03:00
Name : t . Name ,
Token : t . Token ,
ID : t . ID ,
TokenLastEight : t . TokenLastEight ,
2017-02-26 08:25:35 +03:00
} )
2014-11-18 19:07:16 +03:00
}
2018-07-07 04:54:30 +03:00
// DeleteAccessToken delete access tokens
func DeleteAccessToken ( ctx * context . APIContext ) {
// swagger:operation DELETE /users/{username}/tokens/{token} user userDeleteAccessToken
// ---
// summary: delete an access token
// produces:
// - application/json
// parameters:
// - name: username
// in: path
// description: username of user
// type: string
// required: true
// - name: token
// in: path
2020-08-28 11:09:33 +03:00
// description: token to be deleted, identified by ID and if not available by name
// type: string
2018-07-07 04:54:30 +03:00
// required: true
// responses:
// "204":
// "$ref": "#/responses/empty"
2021-04-11 11:53:23 +03:00
// "404":
// "$ref": "#/responses/notFound"
2020-08-28 11:09:33 +03:00
// "422":
// "$ref": "#/responses/error"
token := ctx . Params ( ":id" )
tokenID , _ := strconv . ParseInt ( token , 0 , 64 )
if tokenID == 0 {
tokens , err := models . ListAccessTokens ( models . ListAccessTokensOptions {
Name : token ,
2022-03-22 10:03:22 +03:00
UserID : ctx . Doer . ID ,
2020-08-28 11:09:33 +03:00
} )
if err != nil {
ctx . Error ( http . StatusInternalServerError , "ListAccessTokens" , err )
return
}
switch len ( tokens ) {
case 0 :
ctx . NotFound ( )
return
case 1 :
tokenID = tokens [ 0 ] . ID
default :
2021-07-08 14:38:13 +03:00
ctx . Error ( http . StatusUnprocessableEntity , "DeleteAccessTokenByID" , fmt . Errorf ( "multiple matches for token name '%s'" , token ) )
2020-08-28 11:09:33 +03:00
return
}
}
if tokenID == 0 {
ctx . Error ( http . StatusInternalServerError , "Invalid TokenID" , nil )
return
}
2019-12-20 20:07:12 +03:00
2022-03-22 10:03:22 +03:00
if err := models . DeleteAccessTokenByID ( tokenID , ctx . Doer . ID ) ; err != nil {
2018-07-07 04:54:30 +03:00
if models . IsErrAccessTokenNotExist ( err ) {
2019-03-19 05:29:43 +03:00
ctx . NotFound ( )
2018-07-07 04:54:30 +03:00
} else {
2019-12-20 20:07:12 +03:00
ctx . Error ( http . StatusInternalServerError , "DeleteAccessTokenByID" , err )
2018-07-07 04:54:30 +03:00
}
return
}
2019-12-20 20:07:12 +03:00
ctx . Status ( http . StatusNoContent )
2018-07-07 04:54:30 +03:00
}
2020-02-29 09:19:32 +03:00
// CreateOauth2Application is the handler to create a new OAuth2 Application for the authenticated user
2021-01-26 18:36:53 +03:00
func CreateOauth2Application ( ctx * context . APIContext ) {
2020-02-29 09:19:32 +03:00
// swagger:operation POST /user/applications/oauth2 user userCreateOAuth2Application
// ---
// summary: creates a new OAuth2 application
// produces:
// - application/json
// parameters:
// - name: body
// in: body
// required: true
// schema:
// "$ref": "#/definitions/CreateOAuth2ApplicationOptions"
// responses:
// "201":
// "$ref": "#/responses/OAuth2Application"
2021-04-11 11:53:23 +03:00
// "400":
// "$ref": "#/responses/error"
2021-01-26 18:36:53 +03:00
data := web . GetForm ( ctx ) . ( * api . CreateOAuth2ApplicationOptions )
2022-05-20 17:08:52 +03:00
app , err := auth . CreateOAuth2Application ( ctx , auth . CreateOAuth2ApplicationOptions {
2020-02-29 09:19:32 +03:00
Name : data . Name ,
2022-03-22 10:03:22 +03:00
UserID : ctx . Doer . ID ,
2020-02-29 09:19:32 +03:00
RedirectURIs : data . RedirectURIs ,
} )
if err != nil {
ctx . Error ( http . StatusBadRequest , "" , "error creating oauth2 application" )
return
}
secret , err := app . GenerateClientSecret ( )
if err != nil {
ctx . Error ( http . StatusBadRequest , "" , "error creating application secret" )
return
}
app . ClientSecret = secret
ctx . JSON ( http . StatusCreated , convert . ToOAuth2Application ( app ) )
}
// ListOauth2Applications list all the Oauth2 application
func ListOauth2Applications ( ctx * context . APIContext ) {
// swagger:operation GET /user/applications/oauth2 user userGetOauth2Application
// ---
// summary: List the authenticated user's oauth2 applications
// produces:
// - application/json
// parameters:
// - name: page
// in: query
// description: page number of results to return (1-based)
// type: integer
// - name: limit
// in: query
2020-06-09 07:57:38 +03:00
// description: page size of results
2020-02-29 09:19:32 +03:00
// type: integer
// responses:
// "200":
// "$ref": "#/responses/OAuth2ApplicationList"
2022-03-22 10:03:22 +03:00
apps , total , err := auth . ListOAuth2Applications ( ctx . Doer . ID , utils . GetListOptions ( ctx ) )
2020-02-29 09:19:32 +03:00
if err != nil {
ctx . Error ( http . StatusInternalServerError , "ListOAuth2Applications" , err )
return
}
apiApps := make ( [ ] * api . OAuth2Application , len ( apps ) )
for i := range apps {
apiApps [ i ] = convert . ToOAuth2Application ( apps [ i ] )
apiApps [ i ] . ClientSecret = "" // Hide secret on application list
}
2021-08-12 15:43:08 +03:00
ctx . SetTotalCountHeader ( total )
2020-02-29 09:19:32 +03:00
ctx . JSON ( http . StatusOK , & apiApps )
}
// DeleteOauth2Application delete OAuth2 Application
func DeleteOauth2Application ( ctx * context . APIContext ) {
// swagger:operation DELETE /user/applications/oauth2/{id} user userDeleteOAuth2Application
// ---
// summary: delete an OAuth2 Application
// produces:
// - application/json
// parameters:
// - name: id
// in: path
// description: token to be deleted
// type: integer
// format: int64
// required: true
// responses:
// "204":
// "$ref": "#/responses/empty"
2021-04-11 11:53:23 +03:00
// "404":
// "$ref": "#/responses/notFound"
2020-02-29 09:19:32 +03:00
appID := ctx . ParamsInt64 ( ":id" )
2022-03-22 10:03:22 +03:00
if err := auth . DeleteOAuth2Application ( appID , ctx . Doer . ID ) ; err != nil {
2022-01-02 16:12:35 +03:00
if auth . IsErrOAuthApplicationNotFound ( err ) {
2021-04-10 23:49:10 +03:00
ctx . NotFound ( )
} else {
ctx . Error ( http . StatusInternalServerError , "DeleteOauth2ApplicationByID" , err )
}
2020-02-29 09:19:32 +03:00
return
}
ctx . Status ( http . StatusNoContent )
}
2020-04-10 03:37:31 +03:00
// GetOauth2Application get OAuth2 Application
func GetOauth2Application ( ctx * context . APIContext ) {
// swagger:operation GET /user/applications/oauth2/{id} user userGetOAuth2Application
// ---
// summary: get an OAuth2 Application
// produces:
// - application/json
// parameters:
// - name: id
// in: path
// description: Application ID to be found
// type: integer
// format: int64
// required: true
// responses:
// "200":
// "$ref": "#/responses/OAuth2Application"
2021-04-11 11:53:23 +03:00
// "404":
// "$ref": "#/responses/notFound"
2020-04-10 03:37:31 +03:00
appID := ctx . ParamsInt64 ( ":id" )
2022-05-20 17:08:52 +03:00
app , err := auth . GetOAuth2ApplicationByID ( ctx , appID )
2020-04-10 03:37:31 +03:00
if err != nil {
2022-01-02 16:12:35 +03:00
if auth . IsErrOauthClientIDInvalid ( err ) || auth . IsErrOAuthApplicationNotFound ( err ) {
2020-04-10 03:37:31 +03:00
ctx . NotFound ( )
} else {
ctx . Error ( http . StatusInternalServerError , "GetOauth2ApplicationByID" , err )
}
return
}
app . ClientSecret = ""
ctx . JSON ( http . StatusOK , convert . ToOAuth2Application ( app ) )
}
// UpdateOauth2Application update OAuth2 Application
2021-01-26 18:36:53 +03:00
func UpdateOauth2Application ( ctx * context . APIContext ) {
2020-04-10 03:37:31 +03:00
// swagger:operation PATCH /user/applications/oauth2/{id} user userUpdateOAuth2Application
// ---
// summary: update an OAuth2 Application, this includes regenerating the client secret
// produces:
// - application/json
// parameters:
// - name: id
// in: path
// description: application to be updated
// type: integer
// format: int64
// required: true
// - name: body
// in: body
// required: true
// schema:
// "$ref": "#/definitions/CreateOAuth2ApplicationOptions"
// responses:
// "200":
// "$ref": "#/responses/OAuth2Application"
2021-04-11 11:53:23 +03:00
// "404":
// "$ref": "#/responses/notFound"
2020-04-10 03:37:31 +03:00
appID := ctx . ParamsInt64 ( ":id" )
2021-01-26 18:36:53 +03:00
data := web . GetForm ( ctx ) . ( * api . CreateOAuth2ApplicationOptions )
2022-01-02 16:12:35 +03:00
app , err := auth . UpdateOAuth2Application ( auth . UpdateOAuth2ApplicationOptions {
2020-04-10 03:37:31 +03:00
Name : data . Name ,
2022-03-22 10:03:22 +03:00
UserID : ctx . Doer . ID ,
2020-04-10 03:37:31 +03:00
ID : appID ,
RedirectURIs : data . RedirectURIs ,
} )
if err != nil {
2022-01-02 16:12:35 +03:00
if auth . IsErrOauthClientIDInvalid ( err ) || auth . IsErrOAuthApplicationNotFound ( err ) {
2020-04-10 03:37:31 +03:00
ctx . NotFound ( )
} else {
ctx . Error ( http . StatusInternalServerError , "UpdateOauth2ApplicationByID" , err )
}
return
}
2020-04-30 20:50:47 +03:00
app . ClientSecret , err = app . GenerateClientSecret ( )
2020-04-10 03:37:31 +03:00
if err != nil {
ctx . Error ( http . StatusBadRequest , "" , "error updating application secret" )
return
}
ctx . JSON ( http . StatusOK , convert . ToOAuth2Application ( app ) )
}