| … | … | @@ -0,0 +1,38 @@ |
| 1 | // Persistent Hyperswarm keypair for this bridge. |
| 2 | // |
| 3 | // ⛔ A BRIDGE ADDRESS IS ONLY MEANINGFUL IF IT IS STABLE. `new Hyperswarm()` mints a RANDOM keypair |
| 4 | // per boot, so the key this bridge tells peers to find it on changed on every restart. A peer that |
| 5 | // recorded it would silently stop being able to reach the bridge — and "the bridge did not answer" |
| 6 | // looks identical to "the bridge is down", which is the worst available failure mode. |
| 7 | // |
| 8 | // Measured, not assumed: booting with the swarm door wired printed a different `bridgeKey` each run. |
| 9 | // |
| 10 | // ⚠ A TRANSPORT identity, not account key material. It is a DHT/Noise identity that never signs a |
| 11 | // record, never touches a DID and grants nothing on its own; it only makes this bridge NAMEABLE so a |
| 12 | // peer can choose to ask it for something. Kept as a plain file beside the held-feed store so it |
| 13 | // survives a corestore reset. |
| 14 | // |
| 15 | // ⚠ This is the THIRD copy of this utility in the tree (hyper-proto-peer and atproto-bridge have the |
| 16 | // same one, and atproto-bridge's says so of hpp's). It stays local because there is no shared home |
| 17 | // for transport identity — favela-identity is about who someone IS, not how to reach them — and |
| 18 | // inventing one to hold thirty lines is a bigger change than the thing it would tidy. |
| 19 | |
| 20 | import fs from 'bare-fs' |
| 21 | import { dirname } from 'bare-path' |
| 22 | import b4a from 'b4a' |
| 23 | import crypto from 'hypercore-crypto' |
| 24 | |
| 25 | export function loadOrCreateSwarmKeyPair (file) { |
| 26 | try { |
| 27 | const seed = b4a.from(fs.readFileSync(file, 'utf8').trim(), 'hex') |
| 28 | if (seed.length === 32) return crypto.keyPair(seed) |
| 29 | } catch { /* first boot, or unreadable — mint below */ } |
| 30 | |
| 31 | const seed = crypto.randomBytes(32) |
| 32 | fs.mkdirSync(dirname(file), { recursive: true }) |
| 33 | // 0600: it is not account key material, but it is still this bridge's name and nobody else's. |
| 34 | fs.writeFileSync(file, b4a.toString(seed, 'hex') + '\n', { mode: 0o600 }) |
| 35 | return crypto.keyPair(seed) |
| 36 | } |
| 37 | |
| 38 | export default { loadOrCreateSwarmKeyPair } |