feat: implement QR-to-login and unified logout#40
Conversation
Design proposal: air-gapped QR signing (phone = signer)
This inverts the trust direction of the current PR. Current PR vs. proposal
Why not the alternatives (security rationale)
FlowsA) Skill / NFT purchase (signature is public — no return-QR needed)
B) Login / session decrypt (signature is secret — air-gap return)
Desktop QR read — the hard part (already verified)Instead of fighting the webview camera sandbox, the extension host (Node) spawns a native scanner and returns the decoded string to the webview via Verified on macOS (real command output):
Scanner requirements:
QR payload formats (draft)
Code changes (same branch — this is a model swap, not an add-on)
Open questions for review
Verification status (honest)
|
Visual addendum to the air-gapped QR-signing proposal above — same content, just drawn out. 1. Trust direction: current PR (key handover) vs proposal (signing channel) flowchart LR
subgraph CURR["Current PR — key handover"]
direction TB
D1["Desktop holds key"] -->|"hands secret payload (one-shot)"| P1["Phone ends up with key material"]
P1 -.->|"leaked QR / deeplink"| X1["⚠️ full wallet compromise"]
end
subgraph PROP["Proposal — air-gapped signing channel"]
direction TB
P2["Phone holds key · signer"] -->|"returns signature only (nonce-bound, single-use)"| D2["Desktop verifies"]
D2 -.->|"key never copied"| OK["✅ air-gapped"]
end
CURR ==>|"trust direction inverted"| PROP
2. Flow A — Skill / NFT purchase (signature is public → no return-QR needed) sequenceDiagram
participant D as Desktop
participant P as Phone
participant C as Solana RPC
Note over P: holds the key (signer)
D->>D: build unsigned tx
D->>P: render QR — agentnet://sign type=tx
Note over P: user approves "buy X"
P->>P: sign tx locally
P->>C: submit signed tx (phone's own internet)
D->>C: watch chain for confirmation
C-->>D: confirmed
D->>D: install skill
Note over D,P: signature is PUBLIC → no return-QR needed
3. Flow B — Login / session decrypt (signature is secret → air-gap return) sequenceDiagram
participant D as Desktop
participant Cam as Desktop Camera
participant P as Phone
Note over P: holds the key (signer)
D->>P: show nonce / challenge QR
P->>P: sign fixed message
Note over P: signature = SECRET<br/>derives AES-GCM key for shared memory
P-->>Cam: display signature as QR (photons only)
Cam->>D: decoded string via postMessage
D->>D: verify ed25519, derive key, decrypt memory
Note over D,P: signature is SECRET → never networked, never published
On open question #1 (cross-platform decode): macOS = Vision; for Linux/Windows, zbar as the fallback looks lighter to bundle than a wasm decoder. |
Implements signature-based login using a shared WalletTransport interface and a WalletConnect v2 implementation, conforming CLI, VSCode, Web, and Android surfaces to this seam. Also unifies the logout policy to support soft logout by default and full logout via --full.