UNPKG

@fedify/fedify

Version:

An ActivityPub server framework

224 lines (220 loc) • 7.29 kB
import { Temporal } from "@js-temporal/polyfill"; import { URLPattern } from "urlpattern-polyfill"; globalThis.addEventListener = () => {}; import { assertEquals } from "../assert_equals-CTYbeopb.js"; import { assert } from "../assert-DmFG7ppO.js"; import "../assert_instance_of-CF09JHYM.js"; import "../docloader-C8mmLN-Y.js"; import "../url-kTAI6_KP.js"; import "../multibase-DeCHcK8L.js"; import { Activity, Application, Endpoints, Group, Person, Service } from "../vocab-dDpPQ0fF.js"; import "../langstr-DbWheeIS.js"; import "../lookup-Ozuw-rxN.js"; import "../type-D2s5lmbZ.js"; import "../actor-BP-NTJ2m.js"; import "../key-CPSlDkCj.js"; import { verifyRequest } from "../http-BmfI6U39.js"; import { doesActorOwnKey } from "../owner-DF6Fg4-s.js"; import { extractInboxes, sendActivity } from "../send-CaL5Xv1F.js"; import { test } from "../testing-BZ0dJ4qn.js"; import "../std__assert-vp0TKMS1.js"; import { assertFalse, assertRejects } from "../assert_rejects-C-sxEMM5.js"; import "../assert_is_error-nrwA1GeT.js"; import { assertNotEquals } from "../assert_not_equals-Dc7y-V5Q.js"; import "../assert_throws-Cn9C6Jur.js"; import { mockDocumentLoader } from "../docloader-09nVWLAZ.js"; import { ed25519Multikey, ed25519PrivateKey, rsaPrivateKey2, rsaPublicKey2 } from "../keys-CtFc865v.js"; import { esm_default } from "../esm-Db4De7AS.js"; //#region federation/send.test.ts test("extractInboxes()", () => { const recipients = [ new Person({ id: new URL("https://example.com/alice"), inbox: new URL("https://example.com/alice/inbox"), endpoints: new Endpoints({ sharedInbox: new URL("https://example.com/inbox") }) }), new Application({ id: new URL("https://example.com/app"), inbox: new URL("https://example.com/app/inbox"), endpoints: new Endpoints({ sharedInbox: new URL("https://example.com/inbox") }) }), new Group({ id: new URL("https://example.org/group"), inbox: new URL("https://example.org/group/inbox") }), new Service({ id: new URL("https://example.net/service"), inbox: new URL("https://example.net/service/inbox"), endpoints: new Endpoints({ sharedInbox: new URL("https://example.net/inbox") }) }) ]; let inboxes = extractInboxes({ recipients }); assertEquals(inboxes, { "https://example.com/alice/inbox": { actorIds: new Set(["https://example.com/alice"]), sharedInbox: false }, "https://example.com/app/inbox": { actorIds: new Set(["https://example.com/app"]), sharedInbox: false }, "https://example.org/group/inbox": { actorIds: new Set(["https://example.org/group"]), sharedInbox: false }, "https://example.net/service/inbox": { actorIds: new Set(["https://example.net/service"]), sharedInbox: false } }); inboxes = extractInboxes({ recipients, preferSharedInbox: true }); assertEquals(inboxes, { "https://example.com/inbox": { actorIds: new Set(["https://example.com/alice", "https://example.com/app"]), sharedInbox: true }, "https://example.org/group/inbox": { actorIds: new Set(["https://example.org/group"]), sharedInbox: false }, "https://example.net/inbox": { actorIds: new Set(["https://example.net/service"]), sharedInbox: true } }); inboxes = extractInboxes({ recipients, excludeBaseUris: [new URL("https://foo.bar/")] }); assertEquals(inboxes, { "https://example.com/alice/inbox": { actorIds: new Set(["https://example.com/alice"]), sharedInbox: false }, "https://example.com/app/inbox": { actorIds: new Set(["https://example.com/app"]), sharedInbox: false }, "https://example.org/group/inbox": { actorIds: new Set(["https://example.org/group"]), sharedInbox: false }, "https://example.net/service/inbox": { actorIds: new Set(["https://example.net/service"]), sharedInbox: false } }); inboxes = extractInboxes({ recipients, excludeBaseUris: [new URL("https://example.com/")] }); assertEquals(inboxes, { "https://example.org/group/inbox": { actorIds: new Set(["https://example.org/group"]), sharedInbox: false }, "https://example.net/service/inbox": { actorIds: new Set(["https://example.net/service"]), sharedInbox: false } }); inboxes = extractInboxes({ recipients, preferSharedInbox: true, excludeBaseUris: [new URL("https://example.com/")] }); assertEquals(inboxes, { "https://example.org/group/inbox": { actorIds: new Set(["https://example.org/group"]), sharedInbox: false }, "https://example.net/inbox": { actorIds: new Set(["https://example.net/service"]), sharedInbox: true } }); }); test("sendActivity()", async (t) => { esm_default.spyGlobal(); let httpSigVerified = null; let request = null; esm_default.post("https://example.com/inbox", async (cl) => { httpSigVerified = false; request = cl.request.clone(); const options = { documentLoader: mockDocumentLoader, contextLoader: mockDocumentLoader }; const key = await verifyRequest(request, options); const activity = await Activity.fromJsonLd(await request.json(), options); if (key != null && await doesActorOwnKey(activity, key, options)) httpSigVerified = true; if (httpSigVerified) return new Response("", { status: 202 }); return new Response("", { status: 401 }); }); await t.step("success", async () => { const activity = { "@context": "https://www.w3.org/ns/activitystreams", "type": "Create", "id": "https://example.com/activity", "actor": "https://example.com/person" }; await sendActivity({ activity, keys: [{ privateKey: rsaPrivateKey2, keyId: rsaPublicKey2.id }], inbox: new URL("https://example.com/inbox"), headers: new Headers({ "X-Test": "test" }) }); assert(httpSigVerified); assertNotEquals(request, null); assertEquals(request?.method, "POST"); assertEquals(request?.url, "https://example.com/inbox"); assertEquals(request?.headers.get("Content-Type"), "application/activity+json"); assertEquals(request?.headers.get("X-Test"), "test"); httpSigVerified = null; await assertRejects(() => sendActivity({ activity: { ...activity, actor: "https://example.com/person2" }, keys: [{ privateKey: ed25519PrivateKey, keyId: ed25519Multikey.id }], inbox: new URL("https://example.com/inbox") })); assertFalse(httpSigVerified); assertNotEquals(request, null); assertEquals(request?.method, "POST"); assertEquals(request?.url, "https://example.com/inbox"); assertEquals(request?.headers.get("Content-Type"), "application/activity+json"); }); esm_default.post("https://example.com/inbox2", { status: 500, body: "something went wrong" }); await t.step("failure", async () => { const activity = { "@context": "https://www.w3.org/ns/activitystreams", "type": "Create", "id": "https://example.com/activity", "actor": "https://example.com/person" }; await assertRejects(() => sendActivity({ activity, activityId: "https://example.com/activity", keys: [{ privateKey: rsaPrivateKey2, keyId: rsaPublicKey2.id }], inbox: new URL("https://example.com/inbox2") }), Error, "Failed to send activity https://example.com/activity to https://example.com/inbox2 (500 Internal Server Error):\nsomething went wrong"); }); esm_default.hardReset(); }); //#endregion