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", and on every form the name can take once SAVED (savedForms), so "Setup.exe." is caught too.
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.