Files
OSIT-AE-App-Svelte/documentation/AE__Permissions_and_Security.md
Scott Idem f6344008ea security: use bootstrap key in manifest, add .tmp cache cleanup
- 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>
2026-03-11 10:54:17 -04:00

7.2 KiB
Raw Blame History

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: public is a site-wide unlock (anyone with the passcode). authenticated verifies 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:

  1. Components must never write to $ae_loc.edit_mode — only the system menu toggle and sign-out/permission-drop handlers may change it.
  2. Edit mode is only available to trusted and above in 95% of modules (the toggle is hidden from lower-access users).
  3. Edit mode persists across navigation — it is NOT reset by page loads or component mounts.
  4. Sign-out and permission drops to below authenticated should reset edit_mode to false.

Background: A bug was fixed (2026-02-27) where ae_comp__badge_obj_view.svelte was writing $ae_loc.edit_mode = false in 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 authenticated level 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_KEY instead.
  • Security model: API key is one layer; JWT + x-account-id scoping provides the primary auth.
  • Do not introduce new usages. Prefer PUBLIC_AE_BOOTSTRAP_KEY for 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 when print_count >= 1
  • Edit mode for badges: limited to trusted_access users (toggle hidden from lower levels)
  • person_passcode field (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_access or 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_mode without also checking a permission level. Edit mode is a UI preference, not a permission grant.