@fedify/vocab 2.5.0-dev.2448 → 2.5.0-dev.2494
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/deno.json +1 -1
- package/dist/mod.cjs +80 -3
- package/dist/mod.d.cts +75 -0
- package/dist/mod.d.ts +75 -0
- package/dist/mod.js +80 -3
- package/dist-tests/{actor-C93GLWk5.mjs → actor-CW4MtXG3.mjs} +6 -4
- package/dist-tests/actor.test.mjs +4 -3
- package/dist-tests/{esm-DtAfYdqR.mjs → esm-BIqRhjGA.mjs} +1 -1
- package/dist-tests/gateway.test.mjs +4 -4
- package/dist-tests/license.test.mjs +2 -2
- package/dist-tests/{lookup-C4i0dNeY.mjs → lookup-DFHFanoB.mjs} +2 -2
- package/dist-tests/lookup.test.mjs +35 -15
- package/dist-tests/portable-lookup.test.mjs +52 -13
- package/dist-tests/rolldown-runtime-BWJg4WE8.mjs +37 -0
- package/dist-tests/signed-representation.test.mjs +1 -1
- package/dist-tests/{src-Dn87CPDV.mjs → src-CiJ-s7w0.mjs} +3 -3
- package/dist-tests/translation.test.mjs +2 -2
- package/dist-tests/type.test.mjs +1 -1
- package/dist-tests/undici-D88PC0XH.mjs +22898 -0
- package/dist-tests/{vocab-jHKm_LJ6.mjs → vocab-BMEyHiOV.mjs} +77 -34
- package/dist-tests/vocab.test.mjs +6064 -8
- package/package.json +5 -5
- package/src/actor.ts +4 -0
- package/src/gateway.test.ts +1 -1
- package/src/lookup.test.ts +37 -11
- package/src/portable-lookup.test.ts +72 -7
- package/src/vocab.test.ts +40 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fedify/vocab",
|
|
3
|
-
"version": "2.5.0-dev.
|
|
3
|
+
"version": "2.5.0-dev.2494+f2e9b5d3",
|
|
4
4
|
"homepage": "https://fedify.dev/",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -37,15 +37,15 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@multiformats/base-x": "^4.0.1",
|
|
39
39
|
"@logtape/logtape": "^2.2.0",
|
|
40
|
-
"@opentelemetry/api": "
|
|
40
|
+
"@opentelemetry/api": "~1.9.1",
|
|
41
41
|
"asn1js": "^3.0.10",
|
|
42
42
|
"es-toolkit": "1.46.1",
|
|
43
43
|
"jsonld": "^9.0.0",
|
|
44
44
|
"pkijs": "^3.3.3",
|
|
45
45
|
"temporal-polyfill": "^1.0.1",
|
|
46
|
-
"@fedify/vocab-tools": "2.5.0-dev.
|
|
47
|
-
"@fedify/webfinger": "2.5.0-dev.
|
|
48
|
-
"@fedify/vocab-runtime": "2.5.0-dev.
|
|
46
|
+
"@fedify/vocab-tools": "2.5.0-dev.2494+f2e9b5d3",
|
|
47
|
+
"@fedify/webfinger": "2.5.0-dev.2494+f2e9b5d3",
|
|
48
|
+
"@fedify/vocab-runtime": "2.5.0-dev.2494+f2e9b5d3"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@types/node": "^24.12.2",
|
package/src/actor.ts
CHANGED
|
@@ -394,6 +394,8 @@ async function getPortableActorHandle(
|
|
|
394
394
|
userAgent: options.userAgent,
|
|
395
395
|
tracerProvider: options.tracerProvider,
|
|
396
396
|
meterProvider: options.meterProvider,
|
|
397
|
+
allowPrivateAddress: "allowPrivateAddress" in options &&
|
|
398
|
+
options.allowPrivateAddress === true,
|
|
397
399
|
});
|
|
398
400
|
// Unlike an ordinary actor, whose ID vouches for its host, a portable
|
|
399
401
|
// actor's gateways are claimed by the actor itself, so there is no
|
|
@@ -409,6 +411,8 @@ async function getPortableActorHandle(
|
|
|
409
411
|
userAgent: options.userAgent,
|
|
410
412
|
tracerProvider: options.tracerProvider,
|
|
411
413
|
meterProvider: options.meterProvider,
|
|
414
|
+
allowPrivateAddress: "allowPrivateAddress" in options &&
|
|
415
|
+
options.allowPrivateAddress === true,
|
|
412
416
|
});
|
|
413
417
|
if (
|
|
414
418
|
subjectResult != null && linksToPortableActor(subjectResult, canonicalId)
|
package/src/gateway.test.ts
CHANGED
|
@@ -876,7 +876,7 @@ test("getObject() sends the ActivityStreams Accept header to gateways", {
|
|
|
876
876
|
});
|
|
877
877
|
try {
|
|
878
878
|
const object = await (await createActivity()).getObject({
|
|
879
|
-
documentLoader: getDocumentLoader(),
|
|
879
|
+
documentLoader: getDocumentLoader({ allowPrivateAddress: true }),
|
|
880
880
|
contextLoader: mockDocumentLoader,
|
|
881
881
|
gateways: ["https://example.com"],
|
|
882
882
|
verifyPortableObject: createVerifier(),
|
package/src/lookup.test.ts
CHANGED
|
@@ -18,10 +18,17 @@ import { lookupObject, lookupObserver, traverseCollection } from "./lookup.ts";
|
|
|
18
18
|
import { assertInstanceOf } from "./utils.ts";
|
|
19
19
|
import { Collection, Note, Object, Person } from "./vocab.ts";
|
|
20
20
|
|
|
21
|
+
// lookupObject() accepts this option without declaring it, since Fedify's
|
|
22
|
+
// Context passes it. It makes WebFinger lookups use the global fetch()
|
|
23
|
+
// (fetch-mock here) without resolving hostnames, so that the tests do not
|
|
24
|
+
// depend on the real DNS:
|
|
25
|
+
const allowPrivateAddress = { allowPrivateAddress: true };
|
|
26
|
+
|
|
21
27
|
test("lookupObject()", {
|
|
22
28
|
sanitizeResources: false,
|
|
23
29
|
sanitizeOps: false,
|
|
24
30
|
}, async (t) => {
|
|
31
|
+
const responseTimers: ReturnType<typeof setTimeout>[] = [];
|
|
25
32
|
fetchMock.spyGlobal();
|
|
26
33
|
|
|
27
34
|
fetchMock.get(
|
|
@@ -51,6 +58,7 @@ test("lookupObject()", {
|
|
|
51
58
|
const options = {
|
|
52
59
|
documentLoader: mockDocumentLoader,
|
|
53
60
|
contextLoader: mockDocumentLoader,
|
|
61
|
+
...allowPrivateAddress,
|
|
54
62
|
};
|
|
55
63
|
|
|
56
64
|
await t.step("actor", async () => {
|
|
@@ -114,7 +122,7 @@ test("lookupObject()", {
|
|
|
114
122
|
"begin:https://example.com/.well-known/webfinger",
|
|
115
123
|
() =>
|
|
116
124
|
new Promise((resolve) => {
|
|
117
|
-
setTimeout(() => {
|
|
125
|
+
responseTimers.push(setTimeout(() => {
|
|
118
126
|
resolve({
|
|
119
127
|
subject: "acct:johndoe@example.com",
|
|
120
128
|
links: [
|
|
@@ -125,7 +133,7 @@ test("lookupObject()", {
|
|
|
125
133
|
},
|
|
126
134
|
],
|
|
127
135
|
});
|
|
128
|
-
}, 1000);
|
|
136
|
+
}, 1000));
|
|
129
137
|
}),
|
|
130
138
|
);
|
|
131
139
|
|
|
@@ -170,7 +178,7 @@ test("lookupObject()", {
|
|
|
170
178
|
"begin:https://example.com/.well-known/webfinger",
|
|
171
179
|
() =>
|
|
172
180
|
new Promise((resolve) => {
|
|
173
|
-
setTimeout(() => {
|
|
181
|
+
responseTimers.push(setTimeout(() => {
|
|
174
182
|
resolve({
|
|
175
183
|
subject: "acct:johndoe@example.com",
|
|
176
184
|
links: [
|
|
@@ -181,7 +189,7 @@ test("lookupObject()", {
|
|
|
181
189
|
},
|
|
182
190
|
],
|
|
183
191
|
});
|
|
184
|
-
}, 500);
|
|
192
|
+
}, 500));
|
|
185
193
|
}),
|
|
186
194
|
);
|
|
187
195
|
|
|
@@ -201,7 +209,7 @@ test("lookupObject()", {
|
|
|
201
209
|
"https://example.com/slow-object",
|
|
202
210
|
() =>
|
|
203
211
|
new Promise((resolve) => {
|
|
204
|
-
setTimeout(() => {
|
|
212
|
+
responseTimers.push(setTimeout(() => {
|
|
205
213
|
resolve({
|
|
206
214
|
status: 200,
|
|
207
215
|
headers: { "Content-Type": "application/activity+json" },
|
|
@@ -211,7 +219,7 @@ test("lookupObject()", {
|
|
|
211
219
|
content: "Slow response",
|
|
212
220
|
},
|
|
213
221
|
});
|
|
214
|
-
}, 1000);
|
|
222
|
+
}, 1000));
|
|
215
223
|
}),
|
|
216
224
|
);
|
|
217
225
|
|
|
@@ -226,6 +234,7 @@ test("lookupObject()", {
|
|
|
226
234
|
deepStrictEqual(await promise, null);
|
|
227
235
|
});
|
|
228
236
|
|
|
237
|
+
for (const timer of responseTimers) clearTimeout(timer);
|
|
229
238
|
fetchMock.hardReset();
|
|
230
239
|
fetchMock.removeRoutes();
|
|
231
240
|
});
|
|
@@ -609,6 +618,7 @@ test("FEP-fe34: lookupObject() cross-origin security", {
|
|
|
609
618
|
|
|
610
619
|
// Default behavior should return null
|
|
611
620
|
const result1 = await lookupObject("@user@example.com", {
|
|
621
|
+
...allowPrivateAddress,
|
|
612
622
|
documentLoader: webfingerDocumentLoader,
|
|
613
623
|
contextLoader: mockDocumentLoader,
|
|
614
624
|
});
|
|
@@ -618,6 +628,7 @@ test("FEP-fe34: lookupObject() cross-origin security", {
|
|
|
618
628
|
await rejects(
|
|
619
629
|
() =>
|
|
620
630
|
lookupObject("@user@example.com", {
|
|
631
|
+
...allowPrivateAddress,
|
|
621
632
|
documentLoader: webfingerDocumentLoader,
|
|
622
633
|
contextLoader: mockDocumentLoader,
|
|
623
634
|
crossOrigin: "throw",
|
|
@@ -628,6 +639,7 @@ test("FEP-fe34: lookupObject() cross-origin security", {
|
|
|
628
639
|
|
|
629
640
|
// With crossOrigin: trust, should return the object
|
|
630
641
|
const result2 = await lookupObject("@user@example.com", {
|
|
642
|
+
...allowPrivateAddress,
|
|
631
643
|
documentLoader: webfingerDocumentLoader,
|
|
632
644
|
contextLoader: mockDocumentLoader,
|
|
633
645
|
crossOrigin: "trust",
|
|
@@ -727,12 +739,22 @@ test("FEP-fe34: lookupObject() cross-origin security", {
|
|
|
727
739
|
throw new Error("Network error");
|
|
728
740
|
};
|
|
729
741
|
|
|
742
|
+
// The WebFinger fallback must not reach the network:
|
|
743
|
+
fetchMock.spyGlobal();
|
|
744
|
+
fetchMock.get("begin:https://example.com/.well-known/webfinger", 404);
|
|
745
|
+
|
|
730
746
|
// Network errors should not be confused with cross-origin errors
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
747
|
+
let result;
|
|
748
|
+
try {
|
|
749
|
+
result = await lookupObject("https://example.com/note", {
|
|
750
|
+
...allowPrivateAddress,
|
|
751
|
+
documentLoader: errorDocumentLoader,
|
|
752
|
+
contextLoader: mockDocumentLoader,
|
|
753
|
+
crossOrigin: "throw",
|
|
754
|
+
});
|
|
755
|
+
} finally {
|
|
756
|
+
fetchMock.hardReset();
|
|
757
|
+
}
|
|
736
758
|
|
|
737
759
|
// Should return null because the document loader failed,
|
|
738
760
|
// not because of cross-origin policy
|
|
@@ -850,6 +872,7 @@ test("lookupObject() records activitypub.object.lookup counter", {
|
|
|
850
872
|
await t.step("records kind=actor for an actor result", async () => {
|
|
851
873
|
const [meterProvider, recorder] = createTestMeterProvider();
|
|
852
874
|
const person = await lookupObject("@johndoe@example.com", {
|
|
875
|
+
...allowPrivateAddress,
|
|
853
876
|
documentLoader: mockDocumentLoader,
|
|
854
877
|
contextLoader: mockDocumentLoader,
|
|
855
878
|
meterProvider,
|
|
@@ -936,6 +959,7 @@ test("lookupObject() records activitypub.object.lookup counter", {
|
|
|
936
959
|
});
|
|
937
960
|
const [meterProvider, recorder] = createTestMeterProvider();
|
|
938
961
|
const result = await lookupObject("janedoe@example.com", {
|
|
962
|
+
...allowPrivateAddress,
|
|
939
963
|
documentLoader: mockDocumentLoader,
|
|
940
964
|
contextLoader: mockDocumentLoader,
|
|
941
965
|
meterProvider,
|
|
@@ -987,6 +1011,7 @@ test("lookupObject() records activitypub.object.lookup counter", {
|
|
|
987
1011
|
);
|
|
988
1012
|
const [meterProvider, recorder] = createTestMeterProvider();
|
|
989
1013
|
await lookupObject("@johndoe@example.com", {
|
|
1014
|
+
...allowPrivateAddress,
|
|
990
1015
|
documentLoader: mockDocumentLoader,
|
|
991
1016
|
contextLoader: mockDocumentLoader,
|
|
992
1017
|
meterProvider,
|
|
@@ -1020,6 +1045,7 @@ test("lookupObject() records activitypub.object.lookup counter", {
|
|
|
1020
1045
|
});
|
|
1021
1046
|
const [meterProvider, recorder] = createTestMeterProvider();
|
|
1022
1047
|
await lookupObject(new URL("acct:johndoe@example.com"), {
|
|
1048
|
+
...allowPrivateAddress,
|
|
1023
1049
|
documentLoader: mockDocumentLoader,
|
|
1024
1050
|
contextLoader: mockDocumentLoader,
|
|
1025
1051
|
meterProvider,
|
|
@@ -14,6 +14,9 @@ import { lookupObject } from "./lookup.ts";
|
|
|
14
14
|
import { assertInstanceOf } from "./utils.ts";
|
|
15
15
|
import { Person } from "./vocab.ts";
|
|
16
16
|
|
|
17
|
+
// Runtime-only transport override for hostname-based WebFinger mocks.
|
|
18
|
+
const allowPrivateAddress = { allowPrivateAddress: true };
|
|
19
|
+
|
|
17
20
|
const did = "did:key:z6Mkabc";
|
|
18
21
|
const actorId = `ap+ef61://${did}/actor`;
|
|
19
22
|
const gatewayPath = `/.well-known/apgateway/${did}/actor`;
|
|
@@ -92,6 +95,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
|
|
|
92
95
|
const actor = await lookupObject("@alice@example.com", {
|
|
93
96
|
documentLoader,
|
|
94
97
|
contextLoader: mockDocumentLoader,
|
|
98
|
+
...allowPrivateAddress,
|
|
95
99
|
verifyPortableObject,
|
|
96
100
|
});
|
|
97
101
|
assertInstanceOf(actor, Person);
|
|
@@ -118,6 +122,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
|
|
|
118
122
|
const actor = await lookupObject("@alice@example.com", {
|
|
119
123
|
documentLoader,
|
|
120
124
|
contextLoader: mockDocumentLoader,
|
|
125
|
+
...allowPrivateAddress,
|
|
121
126
|
verifyPortableObject: createVerifier(),
|
|
122
127
|
});
|
|
123
128
|
assertInstanceOf(actor, Person);
|
|
@@ -138,6 +143,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
|
|
|
138
143
|
const actor = await lookupObject("@alice@example.com", {
|
|
139
144
|
documentLoader,
|
|
140
145
|
contextLoader: mockDocumentLoader,
|
|
146
|
+
...allowPrivateAddress,
|
|
141
147
|
verifyPortableObject: createVerifier(),
|
|
142
148
|
gateways: ["https://second.example"],
|
|
143
149
|
});
|
|
@@ -153,6 +159,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
|
|
|
153
159
|
await lookupObject("@alice@example.com", {
|
|
154
160
|
documentLoader,
|
|
155
161
|
contextLoader: mockDocumentLoader,
|
|
162
|
+
...allowPrivateAddress,
|
|
156
163
|
verifyPortableObject: createVerifier(),
|
|
157
164
|
gateways: Array.from(
|
|
158
165
|
{ length: 6 },
|
|
@@ -178,6 +185,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
|
|
|
178
185
|
const actor = await lookupObject("@alice@example.com", {
|
|
179
186
|
documentLoader,
|
|
180
187
|
contextLoader: mockDocumentLoader,
|
|
188
|
+
...allowPrivateAddress,
|
|
181
189
|
verifyPortableObject: createVerifier(),
|
|
182
190
|
});
|
|
183
191
|
assertInstanceOf(actor, Person);
|
|
@@ -197,6 +205,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
|
|
|
197
205
|
const actor = await lookupObject("@alice@example.com", {
|
|
198
206
|
documentLoader,
|
|
199
207
|
contextLoader: mockDocumentLoader,
|
|
208
|
+
...allowPrivateAddress,
|
|
200
209
|
verifyPortableObject,
|
|
201
210
|
});
|
|
202
211
|
assertInstanceOf(actor, Person);
|
|
@@ -227,6 +236,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
|
|
|
227
236
|
await lookupObject("@alice@example.com", {
|
|
228
237
|
documentLoader,
|
|
229
238
|
contextLoader: mockDocumentLoader,
|
|
239
|
+
...allowPrivateAddress,
|
|
230
240
|
verifyPortableObject,
|
|
231
241
|
}),
|
|
232
242
|
null,
|
|
@@ -239,6 +249,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
|
|
|
239
249
|
lookupObject("@alice@example.com", {
|
|
240
250
|
documentLoader,
|
|
241
251
|
contextLoader: mockDocumentLoader,
|
|
252
|
+
...allowPrivateAddress,
|
|
242
253
|
verifyPortableObject,
|
|
243
254
|
crossOrigin: "throw",
|
|
244
255
|
}),
|
|
@@ -248,6 +259,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
|
|
|
248
259
|
await lookupObject("@alice@example.com", {
|
|
249
260
|
documentLoader,
|
|
250
261
|
contextLoader: mockDocumentLoader,
|
|
262
|
+
...allowPrivateAddress,
|
|
251
263
|
verifyPortableObject,
|
|
252
264
|
crossOrigin: "trust",
|
|
253
265
|
}),
|
|
@@ -270,6 +282,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
|
|
|
270
282
|
await lookupObject("@alice@example.com", {
|
|
271
283
|
documentLoader,
|
|
272
284
|
contextLoader: mockDocumentLoader,
|
|
285
|
+
...allowPrivateAddress,
|
|
273
286
|
crossOrigin,
|
|
274
287
|
}),
|
|
275
288
|
null,
|
|
@@ -281,6 +294,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
|
|
|
281
294
|
lookupObject("@alice@example.com", {
|
|
282
295
|
documentLoader,
|
|
283
296
|
contextLoader: mockDocumentLoader,
|
|
297
|
+
...allowPrivateAddress,
|
|
284
298
|
crossOrigin: "throw",
|
|
285
299
|
}),
|
|
286
300
|
/has a different origin than the document URL/,
|
|
@@ -292,6 +306,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
|
|
|
292
306
|
const actor = await lookupObject("@alice@example.com", {
|
|
293
307
|
documentLoader: httpLoader,
|
|
294
308
|
contextLoader: mockDocumentLoader,
|
|
309
|
+
...allowPrivateAddress,
|
|
295
310
|
});
|
|
296
311
|
assertInstanceOf(actor, Person);
|
|
297
312
|
deepStrictEqual(actor.id, new URL(compatibleId));
|
|
@@ -303,6 +318,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
|
|
|
303
318
|
const ordinary = await lookupObject(malformed, {
|
|
304
319
|
documentLoader: ordinaryLoader,
|
|
305
320
|
contextLoader: mockDocumentLoader,
|
|
321
|
+
...allowPrivateAddress,
|
|
306
322
|
});
|
|
307
323
|
assertInstanceOf(ordinary, Person);
|
|
308
324
|
deepStrictEqual(ordinaryLoader.fetched, [malformed]);
|
|
@@ -321,6 +337,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
|
|
|
321
337
|
const options = {
|
|
322
338
|
documentLoader,
|
|
323
339
|
contextLoader: mockDocumentLoader,
|
|
340
|
+
...allowPrivateAddress,
|
|
324
341
|
verifyPortableObject: createVerifier(),
|
|
325
342
|
};
|
|
326
343
|
equal(await lookupObject("@alice@example.com", options), null);
|
|
@@ -341,6 +358,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
|
|
|
341
358
|
const options = {
|
|
342
359
|
documentLoader,
|
|
343
360
|
contextLoader: mockDocumentLoader,
|
|
361
|
+
...allowPrivateAddress,
|
|
344
362
|
verifyPortableObject: createVerifier(),
|
|
345
363
|
};
|
|
346
364
|
equal(await lookupObject(dotted, options), null);
|
|
@@ -368,6 +386,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
|
|
|
368
386
|
await lookupObject("@alice@example.com", {
|
|
369
387
|
documentLoader,
|
|
370
388
|
contextLoader: mockDocumentLoader,
|
|
389
|
+
...allowPrivateAddress,
|
|
371
390
|
verifyPortableObject: createVerifier(),
|
|
372
391
|
}),
|
|
373
392
|
null,
|
|
@@ -397,6 +416,7 @@ test("lookupObject() with FEP-ef61 portable actors", {
|
|
|
397
416
|
await lookupObject("@alice@example.com", {
|
|
398
417
|
documentLoader,
|
|
399
418
|
contextLoader: mockDocumentLoader,
|
|
419
|
+
...allowPrivateAddress,
|
|
400
420
|
verifyPortableObject,
|
|
401
421
|
signal: controller.signal,
|
|
402
422
|
}),
|
|
@@ -573,13 +593,25 @@ test("getActorHandle() with FEP-ef61 portable actors", {
|
|
|
573
593
|
"https://example.com/.well-known/webfinger?resource=acct%3Aalice%40example.com",
|
|
574
594
|
selfLinks(compatibleId),
|
|
575
595
|
);
|
|
576
|
-
deepStrictEqual(
|
|
596
|
+
deepStrictEqual(
|
|
597
|
+
await getActorHandle(actor, {
|
|
598
|
+
...allowPrivateAddress,
|
|
599
|
+
userAgent: undefined,
|
|
600
|
+
}),
|
|
601
|
+
"@alice@example.com",
|
|
602
|
+
);
|
|
577
603
|
});
|
|
578
604
|
|
|
579
605
|
await t.step("canonical self link", async () => {
|
|
580
606
|
fetchMock.removeRoutes();
|
|
581
607
|
fetchMock.get(webFingerPrefix, selfLinks(`ap://${did}/actor`));
|
|
582
|
-
deepStrictEqual(
|
|
608
|
+
deepStrictEqual(
|
|
609
|
+
await getActorHandle(actor, {
|
|
610
|
+
...allowPrivateAddress,
|
|
611
|
+
userAgent: undefined,
|
|
612
|
+
}),
|
|
613
|
+
"@alice@example.com",
|
|
614
|
+
);
|
|
583
615
|
});
|
|
584
616
|
|
|
585
617
|
await t.step("follows a verified subject", async () => {
|
|
@@ -592,7 +624,13 @@ test("getActorHandle() with FEP-ef61 portable actors", {
|
|
|
592
624
|
"begin:https://example.org/.well-known/webfinger",
|
|
593
625
|
{ ...selfLinks(compatibleId), subject: "acct:alice@example.org" },
|
|
594
626
|
);
|
|
595
|
-
deepStrictEqual(
|
|
627
|
+
deepStrictEqual(
|
|
628
|
+
await getActorHandle(actor, {
|
|
629
|
+
...allowPrivateAddress,
|
|
630
|
+
userAgent: undefined,
|
|
631
|
+
}),
|
|
632
|
+
"@alice@example.org",
|
|
633
|
+
);
|
|
596
634
|
|
|
597
635
|
// An unverified subject is ignored:
|
|
598
636
|
fetchMock.removeRoutes();
|
|
@@ -604,7 +642,13 @@ test("getActorHandle() with FEP-ef61 portable actors", {
|
|
|
604
642
|
"begin:https://example.org/.well-known/webfinger",
|
|
605
643
|
selfLinks(`ap://${did}/other`),
|
|
606
644
|
);
|
|
607
|
-
deepStrictEqual(
|
|
645
|
+
deepStrictEqual(
|
|
646
|
+
await getActorHandle(actor, {
|
|
647
|
+
...allowPrivateAddress,
|
|
648
|
+
userAgent: undefined,
|
|
649
|
+
}),
|
|
650
|
+
"@alice@example.com",
|
|
651
|
+
);
|
|
608
652
|
});
|
|
609
653
|
|
|
610
654
|
await t.step("rejects a WebFinger response for another actor", async () => {
|
|
@@ -617,14 +661,28 @@ test("getActorHandle() with FEP-ef61 portable actors", {
|
|
|
617
661
|
) {
|
|
618
662
|
fetchMock.removeRoutes();
|
|
619
663
|
fetchMock.get(webFingerPrefix, jrd);
|
|
620
|
-
await rejects(
|
|
664
|
+
await rejects(
|
|
665
|
+
() =>
|
|
666
|
+
getActorHandle(actor, {
|
|
667
|
+
...allowPrivateAddress,
|
|
668
|
+
userAgent: undefined,
|
|
669
|
+
}),
|
|
670
|
+
TypeError,
|
|
671
|
+
);
|
|
621
672
|
}
|
|
622
673
|
});
|
|
623
674
|
|
|
624
675
|
await t.step("does not fall back when WebFinger fails", async () => {
|
|
625
676
|
fetchMock.removeRoutes();
|
|
626
677
|
fetchMock.get(webFingerPrefix, 404);
|
|
627
|
-
await rejects(
|
|
678
|
+
await rejects(
|
|
679
|
+
() =>
|
|
680
|
+
getActorHandle(actor, {
|
|
681
|
+
...allowPrivateAddress,
|
|
682
|
+
userAgent: undefined,
|
|
683
|
+
}),
|
|
684
|
+
TypeError,
|
|
685
|
+
);
|
|
628
686
|
});
|
|
629
687
|
|
|
630
688
|
await t.step("not enough information", async () => {
|
|
@@ -640,7 +698,14 @@ test("getActorHandle() with FEP-ef61 portable actors", {
|
|
|
640
698
|
}),
|
|
641
699
|
]
|
|
642
700
|
) {
|
|
643
|
-
await rejects(
|
|
701
|
+
await rejects(
|
|
702
|
+
() =>
|
|
703
|
+
getActorHandle(target, {
|
|
704
|
+
...allowPrivateAddress,
|
|
705
|
+
userAgent: undefined,
|
|
706
|
+
}),
|
|
707
|
+
TypeError,
|
|
708
|
+
);
|
|
644
709
|
}
|
|
645
710
|
deepStrictEqual(fetchMock.callHistory.calls().length, 0);
|
|
646
711
|
});
|
package/src/vocab.test.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { createDocumentLoader } from "../../vocab-runtime/src/docloader.ts";
|
|
2
|
+
import { createPublicFetch } from "../../vocab-runtime/src/public-fetch.ts";
|
|
1
3
|
import { mockDocumentLoader, test } from "@fedify/fixture";
|
|
2
4
|
import {
|
|
3
5
|
decodeMultibase,
|
|
@@ -1996,7 +1998,14 @@ test({
|
|
|
1996
1998
|
const activity2 = new Activity({
|
|
1997
1999
|
object: new URL("https://example.com/not-found"),
|
|
1998
2000
|
});
|
|
1999
|
-
deepStrictEqual(
|
|
2001
|
+
deepStrictEqual(
|
|
2002
|
+
await activity2.getObject({
|
|
2003
|
+
documentLoader: mockDocumentLoader,
|
|
2004
|
+
contextLoader: mockDocumentLoader,
|
|
2005
|
+
suppressError: true,
|
|
2006
|
+
}),
|
|
2007
|
+
null,
|
|
2008
|
+
);
|
|
2000
2009
|
|
|
2001
2010
|
const activity3 = await Activity.fromJsonLd({
|
|
2002
2011
|
"@context": "https://www.w3.org/ns/activitystreams",
|
|
@@ -2208,7 +2217,11 @@ test({
|
|
|
2208
2217
|
],
|
|
2209
2218
|
});
|
|
2210
2219
|
const objects2 = await Array.fromAsync(
|
|
2211
|
-
activity2.getObjects({
|
|
2220
|
+
activity2.getObjects({
|
|
2221
|
+
documentLoader: mockDocumentLoader,
|
|
2222
|
+
contextLoader: mockDocumentLoader,
|
|
2223
|
+
suppressError: true,
|
|
2224
|
+
}),
|
|
2212
2225
|
);
|
|
2213
2226
|
deepStrictEqual(objects2.length, 1);
|
|
2214
2227
|
assertInstanceOf(objects2[0], Object);
|
|
@@ -6359,6 +6372,15 @@ for (const typeUri in types) {
|
|
|
6359
6372
|
}
|
|
6360
6373
|
|
|
6361
6374
|
test("Announce.getObject() suppresses redirect, context, and private URL logs", async () => {
|
|
6375
|
+
// Validate every hop, including private redirect targets, while keeping
|
|
6376
|
+
// hostname-based fetch mocks independent of runtime connection pinning.
|
|
6377
|
+
const publicFetch = createPublicFetch({
|
|
6378
|
+
pinner: () => Promise.resolve(null),
|
|
6379
|
+
lookup: () => Promise.resolve([{ address: "93.184.215.14", family: 4 }]),
|
|
6380
|
+
});
|
|
6381
|
+
const documentLoader = createDocumentLoader({}, {
|
|
6382
|
+
openHop: (url) => publicFetch.openPublicFetch(url),
|
|
6383
|
+
});
|
|
6362
6384
|
const records: LogRecord[] = [];
|
|
6363
6385
|
const objectUrl = "https://example.com/suppression-object";
|
|
6364
6386
|
const contextUrl = "https://example.com/suppression-context";
|
|
@@ -6420,7 +6442,14 @@ test("Announce.getObject() suppresses redirect, context, and private URL logs",
|
|
|
6420
6442
|
),
|
|
6421
6443
|
});
|
|
6422
6444
|
if (suppressError) {
|
|
6423
|
-
deepStrictEqual(
|
|
6445
|
+
deepStrictEqual(
|
|
6446
|
+
await announce.getObject({
|
|
6447
|
+
suppressError,
|
|
6448
|
+
documentLoader,
|
|
6449
|
+
contextLoader: documentLoader,
|
|
6450
|
+
}),
|
|
6451
|
+
null,
|
|
6452
|
+
);
|
|
6424
6453
|
deepStrictEqual(
|
|
6425
6454
|
records.filter((r) => r.level === "error"),
|
|
6426
6455
|
[],
|
|
@@ -6428,7 +6457,13 @@ test("Announce.getObject() suppresses redirect, context, and private URL logs",
|
|
|
6428
6457
|
);
|
|
6429
6458
|
ok(records.some((r) => r.level === "warning"), scenario);
|
|
6430
6459
|
} else {
|
|
6431
|
-
await rejects(() =>
|
|
6460
|
+
await rejects(() =>
|
|
6461
|
+
announce.getObject({
|
|
6462
|
+
suppressError,
|
|
6463
|
+
documentLoader,
|
|
6464
|
+
contextLoader: documentLoader,
|
|
6465
|
+
})
|
|
6466
|
+
);
|
|
6432
6467
|
ok(records.some((r) => r.level === "error"), scenario);
|
|
6433
6468
|
}
|
|
6434
6469
|
if (scenario === "private") deepStrictEqual(fetches, 0);
|
|
@@ -6667,7 +6702,7 @@ test("portable verifiers suppress document logs only during dereferencing", asyn
|
|
|
6667
6702
|
try {
|
|
6668
6703
|
for (const suppressError of [true, false, undefined]) {
|
|
6669
6704
|
records.length = 0;
|
|
6670
|
-
const baseLoader = getDocumentLoader();
|
|
6705
|
+
const baseLoader = getDocumentLoader({ allowPrivateAddress: true });
|
|
6671
6706
|
const calls: Parameters<DocumentLoader>[1][] = [];
|
|
6672
6707
|
const documentLoader: DocumentLoader = (url, options) => {
|
|
6673
6708
|
calls.push(options);
|