mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2026-06-22 10:02:15 +00:00
feat: interface for REST API permissions
and a concrete implementation for testing and re-use
This commit is contained in:
parent
9995b923a8
commit
17616708fd
2 changed files with 383 additions and 0 deletions
57
routers/api/v1/permissions/interface.go
Normal file
57
routers/api/v1/permissions/interface.go
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2026 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package permissions
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
auth_model "forgejo.org/models/auth"
|
||||
org_model "forgejo.org/models/organization"
|
||||
"forgejo.org/models/perm"
|
||||
access_model "forgejo.org/models/perm/access"
|
||||
repo_model "forgejo.org/models/repo"
|
||||
user_model "forgejo.org/models/user"
|
||||
"forgejo.org/services/auth"
|
||||
"forgejo.org/services/authz"
|
||||
)
|
||||
|
||||
type Context interface {
|
||||
GetContext() context.Context
|
||||
|
||||
GetRepository() *repo_model.Repository
|
||||
|
||||
GetDoer() *user_model.User
|
||||
|
||||
GetUser() *user_model.User
|
||||
|
||||
GetOrg() *org_model.Organization
|
||||
|
||||
GetTeam() *org_model.Team
|
||||
|
||||
GetPackageOwner() *user_model.User
|
||||
GetPackageAccessMode() perm.AccessMode
|
||||
|
||||
GetPermission() *access_model.Permission
|
||||
SetPermission(*access_model.Permission)
|
||||
|
||||
GetIsSigned() bool
|
||||
|
||||
GetPublicOnly() bool
|
||||
SetPublicOnly(bool)
|
||||
|
||||
GetReducer() authz.AuthorizationReducer
|
||||
SetReducer(authz.AuthorizationReducer)
|
||||
|
||||
GetAuthentication() auth.AuthenticationResult
|
||||
|
||||
GetRequiredScopeCategories() []auth_model.AccessTokenScopeCategory
|
||||
SetRequiredScopeCategories([]auth_model.AccessTokenScopeCategory)
|
||||
|
||||
Error(status int, title string, obj any)
|
||||
InternalServerError(err error)
|
||||
NotFound(objs ...any)
|
||||
|
||||
GetError() error
|
||||
WrittenStatus() int
|
||||
}
|
||||
326
routers/api/v1/permissions/permissions.go
Normal file
326
routers/api/v1/permissions/permissions.go
Normal file
|
|
@ -0,0 +1,326 @@
|
|||
// Copyright 2026 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package permissions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
auth_model "forgejo.org/models/auth"
|
||||
org_model "forgejo.org/models/organization"
|
||||
"forgejo.org/models/perm"
|
||||
access_model "forgejo.org/models/perm/access"
|
||||
repo_model "forgejo.org/models/repo"
|
||||
user_model "forgejo.org/models/user"
|
||||
"forgejo.org/services/auth"
|
||||
"forgejo.org/services/authz"
|
||||
)
|
||||
|
||||
type Permissions struct {
|
||||
ctx context.Context
|
||||
|
||||
token *auth_model.AccessToken
|
||||
doer *user_model.User
|
||||
user *user_model.User
|
||||
team *org_model.Team
|
||||
org *org_model.Organization
|
||||
isSigned bool
|
||||
authentication auth.AuthenticationResult
|
||||
requiredScopeCategories []auth_model.AccessTokenScopeCategory
|
||||
reducer authz.AuthorizationReducer
|
||||
publicOnly bool
|
||||
repository *repo_model.Repository
|
||||
permission *access_model.Permission
|
||||
packageOwner *user_model.User
|
||||
packageAccessMode perm.AccessMode
|
||||
|
||||
status int
|
||||
message string
|
||||
}
|
||||
|
||||
func (o *Permissions) GetContext() context.Context {
|
||||
return o.ctx
|
||||
}
|
||||
|
||||
func (o *Permissions) SetContext(ctx context.Context) {
|
||||
o.ctx = ctx
|
||||
}
|
||||
|
||||
func (o *Permissions) GetToken() *auth_model.AccessToken {
|
||||
return o.token
|
||||
}
|
||||
|
||||
func (o *Permissions) SetToken(token *auth_model.AccessToken) {
|
||||
o.token = token
|
||||
}
|
||||
|
||||
func (o *Permissions) GetRepository() *repo_model.Repository {
|
||||
return o.repository
|
||||
}
|
||||
|
||||
func (o *Permissions) SetRepository(repository *repo_model.Repository) {
|
||||
o.repository = repository
|
||||
}
|
||||
|
||||
func (o *Permissions) GetDoer() *user_model.User {
|
||||
return o.doer
|
||||
}
|
||||
|
||||
func (o *Permissions) SetDoer(doer *user_model.User) {
|
||||
o.doer = doer
|
||||
}
|
||||
|
||||
func (o *Permissions) GetUser() *user_model.User {
|
||||
return o.user
|
||||
}
|
||||
|
||||
func (o *Permissions) SetUser(user *user_model.User) {
|
||||
o.user = user
|
||||
}
|
||||
|
||||
func (o *Permissions) GetOrg() *org_model.Organization {
|
||||
return o.org
|
||||
}
|
||||
|
||||
func (o *Permissions) SetOrg(org *org_model.Organization) {
|
||||
o.org = org
|
||||
}
|
||||
|
||||
func (o *Permissions) GetTeam() *org_model.Team {
|
||||
return o.team
|
||||
}
|
||||
|
||||
func (o *Permissions) SetTeam(team *org_model.Team) {
|
||||
o.team = team
|
||||
}
|
||||
|
||||
func (o *Permissions) GetPackageOwner() *user_model.User {
|
||||
return o.packageOwner
|
||||
}
|
||||
|
||||
func (o *Permissions) SetPackageOwner(packageOwner *user_model.User) {
|
||||
o.packageOwner = packageOwner
|
||||
}
|
||||
|
||||
func (o *Permissions) GetPackageAccessMode() perm.AccessMode {
|
||||
return o.packageAccessMode
|
||||
}
|
||||
|
||||
func (o *Permissions) SetPackageAccessMode(packageAccessMode perm.AccessMode) {
|
||||
o.packageAccessMode = packageAccessMode
|
||||
}
|
||||
|
||||
func (o *Permissions) GetPermission() *access_model.Permission {
|
||||
return o.permission
|
||||
}
|
||||
|
||||
func (o *Permissions) SetPermission(permission *access_model.Permission) {
|
||||
o.permission = permission
|
||||
}
|
||||
|
||||
func (o *Permissions) GetIsSigned() bool {
|
||||
return o.isSigned
|
||||
}
|
||||
|
||||
func (o *Permissions) SetIsSigned(isSigned bool) {
|
||||
o.isSigned = isSigned
|
||||
}
|
||||
|
||||
func (o *Permissions) GetPublicOnly() bool {
|
||||
return o.publicOnly
|
||||
}
|
||||
|
||||
func (o *Permissions) SetPublicOnly(publicOnly bool) {
|
||||
o.publicOnly = publicOnly
|
||||
}
|
||||
|
||||
func (o *Permissions) GetReducer() authz.AuthorizationReducer {
|
||||
return o.reducer
|
||||
}
|
||||
|
||||
func (o *Permissions) SetReducer(reducer authz.AuthorizationReducer) {
|
||||
o.reducer = reducer
|
||||
}
|
||||
|
||||
func (o *Permissions) GetAuthentication() auth.AuthenticationResult {
|
||||
return o.authentication
|
||||
}
|
||||
|
||||
func (o *Permissions) SetAuthentication(authentication auth.AuthenticationResult) {
|
||||
o.authentication = authentication
|
||||
}
|
||||
|
||||
func (o *Permissions) GetRequiredScopeCategories() []auth_model.AccessTokenScopeCategory {
|
||||
return o.requiredScopeCategories
|
||||
}
|
||||
|
||||
func (o *Permissions) SetRequiredScopeCategories(requiredScopeCategories []auth_model.AccessTokenScopeCategory) {
|
||||
o.requiredScopeCategories = requiredScopeCategories
|
||||
}
|
||||
|
||||
func (o *Permissions) GetStatus() int {
|
||||
return o.status
|
||||
}
|
||||
|
||||
func (o *Permissions) SetStatus(status int) {
|
||||
o.status = status
|
||||
}
|
||||
|
||||
func (o *Permissions) GetMessage() string {
|
||||
return o.message
|
||||
}
|
||||
|
||||
func (o *Permissions) SetMessage(message string) {
|
||||
o.message = message
|
||||
}
|
||||
|
||||
func (o *Permissions) GetError() error {
|
||||
if o.status == 0 {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("%d: %s", o.status, o.message)
|
||||
}
|
||||
|
||||
func (o *Permissions) Error(status int, title string, obj any) {
|
||||
var message string
|
||||
if err, ok := obj.(error); ok {
|
||||
message = err.Error()
|
||||
} else {
|
||||
message = fmt.Sprintf("%s", obj)
|
||||
}
|
||||
o.status = status
|
||||
o.message = fmt.Sprintf("%s: %s", title, message)
|
||||
}
|
||||
|
||||
func (o *Permissions) NotFound(objs ...any) {
|
||||
errors := make([]string, 0)
|
||||
message := "Not Found"
|
||||
for _, obj := range objs {
|
||||
// Ignore nil
|
||||
if obj == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if err, ok := obj.(error); ok {
|
||||
errors = append(errors, err.Error())
|
||||
} else {
|
||||
message = obj.(string)
|
||||
}
|
||||
}
|
||||
o.Error(http.StatusNotFound, message, strings.Join(errors, ","))
|
||||
}
|
||||
|
||||
func (o *Permissions) InternalServerError(err error) {
|
||||
o.Error(http.StatusInternalServerError, "InternalServerError", err.Error())
|
||||
}
|
||||
|
||||
func (o *Permissions) WrittenStatus() int {
|
||||
return o.status
|
||||
}
|
||||
|
||||
func (o *Permissions) String() string {
|
||||
return strings.Join(o.Strings(), " ")
|
||||
}
|
||||
|
||||
func (o *Permissions) Strings() []string {
|
||||
var s []string
|
||||
if o.token != nil {
|
||||
s = append(s, fmt.Sprintf("%T(ID=%d Token=%s)", o.token, o.token.ID, o.token.Token))
|
||||
}
|
||||
if o.doer != nil {
|
||||
s = append(s, fmt.Sprintf("%T(Name=%s)", o.doer, o.doer.Name))
|
||||
}
|
||||
if o.user != nil {
|
||||
s = append(s, fmt.Sprintf("%T(Name=%s)", o.user, o.user.Name))
|
||||
}
|
||||
if o.team != nil {
|
||||
s = append(s, fmt.Sprintf("%T(Name=%s)", o.team, o.team.Name))
|
||||
}
|
||||
if o.org != nil {
|
||||
s = append(s, fmt.Sprintf("%T(Name=%s)", o.org, o.org.Name))
|
||||
}
|
||||
if o.isSigned {
|
||||
s = append(s, fmt.Sprintf("isSigned(%v)", o.isSigned))
|
||||
}
|
||||
if o.authentication != nil {
|
||||
var sa []string
|
||||
user := o.authentication.User()
|
||||
if user != nil {
|
||||
sa = append(sa, fmt.Sprintf("%T(Name=%s)", user, user.Name))
|
||||
}
|
||||
if has, scope := o.authentication.Scope().Get(); has {
|
||||
sa = append(sa, fmt.Sprintf("%T(%s)", scope, scope))
|
||||
}
|
||||
if o.authentication.Reducer() != nil {
|
||||
sa = append(sa, fmt.Sprintf("%T", o.authentication.Reducer()))
|
||||
}
|
||||
if o.authentication.IsPasswordAuthentication() {
|
||||
sa = append(sa, fmt.Sprintf("IsPasswordAuthentication(%v)", o.authentication.IsPasswordAuthentication()))
|
||||
}
|
||||
if o.authentication.IsReverseProxyAuthentication() {
|
||||
sa = append(sa, fmt.Sprintf("IsReverseProxyAuthentication(%v)", o.authentication.IsReverseProxyAuthentication()))
|
||||
}
|
||||
if has, oauth2scopes := o.authentication.OAuth2GrantScopes().Get(); has {
|
||||
sa = append(sa, fmt.Sprintf("%T(%s)", oauth2scopes, oauth2scopes))
|
||||
}
|
||||
if has, taskID := o.authentication.ActionsTaskID().Get(); has {
|
||||
sa = append(sa, fmt.Sprintf("ActionsTaskID(%d)", taskID))
|
||||
}
|
||||
s = append(s, fmt.Sprintf("%T(%s)", o.authentication, strings.Join(sa, " ")))
|
||||
}
|
||||
if len(o.requiredScopeCategories) > 0 {
|
||||
s = append(s, fmt.Sprintf("%T(%v)", o.requiredScopeCategories, o.requiredScopeCategories))
|
||||
}
|
||||
if o.reducer != nil {
|
||||
s = append(s, fmt.Sprintf("%T", o.reducer))
|
||||
}
|
||||
if o.publicOnly {
|
||||
s = append(s, fmt.Sprintf("publicOnly(%v)", o.publicOnly))
|
||||
}
|
||||
if o.repository != nil {
|
||||
var sa []string
|
||||
if o.repository.IsPrivate {
|
||||
sa = append(sa, fmt.Sprintf("IsPrivate(%v)", o.repository.IsPrivate))
|
||||
}
|
||||
if o.repository.IsArchived {
|
||||
sa = append(sa, fmt.Sprintf("IsArchived(%v)", o.repository.IsArchived))
|
||||
}
|
||||
if o.repository.IsMirror {
|
||||
sa = append(sa, fmt.Sprintf("IsMirror(%v)", o.repository.IsMirror))
|
||||
}
|
||||
if len(o.repository.Units) > 0 {
|
||||
var units []string
|
||||
for _, repoUnit := range o.repository.Units {
|
||||
units = append(units, repoUnit.Type.String())
|
||||
}
|
||||
sa = append(sa, fmt.Sprintf("Unit(%s)", strings.Join(units, ",")))
|
||||
}
|
||||
s = append(s, fmt.Sprintf("%T(ID=%d Name=%s OwnerName=%s %s)", o.repository, o.repository.ID, o.repository.Name, o.repository.OwnerName, strings.Join(sa, " ")))
|
||||
}
|
||||
if o.permission != nil {
|
||||
var sa []string
|
||||
if len(o.permission.Units) > 0 {
|
||||
var units []string
|
||||
for _, repoUnit := range o.permission.Units {
|
||||
unitString := repoUnit.Type.String()
|
||||
if o.permission.UnitsMode != nil {
|
||||
if mode, has := o.permission.UnitsMode[repoUnit.Type]; has {
|
||||
unitString = fmt.Sprintf("%s:%s", unitString, mode)
|
||||
}
|
||||
}
|
||||
units = append(units, unitString)
|
||||
}
|
||||
sa = append(sa, fmt.Sprintf("Unit(%s)", strings.Join(units, ",")))
|
||||
}
|
||||
sa = append(sa, fmt.Sprintf("AccessMode(%s)", o.permission.AccessMode))
|
||||
s = append(s, fmt.Sprintf("%T(%s)", o.permission, strings.Join(sa, " ")))
|
||||
}
|
||||
if o.packageOwner != nil {
|
||||
s = append(s, fmt.Sprintf("packageOwner %T(Name=%s)", o.packageOwner, o.packageOwner.Name))
|
||||
s = append(s, fmt.Sprintf("packageMode %T(%s)", o.packageAccessMode, o.packageAccessMode))
|
||||
}
|
||||
return s
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue