From e3ba15632f40803f715f6d15a6db3670fc8610b3 Mon Sep 17 00:00:00 2001 From: Jamie Pine Date: Tue, 2 Dec 2025 06:02:16 -0800 Subject: [PATCH] Overhaul pairing docs --- docs/core/pairing.mdx | 242 +++++++++++++++++++++++++++++++++--------- 1 file changed, 194 insertions(+), 48 deletions(-) diff --git a/docs/core/pairing.mdx b/docs/core/pairing.mdx index 34154c012..fceb5f2c0 100644 --- a/docs/core/pairing.mdx +++ b/docs/core/pairing.mdx @@ -11,19 +11,42 @@ Pairing uses a 12-word code to create a secure connection between two devices. T ### The Pairing Code -Instead of complex cryptographic hashes, Spacedrive uses BIP39 mnemonic codes: +Spacedrive uses BIP39 mnemonic codes for pairing, which come in two formats: + +#### Text Format (Local Network Only) + +A 12-word BIP39 mnemonic for manual entry: ``` -brave-lion-sunset-river-eagle-mountain-forest-ocean-thunder-crystal-diamond-phoenix +brave lion sunset river eagle mountain forest ocean thunder crystal diamond phoenix ``` -These codes are: - +This format: +- Works only on the same local network (mDNS discovery) - Easy to read and type -- Contain 128 bits of entropy +- Contains 128 bits of entropy - Valid for 5 minutes - Never reused +#### QR Code Format (Local + Internet) + +A JSON structure that enables both local and cross-network pairing: + +```json +{ + "version": 2, + "words": "brave lion sunset river eagle mountain forest ocean thunder crystal diamond phoenix", + "node_id": "6jn4e7l3pzx2kqhv..." +} +``` + +This format: +- Works across different networks and the internet +- Includes the initiator's node_id for pkarr discovery +- Enables automatic relay fallback +- Same 5-minute expiration +- Recommended for most use cases + ### Security Model The pairing protocol provides multiple security guarantees: @@ -33,6 +56,34 @@ The pairing protocol provides multiple security guarantees: **Integrity**: Challenge-response prevents tampering **Forward secrecy**: New keys for each session +## Choosing a Pairing Method + +### When to Use Text Codes + +Text-based codes are best for: +- Devices on the same local network (home, office) +- Quick pairing without scanning QR codes +- Situations where QR scanning is inconvenient + +**Limitations:** +- Only works on the same subnet +- Cannot traverse NATs or firewalls +- Requires both devices to be on the same physical or virtual network + +### When to Use QR Codes + +QR codes are recommended for: +- Pairing across different networks +- Remote device pairing over the internet +- Maximum reliability (falls back to relay if needed) +- Most production use cases + +**Benefits:** +- Works anywhere with internet connectivity +- Automatic relay fallback for NAT traversal +- Faster on local networks (dual-path discovery) +- More reliable overall + ## Pairing Process ### For the Initiator @@ -41,19 +92,27 @@ The pairing protocol provides multiple security guarantees: Call the pairing API to generate a code: ```typescript -const code = await client.action("network.pair.generate", {}); -console.log(`Share this code: ${code.code}`); +const result = await client.action("network.pair.generate", {}); + +// For local network pairing (manual entry) +console.log(`Share this code: ${result.code}`); + +// For cross-network pairing (QR code) +console.log(`QR code data: ${result.qr_json}`); +// Contains: { version: 2, words: "...", node_id: "..." } ``` - The device advertises on the network and waits for a joiner. The code expires - after 5 minutes. + The device advertises via mDNS (local) and pkarr (internet) and waits for a joiner. The code expires after 5 minutes. + + **Advertisement includes:** + - Session ID (via mDNS user_data) + - Node address published to dns.iroh.link (via pkarr) - When a joiner connects, the initiator sends a cryptographic challenge to - verify they have the correct code. + When a joiner connects, the initiator sends a cryptographic challenge to verify they have the correct code and own their device keys. @@ -65,17 +124,33 @@ After verification, both devices exchange session keys and save the pairing rela -Enter the 12-word code from the initiator: +Enter the code from the initiator (text or QR): ```typescript +// Manual entry (local network only) await client.action("network.pair.join", { - code: "brave-lion-sunset-..." + code: "brave lion sunset river eagle mountain forest ocean thunder crystal diamond phoenix" +}); + +// QR code scan (local + internet) +await client.action("network.pair.join", { + code: '{"version":2,"words":"brave lion sunset...","node_id":"..."}' +}); + +// Manual entry with node_id (enables internet pairing) +await client.action("network.pair.join", { + code: "brave lion sunset...", + node_id: "6jn4e7l3pzx2kqhv..." }); ``` - The system searches for the initiator using: - Local network discovery (mDNS) - - Internet discovery (DHT lookup) - Relay servers (if needed) + The system searches for the initiator using: + - **Local network** (mDNS) - Scans for matching session_id + - **Internet** (pkarr/DNS) - Queries dns.iroh.link for node address (requires node_id) + - **Relay servers** - Automatic fallback if direct connection fails + + With QR codes, both paths run simultaneously and the first to succeed wins. @@ -167,51 +242,90 @@ pub struct PairingSession { ## Discovery Mechanisms -Devices find each other through multiple methods: +Devices find each other through multiple methods, depending on the pairing code format: ### Local Network (mDNS) -On the same network, devices discover each other instantly: +On the same network, devices discover each other instantly using multicast DNS: ```rust -// Automatic local discovery -discovery.add_mdns(); +// Initiator broadcasts session_id via user_data +endpoint.set_user_data_for_discovery(Some(session_id)); -// Broadcasts: "I'm pairing with session X" -// Listens for: "I have session X" +// Joiner listens for matching session_id +discovery_stream.filter(|item| { + item.node_info().data.user_data() == session_id +}); ``` -### Internet (DHT) +**How it works:** +- Initiator includes session_id in mDNS broadcasts +- Joiner scans local network for matching session_id +- Typically connects in 1-3 seconds +- Only works on the same subnet -For pairing across networks, devices use a distributed hash table: +### Internet (Pkarr/DNS) + +For pairing across networks, Spacedrive uses pkarr to publish and resolve node addresses via DNS: ```rust -// Publish to DHT -let key = session_id.to_bytes(); -let record = PairingAdvertisement { - device_info, - addresses: endpoint.my_addresses(), -}; -dht.put_record(key, record); +// Automatic pkarr publishing (done by Iroh) +.add_discovery(PkarrPublisher::n0_dns()) // Publish to dns.iroh.link +.add_discovery(DnsDiscovery::n0_dns()) // Resolve from dns.iroh.link -// Query DHT -let addresses = dht.get_record(session_id).await?; +// Joiner queries by node_id +let node_addr = NodeAddr::new(node_id); // Pkarr resolves in background +endpoint.connect(node_addr, PAIRING_ALPN).await?; ``` +**How it works:** +- Initiator automatically publishes its address to `dns.iroh.link` via pkarr +- Record includes relay_url and any direct addresses +- Joiner queries `dns.iroh.link` with the node_id from QR code +- Pkarr returns all connection options (relay + direct) +- Takes 5-15 seconds including DNS resolution + + +Pkarr uses DNS-based discovery backed by the Mainline DHT. It's more reliable than traditional DHT for NAT traversal and works globally. + + +### Dual-Path Discovery + +When using QR codes (with node_id), Spacedrive races both discovery methods: + +```rust +tokio::select! { + result = try_mdns_discovery(session_id) => { + // Fast path: local network + } + result = try_relay_discovery(node_id) => { + // Reliable path: internet via pkarr + } +} +// First to succeed wins, other is canceled +``` + +This approach optimizes for speed on local networks while ensuring reliability across the internet. + ### Relay Servers -When direct connection fails, devices connect through relay servers: +When direct connection fails, devices automatically connect through relay servers: ```rust -// Automatic relay fallback -if direct_connection_failed { - connection = relay.connect(remote_id).await?; -} +// Relay mode configured at startup +.relay_mode(RelayMode::Default) // Uses n0's production relays + +// Automatic relay fallback during connection +endpoint.connect(node_addr, PAIRING_ALPN).await?; // Tries direct, then relay ``` +**Current Configuration:** +- Uses n0's default relay servers (North America, Europe, Asia-Pacific) +- Relay URLs discovered automatically via pkarr +- Custom relay support coming soon (configurable per-node) + - Relay servers only forward encrypted traffic. They cannot read your data or - compromise security. +Relay servers only forward encrypted QUIC traffic. They cannot decrypt your data or compromise security. ## Cryptographic Details @@ -250,6 +364,32 @@ let (tx_key, rx_key) = hkdf::expand( ); ``` +### Pkarr Implementation + +Spacedrive uses pkarr for decentralized node address resolution: + +```rust +// Automatic publishing (initiator) +let endpoint = Endpoint::builder() + .add_discovery(PkarrPublisher::n0_dns()) // Publishes to dns.iroh.link + .bind().await?; + +// Automatic resolution (joiner) +let endpoint = Endpoint::builder() + .add_discovery(DnsDiscovery::n0_dns()) // Resolves from dns.iroh.link + .bind().await?; + +// Discovery happens automatically during connection +endpoint.connect(NodeAddr::new(node_id), PAIRING_ALPN).await?; +``` + +**How Pkarr Works:** +- Uses DNS TXT records backed by the Mainline DHT +- Records include relay URL and direct addresses +- Automatic publishing every time the node's address changes +- TTL-based caching for performance +- No manual DHT interaction required + ### Transport Security All pairing communication uses encrypted channels: @@ -407,10 +547,12 @@ async fn test_full_pairing_flow() { ### For Users -1. **Share codes securely**: Use encrypted messaging or voice calls -2. **Complete quickly**: Codes expire in 5 minutes -3. **Verify device names**: Check the paired device is correct -4. **One code at a time**: Cancel old attempts before starting new ones +1. **Prefer QR codes**: Use QR codes for reliability across any network +2. **Share codes securely**: Use encrypted messaging or voice calls for text codes +3. **Complete quickly**: Codes expire in 5 minutes +4. **Verify device names**: Check the paired device is correct +5. **One code at a time**: Cancel old attempts before starting new ones +6. **Check network connectivity**: For cross-network pairing, ensure internet access ### For Developers @@ -431,12 +573,16 @@ Check: ### Cannot Find Device -Try: +**For text-based codes:** +- Ensure both devices are on the same local network +- Check that mDNS is not blocked by firewalls +- Text codes only work locally - use QR codes for cross-network pairing -- Ensuring both devices are online -- Checking they're on compatible networks -- Using relay servers if behind strict NATs -- Generating a fresh code +**For QR codes:** +- Ensure both devices have internet connectivity +- Check that the node_id is included in the QR code +- Verify dns.iroh.link is accessible (not blocked by corporate firewalls) +- Try generating a fresh code ### Code Invalid or Expired