2015-12-04 17:16:42 -05:00
// Copyright 2015 The Gogs Authors. All rights reserved.
2018-11-28 19:26:14 +08:00
// Copyright 2016 The Gitea Authors. All rights reserved.
2022-11-27 13:20:29 -05:00
// SPDX-License-Identifier: MIT
2015-12-04 17:16:42 -05:00
2023-11-22 17:09:19 +09:00
// Package v1 Gitea API
2017-05-02 15:35:59 +02:00
//
2017-11-12 23:02:25 -08:00
// This documentation describes the Gitea API.
2017-05-02 15:35:59 +02:00
//
2024-02-18 17:52:02 +08:00
// Schemes: https, http
2022-08-30 21:15:45 -05:00
// License: MIT http://opensource.org/licenses/MIT
2017-05-02 15:35:59 +02:00
//
2022-08-30 21:15:45 -05:00
// Consumes:
// - application/json
// - text/plain
2017-05-02 15:35:59 +02:00
//
2022-08-30 21:15:45 -05:00
// Produces:
// - application/json
// - text/html
2017-05-02 15:35:59 +02:00
//
2022-08-30 21:15:45 -05:00
// Security:
// - BasicAuth :
// - Token :
// - AccessToken :
// - AuthorizationHeaderToken :
// - SudoParam :
// - SudoHeader :
// - TOTPHeader :
2017-08-21 13:13:47 +02:00
//
2022-08-30 21:15:45 -05:00
// SecurityDefinitions:
// BasicAuth:
// type: basic
// Token:
// type: apiKey
// name: token
// in: query
2023-12-11 22:48:53 -05:00
// description: This authentication option is deprecated for removal in Gitea 1.23. Please use AuthorizationHeaderToken instead.
2022-08-30 21:15:45 -05:00
// AccessToken:
// type: apiKey
// name: access_token
// in: query
2023-12-11 22:48:53 -05:00
// description: This authentication option is deprecated for removal in Gitea 1.23. Please use AuthorizationHeaderToken instead.
2022-08-30 21:15:45 -05:00
// AuthorizationHeaderToken:
// type: apiKey
// name: Authorization
// in: header
// description: API tokens must be prepended with "token" followed by a space.
// SudoParam:
// type: apiKey
// name: sudo
// in: query
// description: Sudo API request as the user provided as the key. Admin privileges are required.
// SudoHeader:
// type: apiKey
// name: Sudo
// in: header
// description: Sudo API request as the user provided as the key. Admin privileges are required.
// TOTPHeader:
// type: apiKey
// name: X-GITEA-OTP
// in: header
// description: Must be used in combination with BasicAuth if two-factor authentication is enabled.
2017-08-21 13:13:47 +02:00
//
2017-05-02 15:35:59 +02:00
// swagger:meta
2015-12-04 17:16:42 -05:00
package v1
import (
2025-04-29 06:31:59 +08:00
gocontext "context"
2025-02-18 04:41:03 +08:00
"errors"
2021-11-22 13:05:29 +00:00
"fmt"
2019-12-20 18:07:12 +01:00
"net/http"
2015-12-04 17:16:42 -05:00
"strings"
2023-01-17 16:46:03 -05:00
auth_model "code.gitea.io/gitea/models/auth"
2022-03-29 14:29:02 +08:00
"code.gitea.io/gitea/models/organization"
2022-03-30 10:42:47 +02:00
"code.gitea.io/gitea/models/perm"
2022-05-11 18:09:36 +08:00
access_model "code.gitea.io/gitea/models/perm/access"
2021-12-10 09:27:50 +08:00
repo_model "code.gitea.io/gitea/models/repo"
2021-11-10 03:57:58 +08:00
"code.gitea.io/gitea/models/unit"
2021-11-11 15:03:30 +08:00
user_model "code.gitea.io/gitea/models/user"
2025-08-28 11:52:43 +08:00
"code.gitea.io/gitea/modules/graceful"
2018-09-07 04:31:29 +01:00
"code.gitea.io/gitea/modules/log"
2018-02-14 05:46:00 +01:00
"code.gitea.io/gitea/modules/setting"
2019-05-11 18:21:34 +08:00
api "code.gitea.io/gitea/modules/structs"
2025-11-21 23:16:08 -08:00
"code.gitea.io/gitea/modules/util"
2021-01-26 23:36:53 +08:00
"code.gitea.io/gitea/modules/web"
2022-06-19 00:25:12 -05:00
"code.gitea.io/gitea/routers/api/v1/activitypub"
2016-11-10 17:24:48 +01:00
"code.gitea.io/gitea/routers/api/v1/admin"
"code.gitea.io/gitea/routers/api/v1/misc"
2020-01-09 12:56:32 +01:00
"code.gitea.io/gitea/routers/api/v1/notify"
2016-11-10 17:24:48 +01:00
"code.gitea.io/gitea/routers/api/v1/org"
2022-03-30 10:42:47 +02:00
"code.gitea.io/gitea/routers/api/v1/packages"
2016-11-10 17:24:48 +01:00
"code.gitea.io/gitea/routers/api/v1/repo"
2020-06-22 20:21:31 +02:00
"code.gitea.io/gitea/routers/api/v1/settings"
2016-11-10 17:24:48 +01:00
"code.gitea.io/gitea/routers/api/v1/user"
2023-09-12 08:15:16 +02:00
"code.gitea.io/gitea/routers/common"
2024-04-26 21:11:49 +08:00
"code.gitea.io/gitea/services/actions"
2021-06-10 01:53:16 +08:00
"code.gitea.io/gitea/services/auth"
2024-02-27 15:12:22 +08:00
"code.gitea.io/gitea/services/context"
2021-04-06 20:44:05 +01:00
"code.gitea.io/gitea/services/forms"
2017-11-12 23:02:25 -08:00
2021-11-17 20:34:35 +08:00
_ "code.gitea.io/gitea/routers/api/v1/swagger" // for swagger generation
2021-01-26 23:36:53 +08:00
"gitea.com/go-chi/binding"
"github.com/go-chi/cors"
2015-12-04 17:16:42 -05:00
)
2021-01-26 23:36:53 +08:00
func sudo ( ) func ( ctx * context . APIContext ) {
2018-09-07 04:31:29 +01:00
return func ( ctx * context . APIContext ) {
2021-08-11 02:31:13 +02:00
sudo := ctx . FormString ( "sudo" )
2018-10-20 23:25:14 +02:00
if len ( sudo ) == 0 {
2018-09-07 04:31:29 +01:00
sudo = ctx . Req . Header . Get ( "Sudo" )
}
if len ( sudo ) > 0 {
2022-03-22 08:03:22 +01:00
if ctx . IsSigned && ctx . Doer . IsAdmin {
2022-05-20 22:08:52 +08:00
user , err := user_model . GetUserByName ( ctx , sudo )
2018-09-07 04:31:29 +01:00
if err != nil {
2021-11-24 17:49:20 +08:00
if user_model . IsErrUserNotExist ( err ) {
2025-02-17 14:13:17 +08:00
ctx . APIErrorNotFound ( )
2018-09-07 04:31:29 +01:00
} else {
2025-02-18 04:41:03 +08:00
ctx . APIErrorInternal ( err )
2018-09-07 04:31:29 +01:00
}
return
}
2022-03-22 08:03:22 +01:00
log . Trace ( "Sudo from (%s) to: %s" , ctx . Doer . Name , user . Name )
ctx . Doer = user
2018-09-07 04:31:29 +01:00
} else {
2019-12-20 18:07:12 +01:00
ctx . JSON ( http . StatusForbidden , map [ string ] string {
2018-09-07 04:31:29 +01:00
"message" : "Only administrators allowed to sudo." ,
} )
return
}
}
}
}
2021-01-26 23:36:53 +08:00
func repoAssignment ( ) func ( ctx * context . APIContext ) {
2016-03-13 18:49:16 -04:00
return func ( ctx * context . APIContext ) {
2024-06-19 06:32:45 +08:00
userName := ctx . PathParam ( "username" )
repoName := ctx . PathParam ( "reponame" )
2015-12-04 17:16:42 -05:00
var (
2021-11-24 17:49:20 +08:00
owner * user_model . User
2015-12-04 17:16:42 -05:00
err error
)
// Check if the user is the same as the repository owner.
2025-07-06 18:53:34 +02:00
if ctx . IsSigned && strings . EqualFold ( ctx . Doer . LowerName , userName ) {
2022-03-22 08:03:22 +01:00
owner = ctx . Doer
2015-12-04 17:16:42 -05:00
} else {
2022-05-20 22:08:52 +08:00
owner , err = user_model . GetUserByName ( ctx , userName )
2015-12-04 17:16:42 -05:00
if err != nil {
2021-11-24 17:49:20 +08:00
if user_model . IsErrUserNotExist ( err ) {
2023-09-25 15:17:37 +02:00
if redirectUserID , err := user_model . LookupUserRedirect ( ctx , userName ) ; err == nil {
2025-12-13 18:14:18 -08:00
context . RedirectToUser ( ctx . Base , ctx . Doer , userName , redirectUserID )
2021-11-11 15:03:30 +08:00
} else if user_model . IsErrUserRedirectNotExist ( err ) {
2025-02-17 14:13:17 +08:00
ctx . APIErrorNotFound ( "GetUserByName" , err )
2021-01-24 10:23:05 -05:00
} else {
2025-02-18 04:41:03 +08:00
ctx . APIErrorInternal ( err )
2021-01-24 10:23:05 -05:00
}
2015-12-04 17:16:42 -05:00
} else {
2025-02-18 04:41:03 +08:00
ctx . APIErrorInternal ( err )
2015-12-04 17:16:42 -05:00
}
return
}
}
ctx . Repo . Owner = owner
2022-03-26 10:04:22 +01:00
ctx . ContextUser = owner
2015-12-04 17:16:42 -05:00
// Get repository.
2023-10-11 06:24:07 +02:00
repo , err := repo_model . GetRepositoryByName ( ctx , owner . ID , repoName )
2015-12-04 17:16:42 -05:00
if err != nil {
2021-12-10 09:27:50 +08:00
if repo_model . IsErrRepoNotExist ( err ) {
2023-10-14 10:37:24 +02:00
redirectRepoID , err := repo_model . LookupRedirect ( ctx , owner . ID , repoName )
2017-02-05 09:35:03 -05:00
if err == nil {
2023-05-21 09:50:53 +08:00
context . RedirectToRepo ( ctx . Base , redirectRepoID )
2021-12-12 23:48:20 +08:00
} else if repo_model . IsErrRedirectNotExist ( err ) {
2025-02-17 14:13:17 +08:00
ctx . APIErrorNotFound ( )
2017-02-05 09:35:03 -05:00
} else {
2025-02-18 04:41:03 +08:00
ctx . APIErrorInternal ( err )
2017-02-05 09:35:03 -05:00
}
2015-12-04 17:16:42 -05:00
} else {
2025-02-18 04:41:03 +08:00
ctx . APIErrorInternal ( err )
2015-12-04 17:16:42 -05:00
}
return
}
2019-04-26 02:59:10 +08:00
2017-02-02 07:33:56 -05:00
repo . Owner = owner
2018-11-28 19:26:14 +08:00
ctx . Repo . Repository = repo
2015-12-04 17:16:42 -05:00
2026-02-01 14:01:08 +08:00
if taskID , ok := user_model . GetActionsUserTaskID ( ctx . Doer ) ; ok {
2025-10-22 13:12:31 +02:00
ctx . Repo . Permission , err = access_model . GetActionsUserRepoPermission ( ctx , repo , ctx . Doer , taskID )
2023-01-31 09:45:19 +08:00
if err != nil {
2025-02-18 04:41:03 +08:00
ctx . APIErrorInternal ( err )
2023-01-31 09:45:19 +08:00
return
}
} else {
2025-04-29 06:31:59 +08:00
needTwoFactor , err := doerNeedTwoFactorAuth ( ctx , ctx . Doer )
2023-01-31 09:45:19 +08:00
if err != nil {
2025-02-18 04:41:03 +08:00
ctx . APIErrorInternal ( err )
2023-01-31 09:45:19 +08:00
return
}
2025-04-29 06:31:59 +08:00
if needTwoFactor {
ctx . Repo . Permission = access_model . PermissionNoAccess ( )
} else {
ctx . Repo . Permission , err = access_model . GetUserRepoPermission ( ctx , repo , ctx . Doer )
if err != nil {
ctx . APIErrorInternal ( err )
return
}
}
2015-12-04 17:16:42 -05:00
}
2025-06-25 14:55:19 +08:00
if ! ctx . Repo . Permission . HasAnyUnitAccessOrPublicAccess ( ) {
2025-02-17 14:13:17 +08:00
ctx . APIErrorNotFound ( )
2015-12-04 17:16:42 -05:00
return
}
}
}
2025-04-29 06:31:59 +08:00
func doerNeedTwoFactorAuth ( ctx gocontext . Context , doer * user_model . User ) ( bool , error ) {
if ! setting . TwoFactorAuthEnforced {
return false , nil
}
if doer == nil {
return false , nil
}
has , err := auth_model . HasTwoFactorOrWebAuthn ( ctx , doer . ID )
if err != nil {
return false , err
}
return ! has , nil
}
2022-03-30 10:42:47 +02:00
func reqPackageAccess ( accessMode perm . AccessMode ) func ( ctx * context . APIContext ) {
return func ( ctx * context . APIContext ) {
if ctx . Package . AccessMode < accessMode && ! ctx . IsUserSiteAdmin ( ) {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "user should have specific permission or be a site admin" )
2022-03-30 10:42:47 +02:00
return
}
}
}
2024-10-08 17:51:09 +08:00
func checkTokenPublicOnly ( ) func ( ctx * context . APIContext ) {
return func ( ctx * context . APIContext ) {
if ! ctx . PublicOnly {
return
}
requiredScopeCategories , ok := ctx . Data [ "requiredScopeCategories" ] . ( [ ] auth_model . AccessTokenScopeCategory )
if ! ok || len ( requiredScopeCategories ) == 0 {
return
}
// public Only permission check
switch {
case auth_model . ContainsCategory ( requiredScopeCategories , auth_model . AccessTokenScopeCategoryRepository ) :
if ctx . Repo . Repository != nil && ctx . Repo . Repository . IsPrivate {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "token scope is limited to public repos" )
2024-10-08 17:51:09 +08:00
return
}
case auth_model . ContainsCategory ( requiredScopeCategories , auth_model . AccessTokenScopeCategoryIssue ) :
if ctx . Repo . Repository != nil && ctx . Repo . Repository . IsPrivate {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "token scope is limited to public issues" )
2024-10-08 17:51:09 +08:00
return
}
case auth_model . ContainsCategory ( requiredScopeCategories , auth_model . AccessTokenScopeCategoryOrganization ) :
if ctx . Org . Organization != nil && ctx . Org . Organization . Visibility != api . VisibleTypePublic {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "token scope is limited to public orgs" )
2024-10-08 17:51:09 +08:00
return
}
if ctx . ContextUser != nil && ctx . ContextUser . IsOrganization ( ) && ctx . ContextUser . Visibility != api . VisibleTypePublic {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "token scope is limited to public orgs" )
2024-10-08 17:51:09 +08:00
return
}
case auth_model . ContainsCategory ( requiredScopeCategories , auth_model . AccessTokenScopeCategoryUser ) :
2025-02-07 09:41:55 +01:00
if ctx . ContextUser != nil && ctx . ContextUser . IsTokenAccessAllowed ( ) && ctx . ContextUser . Visibility != api . VisibleTypePublic {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "token scope is limited to public users" )
2024-10-08 17:51:09 +08:00
return
}
case auth_model . ContainsCategory ( requiredScopeCategories , auth_model . AccessTokenScopeCategoryActivityPub ) :
2025-02-07 09:41:55 +01:00
if ctx . ContextUser != nil && ctx . ContextUser . IsTokenAccessAllowed ( ) && ctx . ContextUser . Visibility != api . VisibleTypePublic {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "token scope is limited to public activitypub" )
2024-10-08 17:51:09 +08:00
return
}
case auth_model . ContainsCategory ( requiredScopeCategories , auth_model . AccessTokenScopeCategoryNotification ) :
if ctx . Repo . Repository != nil && ctx . Repo . Repository . IsPrivate {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "token scope is limited to public notifications" )
2024-10-08 17:51:09 +08:00
return
}
case auth_model . ContainsCategory ( requiredScopeCategories , auth_model . AccessTokenScopeCategoryPackage ) :
if ctx . Package != nil && ctx . Package . Owner . Visibility . IsPrivate ( ) {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "token scope is limited to public packages" )
2024-10-08 17:51:09 +08:00
return
}
}
}
}
2023-06-04 14:57:16 -04:00
// if a token is being used for auth, we check that it contains the required scope
// if a token is not being used, reqToken will enforce other sign in methods
func tokenRequiresScopes ( requiredScopeCategories ... auth_model . AccessTokenScopeCategory ) func ( ctx * context . APIContext ) {
return func ( ctx * context . APIContext ) {
// no scope required
if len ( requiredScopeCategories ) == 0 {
return
}
// Need OAuth2 token to be present.
scope , scopeExists := ctx . Data [ "ApiTokenScope" ] . ( auth_model . AccessTokenScope )
if ctx . Data [ "IsApiToken" ] != true || ! scopeExists {
return
}
// use the http method to determine the access level
requiredScopeLevel := auth_model . Read
2025-04-01 12:14:01 +02:00
if ctx . Req . Method == http . MethodPost || ctx . Req . Method == http . MethodPut || ctx . Req . Method == http . MethodPatch || ctx . Req . Method == http . MethodDelete {
2023-06-04 14:57:16 -04:00
requiredScopeLevel = auth_model . Write
}
// get the required scope for the given access level and category
requiredScopes := auth_model . GetRequiredScopes ( requiredScopeLevel , requiredScopeCategories ... )
2024-10-08 17:51:09 +08:00
allow , err := scope . HasScope ( requiredScopes ... )
2023-06-04 14:57:16 -04:00
if err != nil {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "checking scope failed: " + err . Error ( ) )
2023-06-04 14:57:16 -04:00
return
}
2024-10-08 17:51:09 +08:00
if ! allow {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , fmt . Sprintf ( "token does not have at least one of required scope(s), required=%v, token scope=%v" , requiredScopes , scope ) )
2023-06-04 14:57:16 -04:00
return
}
2024-10-08 17:51:09 +08:00
ctx . Data [ "requiredScopeCategories" ] = requiredScopeCategories
// check if scope only applies to public resources
publicOnly , err := scope . PublicOnly ( )
if err != nil {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "parsing public resource scope failed: " + err . Error ( ) )
2023-06-04 14:57:16 -04:00
return
}
2024-10-08 17:51:09 +08:00
// assign to true so that those searching should only filter public repositories/users/organizations
ctx . PublicOnly = publicOnly
2023-06-04 14:57:16 -04:00
}
}
2015-12-04 17:16:42 -05:00
// Contexter middleware already checks token for user sign in process.
2023-06-04 14:57:16 -04:00
func reqToken ( ) func ( ctx * context . APIContext ) {
2018-11-04 01:15:55 +00:00
return func ( ctx * context . APIContext ) {
2026-02-01 14:01:08 +08:00
// if a real user is signed in, or the user is from a Actions task, we are good
2018-11-04 01:15:55 +00:00
if ctx . IsSigned {
2015-12-04 17:16:42 -05:00
return
}
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusUnauthorized , "token is required" )
2015-12-04 17:16:42 -05:00
}
}
2021-03-11 13:40:54 +00:00
func reqExploreSignIn ( ) func ( ctx * context . APIContext ) {
return func ( ctx * context . APIContext ) {
2025-03-30 13:26:19 +08:00
if ( setting . Service . RequireSignInViewStrict || setting . Service . Explore . RequireSigninView ) && ! ctx . IsSigned {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusUnauthorized , "you must be signed in to search for users" )
2021-03-11 13:40:54 +00:00
}
}
}
2024-10-22 13:09:19 +08:00
func reqUsersExploreEnabled ( ) func ( ctx * context . APIContext ) {
return func ( ctx * context . APIContext ) {
if setting . Service . Explore . DisableUsersPage {
2025-02-17 14:13:17 +08:00
ctx . APIErrorNotFound ( )
2024-10-22 13:09:19 +08:00
}
}
}
2023-09-07 16:31:46 +08:00
func reqBasicOrRevProxyAuth ( ) func ( ctx * context . APIContext ) {
2019-04-19 04:59:26 -04:00
return func ( ctx * context . APIContext ) {
2023-09-07 16:31:46 +08:00
if ctx . IsSigned && setting . Service . EnableReverseProxyAuthAPI && ctx . Data [ "AuthedMethod" ] . ( string ) == auth . ReverseProxyMethodName {
return
}
2023-05-21 09:50:53 +08:00
if ! ctx . IsBasicAuth {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusUnauthorized , "auth required" )
2015-12-04 17:16:42 -05:00
return
}
}
}
2018-11-28 19:26:14 +08:00
// reqSiteAdmin user should be the site admin
2021-01-26 23:36:53 +08:00
func reqSiteAdmin ( ) func ( ctx * context . APIContext ) {
2020-11-14 17:13:55 +01:00
return func ( ctx * context . APIContext ) {
2019-04-07 22:49:34 +00:00
if ! ctx . IsUserSiteAdmin ( ) {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "user should be the site admin" )
2015-12-04 17:16:42 -05:00
return
}
}
}
2019-04-07 22:49:34 +00:00
// reqOwner user should be the owner of the repo or site admin.
2021-01-26 23:36:53 +08:00
func reqOwner ( ) func ( ctx * context . APIContext ) {
2020-11-14 17:13:55 +01:00
return func ( ctx * context . APIContext ) {
2023-05-09 07:30:14 +08:00
if ! ctx . Repo . IsOwner ( ) && ! ctx . IsUserSiteAdmin ( ) {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "user should be the owner of the repo" )
2018-11-28 19:26:14 +08:00
return
}
}
}
2023-09-18 08:21:15 +08:00
// reqSelfOrAdmin doer should be the same as the contextUser or site admin
func reqSelfOrAdmin ( ) func ( ctx * context . APIContext ) {
return func ( ctx * context . APIContext ) {
if ! ctx . IsUserSiteAdmin ( ) && ctx . ContextUser != ctx . Doer {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "doer should be the site admin or be same as the contextUser" )
2023-09-18 08:21:15 +08:00
return
}
}
}
2019-04-07 22:49:34 +00:00
// reqAdmin user should be an owner or a collaborator with admin write of a repository, or site admin
2021-01-26 23:36:53 +08:00
func reqAdmin ( ) func ( ctx * context . APIContext ) {
2020-11-14 17:13:55 +01:00
return func ( ctx * context . APIContext ) {
2019-04-07 22:49:34 +00:00
if ! ctx . IsUserRepoAdmin ( ) && ! ctx . IsUserSiteAdmin ( ) {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "user should be an owner or a collaborator with admin write of a repository" )
2018-11-28 19:26:14 +08:00
return
}
}
}
2019-04-07 22:49:34 +00:00
// reqRepoWriter user should have a permission to write to a repo, or be a site admin
2021-11-10 03:57:58 +08:00
func reqRepoWriter ( unitTypes ... unit . Type ) func ( ctx * context . APIContext ) {
2020-11-14 17:13:55 +01:00
return func ( ctx * context . APIContext ) {
2019-04-07 22:49:34 +00:00
if ! ctx . IsUserRepoWriter ( unitTypes ) && ! ctx . IsUserRepoAdmin ( ) && ! ctx . IsUserSiteAdmin ( ) {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "user should have a permission to write to a repo" )
2018-11-28 19:26:14 +08:00
return
}
}
}
2019-04-07 22:49:34 +00:00
// reqRepoReader user should have specific read permission or be a repo admin or a site admin
2021-11-10 03:57:58 +08:00
func reqRepoReader ( unitType unit . Type ) func ( ctx * context . APIContext ) {
2020-11-14 17:13:55 +01:00
return func ( ctx * context . APIContext ) {
2023-05-09 07:30:14 +08:00
if ! ctx . Repo . CanRead ( unitType ) && ! ctx . IsUserRepoAdmin ( ) && ! ctx . IsUserSiteAdmin ( ) {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "user should have specific read permission or be a repo admin or a site admin" )
2016-08-24 16:05:56 -07:00
return
}
}
}
2019-04-07 22:49:34 +00:00
// reqAnyRepoReader user should have any permission to read repository or permissions of site admin
2021-01-26 23:36:53 +08:00
func reqAnyRepoReader ( ) func ( ctx * context . APIContext ) {
2020-11-14 17:13:55 +01:00
return func ( ctx * context . APIContext ) {
2024-04-20 11:15:04 +08:00
if ! ctx . Repo . Permission . HasAnyUnitAccess ( ) && ! ctx . IsUserSiteAdmin ( ) {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "user should have any permission to read repository or permissions of site admin" )
2019-04-07 22:49:34 +00:00
return
2018-11-28 19:26:14 +08:00
}
}
}
2019-04-07 22:49:34 +00:00
// reqOrgOwnership user should be an organization owner, or a site admin
2021-01-26 23:36:53 +08:00
func reqOrgOwnership ( ) func ( ctx * context . APIContext ) {
2017-01-13 21:14:48 -05:00
return func ( ctx * context . APIContext ) {
2023-05-21 09:50:53 +08:00
if ctx . IsUserSiteAdmin ( ) {
2019-04-07 22:49:34 +00:00
return
}
2017-01-13 21:14:48 -05:00
var orgID int64
if ctx . Org . Organization != nil {
orgID = ctx . Org . Organization . ID
} else if ctx . Org . Team != nil {
orgID = ctx . Org . Team . OrgID
} else {
2025-02-18 04:41:03 +08:00
setting . PanicInDevOrTesting ( "reqOrgOwnership: unprepared context" )
ctx . APIErrorInternal ( errors . New ( "reqOrgOwnership: unprepared context" ) )
2017-01-13 21:14:48 -05:00
return
}
2022-03-29 14:29:02 +08:00
isOwner , err := organization . IsOrganizationOwner ( ctx , orgID , ctx . Doer . ID )
2019-04-07 22:49:34 +00:00
if err != nil {
2025-02-18 04:41:03 +08:00
ctx . APIErrorInternal ( err )
2017-12-20 23:43:26 -08:00
return
2019-04-07 22:49:34 +00:00
} else if ! isOwner {
2017-01-26 06:54:04 -05:00
if ctx . Org . Organization != nil {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "Must be an organization owner" )
2017-01-26 06:54:04 -05:00
} else {
2025-02-17 14:13:17 +08:00
ctx . APIErrorNotFound ( )
2017-01-26 06:54:04 -05:00
}
2017-01-13 21:14:48 -05:00
return
}
}
}
2019-04-24 13:32:35 +08:00
// reqTeamMembership user should be an team member, or a site admin
2021-01-26 23:36:53 +08:00
func reqTeamMembership ( ) func ( ctx * context . APIContext ) {
2019-04-24 13:32:35 +08:00
return func ( ctx * context . APIContext ) {
2023-05-21 09:50:53 +08:00
if ctx . IsUserSiteAdmin ( ) {
2019-04-24 13:32:35 +08:00
return
}
if ctx . Org . Team == nil {
2025-02-18 04:41:03 +08:00
setting . PanicInDevOrTesting ( "reqTeamMembership: unprepared context" )
ctx . APIErrorInternal ( errors . New ( "reqTeamMembership: unprepared context" ) )
2019-04-24 13:32:35 +08:00
return
}
2022-01-20 18:46:10 +01:00
orgID := ctx . Org . Team . OrgID
2022-03-29 14:29:02 +08:00
isOwner , err := organization . IsOrganizationOwner ( ctx , orgID , ctx . Doer . ID )
2019-04-24 13:32:35 +08:00
if err != nil {
2025-02-18 04:41:03 +08:00
ctx . APIErrorInternal ( err )
2019-04-24 13:32:35 +08:00
return
} else if isOwner {
return
}
2022-03-29 14:29:02 +08:00
if isTeamMember , err := organization . IsTeamMember ( ctx , orgID , ctx . Org . Team . ID , ctx . Doer . ID ) ; err != nil {
2025-02-18 04:41:03 +08:00
ctx . APIErrorInternal ( err )
2019-04-24 13:32:35 +08:00
return
} else if ! isTeamMember {
2022-03-29 14:29:02 +08:00
isOrgMember , err := organization . IsOrganizationMember ( ctx , orgID , ctx . Doer . ID )
2019-04-24 13:32:35 +08:00
if err != nil {
2025-02-18 04:41:03 +08:00
ctx . APIErrorInternal ( err )
2019-04-24 13:32:35 +08:00
} else if isOrgMember {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "Must be a team member" )
2019-04-24 13:32:35 +08:00
} else {
2025-02-17 14:13:17 +08:00
ctx . APIErrorNotFound ( )
2019-04-24 13:32:35 +08:00
}
return
}
}
}
2019-04-07 22:49:34 +00:00
// reqOrgMembership user should be an organization member, or a site admin
2021-01-26 23:36:53 +08:00
func reqOrgMembership ( ) func ( ctx * context . APIContext ) {
2017-01-13 21:14:48 -05:00
return func ( ctx * context . APIContext ) {
2023-05-21 09:50:53 +08:00
if ctx . IsUserSiteAdmin ( ) {
2019-04-07 22:49:34 +00:00
return
}
2017-01-13 21:14:48 -05:00
var orgID int64
if ctx . Org . Organization != nil {
orgID = ctx . Org . Organization . ID
} else if ctx . Org . Team != nil {
orgID = ctx . Org . Team . OrgID
} else {
2025-02-18 04:41:03 +08:00
setting . PanicInDevOrTesting ( "reqOrgMembership: unprepared context" )
ctx . APIErrorInternal ( errors . New ( "reqOrgMembership: unprepared context" ) )
2017-01-13 21:14:48 -05:00
return
}
2022-03-29 14:29:02 +08:00
if isMember , err := organization . IsOrganizationMember ( ctx , orgID , ctx . Doer . ID ) ; err != nil {
2025-02-18 04:41:03 +08:00
ctx . APIErrorInternal ( err )
2019-04-07 22:49:34 +00:00
return
} else if ! isMember {
2017-01-26 06:54:04 -05:00
if ctx . Org . Organization != nil {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "Must be an organization member" )
2017-01-26 06:54:04 -05:00
} else {
2025-02-17 14:13:17 +08:00
ctx . APIErrorNotFound ( )
2017-01-26 06:54:04 -05:00
}
2017-01-13 21:14:48 -05:00
return
}
}
}
2021-01-26 23:36:53 +08:00
func reqGitHook ( ) func ( ctx * context . APIContext ) {
2019-04-17 08:31:08 +03:00
return func ( ctx * context . APIContext ) {
2022-03-22 08:03:22 +01:00
if ! ctx . Doer . CanEditGitHook ( ) {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "must be allowed to edit Git hooks" )
2019-04-17 08:31:08 +03:00
return
}
}
}
2021-02-11 18:34:34 +01:00
// reqWebhooksEnabled requires webhooks to be enabled by admin.
func reqWebhooksEnabled ( ) func ( ctx * context . APIContext ) {
return func ( ctx * context . APIContext ) {
if setting . DisableWebhooks {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "webhooks disabled by administrator" )
2021-02-11 18:34:34 +01:00
return
}
}
}
2025-02-04 02:21:23 -03:00
// reqStarsEnabled requires Starring to be enabled in the config.
func reqStarsEnabled ( ) func ( ctx * context . APIContext ) {
return func ( ctx * context . APIContext ) {
if setting . Repository . DisableStars {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "stars disabled by administrator" )
2025-02-04 02:21:23 -03:00
return
}
}
}
2021-01-26 23:36:53 +08:00
func orgAssignment ( args ... bool ) func ( ctx * context . APIContext ) {
2016-03-25 18:04:02 -04:00
var (
2016-04-04 19:41:34 -04:00
assignOrg bool
2016-03-25 18:04:02 -04:00
assignTeam bool
)
if len ( args ) > 0 {
2016-04-04 19:41:34 -04:00
assignOrg = args [ 0 ]
}
if len ( args ) > 1 {
assignTeam = args [ 1 ]
2016-03-25 18:04:02 -04:00
}
return func ( ctx * context . APIContext ) {
2016-04-04 19:41:34 -04:00
ctx . Org = new ( context . APIOrganization )
var err error
if assignOrg {
2024-12-24 21:47:45 +08:00
ctx . Org . Organization , err = organization . GetOrgByName ( ctx , ctx . PathParam ( "org" ) )
2016-04-04 19:41:34 -04:00
if err != nil {
2022-03-29 14:29:02 +08:00
if organization . IsErrOrgNotExist ( err ) {
2024-12-24 21:47:45 +08:00
redirectUserID , err := user_model . LookupUserRedirect ( ctx , ctx . PathParam ( "org" ) )
2021-01-24 10:23:05 -05:00
if err == nil {
2025-12-13 18:14:18 -08:00
context . RedirectToUser ( ctx . Base , ctx . Doer , ctx . PathParam ( "org" ) , redirectUserID )
2021-11-11 15:03:30 +08:00
} else if user_model . IsErrUserRedirectNotExist ( err ) {
2025-02-17 14:13:17 +08:00
ctx . APIErrorNotFound ( "GetOrgByName" , err )
2021-01-24 10:23:05 -05:00
} else {
2025-02-18 04:41:03 +08:00
ctx . APIErrorInternal ( err )
2021-01-24 10:23:05 -05:00
}
2016-04-04 19:41:34 -04:00
} else {
2025-02-18 04:41:03 +08:00
ctx . APIErrorInternal ( err )
2016-04-04 19:41:34 -04:00
}
return
2016-03-25 18:04:02 -04:00
}
2022-03-26 10:04:22 +01:00
ctx . ContextUser = ctx . Org . Organization . AsUser ( )
2016-03-25 18:04:02 -04:00
}
if assignTeam {
2024-12-24 21:47:45 +08:00
ctx . Org . Team , err = organization . GetTeamByID ( ctx , ctx . PathParamInt64 ( "teamid" ) )
2016-03-25 18:04:02 -04:00
if err != nil {
2022-03-29 14:29:02 +08:00
if organization . IsErrTeamNotExist ( err ) {
2025-02-17 14:13:17 +08:00
ctx . APIErrorNotFound ( )
2016-03-25 18:04:02 -04:00
} else {
2025-02-18 04:41:03 +08:00
ctx . APIErrorInternal ( err )
2016-03-25 18:04:02 -04:00
}
return
}
}
}
}
2016-08-04 17:08:01 -07:00
func mustEnableIssues ( ctx * context . APIContext ) {
2021-11-10 03:57:58 +08:00
if ! ctx . Repo . CanRead ( unit . TypeIssues ) {
2019-04-22 21:40:51 +01:00
if log . IsTrace ( ) {
if ctx . IsSigned {
log . Trace ( "Permission Denied: User %-v cannot read %-v in Repo %-v\n" +
"User in Repo has Permissions: %-+v" ,
2022-03-22 08:03:22 +01:00
ctx . Doer ,
2021-11-10 03:57:58 +08:00
unit . TypeIssues ,
2019-04-22 21:40:51 +01:00
ctx . Repo . Repository ,
ctx . Repo . Permission )
} else {
log . Trace ( "Permission Denied: Anonymous user cannot read %-v in Repo %-v\n" +
"Anonymous user in Repo has Permissions: %-+v" ,
2021-11-10 03:57:58 +08:00
unit . TypeIssues ,
2019-04-22 21:40:51 +01:00
ctx . Repo . Repository ,
ctx . Repo . Permission )
}
}
2025-02-17 14:13:17 +08:00
ctx . APIErrorNotFound ( )
2016-08-04 16:32:02 -07:00
return
}
}
2019-03-18 21:29:43 -05:00
func mustAllowPulls ( ctx * context . APIContext ) {
2021-11-10 03:57:58 +08:00
if ! ( ctx . Repo . Repository . CanEnablePulls ( ) && ctx . Repo . CanRead ( unit . TypePullRequests ) ) {
2019-04-22 21:40:51 +01:00
if ctx . Repo . Repository . CanEnablePulls ( ) && log . IsTrace ( ) {
if ctx . IsSigned {
log . Trace ( "Permission Denied: User %-v cannot read %-v in Repo %-v\n" +
"User in Repo has Permissions: %-+v" ,
2022-03-22 08:03:22 +01:00
ctx . Doer ,
2021-11-10 03:57:58 +08:00
unit . TypePullRequests ,
2019-04-22 21:40:51 +01:00
ctx . Repo . Repository ,
ctx . Repo . Permission )
} else {
log . Trace ( "Permission Denied: Anonymous user cannot read %-v in Repo %-v\n" +
"Anonymous user in Repo has Permissions: %-+v" ,
2021-11-10 03:57:58 +08:00
unit . TypePullRequests ,
2019-04-22 21:40:51 +01:00
ctx . Repo . Repository ,
ctx . Repo . Permission )
}
}
2025-02-17 14:13:17 +08:00
ctx . APIErrorNotFound ( )
2016-12-02 12:10:39 +01:00
return
}
}
2019-03-18 21:29:43 -05:00
func mustEnableIssuesOrPulls ( ctx * context . APIContext ) {
2021-11-10 03:57:58 +08:00
if ! ctx . Repo . CanRead ( unit . TypeIssues ) &&
! ( ctx . Repo . Repository . CanEnablePulls ( ) && ctx . Repo . CanRead ( unit . TypePullRequests ) ) {
2019-04-22 21:40:51 +01:00
if ctx . Repo . Repository . CanEnablePulls ( ) && log . IsTrace ( ) {
if ctx . IsSigned {
log . Trace ( "Permission Denied: User %-v cannot read %-v and %-v in Repo %-v\n" +
"User in Repo has Permissions: %-+v" ,
2022-03-22 08:03:22 +01:00
ctx . Doer ,
2021-11-10 03:57:58 +08:00
unit . TypeIssues ,
unit . TypePullRequests ,
2019-04-22 21:40:51 +01:00
ctx . Repo . Repository ,
ctx . Repo . Permission )
} else {
log . Trace ( "Permission Denied: Anonymous user cannot read %-v and %-v in Repo %-v\n" +
"Anonymous user in Repo has Permissions: %-+v" ,
2021-11-10 03:57:58 +08:00
unit . TypeIssues ,
unit . TypePullRequests ,
2019-04-22 21:40:51 +01:00
ctx . Repo . Repository ,
ctx . Repo . Permission )
}
}
2025-02-17 14:13:17 +08:00
ctx . APIErrorNotFound ( )
2018-09-04 01:20:54 +08:00
return
}
}
2021-10-25 05:43:40 +02:00
func mustEnableWiki ( ctx * context . APIContext ) {
2021-11-10 03:57:58 +08:00
if ! ( ctx . Repo . CanRead ( unit . TypeWiki ) ) {
2025-02-17 14:13:17 +08:00
ctx . APIErrorNotFound ( )
2021-10-25 05:43:40 +02:00
return
}
}
2025-06-26 02:25:20 +08:00
// FIXME: for consistency, maybe most mustNotBeArchived checks should be replaced with mustEnableEditor
2019-03-18 21:29:43 -05:00
func mustNotBeArchived ( ctx * context . APIContext ) {
2019-01-30 18:20:40 +01:00
if ctx . Repo . Repository . IsArchived {
2025-06-26 02:25:20 +08:00
ctx . APIError ( http . StatusLocked , fmt . Errorf ( "%s is archived" , ctx . Repo . Repository . FullName ( ) ) )
return
}
}
func mustEnableEditor ( ctx * context . APIContext ) {
if ! ctx . Repo . Repository . CanEnableEditor ( ) {
ctx . APIError ( http . StatusLocked , fmt . Errorf ( "%s is not allowed to edit" , ctx . Repo . Repository . FullName ( ) ) )
2019-01-30 18:20:40 +01:00
return
}
}
2022-12-09 07:35:56 +01:00
func mustEnableAttachments ( ctx * context . APIContext ) {
if ! setting . Attachment . Enabled {
2025-02-17 14:13:17 +08:00
ctx . APIErrorNotFound ( )
2022-12-09 07:35:56 +01:00
return
}
}
2021-01-26 23:36:53 +08:00
// bind binding an obj to a func(ctx *context.APIContext)
2023-04-21 02:49:06 +08:00
func bind [ T any ] ( _ T ) any {
return func ( ctx * context . APIContext ) {
2022-12-12 16:09:26 +08:00
theObj := new ( T ) // create a new form obj for every request but not use obj directly
2021-01-26 23:36:53 +08:00
errs := binding . Bind ( ctx . Req , theObj )
if len ( errs ) > 0 {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusUnprocessableEntity , fmt . Sprintf ( "%s: %s" , errs [ 0 ] . FieldNames , errs [ 0 ] . Error ( ) ) )
2021-01-26 23:36:53 +08:00
return
}
web . SetForm ( ctx , theObj )
2023-04-21 02:49:06 +08:00
}
2021-01-26 23:36:53 +08:00
}
2015-12-04 17:16:42 -05:00
2022-03-28 12:46:28 +08:00
func buildAuthGroup ( ) * auth . Group {
group := auth . NewGroup (
& auth . OAuth2 { } ,
2022-06-05 09:16:14 +02:00
& auth . HTTPSign { } ,
2022-04-08 12:22:10 +08:00
& auth . Basic { } , // FIXME: this should be removed once we don't allow basic auth in API
2022-03-28 12:46:28 +08:00
)
2023-09-07 16:31:46 +08:00
if setting . Service . EnableReverseProxyAuthAPI {
group . Add ( & auth . ReverseProxy { } )
}
2023-09-18 07:32:56 +08:00
2025-08-28 11:52:43 +08:00
if setting . IsWindows && auth_model . IsSSPIEnabled ( graceful . GetManager ( ) . ShutdownContext ( ) ) {
2023-09-18 07:32:56 +08:00
group . Add ( & auth . SSPI { } ) // it MUST be the last, see the comment of SSPI
}
2022-03-28 12:46:28 +08:00
return group
}
2023-09-12 08:15:16 +02:00
func apiAuth ( authMethod auth . Method ) func ( * context . APIContext ) {
return func ( ctx * context . APIContext ) {
ar , err := common . AuthShared ( ctx . Base , nil , authMethod )
if err != nil {
2025-11-21 23:16:08 -08:00
msg , ok := auth . ErrAsUserAuthMessage ( err )
msg = util . Iif ( ok , msg , "invalid username, password or token" )
ctx . APIError ( http . StatusUnauthorized , msg )
2023-09-12 08:15:16 +02:00
return
}
ctx . Doer = ar . Doer
ctx . IsSigned = ar . Doer != nil
ctx . IsBasicAuth = ar . IsBasicAuth
}
}
// verifyAuthWithOptions checks authentication according to options
func verifyAuthWithOptions ( options * common . VerifyOptions ) func ( ctx * context . APIContext ) {
return func ( ctx * context . APIContext ) {
// Check prohibit login users.
if ctx . IsSigned {
if ! ctx . Doer . IsActive && setting . Service . RegisterEmailConfirm {
ctx . Data [ "Title" ] = ctx . Tr ( "auth.active_your_account" )
ctx . JSON ( http . StatusForbidden , map [ string ] string {
"message" : "This account is not activated." ,
} )
return
}
if ! ctx . Doer . IsActive || ctx . Doer . ProhibitLogin {
log . Info ( "Failed authentication attempt for %s from %s" , ctx . Doer . Name , ctx . RemoteAddr ( ) )
ctx . Data [ "Title" ] = ctx . Tr ( "auth.prohibit_login" )
ctx . JSON ( http . StatusForbidden , map [ string ] string {
"message" : "This account is prohibited from signing in, please contact your site administrator." ,
} )
return
}
if ctx . Doer . MustChangePassword {
ctx . JSON ( http . StatusForbidden , map [ string ] string {
"message" : "You must change your password. Change it at: " + setting . AppURL + "/user/change_password" ,
} )
return
}
}
// Redirect to dashboard if user tries to visit any non-login page.
if options . SignOutRequired && ctx . IsSigned && ctx . Req . URL . RequestURI ( ) != "/" {
ctx . Redirect ( setting . AppSubURL + "/" )
return
}
if options . SignInRequired {
if ! ctx . IsSigned {
// Restrict API calls with error message.
ctx . JSON ( http . StatusForbidden , map [ string ] string {
"message" : "Only signed in user is allowed to call APIs." ,
} )
return
} else if ! ctx . Doer . IsActive && setting . Service . RegisterEmailConfirm {
ctx . Data [ "Title" ] = ctx . Tr ( "auth.active_your_account" )
ctx . JSON ( http . StatusForbidden , map [ string ] string {
"message" : "This account is not activated." ,
} )
return
}
}
if options . AdminRequired {
if ! ctx . Doer . IsAdmin {
ctx . JSON ( http . StatusForbidden , map [ string ] string {
"message" : "You have no permission to request for this." ,
} )
return
}
}
}
}
2023-12-12 13:01:17 +08:00
func individualPermsChecker ( ctx * context . APIContext ) {
// org permissions have been checked in context.OrgAssignment(), but individual permissions haven't been checked.
if ctx . ContextUser . IsIndividual ( ) {
2025-03-29 22:32:28 +01:00
switch ctx . ContextUser . Visibility {
case api . VisibleTypePrivate :
2023-12-12 13:01:17 +08:00
if ctx . Doer == nil || ( ctx . ContextUser . ID != ctx . Doer . ID && ! ctx . Doer . IsAdmin ) {
2025-02-17 14:13:17 +08:00
ctx . APIErrorNotFound ( "Visit Project" , nil )
2023-12-12 13:01:17 +08:00
return
}
2025-03-29 22:32:28 +01:00
case api . VisibleTypeLimited :
2023-12-12 13:01:17 +08:00
if ctx . Doer == nil {
2025-02-17 14:13:17 +08:00
ctx . APIErrorNotFound ( "Visit Project" , nil )
2023-12-12 13:01:17 +08:00
return
}
}
}
}
2023-12-11 22:48:53 -05:00
// check for and warn against deprecated authentication options
func checkDeprecatedAuthMethods ( ctx * context . APIContext ) {
if ctx . FormString ( "token" ) != "" || ctx . FormString ( "access_token" ) != "" {
2024-02-12 13:04:10 +08:00
ctx . Resp . Header ( ) . Set ( "X-Gitea-Warning" , "token and access_token API authentication is deprecated and will be removed in gitea 1.23. Please use AuthorizationHeaderToken instead. Existing queries will continue to work but without authorization." )
2023-12-11 22:48:53 -05:00
}
}
2021-01-26 23:36:53 +08:00
// Routes registers all v1 APIs routes to web application.
2024-06-19 06:32:45 +08:00
func Routes ( ) * web . Router {
m := web . NewRouter ( )
2021-01-26 23:36:53 +08:00
m . Use ( securityHeaders ( ) )
if setting . CORSConfig . Enabled {
m . Use ( cors . Handler ( cors . Options {
2023-12-25 20:13:18 +08:00
AllowedOrigins : setting . CORSConfig . AllowDomain ,
2021-01-26 23:36:53 +08:00
AllowedMethods : setting . CORSConfig . Methods ,
AllowCredentials : setting . CORSConfig . AllowCredentials ,
2022-11-11 01:39:27 -05:00
AllowedHeaders : append ( [ ] string { "Authorization" , "X-Gitea-OTP" } , setting . CORSConfig . Headers ... ) ,
2021-01-26 23:36:53 +08:00
MaxAge : int ( setting . CORSConfig . MaxAge . Seconds ( ) ) ,
} ) )
2018-02-14 05:46:00 +01:00
}
2021-01-26 23:36:53 +08:00
m . Use ( context . APIContexter ( ) )
2021-01-28 01:46:35 +08:00
2023-12-11 22:48:53 -05:00
m . Use ( checkDeprecatedAuthMethods )
2021-06-10 01:53:16 +08:00
// Get user from session if logged in.
2023-09-12 08:15:16 +02:00
m . Use ( apiAuth ( buildAuthGroup ( ) ) )
2021-06-10 01:53:16 +08:00
2023-09-12 08:15:16 +02:00
m . Use ( verifyAuthWithOptions ( & common . VerifyOptions {
2025-03-30 13:26:19 +08:00
SignInRequired : setting . Service . RequireSignInViewStrict ,
2021-01-26 23:36:53 +08:00
} ) )
2017-10-21 16:05:50 +02:00
2024-04-26 21:11:49 +08:00
addActionsRoutes := func (
2024-06-19 06:32:45 +08:00
m * web . Router ,
2024-04-26 21:11:49 +08:00
reqChecker func ( ctx * context . APIContext ) ,
act actions . API ,
) {
m . Group ( "/actions" , func ( ) {
m . Group ( "/secrets" , func ( ) {
m . Get ( "" , reqToken ( ) , reqChecker , act . ListActionsSecrets )
m . Combo ( "/{secretname}" ) .
Put ( reqToken ( ) , reqChecker , bind ( api . CreateOrUpdateSecretOption { } ) , act . CreateOrUpdateSecret ) .
Delete ( reqToken ( ) , reqChecker , act . DeleteSecret )
} )
m . Group ( "/variables" , func ( ) {
m . Get ( "" , reqToken ( ) , reqChecker , act . ListVariables )
m . Combo ( "/{variablename}" ) .
Get ( reqToken ( ) , reqChecker , act . GetVariable ) .
Delete ( reqToken ( ) , reqChecker , act . DeleteVariable ) .
Post ( reqToken ( ) , reqChecker , bind ( api . CreateVariableOption { } ) , act . CreateVariable ) .
Put ( reqToken ( ) , reqChecker , bind ( api . UpdateVariableOption { } ) , act . UpdateVariable )
} )
m . Group ( "/runners" , func ( ) {
2025-04-18 17:22:41 +02:00
m . Get ( "" , reqToken ( ) , reqChecker , act . ListRunners )
2024-04-26 21:11:49 +08:00
m . Get ( "/registration-token" , reqToken ( ) , reqChecker , act . GetRegistrationToken )
2025-04-18 17:22:41 +02:00
m . Post ( "/registration-token" , reqToken ( ) , reqChecker , act . CreateRegistrationToken )
m . Get ( "/{runner_id}" , reqToken ( ) , reqChecker , act . GetRunner )
m . Delete ( "/{runner_id}" , reqToken ( ) , reqChecker , act . DeleteRunner )
2024-04-26 21:11:49 +08:00
} )
2025-06-20 14:14:00 +02:00
m . Get ( "/runs" , reqToken ( ) , reqChecker , act . ListWorkflowRuns )
m . Get ( "/jobs" , reqToken ( ) , reqChecker , act . ListWorkflowJobs )
2024-04-26 21:11:49 +08:00
} )
}
2021-01-26 23:36:53 +08:00
m . Group ( "" , func ( ) {
2023-01-17 16:46:03 -05:00
// Miscellaneous (no scope required)
2018-07-28 02:19:01 +02:00
if setting . API . EnableSwagger {
2021-01-26 23:36:53 +08:00
m . Get ( "/swagger" , func ( ctx * context . APIContext ) {
2021-10-16 11:34:07 +08:00
ctx . Redirect ( setting . AppSubURL + "/api/swagger" )
2021-01-26 23:36:53 +08:00
} )
2018-02-14 05:46:00 +01:00
}
2023-06-04 14:57:16 -04:00
2021-09-27 19:38:06 -04:00
if setting . Federation . Enabled {
m . Get ( "/nodeinfo" , misc . NodeInfo )
2022-06-19 00:25:12 -05:00
m . Group ( "/activitypub" , func ( ) {
2023-04-04 10:08:23 +08:00
// deprecated, remove in 1.20, use /user-id/{user-id} instead
2022-06-19 00:25:12 -05:00
m . Group ( "/user/{username}" , func ( ) {
m . Get ( "" , activitypub . Person )
m . Post ( "/inbox" , activitypub . ReqHTTPSignature ( ) , activitypub . PersonInbox )
2024-10-08 17:51:09 +08:00
} , context . UserAssignmentAPI ( ) , checkTokenPublicOnly ( ) )
2023-04-04 10:08:23 +08:00
m . Group ( "/user-id/{user-id}" , func ( ) {
m . Get ( "" , activitypub . Person )
m . Post ( "/inbox" , activitypub . ReqHTTPSignature ( ) , activitypub . PersonInbox )
2024-10-08 17:51:09 +08:00
} , context . UserIDAssignmentAPI ( ) , checkTokenPublicOnly ( ) )
2023-06-04 14:57:16 -04:00
} , tokenRequiresScopes ( auth_model . AccessTokenScopeCategoryActivityPub ) )
2021-09-27 19:38:06 -04:00
}
2015-12-04 17:16:42 -05:00
2023-07-26 10:53:31 +08:00
// Misc (public accessible)
2023-06-04 14:57:16 -04:00
m . Group ( "" , func ( ) {
m . Get ( "/version" , misc . Version )
2025-06-11 12:32:55 +02:00
m . Get ( "/signing-key.gpg" , misc . SigningKeyGPG )
m . Get ( "/signing-key.pub" , misc . SigningKeySSH )
2023-06-04 14:57:16 -04:00
m . Post ( "/markup" , reqToken ( ) , bind ( api . MarkupOption { } ) , misc . Markup )
m . Post ( "/markdown" , reqToken ( ) , bind ( api . MarkdownOption { } ) , misc . Markdown )
m . Post ( "/markdown/raw" , reqToken ( ) , misc . MarkdownRaw )
m . Get ( "/gitignore/templates" , misc . ListGitignoresTemplates )
m . Get ( "/gitignore/templates/{name}" , misc . GetGitignoreTemplateInfo )
m . Get ( "/licenses" , misc . ListLicenseTemplates )
m . Get ( "/licenses/{name}" , misc . GetLicenseTemplateInfo )
m . Get ( "/label/templates" , misc . ListLabelTemplates )
m . Get ( "/label/templates/{name}" , misc . GetLabelTemplate )
m . Group ( "/settings" , func ( ) {
m . Get ( "/ui" , settings . GetGeneralUISettings )
m . Get ( "/api" , settings . GetGeneralAPISettings )
m . Get ( "/attachment" , settings . GetGeneralAttachmentSettings )
m . Get ( "/repository" , settings . GetGeneralRepoSettings )
} )
2023-07-26 10:53:31 +08:00
} )
2023-06-04 14:57:16 -04:00
// Notifications (requires 'notifications' scope)
2020-01-09 12:56:32 +01:00
m . Group ( "/notifications" , func ( ) {
m . Combo ( "" ) .
2023-09-05 16:43:34 +02:00
Get ( reqToken ( ) , notify . ListNotifications ) .
2023-06-28 22:26:56 +08:00
Put ( reqToken ( ) , notify . ReadNotifications )
2023-09-05 16:43:34 +02:00
m . Get ( "/new" , reqToken ( ) , notify . NewAvailable )
2021-01-26 23:36:53 +08:00
m . Combo ( "/threads/{id}" ) .
2023-09-05 16:43:34 +02:00
Get ( reqToken ( ) , notify . GetThread ) .
2023-06-28 22:26:56 +08:00
Patch ( reqToken ( ) , notify . ReadThread )
2023-06-04 14:57:16 -04:00
} , tokenRequiresScopes ( auth_model . AccessTokenScopeCategoryNotification ) )
2020-01-09 12:56:32 +01:00
2023-06-04 14:57:16 -04:00
// Users (requires user scope)
2015-12-04 17:16:42 -05:00
m . Group ( "/users" , func ( ) {
2024-10-22 13:09:19 +08:00
m . Get ( "/search" , reqExploreSignIn ( ) , reqUsersExploreEnabled ( ) , user . Search )
2015-12-04 17:16:42 -05:00
2021-01-26 23:36:53 +08:00
m . Group ( "/{username}" , func ( ) {
2021-03-11 13:40:54 +00:00
m . Get ( "" , reqExploreSignIn ( ) , user . GetInfo )
2021-01-26 23:36:53 +08:00
if setting . Service . EnableUserHeatmap {
m . Get ( "/heatmap" , user . GetUserHeatmapData )
}
2015-12-04 17:16:42 -05:00
2023-06-04 14:57:16 -04:00
m . Get ( "/repos" , tokenRequiresScopes ( auth_model . AccessTokenScopeCategoryRepository ) , reqExploreSignIn ( ) , user . ListUserRepos )
2015-12-04 17:16:42 -05:00
m . Group ( "/tokens" , func ( ) {
m . Combo ( "" ) . Get ( user . ListAccessTokens ) .
2023-06-04 14:57:16 -04:00
Post ( bind ( api . CreateAccessTokenOption { } ) , reqToken ( ) , user . CreateAccessToken )
m . Combo ( "/{id}" ) . Delete ( reqToken ( ) , user . DeleteAccessToken )
2023-09-18 08:21:15 +08:00
} , reqSelfOrAdmin ( ) , reqBasicOrRevProxyAuth ( ) )
2023-04-04 21:35:31 +08:00
m . Get ( "/activities/feeds" , user . ListUserActivityFeeds )
2024-10-08 17:51:09 +08:00
} , context . UserAssignmentAPI ( ) , checkTokenPublicOnly ( ) , individualPermsChecker )
2023-06-04 14:57:16 -04:00
} , tokenRequiresScopes ( auth_model . AccessTokenScopeCategoryUser ) )
2015-12-04 17:16:42 -05:00
2023-06-04 14:57:16 -04:00
// Users (requires user scope)
2015-12-04 17:16:42 -05:00
m . Group ( "/users" , func ( ) {
2021-01-26 23:36:53 +08:00
m . Group ( "/{username}" , func ( ) {
2015-12-05 17:13:13 -05:00
m . Get ( "/keys" , user . ListPublicKeys )
2017-03-16 02:27:35 +01:00
m . Get ( "/gpg_keys" , user . ListGPGKeys )
2015-12-21 04:24:11 -08:00
m . Get ( "/followers" , user . ListFollowers )
m . Group ( "/following" , func ( ) {
m . Get ( "" , user . ListFollowing )
2021-01-26 23:36:53 +08:00
m . Get ( "/{target}" , user . CheckFollowing )
2015-12-21 04:24:11 -08:00
} )
2016-11-14 17:33:58 -05:00
2025-02-04 02:21:23 -03:00
m . Get ( "/starred" , reqStarsEnabled ( ) , user . GetStarredRepos )
2016-12-23 20:53:11 -05:00
m . Get ( "/subscriptions" , user . GetWatchedRepos )
2024-10-08 17:51:09 +08:00
} , context . UserAssignmentAPI ( ) , checkTokenPublicOnly ( ) )
2023-06-04 14:57:16 -04:00
} , tokenRequiresScopes ( auth_model . AccessTokenScopeCategoryUser ) , reqToken ( ) )
2015-12-04 17:16:42 -05:00
2023-06-04 14:57:16 -04:00
// Users (requires user scope)
2015-12-04 17:16:42 -05:00
m . Group ( "/user" , func ( ) {
2016-08-11 15:29:39 -07:00
m . Get ( "" , user . GetAuthenticatedUser )
2021-06-23 21:58:44 +02:00
m . Group ( "/settings" , func ( ) {
2023-06-04 14:57:16 -04:00
m . Get ( "" , user . GetUserSettings )
m . Patch ( "" , bind ( api . UserSettingsOptions { } ) , user . UpdateUserSettings )
} , reqToken ( ) )
m . Combo ( "/emails" ) .
Get ( user . ListEmails ) .
Post ( bind ( api . CreateEmailOption { } ) , user . AddEmail ) .
Delete ( bind ( api . DeleteEmailOption { } ) , user . DeleteEmail )
2015-12-21 04:24:11 -08:00
2023-12-27 15:57:54 +08:00
// manage user-level actions features
m . Group ( "/actions" , func ( ) {
m . Group ( "/secrets" , func ( ) {
m . Combo ( "/{secretname}" ) .
Put ( bind ( api . CreateOrUpdateSecretOption { } ) , user . CreateOrUpdateSecret ) .
Delete ( user . DeleteSecret )
} )
2024-03-29 04:40:35 +08:00
m . Group ( "/variables" , func ( ) {
m . Get ( "" , user . ListVariables )
m . Combo ( "/{variablename}" ) .
Get ( user . GetVariable ) .
Delete ( user . DeleteVariable ) .
Post ( bind ( api . CreateVariableOption { } ) , user . CreateVariable ) .
Put ( bind ( api . UpdateVariableOption { } ) , user . UpdateVariable )
} )
2023-12-27 15:57:54 +08:00
m . Group ( "/runners" , func ( ) {
2025-04-18 17:22:41 +02:00
m . Get ( "" , reqToken ( ) , user . ListRunners )
2023-12-27 15:57:54 +08:00
m . Get ( "/registration-token" , reqToken ( ) , user . GetRegistrationToken )
2025-04-18 17:22:41 +02:00
m . Post ( "/registration-token" , reqToken ( ) , user . CreateRegistrationToken )
m . Get ( "/{runner_id}" , reqToken ( ) , user . GetRunner )
m . Delete ( "/{runner_id}" , reqToken ( ) , user . DeleteRunner )
2023-12-27 15:57:54 +08:00
} )
2025-06-20 14:14:00 +02:00
m . Get ( "/runs" , reqToken ( ) , user . ListWorkflowRuns )
m . Get ( "/jobs" , reqToken ( ) , user . ListWorkflowJobs )
2023-09-05 22:02:50 +08:00
} )
2015-12-21 04:24:11 -08:00
m . Get ( "/followers" , user . ListMyFollowers )
m . Group ( "/following" , func ( ) {
m . Get ( "" , user . ListMyFollowing )
2022-03-26 10:04:22 +01:00
m . Group ( "/{username}" , func ( ) {
m . Get ( "" , user . CheckMyFollowing )
2023-06-04 14:57:16 -04:00
m . Put ( "" , user . Follow )
m . Delete ( "" , user . Unfollow )
2024-02-27 15:12:22 +08:00
} , context . UserAssignmentAPI ( ) )
2015-12-21 04:24:11 -08:00
} )
2023-01-17 16:46:03 -05:00
// (admin:public_key scope)
2015-12-04 17:16:42 -05:00
m . Group ( "/keys" , func ( ) {
2023-06-04 14:57:16 -04:00
m . Combo ( "" ) . Get ( user . ListMyPublicKeys ) .
Post ( bind ( api . CreateKeyOption { } ) , user . CreatePublicKey )
m . Combo ( "/{id}" ) . Get ( user . GetPublicKey ) .
Delete ( user . DeletePublicKey )
2015-12-04 17:16:42 -05:00
} )
2023-01-17 16:46:03 -05:00
// (admin:application scope)
2020-02-29 07:19:32 +01:00
m . Group ( "/applications" , func ( ) {
m . Combo ( "/oauth2" ) .
2023-06-04 14:57:16 -04:00
Get ( user . ListOauth2Applications ) .
Post ( bind ( api . CreateOAuth2ApplicationOptions { } ) , user . CreateOauth2Application )
2021-01-26 23:36:53 +08:00
m . Combo ( "/oauth2/{id}" ) .
2023-06-04 14:57:16 -04:00
Delete ( user . DeleteOauth2Application ) .
Patch ( bind ( api . CreateOAuth2ApplicationOptions { } ) , user . UpdateOauth2Application ) .
Get ( user . GetOauth2Application )
2023-01-17 16:46:03 -05:00
} )
2016-11-14 17:33:58 -05:00
2023-01-17 16:46:03 -05:00
// (admin:gpg_key scope)
2017-03-16 02:27:35 +01:00
m . Group ( "/gpg_keys" , func ( ) {
2023-06-04 14:57:16 -04:00
m . Combo ( "" ) . Get ( user . ListMyGPGKeys ) .
Post ( bind ( api . CreateGPGKeyOption { } ) , user . CreateGPGKey )
m . Combo ( "/{id}" ) . Get ( user . GetGPGKey ) .
Delete ( user . DeleteGPGKey )
2017-03-16 02:27:35 +01:00
} )
2023-06-04 14:57:16 -04:00
m . Get ( "/gpg_key_token" , user . GetVerificationToken )
m . Post ( "/gpg_key_verify" , bind ( api . VerifyGPGKeyOption { } ) , user . VerifyUserGPGKey )
2017-03-16 02:27:35 +01:00
2023-01-17 16:46:03 -05:00
// (repo scope)
2023-06-04 14:57:16 -04:00
m . Combo ( "/repos" , tokenRequiresScopes ( auth_model . AccessTokenScopeCategoryRepository ) ) . Get ( user . ListMyRepos ) .
2017-02-24 16:39:49 -05:00
Post ( bind ( api . CreateRepoOption { } ) , repo . Create )
2023-01-17 16:46:03 -05:00
// (repo scope)
2016-11-14 17:33:58 -05:00
m . Group ( "/starred" , func ( ) {
m . Get ( "" , user . GetMyStarredRepos )
2021-01-26 23:36:53 +08:00
m . Group ( "/{username}/{reponame}" , func ( ) {
2016-11-14 17:33:58 -05:00
m . Get ( "" , user . IsStarring )
m . Put ( "" , user . Star )
m . Delete ( "" , user . Unstar )
2024-10-08 17:51:09 +08:00
} , repoAssignment ( ) , checkTokenPublicOnly ( ) )
2025-02-04 02:21:23 -03:00
} , reqStarsEnabled ( ) , tokenRequiresScopes ( auth_model . AccessTokenScopeCategoryRepository ) )
2023-06-04 14:57:16 -04:00
m . Get ( "/times" , repo . ListMyTrackedTimes )
m . Get ( "/stopwatches" , repo . GetStopwatches )
m . Get ( "/subscriptions" , user . GetMyWatchedRepos )
m . Get ( "/teams" , org . ListUserTeams )
2023-03-10 15:28:32 +01:00
m . Group ( "/hooks" , func ( ) {
m . Combo ( "" ) . Get ( user . ListHooks ) .
Post ( bind ( api . CreateHookOption { } ) , user . CreateHook )
m . Combo ( "/{id}" ) . Get ( user . GetHook ) .
Patch ( bind ( api . EditHookOption { } ) , user . EditHook ) .
Delete ( user . DeleteHook )
2023-06-04 14:57:16 -04:00
} , reqWebhooksEnabled ( ) )
2023-06-30 01:22:55 +02:00
m . Group ( "/avatar" , func ( ) {
m . Post ( "" , bind ( api . UpdateUserAvatarOption { } ) , user . UpdateAvatar )
m . Delete ( "" , user . DeleteAvatar )
2024-03-04 09:16:03 +01:00
} )
m . Group ( "/blocks" , func ( ) {
m . Get ( "" , user . ListBlocks )
m . Group ( "/{username}" , func ( ) {
m . Get ( "" , user . CheckUserBlock )
m . Put ( "" , user . BlockUser )
m . Delete ( "" , user . UnblockUser )
2024-10-08 17:51:09 +08:00
} , context . UserAssignmentAPI ( ) , checkTokenPublicOnly ( ) )
2024-03-04 09:16:03 +01:00
} )
2023-06-04 14:57:16 -04:00
} , tokenRequiresScopes ( auth_model . AccessTokenScopeCategoryUser ) , reqToken ( ) )
2015-12-04 17:16:42 -05:00
2023-06-04 14:57:16 -04:00
// Repositories (requires repo scope, org scope)
m . Post ( "/org/{org}/repos" ,
2024-10-08 17:51:09 +08:00
// FIXME: we need org in context
2023-06-04 14:57:16 -04:00
tokenRequiresScopes ( auth_model . AccessTokenScopeCategoryOrganization , auth_model . AccessTokenScopeCategoryRepository ) ,
reqToken ( ) ,
bind ( api . CreateRepoOption { } ) ,
repo . CreateOrgRepoDeprecated )
2020-01-09 17:40:01 +01:00
2023-06-04 14:57:16 -04:00
// requires repo scope
2024-10-08 17:51:09 +08:00
// FIXME: Don't expose repository id outside of the system
2023-06-04 14:57:16 -04:00
m . Combo ( "/repositories/{id}" , reqToken ( ) , tokenRequiresScopes ( auth_model . AccessTokenScopeCategoryRepository ) ) . Get ( repo . GetByID )
2015-12-04 17:16:42 -05:00
2023-06-04 14:57:16 -04:00
// Repos (requires repo scope)
2015-12-04 17:16:42 -05:00
m . Group ( "/repos" , func ( ) {
m . Get ( "/search" , repo . Search )
2023-01-17 16:46:03 -05:00
// (repo scope)
2023-06-04 14:57:16 -04:00
m . Post ( "/migrate" , reqToken ( ) , bind ( api . MigrateRepoOptions { } ) , repo . Migrate )
2015-12-04 17:16:42 -05:00
2021-01-26 23:36:53 +08:00
m . Group ( "/{username}/{reponame}" , func ( ) {
2024-04-16 11:45:04 +08:00
m . Get ( "/compare/*" , reqRepoReader ( unit . TypeCode ) , repo . CompareDiff )
2018-11-28 19:26:14 +08:00
m . Combo ( "" ) . Get ( reqAnyRepoReader ( ) , repo . Get ) .
2023-06-04 14:57:16 -04:00
Delete ( reqToken ( ) , reqOwner ( ) , repo . Delete ) .
Patch ( reqToken ( ) , reqAdmin ( ) , bind ( api . EditRepoOption { } ) , repo . Edit )
m . Post ( "/generate" , reqToken ( ) , reqRepoReader ( unit . TypeCode ) , bind ( api . GenerateRepoOption { } ) , repo . Generate )
2023-01-17 16:46:03 -05:00
m . Group ( "/transfer" , func ( ) {
m . Post ( "" , reqOwner ( ) , bind ( api . TransferRepoOption { } ) , repo . Transfer )
m . Post ( "/accept" , repo . AcceptTransfer )
m . Post ( "/reject" , repo . RejectTransfer )
2023-06-04 14:57:16 -04:00
} , reqToken ( ) )
2025-02-11 03:05:42 +08:00
addActionsRoutes ( m , reqOwner ( ) , repo . NewAction ( ) ) // it adds the routes for secrets/variables and runner management
m . Group ( "/actions/workflows" , func ( ) {
m . Get ( "" , repo . ActionsListRepositoryWorkflows )
m . Get ( "/{workflow_id}" , repo . ActionsGetWorkflow )
m . Put ( "/{workflow_id}/disable" , reqRepoWriter ( unit . TypeActions ) , repo . ActionsDisableWorkflow )
m . Put ( "/{workflow_id}/enable" , reqRepoWriter ( unit . TypeActions ) , repo . ActionsEnableWorkflow )
m . Post ( "/{workflow_id}/dispatches" , reqRepoWriter ( unit . TypeActions ) , bind ( api . CreateActionWorkflowDispatch { } ) , repo . ActionsDispatchWorkflow )
} , context . ReferencesGitRepo ( ) , reqToken ( ) , reqRepoReader ( unit . TypeActions ) )
2025-03-26 11:30:52 -07:00
m . Group ( "/actions/jobs" , func ( ) {
2025-06-20 14:14:00 +02:00
m . Get ( "/{job_id}" , repo . GetWorkflowJob )
2025-03-26 11:30:52 -07:00
m . Get ( "/{job_id}/logs" , repo . DownloadActionsRunJobLogs )
} , reqToken ( ) , reqRepoReader ( unit . TypeActions ) )
2021-02-11 18:34:34 +01:00
m . Group ( "/hooks/git" , func ( ) {
2023-06-04 14:57:16 -04:00
m . Combo ( "" ) . Get ( repo . ListGitHooks )
2021-02-11 18:34:34 +01:00
m . Group ( "/{id}" , func ( ) {
2023-06-04 14:57:16 -04:00
m . Combo ( "" ) . Get ( repo . GetGitHook ) .
Patch ( bind ( api . EditGitHookOption { } ) , repo . EditGitHook ) .
Delete ( repo . DeleteGitHook )
2021-02-11 18:34:34 +01:00
} )
2023-06-04 14:57:16 -04:00
} , reqToken ( ) , reqAdmin ( ) , reqGitHook ( ) , context . ReferencesGitRepo ( true ) )
2016-07-16 19:08:38 -05:00
m . Group ( "/hooks" , func ( ) {
2023-06-04 14:57:16 -04:00
m . Combo ( "" ) . Get ( repo . ListHooks ) .
Post ( bind ( api . CreateHookOption { } ) , repo . CreateHook )
2021-01-26 23:36:53 +08:00
m . Group ( "/{id}" , func ( ) {
2023-06-04 14:57:16 -04:00
m . Combo ( "" ) . Get ( repo . GetHook ) .
Patch ( bind ( api . EditHookOption { } ) , repo . EditHook ) .
Delete ( repo . DeleteHook )
m . Post ( "/tests" , context . ReferencesGitRepo ( ) , context . RepoRefForAPI , repo . TestHook )
2018-04-28 23:21:33 -07:00
} )
2023-06-04 14:57:16 -04:00
} , reqToken ( ) , reqAdmin ( ) , reqWebhooksEnabled ( ) )
2016-12-26 02:37:01 -05:00
m . Group ( "/collaborators" , func ( ) {
2020-04-21 20:52:04 +05:30
m . Get ( "" , reqAnyRepoReader ( ) , repo . ListCollaborators )
2022-04-29 14:24:38 +02:00
m . Group ( "/{collaborator}" , func ( ) {
m . Combo ( "" ) . Get ( reqAnyRepoReader ( ) , repo . IsCollaborator ) .
2024-11-06 19:28:11 -08:00
Put ( reqAdmin ( ) , bind ( api . AddCollaboratorOption { } ) , repo . AddOrUpdateCollaborator ) .
2022-04-29 14:24:38 +02:00
Delete ( reqAdmin ( ) , repo . DeleteCollaborator )
m . Get ( "/permission" , repo . GetRepoPermissions )
2023-01-17 16:46:03 -05:00
} )
2023-06-04 14:57:16 -04:00
} , reqToken ( ) )
m . Get ( "/assignees" , reqToken ( ) , reqAnyRepoReader ( ) , repo . GetAssignees )
m . Get ( "/reviewers" , reqToken ( ) , reqAnyRepoReader ( ) , repo . GetReviewers )
2021-02-01 22:57:12 +01:00
m . Group ( "/teams" , func ( ) {
m . Get ( "" , reqAnyRepoReader ( ) , repo . ListTeams )
m . Combo ( "/{team}" ) . Get ( reqAnyRepoReader ( ) , repo . IsTeam ) .
Put ( reqAdmin ( ) , repo . AddTeam ) .
Delete ( reqAdmin ( ) , repo . DeleteTeam )
2023-06-04 14:57:16 -04:00
} , reqToken ( ) )
2022-04-21 17:17:57 +02:00
m . Get ( "/raw/*" , context . ReferencesGitRepo ( ) , context . RepoRefForAPI , reqRepoReader ( unit . TypeCode ) , repo . GetRawFile )
2022-06-04 15:17:53 +02:00
m . Get ( "/media/*" , context . ReferencesGitRepo ( ) , context . RepoRefForAPI , reqRepoReader ( unit . TypeCode ) , repo . GetRawFileOrLFS )
2025-09-19 05:51:21 +02:00
m . Methods ( "HEAD,GET" , "/archive/*" , reqRepoReader ( unit . TypeCode ) , context . ReferencesGitRepo ( true ) , repo . GetArchive )
2016-12-30 20:15:45 -05:00
m . Combo ( "/forks" ) . Get ( repo . ListForks ) .
2023-06-04 14:57:16 -04:00
Post ( reqToken ( ) , reqRepoReader ( unit . TypeCode ) , bind ( api . CreateForkOption { } ) , repo . CreateFork )
2025-01-10 13:29:55 +08:00
m . Post ( "/merge-upstream" , reqToken ( ) , mustNotBeArchived , reqRepoWriter ( unit . TypeCode ) , bind ( api . MergeUpstreamRequest { } ) , repo . MergeUpstream )
2016-01-15 19:24:03 +01:00
m . Group ( "/branches" , func ( ) {
2022-04-21 17:17:57 +02:00
m . Get ( "" , repo . ListBranches )
m . Get ( "/*" , repo . GetBranch )
2023-09-22 01:43:29 +02:00
m . Delete ( "/*" , reqToken ( ) , reqRepoWriter ( unit . TypeCode ) , mustNotBeArchived , repo . DeleteBranch )
m . Post ( "" , reqToken ( ) , reqRepoWriter ( unit . TypeCode ) , mustNotBeArchived , bind ( api . CreateBranchRepoOption { } ) , repo . CreateBranch )
2025-12-10 11:23:26 -08:00
m . Put ( "/*" , reqToken ( ) , reqRepoWriter ( unit . TypeCode ) , mustNotBeArchived , bind ( api . UpdateBranchRepoOption { } ) , repo . UpdateBranch )
2025-09-01 16:12:05 +00:00
m . Patch ( "/*" , reqToken ( ) , reqRepoWriter ( unit . TypeCode ) , mustNotBeArchived , bind ( api . RenameBranchRepoOption { } ) , repo . RenameBranch )
2022-04-21 17:17:57 +02:00
} , context . ReferencesGitRepo ( ) , reqRepoReader ( unit . TypeCode ) )
2020-02-13 00:19:35 +01:00
m . Group ( "/branch_protections" , func ( ) {
m . Get ( "" , repo . ListBranchProtections )
2023-09-22 01:43:29 +02:00
m . Post ( "" , bind ( api . CreateBranchProtectionOption { } ) , mustNotBeArchived , repo . CreateBranchProtection )
2021-01-26 23:36:53 +08:00
m . Group ( "/{name}" , func ( ) {
2020-02-13 00:19:35 +01:00
m . Get ( "" , repo . GetBranchProtection )
2023-09-22 01:43:29 +02:00
m . Patch ( "" , bind ( api . EditBranchProtectionOption { } ) , mustNotBeArchived , repo . EditBranchProtection )
2020-02-13 00:19:35 +01:00
m . Delete ( "" , repo . DeleteBranchProtection )
} )
2024-11-27 05:41:06 +01:00
m . Post ( "/priority" , bind ( api . UpdateBranchProtectionPriories { } ) , mustNotBeArchived , repo . UpdateBranchProtectionPriories )
2023-06-04 14:57:16 -04:00
} , reqToken ( ) , reqAdmin ( ) )
2019-02-07 20:00:52 +08:00
m . Group ( "/tags" , func ( ) {
m . Get ( "" , repo . ListTags )
2021-06-23 23:08:47 +02:00
m . Get ( "/*" , repo . GetTag )
2023-09-22 01:43:29 +02:00
m . Post ( "" , reqToken ( ) , reqRepoWriter ( unit . TypeCode ) , mustNotBeArchived , bind ( api . CreateTagOption { } ) , repo . CreateTag )
m . Delete ( "/*" , reqToken ( ) , reqRepoWriter ( unit . TypeCode ) , mustNotBeArchived , repo . DeleteTag )
2021-11-10 03:57:58 +08:00
} , reqRepoReader ( unit . TypeCode ) , context . ReferencesGitRepo ( true ) )
2024-06-14 19:56:10 +03:00
m . Group ( "/tag_protections" , func ( ) {
m . Combo ( "" ) . Get ( repo . ListTagProtection ) .
Post ( bind ( api . CreateTagProtectionOption { } ) , mustNotBeArchived , repo . CreateTagProtection )
m . Group ( "/{id}" , func ( ) {
m . Combo ( "" ) . Get ( repo . GetTagProtection ) .
Patch ( bind ( api . EditTagProtectionOption { } ) , mustNotBeArchived , repo . EditTagProtection ) .
Delete ( repo . DeleteTagProtection )
} )
} , reqToken ( ) , reqAdmin ( ) )
2024-05-01 09:40:23 +08:00
m . Group ( "/actions" , func ( ) {
m . Get ( "/tasks" , repo . ListActionTasks )
2025-06-20 14:14:00 +02:00
m . Group ( "/runs" , func ( ) {
m . Group ( "/{run}" , func ( ) {
m . Get ( "" , repo . GetWorkflowRun )
m . Delete ( "" , reqToken ( ) , reqRepoWriter ( unit . TypeActions ) , repo . DeleteActionRun )
m . Get ( "/jobs" , repo . ListWorkflowRunJobs )
m . Get ( "/artifacts" , repo . GetArtifactsOfRun )
} )
2025-05-14 03:18:13 +08:00
} )
2025-02-16 01:32:54 +01:00
m . Get ( "/artifacts" , repo . GetArtifacts )
m . Group ( "/artifacts/{artifact_id}" , func ( ) {
m . Get ( "" , repo . GetArtifact )
m . Delete ( "" , reqRepoWriter ( unit . TypeActions ) , repo . DeleteArtifact )
} )
m . Get ( "/artifacts/{artifact_id}/zip" , repo . DownloadArtifact )
2024-05-01 09:40:23 +08:00
} , reqRepoReader ( unit . TypeActions ) , context . ReferencesGitRepo ( true ) )
2015-12-04 17:16:42 -05:00
m . Group ( "/keys" , func ( ) {
m . Combo ( "" ) . Get ( repo . ListDeployKeys ) .
Post ( bind ( api . CreateKeyOption { } ) , repo . CreateDeployKey )
2021-01-26 23:36:53 +08:00
m . Combo ( "/{id}" ) . Get ( repo . GetDeployKey ) .
2015-12-04 17:16:42 -05:00
Delete ( repo . DeleteDeploykey )
2023-06-04 14:57:16 -04:00
} , reqToken ( ) , reqAdmin ( ) )
2017-09-12 08:48:13 +02:00
m . Group ( "/times" , func ( ) {
m . Combo ( "" ) . Get ( repo . ListTrackedTimesByRepository )
2021-01-26 23:36:53 +08:00
m . Combo ( "/{timetrackingusername}" ) . Get ( repo . ListTrackedTimesByUser )
2023-06-04 14:57:16 -04:00
} , mustEnableIssues , reqToken ( ) )
2021-10-25 05:43:40 +02:00
m . Group ( "/wiki" , func ( ) {
m . Combo ( "/page/{pageName}" ) .
Get ( repo . GetWikiPage ) .
2023-06-04 14:57:16 -04:00
Patch ( mustNotBeArchived , reqToken ( ) , reqRepoWriter ( unit . TypeWiki ) , bind ( api . CreateWikiPageOptions { } ) , repo . EditWikiPage ) .
Delete ( mustNotBeArchived , reqToken ( ) , reqRepoWriter ( unit . TypeWiki ) , repo . DeleteWikiPage )
2021-10-25 05:43:40 +02:00
m . Get ( "/revisions/{pageName}" , repo . ListPageRevisions )
2023-06-04 14:57:16 -04:00
m . Post ( "/new" , reqToken ( ) , mustNotBeArchived , reqRepoWriter ( unit . TypeWiki ) , bind ( api . CreateWikiPageOptions { } ) , repo . NewWikiPage )
2021-10-25 05:43:40 +02:00
m . Get ( "/pages" , repo . ListWikiPages )
} , mustEnableWiki )
2023-06-04 14:57:16 -04:00
m . Post ( "/markup" , reqToken ( ) , bind ( api . MarkupOption { } ) , misc . Markup )
m . Post ( "/markdown" , reqToken ( ) , bind ( api . MarkdownOption { } ) , misc . Markdown )
m . Post ( "/markdown/raw" , reqToken ( ) , misc . MarkdownRaw )
2025-02-04 02:21:23 -03:00
m . Get ( "/stargazers" , reqStarsEnabled ( ) , repo . ListStargazers )
2017-01-06 22:13:02 -05:00
m . Get ( "/subscribers" , repo . ListSubscribers )
2016-12-23 20:53:11 -05:00
m . Group ( "/subscription" , func ( ) {
m . Get ( "" , user . IsWatching )
2024-01-11 20:57:58 -05:00
m . Put ( "" , user . Watch )
m . Delete ( "" , user . Unwatch )
} , reqToken ( ) )
2016-12-31 11:51:22 -05:00
m . Group ( "/releases" , func ( ) {
m . Combo ( "" ) . Get ( repo . ListReleases ) .
2023-06-04 14:57:16 -04:00
Post ( reqToken ( ) , reqRepoWriter ( unit . TypeReleases ) , context . ReferencesGitRepo ( ) , bind ( api . CreateReleaseOption { } ) , repo . CreateRelease )
2023-01-26 17:33:47 +01:00
m . Combo ( "/latest" ) . Get ( repo . GetLatestRelease )
2021-01-26 23:36:53 +08:00
m . Group ( "/{id}" , func ( ) {
2018-03-06 02:22:16 +01:00
m . Combo ( "" ) . Get ( repo . GetRelease ) .
2023-06-04 14:57:16 -04:00
Patch ( reqToken ( ) , reqRepoWriter ( unit . TypeReleases ) , context . ReferencesGitRepo ( ) , bind ( api . EditReleaseOption { } ) , repo . EditRelease ) .
Delete ( reqToken ( ) , reqRepoWriter ( unit . TypeReleases ) , repo . DeleteRelease )
2018-03-06 02:22:16 +01:00
m . Group ( "/assets" , func ( ) {
m . Combo ( "" ) . Get ( repo . ListReleaseAttachments ) .
2023-06-04 14:57:16 -04:00
Post ( reqToken ( ) , reqRepoWriter ( unit . TypeReleases ) , repo . CreateReleaseAttachment )
2023-07-10 17:31:19 +08:00
m . Combo ( "/{attachment_id}" ) . Get ( repo . GetReleaseAttachment ) .
2023-06-04 14:57:16 -04:00
Patch ( reqToken ( ) , reqRepoWriter ( unit . TypeReleases ) , bind ( api . EditAttachmentOptions { } ) , repo . EditReleaseAttachment ) .
Delete ( reqToken ( ) , reqRepoWriter ( unit . TypeReleases ) , repo . DeleteReleaseAttachment )
2018-03-06 02:22:16 +01:00
} )
} )
2020-09-25 21:11:43 +02:00
m . Group ( "/tags" , func ( ) {
2021-01-26 23:36:53 +08:00
m . Combo ( "/{tag}" ) .
2021-02-07 19:32:18 +01:00
Get ( repo . GetReleaseByTag ) .
2023-06-04 14:57:16 -04:00
Delete ( reqToken ( ) , reqRepoWriter ( unit . TypeReleases ) , repo . DeleteReleaseByTag )
2020-09-25 21:11:43 +02:00
} )
2021-11-10 03:57:58 +08:00
} , reqRepoReader ( unit . TypeReleases ) )
2024-01-24 03:32:57 +01:00
m . Post ( "/mirror-sync" , reqToken ( ) , reqRepoWriter ( unit . TypeCode ) , mustNotBeArchived , repo . MirrorSync )
m . Post ( "/push_mirrors-sync" , reqAdmin ( ) , reqToken ( ) , mustNotBeArchived , repo . PushMirrorSync )
2022-07-30 18:45:59 +02:00
m . Group ( "/push_mirrors" , func ( ) {
m . Combo ( "" ) . Get ( repo . ListPushMirrors ) .
2024-01-24 03:32:57 +01:00
Post ( mustNotBeArchived , bind ( api . CreatePushMirrorOption { } ) , repo . AddPushMirror )
2022-07-30 18:45:59 +02:00
m . Combo ( "/{name}" ) .
2024-01-24 03:32:57 +01:00
Delete ( mustNotBeArchived , repo . DeletePushMirrorByRemoteName ) .
2022-07-30 18:45:59 +02:00
Get ( repo . GetPushMirrorByName )
2023-06-04 14:57:16 -04:00
} , reqAdmin ( ) , reqToken ( ) )
2022-07-30 18:45:59 +02:00
2022-04-21 17:17:57 +02:00
m . Get ( "/editorconfig/{filename}" , context . ReferencesGitRepo ( ) , context . RepoRefForAPI , reqRepoReader ( unit . TypeCode ) , repo . GetEditorconfig )
2016-12-02 12:10:39 +01:00
m . Group ( "/pulls" , func ( ) {
2021-01-26 23:36:53 +08:00
m . Combo ( "" ) . Get ( repo . ListPullRequests ) .
2023-06-04 14:57:16 -04:00
Post ( reqToken ( ) , mustNotBeArchived , bind ( api . CreatePullRequestOption { } ) , repo . CreatePullRequest )
2023-05-25 15:17:19 +02:00
m . Get ( "/pinned" , repo . ListPinnedPullRequests )
2026-02-01 13:28:28 +01:00
m . Post ( "/comments/{id}/resolve" , reqToken ( ) , mustNotBeArchived , repo . ResolvePullReviewComment )
m . Post ( "/comments/{id}/unresolve" , reqToken ( ) , mustNotBeArchived , repo . UnresolvePullReviewComment )
2021-01-26 23:36:53 +08:00
m . Group ( "/{index}" , func ( ) {
2017-07-11 21:23:41 -04:00
m . Combo ( "" ) . Get ( repo . GetPullRequest ) .
2023-06-04 14:57:16 -04:00
Patch ( reqToken ( ) , bind ( api . EditPullRequestOption { } ) , repo . EditPullRequest )
2021-09-22 01:04:53 +02:00
m . Get ( ".{diffType:diff|patch}" , repo . DownloadPullDiffOrPatch )
2023-06-04 14:57:16 -04:00
m . Post ( "/update" , reqToken ( ) , repo . UpdatePullRequest )
2021-07-02 14:19:57 +02:00
m . Get ( "/commits" , repo . GetPullRequestCommits )
2022-09-29 04:27:20 +02:00
m . Get ( "/files" , repo . GetPullRequestFiles )
2017-07-11 21:23:41 -04:00
m . Combo ( "/merge" ) . Get ( repo . IsPullRequestMerged ) .
2023-06-04 14:57:16 -04:00
Post ( reqToken ( ) , mustNotBeArchived , bind ( forms . MergePullRequestForm { } ) , repo . MergePullRequest ) .
Delete ( reqToken ( ) , mustNotBeArchived , repo . CancelScheduledAutoMerge )
2020-05-02 02:20:51 +02:00
m . Group ( "/reviews" , func ( ) {
m . Combo ( "" ) .
Get ( repo . ListPullReviews ) .
2023-06-04 14:57:16 -04:00
Post ( reqToken ( ) , bind ( api . CreatePullReviewOptions { } ) , repo . CreatePullReview )
2021-01-26 23:36:53 +08:00
m . Group ( "/{id}" , func ( ) {
2020-05-02 02:20:51 +02:00
m . Combo ( "" ) .
Get ( repo . GetPullReview ) .
2023-06-04 14:57:16 -04:00
Delete ( reqToken ( ) , repo . DeletePullReview ) .
Post ( reqToken ( ) , bind ( api . SubmitPullReviewOptions { } ) , repo . SubmitPullReview )
2020-05-02 02:20:51 +02:00
m . Combo ( "/comments" ) .
Get ( repo . GetPullReviewComments )
2023-06-04 14:57:16 -04:00
m . Post ( "/dismissals" , reqToken ( ) , bind ( api . DismissPullReviewOptions { } ) , repo . DismissPullReview )
m . Post ( "/undismissals" , reqToken ( ) , repo . UnDismissPullReview )
2020-05-02 02:20:51 +02:00
} )
} )
2023-06-04 14:57:16 -04:00
m . Combo ( "/requested_reviewers" , reqToken ( ) ) .
2023-01-17 16:46:03 -05:00
Delete ( bind ( api . PullReviewRequestOptions { } ) , repo . DeleteReviewRequests ) .
Post ( bind ( api . PullReviewRequestOptions { } ) , repo . CreateReviewRequests )
2016-12-02 12:10:39 +01:00
} )
2024-02-26 03:39:01 +01:00
m . Get ( "/{base}/*" , repo . GetPullRequestByBaseHead )
2022-04-21 17:17:57 +02:00
} , mustAllowPulls , reqRepoReader ( unit . TypeCode ) , context . ReferencesGitRepo ( ) )
2026-01-01 09:56:07 +08:00
m . Group ( "/statuses" , func ( ) { // "/statuses/{sha}" only accepts commit ID
2021-01-26 23:36:53 +08:00
m . Combo ( "/{sha}" ) . Get ( repo . GetCommitStatuses ) .
2023-06-04 14:57:16 -04:00
Post ( reqToken ( ) , reqRepoWriter ( unit . TypeCode ) , bind ( api . CreateStatusOption { } ) , repo . NewCommitStatus )
2021-11-10 03:57:58 +08:00
} , reqRepoReader ( unit . TypeCode ) )
2019-08-26 16:09:10 +02:00
m . Group ( "/commits" , func ( ) {
2022-04-21 17:17:57 +02:00
m . Get ( "" , context . ReferencesGitRepo ( ) , repo . GetAllCommits )
2026-01-01 09:56:07 +08:00
m . PathGroup ( "/*" , func ( g * web . RouterPathGroup ) {
// Mis-configured reverse proxy might decode the `%2F` to slash ahead, so we need to support both formats (escaped, unescaped) here.
// It also matches GitHub's behavior
g . MatchPath ( "GET" , "/<ref:*>/status" , repo . GetCombinedCommitStatusByRef )
g . MatchPath ( "GET" , "/<ref:*>/statuses" , repo . GetCommitStatusesByRef )
g . MatchPath ( "GET" , "/<sha>/pull" , repo . GetCommitPullRequest )
} )
2021-11-10 03:57:58 +08:00
} , reqRepoReader ( unit . TypeCode ) )
2018-11-27 23:52:20 +02:00
m . Group ( "/git" , func ( ) {
2019-02-03 11:35:17 +08:00
m . Group ( "/commits" , func ( ) {
2022-04-21 17:17:57 +02:00
m . Get ( "/{sha}" , repo . GetSingleCommit )
2021-09-20 18:14:29 +02:00
m . Get ( "/{sha}.{diffType:diff|patch}" , repo . DownloadCommitDiffOrPatch )
2019-02-03 11:35:17 +08:00
} )
2018-11-27 23:52:20 +02:00
m . Get ( "/refs" , repo . GetGitAllRefs )
m . Get ( "/refs/*" , repo . GetGitRefs )
2022-04-21 17:17:57 +02:00
m . Get ( "/trees/{sha}" , repo . GetTree )
m . Get ( "/blobs/{sha}" , repo . GetBlob )
m . Get ( "/tags/{sha}" , repo . GetAnnotatedTag )
2021-08-11 06:31:40 +05:30
m . Get ( "/notes/{sha}" , repo . GetNote )
2023-01-15 14:33:25 +00:00
} , context . ReferencesGitRepo ( true ) , reqRepoReader ( unit . TypeCode ) )
2025-10-09 22:09:14 +05:30
m . Post ( "/diffpatch" , mustEnableEditor , reqToken ( ) , bind ( api . ApplyDiffPatchFileOptions { } ) , repo . ReqChangeRepoFileOptionsAndCheck , repo . ApplyDiffPatch )
2019-04-17 10:06:35 -06:00
m . Group ( "/contents" , func ( ) {
2019-06-29 16:51:10 -04:00
m . Get ( "" , repo . GetContentsList )
m . Get ( "/*" , repo . GetContents )
2025-06-26 02:25:20 +08:00
m . Group ( "" , func ( ) {
// "change file" operations, need permission to write to the target branch provided by the form
m . Post ( "" , bind ( api . ChangeFilesOptions { } ) , repo . ReqChangeRepoFileOptionsAndCheck , repo . ChangeFiles )
m . Group ( "/*" , func ( ) {
m . Post ( "" , bind ( api . CreateFileOptions { } ) , repo . ReqChangeRepoFileOptionsAndCheck , repo . CreateFile )
m . Put ( "" , bind ( api . UpdateFileOptions { } ) , repo . ReqChangeRepoFileOptionsAndCheck , repo . UpdateFile )
m . Delete ( "" , bind ( api . DeleteFileOptions { } ) , repo . ReqChangeRepoFileOptionsAndCheck , repo . DeleteFile )
} )
} , mustEnableEditor , reqToken ( ) )
2025-04-21 19:20:11 +02:00
} , reqRepoReader ( unit . TypeCode ) , context . ReferencesGitRepo ( ) )
2025-06-25 10:34:21 +08:00
m . Group ( "/contents-ext" , func ( ) {
m . Get ( "" , repo . GetContentsExt )
m . Get ( "/*" , repo . GetContentsExt )
} , reqRepoReader ( unit . TypeCode ) , context . ReferencesGitRepo ( ) )
2025-04-21 19:20:11 +02:00
m . Combo ( "/file-contents" , reqRepoReader ( unit . TypeCode ) , context . ReferencesGitRepo ( ) ) .
Get ( repo . GetFileContentsGet ) .
2025-06-26 02:25:20 +08:00
Post ( bind ( api . GetFilesOptions { } ) , repo . GetFileContentsPost ) // the POST method requires "write" permission, so we also support "GET" method above
2025-06-11 12:32:55 +02:00
m . Get ( "/signing-key.gpg" , misc . SigningKeyGPG )
m . Get ( "/signing-key.pub" , misc . SigningKeySSH )
2019-09-03 17:46:24 +02:00
m . Group ( "/topics" , func ( ) {
m . Combo ( "" ) . Get ( repo . ListTopics ) .
2023-06-04 14:57:16 -04:00
Put ( reqToken ( ) , reqAdmin ( ) , bind ( api . RepoTopicOptions { } ) , repo . UpdateTopics )
2021-01-26 23:36:53 +08:00
m . Group ( "/{topic}" , func ( ) {
2023-06-04 14:57:16 -04:00
m . Combo ( "" ) . Put ( reqToken ( ) , repo . AddTopic ) .
Delete ( reqToken ( ) , repo . DeleteTopic )
2019-09-03 17:46:24 +02:00
} , reqAdmin ( ) )
} , reqAnyRepoReader ( ) )
2022-04-21 17:17:57 +02:00
m . Get ( "/issue_templates" , context . ReferencesGitRepo ( ) , repo . GetIssueTemplates )
2023-03-28 20:22:07 +02:00
m . Get ( "/issue_config" , context . ReferencesGitRepo ( ) , repo . GetIssueConfig )
m . Get ( "/issue_config/validate" , context . ReferencesGitRepo ( ) , repo . ValidateIssueConfig )
2021-11-10 03:57:58 +08:00
m . Get ( "/languages" , reqRepoReader ( unit . TypeCode ) , repo . GetLanguages )
2024-10-02 04:25:08 +09:00
m . Get ( "/licenses" , reqRepoReader ( unit . TypeCode ) , repo . GetLicenses )
2023-04-04 21:35:31 +08:00
m . Get ( "/activities/feeds" , repo . ListRepoActivityFeeds )
2023-05-25 15:17:19 +02:00
m . Get ( "/new_pin_allowed" , repo . AreNewIssuePinsAllowed )
2023-06-30 01:22:55 +02:00
m . Group ( "/avatar" , func ( ) {
m . Post ( "" , bind ( api . UpdateRepoAvatarOption { } ) , repo . UpdateAvatar )
m . Delete ( "" , repo . DeleteAvatar )
} , reqAdmin ( ) , reqToken ( ) )
2024-11-25 11:35:49 -08:00
2025-09-19 05:51:21 +02:00
m . Methods ( "HEAD,GET" , "/{ball_type:tarball|zipball|bundle}/*" , reqRepoReader ( unit . TypeCode ) , context . ReferencesGitRepo ( true ) , repo . DownloadArchive )
2024-10-08 17:51:09 +08:00
} , repoAssignment ( ) , checkTokenPublicOnly ( ) )
2023-06-04 14:57:16 -04:00
} , tokenRequiresScopes ( auth_model . AccessTokenScopeCategoryRepository ) )
2025-02-16 01:32:54 +01:00
// Artifacts direct download endpoint authenticates via signed url
// it is protected by the "sig" parameter (to help to access private repo), so no need to use other middlewares
m . Get ( "/repos/{username}/{reponame}/actions/artifacts/{artifact_id}/zip/raw" , repo . DownloadArtifactRaw )
2023-06-04 14:57:16 -04:00
// Notifications (requires notifications scope)
m . Group ( "/repos" , func ( ) {
m . Group ( "/{username}/{reponame}" , func ( ) {
m . Combo ( "/notifications" , reqToken ( ) ) .
Get ( notify . ListRepoNotifications ) .
Put ( notify . ReadRepoNotifications )
2024-10-08 17:51:09 +08:00
} , repoAssignment ( ) , checkTokenPublicOnly ( ) )
2023-06-04 14:57:16 -04:00
} , tokenRequiresScopes ( auth_model . AccessTokenScopeCategoryNotification ) )
// Issue (requires issue scope)
m . Group ( "/repos" , func ( ) {
m . Get ( "/issues/search" , repo . SearchIssues )
m . Group ( "/{username}/{reponame}" , func ( ) {
m . Group ( "/issues" , func ( ) {
m . Combo ( "" ) . Get ( repo . ListIssues ) .
2023-11-26 01:21:21 +08:00
Post ( reqToken ( ) , mustNotBeArchived , bind ( api . CreateIssueOption { } ) , reqRepoReader ( unit . TypeIssues ) , repo . CreateIssue )
m . Get ( "/pinned" , reqRepoReader ( unit . TypeIssues ) , repo . ListPinnedIssues )
2023-06-04 14:57:16 -04:00
m . Group ( "/comments" , func ( ) {
m . Get ( "" , repo . ListRepoIssueComments )
m . Group ( "/{id}" , func ( ) {
m . Combo ( "" ) .
Get ( repo . GetIssueComment ) .
Patch ( mustNotBeArchived , reqToken ( ) , bind ( api . EditIssueCommentOption { } ) , repo . EditIssueComment ) .
Delete ( reqToken ( ) , repo . DeleteIssueComment )
m . Combo ( "/reactions" ) .
Get ( repo . GetIssueCommentReactions ) .
Post ( reqToken ( ) , bind ( api . EditReactionOption { } ) , repo . PostIssueCommentReaction ) .
Delete ( reqToken ( ) , bind ( api . EditReactionOption { } ) , repo . DeleteIssueCommentReaction )
m . Group ( "/assets" , func ( ) {
m . Combo ( "" ) .
Get ( repo . ListIssueCommentAttachments ) .
Post ( reqToken ( ) , mustNotBeArchived , repo . CreateIssueCommentAttachment )
2023-07-10 17:31:19 +08:00
m . Combo ( "/{attachment_id}" ) .
2023-06-04 14:57:16 -04:00
Get ( repo . GetIssueCommentAttachment ) .
Patch ( reqToken ( ) , mustNotBeArchived , bind ( api . EditAttachmentOptions { } ) , repo . EditIssueCommentAttachment ) .
Delete ( reqToken ( ) , mustNotBeArchived , repo . DeleteIssueCommentAttachment )
} , mustEnableAttachments )
} )
} )
m . Group ( "/{index}" , func ( ) {
m . Combo ( "" ) . Get ( repo . GetIssue ) .
Patch ( reqToken ( ) , bind ( api . EditIssueOption { } ) , repo . EditIssue ) .
Delete ( reqToken ( ) , reqAdmin ( ) , context . ReferencesGitRepo ( ) , repo . DeleteIssue )
m . Group ( "/comments" , func ( ) {
m . Combo ( "" ) . Get ( repo . ListIssueComments ) .
Post ( reqToken ( ) , mustNotBeArchived , bind ( api . CreateIssueCommentOption { } ) , repo . CreateIssueComment )
m . Combo ( "/{id}" , reqToken ( ) ) . Patch ( bind ( api . EditIssueCommentOption { } ) , repo . EditIssueCommentDeprecated ) .
Delete ( repo . DeleteIssueCommentDeprecated )
} )
m . Get ( "/timeline" , repo . ListIssueCommentsAndTimeline )
m . Group ( "/labels" , func ( ) {
m . Combo ( "" ) . Get ( repo . ListIssueLabels ) .
Post ( reqToken ( ) , bind ( api . IssueLabelsOption { } ) , repo . AddIssueLabels ) .
Put ( reqToken ( ) , bind ( api . IssueLabelsOption { } ) , repo . ReplaceIssueLabels ) .
Delete ( reqToken ( ) , repo . ClearIssueLabels )
m . Delete ( "/{id}" , reqToken ( ) , repo . DeleteIssueLabel )
} )
m . Group ( "/times" , func ( ) {
m . Combo ( "" ) .
Get ( repo . ListTrackedTimes ) .
Post ( bind ( api . AddTimeOption { } ) , repo . AddTime ) .
Delete ( repo . ResetIssueTime )
m . Delete ( "/{id}" , repo . DeleteTime )
} , reqToken ( ) )
m . Combo ( "/deadline" ) . Post ( reqToken ( ) , bind ( api . EditDeadlineOption { } ) , repo . UpdateIssueDeadline )
m . Group ( "/stopwatch" , func ( ) {
m . Post ( "/start" , repo . StartIssueStopwatch )
m . Post ( "/stop" , repo . StopIssueStopwatch )
m . Delete ( "/delete" , repo . DeleteIssueStopwatch )
} , reqToken ( ) )
m . Group ( "/subscriptions" , func ( ) {
m . Get ( "" , repo . GetIssueSubscribers )
m . Get ( "/check" , reqToken ( ) , repo . CheckIssueSubscription )
m . Put ( "/{user}" , reqToken ( ) , repo . AddIssueSubscription )
m . Delete ( "/{user}" , reqToken ( ) , repo . DelIssueSubscription )
} )
m . Combo ( "/reactions" ) .
Get ( repo . GetIssueReactions ) .
Post ( reqToken ( ) , bind ( api . EditReactionOption { } ) , repo . PostIssueReaction ) .
Delete ( reqToken ( ) , bind ( api . EditReactionOption { } ) , repo . DeleteIssueReaction )
m . Group ( "/assets" , func ( ) {
m . Combo ( "" ) .
Get ( repo . ListIssueAttachments ) .
Post ( reqToken ( ) , mustNotBeArchived , repo . CreateIssueAttachment )
2023-07-10 17:31:19 +08:00
m . Combo ( "/{attachment_id}" ) .
2023-06-04 14:57:16 -04:00
Get ( repo . GetIssueAttachment ) .
Patch ( reqToken ( ) , mustNotBeArchived , bind ( api . EditAttachmentOptions { } ) , repo . EditIssueAttachment ) .
Delete ( reqToken ( ) , mustNotBeArchived , repo . DeleteIssueAttachment )
} , mustEnableAttachments )
m . Combo ( "/dependencies" ) .
Get ( repo . GetIssueDependencies ) .
Post ( reqToken ( ) , mustNotBeArchived , bind ( api . IssueMeta { } ) , repo . CreateIssueDependency ) .
Delete ( reqToken ( ) , mustNotBeArchived , bind ( api . IssueMeta { } ) , repo . RemoveIssueDependency )
m . Combo ( "/blocks" ) .
Get ( repo . GetIssueBlocks ) .
Post ( reqToken ( ) , bind ( api . IssueMeta { } ) , repo . CreateIssueBlocking ) .
Delete ( reqToken ( ) , bind ( api . IssueMeta { } ) , repo . RemoveIssueBlocking )
m . Group ( "/pin" , func ( ) {
m . Combo ( "" ) .
Post ( reqToken ( ) , reqAdmin ( ) , repo . PinIssue ) .
Delete ( reqToken ( ) , reqAdmin ( ) , repo . UnpinIssue )
m . Patch ( "/{position}" , reqToken ( ) , reqAdmin ( ) , repo . MoveIssuePin )
} )
2025-04-21 02:43:43 +02:00
m . Group ( "/lock" , func ( ) {
m . Combo ( "" ) .
Put ( bind ( api . LockIssueOption { } ) , repo . LockIssue ) .
Delete ( repo . UnlockIssue )
} , reqToken ( ) , reqAdmin ( ) )
2023-06-04 14:57:16 -04:00
} )
} , mustEnableIssuesOrPulls )
m . Group ( "/labels" , func ( ) {
m . Combo ( "" ) . Get ( repo . ListLabels ) .
Post ( reqToken ( ) , reqRepoWriter ( unit . TypeIssues , unit . TypePullRequests ) , bind ( api . CreateLabelOption { } ) , repo . CreateLabel )
m . Combo ( "/{id}" ) . Get ( repo . GetLabel ) .
Patch ( reqToken ( ) , reqRepoWriter ( unit . TypeIssues , unit . TypePullRequests ) , bind ( api . EditLabelOption { } ) , repo . EditLabel ) .
Delete ( reqToken ( ) , reqRepoWriter ( unit . TypeIssues , unit . TypePullRequests ) , repo . DeleteLabel )
} )
m . Group ( "/milestones" , func ( ) {
m . Combo ( "" ) . Get ( repo . ListMilestones ) .
Post ( reqToken ( ) , reqRepoWriter ( unit . TypeIssues , unit . TypePullRequests ) , bind ( api . CreateMilestoneOption { } ) , repo . CreateMilestone )
m . Combo ( "/{id}" ) . Get ( repo . GetMilestone ) .
Patch ( reqToken ( ) , reqRepoWriter ( unit . TypeIssues , unit . TypePullRequests ) , bind ( api . EditMilestoneOption { } ) , repo . EditMilestone ) .
Delete ( reqToken ( ) , reqRepoWriter ( unit . TypeIssues , unit . TypePullRequests ) , repo . DeleteMilestone )
} )
2024-10-08 17:51:09 +08:00
} , repoAssignment ( ) , checkTokenPublicOnly ( ) )
2023-06-04 14:57:16 -04:00
} , tokenRequiresScopes ( auth_model . AccessTokenScopeCategoryIssue ) )
2015-12-04 17:16:42 -05:00
2022-11-12 18:59:15 +00:00
// NOTE: these are Gitea package management API - see packages.CommonRoutes and packages.DockerContainerRoutes for endpoints that implement package manager APIs
2022-03-30 10:42:47 +02:00
m . Group ( "/packages/{username}" , func ( ) {
2025-02-16 19:18:00 -08:00
m . Group ( "/{type}/{name}" , func ( ) {
2025-04-13 22:00:44 +02:00
m . Get ( "/" , packages . ListPackageVersions )
2025-02-16 19:18:00 -08:00
m . Group ( "/{version}" , func ( ) {
m . Get ( "" , packages . GetPackage )
m . Delete ( "" , reqPackageAccess ( perm . AccessModeWrite ) , packages . DeletePackage )
m . Get ( "/files" , packages . ListPackageFiles )
} )
2025-04-13 22:00:44 +02:00
m . Group ( "/-" , func ( ) {
m . Get ( "/latest" , packages . GetLatestPackageVersion )
m . Post ( "/link/{repo_name}" , reqPackageAccess ( perm . AccessModeWrite ) , packages . LinkPackage )
m . Post ( "/unlink" , reqPackageAccess ( perm . AccessModeWrite ) , packages . UnlinkPackage )
} )
2022-03-30 10:42:47 +02:00
} )
2025-02-16 19:18:00 -08:00
m . Get ( "/" , packages . ListPackages )
} , reqToken ( ) , tokenRequiresScopes ( auth_model . AccessTokenScopeCategoryPackage ) , context . UserAssignmentAPI ( ) , context . PackageAssignmentAPI ( ) , reqPackageAccess ( perm . AccessModeRead ) , checkTokenPublicOnly ( ) )
2022-03-30 10:42:47 +02:00
2015-12-17 02:28:47 -05:00
// Organizations
2023-06-04 14:57:16 -04:00
m . Get ( "/user/orgs" , reqToken ( ) , tokenRequiresScopes ( auth_model . AccessTokenScopeCategoryUser , auth_model . AccessTokenScopeCategoryOrganization ) , org . ListMyOrgs )
2021-10-12 12:47:19 +02:00
m . Group ( "/users/{username}/orgs" , func ( ) {
2023-06-04 14:57:16 -04:00
m . Get ( "" , reqToken ( ) , org . ListUserOrgs )
m . Get ( "/{org}/permissions" , reqToken ( ) , org . GetUserOrgsPermissions )
2024-10-08 17:51:09 +08:00
} , tokenRequiresScopes ( auth_model . AccessTokenScopeCategoryUser , auth_model . AccessTokenScopeCategoryOrganization ) , context . UserAssignmentAPI ( ) , checkTokenPublicOnly ( ) )
2023-06-04 14:57:16 -04:00
m . Post ( "/orgs" , tokenRequiresScopes ( auth_model . AccessTokenScopeCategoryOrganization ) , reqToken ( ) , bind ( api . CreateOrgOption { } ) , org . Create )
m . Get ( "/orgs" , org . GetAll , tokenRequiresScopes ( auth_model . AccessTokenScopeCategoryOrganization ) )
2021-01-26 23:36:53 +08:00
m . Group ( "/orgs/{org}" , func ( ) {
2023-04-21 11:39:03 -04:00
m . Combo ( "" ) . Get ( org . Get ) .
2023-06-04 14:57:16 -04:00
Patch ( reqToken ( ) , reqOrgOwnership ( ) , bind ( api . EditOrgOption { } ) , org . Edit ) .
Delete ( reqToken ( ) , reqOrgOwnership ( ) , org . Delete )
2025-01-31 21:59:49 -03:00
m . Post ( "/rename" , reqToken ( ) , reqOrgOwnership ( ) , bind ( api . RenameOrgOption { } ) , org . Rename )
2023-04-21 11:39:03 -04:00
m . Combo ( "/repos" ) . Get ( user . ListOrgRepos ) .
2023-06-04 14:57:16 -04:00
Post ( reqToken ( ) , bind ( api . CreateRepoOption { } ) , repo . CreateOrgRepo )
2017-01-19 19:31:46 -07:00
m . Group ( "/members" , func ( ) {
2023-06-04 14:57:16 -04:00
m . Get ( "" , reqToken ( ) , org . ListMembers )
m . Combo ( "/{username}" ) . Get ( reqToken ( ) , org . IsMember ) .
Delete ( reqToken ( ) , reqOrgOwnership ( ) , org . DeleteMember )
2017-01-19 19:31:46 -07:00
} )
2024-04-26 21:11:49 +08:00
addActionsRoutes (
m ,
reqOrgOwnership ( ) ,
org . NewAction ( ) ,
)
2017-01-19 19:31:46 -07:00
m . Group ( "/public_members" , func ( ) {
2023-04-21 11:39:03 -04:00
m . Get ( "" , org . ListPublicMembers )
m . Combo ( "/{username}" ) . Get ( org . IsPublicMember ) .
2023-06-04 14:57:16 -04:00
Put ( reqToken ( ) , reqOrgMembership ( ) , org . PublicizeMember ) .
Delete ( reqToken ( ) , reqOrgMembership ( ) , org . ConcealMember )
2017-01-19 19:31:46 -07:00
} )
2019-10-01 07:32:28 +02:00
m . Group ( "/teams" , func ( ) {
2023-10-22 07:40:59 +08:00
m . Get ( "" , org . ListTeams )
m . Post ( "" , reqOrgOwnership ( ) , bind ( api . CreateTeamOption { } ) , org . CreateTeam )
m . Get ( "/search" , org . SearchTeam )
} , reqToken ( ) , reqOrgMembership ( ) )
2020-04-01 00:14:46 -04:00
m . Group ( "/labels" , func ( ) {
2023-04-21 11:39:03 -04:00
m . Get ( "" , org . ListLabels )
2023-06-04 14:57:16 -04:00
m . Post ( "" , reqToken ( ) , reqOrgOwnership ( ) , bind ( api . CreateLabelOption { } ) , org . CreateLabel )
m . Combo ( "/{id}" ) . Get ( reqToken ( ) , org . GetLabel ) .
Patch ( reqToken ( ) , reqOrgOwnership ( ) , bind ( api . EditLabelOption { } ) , org . EditLabel ) .
Delete ( reqToken ( ) , reqOrgOwnership ( ) , org . DeleteLabel )
2020-04-01 00:14:46 -04:00
} )
2016-12-06 23:36:28 -05:00
m . Group ( "/hooks" , func ( ) {
m . Combo ( "" ) . Get ( org . ListHooks ) .
Post ( bind ( api . CreateHookOption { } ) , org . CreateHook )
2021-01-26 23:36:53 +08:00
m . Combo ( "/{id}" ) . Get ( org . GetHook ) .
2019-07-03 13:31:29 +08:00
Patch ( bind ( api . EditHookOption { } ) , org . EditHook ) .
Delete ( org . DeleteHook )
2023-06-04 14:57:16 -04:00
} , reqToken ( ) , reqOrgOwnership ( ) , reqWebhooksEnabled ( ) )
2023-06-30 01:22:55 +02:00
m . Group ( "/avatar" , func ( ) {
m . Post ( "" , bind ( api . UpdateUserAvatarOption { } ) , org . UpdateAvatar )
m . Delete ( "" , org . DeleteAvatar )
} , reqToken ( ) , reqOrgOwnership ( ) )
2023-04-04 21:35:31 +08:00
m . Get ( "/activities/feeds" , org . ListOrgActivityFeeds )
2024-03-04 09:16:03 +01:00
m . Group ( "/blocks" , func ( ) {
m . Get ( "" , org . ListBlocks )
m . Group ( "/{username}" , func ( ) {
m . Get ( "" , org . CheckUserBlock )
m . Put ( "" , org . BlockUser )
m . Delete ( "" , org . UnblockUser )
} )
} , reqToken ( ) , reqOrgOwnership ( ) )
2024-10-08 17:51:09 +08:00
} , tokenRequiresScopes ( auth_model . AccessTokenScopeCategoryOrganization ) , orgAssignment ( true ) , checkTokenPublicOnly ( ) )
2021-01-26 23:36:53 +08:00
m . Group ( "/teams/{teamid}" , func ( ) {
2023-06-04 14:57:16 -04:00
m . Combo ( "" ) . Get ( reqToken ( ) , org . GetTeam ) .
Patch ( reqToken ( ) , reqOrgOwnership ( ) , bind ( api . EditTeamOption { } ) , org . EditTeam ) .
Delete ( reqToken ( ) , reqOrgOwnership ( ) , org . DeleteTeam )
2017-01-19 22:16:10 -07:00
m . Group ( "/members" , func ( ) {
2023-06-04 14:57:16 -04:00
m . Get ( "" , reqToken ( ) , org . GetTeamMembers )
2021-01-26 23:36:53 +08:00
m . Combo ( "/{username}" ) .
2023-06-04 14:57:16 -04:00
Get ( reqToken ( ) , org . GetTeamMember ) .
Put ( reqToken ( ) , reqOrgOwnership ( ) , org . AddTeamMember ) .
Delete ( reqToken ( ) , reqOrgOwnership ( ) , org . RemoveTeamMember )
2017-01-19 22:16:10 -07:00
} )
m . Group ( "/repos" , func ( ) {
2023-06-04 14:57:16 -04:00
m . Get ( "" , reqToken ( ) , org . GetTeamRepos )
2021-01-26 23:36:53 +08:00
m . Combo ( "/{org}/{reponame}" ) .
2023-06-04 14:57:16 -04:00
Put ( reqToken ( ) , org . AddTeamRepository ) .
Delete ( reqToken ( ) , org . RemoveTeamRepository ) .
Get ( reqToken ( ) , org . GetTeamRepo )
2017-01-19 22:16:10 -07:00
} )
2023-04-04 21:35:31 +08:00
m . Get ( "/activities/feeds" , org . ListTeamActivityFeeds )
2024-10-08 17:51:09 +08:00
} , tokenRequiresScopes ( auth_model . AccessTokenScopeCategoryOrganization ) , orgAssignment ( false , true ) , reqToken ( ) , reqTeamMembership ( ) , checkTokenPublicOnly ( ) )
2015-12-17 02:28:47 -05:00
2015-12-05 17:13:13 -05:00
m . Group ( "/admin" , func ( ) {
2020-08-24 16:48:15 +01:00
m . Group ( "/cron" , func ( ) {
m . Get ( "" , admin . ListCronTasks )
2021-01-26 23:36:53 +08:00
m . Post ( "/{task}" , admin . PostCronTask )
2020-08-24 16:48:15 +01:00
} )
2019-01-24 04:00:19 +05:30
m . Get ( "/orgs" , admin . GetAllOrgs )
2015-12-05 17:13:13 -05:00
m . Group ( "/users" , func ( ) {
2023-03-15 19:53:01 +08:00
m . Get ( "" , admin . SearchUsers )
2015-12-05 17:13:13 -05:00
m . Post ( "" , bind ( api . CreateUserOption { } ) , admin . CreateUser )
2021-01-26 23:36:53 +08:00
m . Group ( "/{username}" , func ( ) {
2015-12-05 17:13:13 -05:00
m . Combo ( "" ) . Patch ( bind ( api . EditUserOption { } ) , admin . EditUser ) .
Delete ( admin . DeleteUser )
2017-12-06 12:27:10 +02:00
m . Group ( "/keys" , func ( ) {
m . Post ( "" , bind ( api . CreateKeyOption { } ) , admin . CreatePublicKey )
2021-01-26 23:36:53 +08:00
m . Delete ( "/{id}" , admin . DeleteUserPublicKey )
2017-12-06 12:27:10 +02:00
} )
2019-01-24 04:00:19 +05:30
m . Get ( "/orgs" , org . ListUserOrgs )
2015-12-17 02:28:47 -05:00
m . Post ( "/orgs" , bind ( api . CreateOrgOption { } ) , admin . CreateOrg )
2015-12-17 22:57:41 -05:00
m . Post ( "/repos" , bind ( api . CreateRepoOption { } ) , admin . CreateRepo )
2023-03-14 03:45:21 -04:00
m . Post ( "/rename" , bind ( api . RenameUserOption { } ) , admin . RenameUser )
2024-03-01 03:23:28 -05:00
m . Get ( "/badges" , admin . ListUserBadges )
m . Post ( "/badges" , bind ( api . UserBadgeOption { } ) , admin . AddUserBadges )
m . Delete ( "/badges" , bind ( api . UserBadgeOption { } ) , admin . DeleteUserBadges )
2024-02-27 15:12:22 +08:00
} , context . UserAssignmentAPI ( ) )
2015-12-05 17:13:13 -05:00
} )
2023-03-14 03:54:40 -04:00
m . Group ( "/emails" , func ( ) {
m . Get ( "" , admin . GetAllEmails )
m . Get ( "/search" , admin . SearchEmail )
} )
2020-09-25 05:09:23 +01:00
m . Group ( "/unadopted" , func ( ) {
m . Get ( "" , admin . ListUnadoptedRepositories )
2021-01-26 23:36:53 +08:00
m . Post ( "/{username}/{reponame}" , admin . AdoptRepository )
m . Delete ( "/{username}/{reponame}" , admin . DeleteUnadoptedRepository )
2020-09-25 05:09:23 +01:00
} )
2023-01-29 02:12:10 +08:00
m . Group ( "/hooks" , func ( ) {
m . Combo ( "" ) . Get ( admin . ListHooks ) .
Post ( bind ( api . CreateHookOption { } ) , admin . CreateHook )
m . Combo ( "/{id}" ) . Get ( admin . GetHook ) .
Patch ( bind ( api . EditHookOption { } ) , admin . EditHook ) .
Delete ( admin . DeleteHook )
} )
2025-06-20 14:14:00 +02:00
m . Group ( "/actions" , func ( ) {
m . Group ( "/runners" , func ( ) {
m . Get ( "" , admin . ListRunners )
m . Post ( "/registration-token" , admin . CreateRegistrationToken )
m . Get ( "/{runner_id}" , admin . GetRunner )
m . Delete ( "/{runner_id}" , admin . DeleteRunner )
} )
m . Get ( "/runs" , admin . ListWorkflowRuns )
m . Get ( "/jobs" , admin . ListWorkflowJobs )
2025-04-18 17:22:41 +02:00
} )
2023-12-27 15:57:54 +08:00
m . Group ( "/runners" , func ( ) {
m . Get ( "/registration-token" , admin . GetRegistrationToken )
} )
2023-06-04 14:57:16 -04:00
} , tokenRequiresScopes ( auth_model . AccessTokenScopeCategoryAdmin ) , reqToken ( ) , reqSiteAdmin ( ) )
2018-04-11 10:51:44 +08:00
m . Group ( "/topics" , func ( ) {
m . Get ( "/search" , repo . TopicSearch )
2023-06-04 14:57:16 -04:00
} , tokenRequiresScopes ( auth_model . AccessTokenScopeCategoryRepository ) )
2021-01-26 23:36:53 +08:00
} , sudo ( ) )
return m
2019-05-13 08:38:53 -07:00
}
2021-01-26 23:36:53 +08:00
func securityHeaders ( ) func ( http . Handler ) http . Handler {
return func ( next http . Handler ) http . Handler {
return http . HandlerFunc ( func ( resp http . ResponseWriter , req * http . Request ) {
2019-05-13 08:38:53 -07:00
// CORB: https://www.chromium.org/Home/chromium-security/corb-for-developers
// http://stackoverflow.com/a/3146618/244009
2021-01-26 23:36:53 +08:00
resp . Header ( ) . Set ( "x-content-type-options" , "nosniff" )
next . ServeHTTP ( resp , req )
2019-05-13 08:38:53 -07:00
} )
}
2015-12-04 17:16:42 -05:00
}