acl

package
v0.48.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 28, 2026 License: MIT Imports: 8 Imported by: 0

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

Constants

This section is empty.

Variables

This section is empty.

Functions

func CleanRel

func CleanRel(rel string) string

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.

Types

type Level

type Level int

Level is an ordered capability: None < Viewer < Editor < Owner.

const (
	LevelNone Level = iota
	LevelViewer
	LevelEditor
	LevelOwner
)

func ParseLevel

func ParseLevel(s string) Level

ParseLevel maps a grant level string to a Level (unknown → LevelNone).

func RoleCeiling

func RoleCeiling(role string) Level

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).

func (Level) String

func (l Level) String() string

String returns the level string. LevelNone → "none" (NOT "") so the frontend can distinguish "no access" (none) from "ACL not enforced" (field absent); an empty string would be ambiguous with the unwired/dev case.

type Resolver

type Resolver struct {
	// contains filtered or unexported fields
}

Resolver loads grants from the store and builds request-scoped ACL Sets.

func New

func New(store db.Store) *Resolver

New returns a Resolver backed by store.

func (*Resolver) LoadSet

func (r *Resolver) LoadSet(ctx context.Context, u *model.User, s *model.Storage) (*Set, error)

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

func (r *Resolver) Locks(ctx context.Context, storageID int64) *Set

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".

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) CanSee

func (s *Set) CanSee(rel string) bool

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) Ceiling

func (s *Set) Ceiling() Level

Ceiling is the account-role ceiling for this set's user.

func (*Set) Effective

func (s *Set) Effective(rel string) Level

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

func (s *Set) EffectiveIgnoringLocks(rel string) Level

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

func (s *Set) Grants() []*model.FileGrant

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) StorageVisible

func (s *Set) StorageVisible() bool

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL