@fedify/fedify 2.3.7 → 2.3.9-dev.2048
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_instance_of-DBC5X09g.mjs → assert-jSdZMYam.mjs} +19 -1
- package/dist/{builder-Bg7nkigw.mjs → builder-BfY2wZ4V.mjs} +3 -3
- package/dist/{client-D1KuWxjH.mjs → client-DYDoDpMa.mjs} +78 -4
- package/dist/compat/mod.d.cts +1 -1
- package/dist/compat/mod.d.ts +1 -1
- package/dist/compat/outgoing-jsonld.test.mjs +1 -1
- package/dist/compat/public-audience.test.mjs +1 -1
- package/dist/compat/transformers.test.mjs +3 -4
- package/dist/{context-DVoTs_wM.mjs → context-BepjCFHN.mjs} +1 -0
- package/dist/{context-BxVVO5Ro.d.ts → context-CAKnQy1x.d.ts} +4 -3
- package/dist/{context-BpmLyiPx.d.cts → context-CSIggG9_.d.cts} +4 -3
- package/dist/{deno-CTdCdRmf.mjs → deno-ayal9buz.mjs} +1 -1
- package/dist/{docloader-BVBWf8Bg.mjs → docloader-C-JrNL14.mjs} +2 -2
- package/dist/federation/builder.test.mjs +2 -2
- package/dist/federation/circuit-breaker.test.mjs +3 -3
- package/dist/federation/collection.test.mjs +1 -1
- package/dist/federation/handler.test.mjs +128 -11
- package/dist/federation/idempotency.test.mjs +4 -4
- package/dist/federation/inbox.test.mjs +1 -1
- package/dist/federation/keycache.test.mjs +44 -10
- package/dist/federation/kv.test.mjs +1 -1
- package/dist/federation/metrics.test.mjs +1 -1
- package/dist/federation/middleware.test.mjs +109 -19
- 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 +1 -1
- package/dist/federation/negotiation.test.mjs +2 -2
- package/dist/federation/retry.test.mjs +1 -1
- package/dist/federation/router.test.mjs +1 -1
- package/dist/federation/send.test.mjs +141 -7
- package/dist/federation/temporal.test.mjs +2 -2
- package/dist/federation/webfinger.test.mjs +3 -3
- package/dist/{http-B3-zan5-.mjs → http-B2u6PvNX.mjs} +4 -4
- package/dist/{http-BjV0BTWd.cjs → http-BGP2QCbe.cjs} +166 -6
- package/dist/{http-DRVY9K4R.js → http-BPPCh0xN.js} +155 -7
- package/dist/{http-lf8Hsd91.d.ts → http-DQmNpfym.d.ts} +1 -1
- package/dist/{http-VyDTd4G3.d.cts → http-DiWQB8Mr.d.cts} +1 -1
- package/dist/{key-C_a6iE1-.mjs → key-C9DkrWwb.mjs} +155 -7
- package/dist/{keycache-BeU0LCII.mjs → keycache-B3qRQNLj.mjs} +12 -4
- package/dist/{kv-cache-OzUoHKnZ.cjs → kv-cache-C1TC_e9y.cjs} +2 -2
- package/dist/{kv-cache-b1dJZHUx.js → kv-cache-Cl1q1aA9.js} +2 -2
- package/dist/{kv-cache-BjjcmjtG.mjs → kv-cache-qJSjfLGm.mjs} +1 -1
- package/dist/{ld-COo05yJj.mjs → ld-DNl7KwLY.mjs} +3 -3
- package/dist/{metrics-V6vX0M13.mjs → metrics-Ce55disp.mjs} +1 -1
- package/dist/{middleware-DRk6xiYo.mjs → middleware-BCG2BX1n.mjs} +41 -30
- package/dist/{middleware-EDVv6ewB.cjs → middleware-BZojifnF.cjs} +101 -25
- package/dist/{middleware-DRGWEo0V.mjs → middleware-C96wm_7x.mjs} +1 -1
- package/dist/{middleware-K13LhN5w.js → middleware-C_utyVa_.js} +101 -25
- package/dist/{mod-yvIXFAEi.d.cts → mod-1TuoXkGs.d.cts} +1 -1
- package/dist/{mod-B0hW12_O.d.cts → mod-Bid79LFU.d.cts} +1 -1
- package/dist/{mod-Rpy4Uwkk.d.ts → mod-CFuyfw3c.d.ts} +1 -1
- package/dist/{mod-DFvNJcNb.d.ts → mod-DHgc4ygG.d.ts} +1 -1
- package/dist/{mod-CjERT09F.d.cts → mod-PVR75MeU.d.cts} +1 -1
- package/dist/{mod-COIAjwRS.d.ts → mod-TLEvgT1i.d.ts} +1 -1
- package/dist/mod.cjs +5 -5
- package/dist/mod.d.cts +6 -6
- package/dist/mod.d.ts +6 -6
- package/dist/mod.js +5 -5
- package/dist/nodeinfo/client.test.mjs +28 -1
- package/dist/nodeinfo/handler.test.mjs +3 -3
- package/dist/nodeinfo/mod.cjs +1 -1
- package/dist/nodeinfo/mod.js +1 -1
- package/dist/nodeinfo/types.test.mjs +1 -1
- package/dist/otel/exporter.test.mjs +1 -1
- package/dist/{outgoing-jsonld-OFoubetZ.mjs → outgoing-jsonld-HOAywiid.mjs} +1 -1
- package/dist/{owner-CnngXDNJ.d.ts → owner-B3hNQCG8.d.cts} +12 -1
- package/dist/{owner-DEvZuyOE.d.cts → owner-CiBPcC6F.d.ts} +12 -1
- package/dist/owner-DqqDBw-l.mjs +175 -0
- package/dist/{proof-kFq0IDK4.mjs → proof-D5vP7VIN.mjs} +5 -5
- package/dist/{proof-D6gZeewf.js → proof-Dz9ObvUq.js} +112 -58
- package/dist/{proof-Xk8lHNc0.cjs → proof-I6YcKRRq.cjs} +112 -58
- package/dist/{send-3lH63Nqf.mjs → send-CBtR8DQK.mjs} +68 -11
- package/dist/sig/accept.test.mjs +1 -1
- package/dist/sig/http.test.mjs +4 -4
- package/dist/sig/key.test.mjs +170 -3
- package/dist/sig/ld.test.mjs +56 -4
- package/dist/sig/mod.cjs +2 -2
- package/dist/sig/mod.d.cts +3 -3
- package/dist/sig/mod.d.ts +3 -3
- package/dist/sig/mod.js +2 -2
- package/dist/sig/owner.test.mjs +105 -6
- package/dist/sig/proof.test.mjs +73 -5
- package/dist/{temporal-Chwx9cEn.mjs → temporal-B9t2tY9A.mjs} +1 -1
- package/dist/testing/mod.mjs +1 -1
- package/dist/{types-m8u9L86X.cjs → types-DWs-qZaY.cjs} +94 -2
- package/dist/{types-DTONwNqL.js → types-sXITXcWa.js} +78 -4
- package/dist/utils/docloader.test.mjs +28 -4
- package/dist/utils/kv-cache.test.mjs +1 -1
- package/dist/utils/mod.cjs +1 -1
- package/dist/utils/mod.d.cts +1 -1
- package/dist/utils/mod.d.ts +1 -1
- package/dist/utils/mod.js +1 -1
- package/package.json +6 -6
- package/dist/assert-OguE97r2.mjs +0 -23
- package/dist/owner-B3720pz3.mjs +0 -120
- /package/dist/{accept-CPkZzmGN.mjs → accept-Dd__NiUL.mjs} +0 -0
- /package/dist/{activity-listener-tztVvlNb.mjs → activity-listener-ell7W1s9.mjs} +0 -0
- /package/dist/{circuit-breaker-D1fxthDI.mjs → circuit-breaker-CDABzqVf.mjs} +0 -0
- /package/dist/{circuit-breaker-test-utils-CAdwjgMi.mjs → circuit-breaker-test-utils-Dm5MM6l9.mjs} +0 -0
- /package/dist/{collection-Cc3DVAhE.mjs → collection-CA3V5zyK.mjs} +0 -0
- /package/dist/{keys-DGu1NFwu.mjs → keys-BAK-tUlf.mjs} +0 -0
- /package/dist/{kv-rV3vodCc.mjs → kv-CX8qfaad.mjs} +0 -0
- /package/dist/{negotiation-DDstyBvc.mjs → negotiation-CDW-_gUU.mjs} +0 -0
- /package/dist/{public-audience-DZJAUUi8.mjs → public-audience-jwoSIGUw.mjs} +0 -0
- /package/dist/{retry-CXg_MBI-.mjs → retry-_VvV0h9f.mjs} +0 -0
- /package/dist/{types-J53Kw7so.mjs → types-s4mCTGkT.mjs} +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "@js-temporal/polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as version, t as name } from "./deno-
|
|
5
|
-
import { _ as recordKeyLookup, n as getDurationMs, t as classifyFetchError } from "./metrics-
|
|
4
|
+
import { n as version, t as name } from "./deno-ayal9buz.mjs";
|
|
5
|
+
import { _ as recordKeyLookup, n as getDurationMs, t as classifyFetchError } from "./metrics-Ce55disp.mjs";
|
|
6
6
|
import { getLogger } from "@logtape/logtape";
|
|
7
7
|
import { CryptographicKey, Object as Object$1, isActor } from "@fedify/vocab";
|
|
8
8
|
import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
@@ -86,6 +86,118 @@ async function importJwk(jwk, type) {
|
|
|
86
86
|
validateCryptoKey(key, type);
|
|
87
87
|
return key;
|
|
88
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Fetches the document that the given actor URI dereferences to, and returns
|
|
91
|
+
* the actor only if the host that served the document is authoritative for
|
|
92
|
+
* the id the document claims.
|
|
93
|
+
*
|
|
94
|
+
* Only the origin that serves an actor id can speak for it. Without that
|
|
95
|
+
* rule any host could serve a document describing somebody else's actor—and
|
|
96
|
+
* listing its own keys as that actor's.
|
|
97
|
+
*
|
|
98
|
+
* @param actorId The URI of the actor to fetch.
|
|
99
|
+
* @param options Options for fetching the document.
|
|
100
|
+
* @returns The actor, or `null` if the document cannot be fetched, is not an
|
|
101
|
+
* actor, or belongs to another origin.
|
|
102
|
+
* @internal
|
|
103
|
+
*/
|
|
104
|
+
async function fetchActorDocument(actorId, options = {}) {
|
|
105
|
+
const logger = getLogger([
|
|
106
|
+
"fedify",
|
|
107
|
+
"sig",
|
|
108
|
+
"key"
|
|
109
|
+
]);
|
|
110
|
+
const documentLoader = options.documentLoader ?? getDocumentLoader();
|
|
111
|
+
const contextLoader = options.contextLoader ?? getDocumentLoader();
|
|
112
|
+
const { tracerProvider } = options;
|
|
113
|
+
let document;
|
|
114
|
+
let documentUrl = actorId;
|
|
115
|
+
try {
|
|
116
|
+
const remoteDocument = await documentLoader(actorId.href);
|
|
117
|
+
document = remoteDocument.document;
|
|
118
|
+
documentUrl = new URL(remoteDocument.documentUrl ?? "", actorId);
|
|
119
|
+
} catch (error) {
|
|
120
|
+
logger.debug("Failed to fetch the actor {actorId}: {error}", {
|
|
121
|
+
actorId: actorId.href,
|
|
122
|
+
error
|
|
123
|
+
});
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
let object;
|
|
127
|
+
try {
|
|
128
|
+
object = await Object$1.fromJsonLd(document, {
|
|
129
|
+
documentLoader,
|
|
130
|
+
contextLoader,
|
|
131
|
+
tracerProvider,
|
|
132
|
+
baseUrl: documentUrl
|
|
133
|
+
});
|
|
134
|
+
} catch (error) {
|
|
135
|
+
if (!(error instanceof TypeError)) throw error;
|
|
136
|
+
logger.debug("The document served at {documentUrl} is not a valid object: {error}", {
|
|
137
|
+
documentUrl: documentUrl.href,
|
|
138
|
+
error
|
|
139
|
+
});
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
if (!isActor(object)) return null;
|
|
143
|
+
if (object.id == null || object.id.origin !== documentUrl.origin) {
|
|
144
|
+
logger.debug("The document served at {documentUrl} claims to be the actor {actorId}, which belongs to another origin; refusing to treat it as that actor's document.", {
|
|
145
|
+
documentUrl: documentUrl.href,
|
|
146
|
+
actorId: object.id?.href
|
|
147
|
+
});
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
return object;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Resolves the owner that the given key claims, and returns it only if the
|
|
154
|
+
* claim holds.
|
|
155
|
+
*
|
|
156
|
+
* The `owner` of a {@link CryptographicKey}, like the `controller` of
|
|
157
|
+
* a {@link Multikey}, proves nothing on its own: the key document and the
|
|
158
|
+
* claim inside it are served by the same host, so anyone able to serve a key
|
|
159
|
+
* document can name any actor in the world as its owner. The claim becomes
|
|
160
|
+
* meaningful only once the named actor's own document is fetched and turns
|
|
161
|
+
* out to link back to the key. This function performs that mutual-link
|
|
162
|
+
* check, which is the only sound way to learn a fetched key's owner.
|
|
163
|
+
*
|
|
164
|
+
* The claimed owner is always dereferenced, never read out of the key
|
|
165
|
+
* document: an owner embedded there is written by whoever wrote the key.
|
|
166
|
+
*
|
|
167
|
+
* @param key The key whose ownership claim is to be verified. It must carry
|
|
168
|
+
* an `id`, as that is what the owner has to link back to.
|
|
169
|
+
* @param options Options for fetching the claimed owner.
|
|
170
|
+
* @returns The verified owner, or `null` if the key claims no owner, the
|
|
171
|
+
* owner cannot be fetched, or the owner does not link back to
|
|
172
|
+
* the key.
|
|
173
|
+
* @internal
|
|
174
|
+
*/
|
|
175
|
+
async function verifyKeyOwnership(key, options = {}) {
|
|
176
|
+
const logger = getLogger([
|
|
177
|
+
"fedify",
|
|
178
|
+
"sig",
|
|
179
|
+
"key"
|
|
180
|
+
]);
|
|
181
|
+
const keyId = key.id;
|
|
182
|
+
if (keyId == null) return null;
|
|
183
|
+
const claimedOwnerId = key instanceof CryptographicKey ? key.ownerId : key.controllerId;
|
|
184
|
+
if (claimedOwnerId == null) return null;
|
|
185
|
+
const owner = await fetchActorDocument(claimedOwnerId, options);
|
|
186
|
+
if (owner == null) {
|
|
187
|
+
logger.debug("The owner ({claimedOwnerId}) that key {keyId} claims could not be resolved.", {
|
|
188
|
+
keyId: keyId.href,
|
|
189
|
+
claimedOwnerId: claimedOwnerId.href
|
|
190
|
+
});
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
const linkedKeyIds = key instanceof CryptographicKey ? owner.publicKeyIds : owner.assertionMethodIds;
|
|
194
|
+
for (const linkedKeyId of linkedKeyIds) if (linkedKeyId.href === keyId.href) return owner;
|
|
195
|
+
logger.debug("The owner ({claimedOwnerId}) that key {keyId} claims does not list the key as its own.", {
|
|
196
|
+
keyId: keyId.href,
|
|
197
|
+
claimedOwnerId: claimedOwnerId.href
|
|
198
|
+
});
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
89
201
|
async function withFetchKeySpan(keyId, tracerProvider, fetcher) {
|
|
90
202
|
tracerProvider ??= trace.getTracerProvider();
|
|
91
203
|
return await tracerProvider.getTracer(name, version).startActiveSpan("activitypub.fetch_key", {
|
|
@@ -213,7 +325,7 @@ async function getCachedFetchKey(cacheKey, keyId, cls, keyCache, logger) {
|
|
|
213
325
|
async function clearFetchErrorMetadata(keyId, keyCache) {
|
|
214
326
|
await keyCache?.setFetchError?.(keyId, null);
|
|
215
327
|
}
|
|
216
|
-
async function resolveFetchedKey(document, cacheKey, keyId, cls, { documentLoader, contextLoader, keyCache, tracerProvider }, logger) {
|
|
328
|
+
async function resolveFetchedKey(document, cacheKey, documentUrl, keyId, cls, { documentLoader, contextLoader, keyCache, tracerProvider }, logger) {
|
|
217
329
|
let object;
|
|
218
330
|
try {
|
|
219
331
|
object = await Object$1.fromJsonLd(document, {
|
|
@@ -243,8 +355,22 @@ async function resolveFetchedKey(document, cacheKey, keyId, cls, { documentLoade
|
|
|
243
355
|
}
|
|
244
356
|
}
|
|
245
357
|
let key = null;
|
|
246
|
-
|
|
358
|
+
let ownerDocument = null;
|
|
359
|
+
if (object instanceof cls && (object.id == null || object.id.href === keyId)) key = object.id == null ? object.clone({ id: cacheKey }) : object;
|
|
247
360
|
else if (isActor(object)) {
|
|
361
|
+
if (object.id == null || object.id.origin !== documentUrl.origin) {
|
|
362
|
+
logger.debug("Failed to verify; the document served at {documentUrl} claims to be the actor {actorId}, which belongs to another origin.", {
|
|
363
|
+
keyId,
|
|
364
|
+
documentUrl: documentUrl.href,
|
|
365
|
+
actorId: object.id?.href
|
|
366
|
+
});
|
|
367
|
+
await keyCache?.set(cacheKey, null);
|
|
368
|
+
return {
|
|
369
|
+
key: null,
|
|
370
|
+
cached: false
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
ownerDocument = object;
|
|
248
374
|
const keys = cls === CryptographicKey ? object.getPublicKeys({
|
|
249
375
|
documentLoader,
|
|
250
376
|
contextLoader,
|
|
@@ -306,6 +432,25 @@ async function resolveFetchedKey(document, cacheKey, keyId, cls, { documentLoade
|
|
|
306
432
|
cached: false
|
|
307
433
|
};
|
|
308
434
|
}
|
|
435
|
+
const claimedOwnerId = key instanceof CryptographicKey ? key.ownerId : key.controllerId;
|
|
436
|
+
if (ownerDocument != null && claimedOwnerId == null) key = key instanceof CryptographicKey ? key.clone({ owner: ownerDocument.id }) : key.clone({ controller: ownerDocument.id });
|
|
437
|
+
else if (claimedOwnerId != null && claimedOwnerId.href !== ownerDocument?.id?.href) {
|
|
438
|
+
if (await verifyKeyOwnership(key, {
|
|
439
|
+
documentLoader,
|
|
440
|
+
contextLoader,
|
|
441
|
+
tracerProvider
|
|
442
|
+
}) == null) {
|
|
443
|
+
logger.debug("Failed to verify; the owner {claimedOwnerId} that key {keyId} claims does not list the key as its own.", {
|
|
444
|
+
keyId,
|
|
445
|
+
claimedOwnerId: claimedOwnerId.href
|
|
446
|
+
});
|
|
447
|
+
await keyCache?.set(cacheKey, null);
|
|
448
|
+
return {
|
|
449
|
+
key: null,
|
|
450
|
+
cached: false
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
}
|
|
309
454
|
if (keyCache != null) {
|
|
310
455
|
await keyCache.set(cacheKey, key);
|
|
311
456
|
logger.debug("Key {keyId} cached.", { keyId });
|
|
@@ -339,15 +484,18 @@ async function fetchKeyWithResult(cacheKey, cls, options, onCachedUnavailable, o
|
|
|
339
484
|
}
|
|
340
485
|
logger.debug("Fetching key {keyId} to verify signature...", { keyId });
|
|
341
486
|
let document;
|
|
487
|
+
let documentUrl = cacheKey;
|
|
342
488
|
try {
|
|
343
|
-
|
|
489
|
+
const remoteDocument = await (options.documentLoader ?? getDocumentLoader())(keyId);
|
|
490
|
+
document = remoteDocument.document;
|
|
491
|
+
documentUrl = new URL(remoteDocument.documentUrl ?? "", cacheKey);
|
|
344
492
|
} catch (error) {
|
|
345
493
|
const classified = classifyFetchError(error);
|
|
346
494
|
const errored = await onFetchError(error, cacheKey, keyId, keyCache, logger);
|
|
347
495
|
outcome = classified;
|
|
348
496
|
return errored;
|
|
349
497
|
}
|
|
350
|
-
const resolved = await resolveFetchedKey(document, cacheKey, keyId, cls, options, logger);
|
|
498
|
+
const resolved = await resolveFetchedKey(document, cacheKey, documentUrl, keyId, cls, options, logger);
|
|
351
499
|
outcome = { result: resolved.key != null ? "fetched" : "invalid" };
|
|
352
500
|
return resolved;
|
|
353
501
|
} finally {
|
|
@@ -384,4 +532,4 @@ async function fetchKeyInternal(keyId, cls, options = {}) {
|
|
|
384
532
|
});
|
|
385
533
|
}
|
|
386
534
|
//#endregion
|
|
387
|
-
export {
|
|
535
|
+
export { generateCryptoKeyPair as a, verifyKeyOwnership as c, fetchKeyDetailed as i, fetchActorDocument as n, importJwk as o, fetchKey as r, validateCryptoKey as s, exportJwk as t };
|
|
@@ -3,6 +3,7 @@ import "urlpattern-polyfill";
|
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
4
|
import { CryptographicKey, Multikey } from "@fedify/vocab";
|
|
5
5
|
//#region src/federation/keycache.ts
|
|
6
|
+
const KEY_CACHE_GENERATION = "2";
|
|
6
7
|
var KvKeyCache = class {
|
|
7
8
|
kv;
|
|
8
9
|
prefix;
|
|
@@ -23,13 +24,20 @@ var KvKeyCache = class {
|
|
|
23
24
|
keyId.href
|
|
24
25
|
];
|
|
25
26
|
}
|
|
27
|
+
#entryKey(keyId) {
|
|
28
|
+
return [
|
|
29
|
+
...this.prefix,
|
|
30
|
+
KEY_CACHE_GENERATION,
|
|
31
|
+
keyId.href
|
|
32
|
+
];
|
|
33
|
+
}
|
|
26
34
|
async get(keyId) {
|
|
27
35
|
const negativeExpiration = this.nullKeys.get(keyId.href);
|
|
28
36
|
if (negativeExpiration != null) {
|
|
29
37
|
if (Temporal.Now.instant().until(negativeExpiration).sign >= 0) return null;
|
|
30
38
|
this.nullKeys.delete(keyId.href);
|
|
31
39
|
}
|
|
32
|
-
const serialized = await this.kv.get(
|
|
40
|
+
const serialized = await this.kv.get(this.#entryKey(keyId));
|
|
33
41
|
if (serialized === void 0) return void 0;
|
|
34
42
|
if (serialized === null) {
|
|
35
43
|
this.nullKeys.set(keyId.href, Temporal.Now.instant().add(this.unavailableKeyTtl));
|
|
@@ -41,7 +49,7 @@ var KvKeyCache = class {
|
|
|
41
49
|
try {
|
|
42
50
|
return await Multikey.fromJsonLd(serialized, this.options);
|
|
43
51
|
} catch {
|
|
44
|
-
await this.kv.delete(
|
|
52
|
+
await this.kv.delete(this.#entryKey(keyId));
|
|
45
53
|
return;
|
|
46
54
|
}
|
|
47
55
|
}
|
|
@@ -49,12 +57,12 @@ var KvKeyCache = class {
|
|
|
49
57
|
async set(keyId, key) {
|
|
50
58
|
if (key == null) {
|
|
51
59
|
this.nullKeys.set(keyId.href, Temporal.Now.instant().add(this.unavailableKeyTtl));
|
|
52
|
-
await this.kv.set(
|
|
60
|
+
await this.kv.set(this.#entryKey(keyId), null, { ttl: this.unavailableKeyTtl });
|
|
53
61
|
return;
|
|
54
62
|
}
|
|
55
63
|
this.nullKeys.delete(keyId.href);
|
|
56
64
|
const serialized = await key.toJsonLd(this.options);
|
|
57
|
-
await this.kv.set(
|
|
65
|
+
await this.kv.set(this.#entryKey(keyId), serialized);
|
|
58
66
|
}
|
|
59
67
|
async getFetchError(keyId) {
|
|
60
68
|
const cached = await this.kv.get(this.#getFetchErrorKey(keyId));
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
const { Temporal } = require("@js-temporal/polyfill");
|
|
2
2
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
3
3
|
require("./chunk-DDcVe30Y.cjs");
|
|
4
|
-
const require_http = require("./http-
|
|
4
|
+
const require_http = require("./http-BGP2QCbe.cjs");
|
|
5
5
|
let _logtape_logtape = require("@logtape/logtape");
|
|
6
|
-
let es_toolkit = require("es-toolkit");
|
|
7
6
|
let _fedify_vocab_runtime = require("@fedify/vocab-runtime");
|
|
7
|
+
let es_toolkit = require("es-toolkit");
|
|
8
8
|
//#region src/utils/docloader.ts
|
|
9
9
|
const logger$1 = (0, _logtape_logtape.getLogger)([
|
|
10
10
|
"fedify",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Temporal } from "@js-temporal/polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
|
-
import {
|
|
3
|
+
import { T as recordDocumentCache, f as validateCryptoKey, t as doubleKnock } from "./http-BPPCh0xN.js";
|
|
4
4
|
import { getLogger } from "@logtape/logtape";
|
|
5
|
-
import { curry } from "es-toolkit";
|
|
6
5
|
import { UrlError, createActivityPubRequest, getRemoteDocument, logRequest, preloadedContexts, validatePublicUrl } from "@fedify/vocab-runtime";
|
|
6
|
+
import { curry } from "es-toolkit";
|
|
7
7
|
//#region src/utils/docloader.ts
|
|
8
8
|
const logger$1 = getLogger([
|
|
9
9
|
"fedify",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Temporal } from "@js-temporal/polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { p as recordDocumentCache } from "./metrics-
|
|
4
|
+
import { p as recordDocumentCache } from "./metrics-Ce55disp.mjs";
|
|
5
5
|
import { getLogger } from "@logtape/logtape";
|
|
6
6
|
import { preloadedContexts } from "@fedify/vocab-runtime";
|
|
7
7
|
//#region src/utils/kv-cache.ts
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import "@js-temporal/polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as version, t as name } from "./deno-
|
|
5
|
-
import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-
|
|
6
|
-
import {
|
|
4
|
+
import { n as version, t as name } from "./deno-ayal9buz.mjs";
|
|
5
|
+
import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-Ce55disp.mjs";
|
|
6
|
+
import { r as fetchKey, s as validateCryptoKey } from "./key-C9DkrWwb.mjs";
|
|
7
7
|
import { getLogger } from "@logtape/logtape";
|
|
8
8
|
import { Activity, CryptographicKey, Object as Object$1, getTypeId } from "@fedify/vocab";
|
|
9
9
|
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "@js-temporal/polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as version, t as name } from "./deno-
|
|
4
|
+
import { n as version, t as name } from "./deno-ayal9buz.mjs";
|
|
5
5
|
import { metrics } from "@opentelemetry/api";
|
|
6
6
|
import { FetchError } from "@fedify/vocab-runtime";
|
|
7
7
|
//#region src/federation/metrics.ts
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import { Temporal } from "@js-temporal/polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { n as version, t as name } from "./deno-
|
|
5
|
-
import { a as instrumentDocumentLoader, b as recordWebFingerHandle, c as recordCircuitBreakerStateChange, d as recordCollectionRequest, f as recordCollectionTotalItems, g as recordInboxActivity, h as recordFanoutRecipients, i as getRemoteHost, l as recordCollectionDispatchDuration, n as getDurationMs, o as isAbortError, r as getFederationMetrics, u as recordCollectionPageItems, v as recordOutboxActivity, x as registerQueueDepthGauge, y as recordOutboxEnqueue } from "./metrics-
|
|
6
|
-
import { t as formatAcceptSignature } from "./accept-
|
|
7
|
-
import {
|
|
8
|
-
import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-
|
|
9
|
-
import { t as getAuthenticatedDocumentLoader } from "./docloader-
|
|
10
|
-
import { n as kvCache } from "./kv-cache-
|
|
11
|
-
import { _ as wrapContextLoaderForJsonLd, a as compactJsonLd, c as getNormalizationContextLoader, d as isClearlyMalformedContextReference, f as isInvalidUrlTypeError, l as hasSignature, m as verifyCompactJsonLd, p as signJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as hasSignatureLike } from "./ld-
|
|
12
|
-
import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-
|
|
13
|
-
import { r as normalizeOutgoingActivityJsonLd } from "./outgoing-jsonld-
|
|
14
|
-
import { i as verifyObject, n as hasProofLike, r as signObject } from "./proof-
|
|
15
|
-
import { t as getNodeInfo } from "./client-
|
|
16
|
-
import { t as nodeInfoToJson } from "./types-
|
|
17
|
-
import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-
|
|
18
|
-
import { n as FederationBuilderImpl, t as ACTOR_ALIAS_PREFIX } from "./builder-
|
|
19
|
-
import { t as CircuitBreaker } from "./circuit-breaker-
|
|
20
|
-
import { t as buildCollectionSynchronizationHeader } from "./collection-
|
|
21
|
-
import { t as KvKeyCache } from "./keycache-
|
|
22
|
-
import { t as acceptsJsonLd } from "./negotiation-
|
|
23
|
-
import { t as hasMalformedKnownTemporalLiteral } from "./temporal-
|
|
24
|
-
import { t as createExponentialBackoffPolicy } from "./retry-
|
|
4
|
+
import { n as version, t as name } from "./deno-ayal9buz.mjs";
|
|
5
|
+
import { a as instrumentDocumentLoader, b as recordWebFingerHandle, c as recordCircuitBreakerStateChange, d as recordCollectionRequest, f as recordCollectionTotalItems, g as recordInboxActivity, h as recordFanoutRecipients, i as getRemoteHost, l as recordCollectionDispatchDuration, n as getDurationMs, o as isAbortError, r as getFederationMetrics, u as recordCollectionPageItems, v as recordOutboxActivity, x as registerQueueDepthGauge, y as recordOutboxEnqueue } from "./metrics-Ce55disp.mjs";
|
|
6
|
+
import { t as formatAcceptSignature } from "./accept-Dd__NiUL.mjs";
|
|
7
|
+
import { o as importJwk, s as validateCryptoKey, t as exportJwk } from "./key-C9DkrWwb.mjs";
|
|
8
|
+
import { l as verifyRequest, o as parseRfc9421SignatureInput, u as verifyRequestDetailed } from "./http-B2u6PvNX.mjs";
|
|
9
|
+
import { t as getAuthenticatedDocumentLoader } from "./docloader-C-JrNL14.mjs";
|
|
10
|
+
import { n as kvCache } from "./kv-cache-qJSjfLGm.mjs";
|
|
11
|
+
import { _ as wrapContextLoaderForJsonLd, a as compactJsonLd, c as getNormalizationContextLoader, d as isClearlyMalformedContextReference, f as isInvalidUrlTypeError, l as hasSignature, m as verifyCompactJsonLd, p as signJsonLd, r as assertSafeJsonLd, s as detachSignature, t as InvalidContextReferenceError, u as hasSignatureLike } from "./ld-DNl7KwLY.mjs";
|
|
12
|
+
import { n as getKeyOwner, t as doesActorOwnKey } from "./owner-DqqDBw-l.mjs";
|
|
13
|
+
import { r as normalizeOutgoingActivityJsonLd } from "./outgoing-jsonld-HOAywiid.mjs";
|
|
14
|
+
import { i as verifyObject, n as hasProofLike, r as signObject } from "./proof-D5vP7VIN.mjs";
|
|
15
|
+
import { d as readBoundedText, l as BodyTooLargeError, t as getNodeInfo, u as MAX_BODY_SIZE } from "./client-DYDoDpMa.mjs";
|
|
16
|
+
import { t as nodeInfoToJson } from "./types-s4mCTGkT.mjs";
|
|
17
|
+
import { n as extractInboxes, r as sendActivity, t as SendActivityError } from "./send-CBtR8DQK.mjs";
|
|
18
|
+
import { n as FederationBuilderImpl, t as ACTOR_ALIAS_PREFIX } from "./builder-BfY2wZ4V.mjs";
|
|
19
|
+
import { t as CircuitBreaker } from "./circuit-breaker-CDABzqVf.mjs";
|
|
20
|
+
import { t as buildCollectionSynchronizationHeader } from "./collection-CA3V5zyK.mjs";
|
|
21
|
+
import { t as KvKeyCache } from "./keycache-B3qRQNLj.mjs";
|
|
22
|
+
import { t as acceptsJsonLd } from "./negotiation-CDW-_gUU.mjs";
|
|
23
|
+
import { t as hasMalformedKnownTemporalLiteral } from "./temporal-B9t2tY9A.mjs";
|
|
24
|
+
import { t as createExponentialBackoffPolicy } from "./retry-_VvV0h9f.mjs";
|
|
25
25
|
import { getLogger, withContext } from "@logtape/logtape";
|
|
26
26
|
import { RouterError } from "@fedify/uri-template";
|
|
27
27
|
import { Activity, Collection, CollectionPage, CryptographicKey, Link, Multikey, Object as Object$1, OrderedCollection, OrderedCollectionPage, Tombstone, getTypeId, lookupObject, traverseCollection } from "@fedify/vocab";
|
|
@@ -636,13 +636,13 @@ function recordCollectionMetrics(meterProvider, base, result, options = {}) {
|
|
|
636
636
|
* @param parameters The parameters for handling the collection.
|
|
637
637
|
* @returns A promise that resolves to an HTTP response.
|
|
638
638
|
*/
|
|
639
|
-
async function handleCollection(request, { name: name$
|
|
640
|
-
const spanName = name$
|
|
639
|
+
async function handleCollection(request, { name: name$2, identifier, uriGetter, filter, filterPredicate, context, collectionCallbacks, tracerProvider, meterProvider, onUnauthorized, onNotFound }) {
|
|
640
|
+
const spanName = name$2.trim().replace(/\s+/g, "_");
|
|
641
641
|
tracerProvider = tracerProvider ?? trace.getTracerProvider();
|
|
642
642
|
const tracer = tracerProvider.getTracer(name, version);
|
|
643
643
|
const cursor = new URL(request.url).searchParams.get("cursor");
|
|
644
644
|
const metricBase = {
|
|
645
|
-
kind: getCollectionMetricKind(name$
|
|
645
|
+
kind: getCollectionMetricKind(name$2),
|
|
646
646
|
page: cursor != null,
|
|
647
647
|
dispatcher: "built_in"
|
|
648
648
|
};
|
|
@@ -683,7 +683,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
|
|
|
683
683
|
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
684
684
|
return await onNotFound(request);
|
|
685
685
|
}
|
|
686
|
-
const items = filterCollectionItems(page.items, name$
|
|
686
|
+
const items = filterCollectionItems(page.items, name$2, filterPredicate);
|
|
687
687
|
itemCount = items.length;
|
|
688
688
|
span.setAttribute("fedify.collection.items", itemCount);
|
|
689
689
|
return items;
|
|
@@ -723,7 +723,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
|
|
|
723
723
|
} else {
|
|
724
724
|
const uri = new URL(baseUri);
|
|
725
725
|
uri.searchParams.set("cursor", cursor);
|
|
726
|
-
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$
|
|
726
|
+
const pageOrResponse = await tracer.startActiveSpan(`activitypub.dispatch_collection_page ${name$2}`, {
|
|
727
727
|
kind: SpanKind.SERVER,
|
|
728
728
|
attributes: {
|
|
729
729
|
"activitypub.collection.id": uri.href,
|
|
@@ -739,7 +739,7 @@ async function handleCollection(request, { name: name$1, identifier, uriGetter,
|
|
|
739
739
|
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
740
740
|
return await onNotFound(request);
|
|
741
741
|
}
|
|
742
|
-
const items = filterCollectionItems(page.items, name$
|
|
742
|
+
const items = filterCollectionItems(page.items, name$2, filterPredicate);
|
|
743
743
|
itemCount = items.length;
|
|
744
744
|
span.setAttribute("fedify.collection.items", itemCount);
|
|
745
745
|
return {
|
|
@@ -1105,8 +1105,16 @@ async function handleInboxInternal(request, parameters, span) {
|
|
|
1105
1105
|
}
|
|
1106
1106
|
let json;
|
|
1107
1107
|
try {
|
|
1108
|
-
json = await request.clone().
|
|
1108
|
+
json = JSON.parse(await readBoundedText(request.clone(), MAX_BODY_SIZE, request.url));
|
|
1109
1109
|
} catch (error) {
|
|
1110
|
+
if (error instanceof BodyTooLargeError) {
|
|
1111
|
+
request.body?.cancel(error).catch(() => {});
|
|
1112
|
+
span.setStatus({
|
|
1113
|
+
code: SpanStatusCode.ERROR,
|
|
1114
|
+
message: String(error)
|
|
1115
|
+
});
|
|
1116
|
+
return new Response("Inbox body too large.", { status: 413 });
|
|
1117
|
+
}
|
|
1110
1118
|
logger.error("Failed to parse JSON:\n{error}", {
|
|
1111
1119
|
recipient,
|
|
1112
1120
|
error
|
|
@@ -1607,8 +1615,8 @@ var CustomCollectionHandler = class {
|
|
|
1607
1615
|
* @param CollectionPage The CollectionPage constructor.
|
|
1608
1616
|
* @param filterPredicate Optional filter predicate for items.
|
|
1609
1617
|
*/
|
|
1610
|
-
constructor(name$
|
|
1611
|
-
this.name = name$
|
|
1618
|
+
constructor(name$1, values, context, callbacks, tracerProvider = trace.getTracerProvider(), meterProvider, Collection, CollectionPage, filterPredicate) {
|
|
1619
|
+
this.name = name$1;
|
|
1612
1620
|
this.values = values;
|
|
1613
1621
|
this.context = context;
|
|
1614
1622
|
this.callbacks = callbacks;
|
|
@@ -2960,6 +2968,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
2960
2968
|
if (decision.stateChange != null) recordCircuitBreakerSpanEvent(span, remoteHost, decision.stateChange);
|
|
2961
2969
|
}
|
|
2962
2970
|
await sendActivity({
|
|
2971
|
+
allowPrivateAddress: this.allowPrivateAddress,
|
|
2963
2972
|
keys,
|
|
2964
2973
|
activity: message.activity,
|
|
2965
2974
|
activityId: message.activityId,
|
|
@@ -3482,6 +3491,7 @@ var FederationImpl = class extends FederationBuilderImpl {
|
|
|
3482
3491
|
});
|
|
3483
3492
|
const promises = [];
|
|
3484
3493
|
for (const inbox in inboxes) promises.push(sendActivity({
|
|
3494
|
+
allowPrivateAddress: this.allowPrivateAddress,
|
|
3485
3495
|
keys,
|
|
3486
3496
|
activity: jsonLd,
|
|
3487
3497
|
activityId: activity.id?.href,
|
|
@@ -4759,6 +4769,7 @@ async function forwardActivityInternal(ctx, loggerCategory, forwarder, recipient
|
|
|
4759
4769
|
else logger.debug("Forwarding activity immediately without queue since queue is not set.");
|
|
4760
4770
|
const promises = [];
|
|
4761
4771
|
for (const inbox in inboxes) promises.push(sendActivity({
|
|
4772
|
+
allowPrivateAddress: ctx.federation.allowPrivateAddress,
|
|
4762
4773
|
keys,
|
|
4763
4774
|
activity: ctx.activity,
|
|
4764
4775
|
activityId: ctx.activityId,
|