3.5 KiB
Settings Tab
Nav id: settings
Icon: ⚙
What it shows
The client's security and encryption status — current encryption algorithm and KDF parameters, password change form, and a record count summary (messages, meetings, etc.).
Data flow
getEncryptionSettings(token) — GET /vip/settings/encryption?token=<token> — returns VipSettingsResponse.
Settings response object
interface VipSettingsResponse {
encryption: VipEncryptionSettings | { enabled: false }
records?: Record<string, number> // e.g. { messages: 42, meetings: 3, gifts: 1 }
}
interface VipEncryptionSettings {
enabled: true
algorithm: string // e.g. "AES-256-GCM"
kdf: string // e.g. "PBKDF2"
kdfIterations: number
keyCreatedAt: string | null
loginBenchmarkMs: number | null
}
Encryption section
Displays status badge (Active / Not set up), algorithm, KDF + iteration count, key creation date, and last-login KDF benchmark in milliseconds (useful for performance tuning).
The "Change password" / "Set up encryption" button toggles an inline form. On submit, setupPassword(token, newPw) re-derives and re-encrypts the content key server-side, returns a fresh contentKey which is written back to sessionStorage. This means the client does not get logged out when changing their password.
After a successful change, "Password updated — content key re-encrypted." confirmation text appears.
Add to another device (QR login)
A "Show login QR code" button generates a QR code (rendered client-side via qrcode to a <canvas>) encoding the full portal URL: window.location.origin + '/' + token. The client scans it with their phone's camera, which opens the portal URL directly — they then complete their normal password/WebAuthn auth on the new device.
The QR uses the gold/cream palette (#f0e6d3 dark dots on #0d0d14 background) and is hidden by default, revealed on demand, with a Hide button to dismiss it.
No server involvement — the QR is generated entirely in-browser from the token already in the component props.
Records section
If settings.records is present, renders a card listing each key/count pair. Keys are capitalized for display (messages → Messages). This gives the client a lightweight sense of how much data is in their account without exposing raw DB row counts.
WebAuthn
WebAuthn (Face ID / Touch ID) is registered during the first-visit SetPasswordScreen flow, not from the Settings tab. There is currently no UI in Settings to add or remove WebAuthn credentials after initial setup. If this is needed, it should be added here.
Dev proxy
In dev, VITE_API_URL='' makes all API calls relative. Vite proxies /vip/* to localhost:3030 but the bypass function must list every API sub-path — otherwise Vite returns the SPA HTML instead. /settings must be in apiPaths in vite.config.ts or the tab shows "Could not load settings."
Non-obvious details
setupPasswordis reused for both initial setup (first visit) and password change (Settings tab). The API determines which path to take based on whether a key already exists for the token.loginBenchmarkMsis written by the server after each successful password verification — it reflects how long PBKDF2/Argon2 derivation took on the server for that client's parameters. Useful for auditing that KDF cost is appropriate.- The
recordsfield is optional — the API may omit it if counting is expensive or not yet implemented for a given deployment.