Files
Atay-Makhzan/routers/api/v1/api.go
T

1210 lines
43 KiB
Go
Raw Normal View History

2015-12-04 17:16:42 -05:00
// Copyright 2015 The Gogs Authors. All rights reserved.
// Copyright 2016 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
2015-12-04 17:16:42 -05:00
2017-05-02 15:35:59 +02:00
// Package v1 Gitea API.
//
2017-11-12 23:02:25 -08:00
// This documentation describes the Gitea API.
2017-05-02 15:35:59 +02:00
//
2022-08-30 21:15:45 -05:00
// Schemes: http, https
// BasePath: /api/v1
// Version: {{AppVer | JSEscape | Safe}}
// 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
// AccessToken:
// type: apiKey
// name: access_token
// in: query
// 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 (
gocontext "context"
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"
"code.gitea.io/gitea/models/organization"
2022-03-30 10:42:47 +02:00
"code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
2021-11-10 03:57:58 +08:00
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context"
2018-09-07 04:31:29 +01:00
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
2019-05-11 18:21:34 +08:00
api "code.gitea.io/gitea/modules/structs"
2021-01-26 23:36:53 +08:00
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/activitypub"
"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"
"code.gitea.io/gitea/routers/api/v1/org"
2022-03-30 10:42:47 +02:00
"code.gitea.io/gitea/routers/api/v1/packages"
"code.gitea.io/gitea/routers/api/v1/repo"
"code.gitea.io/gitea/routers/api/v1/settings"
"code.gitea.io/gitea/routers/api/v1/user"
"code.gitea.io/gitea/services/auth"
context_service "code.gitea.io/gitea/services/context"
"code.gitea.io/gitea/services/forms"
2017-11-12 23:02:25 -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) {
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 {
user, err := user_model.GetUserByName(ctx, sudo)
2018-09-07 04:31:29 +01:00
if err != nil {
if user_model.IsErrUserNotExist(err) {
2019-03-18 21:29:43 -05:00
ctx.NotFound()
2018-09-07 04:31:29 +01:00
} else {
2019-12-20 18:07:12 +01:00
ctx.Error(http.StatusInternalServerError, "GetUserByName", 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) {
return func(ctx *context.APIContext) {
2021-01-26 23:36:53 +08:00
userName := ctx.Params("username")
repoName := ctx.Params("reponame")
2015-12-04 17:16:42 -05:00
var (
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.
2022-03-22 08:03:22 +01:00
if ctx.IsSigned && ctx.Doer.LowerName == strings.ToLower(userName) {
owner = ctx.Doer
2015-12-04 17:16:42 -05:00
} else {
owner, err = user_model.GetUserByName(ctx, userName)
2015-12-04 17:16:42 -05:00
if err != nil {
if user_model.IsErrUserNotExist(err) {
if redirectUserID, err := user_model.LookupUserRedirect(userName); err == nil {
context.RedirectToUser(ctx.Context, userName, redirectUserID)
} else if user_model.IsErrUserRedirectNotExist(err) {
ctx.NotFound("GetUserByName", err)
} else {
ctx.Error(http.StatusInternalServerError, "LookupUserRedirect", err)
}
2015-12-04 17:16:42 -05:00
} else {
2019-12-20 18:07:12 +01:00
ctx.Error(http.StatusInternalServerError, "GetUserByName", err)
2015-12-04 17:16:42 -05:00
}
return
}
}
ctx.Repo.Owner = owner
ctx.ContextUser = owner
2015-12-04 17:16:42 -05:00
// Get repository.
repo, err := repo_model.GetRepositoryByName(owner.ID, repoName)
2015-12-04 17:16:42 -05:00
if err != nil {
if repo_model.IsErrRepoNotExist(err) {
2021-12-12 23:48:20 +08:00
redirectRepoID, err := repo_model.LookupRedirect(owner.ID, repoName)
2017-02-05 09:35:03 -05:00
if err == nil {
context.RedirectToRepo(ctx.Context, redirectRepoID)
2021-12-12 23:48:20 +08:00
} else if repo_model.IsErrRedirectNotExist(err) {
2019-03-18 21:29:43 -05:00
ctx.NotFound()
2017-02-05 09:35:03 -05:00
} else {
2019-12-20 18:07:12 +01:00
ctx.Error(http.StatusInternalServerError, "LookupRepoRedirect", err)
2017-02-05 09:35:03 -05:00
}
2015-12-04 17:16:42 -05:00
} else {
2019-12-20 18:07:12 +01:00
ctx.Error(http.StatusInternalServerError, "GetRepositoryByName", err)
2015-12-04 17:16:42 -05:00
}
return
}
2017-02-02 07:33:56 -05:00
repo.Owner = owner
ctx.Repo.Repository = repo
2015-12-04 17:16:42 -05:00
ctx.Repo.Permission, err = access_model.GetUserRepoPermission(ctx, repo, ctx.Doer)
if err != nil {
2019-12-20 18:07:12 +01:00
ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
return
2015-12-04 17:16:42 -05:00
}
2016-03-13 23:20:22 -04:00
if !ctx.Repo.HasAccess() {
2019-03-18 21:29:43 -05:00
ctx.NotFound()
2015-12-04 17:16:42 -05:00
return
}
}
}
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() {
ctx.Error(http.StatusForbidden, "reqPackageAccess", "user should have specific permission or be a site admin")
return
}
}
}
2015-12-04 17:16:42 -05:00
// Contexter middleware already checks token for user sign in process.
2021-01-26 23:36:53 +08:00
func reqToken() func(ctx *context.APIContext) {
return func(ctx *context.APIContext) {
if true == ctx.Data["IsApiToken"] {
return
}
2019-04-19 04:59:26 -04:00
if ctx.Context.IsBasicAuth {
ctx.CheckForOTP()
return
}
if ctx.IsSigned {
2015-12-04 17:16:42 -05:00
return
}
2020-11-14 17:13:55 +01:00
ctx.Error(http.StatusUnauthorized, "reqToken", "token is required")
2015-12-04 17:16:42 -05:00
}
}
func reqExploreSignIn() func(ctx *context.APIContext) {
return func(ctx *context.APIContext) {
if setting.Service.Explore.RequireSigninView && !ctx.IsSigned {
ctx.Error(http.StatusUnauthorized, "reqExploreSignIn", "you must be signed in to search for users")
}
}
}
func reqBasicAuth() func(ctx *context.APIContext) {
2019-04-19 04:59:26 -04:00
return func(ctx *context.APIContext) {
if !ctx.Context.IsBasicAuth {
ctx.Error(http.StatusUnauthorized, "reqBasicAuth", "auth required")
2015-12-04 17:16:42 -05:00
return
}
2019-04-19 04:59:26 -04:00
ctx.CheckForOTP()
2015-12-04 17:16:42 -05: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) {
if !ctx.IsUserSiteAdmin() {
2020-11-14 17:13:55 +01:00
ctx.Error(http.StatusForbidden, "reqSiteAdmin", "user should be the site admin")
2015-12-04 17:16:42 -05:00
return
}
}
}
// 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) {
if !ctx.IsUserRepoOwner() && !ctx.IsUserSiteAdmin() {
2020-11-14 17:13:55 +01:00
ctx.Error(http.StatusForbidden, "reqOwner", "user should be the owner of the repo")
return
}
}
}
// 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) {
if !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() {
2020-11-14 17:13:55 +01:00
ctx.Error(http.StatusForbidden, "reqAdmin", "user should be an owner or a collaborator with admin write of a repository")
return
}
}
}
// 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) {
if !ctx.IsUserRepoWriter(unitTypes) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() {
2020-11-14 17:13:55 +01:00
ctx.Error(http.StatusForbidden, "reqRepoWriter", "user should have a permission to write to a repo")
return
}
}
}
// reqRepoBranchWriter user should have a permission to write to a branch, or be a site admin
func reqRepoBranchWriter(ctx *context.APIContext) {
options, ok := web.GetForm(ctx).(api.FileOptionInterface)
if !ok || (!ctx.Repo.CanWriteToBranch(ctx.Doer, options.Branch()) && !ctx.IsUserSiteAdmin()) {
ctx.Error(http.StatusForbidden, "reqRepoBranchWriter", "user should have a permission to write to this branch")
return
}
}
// 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) {
if !ctx.IsUserRepoReaderSpecific(unitType) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() {
2020-11-14 17:13:55 +01:00
ctx.Error(http.StatusForbidden, "reqRepoReader", "user should have specific read permission or be a repo admin or a site admin")
2016-08-24 16:05:56 -07:00
return
}
}
}
// 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) {
if !ctx.IsUserRepoReaderAny() && !ctx.IsUserSiteAdmin() {
2020-11-14 17:13:55 +01:00
ctx.Error(http.StatusForbidden, "reqAnyRepoReader", "user should have any permission to read repository or permissions of site admin")
return
}
}
}
// 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) {
if ctx.Context.IsUserSiteAdmin() {
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 {
2019-12-20 18:07:12 +01:00
ctx.Error(http.StatusInternalServerError, "", "reqOrgOwnership: unprepared context")
2017-01-13 21:14:48 -05:00
return
}
isOwner, err := organization.IsOrganizationOwner(ctx, orgID, ctx.Doer.ID)
if err != nil {
2019-12-20 18:07:12 +01:00
ctx.Error(http.StatusInternalServerError, "IsOrganizationOwner", err)
return
} else if !isOwner {
2017-01-26 06:54:04 -05:00
if ctx.Org.Organization != nil {
2019-12-20 18:07:12 +01:00
ctx.Error(http.StatusForbidden, "", "Must be an organization owner")
2017-01-26 06:54:04 -05:00
} else {
2019-03-18 21:29:43 -05:00
ctx.NotFound()
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) {
if ctx.Context.IsUserSiteAdmin() {
return
}
if ctx.Org.Team == nil {
2019-12-20 18:07:12 +01:00
ctx.Error(http.StatusInternalServerError, "", "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
isOwner, err := organization.IsOrganizationOwner(ctx, orgID, ctx.Doer.ID)
2019-04-24 13:32:35 +08:00
if err != nil {
2019-12-20 18:07:12 +01:00
ctx.Error(http.StatusInternalServerError, "IsOrganizationOwner", err)
2019-04-24 13:32:35 +08:00
return
} else if isOwner {
return
}
if isTeamMember, err := organization.IsTeamMember(ctx, orgID, ctx.Org.Team.ID, ctx.Doer.ID); err != nil {
2019-12-20 18:07:12 +01:00
ctx.Error(http.StatusInternalServerError, "IsTeamMember", err)
2019-04-24 13:32:35 +08:00
return
} else if !isTeamMember {
isOrgMember, err := organization.IsOrganizationMember(ctx, orgID, ctx.Doer.ID)
2019-04-24 13:32:35 +08:00
if err != nil {
2019-12-20 18:07:12 +01:00
ctx.Error(http.StatusInternalServerError, "IsOrganizationMember", err)
2019-04-24 13:32:35 +08:00
} else if isOrgMember {
2019-12-20 18:07:12 +01:00
ctx.Error(http.StatusForbidden, "", "Must be a team member")
2019-04-24 13:32:35 +08:00
} else {
ctx.NotFound()
}
return
}
}
}
// 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) {
if ctx.Context.IsUserSiteAdmin() {
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 {
2019-12-20 18:07:12 +01:00
ctx.Error(http.StatusInternalServerError, "", "reqOrgMembership: unprepared context")
2017-01-13 21:14:48 -05:00
return
}
if isMember, err := organization.IsOrganizationMember(ctx, orgID, ctx.Doer.ID); err != nil {
2019-12-20 18:07:12 +01:00
ctx.Error(http.StatusInternalServerError, "IsOrganizationMember", err)
return
} else if !isMember {
2017-01-26 06:54:04 -05:00
if ctx.Org.Organization != nil {
2019-12-20 18:07:12 +01:00
ctx.Error(http.StatusForbidden, "", "Must be an organization member")
2017-01-26 06:54:04 -05:00
} else {
2019-03-18 21:29:43 -05:00
ctx.NotFound()
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() {
2019-12-20 18:07:12 +01:00
ctx.Error(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 {
ctx.Error(http.StatusForbidden, "", "webhooks disabled by administrator")
return
}
}
}
2021-01-26 23:36:53 +08:00
func orgAssignment(args ...bool) func(ctx *context.APIContext) {
var (
assignOrg bool
assignTeam bool
)
if len(args) > 0 {
assignOrg = args[0]
}
if len(args) > 1 {
assignTeam = args[1]
}
return func(ctx *context.APIContext) {
ctx.Org = new(context.APIOrganization)
var err error
if assignOrg {
ctx.Org.Organization, err = organization.GetOrgByName(ctx.Params(":org"))
if err != nil {
if organization.IsErrOrgNotExist(err) {
redirectUserID, err := user_model.LookupUserRedirect(ctx.Params(":org"))
if err == nil {
context.RedirectToUser(ctx.Context, ctx.Params(":org"), redirectUserID)
} else if user_model.IsErrUserRedirectNotExist(err) {
ctx.NotFound("GetOrgByName", err)
} else {
ctx.Error(http.StatusInternalServerError, "LookupUserRedirect", err)
}
} else {
2019-12-20 18:07:12 +01:00
ctx.Error(http.StatusInternalServerError, "GetOrgByName", err)
}
return
}
ctx.ContextUser = ctx.Org.Organization.AsUser()
}
if assignTeam {
ctx.Org.Team, err = organization.GetTeamByID(ctx, ctx.ParamsInt64(":teamid"))
if err != nil {
if organization.IsErrTeamNotExist(err) {
2019-03-18 21:29:43 -05:00
ctx.NotFound()
} else {
2019-12-20 18:07:12 +01:00
ctx.Error(http.StatusInternalServerError, "GetTeamById", err)
}
return
}
}
}
}
func mustEnableIssues(ctx *context.APIContext) {
2021-11-10 03:57:58 +08:00
if !ctx.Repo.CanRead(unit.TypeIssues) {
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,
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,
ctx.Repo.Repository,
ctx.Repo.Permission)
}
}
2019-03-18 21:29:43 -05:00
ctx.NotFound()
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)) {
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,
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,
ctx.Repo.Repository,
ctx.Repo.Permission)
}
}
2019-03-18 21:29:43 -05:00
ctx.NotFound()
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)) {
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,
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,
ctx.Repo.Repository,
ctx.Repo.Permission)
}
}
2019-03-18 21:29:43 -05:00
ctx.NotFound()
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)) {
2021-10-25 05:43:40 +02:00
ctx.NotFound()
return
}
}
2019-03-18 21:29:43 -05:00
func mustNotBeArchived(ctx *context.APIContext) {
if ctx.Repo.Repository.IsArchived {
2019-03-18 21:29:43 -05:00
ctx.NotFound()
return
}
}
func mustEnableAttachments(ctx *context.APIContext) {
if !setting.Attachment.Enabled {
ctx.NotFound()
return
}
}
2021-01-26 23:36:53 +08:00
// bind binding an obj to a func(ctx *context.APIContext)
func bind[T any](obj T) http.HandlerFunc {
2021-01-26 23:36:53 +08:00
return web.Wrap(func(ctx *context.APIContext) {
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 {
2021-11-22 13:05:29 +00:00
ctx.Error(http.StatusUnprocessableEntity, "validationError", fmt.Sprintf("%s: %s", errs[0].FieldNames, errs[0].Error()))
2021-01-26 23:36:53 +08:00
return
}
web.SetForm(ctx, theObj)
})
}
2015-12-04 17:16:42 -05:00
// The OAuth2 plugin is expected to be executed first, as it must ignore the user id stored
// in the session (if there is a user id stored in session other plugins might return the user
// object for that id).
//
// The Session plugin is expected to be executed second, in order to skip authentication
// for users that have already signed in.
func buildAuthGroup() *auth.Group {
group := auth.NewGroup(
&auth.OAuth2{},
&auth.HTTPSign{},
&auth.Basic{}, // FIXME: this should be removed once we don't allow basic auth in API
)
specialAdd(group)
return group
}
2021-01-26 23:36:53 +08:00
// Routes registers all v1 APIs routes to web application.
func Routes(ctx gocontext.Context) *web.Route {
2022-01-20 18:46:10 +01:00
m := web.NewRoute()
2021-01-26 23:36:53 +08:00
m.Use(securityHeaders())
if setting.CORSConfig.Enabled {
m.Use(cors.Handler(cors.Options{
2022-01-20 18:46:10 +01:00
// Scheme: setting.CORSConfig.Scheme, // FIXME: the cors middleware needs scheme option
2021-01-26 23:36:53 +08:00
AllowedOrigins: setting.CORSConfig.AllowDomain,
2022-01-20 18:46:10 +01:00
// setting.CORSConfig.AllowSubdomain // FIXME: the cors middleware needs allowSubdomain option
2021-01-26 23:36:53 +08:00
AllowedMethods: setting.CORSConfig.Methods,
AllowCredentials: setting.CORSConfig.AllowCredentials,
AllowedHeaders: append([]string{"Authorization", "X-Gitea-OTP"}, setting.CORSConfig.Headers...),
2021-01-26 23:36:53 +08:00
MaxAge: int(setting.CORSConfig.MaxAge.Seconds()),
}))
}
2021-01-26 23:36:53 +08:00
m.Use(context.APIContexter())
2021-01-28 01:46:35 +08:00
group := buildAuthGroup()
if err := group.Init(ctx); err != nil {
log.Error("Could not initialize '%s' auth method, error: %s", group.Name(), err)
}
// Get user from session if logged in.
m.Use(context.APIAuth(group))
2021-01-26 23:36:53 +08:00
m.Use(context.ToggleAPI(&context.ToggleOptions{
SignInRequired: setting.Service.RequireSignInView,
}))
2017-10-21 16:05:50 +02:00
2021-01-26 23:36:53 +08:00
m.Group("", func() {
2015-12-04 17:16:42 -05:00
// Miscellaneous
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) {
ctx.Redirect(setting.AppSubURL + "/api/swagger")
2021-01-26 23:36:53 +08:00
})
}
m.Get("/version", misc.Version)
if setting.Federation.Enabled {
m.Get("/nodeinfo", misc.NodeInfo)
m.Group("/activitypub", func() {
m.Group("/user/{username}", func() {
m.Get("", activitypub.Person)
m.Post("/inbox", activitypub.ReqHTTPSignature(), activitypub.PersonInbox)
}, context_service.UserAssignmentAPI())
})
}
m.Get("/signing-key.gpg", misc.SigningKey)
2015-12-04 17:16:42 -05:00
m.Post("/markdown", bind(api.MarkdownOption{}), misc.Markdown)
m.Post("/markdown/raw", misc.MarkdownRaw)
2020-06-04 11:16:53 +02:00
m.Group("/settings", func() {
m.Get("/ui", settings.GetGeneralUISettings)
m.Get("/api", settings.GetGeneralAPISettings)
2020-09-05 09:43:06 +02:00
m.Get("/attachment", settings.GetGeneralAttachmentSettings)
m.Get("/repository", settings.GetGeneralRepoSettings)
2020-06-04 11:16:53 +02:00
})
2015-12-04 17:16:42 -05:00
2020-01-09 12:56:32 +01:00
// Notifications
m.Group("/notifications", func() {
m.Combo("").
Get(notify.ListNotifications).
Put(notify.ReadNotifications)
m.Get("/new", notify.NewAvailable)
2021-01-26 23:36:53 +08:00
m.Combo("/threads/{id}").
2020-01-09 12:56:32 +01:00
Get(notify.GetThread).
Patch(notify.ReadThread)
}, reqToken())
2015-12-04 17:16:42 -05:00
// Users
m.Group("/users", func() {
m.Get("/search", reqExploreSignIn(), user.Search)
2015-12-04 17:16:42 -05:00
2021-01-26 23:36:53 +08:00
m.Group("/{username}", func() {
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
m.Get("/repos", reqExploreSignIn(), user.ListUserRepos)
2015-12-04 17:16:42 -05:00
m.Group("/tokens", func() {
m.Combo("").Get(user.ListAccessTokens).
Post(bind(api.CreateAccessTokenOption{}), user.CreateAccessToken)
2021-01-26 23:36:53 +08:00
m.Combo("/{id}").Delete(user.DeleteAccessToken)
}, reqBasicAuth())
}, context_service.UserAssignmentAPI())
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
m.Get("/starred", user.GetStarredRepos)
2016-12-23 20:53:11 -05:00
m.Get("/subscriptions", user.GetWatchedRepos)
}, context_service.UserAssignmentAPI())
}, reqToken())
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() {
m.Get("", user.GetUserSettings)
m.Patch("", bind(api.UserSettingsOptions{}), user.UpdateUserSettings)
}, reqToken())
2015-12-21 04:24:11 -08:00
m.Combo("/emails").Get(user.ListEmails).
Post(bind(api.CreateEmailOption{}), user.AddEmail).
2017-11-12 23:02:25 -08:00
Delete(bind(api.DeleteEmailOption{}), user.DeleteEmail)
2015-12-21 04:24:11 -08:00
m.Get("/followers", user.ListMyFollowers)
m.Group("/following", func() {
m.Get("", user.ListMyFollowing)
m.Group("/{username}", func() {
m.Get("", user.CheckMyFollowing)
m.Put("", user.Follow)
m.Delete("", user.Unfollow)
}, context_service.UserAssignmentAPI())
2015-12-21 04:24:11 -08:00
})
2015-12-04 17:16:42 -05:00
m.Group("/keys", func() {
m.Combo("").Get(user.ListMyPublicKeys).
Post(bind(api.CreateKeyOption{}), user.CreatePublicKey)
2021-01-26 23:36:53 +08:00
m.Combo("/{id}").Get(user.GetPublicKey).
2015-12-04 17:16:42 -05:00
Delete(user.DeletePublicKey)
})
m.Group("/applications", func() {
m.Combo("/oauth2").
Get(user.ListOauth2Applications).
Post(bind(api.CreateOAuth2ApplicationOptions{}), user.CreateOauth2Application)
2021-01-26 23:36:53 +08:00
m.Combo("/oauth2/{id}").
Delete(user.DeleteOauth2Application).
Patch(bind(api.CreateOAuth2ApplicationOptions{}), user.UpdateOauth2Application).
Get(user.GetOauth2Application)
}, reqToken())
2016-11-14 17:33:58 -05:00
2017-03-16 02:27:35 +01:00
m.Group("/gpg_keys", func() {
m.Combo("").Get(user.ListMyGPGKeys).
Post(bind(api.CreateGPGKeyOption{}), user.CreateGPGKey)
2021-01-26 23:36:53 +08:00
m.Combo("/{id}").Get(user.GetGPGKey).
2017-03-16 02:27:35 +01:00
Delete(user.DeleteGPGKey)
})
m.Get("/gpg_key_token", user.GetVerificationToken)
m.Post("/gpg_key_verify", bind(api.VerifyGPGKeyOption{}), user.VerifyUserGPGKey)
2017-02-24 16:39:49 -05:00
m.Combo("/repos").Get(user.ListMyRepos).
Post(bind(api.CreateRepoOption{}), repo.Create)
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)
2016-12-29 08:17:32 -05:00
}, repoAssignment())
2016-11-14 17:33:58 -05:00
})
2017-09-12 08:48:13 +02:00
m.Get("/times", repo.ListMyTrackedTimes)
2016-12-23 20:53:11 -05:00
2019-12-12 05:23:05 +01:00
m.Get("/stopwatches", repo.GetStopwatches)
2016-12-23 20:53:11 -05:00
m.Get("/subscriptions", user.GetMyWatchedRepos)
m.Get("/teams", org.ListUserTeams)
}, reqToken())
2015-12-04 17:16:42 -05:00
// Repositories
2021-01-26 23:36:53 +08:00
m.Post("/org/{org}/repos", reqToken(), bind(api.CreateRepoOption{}), repo.CreateOrgRepoDeprecated)
2021-01-26 23:36:53 +08:00
m.Combo("/repositories/{id}", reqToken()).Get(repo.GetByID)
2015-12-04 17:16:42 -05:00
m.Group("/repos", func() {
m.Get("/search", repo.Search)
m.Get("/issues/search", repo.SearchIssues)
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() {
m.Combo("").Get(reqAnyRepoReader(), repo.Get).
Delete(reqToken(), reqOwner(), repo.Delete).
Patch(reqToken(), reqAdmin(), bind(api.EditRepoOption{}), repo.Edit)
2021-11-10 03:57:58 +08:00
m.Post("/generate", reqToken(), reqRepoReader(unit.TypeCode), bind(api.GenerateRepoOption{}), repo.Generate)
2020-01-31 16:49:04 +01:00
m.Post("/transfer", reqOwner(), bind(api.TransferRepoOption{}), repo.Transfer)
2021-12-24 05:26:52 +01:00
m.Post("/transfer/accept", reqToken(), repo.AcceptTransfer)
m.Post("/transfer/reject", reqToken(), repo.RejectTransfer)
2020-01-09 12:56:32 +01:00
m.Combo("/notifications").
Get(reqToken(), notify.ListRepoNotifications).
Put(reqToken(), notify.ReadRepoNotifications)
2021-02-11 18:34:34 +01:00
m.Group("/hooks/git", func() {
m.Combo("").Get(repo.ListGitHooks)
m.Group("/{id}", func() {
m.Combo("").Get(repo.GetGitHook).
Patch(bind(api.EditGitHookOption{}), repo.EditGitHook).
Delete(repo.DeleteGitHook)
})
}, reqToken(), reqAdmin(), reqGitHook(), context.ReferencesGitRepo(true))
2016-07-16 19:08:38 -05:00
m.Group("/hooks", func() {
m.Combo("").Get(repo.ListHooks).
Post(bind(api.CreateHookOption{}), repo.CreateHook)
2021-01-26 23:36:53 +08:00
m.Group("/{id}", func() {
2018-04-28 23:21:33 -07: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
})
2021-02-11 18:34:34 +01:00
}, reqToken(), reqAdmin(), reqWebhooksEnabled())
2016-12-26 02:37:01 -05:00
m.Group("/collaborators", func() {
m.Get("", reqAnyRepoReader(), repo.ListCollaborators)
m.Group("/{collaborator}", func() {
m.Combo("").Get(reqAnyRepoReader(), repo.IsCollaborator).
Put(reqAdmin(), bind(api.AddCollaboratorOption{}), repo.AddCollaborator).
Delete(reqAdmin(), repo.DeleteCollaborator)
m.Get("/permission", repo.GetRepoPermissions)
}, reqToken())
}, reqToken())
m.Get("/assignees", reqToken(), reqAnyRepoReader(), repo.GetAssignees)
m.Get("/reviewers", reqToken(), reqAnyRepoReader(), repo.GetReviewers)
m.Group("/teams", func() {
m.Get("", reqAnyRepoReader(), repo.ListTeams)
m.Combo("/{team}").Get(reqAnyRepoReader(), repo.IsTeam).
Put(reqAdmin(), repo.AddTeam).
Delete(reqAdmin(), repo.DeleteTeam)
}, reqToken())
m.Get("/raw/*", context.ReferencesGitRepo(), context.RepoRefForAPI, reqRepoReader(unit.TypeCode), repo.GetRawFile)
m.Get("/media/*", context.ReferencesGitRepo(), context.RepoRefForAPI, reqRepoReader(unit.TypeCode), repo.GetRawFileOrLFS)
2021-11-10 03:57:58 +08:00
m.Get("/archive/*", reqRepoReader(unit.TypeCode), repo.GetArchive)
2016-12-30 20:15:45 -05:00
m.Combo("/forks").Get(repo.ListForks).
2021-11-10 03:57:58 +08:00
Post(reqToken(), reqRepoReader(unit.TypeCode), bind(api.CreateForkOption{}), repo.CreateFork)
2016-01-15 19:24:03 +01:00
m.Group("/branches", func() {
m.Get("", repo.ListBranches)
m.Get("/*", repo.GetBranch)
m.Delete("/*", reqRepoWriter(unit.TypeCode), repo.DeleteBranch)
m.Post("", reqRepoWriter(unit.TypeCode), bind(api.CreateBranchRepoOption{}), repo.CreateBranch)
}, context.ReferencesGitRepo(), reqRepoReader(unit.TypeCode))
2020-02-13 00:19:35 +01:00
m.Group("/branch_protections", func() {
m.Get("", repo.ListBranchProtections)
m.Post("", bind(api.CreateBranchProtectionOption{}), 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)
m.Patch("", bind(api.EditBranchProtectionOption{}), repo.EditBranchProtection)
m.Delete("", repo.DeleteBranchProtection)
})
}, 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)
2021-11-10 03:57:58 +08:00
m.Post("", reqRepoWriter(unit.TypeCode), bind(api.CreateTagOption{}), repo.CreateTag)
2021-06-23 23:08:47 +02:00
m.Delete("/*", repo.DeleteTag)
2021-11-10 03:57:58 +08:00
}, reqRepoReader(unit.TypeCode), 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)
}, 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)
2020-01-08 22:14:00 +01:00
}, mustEnableIssues, reqToken())
2021-10-25 05:43:40 +02:00
m.Group("/wiki", func() {
m.Combo("/page/{pageName}").
Get(repo.GetWikiPage).
2021-11-10 03:57:58 +08:00
Patch(mustNotBeArchived, reqRepoWriter(unit.TypeWiki), bind(api.CreateWikiPageOptions{}), repo.EditWikiPage).
Delete(mustNotBeArchived, reqRepoWriter(unit.TypeWiki), repo.DeleteWikiPage)
2021-10-25 05:43:40 +02:00
m.Get("/revisions/{pageName}", repo.ListPageRevisions)
2021-11-10 03:57:58 +08:00
m.Post("/new", mustNotBeArchived, reqRepoWriter(unit.TypeWiki), bind(api.CreateWikiPageOptions{}), repo.NewWikiPage)
2021-10-25 05:43:40 +02:00
m.Get("/pages", repo.ListWikiPages)
}, mustEnableWiki)
2016-03-13 23:20:22 -04:00
m.Group("/issues", func() {
2017-07-11 21:23:41 -04:00
m.Combo("").Get(repo.ListIssues).
Post(reqToken(), mustNotBeArchived, bind(api.CreateIssueOption{}), repo.CreateIssue)
2016-12-22 09:29:26 +01:00
m.Group("/comments", func() {
m.Get("", repo.ListRepoIssueComments)
2021-01-26 23:36:53 +08:00
m.Group("/{id}", func() {
m.Combo("").
Get(repo.GetIssueComment).
Patch(mustNotBeArchived, reqToken(), bind(api.EditIssueCommentOption{}), repo.EditIssueComment).
Delete(reqToken(), repo.DeleteIssueComment)
m.Combo("/reactions").
2019-12-07 23:04:19 +01:00
Get(repo.GetIssueCommentReactions).
2021-01-16 19:23:02 +08:00
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)
m.Combo("/{asset}").
Get(repo.GetIssueCommentAttachment).
Patch(reqToken(), mustNotBeArchived, bind(api.EditAttachmentOptions{}), repo.EditIssueCommentAttachment).
Delete(reqToken(), mustNotBeArchived, repo.DeleteIssueCommentAttachment)
}, mustEnableAttachments)
2019-12-07 23:04:19 +01:00
})
2016-12-22 09:29:26 +01:00
})
2021-01-26 23:36:53 +08:00
m.Group("/{index}", func() {
2017-07-11 21:23:41 -04:00
m.Combo("").Get(repo.GetIssue).
2022-03-01 01:20:15 +01:00
Patch(reqToken(), bind(api.EditIssueOption{}), repo.EditIssue).
Delete(reqToken(), reqAdmin(), context.ReferencesGitRepo(), repo.DeleteIssue)
m.Group("/comments", func() {
2017-07-11 21:23:41 -04:00
m.Combo("").Get(repo.ListIssueComments).
Post(reqToken(), mustNotBeArchived, bind(api.CreateIssueCommentOption{}), repo.CreateIssueComment)
2021-01-26 23:36:53 +08:00
m.Combo("/{id}", reqToken()).Patch(bind(api.EditIssueCommentOption{}), repo.EditIssueCommentDeprecated).
2017-11-19 23:24:07 -08:00
Delete(repo.DeleteIssueCommentDeprecated)
})
m.Get("/timeline", repo.ListIssueCommentsAndTimeline)
2016-08-03 09:24:16 -07:00
m.Group("/labels", func() {
m.Combo("").Get(repo.ListIssueLabels).
2017-07-11 21:23:41 -04:00
Post(reqToken(), bind(api.IssueLabelsOption{}), repo.AddIssueLabels).
Put(reqToken(), bind(api.IssueLabelsOption{}), repo.ReplaceIssueLabels).
Delete(reqToken(), repo.ClearIssueLabels)
2021-01-26 23:36:53 +08:00
m.Delete("/{id}", reqToken(), repo.DeleteIssueLabel)
2016-08-03 09:24:16 -07:00
})
2017-09-12 08:48:13 +02:00
m.Group("/times", func() {
2020-01-08 22:14:00 +01:00
m.Combo("").
2019-12-27 21:30:58 +01:00
Get(repo.ListTrackedTimes).
Post(bind(api.AddTimeOption{}), repo.AddTime).
Delete(repo.ResetIssueTime)
2021-01-26 23:36:53 +08:00
m.Delete("/{id}", repo.DeleteTime)
2020-01-08 22:14:00 +01:00
}, reqToken())
2018-07-16 14:43:00 +02:00
m.Combo("/deadline").Post(reqToken(), bind(api.EditDeadlineOption{}), repo.UpdateIssueDeadline)
m.Group("/stopwatch", func() {
m.Post("/start", reqToken(), repo.StartIssueStopwatch)
m.Post("/stop", reqToken(), repo.StopIssueStopwatch)
2019-12-12 05:23:05 +01:00
m.Delete("/delete", reqToken(), repo.DeleteIssueStopwatch)
})
2019-11-02 16:27:49 +01:00
m.Group("/subscriptions", func() {
2019-11-20 15:50:54 +01:00
m.Get("", repo.GetIssueSubscribers)
m.Get("/check", reqToken(), repo.CheckIssueSubscription)
2021-01-26 23:36:53 +08:00
m.Put("/{user}", reqToken(), repo.AddIssueSubscription)
m.Delete("/{user}", reqToken(), repo.DelIssueSubscription)
2019-11-02 16:27:49 +01:00
})
m.Combo("/reactions").
2019-12-07 23:04:19 +01:00
Get(repo.GetIssueReactions).
2021-01-16 19:23:02 +08:00
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)
m.Combo("/{asset}").
Get(repo.GetIssueAttachment).
Patch(reqToken(), mustNotBeArchived, bind(api.EditAttachmentOptions{}), repo.EditIssueAttachment).
Delete(reqToken(), mustNotBeArchived, repo.DeleteIssueAttachment)
}, mustEnableAttachments)
2016-08-03 09:24:16 -07:00
})
}, mustEnableIssuesOrPulls)
2016-08-03 09:24:16 -07:00
m.Group("/labels", func() {
m.Combo("").Get(repo.ListLabels).
2021-11-10 03:57:58 +08:00
Post(reqToken(), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), bind(api.CreateLabelOption{}), repo.CreateLabel)
2021-01-26 23:36:53 +08:00
m.Combo("/{id}").Get(repo.GetLabel).
2021-11-10 03:57:58 +08:00
Patch(reqToken(), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), bind(api.EditLabelOption{}), repo.EditLabel).
Delete(reqToken(), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), repo.DeleteLabel)
})
2019-04-12 01:53:34 -04:00
m.Post("/markdown", bind(api.MarkdownOption{}), misc.Markdown)
m.Post("/markdown/raw", misc.MarkdownRaw)
m.Group("/milestones", func() {
m.Combo("").Get(repo.ListMilestones).
2021-11-10 03:57:58 +08:00
Post(reqToken(), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), bind(api.CreateMilestoneOption{}), repo.CreateMilestone)
2021-01-26 23:36:53 +08:00
m.Combo("/{id}").Get(repo.GetMilestone).
2021-11-10 03:57:58 +08:00
Patch(reqToken(), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), bind(api.EditMilestoneOption{}), repo.EditMilestone).
Delete(reqToken(), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), repo.DeleteMilestone)
})
2017-01-06 02:05:09 -05:00
m.Get("/stargazers", 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)
2017-07-11 21:23:41 -04:00
m.Put("", reqToken(), user.Watch)
m.Delete("", reqToken(), user.Unwatch)
2016-12-29 08:17:32 -05:00
})
2016-12-31 11:51:22 -05:00
m.Group("/releases", func() {
m.Combo("").Get(repo.ListReleases).
Post(reqToken(), reqRepoWriter(unit.TypeReleases), context.ReferencesGitRepo(), bind(api.CreateReleaseOption{}), repo.CreateRelease)
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).
Patch(reqToken(), reqRepoWriter(unit.TypeReleases), context.ReferencesGitRepo(), bind(api.EditReleaseOption{}), repo.EditRelease).
2021-11-10 03:57:58 +08:00
Delete(reqToken(), reqRepoWriter(unit.TypeReleases), repo.DeleteRelease)
2018-03-06 02:22:16 +01:00
m.Group("/assets", func() {
m.Combo("").Get(repo.ListReleaseAttachments).
2021-11-10 03:57:58 +08:00
Post(reqToken(), reqRepoWriter(unit.TypeReleases), repo.CreateReleaseAttachment)
2021-01-26 23:36:53 +08:00
m.Combo("/{asset}").Get(repo.GetReleaseAttachment).
2021-11-10 03:57:58 +08: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}").
Get(repo.GetReleaseByTag).
2021-11-10 03:57:58 +08: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))
m.Post("/mirror-sync", reqToken(), reqRepoWriter(unit.TypeCode), repo.MirrorSync)
m.Post("/push_mirrors-sync", reqAdmin(), repo.PushMirrorSync)
m.Group("/push_mirrors", func() {
m.Combo("").Get(repo.ListPushMirrors).
Post(bind(api.CreatePushMirrorOption{}), repo.AddPushMirror)
m.Combo("/{name}").
Delete(repo.DeletePushMirrorByRemoteName).
Get(repo.GetPushMirrorByName)
}, reqAdmin())
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).
Post(reqToken(), mustNotBeArchived, bind(api.CreatePullRequestOption{}), repo.CreatePullRequest)
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).
Patch(reqToken(), bind(api.EditPullRequestOption{}), repo.EditPullRequest)
m.Get(".{diffType:diff|patch}", repo.DownloadPullDiffOrPatch)
2020-08-05 04:55:22 +08:00
m.Post("/update", reqToken(), repo.UpdatePullRequest)
2021-07-02 14:19:57 +02:00
m.Get("/commits", repo.GetPullRequestCommits)
m.Get("/files", repo.GetPullRequestFiles)
2017-07-11 21:23:41 -04:00
m.Combo("/merge").Get(repo.IsPullRequestMerged).
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).
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).
Delete(reqToken(), repo.DeletePullReview).
Post(reqToken(), bind(api.SubmitPullReviewOptions{}), repo.SubmitPullReview)
m.Combo("/comments").
Get(repo.GetPullReviewComments)
2021-02-12 01:32:25 +08:00
m.Post("/dismissals", reqToken(), bind(api.DismissPullReviewOptions{}), repo.DismissPullReview)
m.Post("/undismissals", reqToken(), repo.UnDismissPullReview)
2020-05-02 02:20:51 +02:00
})
})
2020-10-21 02:18:25 +08:00
m.Combo("/requested_reviewers").
Delete(reqToken(), bind(api.PullReviewRequestOptions{}), repo.DeleteReviewRequests).
Post(reqToken(), bind(api.PullReviewRequestOptions{}), repo.CreateReviewRequests)
2016-12-02 12:10:39 +01:00
})
}, mustAllowPulls, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo())
2017-04-21 13:32:31 +02:00
m.Group("/statuses", func() {
2021-01-26 23:36:53 +08:00
m.Combo("/{sha}").Get(repo.GetCommitStatuses).
Post(reqToken(), reqRepoWriter(unit.TypeCode), bind(api.CreateStatusOption{}), repo.NewCommitStatus)
2021-11-10 03:57:58 +08:00
}, reqRepoReader(unit.TypeCode))
m.Group("/commits", func() {
m.Get("", context.ReferencesGitRepo(), repo.GetAllCommits)
2021-01-26 23:36:53 +08:00
m.Group("/{ref}", func() {
m.Get("/status", repo.GetCombinedCommitStatusByRef)
m.Get("/statuses", repo.GetCommitStatusesByRef)
2022-04-30 16:32:01 +02:00
}, context.ReferencesGitRepo())
2021-11-10 03:57:58 +08:00
}, reqRepoReader(unit.TypeCode))
m.Group("/git", func() {
2019-02-03 11:35:17 +08:00
m.Group("/commits", func() {
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
})
m.Get("/refs", repo.GetGitAllRefs)
m.Get("/refs/*", repo.GetGitRefs)
m.Get("/trees/{sha}", repo.GetTree)
m.Get("/blobs/{sha}", repo.GetBlob)
m.Get("/tags/{sha}", repo.GetAnnotatedTag)
m.Get("/notes/{sha}", repo.GetNote)
}, context.ReferencesGitRepo(), reqRepoReader(unit.TypeCode))
m.Post("/diffpatch", reqRepoWriter(unit.TypeCode), reqToken(), bind(api.ApplyDiffPatchFileOptions{}), repo.ApplyDiffPatch)
m.Group("/contents", func() {
2019-06-29 16:51:10 -04:00
m.Get("", repo.GetContentsList)
m.Get("/*", repo.GetContents)
m.Group("/*", func() {
m.Post("", bind(api.CreateFileOptions{}), reqRepoBranchWriter, repo.CreateFile)
m.Put("", bind(api.UpdateFileOptions{}), reqRepoBranchWriter, repo.UpdateFile)
m.Delete("", bind(api.DeleteFileOptions{}), reqRepoBranchWriter, repo.DeleteFile)
}, reqToken())
2021-11-10 03:57:58 +08:00
}, reqRepoReader(unit.TypeCode))
m.Get("/signing-key.gpg", misc.SigningKey)
m.Group("/topics", func() {
m.Combo("").Get(repo.ListTopics).
Put(reqToken(), reqAdmin(), bind(api.RepoTopicOptions{}), repo.UpdateTopics)
2021-01-26 23:36:53 +08:00
m.Group("/{topic}", func() {
m.Combo("").Put(reqToken(), repo.AddTopic).
Delete(reqToken(), repo.DeleteTopic)
}, reqAdmin())
}, reqAnyRepoReader())
m.Get("/issue_templates", context.ReferencesGitRepo(), repo.GetIssueTemplates)
2021-11-10 03:57:58 +08:00
m.Get("/languages", reqRepoReader(unit.TypeCode), repo.GetLanguages)
}, repoAssignment())
2017-07-11 21:23:41 -04:00
})
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() {
m.Group("/{type}/{name}/{version}", func() {
m.Get("", packages.GetPackage)
m.Delete("", reqPackageAccess(perm.AccessModeWrite), packages.DeletePackage)
m.Get("/files", packages.ListPackageFiles)
})
m.Get("/", packages.ListPackages)
}, context_service.UserAssignmentAPI(), context.PackageAssignmentAPI(), reqPackageAccess(perm.AccessModeRead))
2015-12-17 02:28:47 -05:00
// Organizations
m.Get("/user/orgs", reqToken(), org.ListMyOrgs)
m.Group("/users/{username}/orgs", func() {
m.Get("", org.ListUserOrgs)
m.Get("/{org}/permissions", reqToken(), org.GetUserOrgsPermissions)
}, context_service.UserAssignmentAPI())
2018-11-21 01:31:30 +08:00
m.Post("/orgs", reqToken(), bind(api.CreateOrgOption{}), org.Create)
2020-01-12 16:43:44 +01:00
m.Get("/orgs", org.GetAll)
2021-01-26 23:36:53 +08:00
m.Group("/orgs/{org}", func() {
2017-01-26 06:54:04 -05:00
m.Combo("").Get(org.Get).
2018-12-27 21:06:58 +05:30
Patch(reqToken(), reqOrgOwnership(), bind(api.EditOrgOption{}), org.Edit).
Delete(reqToken(), reqOrgOwnership(), org.Delete)
m.Combo("/repos").Get(user.ListOrgRepos).
Post(reqToken(), bind(api.CreateRepoOption{}), repo.CreateOrgRepo)
m.Group("/members", func() {
m.Get("", org.ListMembers)
2021-01-26 23:36:53 +08:00
m.Combo("/{username}").Get(org.IsMember).
Delete(reqToken(), reqOrgOwnership(), org.DeleteMember)
})
m.Group("/public_members", func() {
m.Get("", org.ListPublicMembers)
2021-01-26 23:36:53 +08:00
m.Combo("/{username}").Get(org.IsPublicMember).
Put(reqToken(), reqOrgMembership(), org.PublicizeMember).
Delete(reqToken(), reqOrgMembership(), org.ConcealMember)
})
2019-10-01 07:32:28 +02:00
m.Group("/teams", func() {
m.Get("", org.ListTeams)
m.Post("", reqOrgOwnership(), bind(api.CreateTeamOption{}), org.CreateTeam)
2019-10-01 07:32:28 +02:00
m.Get("/search", org.SearchTeam)
}, reqToken(), reqOrgMembership())
2020-04-01 00:14:46 -04:00
m.Group("/labels", func() {
m.Get("", org.ListLabels)
m.Post("", reqToken(), reqOrgOwnership(), bind(api.CreateLabelOption{}), org.CreateLabel)
2021-01-26 23:36:53 +08:00
m.Combo("/{id}").Get(org.GetLabel).
2020-04-01 00:14:46 -04:00
Patch(reqToken(), reqOrgOwnership(), bind(api.EditLabelOption{}), org.EditLabel).
Delete(reqToken(), reqOrgOwnership(), org.DeleteLabel)
})
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)
2021-02-11 18:34:34 +01:00
}, reqToken(), reqOrgOwnership(), reqWebhooksEnabled())
}, orgAssignment(true))
2021-01-26 23:36:53 +08:00
m.Group("/teams/{teamid}", func() {
2017-01-19 22:16:10 -07:00
m.Combo("").Get(org.GetTeam).
2017-01-26 06:54:04 -05:00
Patch(reqOrgOwnership(), bind(api.EditTeamOption{}), org.EditTeam).
Delete(reqOrgOwnership(), org.DeleteTeam)
2017-01-19 22:16:10 -07:00
m.Group("/members", func() {
m.Get("", org.GetTeamMembers)
2021-01-26 23:36:53 +08:00
m.Combo("/{username}").
Get(org.GetTeamMember).
2017-01-26 06:54:04 -05:00
Put(reqOrgOwnership(), org.AddTeamMember).
Delete(reqOrgOwnership(), org.RemoveTeamMember)
2017-01-19 22:16:10 -07:00
})
m.Group("/repos", func() {
m.Get("", org.GetTeamRepos)
2021-01-26 23:36:53 +08:00
m.Combo("/{org}/{reponame}").
2017-01-26 06:54:04 -05:00
Put(org.AddTeamRepository).
Delete(org.RemoveTeamRepository).
Get(org.GetTeamRepo)
2017-01-19 22:16:10 -07:00
})
2019-04-24 13:32:35 +08:00
}, orgAssignment(false, true), reqToken(), reqTeamMembership())
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() {
2019-01-24 04:00:19 +05:30
m.Get("", admin.GetAllUsers)
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)
m.Group("/keys", func() {
m.Post("", bind(api.CreateKeyOption{}), admin.CreatePublicKey)
2021-01-26 23:36:53 +08:00
m.Delete("/{id}", admin.DeleteUserPublicKey)
})
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)
}, context_service.UserAssignmentAPI())
2015-12-05 17:13:13 -05:00
})
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
})
}, reqToken(), reqSiteAdmin())
2018-04-11 10:51:44 +08:00
m.Group("/topics", func() {
m.Get("/search", repo.TopicSearch)
})
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
}