// observer-grant.test.js — the bridge tells a peer which observation feed is theirs and who founded it, signed
// with the bridge's own swarm key (hyper-social #82, I1 S3, operator decision O-2 option b).
//
// ⛔ WHY SIGNED. The peer trusts the observer root it is handed only because it arrives signed by the bridge key it
// chose to claim against. A grant that could be forged, or lifted from one user and replayed to another, would let
// anyone point a node at a feed of their choosing and have it rendered as that user's notifications.
import test from 'brittle'
import b4a from 'b4a'
import crypto from 'hypercore-crypto'
import { observerBytes, signObserver, verifyObserver, OBSERVER } from '../lib/observer-grant.js'
const G = { username: 'fleeky', generation: 1, observationFeed: 'f6'.repeat(32), observerRoot: 'e4'.repeat(32) }
test('the exact bytes, pinned — a drift on either side fails here, with a readable diff', (t) => {
t.is(OBSERVER, 'favela-bridge:v1:observer')
t.is(b4a.toString(observerBytes(G)), 'favela-bridge:v1:observer:fleeky:1:' + 'f6'.repeat(32) + ':' + 'e4'.repeat(32))
t.is(b4a.toString(observerBytes({ ...G, generation: '1' })), b4a.toString(observerBytes(G)), 'the generation is normalised')
})
test('★ signed with the bridge key, verified against the bridge key the peer claimed with', (t) => {
const bridge = crypto.keyPair()
const sig = signObserver(G, bridge)
t.ok(/^[0-9a-f]{128}$/.test(sig), 'a hex signature')
t.is(verifyObserver(G, sig, b4a.toString(bridge.publicKey, 'hex')), true)
})
test('⛔ another key, another user, another generation, another feed or root: refused', (t) => {
const bridge = crypto.keyPair()
const sig = signObserver(G, bridge)
const pub = b4a.toString(bridge.publicKey, 'hex')
t.is(verifyObserver(G, sig, b4a.toString(crypto.keyPair().publicKey, 'hex')), false, 'a different bridge')
t.is(verifyObserver({ ...G, username: 'ashatron' }, sig, pub), false, 'replayed to another user')
t.is(verifyObserver({ ...G, generation: 2 }, sig, pub), false, 'replayed to a re-claimed name')
t.is(verifyObserver({ ...G, observationFeed: 'aa'.repeat(32) }, sig, pub), false, 'pointed at another feed')
t.is(verifyObserver({ ...G, observerRoot: 'bb'.repeat(32) }, sig, pub), false, 'claimed another founder')
t.is(verifyObserver(G, 'zz', pub), false, 'junk signature')
t.is(verifyObserver(G, sig, 'nope'), false, 'junk key')
})