Per-device tokens with revocation (issue #11)
Auth previously used the shared IRIS_TOKEN as the security principal: a leaked token meant access to all devices, and a compromised device could not be isolated. Gateway: - pairing.py: devices.token column (in-place migration) + revoked denylist table; issue_token (idempotent, 64 hex), token_for, reissue_token, revoke/unrevoke/is_revoked/list_revoked. The token never leaks into device dicts (push fan-out / listings). - http_server.py: auth accepts the shared token (bootstrap/legacy) OR the device's own token (both constant-time); a revoked device_id is rejected with 401 before either comparison. On SSE open (pairing) the per-device token is minted and returned in hello.ack. - protocol.py: hello_ack(..., device_token). - adapter.py: setup flow (hermes gateway setup -> Iris) now offers 'Remove a paired device?' on an existing setup: numbered select menu (last option = exit the removal loop), confirmation, back to the menu for further removals. - tools/iris_devices.py: operator CLI (list / revoke / unrevoke / reissue), stdlib only. App: - SecureStore.deviceToken (Android: EncryptedSharedPreferences; Desktop: second keyring slot iris-device-token / device_token.enc). - HelloAckPayload.deviceToken; GatewayClient stores it on hello and presents it instead of the shared token from then on (live provider in HttpGateway); savePairing/clear wipe it for re-pairing. Docs: 09 §9.3 stretch -> implemented (revocation semantics, both control surfaces), 04 hello.ack example, frames.schema.json, M7 row 13. Tests: 8 new Python tests (issuance, acceptance, revocation, isolation, unrevoke, registry unit x2, setup-flow menu) - 94/94 pass; 2 new Kotlin wire tests - green. Live-verified against a running gateway (hello.ack token matches devices.db; revoke -> 401 even with shared token; unrevoke -> 200; setup TUI both paths).
This commit is contained in:
1 parent
746d809d48
commit
7faaf2aa1c
23 files changed
+837
-66
No files matched your search
+4
-4
@@ -40,7 +40,7 @@ Everything in the feature checklist below.
|
||||
## Feature checklist → where it's handled
|
||||
|
||||
| Requirement | Gateway plugin | App |
|
||||
|---|---|---|
|
||||
| --- | --- | --- |
|
||||
| Input box, auto-grow (max height) | — | Compose `TextField` + bounded `heightIn` |
|
||||
| Menu button → all slash commands | Dispatches `/…`; serves command catalog | Bottom-sheet menu + `/` autocomplete |
|
||||
| Tool output (app decides how much) | Emits **structured** tool events | App setting: everything / truncated / nothing |
|
||||
@@ -55,7 +55,7 @@ Everything in the feature checklist below.
|
||||
## Locked decisions (from planning)
|
||||
|
||||
| Decision | Choice |
|
||||
|---|---|
|
||||
| --- | --- |
|
||||
| Desktop app tech | **Compose Multiplatform** (shares Android code; "tweaked" for big screen) |
|
||||
| Push backend | **Both** — ntfy default, FCM optional (`IRIS_PUSH_BACKEND`) |
|
||||
| Media transport | **Over the WebSocket** (chunked binary frames; no extra Python deps) |
|
||||
@@ -74,7 +74,7 @@ Everything in the feature checklist below.
|
||||
## Verified environment state (2026-08-19)
|
||||
|
||||
| Item | State |
|
||||
|---|---|
|
||||
| --- | --- |
|
||||
| OS | CachyOS (Arch-based), `pacman` present |
|
||||
| JDK | **Not installed** → Milestone M0 (`pacman -S jdk17-openjdk`) |
|
||||
| Android SDK | **Not installed** → M0 (cmdline-tools + sdkmanager) |
|
||||
@@ -90,4 +90,4 @@ Everything in the feature checklist below.
|
||||
- Product/effort name: **Iris × Hermes** (folder `iris_x_hermes`).
|
||||
- hermes platform name: **`iris`** (the plugin registers `Platform("iris")`).
|
||||
- WS default port: **8790** (configurable).
|
||||
- Default chat id: **`default`** (the home channel).
|
||||
- Default chat id: **`default`** (the home channel).
|
||||
Reference in new issue
Block a user