Skip to content

Commit ebd2328

Browse files
committed
Merge public only check into scope check function
1 parent b37b065 commit ebd2328

File tree

1 file changed

+71
-83
lines changed

1 file changed

+71
-83
lines changed

routers/api/v1/api.go

Lines changed: 71 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -250,9 +250,6 @@ func tokenRequiresScopes(requiredScopeCategories ...auth_model.AccessTokenScopeC
250250
return
251251
}
252252

253-
ctx.Data["ApiTokenScopePublicRepoOnly"] = false
254-
ctx.Data["ApiTokenScopePublicOrgOnly"] = false
255-
256253
// use the http method to determine the access level
257254
requiredScopeLevel := auth_model.Read
258255
if ctx.Req.Method == "POST" || ctx.Req.Method == "PUT" || ctx.Req.Method == "PATCH" || ctx.Req.Method == "DELETE" {
@@ -261,56 +258,73 @@ func tokenRequiresScopes(requiredScopeCategories ...auth_model.AccessTokenScopeC
261258

262259
// get the required scope for the given access level and category
263260
requiredScopes := auth_model.GetRequiredScopes(requiredScopeLevel, requiredScopeCategories...)
264-
265-
// check if scope only applies to public resources
266-
publicOnly, err := scope.PublicOnly()
267-
if err != nil {
268-
ctx.Error(http.StatusForbidden, "tokenRequiresScope", "parsing public resource scope failed: "+err.Error())
269-
return
270-
}
271-
272-
// this context is used by the middleware in the specific route
273-
ctx.Data["ApiTokenScopePublicRepoOnly"] = publicOnly && auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryRepository)
274-
ctx.Data["ApiTokenScopePublicOrgOnly"] = publicOnly && auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryOrganization)
275-
276261
allow, err := scope.HasScope(requiredScopes...)
277262
if err != nil {
278263
ctx.Error(http.StatusForbidden, "tokenRequiresScope", "checking scope failed: "+err.Error())
279264
return
280265
}
281266

282-
if allow {
267+
if !allow {
268+
ctx.Error(http.StatusForbidden, "tokenRequiresScope", fmt.Sprintf("token does not have at least one of required scope(s): %v", requiredScopes))
283269
return
284270
}
285271

286-
ctx.Error(http.StatusForbidden, "tokenRequiresScope", fmt.Sprintf("token does not have at least one of required scope(s): %v", requiredScopes))
287-
}
288-
}
289-
290-
// Contexter middleware already checks token for user sign in process.
291-
func reqToken() func(ctx *context.APIContext) {
292-
return func(ctx *context.APIContext) {
293-
// If actions token is present
294-
if true == ctx.Data["IsActionsToken"] {
272+
// check if scope only applies to public resources
273+
publicOnly, err := scope.PublicOnly()
274+
if err != nil {
275+
ctx.Error(http.StatusForbidden, "tokenRequiresScope", "parsing public resource scope failed: "+err.Error())
295276
return
296277
}
297278

298-
if true == ctx.Data["IsApiToken"] {
299-
publicRepo, pubRepoExists := ctx.Data["ApiTokenScopePublicRepoOnly"]
300-
publicOrg, pubOrgExists := ctx.Data["ApiTokenScopePublicOrgOnly"]
279+
if !publicOnly {
280+
return
281+
}
301282

302-
if pubRepoExists && publicRepo.(bool) &&
303-
ctx.Repo.Repository != nil && ctx.Repo.Repository.IsPrivate {
283+
switch {
284+
case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryRepository),
285+
auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryIssue):
286+
if ctx.Repo.Repository != nil && ctx.Repo.Repository.IsPrivate {
304287
ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public repos")
305288
return
306289
}
307-
308-
if pubOrgExists && publicOrg.(bool) &&
309-
ctx.Org.Organization != nil && ctx.Org.Organization.Visibility != api.VisibleTypePublic {
290+
case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryOrganization):
291+
if ctx.Org.Organization != nil && ctx.Org.Organization.Visibility != api.VisibleTypePublic {
310292
ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public orgs")
311293
return
312294
}
295+
if ctx.ContextUser != nil && ctx.ContextUser.IsOrganization() && ctx.ContextUser.Visibility != api.VisibleTypePublic {
296+
ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public orgs")
297+
return
298+
}
299+
case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryUser):
300+
if ctx.ContextUser != nil && !ctx.ContextUser.IsOrganization() && ctx.ContextUser.Visibility != api.VisibleTypePublic {
301+
ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public users")
302+
return
303+
}
304+
case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryActivityPub):
305+
if ctx.ContextUser != nil && !ctx.ContextUser.IsOrganization() && ctx.ContextUser.Visibility != api.VisibleTypePublic {
306+
ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public activitypub")
307+
return
308+
}
309+
case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryNotification):
310+
if ctx.Repo.Repository != nil && ctx.Repo.Repository.IsPrivate {
311+
ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public notifications")
312+
return
313+
}
314+
case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryPackage):
315+
if ctx.Package != nil && ctx.Package.Owner.Visibility.IsPrivate() {
316+
ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public packages")
317+
return
318+
}
319+
}
320+
}
321+
}
313322

323+
// Contexter middleware already checks token for user sign in process.
324+
func reqToken() func(ctx *context.APIContext) {
325+
return func(ctx *context.APIContext) {
326+
// If actions token is present
327+
if true == ctx.Data["IsActionsToken"] {
314328
return
315329
}
316330

@@ -388,15 +402,6 @@ func reqRepoWriter(unitTypes ...unit.Type) func(ctx *context.APIContext) {
388402
ctx.Error(http.StatusForbidden, "reqRepoWriter", "user should have a permission to write to a repo")
389403
return
390404
}
391-
392-
for _, unitType := range unitTypes {
393-
if ctx.Repo.CanWrite(unitType) {
394-
checkPublicOnly(ctx, unitType)
395-
if ctx.Written() {
396-
return
397-
}
398-
}
399-
}
400405
}
401406
}
402407

@@ -407,23 +412,6 @@ func reqRepoBranchWriter(ctx *context.APIContext) {
407412
ctx.Error(http.StatusForbidden, "reqRepoBranchWriter", "user should have a permission to write to this branch")
408413
return
409414
}
410-
411-
checkPublicOnly(ctx, unit.TypeCode)
412-
}
413-
414-
func checkPublicOnly(ctx *context.APIContext, unitType unit.Type) {
415-
if true == ctx.Data["IsApiToken"] {
416-
switch unitType {
417-
case unit.TypeCode:
418-
publicRepo, pubRepoExists := ctx.Data["ApiTokenScopePublicRepoOnly"]
419-
420-
if pubRepoExists && publicRepo.(bool) &&
421-
ctx.Repo.Repository != nil && ctx.Repo.Repository.IsPrivate {
422-
ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public repos")
423-
return
424-
}
425-
}
426-
}
427415
}
428416

429417
// reqRepoReader user should have specific read permission or be a repo admin or a site admin
@@ -433,8 +421,6 @@ func reqRepoReader(unitType unit.Type) func(ctx *context.APIContext) {
433421
ctx.Error(http.StatusForbidden, "reqRepoReader", "user should have specific read permission or be a repo admin or a site admin")
434422
return
435423
}
436-
437-
checkPublicOnly(ctx, unitType)
438424
}
439425
}
440426

@@ -950,7 +936,7 @@ func Routes() *web.Router {
950936

951937
// Users (requires user scope)
952938
m.Group("/users", func() {
953-
m.Get("/search", reqExploreSignIn(), user.Search)
939+
m.Get("/search", reqExploreSignIn(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser), user.Search)
954940

955941
m.Group("/{username}", func() {
956942
m.Get("", reqExploreSignIn(), user.GetInfo)
@@ -967,8 +953,8 @@ func Routes() *web.Router {
967953
}, reqSelfOrAdmin(), reqBasicOrRevProxyAuth())
968954

969955
m.Get("/activities/feeds", user.ListUserActivityFeeds)
970-
}, context.UserAssignmentAPI(), individualPermsChecker)
971-
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser))
956+
}, context.UserAssignmentAPI(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser), individualPermsChecker)
957+
})
972958

973959
// Users (requires user scope)
974960
m.Group("/users", func() {
@@ -985,8 +971,8 @@ func Routes() *web.Router {
985971
m.Get("/starred", user.GetStarredRepos)
986972

987973
m.Get("/subscriptions", user.GetWatchedRepos)
988-
}, context.UserAssignmentAPI())
989-
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser), reqToken())
974+
}, reqToken(), context.UserAssignmentAPI(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser))
975+
})
990976

991977
// Users (requires user scope)
992978
m.Group("/user", func() {
@@ -1067,13 +1053,13 @@ func Routes() *web.Router {
10671053

10681054
// (repo scope)
10691055
m.Group("/starred", func() {
1070-
m.Get("", user.GetMyStarredRepos)
1056+
m.Get("", tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository), user.GetMyStarredRepos)
10711057
m.Group("/{username}/{reponame}", func() {
10721058
m.Get("", user.IsStarring)
10731059
m.Put("", user.Star)
10741060
m.Delete("", user.Unstar)
1075-
}, repoAssignment())
1076-
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository))
1061+
}, repoAssignment(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository))
1062+
})
10771063
m.Get("/times", repo.ListMyTrackedTimes)
10781064
m.Get("/stopwatches", repo.GetStopwatches)
10791065
m.Get("/subscriptions", user.GetMyWatchedRepos)
@@ -1099,24 +1085,26 @@ func Routes() *web.Router {
10991085
m.Delete("", user.UnblockUser)
11001086
}, context.UserAssignmentAPI())
11011087
})
1102-
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser), reqToken())
1088+
}, reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser))
11031089

11041090
// Repositories (requires repo scope, org scope)
11051091
m.Post("/org/{org}/repos",
1092+
// FIXME: we need org in context
11061093
tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization, auth_model.AccessTokenScopeCategoryRepository),
11071094
reqToken(),
11081095
bind(api.CreateRepoOption{}),
11091096
repo.CreateOrgRepoDeprecated)
11101097

11111098
// requires repo scope
1099+
// FIXME: Don't expose repository id outside of the system
11121100
m.Combo("/repositories/{id}", reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository)).Get(repo.GetByID)
11131101

11141102
// Repos (requires repo scope)
11151103
m.Group("/repos", func() {
1116-
m.Get("/search", repo.Search)
1104+
m.Get("/search", tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository), repo.Search)
11171105

11181106
// (repo scope)
1119-
m.Post("/migrate", reqToken(), bind(api.MigrateRepoOptions{}), repo.Migrate)
1107+
m.Post("/migrate", reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository), bind(api.MigrateRepoOptions{}), repo.Migrate)
11201108

11211109
m.Group("/{username}/{reponame}", func() {
11221110
m.Get("/compare/*", reqRepoReader(unit.TypeCode), repo.CompareDiff)
@@ -1362,21 +1350,21 @@ func Routes() *web.Router {
13621350
m.Post("", bind(api.UpdateRepoAvatarOption{}), repo.UpdateAvatar)
13631351
m.Delete("", repo.DeleteAvatar)
13641352
}, reqAdmin(), reqToken())
1365-
}, repoAssignment())
1366-
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository))
1353+
}, repoAssignment(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository))
1354+
})
13671355

13681356
// Notifications (requires notifications scope)
13691357
m.Group("/repos", func() {
13701358
m.Group("/{username}/{reponame}", func() {
13711359
m.Combo("/notifications", reqToken()).
13721360
Get(notify.ListRepoNotifications).
13731361
Put(notify.ReadRepoNotifications)
1374-
}, repoAssignment())
1375-
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryNotification))
1362+
}, repoAssignment(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryNotification))
1363+
})
13761364

13771365
// Issue (requires issue scope)
13781366
m.Group("/repos", func() {
1379-
m.Get("/issues/search", repo.SearchIssues)
1367+
m.Get("/issues/search", tokenRequiresScopes(auth_model.AccessTokenScopeCategoryIssue), repo.SearchIssues)
13801368

13811369
m.Group("/{username}/{reponame}", func() {
13821370
m.Group("/issues", func() {
@@ -1485,8 +1473,8 @@ func Routes() *web.Router {
14851473
Patch(reqToken(), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), bind(api.EditMilestoneOption{}), repo.EditMilestone).
14861474
Delete(reqToken(), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), repo.DeleteMilestone)
14871475
})
1488-
}, repoAssignment())
1489-
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryIssue))
1476+
}, repoAssignment(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryIssue))
1477+
})
14901478

14911479
// NOTE: these are Gitea package management API - see packages.CommonRoutes and packages.DockerContainerRoutes for endpoints that implement package manager APIs
14921480
m.Group("/packages/{username}", func() {
@@ -1496,14 +1484,14 @@ func Routes() *web.Router {
14961484
m.Get("/files", reqToken(), packages.ListPackageFiles)
14971485
})
14981486
m.Get("/", reqToken(), packages.ListPackages)
1499-
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryPackage), context.UserAssignmentAPI(), context.PackageAssignmentAPI(), reqPackageAccess(perm.AccessModeRead))
1487+
}, context.UserAssignmentAPI(), context.PackageAssignmentAPI(), reqPackageAccess(perm.AccessModeRead), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryPackage))
15001488

15011489
// Organizations
15021490
m.Get("/user/orgs", reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), org.ListMyOrgs)
15031491
m.Group("/users/{username}/orgs", func() {
15041492
m.Get("", reqToken(), org.ListUserOrgs)
15051493
m.Get("/{org}/permissions", reqToken(), org.GetUserOrgsPermissions)
1506-
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), context.UserAssignmentAPI())
1494+
}, context.UserAssignmentAPI(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization))
15071495
m.Post("/orgs", tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), reqToken(), bind(api.CreateOrgOption{}), org.Create)
15081496
m.Get("/orgs", org.GetAll, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization))
15091497
m.Group("/orgs/{org}", func() {
@@ -1561,7 +1549,7 @@ func Routes() *web.Router {
15611549
m.Delete("", org.UnblockUser)
15621550
})
15631551
}, reqToken(), reqOrgOwnership())
1564-
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), orgAssignment(true))
1552+
}, orgAssignment(true), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization))
15651553
m.Group("/teams/{teamid}", func() {
15661554
m.Combo("").Get(reqToken(), org.GetTeam).
15671555
Patch(reqToken(), reqOrgOwnership(), bind(api.EditTeamOption{}), org.EditTeam).
@@ -1581,7 +1569,7 @@ func Routes() *web.Router {
15811569
Get(reqToken(), org.GetTeamRepo)
15821570
})
15831571
m.Get("/activities/feeds", org.ListTeamActivityFeeds)
1584-
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), orgAssignment(false, true), reqToken(), reqTeamMembership())
1572+
}, orgAssignment(false, true), reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), reqTeamMembership())
15851573

15861574
m.Group("/admin", func() {
15871575
m.Group("/cron", func() {

0 commit comments

Comments
 (0)