| … | … | @@ -19,7 +19,7 @@ import pathm from 'bare-path' |
| 19 | 19 | import { keyFromPrivate } from 'atproto-identity/lib/atproto-identity.js' |
| 20 | 20 | import { signAssertion } from 'atproto-identity/lib/auth.js' |
| 21 | 21 | import { makeAtprotoWebVerify, verifyChallengeSig } from 'atproto-identity/lib/web-auth.js' |
| 22 | | import { loadOrCreateSubKey, signChallenge, tokenFromSetCookie, establishSession, mintSubKey } from '../lib/session.js' |
| 22 | import { loadOrCreateSubKey, signChallenge, tokenFromSetCookie, establishSession, mintSubKey, sessionNodeOf } from '../lib/session.js' |
| 23 | 23 | |
| 24 | 24 | const assert = (c, m) => { if (!c) { console.error('FAIL:', m); process.exit(1) } console.log(' ok -', m) } |
| 25 | 25 | const toHex = (b) => Array.from(b).map((x) => x.toString(16).padStart(2, '0')).join('') |
| … | … | @@ -136,4 +136,27 @@ for (const [args, why] of [ |
| 136 | 136 | assert(e !== null, 'refuses without ' + why) |
| 137 | 137 | } |
| 138 | 138 | |
| 139 | // ── 7. the SHAPE hpp actually hands us ────────────────────────────────────────────────────────────── |
| 140 | // THE BUG THIS EXISTS FOR (found on a handset, 2026-08-11): every fixture above is a hand-written object |
| 141 | // with a delegate() on it, so the suite only ever proved establishSession against a node shaped the way |
| 142 | // the test author imagined. hpp does not hand us that. `bootSwarmDevice` returns a WRAPPER — |
| 143 | // { device, sb, did, self, blobs, control, … } (hyper-proto-peer/lib/device-node.js:595) — and delegate() |
| 144 | // lives on the SwarmDevice INSIDE it (swarm-device.js:699). The wrapper carries `.did`, so it passes a |
| 145 | // casual "looks like a node" reading and then trips the delegate() guard at runtime, on the phone, with |
| 146 | // the UI silently downgraded to anonymous. A mock that cannot reproduce the caller's shape cannot catch |
| 147 | // a caller-shape bug, so this asserts the REAL shape. |
| 148 | console.log('hpp wrapper shape') |
| 149 | const wrapper = { did: DID, device: fakeNode, sb: {}, blobs: {}, control: null } // as device-node.js:595 returns |
| 150 | assert(typeof wrapper.delegate !== 'function', 'the wrapper itself has NO delegate — this is the bug') |
| 151 | assert(sessionNodeOf(wrapper) === fakeNode, 'unwraps the SwarmDevice out of the hpp wrapper') |
| 152 | assert(sessionNodeOf(fakeNode) === fakeNode, 'passes a bare SwarmDevice through unchanged') |
| 153 | assert(sessionNodeOf(null) === null, 'null in, null out') |
| 154 | assert(sessionNodeOf({ did: DID, sb: {} }) === null, 'an entry with no delegate anywhere is refused, not guessed at') |
| 155 | |
| 156 | // and end-to-end: the wrapper, unwrapped, signs in for real |
| 157 | const wrapped = await establishSession({ |
| 158 | favelaUrl: 'http://127.0.0.1:4041', node: sessionNodeOf(wrapper), privHex: k1.privHex, pubHex: k1.pubHex, fetchImpl: fakeFetch |
| 159 | }) |
| 160 | assert(wrapped.token && wrapped.did === DID, 'a session is established from the shape hpp really returns') |
| 161 | |
| 139 | 162 | console.log('\nall session tests passed') |