Documentation
¶
Overview ¶
Package acl implements per-user / per-file&folder access control for filex.
It is the identity-driven complement to package confine. confine is the token HARD-CEILING (a token's `root:` scope + X-Filex-Root header, a single subtree) and runs as a chi middleware that rewrites request paths. acl runs AFTER, inside the handlers, keyed off the authenticated *user* (not the token) so plain cookie/session callers are filtered too — closing the gap where a session user previously saw every storage and every path.
The two compose: confine narrows to at most one subtree; acl narrows to the (possibly many, possibly none) subtrees the user was granted, and assigns a capability level (viewer/editor/owner) that is finally capped by the user's account-role ceiling.
Backwards compatible: on a storage with RBACEnabled=false, acl returns the account-role base level (user→editor, viewer→viewer, admin→owner) for every path and treats the storage as fully visible — reproducing pre-00012 behavior exactly. Grants are only consulted on RBAC-on storages.
Index ¶
- func CleanRel(rel string) string
- func UserGrants(ctx context.Context, store db.Store, storageID int64, u *model.User) ([]*model.FileGrant, error)
- type Level
- type Resolver
- func (r *Resolver) AttachVaults(f VaultFinder)
- func (r *Resolver) LoadSet(ctx context.Context, u *model.User, s *model.Storage) (*Set, error)
- func (r *Resolver) Locks(ctx context.Context, storageID int64) *Set
- func (r *Resolver) Perms(ctx context.Context, u *model.User) (*perm.Result, error)
- func (r *Resolver) PermsPreview(ctx context.Context, u *model.User, change func(*perm.Input)) (*perm.Result, error)
- func (r *Resolver) VaultRoot(ctx context.Context, storageID int64, rel string) (string, bool)
- type Set
- func (s *Set) Allows(p perm.Perm) bool
- func (s *Set) AllowsAt(rel string, p perm.Perm) bool
- func (s *Set) BlockedExtension(rel string) string
- func (s *Set) Can(rel string, p perm.Perm) bool
- func (s *Set) CanSee(rel string) bool
- func (s *Set) Ceiling() Level
- func (s *Set) Effective(rel string) Level
- func (s *Set) EffectiveIgnoringLocks(rel string) Level
- func (s *Set) Grants() []*model.FileGrant
- func (s *Set) Lock(rel string) *model.AppPluginLock
- func (s *Set) LockWithin(rel string) *model.AppPluginLock
- func (s *Set) Perms() *perm.Result
- func (s *Set) StorageVisible() bool
- func (s *Set) VaultRoot(rel string) (string, bool)
- func (s *Set) WhyAt(rel string, p perm.Perm) perm.Source
- type VaultFinder
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CleanRel ¶
CleanRel normalizes a storage-relative path to confine-form: no leading or trailing slash, traversal collapsed, "" == root. Mirrors confine.split's rel handling so acl and confine agree on path identity.
func UserGrants ¶ added in v0.50.0
func UserGrants(ctx context.Context, store db.Store, storageID int64, u *model.User) ([]*model.FileGrant, error)
UserGrants is every grant that reaches u on one storage: their own, and those of the groups they are in (group_file_grants) that are in their tenant. A group's grant counts exactly as a grant to each member would — the highest covering level wins, and the account-role ceiling caps it.
Types ¶
type Level ¶
type Level int
Level is an ordered capability: None < Viewer < Editor < Owner.
func NeedLevel ¶ added in v0.49.0
NeedLevel is the path capability a file-scoped permission also requires: holding files.delete lets a user delete only where acl already lets them write. Permissions that are not about a path answer LevelNone.
The levels are the ones the handlers demanded before permissions existed: reads are viewer, every mutation is editor, sharing a public link is editor (handlers/share.go) and sharing with a person is owner (handlers/grants.go).
func ParseLevel ¶
ParseLevel maps a grant level string to a Level (unknown → LevelNone).
func RoleCeiling ¶
RoleCeiling is the maximum effective level an account role may ever reach. A viewer account is capped at LevelViewer (read-only everywhere, even on RBAC-off storages and even if handed an editor/owner item grant).
type Resolver ¶
type Resolver struct {
// contains filtered or unexported fields
}
Resolver loads grants from the store and builds request-scoped ACL Sets.
func (*Resolver) AttachVaults ¶ added in v0.54.0
func (r *Resolver) AttachVaults(f VaultFinder)
AttachVaults gives every Set this resolver builds - the lock views every write door hands writegate.Check (Locks), and the request sets (LoadSet) - the answer to "is this path inside a vault", so writegate refuses a write there whichever door it comes through. Called once at wiring, when vaults are on (FILEX_E2E_VAULT).
func (*Resolver) LoadSet ¶
LoadSet builds the ACL set for user u on storage s. For admins and RBAC-off storages it skips the grant query entirely (they never consult grants).
func (*Resolver) Locks ¶
Locks returns the live app-plugin locks of one storage as a Set that answers only Lock and LockWithin — for a write with no person behind it (a document server's save, an app's output) and for protocol sessions, whose per-session Set was loaded when the session began and does not see a lock taken after that (writegate.Check). A nil Resolver answers nil, which writegate reads as "nothing is locked".
func (*Resolver) Perms ¶ added in v0.49.0
Perms resolves u's per-user permissions — for the checks that are not about a path (comments, tokens, protocol access, the admin area). A nil Resolver or one without a store answers nil, which Allows reads as "not enforced".
func (*Resolver) PermsPreview ¶ added in v0.49.0
func (r *Resolver) PermsPreview(ctx context.Context, u *model.User, change func(*perm.Input)) (*perm.Result, error)
PermsPreview is Perms for a state that is not stored yet (perm.Loader. Preview): what u would hold after change. Nil, like Perms, when unwired.
func (*Resolver) VaultRoot ¶ added in v0.55.0
VaultRoot is the attached finder's answer (AttachVaults) for a path on a storage: the vault folder rel is inside of, or is. ok is false while vaults are off, and on a nil resolver. It makes the Resolver a VaultFinder for the readers that ask about rows from many storages at once without a Set per storage (the `encrypted` stamp on Recent, Starred, search hits, task #189).
type Set ¶
type Set struct {
// contains filtered or unexported fields
}
Set is the resolved ACL for one (user, storage) pair for the duration of a request. Grants are batch-loaded once by LoadSet; Effective / CanSee / StorageVisible are then pure in-memory checks with no further DB access.
func (*Set) Allows ¶ added in v0.49.0
Allows reports whether the caller holds per-user permission p, regardless of path. Nil permissions (no loader wired — tests only) allow.
func (*Set) AllowsAt ¶ added in v0.49.0
AllowsAt is Allows for an action on rel: the same answer, except where a permission rule limited to storages or paths (perm.Result.CanAt) matches this storage and rel. Every check that has the path should ask this one.
func (*Set) BlockedExtension ¶ added in v0.49.0
BlockedExtension returns the extension of rel's name that a permission rule binding this caller blocks ("exe", "tar.gz"), or "". Compared on the lowercase name, so "Setup.EXE" is caught by "exe".
func (*Set) Can ¶ added in v0.49.0
Can reports whether the caller may take action p on rel: the path level p needs (NeedLevel, which includes the app-plugin lock cap) AND the per-user permission itself.
A file type a permission rule blocks (blocked_extensions) is refused here for every action that would produce a file of that name — adding, changing or renaming/moving to it — so every door that asks Can refuses it without knowing rules exist. What such a file already there can still do is be read and deleted.
func (*Set) CanSee ¶
CanSee reports whether rel should appear in a listing for this caller: either the caller has ≥viewer on it, OR rel is a (strict or equal) ancestor of a granted path — so ancestor folders render as traversal nodes that let the user drill down to the subtree they were actually granted.
func (*Set) Effective ¶
Effective returns the caller's effective capability on a storage-relative path: the highest grant covering it (direct or inherited from an ancestor folder), capped by the account-role ceiling. Admins are always Owner; RBAC-off storages return the account-role base.
func (*Set) EffectiveIgnoringLocks ¶
EffectiveIgnoringLocks is Effective without the app-plugin lock cap — for the one caller that may write into a locked file: a job of the plugin holding the lock.
func (*Set) Grants ¶
Grants returns the raw grants loaded for this set (may be nil for admins / RBAC-off storages). The permissions handler uses this for the panel.
func (*Set) Lock ¶
func (s *Set) Lock(rel string) *model.AppPluginLock
Lock returns the live app-plugin lock on rel, or nil. Exact path only: a lock on a file does not freeze its folder (the folder can still gain siblings), and a lock on a folder freezes only the folder entry itself.
func (*Set) LockWithin ¶
func (s *Set) LockWithin(rel string) *model.AppPluginLock
LockWithin returns a live app-plugin lock on rel itself or anywhere under it, or nil. Renaming, moving or deleting a folder takes every file inside along, so a mutation of the folder ENTRY is refused while any descendant is locked — while uploads into the folder, which touch no locked file, stay open (LockWithin is consulted by source-side mutations only; Effective is not).
func (*Set) Perms ¶ added in v0.49.0
Perms returns the caller's resolved permissions (nil when unwired).
func (*Set) StorageVisible ¶
StorageVisible reports whether the storage should appear in the caller's storage/drive list at all. Admins and RBAC-off storages are always visible; on an RBAC-on storage a non-admin needs at least one grant.