improve PEER_AUTH_PLAN.md and re-organize files
This commit is contained in:
@@ -1,66 +0,0 @@
|
||||
# Streamed Install Next Steps
|
||||
|
||||
I’d treat the prototype as proof of the hard part: “can we stream
|
||||
archive-derived install bytes into `local/` without making the receiver a
|
||||
source?” Yes. Next I’d harden the pieces that decide whether this is
|
||||
product-ready.
|
||||
|
||||
1. **Done — Move from CLI-only to real app integration**
|
||||
|
||||
The GUI now has an explicit “Low disk install” action in the game detail
|
||||
modal for remote-only games. The Tauri backend queues that path through
|
||||
`stream_install_game`, injects the shared external `unrar` stream provider,
|
||||
and hands fetched file details to `StreamInstallGame` instead of the normal
|
||||
download command.
|
||||
|
||||
2. **Done — Replace per-file `unrar p` with a final archive provider**
|
||||
|
||||
The shared external `unrar` stream provider now runs `unrar lt` once for the
|
||||
archive metadata and one sequential `unrar p` pass per archive for payload
|
||||
bytes. It frames directories, file starts, file chunks, and file ends from
|
||||
the technical listing, so CLI and GUI callers use one purpose-built provider
|
||||
instead of a per-file extraction loop.
|
||||
|
||||
3. **Done — Handle solid archives deliberately**
|
||||
|
||||
The provider exposes the RAR `solid` flag in `ArchiveBegin` and always uses
|
||||
one sequential payload pass per archive, which is the safe path for solid
|
||||
archives. S41 now verifies a real solid RAR fixture through the Docker
|
||||
peer-cli flow, including local-only final state, absent root archive/sentinel,
|
||||
byte count, and extracted payload SHA-256 hashes.
|
||||
|
||||
4. **Done — Decide the integrity model**
|
||||
|
||||
Streamed installs intentionally verify against sender archive metadata for
|
||||
now: each file must match the RAR-advertised size and CRC32. That catches
|
||||
transport corruption, truncation, and provider bugs, but does not claim
|
||||
malicious-peer protection. Trusted content remains a separate catalog schema
|
||||
step: add catalog-owned archive or extracted-file SHA-256 hashes, then verify
|
||||
those at the receiver before commit.
|
||||
|
||||
5. **Done — Upgrade retry/resume semantics**
|
||||
|
||||
Streamed install attempts now use the same majority-validated peer set as
|
||||
normal downloads, and each failed attempt rolls back its staging transaction
|
||||
before trying the next peer. S42 pins the policy: retry the whole stream from
|
||||
another validated peer, keep no partial files across attempts, and do not add
|
||||
byte-offset resume until there is a strong reason.
|
||||
|
||||
6. **Done — Expand scenario coverage**
|
||||
|
||||
S43-S47 cover the remaining streamed-install edges: already-installed
|
||||
rejection, corrupt archive rollback, sender disconnect mid-stream, receiver
|
||||
cancel mid-stream, and multi-archive `.eti` roots streamed in sorted order.
|
||||
The peer-cli harness now exposes `cancel-download` so cancellation scenarios
|
||||
exercise the same runtime path as the GUI.
|
||||
|
||||
7. **Done — Clean product semantics**
|
||||
|
||||
The UI now keeps streamed installs in the installed visual state while making
|
||||
the sharing limitation explicit: cards show `Not shareable`, and the detail
|
||||
modal status shows `Installed, not shareable`. Downloaded-and-installed games
|
||||
keep the normal `Installed` label.
|
||||
|
||||
The remaining production-readiness step is additive: move from sender-owned RAR
|
||||
metadata to catalog-owned archive or extracted-file hashes, then verify those
|
||||
at the receiver before committing the streamed install.
|
||||
@@ -34,7 +34,7 @@ not three partially compatible protocol generations.
|
||||
| Content authority | Ship BLAKE3 file and chunk hashes from the same bundled catalog authority as `game.db`. | Every eligible nearby peer is usable automatically; wrong bytes are rejected and retried elsewhere. |
|
||||
| Peer identity | Use one installation-local TLS key and derive `PeerId` from that TLS public key. | Identity works silently and survives ordinary restarts when possible; users do not manage it. |
|
||||
| Transport | Pin every outbound QUIC connection to the expected `PeerId`. | An address spoof or MITM cannot impersonate the peer selected as a source. |
|
||||
| Control messages | Use ordinary bounded protocol messages inside TLS. Treat unauthenticated inbound change notifications only as hints that trigger a pinned pull. | No signed-envelope layer, nonce ledger, or message-signing overhead. |
|
||||
| Control messages | Use ordinary bounded protocol messages inside TLS. Treat unauthenticated inbound change notifications only as hints that trigger a pinned pull, and carry current revisions on the liveness ping that already runs so a lost hint self-heals. | No signed-envelope layer, nonce ledger, or message-signing overhead. |
|
||||
| Call to Play | Exchange only each peer's own session state by direct pinned pulls; do not relay third-party histories. | Calls are live LAN-party state and disappear naturally as their authors leave. |
|
||||
| Privacy | Provide one global Local network sharing switch. | Participation is easy to understand; no per-peer policy matrix. |
|
||||
| Protocol rollout | Make one cutover to the new current protocol. | Mixed versions are explained clearly, without maintaining legacy paths. |
|
||||
@@ -50,6 +50,9 @@ bundled content manifest -> validated local download plan
|
||||
|
||||
local Call to Play change -> cheap invalidation hint to known peers
|
||||
-> each peer pulls the author's current state over pinned TLS
|
||||
|
||||
pinned liveness ping -> responder's own current revisions
|
||||
-> pull that one responder only on mismatch
|
||||
```
|
||||
|
||||
## 2. Threat model and guarantees
|
||||
@@ -316,6 +319,31 @@ This extra pull is one small LAN round trip and removes general signed
|
||||
envelopes, canonical opaque payloads, nonce caches, replay semantics, inbound
|
||||
client-certificate plumbing, and connect-back authority state.
|
||||
|
||||
Hints are a latency optimization, never a correctness requirement. The liveness
|
||||
ping that already runs is the reconciliation channel: `Pong` carries the
|
||||
responder's own `(runtime_session_id, library_revision, call_to_play_revision)`.
|
||||
The initiator compares them against what it has cached for that endpoint
|
||||
generation and, on any mismatch or a new session ID, schedules exactly the
|
||||
coalesced pinned pull a hint would have scheduled. A hint that was dropped,
|
||||
never sent, or discarded by rate limiting therefore converges within one ping
|
||||
interval, with no new timer, no mDNS payload growth, and no periodic full-state
|
||||
polling.
|
||||
|
||||
Freshness for that check must be measured from the local peer's own last pinned
|
||||
exchange with the remote peer, never from inbound activity. The current
|
||||
`ping_idle_peers` skips any peer whose `last_seen` was refreshed by traffic
|
||||
arriving from it (`update_last_seen_by_addr`), so a peer that keeps talking to
|
||||
us would suppress the very check that detects our staleness about it. Track the
|
||||
last completed outbound pinned exchange separately from `last_seen`, which
|
||||
continues to serve stale-peer pruning. Inbound traffic is not evidence of
|
||||
freshness, for the same reason it is not evidence of identity.
|
||||
|
||||
Revisions on `Pong` are a staleness signal, not content authority; the pull
|
||||
remains the authoritative step. A responder that inflates its revision only
|
||||
causes pulls of its own state, bounded by the same coalescing and rate limits. A
|
||||
responder that understates it leaves the initiator stale about that responder
|
||||
alone, which it could already achieve by changing nothing.
|
||||
|
||||
An unproven address collision never evicts an authenticated peer. If a pinned
|
||||
dial later proves that a different ID now owns the same address, atomically
|
||||
replace address ownership and retire the old record only if it still names
|
||||
@@ -437,9 +465,9 @@ The cutover includes:
|
||||
- version-bound ALPN and per-installation server certificates instead of the
|
||||
repository-wide `cert.pem`/`key.pem`;
|
||||
- mDNS candidate-only semantics and useful incompatible-version telemetry;
|
||||
- responder-owned pull snapshots plus bounded change hints instead of inbound
|
||||
state-bearing `Hello`, pushed `LibraryDelta`, and pushed/relayed
|
||||
`CallToPlayEvents`;
|
||||
- responder-owned pull snapshots, revision-bearing `Pong`, and bounded change
|
||||
hints instead of inbound state-bearing `Hello`, pushed `LibraryDelta`, and
|
||||
pushed/relayed `CallToPlayEvents`;
|
||||
- cryptographic `content_id` in game availability and catalog-driven chunk
|
||||
requests;
|
||||
- canonical forward-slash catalog paths;
|
||||
@@ -462,7 +490,7 @@ real reusable boundary; a new identity crate is not required by the design.
|
||||
| `lanspread-proto` | `PeerId`, `PeerEndpoint`, `content_id`, pull snapshots, change hints, author-owned Call-to-Play wire types, and the one protocol version. No crypto or storage logic. |
|
||||
| `lanspread-peer::identity` | Simple key/certificate load-or-generate, SPKI-derived ID, and test identity injection. |
|
||||
| `lanspread-peer::network` | Per-endpoint rustls client config, full responder verification, ALPN, and no address-only connect. |
|
||||
| discovery/handshake/liveness | Candidate-only mDNS, pinned pulls, hint coalescing, endpoint generations, and version-mismatch reporting. |
|
||||
| discovery/handshake/liveness | Candidate-only mDNS, pinned pulls, hint coalescing, revision reconciliation on ping, endpoint generations, and version-mismatch reporting. |
|
||||
| `peer_db` | Authenticated endpoint/state records and exact `content_id` source lookup. |
|
||||
| download/storage/stream install | Validated catalog plan, hash-as-received, source quarantine/retry, sentinel commit, and protected staging. |
|
||||
| `call_to_play` | Local author slice, per-peer replacement snapshots, simple authority checks, timers, and bounds. |
|
||||
@@ -529,6 +557,9 @@ This phase is not complete until:
|
||||
CLI dial rejects the wrong key at the expected address;
|
||||
- a forged mDNS record or inbound hint cannot create/rebind/remove peer state,
|
||||
inject a library/Call-to-Play update, or bypass a pinned pull;
|
||||
- a change hint that is dropped, never sent, or rate-limited away still
|
||||
converges within one ping interval, and inbound traffic from a peer does not
|
||||
defer that peer's revision check;
|
||||
- an honest multi-source download swarms automatically and commits only the
|
||||
catalog bytes;
|
||||
- one bad source is quarantined and another source completes the chunk;
|
||||
Reference in New Issue
Block a user