Files
Jonathan Miller 6c7a6e4061
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Branch Policy Check / Verify merge target (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
PR RC Release / Build RC Release (pull_request) Failing after 21s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
fix(licenses): RequireUnitReader allows LicensedReadOnly access
RequireUnitReader now checks for LicensedReadOnly context flag
before checking standard permissions. This lets the releases
download route pass through for licensed private repos where
RepoAssignment granted read-only access via license key.

Fixes the 404 on /releases/download/ with valid dlid= param.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-06-02 10:23:38 -05:00

101 lines
2.7 KiB
Go

// Copyright 2018 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package context
import (
"net/http"
"slices"
auth_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/auth"
repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/unit"
)
// CheckTokenScopes checks whether the authenticated API token contains any of the given scopes.
func CheckTokenScopes(ctx *Context, repo *repo_model.Repository, scopes ...auth_model.AccessTokenScope) {
if ctx.Data["IsApiToken"] != true {
return
}
scope, ok := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope)
if !ok {
return
}
publicOnly, err := scope.PublicOnly()
if err != nil {
ctx.ServerError("PublicOnly", err)
return
}
if publicOnly && repo != nil && repo.IsPrivate {
ctx.HTTPError(http.StatusForbidden)
return
}
scopeMatched, err := scope.HasAnyScope(scopes...)
if err != nil {
ctx.ServerError("HasAnyScope", err)
return
}
if !scopeMatched {
ctx.HTTPError(http.StatusForbidden)
}
}
// RequireRepoAdmin returns a middleware for requiring repository admin permission
func RequireRepoAdmin() func(ctx *Context) {
return func(ctx *Context) {
if !ctx.IsSigned || !ctx.Repo.Permission.IsAdmin() {
ctx.NotFound(nil)
return
}
}
}
// CanWriteToBranch checks if the user is allowed to write to the branch of the repo
func CanWriteToBranch() func(ctx *Context) {
return func(ctx *Context) {
if !ctx.Repo.CanWriteToBranch(ctx, ctx.Doer, ctx.Repo.BranchName) {
ctx.NotFound(nil)
return
}
}
}
// RequireUnitWriter returns a middleware for requiring repository write to one of the unit permission
func RequireUnitWriter(unitTypes ...unit.Type) func(ctx *Context) {
return func(ctx *Context) {
if slices.ContainsFunc(unitTypes, ctx.Repo.Permission.CanWrite) {
return
}
ctx.NotFound(nil)
}
}
// RequireUnitReader returns a middleware for requiring repository write to one of the unit permission
func RequireUnitReader(unitTypes ...unit.Type) func(ctx *Context) {
return func(ctx *Context) {
// Licensed read-only mode grants read access to all units.
if ctx.Data["LicensedReadOnly"] == true {
return
}
for _, unitType := range unitTypes {
if ctx.Repo.Permission.CanRead(unitType) {
return
}
if unitType == unit.TypeCode && canWriteAsMaintainer(ctx) {
return
}
}
ctx.NotFound(nil)
}
}
// CheckRepoScopedToken checks whether the authenticated API token has repo scope.
func CheckRepoScopedToken(ctx *Context, repo *repo_model.Repository, level auth_model.AccessTokenScopeLevel) {
CheckTokenScopes(ctx, repo, auth_model.GetRequiredScopes(level, auth_model.AccessTokenScopeCategoryRepository)...)
}