80 lines
3.5 KiB
Markdown
80 lines
3.5 KiB
Markdown
# 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
|
|
|
|
```typescript
|
|
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
|
|
|
|
- `setupPassword` is 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.
|
|
- `loginBenchmarkMs` is 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 `records` field is optional — the API may omit it if counting is expensive or not yet implemented for a given deployment.
|