clone

a self-hosted multitenant nostr relay with sites, file storage, git hosting, and inbox and outbox delivery

feat/ui-updates
tinyrelay / scripts / private-services.test.mjs
private-services.test.mjs 4.1K
1import assert from "node:assert/strict";2import {readFile} from "node:fs/promises";3import test from "node:test";4import vm from "node:vm";56const shared = await readFile(new URL("../tinyclient/tiny.js", import.meta.url), "utf8");7const source = await readFile(new URL("../tinyclient/private-services.js", import.meta.url), "utf8");8class Element {}9const definitions = new Map();10const sandbox = {11 URL, TextEncoder, HTMLElement: Element,12 document: {}, Response,13 customElements: {define(name, value) { if (definitions.has(name)) throw Error("duplicate definition"); definitions.set(name, value); }, get(name) { return definitions.get(name); }},14 tinySigner: {15 getPublicKey: async () => "a".repeat(64),16 nip44Encrypt: async (_pubkey, value) => "enc:" + value,17 nip44Decrypt: async (_pubkey, value) => value.replace(/^enc:/, "")18 },19 nostr: {signEvent: async event => event},20 NostrSigner: {verifyEvent: () => true}21};22sandbox.window = sandbox;23 sandbox.tiny = {files: {}};24vm.runInNewContext(shared + source, sandbox);25const api = sandbox.tiny.files.privateServices;2627test("can be evaluated again after in-place navigation", async () => {28 assert.doesNotThrow(() => vm.runInNewContext(source, sandbox));29 assert.equal(definitions.size, 1);30});3132test("accepts tenant paths while rejecting unsafe relay URLs", () => {33 assert.equal(api.validURL("wss://Relay.Example/r/Private"), true);34 assert.equal(api.canonicalURL("wss://Relay.Example/r/Private/"), "wss://relay.example/r/Private");35 assert.equal(api.validURL("wss://relay.example/?token=secret"), false);36 assert.equal(api.validURL("wss://user:pass@relay.example"), false);37 assert.equal(api.validURL("https://relay.example"), false);38});3940test("NIP-44 helpers round-trip and retain unrelated private entries", async () => {41 const clear = JSON.stringify([["name", "work"], ["g", "wss://old.example"], ["p", "b".repeat(64)]]);42 const encrypted = await api.encrypt("a".repeat(64), clear);43 assert.equal(await api.decrypt("a".repeat(64), encrypted), clear);44 assert.deepEqual(JSON.parse(JSON.stringify(api.mergeRows([["name", "work"], ["g", "wss://old.example"], ["p", "b".repeat(64)]], ["wss://new.example/r/tenant"]))), [["name", "work"], ["p", "b".repeat(64)], ["g", "wss://new.example/r/tenant"]]);45});4647test("NIP-07 nip44 methods are accepted alongside bunker methods", async () => {48 sandbox.tinySigner = null;49 sandbox.nostr = {nip44: {50 encrypt: async (_pubkey, value) => "nip07:" + value,51 decrypt: async (_pubkey, value) => value.replace(/^nip07:/, "")52 }};53 const encrypted = await api.encrypt("a".repeat(64), "private");54 assert.equal(encrypted, "nip07:private");55 assert.equal(await api.decrypt("a".repeat(64), encrypted), "private");56});5758test("kind 10318 wire has no public tags", () => {59 const event = api.wireEvent("ciphertext");60 assert.equal(event.kind, 10318);61 assert.equal(JSON.stringify(event.tags), "[]");62 assert.equal(event.content, "ciphertext");63});6465test("reads only a verified kind 10318 event for the requested author", async () => {66 const pubkey = "a".repeat(64);67 const event = {kind: 10318, pubkey, tags: [], content: "ciphertext", id: "1", sig: "2"};68 const requests = [];69 sandbox.tiny = {signedFetch: async (_path, _method, body) => {70 requests.push(JSON.parse(body));71 return new Response(JSON.stringify([event]), {status: 200});72 }};73 sandbox.NostrSigner.verifyEvent = () => true;74 assert.deepEqual(JSON.parse(JSON.stringify(await api.readList(pubkey))), event);75 assert.deepEqual(JSON.parse(JSON.stringify(requests[0])), [{kinds: [10318], authors: [pubkey], limit: 1}]);76 sandbox.tiny.signedFetch = async () => new Response(JSON.stringify([{...event, pubkey: "b".repeat(64)}]), {status: 200});77 await assert.rejects(api.readList(pubkey), /invalid/);78 sandbox.tiny.signedFetch = async () => new Response(JSON.stringify({items: []}), {status: 200});79 await assert.rejects(api.readList(pubkey), /malformed/);80});8182test("rejects a failed event signature", () => {83 sandbox.NostrSigner.verifyEvent = () => false;84 assert.equal(api.acceptEvent({kind: 10318, pubkey: "a".repeat(64), tags: [], content: ""}, "a".repeat(64)), false);85});