This commit is contained in:
Jabberwocky238
2026-07-15 11:06:48 -04:00
commit c746f88bbe
69 changed files with 14975 additions and 0 deletions
+53
View File
@@ -0,0 +1,53 @@
// 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
}