// 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/)
})