OverviewFilesCommitsIssuesDocsReleasesPeers

favela-peer / test / bridge-collect.test.js

49 lines · javascript ref:
// bridge-collect.test.js — the request this node sends to collect what a bridge saw for it.
//
// ⛔ WHY A PULL AT ALL. A handset is not addressable. Measured on ap.7rnx.net: a registered peer's
// outbox hangs for the full timeout because the device holding that feed does not answer, so a bridge
// with a like to hand over has nowhere to send it. The direction has to be ours.
//
// ⚠ This daemon still learns nothing about the network — boundary.test.js is what keeps that true,
// and nothing here names one.

import test from 'brittle'
import b4a from 'b4a'
import IdentityKey from 'keet-identity-key'
import crypto from 'hypercore-crypto'
import { readAttested } from 'favela-identity/lib/attestation.js'
import { collectBytes } from 'favela-identity/lib/bridge-claim.js'
import { buildCollect } from '../lib/bridge.js'

async function identity () {
  const idk = await IdentityKey.from({ mnemonic: IdentityKey.generateMnemonic() })
  const kp = crypto.keyPair()
  const proof = await IdentityKey.bootstrap({ identity: idk.identityKeyPair }, kp.publicKey)
  return { rootHex: b4a.toString(idk.identityKeyPair.publicKey, 'hex'), cred: { keyPair: kp, proof: b4a.toString(proof, 'base64') } }
}

test('★★ what this node sends verifies as the bytes a bridge rebuilds', async (t) => {
  const me = await identity()
  const req = buildCollect({ nonce: 'n1', username: 'alice', since: 4, root: me.rootHex, cred: me.cred })

  t.is(req.username, 'alice')
  t.is(req.since, 4, 'the cursor travels, so the bridge can rebuild the same bytes')

  // This is exactly what ap-bridge's Admission does, minus the challenge it owns.
  const seen = readAttested(req.proof, collectBytes({ nonce: 'n1', username: 'alice', since: 4 }), me.rootHex)
  t.ok(seen, 'attested')
  t.is(seen.root, me.rootHex)
})

test('⛔ the cursor is inside the proof — a reply cannot be rewound in flight', async (t) => {
  const me = await identity()
  const req = buildCollect({ nonce: 'n1', username: 'alice', since: 4, root: me.rootHex, cred: me.cred })
  // Somebody rewrites `since` to 0 on the way to the bridge to rake in the whole buffer.
  t.absent(readAttested(req.proof, collectBytes({ nonce: 'n1', username: 'alice', since: 0 }), me.rootHex), 'refused')
})

test('⛔ an unlinked device is told what to do, not handed a crypto error', async (t) => {
  const me = await identity()
  t.exception(() => buildCollect({ nonce: 'n1', username: 'alice', root: null, cred: me.cred }), /link this device/)
})