Documentation
¶
Overview ¶
Package perm is filex's per-user permission model: 29 named permissions, the presets built from them, and the resolver that turns an account's role, the install's defaults, the permission rules that match it and its own overrides into one answer per permission — with where that answer came from, so "why can't they do this?" has a reply.
It is the complement to package acl, not a replacement. acl answers "how far may this user reach into this path" (folder grants, the viewer ceiling, app-plugin locks); perm answers "which actions may this user take at all". A file action needs both (acl.Set.Can, Phase 2).
⚠ Permissions are persisted BY NAME (overrides, rules, the defaults setting), never by bit position. The bit layout of Set is a runtime detail and may be reordered freely; a stored name that is no longer in the catalogue is ignored on read.
Index ¶
- Constants
- Variables
- func AppDefaultFor(def AppDefault) map[string]bool
- func AppKey(plugin, id string) string
- func Conditionable(p Perm) bool
- func DismissGap(ctx context.Context, store db.Store, id string) error
- func EffectiveRole(own int64, groups []*model.Group, rules []*model.PermissionRule, ...) (roleID int64, via *model.Group)
- func Foreign(k string) bool
- func ForeignEffects(m map[string]string) map[string]string
- func ForeignKeys(list []string) []string
- func GroupBefore(a, b *model.Group) bool
- func GroupInScope(g *model.Group, providerID *int64) bool
- func HolderRole(r *model.PermissionRule, set Set) string
- func Invalidate()
- func InvalidateFor(ctx context.Context, userIDs ...int64)
- func IsAppKey(k string) bool
- func KeepForeignEffects(m, stored map[string]string) map[string]string
- func Known(k Perm) bool
- func LevelUnderGroups(current string, groupRole *model.PermissionRule, kept string) string
- func MatchPreset(s Set) string
- func Middleware(next http.Handler) http.Handler
- func NormalizeRule(r *model.PermissionRule) error
- func NormalizeRuleEdit(r, prev *model.PermissionRule) error
- func NoteGapsSaved(ctx context.Context, store db.Store, before, after []Gap, shown []string) error
- func PreviewHolderRole(r model.PermissionRule) string
- func RestoreBuiltinGap(ctx context.Context, store db.Store, g Gap) ([]string, []string, error)
- func RoleHolder(r *model.PermissionRule) string
- func SaveAppDecisions(ctx context.Context, store db.Store, role string, m map[string]string) error
- func SaveDefaults(ctx context.Context, store db.Store, s Set) error
- func SaveRoleBase(ctx context.Context, store db.Store, role string, s Set) error
- func SetInvalidateHook(fn InvalidateHook)
- func StartingRole(rules []*model.PermissionRule, groups []string, providerID *int64) *model.PermissionRule
- func StoredForeign(ctx context.Context, store db.Store, role string) ([]string, error)
- func ValidAppDefault(d string) bool
- func ValidateAppDecisions(m map[string]string) error
- func ValidateEffects(m map[string]string) error
- func ValidateEffectsEdit(m, stored map[string]string) error
- func ValidateRoleBase(role string, s Set) error
- func WithMemo(ctx context.Context) context.Context
- func WithoutForeign(m map[string]string) map[string]string
- type AppDecisions
- type AppDefault
- type Def
- type Gap
- func AllGaps(ctx context.Context, store db.Store) ([]Gap, error)
- func AnnounceGaps(ctx context.Context, store db.Store) (fresh, open []Gap, err error)
- func BuiltinRoleGaps(ctx context.Context, store db.Store, role string) ([]Gap, error)
- func FindGap(ctx context.Context, store db.Store, id string) (Gap, bool, error)
- func OpenGaps(ctx context.Context, store db.Store) ([]Gap, error)
- func RuleGaps(r *model.PermissionRule) []Gap
- type Group
- type GroupRef
- type Input
- type InvalidateHook
- type Loader
- type Perm
- type Preset
- type Result
- func (r *Result) AllowedInFolders() Set
- func (r *Result) AppAllowed(key string, def AppDefault) (bool, Source)
- func (r *Result) AppInherited(key string, def AppDefault) (bool, Source)
- func (r *Result) Can(p Perm) bool
- func (r *Result) CanAt(storageID int64, rel string, p Perm) bool
- func (r *Result) ConditionalRules() []int64
- func (r *Result) VariesByFolder() Set
- func (r *Result) Why(p Perm) Source
- func (r *Result) WhyAt(storageID int64, rel string, p Perm) Source
- type Set
- type Source
- type SourceKind
- type UpgradeReport
Constants ¶
const ( PresetFullAdmin = "full_admin" PresetStandard = "standard" PresetReadOnly = "read_only" PresetUploadOnly = "upload_only" PresetGuest = "guest" )
Preset names.
const AppPrefix = "app."
AppPrefix starts every app permission key.
const MaxRuleDescriptionLen = 1000
MaxRuleDescriptionLen bounds a translated description: what the role's own description column holds on MySQL (00069, VARCHAR(1000)). A translated name is bounded like the name (MaxRuleNameLen).
const MaxRuleNameLen = 100
MaxRuleNameLen bounds a rule's name.
const SnapshotTTL = 3 * time.Second
SnapshotTTL bounds how stale the cached defaults and rules may be. Writes in this process call Invalidate and are seen at once; the TTL is what carries a write made by ANOTHER filex process on the same database.
Variables ¶
var ErrInvalid = errors.New("perm: invalid")
ErrInvalid wraps every validation failure so callers can map it to a 400.
var Guest = Of(FilesDownload)
Guest can look and download, and cannot even change its own profile — a shared or demo login.
var ReadOnly = Standard & viewerCeiling
ReadOnly is what a role=viewer account could do before permissions existed: read, comment, personal tags, AI, apps, every protocol and token (read-only — acl caps the level), and its own profile. No file mutation, no sharing.
var Standard = filter(func(d Def) bool { return d.Group != GroupAdmin })
Standard is everything outside the admin area: exactly what a role=user account could do before permissions existed. It is the fallback for the install's defaults, so an upgrade changes nobody's access.
var UploadOnly = Of(FilesCreate, FilesEncrypt, AccountEdit)
UploadOnly can put files in — encrypted ones too, as it could before files.encrypt existed — and nothing else: a drop-box account.
Functions ¶
func AppDefaultFor ¶ added in v0.50.0
func AppDefaultFor(def AppDefault) map[string]bool
AppDefaultFor is, for each built-in role (viewer, user, admin), whether an account on it holds an app permission whose manifest default is def when nobody has decided it: no exception, no custom role, no decision of the built-in role. It is AppAllowed itself, asked of such an account, so the catalogue (GET /api/admin/roles/catalogue → apps[].default_for) carries the answer and the role editors' "Default (allowed / not allowed)" only reads it — 0.49.0's editors kept a copy of the last layer of appDecide.
func Conditionable ¶
Conditionable reports whether p may be changed by a rule with conditions.
func DismissGap ¶ added in v0.52.0
DismissGap records that the gap named id is on purpose: it is not shown again while it stays as it is.
func EffectiveRole ¶ added in v0.50.0
func EffectiveRole(own int64, groups []*model.Group, rules []*model.PermissionRule, providerID *int64) (roleID int64, via *model.Group)
EffectiveRole is the custom role an account holds: own when it is not 0, else its groups' (see above). groups are the account's; rules are every custom role (a group's role missing from them, or of another tenant, is no role). via is the group it came from, nil for the account's own role or none.
func Foreign ¶ added in v0.52.0
Foreign reports whether k is a permission this version does not know: not in the catalogue and not an app permission (perm/app.go, which has rules of its own).
func ForeignEffects ¶ added in v0.52.0
ForeignEffects returns the entries of an Allow / Deny map whose key this version does not know; nil when there are none.
func ForeignKeys ¶ added in v0.52.0
ForeignKeys returns the keys of list this version does not know, in their order, each once.
func GroupBefore ¶ added in v0.50.0
GroupBefore is the order a member's role is looked for in: the higher priority first, then the lower id.
func GroupInScope ¶ added in v0.50.0
GroupInScope reports whether a group reaches an account of the given tenant: an install-wide group reaches everyone, a tenant's group only its own people.
func HolderRole ¶
func HolderRole(r *model.PermissionRule, set Set) string
HolderRole is the built-in role the people holding r get. It is not a choice: a role that can add, change, delete or share anything — everywhere or in some folders — needs the User level to do it; any other role is a Viewer's, which keeps a read-only role read-only on every door, even if an exception later allows a write.
func Invalidate ¶
func Invalidate()
Invalidate drops every Loader's cached defaults and rules. Call it after writing either. Prefer InvalidateFor, which says whose people the change can concern: Invalidate tells the hook nothing about it, which the server reads as "anybody, on every tenant".
func InvalidateFor ¶ added in v0.54.0
InvalidateFor is Invalidate for a write made by ctx's caller about the named accounts. It tells the invalidate hook (the realtime hub: open explorers ask their menu answers again, #196) who may be concerned: the named accounts when there are any, else the people of the caller's tenant (ctx's tenant scope), else - a platform-level change, or a single-tenant install - everybody.
func KeepForeignEffects ¶ added in v0.52.0
KeepForeignEffects puts the entries of stored this version does not know into m, as they were stored, and returns m.
func LevelUnderGroups ¶ added in v0.50.0
func LevelUnderGroups(current string, groupRole *model.PermissionRule, kept string) string
LevelUnderGroups is the built-in level (User or Viewer) of an account with no custom role of its own, as its groups decide it: the level the role its groups give it sets (RoleHolder); with none, the level kept from before a group's role first moved it (kept, "" for none — never administrator); else the level it has now.
ONE rule: group.SyncLevels writes it, and every preview a delegated administrator is judged by reads it (Loader.Preview, the admin handlers' groupsPreview) — so a change is judged at the level the account will really be on.
func MatchPreset ¶
MatchPreset returns the name of the preset equal to s, or "" (custom).
func Middleware ¶
Middleware installs WithMemo on every request.
func NormalizeRule ¶
func NormalizeRule(r *model.PermissionRule) error
NormalizeRule validates r in place and canonicalizes what it can (trimmed name and targets, lowercase dot-less extensions). It does not check that user ids or the provider exist — that is the handler's job, with the store.
func NormalizeRuleEdit ¶
func NormalizeRuleEdit(r, prev *model.PermissionRule) error
NormalizeRuleEdit is NormalizeRule for a new version of prev (nil for a new role). Two things differ: a language prev's translations already carry stays acceptable (normalizeRuleTexts), and a permission prev holds that this version does not know - a later version's - is kept as prev has it, in the role's own list and in its folder part, whether the request sends it back or leaves it out (foreign.go). A folder part taken away takes those with it.
func NoteGapsSaved ¶ added in v0.52.0
NoteGapsSaved records what a save on this version did to one list's gaps: before and after are that list's gaps either side of the save. A gap the save opened is on purpose when the editor showed the administrator its key (shown: the keys it showed) and is dismissed there and then; a dismissed gap the save closed leaves the dismissed list, so that it is shown again should it ever open the other way.
func PreviewHolderRole ¶ added in v0.50.0
func PreviewHolderRole(r model.PermissionRule) string
PreviewHolderRole is RoleHolder for a role still being edited: the body as the role editor has it now, which may not be valid yet (no name, a path half typed). It answers what the role's people would be on if the body were saved as it stands — with the folder conditions a save stores (a blank path names no folder) — and refuses nothing. The custom role editor asks it (POST /api/admin/roles/preview) for each app permission's "Default" instead of keeping its own copy of this rule, which 0.49.0's did.
func RestoreBuiltinGap ¶ added in v0.52.0
RestoreBuiltinGap gives a built-in role's stored list the gap's key, and returns the list before and after. Everything else in it - a later version's keys too - stays as it is.
func RoleHolder ¶
func RoleHolder(r *model.PermissionRule) string
RoleHolder is HolderRole for a role as stored.
func SaveAppDecisions ¶
SaveAppDecisions replaces one built-in role's app decisions ({} clears them).
func SaveDefaults ¶
SaveDefaults stores the install's defaults for role=user. Role-only permissions are refused rather than silently dropped. A key the stored list holds that this version does not know - a later version's - is kept (foreign.go).
func SaveRoleBase ¶
SaveRoleBase stores the base of a built-in role. A viewer's is refused if it names a permission a viewer can never hold, rather than silently trimmed. A key the stored list holds that this version does not know is kept: the page cannot show it, so the save cannot have taken it away (foreign.go).
func SetInvalidateHook ¶ added in v0.54.0
func SetInvalidateHook(fn InvalidateHook)
SetInvalidateHook installs fn to be called after every invalidation; nil removes it. fn must not block: it runs on the request that wrote the change. The server wires the realtime hub here (api.BuildRouter), so a role, a rule or a group membership edited reaches the open explorers it can concern as an `access.changed` frame (internal/realtime/access.go).
func StartingRole ¶
func StartingRole(rules []*model.PermissionRule, groups []string, providerID *int64) *model.PermissionRule
StartingRole is the custom role a NEW account is given when its first SSO sign-in carries one of the groups a role names: the lowest-numbered enabled role in the account's tenant with a matching sso_group target, or nil.
func StoredForeign ¶ added in v0.52.0
StoredForeign returns the keys a built-in role's saved list holds that this version does not know: what its page cannot show and its save keeps.
func ValidAppDefault ¶
ValidAppDefault reports whether d is one of the three.
func ValidateAppDecisions ¶
ValidateAppDecisions is SaveAppDecisions' check without the write.
func ValidateEffects ¶
ValidateEffects checks an overrides or rule effects map: known keys, not role-only, allow/deny only.
func ValidateEffectsEdit ¶ added in v0.52.0
ValidateEffectsEdit is ValidateEffects for a new version of stored (a person's exceptions, a role's folder part): a key this version does not know passes when stored holds it already. Its effect is not looked at: the stored one is kept (KeepForeignEffects).
func ValidateRoleBase ¶
ValidateRoleBase is SaveRoleBase's check without the write: role=user may not hold a role-only permission, role=viewer nothing past the viewer ceiling, and no other role has an editable base.
func WithMemo ¶
WithMemo returns ctx carrying a memo so a request that consults permissions several times (one acl.LoadSet per storage it touches) resolves each account once. Install it once per request, at the router.
func WithoutForeign ¶ added in v0.52.0
WithoutForeign returns m without the keys this version does not know: what a request leaves when the later version's entries, which it may only send back, are set aside to be put back as they were stored (KeepForeignEffects).
Types ¶
type AppDecisions ¶
AppDecisions is the built-in roles' app decisions: {"user": {"app.sign.request": "deny"}, "viewer": {...}}.
func LoadAppDecisions ¶
LoadAppDecisions reads the built-in roles' app decisions; none is empty.
type AppDefault ¶
type AppDefault string
AppDefault is who holds an app permission nobody has decided: the app's manifest picks it, the administrator can change it per role and per person.
const ( // AppDefaultViewer: every account (viewers included). AppDefaultViewer AppDefault = "viewer" // AppDefaultUser: accounts that can change files — not viewers. AppDefaultUser AppDefault = "user" // AppDefaultAdmin: administrators only, until granted. AppDefaultAdmin AppDefault = "admin" )
type Def ¶
type Def struct {
Key Perm
Group Group
// RoleOnly entries are held only through the account role; rules and
// overrides naming them are ignored (and refused by Validate*).
RoleOnly bool
// ViewerCapped entries can never be allowed for a role=viewer account,
// whatever a rule or override says — the same line acl.RoleCeiling draws
// at LevelViewer for file mutation, extended to sharing (which needs
// editor level today, see handlers/share.go).
ViewerCapped bool
}
Def describes one catalogue entry.
type Gap ¶ added in v0.52.0
type Gap struct {
// ID names the gap for the restore and dismiss requests:
// "builtin:user:files.encrypt", "role:12:files.encrypt".
ID string `json:"id"`
Key Perm `json:"key"`
From Perm `json:"from"`
// Role is the built-in role whose list it is ("user"); empty for a
// custom role.
Role string `json:"role,omitempty"`
// RuleID and RuleName are the custom role whose folder part it is.
RuleID int64 `json:"rule_id,omitempty"`
RuleName string `json:"rule_name,omitempty"`
// ProviderID is the custom role's tenant: nil for the platform's own
// roles and on an install without tenants.
ProviderID *int64 `json:"-"`
}
Gap is one list that allows From and not Key.
func AllGaps ¶ added in v0.52.0
AllGaps returns every gap, dismissed or not: the built-in roles' first, then the custom roles' in id order.
func AnnounceGaps ¶ added in v0.52.0
AnnounceGaps returns the open gaps, and those of them administrators have not been told of yet, and records that they now have been. It also lets go of the dismissals of gaps that are gone. Called at start and after a save that can open one (internal/permgap).
func BuiltinRoleGaps ¶ added in v0.52.0
BuiltinRoleGaps returns the gaps of a built-in role's saved list.
func FindGap ¶ added in v0.52.0
FindGap returns the gap named id, dismissed or not; false when there is no such gap any more (the list was saved, the role deleted).
func RuleGaps ¶ added in v0.52.0
func RuleGaps(r *model.PermissionRule) []Gap
RuleGaps returns the gaps of a custom role's folder part: it allows the older key there, does not decide the carved-out one, and the role's own list does not hold it (where it does, the folder part inherits it).
type Input ¶
type Input struct {
UserID int64
Role string
ProviderID *int64
// CustomRoleID is the one custom role the account holds: its own
// (user_custom_roles), else its groups' (EffectiveRole); 0 is none.
CustomRoleID int64
// ViaGroup is the group CustomRoleID came from; nil when it is the
// account's own.
ViaGroup *GroupRef
// Groups are the account's groups, for Loader.Preview only: filled from
// the store before the change, so a change can leave one out or alter
// one (a group deleted, its role cleared), and the role is then picked
// from them. Resolve does not read it.
Groups []*model.Group
// Defaults is the base set for role=user (model.SettingPermissionDefaults).
Defaults Set
// ViewerBase is the base set for role=viewer
// (model.SettingPermissionViewerDefaults); nil is the Read-only preset.
ViewerBase *Set
// Rules is every custom role on the install; Resolve applies the
// account's own (CustomRoleID), if it is enabled and in scope.
Rules []*model.PermissionRule
// Overrides is the user's own allow/deny map (keys are Perm names, and
// app permission keys — perm/app.go).
Overrides map[string]string
// AppDecisions are the account's built-in role's decisions about app
// permissions (SettingPermissionAppDefaults for its role).
AppDecisions map[string]string
}
Input is everything Resolve needs about one account. The Loader fills it from the store; tests build it by hand.
type InvalidateHook ¶ added in v0.54.0
InvalidateHook is told after every invalidation: the writer's context and the accounts it named (none: the writer's tenant, or everybody).
type Loader ¶
Loader reads what Resolve needs from the store.
⚠ Any read failure is returned, never papered over with a default: the caller denies on error (the same rule acl.Resolver follows). Falling back to the Standard preset when the defaults row is unreadable would hand an install that had narrowed its defaults the full set back.
func (*Loader) Load ¶
Load resolves u's permissions. A nil user holds nothing. An administrator is answered without touching the store. Within a request carrying a memo (WithMemo), an account is resolved once.
func (*Loader) Preview ¶
Preview resolves u as Load would after change has been applied to the input: what the account WOULD hold with other exceptions, another custom role or another built-in role. u may be a new account that is not stored yet (id 0: no exceptions, no custom role). The per-request memo is neither read nor filled — the answer is about a state that does not exist.
It is how a delegated administrator's change is judged by its RESULT rather than by the words of the request: lifting a Deny, ending a restrictive custom role or picking a built-in role all hand out permissions without the request naming a single one.
type Perm ¶
type Perm string
Perm is one permission, identified by its stable key.
const ( FilesDownload Perm = "files.download" FilesCreate Perm = "files.create" FilesModify Perm = "files.modify" FilesRename Perm = "files.rename" // a new name in the same folder FilesMove Perm = "files.move" // to another folder FilesDelete Perm = "files.delete" // to trash FilesPurge Perm = "files.purge" // permanent delete, empty trash // FilesEncrypt is making something end-to-end encrypted: a folder's // first .filex-e2e.json (a new encrypted folder, or the first step of // encrypting one in place) or a new .fxe. It is carved out of // files.create, which the same write needs as well. FilesEncrypt Perm = "files.encrypt" FilesTag Perm = "files.tag" )
File actions. Path-scopable; each maps to an operation every protocol has.
const ( CommentsWrite Perm = "comments.write" AIUse Perm = "ai.use" PluginsRun Perm = "plugins.run" )
Sharing and features.
const ( AccessWebDAV Perm = "access.webdav" AccessSFTP Perm = "access.sftp" AccessFTP Perm = "access.ftp" AccessS3 Perm = "access.s3" AccessNFS Perm = "access.nfs" AccessAPI Perm = "access.api" AccessDesktop Perm = "access.desktop" )
Access outside the web app.
const ( AdminUsers Perm = "admin.users" AdminGrants Perm = "admin.grants" AdminAudit Perm = "admin.audit" AdminMonitor Perm = "admin.monitor" // AdminFull is the account role `admin`, surfaced as a permission so the // UI can show it. It is never granted by a rule or an override: storages, // settings, SSO, plugins and updates each amount to full control of the // server, so the only way to hold them is to BE an administrator. AdminFull Perm = "admin.full" )
Admin area.
const (
AccountEdit Perm = "account.edit"
)
Own account.
func CarvedOut ¶ added in v0.52.0
func CarvedOut() []Perm
CarvedOut returns the permissions carved out of an older one, in key order: the ones a gap can be about.
func RelocateNeeds ¶
RelocateNeeds is what taking a path from src to dst is: a new name in the same folder is files.rename, the same name in another folder (or on another storage) files.move, and both at once needs both. Paths are storage-relative. A path that does not change still counts as a rename, so every caller has something to check.
type Result ¶
type Result struct {
Allowed Set
Sources map[Perm]Source
// Settings is the most restrictive merge of every applying rule's
// settings.
Settings model.PermRuleSettings
// Rules are the ids of the rules that applied, in input order.
Rules []int64
// ViaGroup is the group the account's custom role came from, or nil.
ViaGroup *GroupRef
// contains filtered or unexported fields
}
Result is one account's resolved permissions.
func Resolve ¶
Resolve computes an account's permissions. Layers, lowest first:
- base — role=user: in.Defaults; role=viewer: in.ViewerBase (the Read-only preset when unset); other: nothing.
- the account's custom role (one per person, CustomRoleID — its own, or else its groups', EffectiveRole), when it is enabled and in the account's tenant: its own list REPLACES the base, and its "different in some folders" part applies per path (CanAt).
- overrides — the user's own allow/deny; always wins over rules.
Then two hard lines no layer can cross: role-only permissions (admin.full) follow the role alone, and a viewer account never holds a ViewerCapped permission. role=admin short-circuits everything: an administrator holds every permission and is bound by no rule (they could edit the rule anyway).
func (*Result) AllowedInFolders ¶
AllowedInFolders is what the account may do only in some folders: the permissions its role's "different in some folders" part allows that it does not hold everywhere — minus what its own exceptions deny, and what a viewer can never hold. A client offers these actions and lets the server decide per path (CanAt); it must not hide them.
func (*Result) AppAllowed ¶
func (r *Result) AppAllowed(key string, def AppDefault) (bool, Source)
AppAllowed decides the app permission key for this account. def is the app's manifest default for it. Layers, highest first: the administrator role, the person's own exception, their custom role's decision, the built-in role's decision, the app default.
func (*Result) AppInherited ¶
func (r *Result) AppInherited(key string, def AppDefault) (bool, Source)
AppInherited is AppAllowed without the person's own exception: what the account would get from its role and the app's default alone — the answer a person's "Default" choice stands for on their exceptions editor.
func (*Result) CanAt ¶
CanAt is Can for an action on one path of one storage: the same answer, except where a conditioned rule (model.PermRuleConditions) matches — its allow or deny then counts as a rule's does, beneath the user's overrides.
func (*Result) ConditionalRules ¶
ConditionalRules returns the ids of the applying rules that bind only some storages or paths — they are not in Rules, and not in Allowed.
func (*Result) VariesByFolder ¶
VariesByFolder is every permission whose answer can differ from path to path: those the role's folder part allows or denies somewhere — minus what an exception of the account's own fixes everywhere, and what a viewer can never hold. A client asks the server (CanAt, per path) about these before offering them, and trusts Allowed for the rest.
type Set ¶
type Set uint64
Set is a set of permissions as a bitset — the in-memory form only.
func FromStrings ¶
FromStrings parses persisted keys, dropping unknown ones (a permission removed from the catalogue must not fail a whole read).
func LoadDefaults ¶
LoadDefaults returns the install's defaults for role=user: the stored set, or Standard when none was ever saved.
func LoadRoleBase ¶
LoadRoleBase returns the editable base of a built-in role: the defaults for role=user, the viewer defaults (capped at the viewer ceiling) for role=viewer. Administrators have no editable base — everything is theirs.
func RoleSet ¶
func RoleSet(r *model.PermissionRule) Set
RoleSet is what a custom role allows everywhere: its own list.
func ViewerCeiling ¶
func ViewerCeiling() Set
ViewerCeiling is every permission a viewer account can ever hold.
type Source ¶
type Source struct {
Kind SourceKind `json:"kind"`
RuleID int64 `json:"rule_id,omitempty"`
RuleName string `json:"rule_name,omitempty"`
// RuleNames are the role's names in other languages (migration 00071),
// kept so a refusal can name the role in its reader's language
// (RuleNameFor). Not on the wire: rule_name stays the role's own name,
// and the admin pages hold the translations with the role itself.
RuleNames map[string]string `json:"-"`
// GroupID and GroupName say the custom role is the account's through a
// group (it has none of its own) — set on a SourceRule or SourceRoleOff
// answer only.
GroupID int64 `json:"group_id,omitempty"`
GroupName string `json:"group_name,omitempty"`
}
Source is where one permission's answer came from.
func (Source) RuleNameFor ¶
RuleNameFor is the deciding role's name for a reader of lang: its translation, else its own name (model.LocalizedText, the one rule PermissionRule.NameFor follows too).
type SourceKind ¶
type SourceKind string
SourceKind says which layer decided a permission.
const ( // SourceRole: the account role decided outright (admin holds everything; // admin.full follows the role alone). SourceRole SourceKind = "role" // SourceBase: nothing overrode it; it is the role's starting set (the // install defaults for role=user, the Read-only preset for role=viewer). SourceBase SourceKind = "base" // SourceRule: the account's custom role decided it (its list, or its // "different in some folders" part). SourceRule SourceKind = "rule" // SourceOverride: the user's own override. SourceOverride SourceKind = "override" // SourceViewerCeiling: something allowed it, but a viewer account can // never hold it. SourceViewerCeiling SourceKind = "viewer_ceiling" // SourceRoleOff: the account's custom role is switched off, and a // switched-off role gives nothing (never the built-in role instead — for // a role that takes things away, that would be MORE access). SourceRoleOff SourceKind = "role_off" )
const SourceAppDefault SourceKind = "app_default"
SourceAppDefault is an app permission decided by the app's own default.
type UpgradeReport ¶ added in v0.51.0
type UpgradeReport struct {
// Added are the catalogue's keys the install had not known, in
// catalogue order — with or without an older key to follow.
Added []Perm
// RolesChanged is how many custom roles were given an added key.
RolesChanged int
// DefaultsChanged: a built-in role's saved list was given one.
DefaultsChanged bool
// ExceptionsChanged is how many people's own exceptions were given one.
ExceptionsChanged int
}
UpgradeReport is what one UpgradeCatalogue changed.
func UpgradeCatalogue ¶ added in v0.51.0
UpgradeCatalogue gives every saved role, and every person's own exceptions, the keys this version added that they held through an older key (inheritOnAdd), and records the catalogue. Call it at start, after the migrations and before serving; a start that finds the catalogue it recorded changes nothing.
All or nothing, in one transaction: the catalogue is recorded only together with every change it implies, so a start that fails part-way leaves the database as it found it and the next start does the whole of it again. ⚠ The server runs on after such a failure, and a list an administrator edits before the next start looks like one saved before the key existed: the retry gives it the key as well.