// node --test web/fedproxy-ssh-public-keys/fedproxy-cubit.test.mjs (after `cargo wasm`) // The cubit with the real fedproxy module and runModule; only OAuth and the PDS are stubbed. import assert from "node:assert/strict"; import { registerHooks } from "node:module"; import { test } from "node:test"; import { load } from "../../../atlibs/rust/src/harness.mjs"; // The page resolves atlibs/ through its import map; Node gets the same mapping here. registerHooks({ resolve(specifier, context, next) { const lib = specifier.startsWith("atlibs/") && new URL(`../../../atlibs/javascript/src/${specifier.slice("atlibs/".length)}`, import.meta.url).href; return next(lib || specifier, context); }, }); const { FedproxyCubit } = await import("./fedproxy-cubit.js"); const { run } = await load(new URL("../../target/wasm32-unknown-unknown/release/fedproxy.wasm", import.meta.url)); const did = "did:plc:lpfuqerea3deuoyrn7ojser4"; const handle = "alice.bsky.social"; const key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG9BVPpCtKTckpQVk4etPSsC65Vo91Ie0kpjJH6PSdow laptop"; // A PDS holding com.fedproxy.sshPublicKey records, answering the calls the module plans. function pds(records = []) { const calls = []; const agent = { did, com: { atproto: { server: { getSession: async () => ({ success: true, data: { handle } }) } } }, async call(nsid, params, input) { calls.push(nsid); if (nsid === "com.atproto.repo.listRecords") return { data: { records } }; if (nsid === "com.atproto.repo.createRecord") { const uri = `at://${did}/com.fedproxy.sshPublicKey/${records.length}`; records.push({ uri, value: input.record }); return { data: { uri, cid: "bafy" } }; } throw new Error(`unexpected ${nsid}`); }, }; return { agent, calls, records }; } function cubitWith({ session = { sub: did }, agent } = {}) { const revoked = []; const client = Promise.resolve({ init: async () => (session ? { session } : undefined), signIn: async () => { throw new Error("popup blocked"); }, revoke: async (sub) => revoked.push(sub), }); const cubit = new FedproxyCubit({ client, makeAgent: () => agent, module: Promise.resolve({ module: new Uint8Array(), calls: ["com.atproto.repo.listRecords", "com.atproto.repo.createRecord"] }), ctx: { wasm: { run: async ({ entry, input }) => run(entry, input) } }, }); const states = []; cubit.subscribe((state) => states.push(state)); return { cubit, states, revoked }; } const summary = (s) => `${s.session} keys:${s.keys.status} create:${s.create.status}`; test("init without a session shows sign-in", async () => { const { cubit, states } = cubitWith({ session: null }); await cubit.init(); assert.deepEqual(states.map(summary), ["loading keys:idle create:idle", "signed-out keys:idle create:idle"]); }); test("init restores the session and lists keys grouped by service", async () => { const { agent } = pds([{ uri: `at://${did}/com.fedproxy.sshPublicKey/1`, value: { service: "app", name: "laptop", key } }]); const { cubit, states } = cubitWith({ agent }); await cubit.init(); assert.deepEqual(states.map(summary), [ "loading keys:idle create:idle", "signed-in keys:idle create:idle", "signed-in keys:loading create:idle", "signed-in keys:loaded create:idle", ]); assert.equal(cubit.state.handle, handle); const [service] = cubit.state.keys.services; assert.equal(service.host, "app--alice-bsky-social.fedproxy.com"); assert.match(service.command, /-R app:80:127\.0\.0\.1:8080/); }); test("a rejected key reports the module's message and writes nothing", async () => { const { agent, calls } = pds(); const { cubit, states } = cubitWith({ agent }); await cubit.init(); states.length = 0; await cubit.createKey({ name: "laptop", service: "app", key: "not a key" }); assert.deepEqual(states.map((s) => s.create.status), ["busy", "error"]); assert.match(cubit.state.create.error, /^key must be an OpenSSH public key/); assert.ok(!calls.includes("com.atproto.repo.createRecord")); }); test("creating a key writes it, relists, then reports done with its uri", async () => { const { agent, records } = pds(); const { cubit, states } = cubitWith({ agent }); await cubit.init(); states.length = 0; await cubit.createKey({ name: "laptop", service: "*.app", key }); assert.deepEqual(states.map((s) => `${s.keys.status}/${s.create.status}`), ["loaded/busy", "loading/busy", "loaded/busy", "loaded/done"]); assert.equal(records.length, 1); assert.equal(records[0].value.service, "*.app"); assert.equal(cubit.state.create.uri, `at://${did}/com.fedproxy.sshPublicKey/0`); assert.equal(cubit.state.keys.services[0].host, "*.app--alice-bsky-social.fedproxy.com"); }); test("login failure is shown; logout revokes and resets", async () => { const { agent } = pds(); const { cubit, revoked } = cubitWith({ agent }); await cubit.init(); await cubit.login("alice.bsky.social"); assert.deepEqual(cubit.state.login, { busy: false, error: "Login error: popup blocked" }); await cubit.logout(); assert.deepEqual(revoked, [did]); assert.equal(summary(cubit.state), "signed-out keys:idle create:idle"); });