aboutsummaryrefslogtreecommitdiffstats
path: root/routers/api
diff options
context:
space:
mode:
authorJack Hay <jack@allspice.io>2023-06-04 14:57:16 -0400
committerGitHub <noreply@github.com>2023-06-04 20:57:16 +0200
commit18de83b2a3fc120922096b7348d6375094ae1532 (patch)
treea9724bcb6f00a040e5a16970ce56931cd1aa3d51 /routers/api
parent520eb57d7642a5fca3df319e5b5d1c7c9018087c (diff)
downloadgitea-18de83b2a3fc120922096b7348d6375094ae1532.tar.gz
gitea-18de83b2a3fc120922096b7348d6375094ae1532.zip
Redesign Scoped Access Tokens (#24767)
## Changes - Adds the following high level access scopes, each with `read` and `write` levels: - `activitypub` - `admin` (hidden if user is not a site admin) - `misc` - `notification` - `organization` - `package` - `issue` - `repository` - `user` - Adds new middleware function `tokenRequiresScopes()` in addition to `reqToken()` - `tokenRequiresScopes()` is used for each high-level api section - _if_ a scoped token is present, checks that the required scope is included based on the section and HTTP method - `reqToken()` is used for individual routes - checks that required authentication is present (but does not check scope levels as this will already have been handled by `tokenRequiresScopes()` - Adds migration to convert old scoped access tokens to the new set of scopes - Updates the user interface for scope selection ### User interface example <img width="903" alt="Screen Shot 2023-05-31 at 1 56 55 PM" src="https://github.com/go-gitea/gitea/assets/23248839/654766ec-2143-4f59-9037-3b51600e32f3"> <img width="917" alt="Screen Shot 2023-05-31 at 1 56 43 PM" src="https://github.com/go-gitea/gitea/assets/23248839/1ad64081-012c-4a73-b393-66b30352654c"> ## tokenRequiresScopes Design Decision - `tokenRequiresScopes()` was added to more reliably cover api routes. For an incoming request, this function uses the given scope category (say `AccessTokenScopeCategoryOrganization`) and the HTTP method (say `DELETE`) and verifies that any scoped tokens in use include `delete:organization`. - `reqToken()` is used to enforce auth for individual routes that require it. If a scoped token is not present for a request, `tokenRequiresScopes()` will not return an error ## TODO - [x] Alphabetize scope categories - [x] Change 'public repos only' to a radio button (private vs public). Also expand this to organizations - [X] Disable token creation if no scopes selected. Alternatively, show warning - [x] `reqToken()` is missing from many `POST/DELETE` routes in the api. `tokenRequiresScopes()` only checks that a given token has the correct scope, `reqToken()` must be used to check that a token (or some other auth) is present. - _This should be addressed in this PR_ - [x] The migration should be reviewed very carefully in order to minimize access changes to existing user tokens. - _This should be addressed in this PR_ - [x] Link to api to swagger documentation, clarify what read/write/delete levels correspond to - [x] Review cases where more than one scope is needed as this directly deviates from the api definition. - _This should be addressed in this PR_ - For example: ```go m.Group("/users/{username}/orgs", func() { m.Get("", reqToken(), org.ListUserOrgs) m.Get("/{org}/permissions", reqToken(), org.GetUserOrgsPermissions) }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), context_service.UserAssignmentAPI()) ``` ## Future improvements - [ ] Add required scopes to swagger documentation - [ ] Redesign `reqToken()` to be opt-out rather than opt-in - [ ] Subdivide scopes like `repository` - [ ] Once a token is created, if it has no scopes, we should display text instead of an empty bullet point - [ ] If the 'public repos only' option is selected, should read categories be selected by default Closes #24501 Closes #24799 Co-authored-by: Jonathan Tran <jon@allspice.io> Co-authored-by: Kyle D <kdumontnu@gmail.com> Co-authored-by: silverwind <me@silverwind.io>
Diffstat (limited to 'routers/api')
-rw-r--r--routers/api/v1/api.go677
1 files changed, 372 insertions, 305 deletions
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go
index 45e36e84fe..37361a8b96 100644
--- a/routers/api/v1/api.go
+++ b/routers/api/v1/api.go
@@ -236,44 +236,85 @@ func reqPackageAccess(accessMode perm.AccessMode) func(ctx *context.APIContext)
}
}
+// 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
+ }
+
+ ctx.Data["ApiTokenScopePublicRepoOnly"] = false
+ ctx.Data["ApiTokenScopePublicOrgOnly"] = false
+
+ // use the http method to determine the access level
+ requiredScopeLevel := auth_model.Read
+ if ctx.Req.Method == "POST" || ctx.Req.Method == "PUT" || ctx.Req.Method == "PATCH" || ctx.Req.Method == "DELETE" {
+ requiredScopeLevel = auth_model.Write
+ }
+
+ // get the required scope for the given access level and category
+ requiredScopes := auth_model.GetRequiredScopes(requiredScopeLevel, requiredScopeCategories...)
+
+ // check if scope only applies to public resources
+ publicOnly, err := scope.PublicOnly()
+ if err != nil {
+ ctx.Error(http.StatusForbidden, "tokenRequiresScope", "parsing public resource scope failed: "+err.Error())
+ return
+ }
+
+ // this context is used by the middleware in the specific route
+ ctx.Data["ApiTokenScopePublicRepoOnly"] = publicOnly && auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryRepository)
+ ctx.Data["ApiTokenScopePublicOrgOnly"] = publicOnly && auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryOrganization)
+
+ allow, err := scope.HasScope(requiredScopes...)
+ if err != nil {
+ ctx.Error(http.StatusForbidden, "tokenRequiresScope", "checking scope failed: "+err.Error())
+ return
+ }
+
+ if allow {
+ return
+ }
+
+ ctx.Error(http.StatusForbidden, "tokenRequiresScope", fmt.Sprintf("token does not have at least one of required scope(s): %v", requiredScopes))
+ }
+}
+
// Contexter middleware already checks token for user sign in process.
-func reqToken(requiredScope auth_model.AccessTokenScope) func(ctx *context.APIContext) {
+func reqToken() func(ctx *context.APIContext) {
return func(ctx *context.APIContext) {
// If actions token is present
if true == ctx.Data["IsActionsToken"] {
return
}
- // If OAuth2 token is present
- if _, ok := ctx.Data["ApiTokenScope"]; ctx.Data["IsApiToken"] == true && ok {
- // no scope required
- if requiredScope == "" {
- return
- }
+ if true == ctx.Data["IsApiToken"] {
+ publicRepo, pubRepoExists := ctx.Data["ApiTokenScopePublicRepoOnly"]
+ publicOrg, pubOrgExists := ctx.Data["ApiTokenScopePublicOrgOnly"]
- // check scope
- scope := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope)
- allow, err := scope.HasScope(requiredScope)
- if err != nil {
- ctx.Error(http.StatusForbidden, "reqToken", "parsing token failed: "+err.Error())
- return
- }
- if allow {
+ if pubRepoExists && publicRepo.(bool) &&
+ ctx.Repo.Repository != nil && ctx.Repo.Repository.IsPrivate {
+ ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public repos")
return
}
- // if requires 'repo' scope, but only has 'public_repo' scope, allow it only if the repo is public
- if requiredScope == auth_model.AccessTokenScopeRepo {
- if allowPublicRepo, err := scope.HasScope(auth_model.AccessTokenScopePublicRepo); err == nil && allowPublicRepo {
- if ctx.Repo.Repository != nil && !ctx.Repo.Repository.IsPrivate {
- return
- }
- }
+ if pubOrgExists && publicOrg.(bool) &&
+ ctx.Org.Organization != nil && ctx.Org.Organization.Visibility != api.VisibleTypePublic {
+ ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public orgs")
+ return
}
- ctx.Error(http.StatusForbidden, "reqToken", "token does not have required scope: "+requiredScope)
return
}
+
if ctx.IsBasicAuth {
ctx.CheckForOTP()
return
@@ -700,7 +741,7 @@ func Routes(ctx gocontext.Context) *web.Route {
ctx.Redirect(setting.AppSubURL + "/api/swagger")
})
}
- m.Get("/version", misc.Version)
+
if setting.Federation.Enabled {
m.Get("/nodeinfo", misc.NodeInfo)
m.Group("/activitypub", func() {
@@ -713,37 +754,43 @@ func Routes(ctx gocontext.Context) *web.Route {
m.Get("", activitypub.Person)
m.Post("/inbox", activitypub.ReqHTTPSignature(), activitypub.PersonInbox)
}, context_service.UserIDAssignmentAPI())
- })
+ }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryActivityPub))
}
- m.Get("/signing-key.gpg", misc.SigningKey)
- m.Post("/markup", bind(api.MarkupOption{}), misc.Markup)
- m.Post("/markdown", bind(api.MarkdownOption{}), misc.Markdown)
- m.Post("/markdown/raw", 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)
- })
- // Notifications (requires 'notification' scope)
+ // Misc (requires 'misc' scope)
+ m.Group("", func() {
+ m.Get("/version", misc.Version)
+ m.Get("/signing-key.gpg", misc.SigningKey)
+ 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)
+ })
+ }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryMisc))
+
+ // Notifications (requires 'notifications' scope)
m.Group("/notifications", func() {
m.Combo("").
Get(notify.ListNotifications).
- Put(notify.ReadNotifications)
+ Put(notify.ReadNotifications, reqToken())
m.Get("/new", notify.NewAvailable)
m.Combo("/threads/{id}").
Get(notify.GetThread).
- Patch(notify.ReadThread)
- }, reqToken(auth_model.AccessTokenScopeNotification))
+ Patch(notify.ReadThread, reqToken())
+ }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryNotification))
- // Users (no scope required)
+ // Users (requires user scope)
m.Group("/users", func() {
m.Get("/search", reqExploreSignIn(), user.Search)
@@ -754,18 +801,18 @@ func Routes(ctx gocontext.Context) *web.Route {
m.Get("/heatmap", user.GetUserHeatmapData)
}
- m.Get("/repos", reqExploreSignIn(), user.ListUserRepos)
+ m.Get("/repos", tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository), reqExploreSignIn(), user.ListUserRepos)
m.Group("/tokens", func() {
m.Combo("").Get(user.ListAccessTokens).
- Post(bind(api.CreateAccessTokenOption{}), user.CreateAccessToken)
- m.Combo("/{id}").Delete(user.DeleteAccessToken)
+ Post(bind(api.CreateAccessTokenOption{}), reqToken(), user.CreateAccessToken)
+ m.Combo("/{id}").Delete(reqToken(), user.DeleteAccessToken)
}, reqBasicAuth())
m.Get("/activities/feeds", user.ListUserActivityFeeds)
}, context_service.UserAssignmentAPI())
- })
+ }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser))
- // (no scope required)
+ // Users (requires user scope)
m.Group("/users", func() {
m.Group("/{username}", func() {
m.Get("/keys", user.ListPublicKeys)
@@ -781,59 +828,61 @@ func Routes(ctx gocontext.Context) *web.Route {
m.Get("/subscriptions", user.GetWatchedRepos)
}, context_service.UserAssignmentAPI())
- }, reqToken(""))
+ }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser), reqToken())
+ // Users (requires user scope)
m.Group("/user", func() {
m.Get("", user.GetAuthenticatedUser)
m.Group("/settings", func() {
- m.Get("", reqToken(auth_model.AccessTokenScopeReadUser), user.GetUserSettings)
- m.Patch("", reqToken(auth_model.AccessTokenScopeUser), bind(api.UserSettingsOptions{}), user.UpdateUserSettings)
- })
- m.Combo("/emails").Get(reqToken(auth_model.AccessTokenScopeReadUser), user.ListEmails).
- Post(reqToken(auth_model.AccessTokenScopeUser), bind(api.CreateEmailOption{}), user.AddEmail).
- Delete(reqToken(auth_model.AccessTokenScopeUser), bind(api.DeleteEmailOption{}), user.DeleteEmail)
+ 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)
m.Get("/followers", user.ListMyFollowers)
m.Group("/following", func() {
m.Get("", user.ListMyFollowing)
m.Group("/{username}", func() {
m.Get("", user.CheckMyFollowing)
- m.Put("", reqToken(auth_model.AccessTokenScopeUserFollow), user.Follow) // requires 'user:follow' scope
- m.Delete("", reqToken(auth_model.AccessTokenScopeUserFollow), user.Unfollow) // requires 'user:follow' scope
+ m.Put("", user.Follow)
+ m.Delete("", user.Unfollow)
}, context_service.UserAssignmentAPI())
})
// (admin:public_key scope)
m.Group("/keys", func() {
- m.Combo("").Get(reqToken(auth_model.AccessTokenScopeReadPublicKey), user.ListMyPublicKeys).
- Post(reqToken(auth_model.AccessTokenScopeWritePublicKey), bind(api.CreateKeyOption{}), user.CreatePublicKey)
- m.Combo("/{id}").Get(reqToken(auth_model.AccessTokenScopeReadPublicKey), user.GetPublicKey).
- Delete(reqToken(auth_model.AccessTokenScopeWritePublicKey), user.DeletePublicKey)
+ m.Combo("").Get(user.ListMyPublicKeys).
+ Post(bind(api.CreateKeyOption{}), user.CreatePublicKey)
+ m.Combo("/{id}").Get(user.GetPublicKey).
+ Delete(user.DeletePublicKey)
})
// (admin:application scope)
m.Group("/applications", func() {
m.Combo("/oauth2").
- Get(reqToken(auth_model.AccessTokenScopeReadApplication), user.ListOauth2Applications).
- Post(reqToken(auth_model.AccessTokenScopeWriteApplication), bind(api.CreateOAuth2ApplicationOptions{}), user.CreateOauth2Application)
+ Get(user.ListOauth2Applications).
+ Post(bind(api.CreateOAuth2ApplicationOptions{}), user.CreateOauth2Application)
m.Combo("/oauth2/{id}").
- Delete(reqToken(auth_model.AccessTokenScopeWriteApplication), user.DeleteOauth2Application).
- Patch(reqToken(auth_model.AccessTokenScopeWriteApplication), bind(api.CreateOAuth2ApplicationOptions{}), user.UpdateOauth2Application).
- Get(reqToken(auth_model.AccessTokenScopeReadApplication), user.GetOauth2Application)
+ Delete(user.DeleteOauth2Application).
+ Patch(bind(api.CreateOAuth2ApplicationOptions{}), user.UpdateOauth2Application).
+ Get(user.GetOauth2Application)
})
// (admin:gpg_key scope)
m.Group("/gpg_keys", func() {
- m.Combo("").Get(reqToken(auth_model.AccessTokenScopeReadGPGKey), user.ListMyGPGKeys).
- Post(reqToken(auth_model.AccessTokenScopeWriteGPGKey), bind(api.CreateGPGKeyOption{}), user.CreateGPGKey)
- m.Combo("/{id}").Get(reqToken(auth_model.AccessTokenScopeReadGPGKey), user.GetGPGKey).
- Delete(reqToken(auth_model.AccessTokenScopeWriteGPGKey), user.DeleteGPGKey)
+ m.Combo("").Get(user.ListMyGPGKeys).
+ Post(bind(api.CreateGPGKeyOption{}), user.CreateGPGKey)
+ m.Combo("/{id}").Get(user.GetGPGKey).
+ Delete(user.DeleteGPGKey)
})
- m.Get("/gpg_key_token", reqToken(auth_model.AccessTokenScopeReadGPGKey), user.GetVerificationToken)
- m.Post("/gpg_key_verify", reqToken(auth_model.AccessTokenScopeReadGPGKey), bind(api.VerifyGPGKeyOption{}), user.VerifyUserGPGKey)
+ m.Get("/gpg_key_token", user.GetVerificationToken)
+ m.Post("/gpg_key_verify", bind(api.VerifyGPGKeyOption{}), user.VerifyUserGPGKey)
// (repo scope)
- m.Combo("/repos", reqToken(auth_model.AccessTokenScopeRepo)).Get(user.ListMyRepos).
+ m.Combo("/repos", tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository)).Get(user.ListMyRepos).
Post(bind(api.CreateRepoOption{}), repo.Create)
// (repo scope)
@@ -844,64 +893,65 @@ func Routes(ctx gocontext.Context) *web.Route {
m.Put("", user.Star)
m.Delete("", user.Unstar)
}, repoAssignment())
- }, reqToken(auth_model.AccessTokenScopeRepo))
- m.Get("/times", reqToken(auth_model.AccessTokenScopeRepo), repo.ListMyTrackedTimes)
- m.Get("/stopwatches", reqToken(auth_model.AccessTokenScopeRepo), repo.GetStopwatches)
- m.Get("/subscriptions", reqToken(auth_model.AccessTokenScopeRepo), user.GetMyWatchedRepos)
- m.Get("/teams", reqToken(auth_model.AccessTokenScopeRepo), org.ListUserTeams)
+ }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository))
+ m.Get("/times", repo.ListMyTrackedTimes)
+ m.Get("/stopwatches", repo.GetStopwatches)
+ m.Get("/subscriptions", user.GetMyWatchedRepos)
+ m.Get("/teams", org.ListUserTeams)
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)
- }, reqToken(auth_model.AccessTokenScopeAdminUserHook), reqWebhooksEnabled())
- }, reqToken(""))
+ }, reqWebhooksEnabled())
+ }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser), reqToken())
- // Repositories
- m.Post("/org/{org}/repos", reqToken(auth_model.AccessTokenScopeAdminOrg), bind(api.CreateRepoOption{}), repo.CreateOrgRepoDeprecated)
+ // Repositories (requires repo scope, org scope)
+ m.Post("/org/{org}/repos",
+ tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization, auth_model.AccessTokenScopeCategoryRepository),
+ reqToken(),
+ bind(api.CreateRepoOption{}),
+ repo.CreateOrgRepoDeprecated)
- m.Combo("/repositories/{id}", reqToken(auth_model.AccessTokenScopeRepo)).Get(repo.GetByID)
+ // requires repo scope
+ m.Combo("/repositories/{id}", reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository)).Get(repo.GetByID)
+ // Repos (requires repo scope)
m.Group("/repos", func() {
m.Get("/search", repo.Search)
- m.Get("/issues/search", repo.SearchIssues)
-
// (repo scope)
- m.Post("/migrate", reqToken(auth_model.AccessTokenScopeRepo), bind(api.MigrateRepoOptions{}), repo.Migrate)
+ m.Post("/migrate", reqToken(), bind(api.MigrateRepoOptions{}), repo.Migrate)
m.Group("/{username}/{reponame}", func() {
m.Combo("").Get(reqAnyRepoReader(), repo.Get).
- Delete(reqToken(auth_model.AccessTokenScopeDeleteRepo), reqOwner(), repo.Delete).
- Patch(reqToken(auth_model.AccessTokenScopeRepo), reqAdmin(), bind(api.EditRepoOption{}), repo.Edit)
- m.Post("/generate", reqToken(auth_model.AccessTokenScopeRepo), reqRepoReader(unit.TypeCode), bind(api.GenerateRepoOption{}), repo.Generate)
+ 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)
m.Group("/transfer", func() {
m.Post("", reqOwner(), bind(api.TransferRepoOption{}), repo.Transfer)
m.Post("/accept", repo.AcceptTransfer)
m.Post("/reject", repo.RejectTransfer)
- }, reqToken(auth_model.AccessTokenScopeRepo))
- m.Combo("/notifications", reqToken(auth_model.AccessTokenScopeNotification)).
- Get(notify.ListRepoNotifications).
- Put(notify.ReadRepoNotifications)
+ }, reqToken())
m.Group("/hooks/git", func() {
- m.Combo("").Get(reqToken(auth_model.AccessTokenScopeReadRepoHook), repo.ListGitHooks)
+ m.Combo("").Get(repo.ListGitHooks)
m.Group("/{id}", func() {
- m.Combo("").Get(reqToken(auth_model.AccessTokenScopeReadRepoHook), repo.GetGitHook).
- Patch(reqToken(auth_model.AccessTokenScopeWriteRepoHook), bind(api.EditGitHookOption{}), repo.EditGitHook).
- Delete(reqToken(auth_model.AccessTokenScopeWriteRepoHook), repo.DeleteGitHook)
+ m.Combo("").Get(repo.GetGitHook).
+ Patch(bind(api.EditGitHookOption{}), repo.EditGitHook).
+ Delete(repo.DeleteGitHook)
})
- }, reqAdmin(), reqGitHook(), context.ReferencesGitRepo(true))
+ }, reqToken(), reqAdmin(), reqGitHook(), context.ReferencesGitRepo(true))
m.Group("/hooks", func() {
- m.Combo("").Get(reqToken(auth_model.AccessTokenScopeReadRepoHook), repo.ListHooks).
- Post(reqToken(auth_model.AccessTokenScopeWriteRepoHook), bind(api.CreateHookOption{}), repo.CreateHook)
+ m.Combo("").Get(repo.ListHooks).
+ Post(bind(api.CreateHookOption{}), repo.CreateHook)
m.Group("/{id}", func() {
- m.Combo("").Get(reqToken(auth_model.AccessTokenScopeReadRepoHook), repo.GetHook).
- Patch(reqToken(auth_model.AccessTokenScopeWriteRepoHook), bind(api.EditHookOption{}), repo.EditHook).
- Delete(reqToken(auth_model.AccessTokenScopeWriteRepoHook), repo.DeleteHook)
- m.Post("/tests", reqToken(auth_model.AccessTokenScopeReadRepoHook), context.ReferencesGitRepo(), context.RepoRefForAPI, repo.TestHook)
+ m.Combo("").Get(repo.GetHook).
+ Patch(bind(api.EditHookOption{}), repo.EditHook).
+ Delete(repo.DeleteHook)
+ m.Post("/tests", context.ReferencesGitRepo(), context.RepoRefForAPI, repo.TestHook)
})
- }, reqAdmin(), reqWebhooksEnabled())
+ }, reqToken(), reqAdmin(), reqWebhooksEnabled())
m.Group("/collaborators", func() {
m.Get("", reqAnyRepoReader(), repo.ListCollaborators)
m.Group("/{collaborator}", func() {
@@ -910,25 +960,25 @@ func Routes(ctx gocontext.Context) *web.Route {
Delete(reqAdmin(), repo.DeleteCollaborator)
m.Get("/permission", repo.GetRepoPermissions)
})
- }, reqToken(auth_model.AccessTokenScopeRepo))
- m.Get("/assignees", reqToken(auth_model.AccessTokenScopeRepo), reqAnyRepoReader(), repo.GetAssignees)
- m.Get("/reviewers", reqToken(auth_model.AccessTokenScopeRepo), reqAnyRepoReader(), repo.GetReviewers)
+ }, 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(auth_model.AccessTokenScopeRepo))
+ }, 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)
m.Get("/archive/*", reqRepoReader(unit.TypeCode), repo.GetArchive)
m.Combo("/forks").Get(repo.ListForks).
- Post(reqToken(auth_model.AccessTokenScopeRepo), reqRepoReader(unit.TypeCode), bind(api.CreateForkOption{}), repo.CreateFork)
+ Post(reqToken(), reqRepoReader(unit.TypeCode), bind(api.CreateForkOption{}), repo.CreateFork)
m.Group("/branches", func() {
m.Get("", repo.ListBranches)
m.Get("/*", repo.GetBranch)
- m.Delete("/*", reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeCode), repo.DeleteBranch)
- m.Post("", reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeCode), bind(api.CreateBranchRepoOption{}), repo.CreateBranch)
+ m.Delete("/*", reqToken(), reqRepoWriter(unit.TypeCode), repo.DeleteBranch)
+ m.Post("", reqToken(), reqRepoWriter(unit.TypeCode), bind(api.CreateBranchRepoOption{}), repo.CreateBranch)
}, context.ReferencesGitRepo(), reqRepoReader(unit.TypeCode))
m.Group("/branch_protections", func() {
m.Get("", repo.ListBranchProtections)
@@ -938,218 +988,112 @@ func Routes(ctx gocontext.Context) *web.Route {
m.Patch("", bind(api.EditBranchProtectionOption{}), repo.EditBranchProtection)
m.Delete("", repo.DeleteBranchProtection)
})
- }, reqToken(auth_model.AccessTokenScopeRepo), reqAdmin())
+ }, reqToken(), reqAdmin())
m.Group("/tags", func() {
m.Get("", repo.ListTags)
m.Get("/*", repo.GetTag)
- m.Post("", reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeCode), bind(api.CreateTagOption{}), repo.CreateTag)
- m.Delete("/*", reqToken(auth_model.AccessTokenScopeRepo), repo.DeleteTag)
+ m.Post("", reqToken(), reqRepoWriter(unit.TypeCode), bind(api.CreateTagOption{}), repo.CreateTag)
+ m.Delete("/*", reqToken(), repo.DeleteTag)
}, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo(true))
m.Group("/keys", func() {
m.Combo("").Get(repo.ListDeployKeys).
Post(bind(api.CreateKeyOption{}), repo.CreateDeployKey)
m.Combo("/{id}").Get(repo.GetDeployKey).
Delete(repo.DeleteDeploykey)
- }, reqToken(auth_model.AccessTokenScopeRepo), reqAdmin())
+ }, reqToken(), reqAdmin())
m.Group("/times", func() {
m.Combo("").Get(repo.ListTrackedTimesByRepository)
m.Combo("/{timetrackingusername}").Get(repo.ListTrackedTimesByUser)
- }, mustEnableIssues, reqToken(auth_model.AccessTokenScopeRepo))
+ }, mustEnableIssues, reqToken())
m.Group("/wiki", func() {
m.Combo("/page/{pageName}").
Get(repo.GetWikiPage).
- Patch(mustNotBeArchived, reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeWiki), bind(api.CreateWikiPageOptions{}), repo.EditWikiPage).
- Delete(mustNotBeArchived, reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeWiki), repo.DeleteWikiPage)
+ Patch(mustNotBeArchived, reqToken(), reqRepoWriter(unit.TypeWiki), bind(api.CreateWikiPageOptions{}), repo.EditWikiPage).
+ Delete(mustNotBeArchived, reqToken(), reqRepoWriter(unit.TypeWiki), repo.DeleteWikiPage)
m.Get("/revisions/{pageName}", repo.ListPageRevisions)
- m.Post("/new", mustNotBeArchived, reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeWiki), bind(api.CreateWikiPageOptions{}), repo.NewWikiPage)
+ m.Post("/new", reqToken(), mustNotBeArchived, reqRepoWriter(unit.TypeWiki), bind(api.CreateWikiPageOptions{}), repo.NewWikiPage)
m.Get("/pages", repo.ListWikiPages)
}, mustEnableWiki)
- m.Group("/issues", func() {
- m.Combo("").Get(repo.ListIssues).
- Post(reqToken(auth_model.AccessTokenScopeRepo), mustNotBeArchived, bind(api.CreateIssueOption{}), repo.CreateIssue)
- m.Get("/pinned", repo.ListPinnedIssues)
- m.Group("/comments", func() {
- m.Get("", repo.ListRepoIssueComments)
- m.Group("/{id}", func() {
- m.Combo("").
- Get(repo.GetIssueComment).
- Patch(mustNotBeArchived, reqToken(auth_model.AccessTokenScopeRepo), bind(api.EditIssueCommentOption{}), repo.EditIssueComment).
- Delete(reqToken(auth_model.AccessTokenScopeRepo), repo.DeleteIssueComment)
- m.Combo("/reactions").
- Get(repo.GetIssueCommentReactions).
- Post(reqToken(auth_model.AccessTokenScopeRepo), bind(api.EditReactionOption{}), repo.PostIssueCommentReaction).
- Delete(reqToken(auth_model.AccessTokenScopeRepo), bind(api.EditReactionOption{}), repo.DeleteIssueCommentReaction)
- m.Group("/assets", func() {
- m.Combo("").
- Get(repo.ListIssueCommentAttachments).
- Post(reqToken(auth_model.AccessTokenScopeRepo), mustNotBeArchived, repo.CreateIssueCommentAttachment)
- m.Combo("/{asset}").
- Get(repo.GetIssueCommentAttachment).
- Patch(reqToken(auth_model.AccessTokenScopeRepo), mustNotBeArchived, bind(api.EditAttachmentOptions{}), repo.EditIssueCommentAttachment).
- Delete(reqToken(auth_model.AccessTokenScopeRepo), mustNotBeArchived, repo.DeleteIssueCommentAttachment)
- }, mustEnableAttachments)
- })
- })
- m.Group("/{index}", func() {
- m.Combo("").Get(repo.GetIssue).
- Patch(reqToken(auth_model.AccessTokenScopeRepo), bind(api.EditIssueOption{}), repo.EditIssue).
- Delete(reqToken(auth_model.AccessTokenScopeRepo), reqAdmin(), context.ReferencesGitRepo(), repo.DeleteIssue)
- m.Group("/comments", func() {
- m.Combo("").Get(repo.ListIssueComments).
- Post(reqToken(auth_model.AccessTokenScopeRepo), mustNotBeArchived, bind(api.CreateIssueCommentOption{}), repo.CreateIssueComment)
- m.Combo("/{id}", reqToken(auth_model.AccessTokenScopeRepo)).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(auth_model.AccessTokenScopeRepo), bind(api.IssueLabelsOption{}), repo.AddIssueLabels).
- Put(reqToken(auth_model.AccessTokenScopeRepo), bind(api.IssueLabelsOption{}), repo.ReplaceIssueLabels).
- Delete(reqToken(auth_model.AccessTokenScopeRepo), repo.ClearIssueLabels)
- m.Delete("/{id}", reqToken(auth_model.AccessTokenScopeRepo), 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(auth_model.AccessTokenScopeRepo))
- m.Combo("/deadline").Post(reqToken(auth_model.AccessTokenScopeRepo), bind(api.EditDeadlineOption{}), repo.UpdateIssueDeadline)
- m.Group("/stopwatch", func() {
- m.Post("/start", reqToken(auth_model.AccessTokenScopeRepo), repo.StartIssueStopwatch)
- m.Post("/stop", reqToken(auth_model.AccessTokenScopeRepo), repo.StopIssueStopwatch)
- m.Delete("/delete", reqToken(auth_model.AccessTokenScopeRepo), repo.DeleteIssueStopwatch)
- })
- m.Group("/subscriptions", func() {
- m.Get("", repo.GetIssueSubscribers)
- m.Get("/check", reqToken(auth_model.AccessTokenScopeRepo), repo.CheckIssueSubscription)
- m.Put("/{user}", reqToken(auth_model.AccessTokenScopeRepo), repo.AddIssueSubscription)
- m.Delete("/{user}", reqToken(auth_model.AccessTokenScopeRepo), repo.DelIssueSubscription)
- })
- m.Combo("/reactions").
- Get(repo.GetIssueReactions).
- Post(reqToken(auth_model.AccessTokenScopeRepo), bind(api.EditReactionOption{}), repo.PostIssueReaction).
- Delete(reqToken(auth_model.AccessTokenScopeRepo), bind(api.EditReactionOption{}), repo.DeleteIssueReaction)
- m.Group("/assets", func() {
- m.Combo("").
- Get(repo.ListIssueAttachments).
- Post(reqToken(auth_model.AccessTokenScopeRepo), mustNotBeArchived, repo.CreateIssueAttachment)
- m.Combo("/{asset}").
- Get(repo.GetIssueAttachment).
- Patch(reqToken(auth_model.AccessTokenScopeRepo), mustNotBeArchived, bind(api.EditAttachmentOptions{}), repo.EditIssueAttachment).
- Delete(reqToken(auth_model.AccessTokenScopeRepo), mustNotBeArchived, repo.DeleteIssueAttachment)
- }, mustEnableAttachments)
- m.Combo("/dependencies").
- Get(repo.GetIssueDependencies).
- Post(reqToken(auth_model.AccessTokenScopeRepo), mustNotBeArchived, bind(api.IssueMeta{}), repo.CreateIssueDependency).
- Delete(reqToken(auth_model.AccessTokenScopeRepo), mustNotBeArchived, bind(api.IssueMeta{}), repo.RemoveIssueDependency)
- m.Combo("/blocks").
- Get(repo.GetIssueBlocks).
- Post(reqToken(auth_model.AccessTokenScopeRepo), bind(api.IssueMeta{}), repo.CreateIssueBlocking).
- Delete(reqToken(auth_model.AccessTokenScopeRepo), bind(api.IssueMeta{}), repo.RemoveIssueBlocking)
- m.Group("/pin", func() {
- m.Combo("").
- Post(reqToken(auth_model.AccessTokenScopeRepo), reqAdmin(), repo.PinIssue).
- Delete(reqToken(auth_model.AccessTokenScopeRepo), reqAdmin(), repo.UnpinIssue)
- m.Patch("/{position}", reqToken(auth_model.AccessTokenScopeRepo), reqAdmin(), repo.MoveIssuePin)
- })
- })
- }, mustEnableIssuesOrPulls)
- m.Group("/labels", func() {
- m.Combo("").Get(repo.ListLabels).
- Post(reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), bind(api.CreateLabelOption{}), repo.CreateLabel)
- m.Combo("/{id}").Get(repo.GetLabel).
- Patch(reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), bind(api.EditLabelOption{}), repo.EditLabel).
- Delete(reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), repo.DeleteLabel)
- })
- m.Post("/markup", reqToken(auth_model.AccessTokenScopeRepo), bind(api.MarkupOption{}), misc.Markup)
- m.Post("/markdown", reqToken(auth_model.AccessTokenScopeRepo), bind(api.MarkdownOption{}), misc.Markdown)
- m.Post("/markdown/raw", reqToken(auth_model.AccessTokenScopeRepo), misc.MarkdownRaw)
- m.Group("/milestones", func() {
- m.Combo("").Get(repo.ListMilestones).
- Post(reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), bind(api.CreateMilestoneOption{}), repo.CreateMilestone)
- m.Combo("/{id}").Get(repo.GetMilestone).
- Patch(reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), bind(api.EditMilestoneOption{}), repo.EditMilestone).
- Delete(reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), repo.DeleteMilestone)
- })
+ 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("/stargazers", repo.ListStargazers)
m.Get("/subscribers", repo.ListSubscribers)
m.Group("/subscription", func() {
m.Get("", user.IsWatching)
- m.Put("", reqToken(auth_model.AccessTokenScopeRepo), user.Watch)
- m.Delete("", reqToken(auth_model.AccessTokenScopeRepo), user.Unwatch)
+ m.Put("", reqToken(), user.Watch)
+ m.Delete("", reqToken(), user.Unwatch)
})
m.Group("/releases", func() {
m.Combo("").Get(repo.ListReleases).
- Post(reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeReleases), context.ReferencesGitRepo(), bind(api.CreateReleaseOption{}), repo.CreateRelease)
+ Post(reqToken(), reqRepoWriter(unit.TypeReleases), context.ReferencesGitRepo(), bind(api.CreateReleaseOption{}), repo.CreateRelease)
m.Combo("/latest").Get(repo.GetLatestRelease)
m.Group("/{id}", func() {
m.Combo("").Get(repo.GetRelease).
- Patch(reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeReleases), context.ReferencesGitRepo(), bind(api.EditReleaseOption{}), repo.EditRelease).
- Delete(reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeReleases), repo.DeleteRelease)
+ Patch(reqToken(), reqRepoWriter(unit.TypeReleases), context.ReferencesGitRepo(), bind(api.EditReleaseOption{}), repo.EditRelease).
+ Delete(reqToken(), reqRepoWriter(unit.TypeReleases), repo.DeleteRelease)
m.Group("/assets", func() {
m.Combo("").Get(repo.ListReleaseAttachments).
- Post(reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeReleases), repo.CreateReleaseAttachment)
+ Post(reqToken(), reqRepoWriter(unit.TypeReleases), repo.CreateReleaseAttachment)
m.Combo("/{asset}").Get(repo.GetReleaseAttachment).
- Patch(reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeReleases), bind(api.EditAttachmentOptions{}), repo.EditReleaseAttachment).
- Delete(reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeReleases), repo.DeleteReleaseAttachment)
+ Patch(reqToken(), reqRepoWriter(unit.TypeReleases), bind(api.EditAttachmentOptions{}), repo.EditReleaseAttachment).
+ Delete(reqToken(), reqRepoWriter(unit.TypeReleases), repo.DeleteReleaseAttachment)
})
})
m.Group("/tags", func() {
m.Combo("/{tag}").
Get(repo.GetReleaseByTag).
- Delete(reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeReleases), repo.DeleteReleaseByTag)
+ Delete(reqToken(), reqRepoWriter(unit.TypeReleases), repo.DeleteReleaseByTag)
})
}, reqRepoReader(unit.TypeReleases))
- m.Post("/mirror-sync", reqToken(auth_model.AccessTokenScopeRepo), reqRepoWriter(unit.TypeCode), repo.MirrorSync)
- m.Post("/push_mirrors-sync", reqAdmin(), reqToken(auth_model.AccessTokenScopeRepo), repo.PushMirrorSync)
+ m.Post("/mirror-sync", reqToken(), reqRepoWriter(unit.TypeCode), repo.MirrorSync)
+ m.Post("/push_mirrors-sync", reqAdmin(), reqToken(), 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(), reqToken(auth_model.AccessTokenScopeRepo))
+ }, reqAdmin(), reqToken())
m.Get("/editorconfig/{filename}", context.ReferencesGitRepo(), context.RepoRefForAPI, reqRepoReader(unit.TypeCode), repo.GetEditorconfig)
m.Group("/pulls", func() {
m.Combo("").Get(repo.ListPullRequests).
- Post(reqToken(auth_model.AccessTokenScopeRepo), mustNotBeArchived, bind(api.CreatePullRequestOption{}), repo.CreatePullRequest)
+ Post(reqToken(), mustNotBeArchived, bind(api.CreatePullRequestOption{}), repo.CreatePullRequest)
m.Get("/pinned", repo.ListPinnedPullRequests)
m.Group("/{index}", func() {
m.Combo("").Get(repo.GetPullRequest).
- Patch(reqToken(auth_model.AccessTokenScopeRepo), bind(api.EditPullRequestOption{}), repo.EditPullRequest)
+ Patch(reqToken(), bind(api.EditPullRequestOption{}), repo.EditPullRequest)
m.Get(".{diffType:diff|patch}", repo.DownloadPullDiffOrPatch)
- m.Post("/update", reqToken(auth_model.AccessTokenScopeRepo), repo.UpdatePullRequest)
+ m.Post("/update", reqToken(), repo.UpdatePullRequest)
m.Get("/commits", repo.GetPullRequestCommits)
m.Get("/files", repo.GetPullRequestFiles)
m.Combo("/merge").Get(repo.IsPullRequestMerged).
- Post(reqToken(auth_model.AccessTokenScopeRepo), mustNotBeArchived, bind(forms.MergePullRequestForm{}), repo.MergePullRequest).
- Delete(reqToken(auth_model.AccessTokenScopeRepo), mustNotBeArchived, repo.CancelScheduledAutoMerge)
+ Post(reqToken(), mustNotBeArchived, bind(forms.MergePullRequestForm{}), repo.MergePullRequest).
+ Delete(reqToken(), mustNotBeArchived, repo.CancelScheduledAutoMerge)
m.Group("/reviews", func() {
m.Combo("").
Get(repo.ListPullReviews).
- Post(reqToken(auth_model.AccessTokenScopeRepo), bind(api.CreatePullReviewOptions{}), repo.CreatePullReview)
+ Post(reqToken(), bind(api.CreatePullReviewOptions{}), repo.CreatePullReview)
m.Group("/{id}", func() {
m.Combo("").
Get(repo.GetPullReview).
- Delete(reqToken(auth_model.AccessTokenScopeRepo), repo.DeletePullReview).
- Post(reqToken(auth_model.AccessTokenScopeRepo), bind(api.SubmitPullReviewOptions{}), repo.SubmitPullReview)
+ Delete(reqToken(), repo.DeletePullReview).
+ Post(reqToken(), bind(api.SubmitPullReviewOptions{}), repo.SubmitPullReview)
m.Combo("/comments").
Get(repo.GetPullReviewComments)
- m.Post("/dismissals", reqToken(auth_model.AccessTokenScopeRepo), bind(api.DismissPullReviewOptions{}), repo.DismissPullReview)
- m.Post("/undismissals", reqToken(auth_model.AccessTokenScopeRepo), repo.UnDismissPullReview)
+ m.Post("/dismissals", reqToken(), bind(api.DismissPullReviewOptions{}), repo.DismissPullReview)
+ m.Post("/undismissals", reqToken(), repo.UnDismissPullReview)
})
})
- m.Combo("/requested_reviewers", reqToken(auth_model.AccessTokenScopeRepo)).
+ m.Combo("/requested_reviewers", reqToken()).
Delete(bind(api.PullReviewRequestOptions{}), repo.DeleteReviewRequests).
Post(bind(api.PullReviewRequestOptions{}), repo.CreateReviewRequests)
})
}, mustAllowPulls, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo())
m.Group("/statuses", func() {
m.Combo("/{sha}").Get(repo.GetCommitStatuses).
- Post(reqToken(auth_model.AccessTokenScopeRepoStatus), reqRepoWriter(unit.TypeCode), bind(api.CreateStatusOption{}), repo.NewCommitStatus)
+ Post(reqToken(), reqRepoWriter(unit.TypeCode), bind(api.CreateStatusOption{}), repo.NewCommitStatus)
}, reqRepoReader(unit.TypeCode))
m.Group("/commits", func() {
m.Get("", context.ReferencesGitRepo(), repo.GetAllCommits)
@@ -1170,24 +1114,24 @@ func Routes(ctx gocontext.Context) *web.Route {
m.Get("/tags/{sha}", repo.GetAnnotatedTag)
m.Get("/notes/{sha}", repo.GetNote)
}, context.ReferencesGitRepo(true), reqRepoReader(unit.TypeCode))
- m.Post("/diffpatch", reqRepoWriter(unit.TypeCode), reqToken(auth_model.AccessTokenScopeRepo), bind(api.ApplyDiffPatchFileOptions{}), repo.ApplyDiffPatch)
+ m.Post("/diffpatch", reqRepoWriter(unit.TypeCode), reqToken(), bind(api.ApplyDiffPatchFileOptions{}), repo.ApplyDiffPatch)
m.Group("/contents", func() {
m.Get("", repo.GetContentsList)
- m.Post("", reqToken(auth_model.AccessTokenScopeRepo), bind(api.ChangeFilesOptions{}), reqRepoBranchWriter, repo.ChangeFiles)
+ m.Post("", reqToken(), bind(api.ChangeFilesOptions{}), reqRepoBranchWriter, repo.ChangeFiles)
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(auth_model.AccessTokenScopeRepo))
+ }, reqToken())
}, reqRepoReader(unit.TypeCode))
m.Get("/signing-key.gpg", misc.SigningKey)
m.Group("/topics", func() {
m.Combo("").Get(repo.ListTopics).
- Put(reqToken(auth_model.AccessTokenScopeRepo), reqAdmin(), bind(api.RepoTopicOptions{}), repo.UpdateTopics)
+ Put(reqToken(), reqAdmin(), bind(api.RepoTopicOptions{}), repo.UpdateTopics)
m.Group("/{topic}", func() {
- m.Combo("").Put(reqToken(auth_model.AccessTokenScopeRepo), repo.AddTopic).
- Delete(reqToken(auth_model.AccessTokenScopeRepo), repo.DeleteTopic)
+ m.Combo("").Put(reqToken(), repo.AddTopic).
+ Delete(reqToken(), repo.DeleteTopic)
}, reqAdmin())
}, reqAnyRepoReader())
m.Get("/issue_templates", context.ReferencesGitRepo(), repo.GetIssueTemplates)
@@ -1197,54 +1141,177 @@ func Routes(ctx gocontext.Context) *web.Route {
m.Get("/activities/feeds", repo.ListRepoActivityFeeds)
m.Get("/new_pin_allowed", repo.AreNewIssuePinsAllowed)
}, repoAssignment())
- })
+ }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository))
+
+ // Notifications (requires notifications scope)
+ m.Group("/repos", func() {
+ m.Group("/{username}/{reponame}", func() {
+ m.Combo("/notifications", reqToken()).
+ Get(notify.ListRepoNotifications).
+ Put(notify.ReadRepoNotifications)
+ }, repoAssignment())
+ }, 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).
+ Post(reqToken(), mustNotBeArchived, bind(api.CreateIssueOption{}), repo.CreateIssue)
+ m.Get("/pinned", repo.ListPinnedIssues)
+ 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)
+ m.Combo("/{asset}").
+ 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)
+ m.Combo("/{asset}").
+ 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)
+ })
+ })
+ }, 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)
+ })
+ }, repoAssignment())
+ }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryIssue))
// NOTE: these are Gitea package management API - see packages.CommonRoutes and packages.DockerContainerRoutes for endpoints that implement package manager APIs
m.Group("/packages/{username}", func() {
m.Group("/{type}/{name}/{version}", func() {
- m.Get("", reqToken(auth_model.AccessTokenScopeReadPackage), packages.GetPackage)
- m.Delete("", reqToken(auth_model.AccessTokenScopeDeletePackage), reqPackageAccess(perm.AccessModeWrite), packages.DeletePackage)
- m.Get("/files", reqToken(auth_model.AccessTokenScopeReadPackage), packages.ListPackageFiles)
+ m.Get("", reqToken(), packages.GetPackage)
+ m.Delete("", reqToken(), reqPackageAccess(perm.AccessModeWrite), packages.DeletePackage)
+ m.Get("/files", reqToken(), packages.ListPackageFiles)
})
- m.Get("/", reqToken(auth_model.AccessTokenScopeReadPackage), packages.ListPackages)
- }, context_service.UserAssignmentAPI(), context.PackageAssignmentAPI(), reqPackageAccess(perm.AccessModeRead))
+ m.Get("/", reqToken(), packages.ListPackages)
+ }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryPackage), context_service.UserAssignmentAPI(), context.PackageAssignmentAPI(), reqPackageAccess(perm.AccessModeRead))
// Organizations
- m.Get("/user/orgs", reqToken(auth_model.AccessTokenScopeReadOrg), org.ListMyOrgs)
+ m.Get("/user/orgs", reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), org.ListMyOrgs)
m.Group("/users/{username}/orgs", func() {
- m.Get("", reqToken(auth_model.AccessTokenScopeReadOrg), org.ListUserOrgs)
- m.Get("/{org}/permissions", reqToken(auth_model.AccessTokenScopeReadOrg), org.GetUserOrgsPermissions)
- }, context_service.UserAssignmentAPI())
- m.Post("/orgs", reqToken(auth_model.AccessTokenScopeWriteOrg), bind(api.CreateOrgOption{}), org.Create)
- m.Get("/orgs", org.GetAll)
+ m.Get("", reqToken(), org.ListUserOrgs)
+ m.Get("/{org}/permissions", reqToken(), org.GetUserOrgsPermissions)
+ }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), context_service.UserAssignmentAPI())
+ m.Post("/orgs", tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), reqToken(), bind(api.CreateOrgOption{}), org.Create)
+ m.Get("/orgs", org.GetAll, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization))
m.Group("/orgs/{org}", func() {
m.Combo("").Get(org.Get).
- Patch(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), bind(api.EditOrgOption{}), org.Edit).
- Delete(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), org.Delete)
+ Patch(reqToken(), reqOrgOwnership(), bind(api.EditOrgOption{}), org.Edit).
+ Delete(reqToken(), reqOrgOwnership(), org.Delete)
m.Combo("/repos").Get(user.ListOrgRepos).
- Post(reqToken(auth_model.AccessTokenScopeWriteOrg), bind(api.CreateRepoOption{}), repo.CreateOrgRepo)
+ Post(reqToken(), bind(api.CreateRepoOption{}), repo.CreateOrgRepo)
m.Group("/members", func() {
- m.Get("", reqToken(auth_model.AccessTokenScopeReadOrg), org.ListMembers)
- m.Combo("/{username}").Get(reqToken(auth_model.AccessTokenScopeReadOrg), org.IsMember).
- Delete(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), org.DeleteMember)
+ m.Get("", reqToken(), org.ListMembers)
+ m.Combo("/{username}").Get(reqToken(), org.IsMember).
+ Delete(reqToken(), reqOrgOwnership(), org.DeleteMember)
})
m.Group("/public_members", func() {
m.Get("", org.ListPublicMembers)
m.Combo("/{username}").Get(org.IsPublicMember).
- Put(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgMembership(), org.PublicizeMember).
- Delete(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgMembership(), org.ConcealMember)
+ Put(reqToken(), reqOrgMembership(), org.PublicizeMember).
+ Delete(reqToken(), reqOrgMembership(), org.ConcealMember)
})
m.Group("/teams", func() {
- m.Get("", reqToken(auth_model.AccessTokenScopeReadOrg), org.ListTeams)
- m.Post("", reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), bind(api.CreateTeamOption{}), org.CreateTeam)
- m.Get("/search", reqToken(auth_model.AccessTokenScopeReadOrg), org.SearchTeam)
+ m.Get("", reqToken(), org.ListTeams)
+ m.Post("", reqToken(), reqOrgOwnership(), bind(api.CreateTeamOption{}), org.CreateTeam)
+ m.Get("/search", reqToken(), org.SearchTeam)
}, reqOrgMembership())
m.Group("/labels", func() {
m.Get("", org.ListLabels)
- m.Post("", reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), bind(api.CreateLabelOption{}), org.CreateLabel)
- m.Combo("/{id}").Get(reqToken(auth_model.AccessTokenScopeReadOrg), org.GetLabel).
- Patch(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), bind(api.EditLabelOption{}), org.EditLabel).
- Delete(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), org.DeleteLabel)
+ 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)
})
m.Group("/hooks", func() {
m.Combo("").Get(org.ListHooks).
@@ -1252,29 +1319,29 @@ func Routes(ctx gocontext.Context) *web.Route {
m.Combo("/{id}").Get(org.GetHook).
Patch(bind(api.EditHookOption{}), org.EditHook).
Delete(org.DeleteHook)
- }, reqToken(auth_model.AccessTokenScopeAdminOrgHook), reqOrgOwnership(), reqWebhooksEnabled())
+ }, reqToken(), reqOrgOwnership(), reqWebhooksEnabled())
m.Get("/activities/feeds", org.ListOrgActivityFeeds)
- }, orgAssignment(true))
+ }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), orgAssignment(true))
m.Group("/teams/{teamid}", func() {
- m.Combo("").Get(reqToken(auth_model.AccessTokenScopeReadOrg), org.GetTeam).
- Patch(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), bind(api.EditTeamOption{}), org.EditTeam).
- Delete(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), org.DeleteTeam)
+ m.Combo("").Get(reqToken(), org.GetTeam).
+ Patch(reqToken(), reqOrgOwnership(), bind(api.EditTeamOption{}), org.EditTeam).
+ Delete(reqToken(), reqOrgOwnership(), org.DeleteTeam)
m.Group("/members", func() {
- m.Get("", reqToken(auth_model.AccessTokenScopeReadOrg), org.GetTeamMembers)
+ m.Get("", reqToken(), org.GetTeamMembers)
m.Combo("/{username}").
- Get(reqToken(auth_model.AccessTokenScopeReadOrg), org.GetTeamMember).
- Put(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), org.AddTeamMember).
- Delete(reqToken(auth_model.AccessTokenScopeWriteOrg), reqOrgOwnership(), org.RemoveTeamMember)
+ Get(reqToken(), org.GetTeamMember).
+ Put(reqToken(), reqOrgOwnership(), org.AddTeamMember).
+ Delete(reqToken(), reqOrgOwnership(), org.RemoveTeamMember)
})
m.Group("/repos", func() {
- m.Get("", reqToken(auth_model.AccessTokenScopeReadOrg), org.GetTeamRepos)
+ m.Get("", reqToken(), org.GetTeamRepos)
m.Combo("/{org}/{reponame}").
- Put(reqToken(auth_model.AccessTokenScopeWriteOrg), org.AddTeamRepository).
- Delete(reqToken(auth_model.AccessTokenScopeWriteOrg), org.RemoveTeamRepository).
- Get(reqToken(auth_model.AccessTokenScopeReadOrg), org.GetTeamRepo)
+ Put(reqToken(), org.AddTeamRepository).
+ Delete(reqToken(), org.RemoveTeamRepository).
+ Get(reqToken(), org.GetTeamRepo)
})
m.Get("/activities/feeds", org.ListTeamActivityFeeds)
- }, orgAssignment(false, true), reqToken(""), reqTeamMembership())
+ }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), orgAssignment(false, true), reqToken(), reqTeamMembership())
m.Group("/admin", func() {
m.Group("/cron", func() {
@@ -1314,11 +1381,11 @@ func Routes(ctx gocontext.Context) *web.Route {
Patch(bind(api.EditHookOption{}), admin.EditHook).
Delete(admin.DeleteHook)
})
- }, reqToken(auth_model.AccessTokenScopeSudo), reqSiteAdmin())
+ }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryAdmin), reqToken(), reqSiteAdmin())
m.Group("/topics", func() {
m.Get("/search", repo.TopicSearch)
- })
+ }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository))
}, sudo())
return m