OverviewFilesCommitsIssuesDocsReleasesPeers

favela-identity / test / observer-grant.test.js

40 lines · javascript ref:
// 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')
})