54 lines
2.2 KiB
Go
54 lines
2.2 KiB
Go
// Shared access-check primitives and errors.
|
|
//
|
|
// state defines its own error sentinels (ErrDenied / ErrInvalidToken /
|
|
// ErrRepoNotFound) and stays free of any gitrpc dependency -- the cmd layer
|
|
// maps these to HTTP/SSH outcomes. hasAccess is the single ACL-rank check
|
|
// shared by the SSH and PAT access paths.
|
|
|
|
package state
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"simplegit/common"
|
|
)
|
|
|
|
var (
|
|
// ErrDenied means the caller is not permitted: an anonymous caller needing
|
|
// a grant, or an authenticated caller whose ACL grant is insufficient.
|
|
ErrDenied = errors.New("access denied")
|
|
// ErrInvalidToken means a PAT was presented but could not be matched (unknown
|
|
// hash) or has expired. Distinct from anonymous (no PAT at all).
|
|
ErrInvalidToken = errors.New("invalid or expired token")
|
|
// ErrRepoNotFound means no DB row for the (owner, name). Surfaced to callers
|
|
// of Open/RepoPath; access paths map it to ErrDenied so existence is never
|
|
// leaked.
|
|
ErrRepoNotFound = errors.New("repository not found")
|
|
// ErrNamespaceNotFound means no repo exists in the namespace yet, so its
|
|
// shared NamespaceID cannot be resolved. CreateRepo treats this as "mint a
|
|
// new NamespaceID"; ACLUpsertOnNS surfaces it (grant before any repo exists).
|
|
ErrNamespaceNotFound = errors.New("namespace does not exist")
|
|
)
|
|
|
|
// hasAccess reports whether the credential (credType, credID) holds an ACL grant
|
|
// satisfying perm on the repo (repoID) or its namespace (nsID). ACL targets are
|
|
// polymorphic -- TargetTypeRepo or TargetTypeNS -- so a grant on either applies,
|
|
// and the best-ranked matching grant wins. No grant means false (the public-read
|
|
// shortcut is handled by the caller before this is called).
|
|
func (s *LocalState) hasAccess(credType CredType, credID, repoID, nsID int64, perm common.Perm) (bool, error) {
|
|
var acls []ACL
|
|
err := s.engine.Where("cred_type = ? AND cred_id = ? AND ((target_type = ? AND target_id = ?) OR (target_type = ? AND target_id = ?))",
|
|
credType, credID, TargetTypeRepo, repoID, TargetTypeNS, nsID).Find(&acls)
|
|
if err != nil {
|
|
return false, fmt.Errorf("lookup acl: %w", err)
|
|
}
|
|
best := 0
|
|
for _, a := range acls {
|
|
if r := common.Perm(a.Perm).PermRank(); r > best {
|
|
best = r
|
|
}
|
|
}
|
|
return best >= perm.PermRank(), nil
|
|
}
|