One pairing, many devices
+§9 proposal for Atem + Astation — same account, no repeated pairing, no forwarding through the Mac, no trust in the account login. + Full text: account-trust.md
+ +The idea
+The account keeps a small signed device list. Atem pins its start when it pairs once, then accepts exactly the devices that list names — whoever relays the traffic.
+Who holds what
+Each device keeps its own key. The relay only stores the list; signatures make it trustworthy.
++flowchart LR + subgraph ACC["Account: alice"] + direction TB + MAC["Mac Astation
device key in Secure Enclave
roles: manage · control · view"] + PHONE["iPhone Astation
own device key
roles: control · view"] + IPAD["iPad Astation
own device key
roles: view"] + end + LOG[("Membership log
1 add Mac (genesis)
2 add iPhone — signed by Mac
3 add iPad — signed by Mac")] + RELAY["Relay
routes traffic + stores the log
(untrusted)"] + subgraph HOSTS["Your machines"] + direction TB + A1["Atem on Genie
pins: account + genesis hash
+ newest seq seen"] + A2["Atem on laptop
same pin"] + end + MAC -- "appends signed entries" --> LOG + LOG --- RELAY + PHONE <-- "session channel" --> RELAY + RELAY <-- "session channel" --> A1 + IPAD <-. "direct :8080 (LAN)" .-> A2 + RELAY <--> A2 + A1 -. "verifies chain back to its pin" .-> LOG +
Adding the iPhone — once
+The approval is a signature by a trusted device after the user compares a code and authenticates. Logging in alone produces nothing Atem accepts.
++sequenceDiagram + autonumber + actor U as You + participant P as iPhone Astation + participant R as Relay + participant M as Mac Astation (manager) + participant A as Atem (any host) + U->>P: sign in to the same account + P->>P: create device key (Secure Enclave) + P->>R: "please add me" + key + short code ABCD-1234 + R->>M: pending request + M->>U: "Allow iPhone? code ABCD-1234" + U->>M: codes match → Touch ID / password + M->>M: sign entry seq 2: add iPhone, roles control+view + M->>R: append entry (relay stores, can't forge) + Note over A: no action on any Atem — it learns entry 2
the next time any device connects or it polls the head +
The iPhone connects to Atem
+Atem checks the chain from its pin, a fresh head, and that the device really holds its key — then grants exactly its roles.
+
+sequenceDiagram
+ autonumber
+ participant P as iPhone Astation
+ participant R as Relay
+ participant M as Any online manager
+ participant A as Atem
+ P->>A: hello (via relay or direct :8080)
+ A->>P: challenge nonce + Atem's newest seq (2)
+ P->>M: head attestation for nonce, please
+ M->>P: signed {seq 3, head hash, nonce, time}
+ P->>A: entries 3 + attestation + signature over (nonce, atem id, trust gen, ephemeral keys)
+ A->>A: entries chain from pinned hash? attestation by a listed manager, not older than seq 2?
+ A->>A: iPhone listed, not removed, roles control+view? signature valid?
+ A->>P: welcome — roles control+view, 24 h window starts now
+ Note over P,A: Step 2 of the proposal: both derive session keys from the ephemeral exchange
so the relay can't read terminal or chat traffic
+ Removing a device, and staying safe offline
+Removal is just another signed entry. Atem never moves backwards and never trusts a list older than 24 h.
++flowchart TD + RM["Mac: Settings → Devices → Remove Old iPad
(Touch ID)"] --> E4["entry seq 4: remove Old iPad
signed by Mac"] + E4 --> REL[("Relay stores seq 4")] + REL --> C1{"Next connection to Atem
brings entries up to the head"} + C1 -- "Atem sees seq 4" --> GONE["Old iPad refused
its live attachment is fenced"] + C1 -- "relay withholds seq 4" --> WIN{"Attestation the iPad shows
older than 24 h?"} + WIN -- "yes" --> PAUSE["refused / paused
(no fresh proof)"] + WIN -- "no" --> LATE["accepted at most until the
24 h window ends — the approved bound"] + HW["Atem keeps the highest seq it has seen
— a list older than that is always refused"] -.-> C1 + LOST["All manager devices lost?"] --> REC["local atem unpair + atem pair
→ new genesis, new trust generation
(data and keys kept)"] +