@fedify/fedify 2.2.0-pr.715.27 → 2.2.0-pr.731.0.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assert_strict_equals-Dmjbg-bA.mjs +41 -0
- package/dist/{builder-DQtY9nHQ.mjs → builder-Baov5O1s.mjs} +3 -3
- package/dist/compat/mod.d.cts +1 -1
- package/dist/compat/mod.d.ts +1 -1
- package/dist/compat/outgoing-jsonld.test.d.mts +2 -0
- package/dist/compat/outgoing-jsonld.test.mjs +189 -0
- package/dist/compat/public-audience.test.d.mts +2 -0
- package/dist/compat/public-audience.test.mjs +178 -0
- package/dist/compat/transformers.test.mjs +3 -3
- package/dist/{context-BGrYMSTk.d.ts → context-BzH2-ajs.d.ts} +22 -0
- package/dist/{context-CMUd4wy0.d.cts → context-DJGagtNd.d.cts} +22 -0
- package/dist/{deno-_fgAC2zJ.mjs → deno-bMTksNdm.mjs} +1 -1
- package/dist/{docloader-vRYuv1jI.mjs → docloader-CNb_EIVC.mjs} +2 -2
- package/dist/federation/builder.test.mjs +3 -3
- package/dist/federation/collection.test.mjs +2 -2
- package/dist/federation/handler.test.mjs +8 -8
- package/dist/federation/idempotency.test.mjs +5 -5
- package/dist/federation/inbox.test.mjs +1 -1
- package/dist/federation/keycache.test.mjs +3 -3
- package/dist/federation/kv.test.mjs +2 -2
- package/dist/federation/middleware.test.mjs +160 -10
- package/dist/federation/mod.cjs +1 -1
- package/dist/federation/mod.d.cts +2 -2
- package/dist/federation/mod.d.ts +2 -2
- package/dist/federation/mod.js +1 -1
- package/dist/federation/mq.test.mjs +17 -10
- package/dist/federation/negotiation.test.mjs +3 -3
- package/dist/federation/retry.test.mjs +1 -1
- package/dist/federation/router.test.mjs +2 -2
- package/dist/federation/send.test.mjs +6 -6
- package/dist/federation/webfinger.test.mjs +3 -3
- package/dist/{http-s3HaFg5o.js → http-CqyW3LNC.js} +1 -1
- package/dist/{http-R-epZzZQ.cjs → http-Cr8G4qjh.cjs} +1 -1
- package/dist/{http-C8rif6ld.mjs → http-FJABWPPb.mjs} +3 -3
- package/dist/{key-Ce0SDXK2.mjs → key-CjAnbVVw.mjs} +1 -1
- package/dist/{kv-cache-Btpmwlb5.cjs → kv-cache-C0Gbhf8a.cjs} +1 -1
- package/dist/{kv-cache-ChSAw77q.js → kv-cache-DHHUofSR.js} +1 -1
- package/dist/{ld-BsDP9tTM.mjs → ld-Br9Nfaj_.mjs} +2 -2
- package/dist/{middleware-DtEWmK1Y.mjs → middleware-BBn1W0f9.mjs} +34 -22
- package/dist/{middleware-DFQeBAbL.mjs → middleware-CcNkmg2C.mjs} +1 -1
- package/dist/{middleware-CXG1M9Om.cjs → middleware-Dy5dHeo9.cjs} +1 -1
- package/dist/{middleware-vUbXbazq.cjs → middleware-T6IfI9DE.cjs} +20 -9
- package/dist/{middleware-C4ymcV-E.js → middleware-qArtjTPM.js} +19 -8
- package/dist/{mod-CJXfyw7v.d.ts → mod-2d12ffz3.d.ts} +1 -1
- package/dist/{mod-BcJHeuv1.d.cts → mod-D35TRn09.d.cts} +1 -1
- package/dist/mod.cjs +4 -4
- package/dist/mod.d.cts +2 -2
- package/dist/mod.d.ts +2 -2
- package/dist/mod.js +4 -4
- package/dist/nodeinfo/client.test.mjs +2 -2
- package/dist/nodeinfo/handler.test.mjs +3 -3
- package/dist/nodeinfo/types.test.mjs +2 -2
- package/dist/otel/exporter.test.mjs +2 -2
- package/dist/outgoing-jsonld-CNmZLixq.mjs +203 -0
- package/dist/{owner-CTfDotXM.mjs → owner-Bnpayci1.mjs} +2 -2
- package/dist/{proof-qQIVjzlw.js → proof-CjmkpD7k.js} +425 -41
- package/dist/{proof-3RPJLWOU.cjs → proof-DUxbInOx.cjs} +428 -38
- package/dist/{proof-UdlPVu_P.mjs → proof-I8sYnUWs.mjs} +38 -31
- package/dist/public-audience-DYFHzm_c.mjs +192 -0
- package/dist/{send-kudDOImz.mjs → send-vh20v1J9.mjs} +2 -2
- package/dist/sig/accept.test.mjs +1 -1
- package/dist/sig/http.test.mjs +5 -5
- package/dist/sig/key.test.mjs +3 -3
- package/dist/sig/ld.test.mjs +4 -4
- package/dist/sig/mod.cjs +2 -2
- package/dist/sig/mod.js +2 -2
- package/dist/sig/owner.test.mjs +4 -4
- package/dist/sig/proof.test.mjs +78 -5
- package/dist/{std__assert-Duiq_YC9.mjs → std__assert-CRDpx_HF.mjs} +3 -38
- package/dist/testing/mod.d.mts +22 -0
- package/dist/utils/docloader.test.mjs +4 -4
- package/dist/utils/kv-cache.test.mjs +1 -1
- package/dist/utils/mod.cjs +1 -1
- package/dist/utils/mod.js +1 -1
- package/package.json +6 -6
- /package/dist/{accept-Dd__NiUL.mjs → accept-CPkZzmGN.mjs} +0 -0
- /package/dist/{activity-listener-Ck3JZ_hR.mjs → activity-listener-ell7W1s9.mjs} +0 -0
- /package/dist/{assert-ddO5KLpe.mjs → assert-DikXweDx.mjs} +0 -0
- /package/dist/{client-DEpOVgY1.mjs → client-D_1QpnWt.mjs} +0 -0
- /package/dist/{collection-BD6-SZ6O.mjs → collection-D-HqUuA2.mjs} +0 -0
- /package/dist/{keycache-CCSwkQcY.mjs → keycache-EGATflN-.mjs} +0 -0
- /package/dist/{keys-BAK-tUlf.mjs → keys-DGu1NFwu.mjs} +0 -0
- /package/dist/{kv-cache-B01V7s3h.mjs → kv-cache-U__xU4qR.mjs} +0 -0
- /package/dist/{kv-tL2TOE9X.mjs → kv-rV3vodCc.mjs} +0 -0
- /package/dist/{negotiation-DnsfFF8I.mjs → negotiation-SQvQgUqe.mjs} +0 -0
- /package/dist/{retry-B_E3V_Dx.mjs → retry-bMXBL97A.mjs} +0 -0
- /package/dist/{types-DCP0WLdt.mjs → types-J53Kw7so.mjs} +0 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import "@js-temporal/polyfill";
|
|
2
|
+
import "urlpattern-polyfill";
|
|
3
|
+
globalThis.addEventListener = () => {};
|
|
4
|
+
import { a as red, i as buildMessage, l as AssertionError, n as diffStr, r as diff, s as format } from "./assert_equals-Ew3jOFa3.mjs";
|
|
5
|
+
//#region ../../node_modules/.pnpm/@jsr+std__assert@0.226.0/node_modules/@jsr/std__assert/assert_strict_equals.js
|
|
6
|
+
/**
|
|
7
|
+
* Make an assertion that `actual` and `expected` are equal using
|
|
8
|
+
* {@linkcode Object.is} for equality comparison. If not, then throw.
|
|
9
|
+
*
|
|
10
|
+
* @example Usage
|
|
11
|
+
* ```ts no-eval
|
|
12
|
+
* import { assertStrictEquals } from "@std/assert/assert-strict-equals";
|
|
13
|
+
*
|
|
14
|
+
* const a = {};
|
|
15
|
+
* const b = a;
|
|
16
|
+
* assertStrictEquals(a, b); // Doesn't throw
|
|
17
|
+
*
|
|
18
|
+
* const c = {};
|
|
19
|
+
* const d = {};
|
|
20
|
+
* assertStrictEquals(c, d); // Throws
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @typeParam T The type of the expected value.
|
|
24
|
+
* @param actual The actual value to compare.
|
|
25
|
+
* @param expected The expected value to compare.
|
|
26
|
+
* @param msg The optional message to display if the assertion fails.
|
|
27
|
+
*/ function assertStrictEquals(actual, expected, msg) {
|
|
28
|
+
if (Object.is(actual, expected)) return;
|
|
29
|
+
const msgSuffix = msg ? `: ${msg}` : ".";
|
|
30
|
+
let message;
|
|
31
|
+
const actualString = format(actual);
|
|
32
|
+
const expectedString = format(expected);
|
|
33
|
+
if (actualString === expectedString) message = `Values have the same structure but are not reference-equal${msgSuffix}\n\n${red(actualString.split("\n").map((l) => ` ${l}`).join("\n"))}\n`;
|
|
34
|
+
else {
|
|
35
|
+
const stringDiff = typeof actual === "string" && typeof expected === "string";
|
|
36
|
+
message = `Values are not strictly equal${msgSuffix}\n${buildMessage(stringDiff ? diffStr(actual, expected) : diff(actualString.split("\n"), expectedString.split("\n")), { stringDiff }).join("\n")}`;
|
|
37
|
+
}
|
|
38
|
+
throw new AssertionError(message);
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
export { assertStrictEquals as t };
|
|
@@ -2,8 +2,8 @@ import "@js-temporal/polyfill";
|
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { n as RouterError, t as Router } from "./router-CrMLXoOr.mjs";
|
|
5
|
-
import { n as version, t as name } from "./deno-
|
|
6
|
-
import { t as ActivityListenerSet } from "./activity-listener-
|
|
5
|
+
import { n as version, t as name } from "./deno-bMTksNdm.mjs";
|
|
6
|
+
import { t as ActivityListenerSet } from "./activity-listener-ell7W1s9.mjs";
|
|
7
7
|
import { Tombstone, getTypeId } from "@fedify/vocab";
|
|
8
8
|
import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
9
9
|
import { getLogger } from "@logtape/logtape";
|
|
@@ -58,7 +58,7 @@ var FederationBuilderImpl = class {
|
|
|
58
58
|
this.collectionTypeIds = {};
|
|
59
59
|
}
|
|
60
60
|
async build(options) {
|
|
61
|
-
const { FederationImpl } = await import("./middleware-
|
|
61
|
+
const { FederationImpl } = await import("./middleware-CcNkmg2C.mjs");
|
|
62
62
|
const f = new FederationImpl(options);
|
|
63
63
|
const trailingSlashInsensitiveValue = f.router.trailingSlashInsensitive;
|
|
64
64
|
f.router = this.router.clone();
|
package/dist/compat/mod.d.cts
CHANGED
package/dist/compat/mod.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Temporal } from "@js-temporal/polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
|
-
import { Ot as ActivityTransformer, n as Context } from "../context-
|
|
3
|
+
import { Ot as ActivityTransformer, n as Context } from "../context-BzH2-ajs.js";
|
|
4
4
|
import { Activity } from "@fedify/vocab";
|
|
5
5
|
|
|
6
6
|
//#region src/compat/transformers.d.ts
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import "@js-temporal/polyfill";
|
|
2
|
+
import "urlpattern-polyfill";
|
|
3
|
+
globalThis.addEventListener = () => {};
|
|
4
|
+
import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
|
|
5
|
+
import { t as assertStrictEquals } from "../assert_strict_equals-Dmjbg-bA.mjs";
|
|
6
|
+
import { n as normalizeAttachmentArrays, r as normalizeOutgoingActivityJsonLd, t as isPreloadedContextAttachmentSafe } from "../outgoing-jsonld-CNmZLixq.mjs";
|
|
7
|
+
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
8
|
+
import { Create, Document, Note, PUBLIC_COLLECTION } from "@fedify/vocab";
|
|
9
|
+
//#region src/compat/outgoing-jsonld.test.ts
|
|
10
|
+
test("normalizeAttachmentArrays() wraps scalar attachments", async () => {
|
|
11
|
+
const object = (await normalizeAttachmentArrays({
|
|
12
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
13
|
+
type: "Create",
|
|
14
|
+
object: {
|
|
15
|
+
type: "Note",
|
|
16
|
+
attachment: {
|
|
17
|
+
type: "Document",
|
|
18
|
+
mediaType: "image/png",
|
|
19
|
+
url: "https://example.com/image.png"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
})).object;
|
|
23
|
+
assertEquals(object.attachment, [{
|
|
24
|
+
type: "Document",
|
|
25
|
+
mediaType: "image/png",
|
|
26
|
+
url: "https://example.com/image.png"
|
|
27
|
+
}]);
|
|
28
|
+
});
|
|
29
|
+
test("normalizeAttachmentArrays() skips canonicalization for known-safe contexts", async () => {
|
|
30
|
+
assertEquals((await normalizeAttachmentArrays({
|
|
31
|
+
"@context": ["https://www.w3.org/ns/activitystreams", "https://w3id.org/security/data-integrity/v1"],
|
|
32
|
+
type: "Note",
|
|
33
|
+
attachment: {
|
|
34
|
+
type: "Document",
|
|
35
|
+
mediaType: "image/png",
|
|
36
|
+
url: "https://example.com/image.png"
|
|
37
|
+
}
|
|
38
|
+
}, () => {
|
|
39
|
+
throw new Error("context loader should not be called");
|
|
40
|
+
})).attachment, [{
|
|
41
|
+
type: "Document",
|
|
42
|
+
mediaType: "image/png",
|
|
43
|
+
url: "https://example.com/image.png"
|
|
44
|
+
}]);
|
|
45
|
+
});
|
|
46
|
+
test("isPreloadedContextAttachmentSafe() checks scoped contexts", () => {
|
|
47
|
+
assertEquals(isPreloadedContextAttachmentSafe({ "@context": {
|
|
48
|
+
attachment: {
|
|
49
|
+
"@id": "as:attachment",
|
|
50
|
+
"@type": "@id"
|
|
51
|
+
},
|
|
52
|
+
Example: { "@context": { attachment: {
|
|
53
|
+
"@id": "as:attachment",
|
|
54
|
+
"@type": "@id"
|
|
55
|
+
} } }
|
|
56
|
+
} }), true);
|
|
57
|
+
assertEquals(isPreloadedContextAttachmentSafe({ "@context": { Example: { "@context": { attachment: "https://example.com/custom-attachment" } } } }), false);
|
|
58
|
+
});
|
|
59
|
+
test("normalizeAttachmentArrays() does not wrap JSON-LD list objects", async () => {
|
|
60
|
+
const attachment = { "@list": [{
|
|
61
|
+
type: "Document",
|
|
62
|
+
url: "https://example.com/image.png"
|
|
63
|
+
}] };
|
|
64
|
+
assertEquals((await normalizeAttachmentArrays({
|
|
65
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
66
|
+
type: "Note",
|
|
67
|
+
attachment
|
|
68
|
+
}, () => {
|
|
69
|
+
throw new Error("context loader should not be called");
|
|
70
|
+
})).attachment, attachment);
|
|
71
|
+
});
|
|
72
|
+
test("normalizeAttachmentArrays() does not traverse JSON-LD value payloads", async () => {
|
|
73
|
+
const output = await normalizeAttachmentArrays({
|
|
74
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
75
|
+
type: "Note",
|
|
76
|
+
attachment: { type: "Document" },
|
|
77
|
+
content: {
|
|
78
|
+
"@type": "@json",
|
|
79
|
+
"@value": {
|
|
80
|
+
"@context": { attachment: "https://example.com/custom-attachment" },
|
|
81
|
+
attachment: "https://example.com/metadata"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}, () => {
|
|
85
|
+
throw new Error("context loader should not be called");
|
|
86
|
+
});
|
|
87
|
+
assertEquals(output.attachment, [{ type: "Document" }]);
|
|
88
|
+
assertEquals(output.content, {
|
|
89
|
+
"@type": "@json",
|
|
90
|
+
"@value": {
|
|
91
|
+
"@context": { attachment: "https://example.com/custom-attachment" },
|
|
92
|
+
attachment: "https://example.com/metadata"
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
test("normalizeAttachmentArrays() leaves attachment arrays unchanged", async () => {
|
|
97
|
+
const attachment = [{
|
|
98
|
+
type: "Document",
|
|
99
|
+
mediaType: "image/png",
|
|
100
|
+
url: "https://example.com/image.png"
|
|
101
|
+
}];
|
|
102
|
+
assertEquals((await normalizeAttachmentArrays({
|
|
103
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
104
|
+
type: "Note",
|
|
105
|
+
attachment
|
|
106
|
+
})).attachment, attachment);
|
|
107
|
+
});
|
|
108
|
+
test("normalizeAttachmentArrays() leaves documents without attachments unchanged", async () => {
|
|
109
|
+
const input = {
|
|
110
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
111
|
+
type: "Note",
|
|
112
|
+
content: "Hello"
|
|
113
|
+
};
|
|
114
|
+
assertEquals(await normalizeAttachmentArrays(input), input);
|
|
115
|
+
});
|
|
116
|
+
test("normalizeAttachmentArrays() leaves @context subtrees untouched", async () => {
|
|
117
|
+
const output = await normalizeAttachmentArrays({
|
|
118
|
+
"@context": ["https://www.w3.org/ns/activitystreams", { attachment: "https://example.com/custom-attachment" }],
|
|
119
|
+
type: "Note",
|
|
120
|
+
attachment: "https://example.com/attachment"
|
|
121
|
+
});
|
|
122
|
+
const context = output["@context"];
|
|
123
|
+
assertEquals(context[1], { attachment: "https://example.com/custom-attachment" });
|
|
124
|
+
assertEquals(output.attachment, ["https://example.com/attachment"]);
|
|
125
|
+
});
|
|
126
|
+
test("normalizeAttachmentArrays() bails out when wrapping changes semantics", async () => {
|
|
127
|
+
assertEquals((await normalizeAttachmentArrays({
|
|
128
|
+
"@context": { attachment: {
|
|
129
|
+
"@id": "https://example.com/custom-attachment",
|
|
130
|
+
"@type": "@json"
|
|
131
|
+
} },
|
|
132
|
+
attachment: { custom: true }
|
|
133
|
+
})).attachment, { custom: true });
|
|
134
|
+
});
|
|
135
|
+
test("normalizeAttachmentArrays() does not poison the global prototype via a __proto__ key", async () => {
|
|
136
|
+
await normalizeAttachmentArrays(JSON.parse(`{
|
|
137
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
138
|
+
"type": "Note",
|
|
139
|
+
"attachment": { "type": "Document" },
|
|
140
|
+
"__proto__": { "polluted": true }
|
|
141
|
+
}`));
|
|
142
|
+
assertEquals(Object.prototype.polluted, void 0);
|
|
143
|
+
});
|
|
144
|
+
test("normalizeAttachmentArrays() stops before blowing the stack on pathological nesting", async () => {
|
|
145
|
+
let deep = { attachment: { type: "Document" } };
|
|
146
|
+
for (let i = 0; i < 256; i++) deep = { object: deep };
|
|
147
|
+
const input = {
|
|
148
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
149
|
+
type: "Create",
|
|
150
|
+
object: deep
|
|
151
|
+
};
|
|
152
|
+
assertStrictEquals(await normalizeAttachmentArrays(input), input);
|
|
153
|
+
});
|
|
154
|
+
test("normalizeAttachmentArrays() skips canonicalization for pathological nesting", async () => {
|
|
155
|
+
let deep = { type: "Note" };
|
|
156
|
+
for (let i = 0; i < 256; i++) deep = { object: deep };
|
|
157
|
+
assertEquals((await normalizeAttachmentArrays({
|
|
158
|
+
"@context": ["https://www.w3.org/ns/activitystreams", "https://example.com/context"],
|
|
159
|
+
type: "Note",
|
|
160
|
+
attachment: { type: "Document" },
|
|
161
|
+
object: deep
|
|
162
|
+
}, () => {
|
|
163
|
+
throw new Error("context loader should not be called");
|
|
164
|
+
})).attachment, { type: "Document" });
|
|
165
|
+
});
|
|
166
|
+
test("normalizeOutgoingActivityJsonLd() applies outgoing JSON-LD workarounds", async () => {
|
|
167
|
+
const compact = await new Create({
|
|
168
|
+
id: new URL("https://example.com/activities/1"),
|
|
169
|
+
actor: new URL("https://example.com/alice"),
|
|
170
|
+
object: new Note({
|
|
171
|
+
id: new URL("https://example.com/notes/1"),
|
|
172
|
+
tos: [PUBLIC_COLLECTION],
|
|
173
|
+
attachments: [new Document({
|
|
174
|
+
mediaType: "image/png",
|
|
175
|
+
url: new URL("https://example.com/image.png")
|
|
176
|
+
})]
|
|
177
|
+
}),
|
|
178
|
+
tos: [PUBLIC_COLLECTION]
|
|
179
|
+
}).toJsonLd({ format: "compact" });
|
|
180
|
+
assertEquals(compact.to, "as:Public");
|
|
181
|
+
const compactObject = compact.object;
|
|
182
|
+
assertEquals(Array.isArray(compactObject.attachment), false);
|
|
183
|
+
const normalized = await normalizeOutgoingActivityJsonLd(compact, mockDocumentLoader);
|
|
184
|
+
assertEquals(normalized.to, PUBLIC_COLLECTION.href);
|
|
185
|
+
const normalizedObject = normalized.object;
|
|
186
|
+
assertEquals(Array.isArray(normalizedObject.attachment), true);
|
|
187
|
+
});
|
|
188
|
+
//#endregion
|
|
189
|
+
export {};
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import "@js-temporal/polyfill";
|
|
2
|
+
import "urlpattern-polyfill";
|
|
3
|
+
globalThis.addEventListener = () => {};
|
|
4
|
+
import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
|
|
5
|
+
import { t as assertNotEquals } from "../assert_not_equals--wG9hV7u.mjs";
|
|
6
|
+
import { t as normalizePublicAudience } from "../public-audience-DYFHzm_c.mjs";
|
|
7
|
+
import { test } from "@fedify/fixture";
|
|
8
|
+
import { Create, Note, PUBLIC_COLLECTION } from "@fedify/vocab";
|
|
9
|
+
import { getDocumentLoader, preloadedContexts } from "@fedify/vocab-runtime";
|
|
10
|
+
//#region src/compat/public-audience.test.ts
|
|
11
|
+
const PUBLIC_URI = PUBLIC_COLLECTION.href;
|
|
12
|
+
const AS_CONTEXT = "https://www.w3.org/ns/activitystreams";
|
|
13
|
+
test("normalizePublicAudience() rewrites every addressing field and both CURIE forms", async () => {
|
|
14
|
+
const output = await normalizePublicAudience({
|
|
15
|
+
"@context": AS_CONTEXT,
|
|
16
|
+
type: "Note",
|
|
17
|
+
id: "https://example.com/notes/1",
|
|
18
|
+
to: "as:Public",
|
|
19
|
+
cc: ["as:Public", "https://example.com/bob"],
|
|
20
|
+
bto: "Public",
|
|
21
|
+
bcc: ["Public"],
|
|
22
|
+
audience: ["as:Public", "Public"]
|
|
23
|
+
});
|
|
24
|
+
assertEquals(output.to, PUBLIC_URI);
|
|
25
|
+
assertEquals(output.cc, [PUBLIC_URI, "https://example.com/bob"]);
|
|
26
|
+
assertEquals(output.bto, PUBLIC_URI);
|
|
27
|
+
assertEquals(output.bcc, [PUBLIC_URI]);
|
|
28
|
+
assertEquals(output.audience, [PUBLIC_URI, PUBLIC_URI]);
|
|
29
|
+
});
|
|
30
|
+
test("normalizePublicAudience() normalises activities serialized by @fedify/vocab", async () => {
|
|
31
|
+
const compact = await new Create({
|
|
32
|
+
id: new URL("https://example.com/activities/1"),
|
|
33
|
+
actor: new URL("https://example.com/alice"),
|
|
34
|
+
object: new Note({
|
|
35
|
+
id: new URL("https://example.com/notes/1"),
|
|
36
|
+
content: "Hello, world!",
|
|
37
|
+
tos: [PUBLIC_COLLECTION]
|
|
38
|
+
}),
|
|
39
|
+
tos: [PUBLIC_COLLECTION],
|
|
40
|
+
ccs: [new URL("https://example.com/followers")]
|
|
41
|
+
}).toJsonLd({ format: "compact" });
|
|
42
|
+
assertEquals(compact.to, "as:Public");
|
|
43
|
+
const normalized = await normalizePublicAudience(compact, getDocumentLoader());
|
|
44
|
+
assertEquals(normalized.to, PUBLIC_URI);
|
|
45
|
+
const nestedObject = normalized.object;
|
|
46
|
+
assertEquals(nestedObject.to, PUBLIC_URI);
|
|
47
|
+
});
|
|
48
|
+
test("normalizePublicAudience() is a no-op without the CURIE", async () => {
|
|
49
|
+
const input = {
|
|
50
|
+
"@context": AS_CONTEXT,
|
|
51
|
+
type: "Note",
|
|
52
|
+
id: "https://example.com/notes/3",
|
|
53
|
+
to: PUBLIC_URI
|
|
54
|
+
};
|
|
55
|
+
assertEquals(await normalizePublicAudience(input), input);
|
|
56
|
+
});
|
|
57
|
+
test("normalizePublicAudience() leaves non-addressing fields untouched", async () => {
|
|
58
|
+
const output = await normalizePublicAudience({
|
|
59
|
+
"@context": AS_CONTEXT,
|
|
60
|
+
type: "Note",
|
|
61
|
+
id: "https://example.com/notes/4",
|
|
62
|
+
name: "as:Public",
|
|
63
|
+
to: "as:Public"
|
|
64
|
+
});
|
|
65
|
+
assertEquals(output.name, "as:Public");
|
|
66
|
+
assertEquals(output.to, PUBLIC_URI);
|
|
67
|
+
});
|
|
68
|
+
test("normalizePublicAudience() rewrites without canonicalization for known-safe contexts", async () => {
|
|
69
|
+
const rejecting = () => {
|
|
70
|
+
throw new Error("contextLoader should not be called for a known-safe @context");
|
|
71
|
+
};
|
|
72
|
+
assertEquals((await normalizePublicAudience({
|
|
73
|
+
"@context": AS_CONTEXT,
|
|
74
|
+
type: "Note",
|
|
75
|
+
id: "https://example.com/notes/fast1",
|
|
76
|
+
to: "as:Public"
|
|
77
|
+
}, rejecting)).to, PUBLIC_URI);
|
|
78
|
+
assertEquals((await normalizePublicAudience({
|
|
79
|
+
"@context": [AS_CONTEXT, "https://w3id.org/security/data-integrity/v1"],
|
|
80
|
+
type: "Note",
|
|
81
|
+
id: "https://example.com/notes/fast2",
|
|
82
|
+
to: "as:Public"
|
|
83
|
+
}, rejecting)).to, PUBLIC_URI);
|
|
84
|
+
});
|
|
85
|
+
test("normalizePublicAudience() falls back to canonicalization for unknown-URL contexts", async () => {
|
|
86
|
+
let loaderCalls = 0;
|
|
87
|
+
const loader = (url) => {
|
|
88
|
+
loaderCalls++;
|
|
89
|
+
return Promise.resolve({
|
|
90
|
+
contextUrl: null,
|
|
91
|
+
documentUrl: url,
|
|
92
|
+
document: preloadedContexts[AS_CONTEXT]
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
assertEquals((await normalizePublicAudience({
|
|
96
|
+
"@context": [AS_CONTEXT, "https://custom.example/ctx"],
|
|
97
|
+
type: "Note",
|
|
98
|
+
id: "https://example.com/notes/unknown",
|
|
99
|
+
to: "as:Public"
|
|
100
|
+
}, loader)).to, PUBLIC_URI);
|
|
101
|
+
assertEquals(loaderCalls > 0, true);
|
|
102
|
+
});
|
|
103
|
+
test("normalizePublicAudience() leaves @context subtrees untouched", async () => {
|
|
104
|
+
const inlineCtx = (await normalizePublicAudience({
|
|
105
|
+
"@context": [AS_CONTEXT, { "customTerm": "as:Public" }],
|
|
106
|
+
type: "Note",
|
|
107
|
+
id: "https://example.com/notes/context",
|
|
108
|
+
to: PUBLIC_URI
|
|
109
|
+
}))["@context"][1];
|
|
110
|
+
assertEquals(inlineCtx.customTerm, "as:Public");
|
|
111
|
+
});
|
|
112
|
+
test("normalizePublicAudience() does not traverse prototype-polluted keys", async () => {
|
|
113
|
+
const polluted = Object.create({ to: "as:Public" });
|
|
114
|
+
polluted["@context"] = AS_CONTEXT;
|
|
115
|
+
polluted.type = "Note";
|
|
116
|
+
polluted.id = "https://example.com/notes/proto";
|
|
117
|
+
const output = await normalizePublicAudience(polluted);
|
|
118
|
+
assertEquals(Object.hasOwn(output, "to"), false);
|
|
119
|
+
});
|
|
120
|
+
test("normalizePublicAudience() stops before blowing the stack on pathological nesting", async () => {
|
|
121
|
+
let deep = { to: "as:Public" };
|
|
122
|
+
for (let i = 0; i < 256; i++) deep = { nested: deep };
|
|
123
|
+
assertEquals(typeof await normalizePublicAudience({
|
|
124
|
+
"@context": AS_CONTEXT,
|
|
125
|
+
type: "Note",
|
|
126
|
+
id: "https://example.com/notes/deep",
|
|
127
|
+
to: "as:Public",
|
|
128
|
+
object: deep
|
|
129
|
+
}), "object");
|
|
130
|
+
});
|
|
131
|
+
test("normalizePublicAudience() does not poison the global prototype via a __proto__ key", async () => {
|
|
132
|
+
await normalizePublicAudience(JSON.parse(`{
|
|
133
|
+
"@context": "https://www.w3.org/ns/activitystreams",
|
|
134
|
+
"type": "Note",
|
|
135
|
+
"id": "https://example.com/notes/proto-pollution",
|
|
136
|
+
"to": "as:Public",
|
|
137
|
+
"__proto__": { "polluted": true }
|
|
138
|
+
}`));
|
|
139
|
+
assertEquals(Object.prototype.polluted, void 0);
|
|
140
|
+
});
|
|
141
|
+
test("normalizePublicAudience() bails out on nested @context that redefines as:", async () => {
|
|
142
|
+
const output = await normalizePublicAudience({
|
|
143
|
+
"@context": AS_CONTEXT,
|
|
144
|
+
type: "Create",
|
|
145
|
+
id: "https://example.com/activities/nested",
|
|
146
|
+
actor: "https://example.com/alice",
|
|
147
|
+
to: "as:Public",
|
|
148
|
+
object: {
|
|
149
|
+
"@context": { "as": "https://not-activitystreams.example/" },
|
|
150
|
+
type: "https://www.w3.org/ns/activitystreams#Note",
|
|
151
|
+
id: "https://example.com/objects/nested",
|
|
152
|
+
to: "as:Public"
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
assertEquals(output.to, "as:Public");
|
|
156
|
+
const nested = output.object;
|
|
157
|
+
assertEquals(nested.to, "as:Public");
|
|
158
|
+
});
|
|
159
|
+
test("normalizePublicAudience() bails out when the rewrite changes semantics", async () => {
|
|
160
|
+
const output = await normalizePublicAudience({
|
|
161
|
+
"@context": {
|
|
162
|
+
"as": "https://not-activitystreams.example/",
|
|
163
|
+
"to": {
|
|
164
|
+
"@id": "https://www.w3.org/ns/activitystreams#to",
|
|
165
|
+
"@type": "@id"
|
|
166
|
+
},
|
|
167
|
+
"type": "@type",
|
|
168
|
+
"id": "@id"
|
|
169
|
+
},
|
|
170
|
+
type: "https://www.w3.org/ns/activitystreams#Note",
|
|
171
|
+
id: "https://example.com/notes/5",
|
|
172
|
+
to: "as:Public"
|
|
173
|
+
});
|
|
174
|
+
assertEquals(output.to, "as:Public");
|
|
175
|
+
assertNotEquals(output.to, PUBLIC_URI);
|
|
176
|
+
});
|
|
177
|
+
//#endregion
|
|
178
|
+
export {};
|
|
@@ -3,9 +3,9 @@ import "urlpattern-polyfill";
|
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
|
|
5
5
|
import { t as assertInstanceOf } from "../assert_instance_of-C4Ri6VuN.mjs";
|
|
6
|
-
import { t as assert } from "../assert-
|
|
7
|
-
import { t as MemoryKvStore } from "../kv-
|
|
8
|
-
import { n as FederationImpl, v as actorDehydrator, y as autoIdAssigner } from "../middleware-
|
|
6
|
+
import { t as assert } from "../assert-DikXweDx.mjs";
|
|
7
|
+
import { t as MemoryKvStore } from "../kv-rV3vodCc.mjs";
|
|
8
|
+
import { n as FederationImpl, v as actorDehydrator, y as autoIdAssigner } from "../middleware-BBn1W0f9.mjs";
|
|
9
9
|
import { test } from "@fedify/fixture";
|
|
10
10
|
import { Follow, Person } from "@fedify/vocab";
|
|
11
11
|
//#region src/compat/transformers.test.ts
|
|
@@ -702,6 +702,15 @@ interface FanoutMessage {
|
|
|
702
702
|
readonly activityType: string;
|
|
703
703
|
readonly collectionSync?: string;
|
|
704
704
|
readonly orderingKey?: string;
|
|
705
|
+
/**
|
|
706
|
+
* Whether to apply outgoing JSON-LD wire-format normalization to queued
|
|
707
|
+
* activities that already carry Object Integrity Proofs.
|
|
708
|
+
*
|
|
709
|
+
* `true` is used for proofs Fedify created before fanout, or when callers
|
|
710
|
+
* explicitly request normalization for locally pre-signed activities.
|
|
711
|
+
* `false`/`undefined` preserves existing proofs as-is.
|
|
712
|
+
*/
|
|
713
|
+
readonly normalizeExistingProofs?: boolean;
|
|
705
714
|
readonly traceContext: Readonly<Record<string, string>>;
|
|
706
715
|
}
|
|
707
716
|
interface OutboxMessage {
|
|
@@ -2668,6 +2677,19 @@ interface SendActivityOptions {
|
|
|
2668
2677
|
*/
|
|
2669
2678
|
readonly fanout?: "auto" | "skip" | "force";
|
|
2670
2679
|
/**
|
|
2680
|
+
* Whether to apply Fedify's outgoing JSON-LD wire-format compatibility fixes
|
|
2681
|
+
* to activities that already carry Object Integrity Proofs.
|
|
2682
|
+
*
|
|
2683
|
+
* By default, Fedify preserves existing proofs byte-for-byte because it
|
|
2684
|
+
* cannot know whether they were created for the normalized outgoing wire
|
|
2685
|
+
* form. Set this to `true` when sending an activity that was pre-signed
|
|
2686
|
+
* locally with `signObject()` or `createProof()`, so the emitted
|
|
2687
|
+
* compact JSON-LD matches the bytes covered by the proof.
|
|
2688
|
+
*
|
|
2689
|
+
* @since 2.2.0
|
|
2690
|
+
*/
|
|
2691
|
+
readonly normalizeExistingProofs?: boolean;
|
|
2692
|
+
/**
|
|
2671
2693
|
* The base URIs to exclude from the recipients' inboxes. It is useful
|
|
2672
2694
|
* for excluding the recipients having the same shared inbox with the sender.
|
|
2673
2695
|
*
|
|
@@ -700,6 +700,15 @@ interface FanoutMessage {
|
|
|
700
700
|
readonly activityType: string;
|
|
701
701
|
readonly collectionSync?: string;
|
|
702
702
|
readonly orderingKey?: string;
|
|
703
|
+
/**
|
|
704
|
+
* Whether to apply outgoing JSON-LD wire-format normalization to queued
|
|
705
|
+
* activities that already carry Object Integrity Proofs.
|
|
706
|
+
*
|
|
707
|
+
* `true` is used for proofs Fedify created before fanout, or when callers
|
|
708
|
+
* explicitly request normalization for locally pre-signed activities.
|
|
709
|
+
* `false`/`undefined` preserves existing proofs as-is.
|
|
710
|
+
*/
|
|
711
|
+
readonly normalizeExistingProofs?: boolean;
|
|
703
712
|
readonly traceContext: Readonly<Record<string, string>>;
|
|
704
713
|
}
|
|
705
714
|
interface OutboxMessage {
|
|
@@ -2666,6 +2675,19 @@ interface SendActivityOptions {
|
|
|
2666
2675
|
*/
|
|
2667
2676
|
readonly fanout?: "auto" | "skip" | "force";
|
|
2668
2677
|
/**
|
|
2678
|
+
* Whether to apply Fedify's outgoing JSON-LD wire-format compatibility fixes
|
|
2679
|
+
* to activities that already carry Object Integrity Proofs.
|
|
2680
|
+
*
|
|
2681
|
+
* By default, Fedify preserves existing proofs byte-for-byte because it
|
|
2682
|
+
* cannot know whether they were created for the normalized outgoing wire
|
|
2683
|
+
* form. Set this to `true` when sending an activity that was pre-signed
|
|
2684
|
+
* locally with `signObject()` or `createProof()`, so the emitted
|
|
2685
|
+
* compact JSON-LD matches the bytes covered by the proof.
|
|
2686
|
+
*
|
|
2687
|
+
* @since 2.2.0
|
|
2688
|
+
*/
|
|
2689
|
+
readonly normalizeExistingProofs?: boolean;
|
|
2690
|
+
/**
|
|
2669
2691
|
* The base URIs to exclude from the recipients' inboxes. It is useful
|
|
2670
2692
|
* for excluding the recipients having the same shared inbox with the sender.
|
|
2671
2693
|
*
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "@js-temporal/polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { o as validateCryptoKey } from "./key-
|
|
5
|
-
import { n as doubleKnock } from "./http-
|
|
4
|
+
import { o as validateCryptoKey } from "./key-CjAnbVVw.mjs";
|
|
5
|
+
import { n as doubleKnock } from "./http-FJABWPPb.mjs";
|
|
6
6
|
import { curry } from "es-toolkit";
|
|
7
7
|
import { UrlError, createActivityPubRequest, getRemoteDocument, logRequest, validatePublicUrl } from "@fedify/vocab-runtime";
|
|
8
8
|
import { getLogger } from "@logtape/logtape";
|
|
@@ -3,10 +3,10 @@ import "urlpattern-polyfill";
|
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { n as RouterError } from "../router-CrMLXoOr.mjs";
|
|
5
5
|
import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
|
|
6
|
-
import {
|
|
6
|
+
import { i as assertExists } from "../std__assert-CRDpx_HF.mjs";
|
|
7
7
|
import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
|
|
8
|
-
import { t as MemoryKvStore } from "../kv-
|
|
9
|
-
import { n as createFederationBuilder } from "../builder-
|
|
8
|
+
import { t as MemoryKvStore } from "../kv-rV3vodCc.mjs";
|
|
9
|
+
import { n as createFederationBuilder } from "../builder-Baov5O1s.mjs";
|
|
10
10
|
import { test } from "@fedify/fixture";
|
|
11
11
|
import { Activity, Note, Person } from "@fedify/vocab";
|
|
12
12
|
//#region src/federation/builder.test.ts
|
|
@@ -2,8 +2,8 @@ import "@js-temporal/polyfill";
|
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
|
|
5
|
-
import "../std__assert-
|
|
6
|
-
import { n as digest, t as buildCollectionSynchronizationHeader } from "../collection-
|
|
5
|
+
import "../std__assert-CRDpx_HF.mjs";
|
|
6
|
+
import { n as digest, t as buildCollectionSynchronizationHeader } from "../collection-D-HqUuA2.mjs";
|
|
7
7
|
import { test } from "@fedify/fixture";
|
|
8
8
|
import { decodeHex } from "byte-encodings/hex";
|
|
9
9
|
//#region src/federation/collection.test.ts
|
|
@@ -3,15 +3,15 @@ import "urlpattern-polyfill";
|
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { n as createOutboxContext, r as createRequestContext, t as createInboxContext } from "../context-Dk_tacqz.mjs";
|
|
5
5
|
import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
|
|
6
|
-
import "../std__assert-
|
|
6
|
+
import "../std__assert-CRDpx_HF.mjs";
|
|
7
7
|
import { t as assertInstanceOf } from "../assert_instance_of-C4Ri6VuN.mjs";
|
|
8
|
-
import { t as assert } from "../assert-
|
|
9
|
-
import { r as parseAcceptSignature } from "../accept-
|
|
10
|
-
import { s as signRequest } from "../http-
|
|
11
|
-
import { a as rsaPrivateKey3, c as rsaPublicKey3, s as rsaPublicKey2 } from "../keys-
|
|
12
|
-
import { t as MemoryKvStore } from "../kv-
|
|
13
|
-
import { c as handleActor, d as handleInbox, f as handleObject, h as respondWithObjectIfAcceptable, l as handleCollection, m as respondWithObject, o as createFederation, p as handleOutbox, u as handleCustomCollection } from "../middleware-
|
|
14
|
-
import { t as ActivityListenerSet } from "../activity-listener-
|
|
8
|
+
import { t as assert } from "../assert-DikXweDx.mjs";
|
|
9
|
+
import { r as parseAcceptSignature } from "../accept-CPkZzmGN.mjs";
|
|
10
|
+
import { s as signRequest } from "../http-FJABWPPb.mjs";
|
|
11
|
+
import { a as rsaPrivateKey3, c as rsaPublicKey3, s as rsaPublicKey2 } from "../keys-DGu1NFwu.mjs";
|
|
12
|
+
import { t as MemoryKvStore } from "../kv-rV3vodCc.mjs";
|
|
13
|
+
import { c as handleActor, d as handleInbox, f as handleObject, h as respondWithObjectIfAcceptable, l as handleCollection, m as respondWithObject, o as createFederation, p as handleOutbox, u as handleCustomCollection } from "../middleware-BBn1W0f9.mjs";
|
|
14
|
+
import { t as ActivityListenerSet } from "../activity-listener-ell7W1s9.mjs";
|
|
15
15
|
import { createTestTracerProvider, mockDocumentLoader, test } from "@fedify/fixture";
|
|
16
16
|
import { Activity, Create, Note, Person, Tombstone } from "@fedify/vocab";
|
|
17
17
|
import { FetchError } from "@fedify/vocab-runtime";
|
|
@@ -2,11 +2,11 @@ import "@js-temporal/polyfill";
|
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
|
|
5
|
-
import "../std__assert-
|
|
6
|
-
import { n as ed25519PrivateKey, r as ed25519PublicKey, t as ed25519Multikey } from "../keys-
|
|
7
|
-
import { r as signObject } from "../proof-
|
|
8
|
-
import { t as MemoryKvStore } from "../kv-
|
|
9
|
-
import { o as createFederation } from "../middleware-
|
|
5
|
+
import "../std__assert-CRDpx_HF.mjs";
|
|
6
|
+
import { n as ed25519PrivateKey, r as ed25519PublicKey, t as ed25519Multikey } from "../keys-DGu1NFwu.mjs";
|
|
7
|
+
import { r as signObject } from "../proof-I8sYnUWs.mjs";
|
|
8
|
+
import { t as MemoryKvStore } from "../kv-rV3vodCc.mjs";
|
|
9
|
+
import { o as createFederation } from "../middleware-BBn1W0f9.mjs";
|
|
10
10
|
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
11
11
|
import { Create, Follow, Person } from "@fedify/vocab";
|
|
12
12
|
//#region src/federation/idempotency.test.ts
|
|
@@ -3,7 +3,7 @@ import "urlpattern-polyfill";
|
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
|
|
5
5
|
import { t as assertThrows } from "../assert_throws-4NwKEy2q.mjs";
|
|
6
|
-
import { t as ActivityListenerSet } from "../activity-listener-
|
|
6
|
+
import { t as ActivityListenerSet } from "../activity-listener-ell7W1s9.mjs";
|
|
7
7
|
import { test } from "@fedify/fixture";
|
|
8
8
|
import { Activity, Create, Invite, Offer, Update } from "@fedify/vocab";
|
|
9
9
|
//#region src/federation/inbox.test.ts
|
|
@@ -3,9 +3,9 @@ import "urlpattern-polyfill";
|
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { t as assertEquals } from "../assert_equals-Ew3jOFa3.mjs";
|
|
5
5
|
import { t as assertInstanceOf } from "../assert_instance_of-C4Ri6VuN.mjs";
|
|
6
|
-
import { t as assert } from "../assert-
|
|
7
|
-
import { t as MemoryKvStore } from "../kv-
|
|
8
|
-
import { t as KvKeyCache } from "../keycache-
|
|
6
|
+
import { t as assert } from "../assert-DikXweDx.mjs";
|
|
7
|
+
import { t as MemoryKvStore } from "../kv-rV3vodCc.mjs";
|
|
8
|
+
import { t as KvKeyCache } from "../keycache-EGATflN-.mjs";
|
|
9
9
|
import { test } from "@fedify/fixture";
|
|
10
10
|
import { CryptographicKey, Multikey } from "@fedify/vocab";
|
|
11
11
|
//#region src/federation/keycache.test.ts
|