OverviewFilesCommitsIssuesDocsReleasesPeers

atproto-bridge / pds / test / swarm-keypair.test.js

61 lines · javascript ref:
// The membrane's PERSISTENT swarm identity (hyper-social#21 P0).
//
// The property under test is the one the P0 turned on: the Noise public key a peer would allowlist
// in PEER_WRITERS must be the SAME after a restart. The old `new Hyperswarm()` failed exactly here —
// a fresh random key per boot, so an allowlist entry authorised one boot and then silently stopped.
//
// The control (second test) is what makes the first meaningful: it demonstrates the pre-fix
// behaviour, so a regression that quietly reverts to random keys cannot pass.

import test from 'brittle'
import { mkdtempSync, rmSync, readFileSync, statSync, existsSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import b4a from 'b4a'
import Hyperswarm from 'hyperswarm'
import { loadOrCreateSwarmKeyPair } from '../lib/swarm-keypair.js'

test('swarm keypair: created once, then STABLE across restarts (the PEER_WRITERS contract)', async (t) => {
  const dir = mkdtempSync(join(tmpdir(), 'bridge-swarmkey-'))
  t.teardown(() => rmSync(dir, { recursive: true, force: true }))

  const first = loadOrCreateSwarmKeyPair(dir)
  const file = join(dir, 'swarm-keypair.json')
  t.ok(existsSync(file), 'first boot persists <storage>/swarm-keypair.json')
  t.is(first.publicKey.length, 32, 'publicKey is 32 bytes')
  t.is(first.secretKey.length, 64, 'secretKey is 64 bytes')

  // The restart. Same storage dir → the SAME key, which is the whole point.
  const second = loadOrCreateSwarmKeyPair(dir)
  t.ok(b4a.equals(first.publicKey, second.publicKey), 'RESTART: public key is unchanged')
  t.ok(b4a.equals(first.secretKey, second.secretKey), 'RESTART: secret key is unchanged')

  // It must be the key Hyperswarm actually presents to a peer — a persisted file that the swarm
  // ignores would pass every assertion above and still fail in the field.
  const swarm = new Hyperswarm({ keyPair: second })
  t.teardown(() => swarm.destroy())
  t.ok(b4a.equals(swarm.keyPair.publicKey, first.publicKey), 'the swarm presents the persisted key')

  const saved = JSON.parse(readFileSync(file, 'utf8'))
  t.is(saved.publicKey, b4a.toString(first.publicKey, 'hex'), 'file holds the hex public key an operator pastes into PEER_WRITERS')
  t.is(statSync(file).mode & 0o777, 0o600, 'secret-bearing file is 0600')

  // A different storage dir is a different membrane, not the same one.
  const other = mkdtempSync(join(tmpdir(), 'bridge-swarmkey-'))
  t.teardown(() => rmSync(other, { recursive: true, force: true }))
  t.absent(b4a.equals(loadOrCreateSwarmKeyPair(other).publicKey, first.publicKey), 'separate storage → separate identity')
})

test('control: plain `new Hyperswarm()` mints a NEW key per boot — the bug being fixed', async (t) => {
  const a = new Hyperswarm()
  const b = new Hyperswarm()
  t.teardown(async () => { await a.destroy(); await b.destroy() })
  t.absent(b4a.equals(a.keyPair.publicKey, b.keyPair.publicKey),
    'two unkeyed swarms differ — an allowlist entry would authorise exactly one boot')
})

test('storage must be a path — refuse rather than write a keypair somewhere unintended', async (t) => {
  t.exception(() => loadOrCreateSwarmKeyPair(null), /storage must be a directory path/)
  t.exception(() => loadOrCreateSwarmKeyPair({ storage: '/tmp' }), /storage must be a directory path/)
})