OverviewFilesCommitsIssuesDocsReleasesPeers

favela-web / bin / favela-pair.js

48 lines · javascript ref:
// favela-pair — mint an hpp-initiated pairing invite (the "hash URL") so a browser can sign in AS the DID
// without the backwards manual delegation shuttle. The OWNER runs this on the hpp host (having the control
// key + writer seed = proof of ownership); it connects to the hpp control surface as a writer, mints a
// blind-pairing invite whose onSubkey relays to the hpp's `delegate` RPC (the key-holder signs), and prints
// the invite. The browser pastes it into the favela login → favela-web joins the tunnel → the hpp delegates
// the browser's sub-key → session. favela stays keyless throughout.
//
// Run:  FAVELA_CONTROL_KEY=<hpp control key> FAVELA_WRITER_SEED=<seed> bare bin/favela-pair.js
import '../lib/bare-globals.js'
import process from 'bare-process'
import { Writer } from '../lib/writer.js'
import { createPairInvite } from '../lib/pairing.js'

// ⛔ NO DEFAULT. This fell back to the author's LIVE wj62 hpp control key, so running this on a box
// with no local socket dialled production over the DHT — the accident lib/writer.js:56-62 already
// records ('a post landed in wj62 from a test run'). Unset now means unreachable, which is correct.
const CONTROL = (process.env.FAVELA_CONTROL_KEY || '').trim() || null
// DEDICATED pairing writer identity — MUST differ from favela-web's poster seed
// (lib/writer.js WRITE_SEED). Both derive a Hyperswarm keypair from the seed; if they
// matched, favela-web's persistent poster and this CLI would claim the SAME swarm identity
// and collide on the DHT (the pair CLI then gets "no hpp connection"). Its pubkey
// (277037f8…) is in the hpp `writers` allowlist alongside the poster's (2c5499…).
const SEED = process.env.FAVELA_WRITER_SEED || 'favela-pair-tabertron-2026-07-16'
const EXTERNAL = (process.env.FAVELA_EXTERNAL_URL || 'https://pds.7rnx.net').replace(/\/$/, '')

const writer = new Writer({ controlKey: CONTROL, writerSeed: SEED })
console.log('[pair] connecting to the hpp control surface…')
if (!(await writer.ready({ timeout: 30000 }))) {
  console.error('[pair] no hpp connection (daemon up? control key current? writer allowlisted?)')
  process.exit(1)
}

const source = await createPairInvite({ onSubkey: (subKey) => writer.delegate(subKey) })
console.log('\n=== favela pairing invite (hpp-initiated) ===')
console.log('Paste this invite into the favela login:\n')
console.log('  ' + source.inviteHex + '\n')
console.log('or open:  ' + EXTERNAL + '/login#pair=' + source.inviteHex)
console.log('\nWaiting for your browser to pair (up to 5 min)…')
try {
  const r = await source.waitForPeer()
  console.log('[pair] ✓ delegated sub-key ' + r.subKey.slice(0, 16) + '… — your browser is now signed in as ' + r.delegation.did)
} catch (e) {
  console.error('[pair] failed:', e.message)
}
try { await source.close() } catch {}
try { await writer.close() } catch {}
process.exit(0)