// ROOM-CONTRACT §1.1 / §6 test 1 — a captured room op replayed by ANOTHER writer must do nothing.
//
// ⛔ v1 (room.js 0.0.62) authorises an op by the identity root signed INTO its payload, so a correctly
// signed op is valid every time it appears, from anyone: re-appending a captured `add-member` re-admits a
// member a moderator removed. v2 authorises by the writer core that CARRIED the op (Keet's model), so a
// replay from any other core is ignored by construction.
import test from 'brittle'
import Corestore from 'corestore'
import fs from '#node:fs'
import os from '#node:os'
import { join } from '#node:path'
import { Room, PEER, ADMIN } from '../lib/room.js'
import { identity } from './helpers.js'
const tmp = () => fs.mkdtempSync(join(os.tmpdir(), 'favela-replay-'))
async function who () {
const id = await identity()
return { root: id.rootHex, device: await id.device() }
}
const until = async (fn, ms = 10000) => {
const end = Date.now() + ms
while (Date.now() < end) { const v = await fn(); if (v) return v; await new Promise((resolve) => setTimeout(resolve, 40)) }
return null
}
test('a captured op re-appended by another writer core is ignored (§1.1 replay)', async (t) => {
const admin = await who()
const peer = await who()
const one = new Room(new Corestore(tmp()).namespace('room'), null)
await one.ready()
await one.found(admin.device)
await one.update()
// A second node in the room as a plain member, carrying its own core.
const two = new Room(new Corestore(tmp()).namespace('room'), one.key)
await two.ready()
const s1 = one.base.replicate(true); const s2 = two.base.replicate(false)
s1.pipe(s2).pipe(s1)
t.teardown(async () => { s1.destroy(); s2.destroy(); await one.close(); await two.close() })
await admitAsPeer(t, one, two, admin, peer)
// A third identity the admin lets in, then removes — the state a replay would try to undo.
const victim = await who()
const captured = await letInThenRemove(one, admin, victim)
t.is(await one.roleOf(victim.root), null, 'precondition: the member is removed')
// The PEER's node re-appends the admin's captured op verbatim.
await two.base.append(captured, { optimistic: true })
await until(async () => { await one.update(); await two.update(); return false }, 1500)
t.is(await one.roleOf(victim.root), null, 'the replayed op did not bring the removed member back')
t.ok(await one.roleOf(admin.root) === ADMIN, 'and the admin is still the admin')
if (typeof one.invites === 'function') {
// v2: the captured op was the admin's ADMIN invitation. Replayed from the peer's core it is the peer's
// op — and its id is already taken, so it creates nothing; no invitation is ever attributed to the peer.
const invites = await one.invites()
t.absent(invites.some((i) => i.by === peer.root), 'the replay created no invitation at all')
t.ok(invites.every((i) => i.by === admin.root), 'every invitation is the admin\'s own')
}
})
// v1 and v2 admit a member differently; each branch is the documented path for its version.
async function admitAsPeer (t, one, two, admin, peer) {
if (typeof one.invite === 'function') {
const { token } = await one.invite({ role: PEER }, admin.device)
await one.update()
await until(async () => { await two.update(); return (await two.members()).length >= 1 })
await two.join(token, peer.device)
} else {
await one.addMember(peer.root, PEER, admin.device)
await one.admitDevice(peer.device, admin.device, two.base.local.key.toString('hex'))
}
t.ok(await until(async () => { await one.update(); await two.update(); return (await one.roleOf(peer.root)) === PEER }), 'the peer is in')
}
// Returns the raw bytes of the op that ADMITTED the victim, as a replayer would have captured them.
// ⛔ The OP VALUE handed to append — not `base.local.get(n)`, which is an encoded oplog node (links,
// clock) and re-appending it wraps it again, so apply cannot even parse it and the "replay" proves nothing.
async function letInThenRemove (one, admin, victim) {
const seen = []
const append = one.base.append.bind(one.base)
one.base.append = (value, opts) => { seen.push(value); return append(value, opts) }
try {
if (typeof one.invite === 'function') {
// v2 has no admin-signed admission to replay: a member is admitted by its OWN join, from its OWN
// core. The captured op is the admin's invite — replaying an admin op from a peer's core must not
// act as the admin (it would at most be the peer's own invite, capped at the peer's role).
await one.invite({ role: ADMIN }, admin.device)
await one.update()
await one.removeMember(victim.root, admin.device)
await one.update()
return seen[0]
}
await one.addMember(victim.root, PEER, admin.device)
await one.update()
await one.removeMember(victim.root, admin.device)
await one.update()
return seen[0]
} finally { one.base.append = append }
}