This commit is contained in:
Jabberwocky238
2026-07-17 05:55:31 -04:00
parent 67c07b3bcf
commit 68cda1972c
19 changed files with 897 additions and 897 deletions
+27 -27
View File
@@ -1,13 +1,13 @@
// HTTP-transport (PAT) access checks.
//
// A PAT is an opaque credential. Only its sha256 hash is stored; the plaintext
// is returned once at creation. AccessByPAT takes the PAT string directly (the
// cmd layer parses it out of the Authorization header) and checks it against the
// repo's (or its namespace's) ACL -- the state-layer half of the IState.AccessByPAT
// contract.
//
// PATs are created via ACLUpsertPATOnNS/OnRepo (IStateMut); there is no separate
// CreatePAT and intentionally no list/management read surface.
package state
@@ -22,18 +22,18 @@ import (
"simplegit/common"
)
const patPrefix = "sgp_" // plaintext token prefix
const patPrefix = "sgp_"
// AccessByPAT authorizes pat for perm on owner/name.
//
// - public read is open to everyone, including anonymous (pat ignored);
// - an empty pat is anonymous: allowed only by the public-read shortcut,
// otherwise ErrDenied (the caller decides 401 vs 403 from pat presence);
// - a present-but-unknown or expired pat yields ErrInvalidToken;
// - an authenticated but insufficient grant yields ErrDenied;
// - an unknown repo yields ErrDenied (existence never leaked).
//
// skip-auth allows all.
func (s *LocalState) AccessByPAT(ctx context.Context, pat, owner, name string, perm common.Perm) (bool, error) {
r, err := s.findRepo(owner, name)
if err != nil {
@@ -42,17 +42,17 @@ func (s *LocalState) AccessByPAT(ctx context.Context, pat, owner, name string, p
}
return false, err
}
// public read is open to everyone, including anonymous
if perm == common.PermRead && !r.IsPrivate {
return true, nil
}
if pat == "" {
// anonymous, but this needs a grant (private read, or any write)
return false, ErrDenied
}
p, err := s.lookupPAT(pat)
if err != nil {
return false, err // ErrInvalidToken
return false, err
}
ok, err := s.hasAccess(CredTypePAT, p.ID, r.ID, r.NamespaceID, perm)
if err != nil {
@@ -64,8 +64,8 @@ func (s *LocalState) AccessByPAT(ctx context.Context, pat, owner, name string, p
return true, nil
}
// lookupPAT hashes the presented token and returns the matching PAT row, or
// ErrInvalidToken if unknown or expired. Best-effort last-used stamp.
func (s *LocalState) lookupPAT(token string) (*PAT, error) {
sum := sha256.Sum256([]byte(token))
var pat PAT
@@ -79,7 +79,7 @@ func (s *LocalState) lookupPAT(token string) (*PAT, error) {
if pat.ExpiresAt != nil && time.Now().After(*pat.ExpiresAt) {
return nil, ErrInvalidToken
}
// best-effort last-used stamp; a failure here must not block access
now := time.Now()
if _, err := s.engine.ID(pat.ID).Cols("last_used_at").Update(&PAT{LastUsedAt: &now}); err == nil {
pat.LastUsedAt = &now