- manifest.webmanifest/+server.ts: swap PUBLIC_AE_API_SECRET_KEY → PUBLIC_AE_BOOTSTRAP_KEY (least privilege; endpoint only needs a site-domain lookup, same as the bootstrap use case) - electron_relay.ts: add cleanup_tmp_files() — runs `find ... -name "*.tmp" -mmin +N -delete` via native run_cmd bridge - launcher_background_sync.svelte: call cleanup_tmp_files() on mount when is_native && cache_root are present (once per startup) - AE__Permissions_and_Security.md: close Sev-1 audit language - TODO__Agents.md: mark PUBLIC_AE_API_SECRET_KEY audit as complete Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7.2 KiB
Aether — Permissions and Security
Last updated: 2026-02-27
Source of truth: src/lib/ae_utils/ae_utils__perm_checks.ts, src/lib/stores/ae_stores.ts
Access Level Hierarchy
Highest to lowest. Each level inherits all access from every level below it.
| Level | access_type string |
Typical Use |
|---|---|---|
| Super | super |
OSIT internal — full system access |
| Manager | manager |
Account managers |
| Administrator | administrator |
Event/account admins |
| Trusted | trusted |
Onsite staff — site passcode or AE login |
| Public | public |
Site-wide passcode granted |
| Authenticated | authenticated |
Identity verified (e.g. IDAA Novi UUID) |
| Anonymous | anonymous |
Default — not signed in |
Note on Public vs Authenticated:
publicis a site-wide unlock (anyone with the passcode).authenticatedverifies a specific identity. In the hierarchy, public outranks authenticated because it implies broader site access.
$ae_loc Store — Permission Flags
$ae_loc is a persisted() store (backed by localStorage). Key fields:
$ae_loc.access_type // string: current access type ('anonymous', 'trusted', etc.)
// Cumulative boolean flags (true = "you have AT LEAST this level")
$ae_loc.anonymous_access // always true
$ae_loc.authenticated_access // true from authenticated and above
$ae_loc.public_access // true from public and above
$ae_loc.trusted_access // true from trusted and above ← most-used gate
$ae_loc.administrator_access // true from administrator and above
$ae_loc.manager_access // true from manager and above
$ae_loc.super_access // true only at super
// Exclusive check flags (true = "you are EXACTLY this level")
$ae_loc.trusted_check // true only if access_type === 'trusted'
$ae_loc.administrator_check // etc.
// (rarely needed — prefer the _access flags)
// Behavior flags
$ae_loc.edit_mode // boolean — user preference, see below
$ae_loc.adv_mode // boolean — advanced mode toggle
Additional intermediate levels (in permission checks, not in hierarchy order)
support, assistant, verified, provisional — appear in _access flags but are not part of the canonical access_level_order. Treat as internal/intermediate.
Edit Mode — Critical Rules
$ae_loc.edit_mode is a user preference, not a permission level.
Rules that must never be broken:
- Components must never write to
$ae_loc.edit_mode— only the system menu toggle and sign-out/permission-drop handlers may change it. - Edit mode is only available to
trustedand above in 95% of modules (the toggle is hidden from lower-access users). - Edit mode persists across navigation — it is NOT reset by page loads or component mounts.
- Sign-out and permission drops to below
authenticatedshould resetedit_modetofalse.
Background: A bug was fixed (2026-02-27) where
ae_comp__badge_obj_view.sveltewas writing$ae_loc.edit_mode = falsein a data-loading$effect, silently overriding the user's preference on every navigation to the badge print page.
Authentication Methods
| Method | Grants | Used For |
|---|---|---|
Site passcode (site_access_code_kv) |
trusted, public, or authenticated |
Onsite staff and event attendees |
| AE Username + Password | trusted and above |
Staff with AE accounts |
| Novi UUID | authenticated |
IDAA members (Novi membership system) |
Passcodes are stored per-level in $ae_loc.site_access_code_kv:
site_access_code_kv: {
administrator: null, // highest passcode tier
trusted: null, // onsite staff passcode
public: 'public1980', // example
authenticated: 'auth1980'
}
Utility Functions
process_permission_checks(access_type: string)
Returns a full permission object (_check and _access flags) for a given access type string. Used when access type changes to update $ae_loc.
import { process_permission_checks } from '$lib/ae_utils/ae_utils__perm_checks';
const checks = process_permission_checks('trusted');
// checks.trusted_access === true
// checks.administrator_access === false
compare_access_levels(level_a, level_b)
Returns 1 if level_a is higher, -1 if lower, 0 if equal. Useful for threshold comparisons.
Privacy and Security Rules
IDAA — International Doctors in Alcoholics Anonymous
- ALL IDAA content is private. Always. No exceptions.
- BB (Bulletin Board / Posts), Archives, Recovery Meetings — all require authentication.
- IDAA users authenticate via Novi UUID at
authenticatedlevel or higher. - A prior agent accidentally exposed IDAA BB data publicly — treat any IDAA exposure as Sev-1.
Journals
- Private personal data. Always authenticated. Passcode/encryption features exist.
- Never expose journal content publicly.
PUBLIC_AE_API_SECRET_KEY
- Audit closed 2026-03-11.
PUBLIC_*prefix is by design — key is always in the client bundle. - Anonymous site-domain lookup uses the limited-permission
PUBLIC_AE_BOOTSTRAP_KEYinstead. - Security model: API key is one layer; JWT +
x-account-idscoping provides the primary auth. - Do not introduce new usages. Prefer
PUBLIC_AE_BOOTSTRAP_KEYfor unauthenticated lookups.
Email Display
Non-trusted users must never see a full email address. Obscure using:
// joh***@example.com
function obscure_email(email: string): string {
const at = email.indexOf('@');
if (at < 0) return email;
return `${email.slice(0, Math.min(3, at))}***${email.slice(at)}`;
}
This pattern lives in ae_comp__badge_obj_li.svelte — move to ae_utils if needed elsewhere.
Module-Specific Permission Patterns
Events — Badges
| Scenario | Visibility | Print Action | Review Actions |
|---|---|---|---|
| Anonymous / below trusted | Unprinted only | None (name display only) | Email Review Link button (→ email API) |
| Trusted, not Edit Mode | Unprinted only | Clickable (first print) | Email Review Link button |
| Trusted, Edit Mode | All non-hidden | Clickable incl. reprint; shows Nx count |
Email Review Link + direct Review Link (clipboard) |
- Print count badge: shown as
Nx(e.g.2×) next to the printer icon whenprint_count >= 1 - Edit mode for badges: limited to
trusted_accessusers (toggle hidden from lower levels) person_passcodefield (for attendee-gated review URL): not yet in DB as of 2026-02-27
IDAA
- Auth gate test must be the first test in any test file — privacy enforcement is a hard requirement.
- Default required permission:
trusted_accessor higher for module access.
Common Template Patterns
<!-- Gate on trusted access -->
{#if $ae_loc.trusted_access}
<!-- Gate on edit mode (always check trusted too — edit mode alone is insufficient) -->
{#if $ae_loc.trusted_access && $ae_loc.edit_mode}
<!-- Gate on administrator -->
{#if $ae_loc.administrator_access}
<!-- Show full vs obscured email -->
{$ae_loc.trusted_access ? email : obscure_email(email)}
Never gate purely on
$ae_loc.edit_modewithout also checking a permission level. Edit mode is a UI preference, not a permission grant.