~ knotless Search/
↑↓ move↵ open⇧↵ all results

johnandersen777.bsky.social/atlibs

0
0
main
106 lines · 8.6 KB Raw History
// node --test examples/node-hono/test.mjs   (needs `npm install` here, `cargo wasm`, `cargo host`; skips without hono)
import assert from "node:assert/strict";
import { mkdtemp } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { test } from "node:test";

import { atlibs, scopeFixture } from "../../rust/host/conformance.mjs";
import { contextOptions, createNodeContext } from "../../javascript/src/server/index.js";

const hono = await import("hono").catch(() => null);

test("a Hono app mounts clientMetadataHandler and runs a staged module", { skip: !hono && "npm install in examples/node-hono" }, async () => {
	const { createApp } = await import("./server.mjs");
	const dir = await mkdtemp(join(tmpdir(), "atlibs-hono-"));
	await atlibs(["stage", "--target", "server", "--out", dir, "compose", "vibescrobble"]);
	const ctx = createNodeContext(contextOptions(join(dir, "state")));
	const app = await createApp(join(dir, "stage.json"), { ctx, call: async () => ({}), origin: "https://site.example" });
	try {
		const doc = await (await app.fetch(new Request("https://site.example/oauth/vibescrobble/client-metadata.json"))).json();
		assert.equal(doc.client_id, "https://site.example/oauth/vibescrobble/client-metadata.json");
		assert.equal((await app.fetch(new Request("https://site.example/oauth/nope/client-metadata.json"))).status, 404);
		const body = JSON.stringify({ call: { input: { n: 4 } } });
		const run = (url, headers = {}) => app.fetch(new Request(url, { method: "POST", body, headers: { "content-type": "application/json", ...headers } }));
		const ran = await (await run("https://site.example/run/compose/even", { origin: "https://site.example" })).json();
		assert.deepEqual(ran.result, { allow: true, violations: [] });
		assert.equal((await run("http://127.0.0.1:8788/run/compose/even")).status, 200, "loopback, no Origin (curl)");
		// review 3c H1: a cross-site page (no-cors text/plain, or another Origin) and DNS rebinding (Host) are refused.
		assert.equal((await run("https://site.example/run/compose/even", { "content-type": "text/plain" })).status, 415);
		assert.equal((await run("https://site.example/run/compose/even", { origin: "https://evil.example" })).status, 403);
		assert.equal((await run("http://127.0.0.1:8788/run/compose/even", { origin: "https://evil.example" })).status, 403);
		assert.equal((await run("http://evil.example:8788/run/compose/even")).status, 403);
		assert.equal((await run("https://site.example/run/compose/even", { "content-type": "application/json; charset=utf-8" })).status, 200);
		assert.equal((await app.fetch(new Request("https://site.example/.well-known/did.json"))).status, 404, "no session record declares app");
	} finally {
		ctx.close();
	}
});

test("a session record that declares app: the server serves the app's did:web and its read-only repo on its origin", { skip: !hono && "npm install in examples/node-hono" }, async () => {
	const { createApp } = await import("./server.mjs");
	const { readFile, writeFile } = await import("node:fs/promises");
	const dir = await mkdtemp(join(tmpdir(), "atlibs-hono-app-"));
	await atlibs(["stage", "--target", "server", "--out", dir, "vibescrobble"]);
	const stage = JSON.parse(await readFile(join(dir, "stage.json"), "utf8"));
	const record = stage.sessions.vibescrobble.record;
	const template = new URL(record.clientMetadata.client_id).origin;
	record.app = { records: [{ collection: "dev.cocore.app.registration", rkey: "self", value: { $type: "dev.cocore.app.registration", name: "vibes", returnUrls: [`${template}/done`], createdAt: "2026-11-10T00:00:00.000Z" } }], wellKnown: { "cocore-app.json": { did: `did:web:${new URL(template).host}` } } };
	await writeFile(join(dir, "stage.json"), JSON.stringify(stage));
	const ctx = createNodeContext(contextOptions(join(dir, "state")));
	try {
		const app = await createApp(join(dir, "stage.json"), { ctx, call: async () => ({}), origin: "https://site.example" });
		const get = async (path) => (await app.fetch(new Request(`https://site.example${path}`))).json();
		assert.equal((await get("/.well-known/did.json")).id, "did:web:site.example");
		assert.deepEqual(await get("/.well-known/cocore-app.json"), { did: "did:web:site.example" });
		assert.deepEqual((await get("/xrpc/com.atproto.repo.getRecord?repo=did:web:site.example&collection=dev.cocore.app.registration&rkey=self")).value.returnUrls, ["https://site.example/done"]);
		const again = await createApp(join(dir, "stage.json"), { ctx, call: async () => ({}), origin: "https://site.example" });
		assert.deepEqual((await (await again.fetch(new Request("https://site.example/.well-known/did.json"))).json()).verificationMethod, (await get("/.well-known/did.json")).verificationMethod, "the key is kept in the state dir");
	} finally {
		ctx.close();
	}
});

const oauthInstalled = await import("../../javascript/src/oauth-server/index.js").then(() => true, () => false);

test("a Hono app signs users in (javascript/src/oauth-server) and runs each request as its own user", { skip: (!hono && "npm install in examples/node-hono") || (!oauthInstalled && "npm install in javascript/src/oauth-server") }, async () => {
	const { createApp } = await import("./server.mjs");
	const { oauthServer } = await import("../../javascript/src/oauth-server/index.js");
	const { browser, fakeAtproto } = await import("../../javascript/src/oauth-server/fake.mjs");
	const ORIGIN = "https://site.example";
	const dir = await mkdtemp(join(tmpdir(), "atlibs-hono-oauth-"));
	await atlibs(["stage", "--target", "server", "--out", dir, "statusphere"]);
	let app;
	const fake = await fakeAtproto({ fetchClient: (url) => app.fetch(new Request(url)) });
	const ctx = createNodeContext(contextOptions(join(dir, "state")));
	try {
		const oauth = await oauthServer(ctx, { origin: ORIGIN, scope: "atproto transition:generic", fetch: (i, n) => fetch(i, n), handleResolver: fake.base, plcDirectoryUrl: fake.base, allowHttp: true });
		app = await createApp(join(dir, "stage.json"), { ctx, call: async () => Promise.reject(new Error("no operator account")), origin: ORIGIN, oauth });
		const handles = {};
		for (const user of ["alice", "bob"]) {
			const b = browser((url) => (url.startsWith(ORIGIN) ? (req) => app.fetch(req) : fetch));
			await b.go(`${ORIGIN}/oauth/login?handle=${user}.test`);
			handles[user] = b.cookie(ORIGIN, "atlibs_session");
			assert.ok(handles[user], `${user} signed in`);
		}
		const run = (handle) => app.fetch(new Request(`${ORIGIN}/run/statusphere/set_status`, { method: "POST", headers: { "content-type": "application/json", authorization: `Bearer ${handle}` }, body: JSON.stringify({ status: "🙂", now: new Date().toISOString() }) })).then((r) => r.json());
		const ran = await Promise.all([handles.alice, handles.bob, handles.alice, handles.bob].map(run));
		ran.forEach((r, i) => assert.ok(r.result?.uri?.startsWith(`at://${fake.did(i % 2 ? "bob" : "alice")}/`), JSON.stringify(r)));
		assert.ok(fake.writes.every((w) => w.sub === w.repo));
		assert.equal((await app.fetch(new Request(`${ORIGIN}/run/statusphere/set_status`, { method: "POST", headers: { "content-type": "application/json", authorization: "Bearer forged" }, body: "{}" }))).status, 401);
		assert.equal((await app.fetch(new Request(`${ORIGIN}/oauth/logout`, { method: "POST", headers: { authorization: `Bearer ${handles.bob}`, origin: "https://evil.example" } }))).status, 403, "a cross-site sign-out");
		// two modules under the same sign-in (granted transition:generic): each run is held to its own module's session (stage.json)
		const scopes = await scopeFixture();
		await atlibs(["stage", "--target", "server", "--out", join(scopes, "staged"), join(scopes, "comp.json")]);
		const scoped = await createApp(join(scopes, "staged", "stage.json"), { ctx, call: async () => Promise.reject(new Error("no operator account")), origin: ORIGIN, oauth });
		const create = (module, collection) => scoped.fetch(new Request(`${ORIGIN}/run/${module}/caller`, { method: "POST", headers: { "content-type": "application/json", authorization: `Bearer ${handles.alice}` }, body: JSON.stringify({ nsid: "com.atproto.repo.createRecord", input: { repo: fake.did("alice"), collection, record: {} } }) })).then((r) => r.json());
		fake.writes.length = 0;
		assert.equal((await create("a", "com.example.a")).result.q.ok, true);
		assert.equal((await create("a", "com.example.b")).result.q.error, "a may not call com.atproto.repo.createRecord with sessions sa");
		assert.equal((await create("b", "com.example.a")).result.q.error, "b may not call com.atproto.repo.createRecord with sessions sb");
		assert.deepEqual(fake.writes.map((w) => w.collection), ["com.example.a"]);
	} finally {
		ctx.close();
		await fake.close();
	}
});