OverviewFilesCommitsIssuesDocsReleasesPeers

favela-peer / test / registry-peer.test.js

170 lines · javascript ref:
// The registry at the Peer surface: ask, honour, browse, delist.

import test from 'brittle'
import fs from '#node:fs'
import os from '#node:os'
import { join } from '#node:path'
import Corestore from 'corestore'
import { RecordStore } from '../lib/record-store.js'
import { Feed } from '../lib/feed-base.js'
import { Peer } from '../lib/peer.js'
import { attest, identity } from './helpers.js'

const tmp = () => fs.mkdtempSync(join(os.tmpdir(), 'favela-reg-'))
const rec = (body) => ({ frontmatter: { createdAt: '2026-09-06T00:00:00Z' }, body })

async function mkFeed () {
  const f = new Feed(new Corestore(tmp()), null, { store: new RecordStore(tmp()), optimistic: true })
  await f.ready()
  await f.addDevice(await attest(f))
  await f.update()
  return f
}
const mkPeer = async () => new Peer(await mkFeed()).ready()

// A feed owned by a REAL identity whose device we keep, so a knock can prove it is that identity
// asking (feed.js applyKnock) and a reader can check the listed feed's founder against the root.
async function mkOwned () {
  const dev = await (await identity()).device()
  const f = new Feed(new Corestore(tmp()), null, { store: new RecordStore(tmp()), optimistic: true })
  await f.ready()
  await f.addDevice(dev.bind(f.deviceKey))
  await f.update()
  f.asOwner = (writerKeyHex) => dev.bind(writerKeyHex) // their binder
  return f
}

test('ask, honour, browse — and the knock is cleared by being honoured', async (t) => {
  const registry = await mkPeer()
  const them = await mkOwned()
  t.teardown(() => Promise.all([registry.close(), them.close()]))

  // The ask is a knock on the registry, written through the registry's writer here (no transport),
  // but PROVEN with THEIR device: the rule it exercises is the same one apply enforces.
  await registry.feed.knock(them.key, them.asOwner)
  await registry.update()
  t.is((await registry.knocks()).length, 1, 'the request is waiting')

  await registry.listFeed(them.key, rec('a feed worth reading'))
  await registry.update()

  const dir = await registry.directory()
  t.is(dir.length, 1, 'it is in the directory')
  t.is(dir[0].feed, them.key.toString('hex'))
  t.is(dir[0].record.body, 'a feed worth reading\n')
  t.alike(await registry.knocks(), [], 'and the request is cleared')
})

test('⛔ a registry cannot list a feed that never asked', async (t) => {
  const registry = await mkPeer()
  const them = await mkFeed()
  t.teardown(() => Promise.all([registry.close(), them.close()]))

  // Refused up front at the Peer surface: there is no proven knock naming that feed, so there is no
  // root to grant the listing to. (apply refuses it independently too; registry.test.js.)
  await t.exception(registry.listFeed(them.key, rec('unsolicited')), /no live, proven knock/,
    'refused, rather than appending an op apply would silently ignore')
  await registry.update()

  t.alike(await registry.directory(), [], 'consent is structural, not a convention')
})

test('subscribing to a registry surfaces its listings, without being in it', async (t) => {
  const me = await mkPeer()
  const registry = await mkPeer()
  const them = await mkOwned()
  t.teardown(() => Promise.all([me.close(), registry.close(), them.close()]))

  await registry.feed.knock(them.key, them.asOwner)
  await registry.update()
  await registry.listFeed(them.key, rec('listed'))
  await registry.update()

  await me.follow(registry.feed.key, registry.feed)
  await me.update()

  const dir = await me.directory()
  t.is(dir.length, 1, 'I can read the directory')
  t.is(dir[0].registry, registry.feed.key.toString('hex'), 'and see which registry vouched')
  t.alike(await registry.directory().then((d) => d.map((x) => x.feed)), [them.key.toString('hex')],
    '⛔ reading it did not put ME in it — subscribe and be-listed stay separate')
})

test('delisting removes it from the directory but is not a retraction', async (t) => {
  const registry = await mkPeer()
  const them = await mkOwned()
  t.teardown(() => Promise.all([registry.close(), them.close()]))

  await registry.feed.knock(them.key, them.asOwner)
  await registry.update()
  await registry.listFeed(them.key, rec('listed'))
  await registry.update()
  await registry.delist(them.key)
  await registry.update()

  t.alike(await registry.directory(), [], 'gone from the directory')
  t.is((await registry.feed.resolve('listing', them.key.toString('hex'))).status, 'deleted',
    'as a tombstone — anyone who already replicated it still has it')
})

test('the same feed listed by two registries is two endorsements, not one', async (t) => {
  const me = await mkPeer()
  const r1 = await mkPeer()
  const r2 = await mkPeer()
  const them = await mkOwned()
  t.teardown(() => Promise.all([me.close(), r1.close(), r2.close(), them.close()]))

  for (const r of [r1, r2]) {
    await r.feed.knock(them.key, them.asOwner)
    await r.update()
    await r.listFeed(them.key, rec('listed'))
    await r.update()
  }
  await me.follow(r1.feed.key, r1.feed)
  await me.follow(r2.feed.key, r2.feed)
  await me.update()

  const dir = await me.directory()
  t.is(dir.length, 2, 'both kept — collapsing them would throw away who vouched')
  t.alike(new Set(dir.map((x) => x.feed)).size, 1, 'for one feed')
})

// ⛔⛔ THE READER'S HALF OF CONSENT (hyper-social #77). Apply can prove WHICH identity knocked, but it
// cannot read the listed feed, so it cannot prove that identity OWNS the feed it named. A reader that
// holds the feed can: its founder root must equal the root the listing was granted to.
test('⛔ a listing is verified against the listed feed\'s founder, and a spoofer\'s fails', async (t) => {
  const me = await mkPeer()
  const registry = await mkPeer()
  const them = await mkOwned()
  const spoofer = await mkOwned() // a real identity, asking about a feed that is NOT its own
  t.teardown(() => Promise.all([me.close(), registry.close(), them.close(), spoofer.close()]))

  // The genuine ask: their identity, naming their feed.
  await registry.feed.knock(them.key, them.asOwner)
  await registry.update()
  await registry.listFeed(them.key, rec('genuine'))
  await registry.update()

  await me.follow(registry.feed.key, registry.feed)
  await me.follow(them.key, them) // I hold their feed, so I can check its founder
  await me.update()
  let dir = await me.directory()
  t.is(dir.length, 1)
  t.is(dir[0].verified, true, 'their identity knocked, and their feed\'s founder is that identity')

  // The spoof: a different identity knocks NAMING their feed, and a careless registry lists it.
  const victim = await mkOwned()
  t.teardown(() => victim.close())
  await registry.feed.knock(victim.key, spoofer.asOwner)
  await registry.update()
  await registry.listFeed(victim.key, rec('spoofed'))
  await registry.update()
  await me.follow(victim.key, victim)
  await me.update()

  dir = await me.directory()
  const spoofed = dir.find((d) => d.feed === victim.key.toString('hex'))
  t.ok(spoofed, 'apply let it through: it cannot read the victim\'s feed')
  t.is(spoofed.verified, false, '⛔ but a reader holding the feed sees its founder is NOT the identity that asked')
})