@fedify/fedify 2.4.0-dev.2093 → 2.4.0-dev.2099
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/{builder-Ld4Y9ymR.mjs → builder-Bno54o_-.mjs} +2 -2
- package/dist/compat/mod.d.cts +1 -1
- package/dist/compat/mod.d.ts +1 -1
- package/dist/compat/transformers.test.mjs +1 -1
- package/dist/{compound-proof-CTx_lewQ.mjs → compound-proof-X3SxXVbc.mjs} +2 -2
- package/dist/{context-CZjZYXFC.d.cts → context-C43spTGI.d.cts} +5 -2
- package/dist/{context-BSywYspi.d.ts → context-MORIQJIh.d.ts} +5 -2
- package/dist/{deno-8t8k_6Yv.mjs → deno-dxdvl2XZ.mjs} +1 -1
- package/dist/{docloader-DJKcsAiF.mjs → docloader-eBxQDsk9.mjs} +2 -2
- package/dist/federation/builder.test.mjs +1 -1
- package/dist/federation/compound-fanout.test.mjs +3 -3
- package/dist/federation/handler-compound-proof.test.mjs +3 -3
- package/dist/federation/handler.test.mjs +5 -5
- package/dist/federation/hashlink-media.test.mjs +2 -2
- package/dist/federation/idempotency.test.mjs +2 -2
- package/dist/federation/metrics.test.mjs +1 -1
- package/dist/federation/middleware.test.mjs +7 -7
- 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/outgoing-proof.test.mjs +5 -5
- package/dist/federation/portable-gateway-keys.test.mjs +3 -3
- package/dist/federation/portable-inbox.test.mjs +375 -10
- package/dist/federation/portable.test.mjs +3 -3
- package/dist/federation/send.test.mjs +3 -3
- package/dist/federation/tasks/enqueue.test.mjs +1 -1
- package/dist/federation/tasks/tasks.test.mjs +2 -2
- package/dist/federation/temporal.test.mjs +1 -1
- package/dist/federation/webfinger.test.mjs +1 -1
- package/dist/{federation-aSHO04ob.cjs → federation-C4Ef3JKa.cjs} +1211 -1089
- package/dist/{http-DSaSAN7X.cjs → http-C8cZTE3Y.cjs} +89 -2
- package/dist/{http-DyT7DP1Y.js → http-D-rbr_Sy.js} +78 -3
- package/dist/{http-B2ftY0Ha.mjs → http-DsgawTd8.mjs} +82 -7
- package/dist/{key-Dwm4VswT.mjs → key-DYfmjnmp.mjs} +2 -2
- package/dist/{kv-cache-DmroAz3M.js → kv-cache-DIxwMeNi.js} +1 -1
- package/dist/{kv-cache-BSJAlP4C.cjs → kv-cache-Dvd-Q-E2.cjs} +1 -1
- package/dist/{kv-cache-D0yYukqk.mjs → kv-cache-EvOgrFsS.mjs} +1 -1
- package/dist/{ld-BYZOoDzZ.mjs → ld-B00wWHzc.mjs} +3 -3
- package/dist/{metrics-B7YwKTFr.mjs → metrics-BP3vdBpb.mjs} +1 -1
- package/dist/{middleware-E_0IH72m.mjs → middleware-Br1_d-Ga.mjs} +627 -505
- package/dist/{middleware-Blq0882d.js → middleware-CcXMe400.js} +1307 -1185
- package/dist/{middleware-BNeqKSsL.mjs → middleware-CeBVBa61.mjs} +1 -1
- package/dist/{mod-B2h2KY0q.d.ts → mod-BL5BQHCq.d.ts} +1 -1
- package/dist/{mod-JzkaEXsi.d.cts → mod-DMI4DbOo.d.cts} +1 -1
- package/dist/mod.cjs +5 -5
- package/dist/mod.d.cts +2 -2
- package/dist/mod.d.ts +2 -2
- package/dist/mod.js +5 -5
- package/dist/nodeinfo/handler.test.mjs +1 -1
- package/dist/{owner-Cgx2Dc7I.mjs → owner-BJPDRDRq.mjs} +3 -3
- package/dist/{owner-szIZl4qI.cjs → owner-DSzH7wro.cjs} +1 -1
- package/dist/{owner-DAGSC5gX.js → owner-U12fDpQW.js} +1 -1
- package/dist/{portable-key-Cn1WJSN1.mjs → portable-key-D0mWbV9G.mjs} +1 -1
- package/dist/{proof-DVXC6nYz.mjs → proof-ChjBwnep.mjs} +4 -4
- package/dist/{send-D-hOvYKy.mjs → send-yFX0E-ye.mjs} +3 -3
- package/dist/sig/compound-proof-discovery.test.mjs +1 -1
- package/dist/sig/compound-proof-producer.test.mjs +1 -1
- package/dist/sig/compound-proof-verification.test.mjs +2 -2
- package/dist/sig/compound-proof.test.mjs +2 -2
- package/dist/sig/http.test.mjs +72 -2
- package/dist/sig/key.test.mjs +1 -1
- package/dist/sig/ld.test.mjs +2 -2
- package/dist/sig/mod.cjs +3 -3
- package/dist/sig/mod.js +3 -3
- package/dist/sig/owner.test.mjs +1 -1
- package/dist/sig/portable-collection.test.mjs +2 -2
- package/dist/sig/portable-key.test.mjs +3 -3
- package/dist/sig/proof.test.mjs +3 -3
- package/dist/{sig-CXOKN4Br.cjs → sig-B689Nj7y.cjs} +2 -2
- package/dist/{sig-B5Ell7pO.js → sig-C85KqAcx.js} +2 -2
- package/dist/{temporal-CqpKGEPk.mjs → temporal-Dl9x-Qw4.mjs} +1 -1
- package/dist/testing/kv.test.mjs +1 -1
- package/dist/testing/mod.d.mts +5 -2
- package/dist/utils/docloader.test.mjs +2 -2
- 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
|
@@ -16,7 +16,7 @@ json_canon = require_rolldown_runtime.__toESM(json_canon, 1);
|
|
|
16
16
|
let _opentelemetry_semantic_conventions = require("@opentelemetry/semantic-conventions");
|
|
17
17
|
//#region deno.json
|
|
18
18
|
var name = "@fedify/fedify";
|
|
19
|
-
var version = "2.4.0-dev.
|
|
19
|
+
var version = "2.4.0-dev.2099+cd074fe2";
|
|
20
20
|
//#endregion
|
|
21
21
|
//#region src/sig/portable-key-id.ts
|
|
22
22
|
const COMPATIBLE_KEY_ID_PATH_PATTERN = /^\/\.well-known\/apgateway\/did(?::|%3A)/i;
|
|
@@ -7876,6 +7876,81 @@ function parseRfc9421Signature(signature) {
|
|
|
7876
7876
|
for (const [key, value] of Object.entries(dict)) if (value.value instanceof Uint8Array) result[key] = value.value;
|
|
7877
7877
|
return result;
|
|
7878
7878
|
}
|
|
7879
|
+
/**
|
|
7880
|
+
* Parses the `Signature` header of draft-cavage HTTP Signatures into its
|
|
7881
|
+
* fields, e.g., `keyId` and `headers`.
|
|
7882
|
+
*/
|
|
7883
|
+
function parseDraftSignature(signature) {
|
|
7884
|
+
return Object.fromEntries(signature.split(",").map((pair) => pair.match(/^\s*([A-Za-z]+)=(?:"([^"]*)"|(\d+))\s*$/)).filter((m) => m != null).map((m) => [m[1], m[2] ?? m[3]]));
|
|
7885
|
+
}
|
|
7886
|
+
/**
|
|
7887
|
+
* Lists the HTTP Signatures that a request claims to carry, without verifying
|
|
7888
|
+
* any of them. Signatures whose key IDs are not URLs are left out.
|
|
7889
|
+
* @param request The request.
|
|
7890
|
+
* @returns The signatures; RFC 9421 ones if the request has
|
|
7891
|
+
* a `Signature-Input` header, or a draft-cavage one otherwise.
|
|
7892
|
+
* @internal
|
|
7893
|
+
*/
|
|
7894
|
+
function listRequestSignatures(request) {
|
|
7895
|
+
const signatureInput = request.headers.get("Signature-Input");
|
|
7896
|
+
if (signatureInput != null) {
|
|
7897
|
+
const signatures = [];
|
|
7898
|
+
const inputs = parseRfc9421SignatureInput(signatureInput);
|
|
7899
|
+
for (const [label, input] of Object.entries(inputs)) {
|
|
7900
|
+
const keyId = parseKeyId(input.keyId);
|
|
7901
|
+
if (keyId == null) continue;
|
|
7902
|
+
signatures.push({
|
|
7903
|
+
keyId,
|
|
7904
|
+
label,
|
|
7905
|
+
components: input.components
|
|
7906
|
+
});
|
|
7907
|
+
}
|
|
7908
|
+
return signatures;
|
|
7909
|
+
}
|
|
7910
|
+
const signature = request.headers.get("Signature");
|
|
7911
|
+
if (signature == null) return [];
|
|
7912
|
+
const values = parseDraftSignature(signature);
|
|
7913
|
+
const keyId = parseKeyId(values.keyId);
|
|
7914
|
+
if (keyId == null) return [];
|
|
7915
|
+
return [{
|
|
7916
|
+
keyId,
|
|
7917
|
+
label: null,
|
|
7918
|
+
components: (values.headers ?? "").split(/\s+/g).filter((name) => name !== "").map((name) => ({
|
|
7919
|
+
value: name,
|
|
7920
|
+
params: {}
|
|
7921
|
+
}))
|
|
7922
|
+
}];
|
|
7923
|
+
}
|
|
7924
|
+
/**
|
|
7925
|
+
* Makes a copy of a request that carries only one of its RFC 9421 signatures,
|
|
7926
|
+
* so that verifying the copy verifies that signature and no other.
|
|
7927
|
+
* A draft-cavage signature is the only one in its request, so the request is
|
|
7928
|
+
* just copied.
|
|
7929
|
+
* @param request The request, whose body must not be consumed.
|
|
7930
|
+
* @param signature One of the signatures that {@link listRequestSignatures}
|
|
7931
|
+
* lists for the request.
|
|
7932
|
+
* @returns The copy of the request.
|
|
7933
|
+
* @internal
|
|
7934
|
+
*/
|
|
7935
|
+
function selectRequestSignature(request, signature) {
|
|
7936
|
+
const copy = request.clone();
|
|
7937
|
+
if (signature.label == null) return copy;
|
|
7938
|
+
const { label } = signature;
|
|
7939
|
+
const pick = (header) => {
|
|
7940
|
+
if (header == null) return "";
|
|
7941
|
+
let dict;
|
|
7942
|
+
try {
|
|
7943
|
+
dict = (0, structured_field_values.decodeDict)(header);
|
|
7944
|
+
} catch {
|
|
7945
|
+
return "";
|
|
7946
|
+
}
|
|
7947
|
+
return Object.hasOwn(dict, label) ? (0, structured_field_values.encodeDict)({ [label]: dict[label] }) : "";
|
|
7948
|
+
};
|
|
7949
|
+
const headers = new Headers(copy.headers);
|
|
7950
|
+
headers.set("Signature-Input", pick(headers.get("Signature-Input")));
|
|
7951
|
+
headers.set("Signature", pick(headers.get("Signature")));
|
|
7952
|
+
return new Request(copy, { headers });
|
|
7953
|
+
}
|
|
7879
7954
|
async function signRequestRfc9421(request, privateKey, keyId, span, currentTime, bodyBuffer, rfc9421Options) {
|
|
7880
7955
|
if (privateKey.algorithm.name !== "RSASSA-PKCS1-v1_5") throw new TypeError("Unsupported algorithm: " + privateKey.algorithm.name);
|
|
7881
7956
|
const url = new URL(request.url);
|
|
@@ -8107,7 +8182,7 @@ async function verifyRequestDraft(request, span, metricsContext, { documentLoade
|
|
|
8107
8182
|
logger.debug("Failed to verify; no Signature header found.", { headers: Object.fromEntries(request.headers.entries()) });
|
|
8108
8183
|
return noSignatureResult();
|
|
8109
8184
|
}
|
|
8110
|
-
const sigValues =
|
|
8185
|
+
const sigValues = parseDraftSignature(sigHeader);
|
|
8111
8186
|
const parsedKeyId = parseKeyId(sigValues.keyId);
|
|
8112
8187
|
const dateHeader = request.headers.get("Date");
|
|
8113
8188
|
if (dateHeader == null) {
|
|
@@ -9008,6 +9083,12 @@ Object.defineProperty(exports, "isSamePublicKey", {
|
|
|
9008
9083
|
return isSamePublicKey;
|
|
9009
9084
|
}
|
|
9010
9085
|
});
|
|
9086
|
+
Object.defineProperty(exports, "listRequestSignatures", {
|
|
9087
|
+
enumerable: true,
|
|
9088
|
+
get: function() {
|
|
9089
|
+
return listRequestSignatures;
|
|
9090
|
+
}
|
|
9091
|
+
});
|
|
9011
9092
|
Object.defineProperty(exports, "name", {
|
|
9012
9093
|
enumerable: true,
|
|
9013
9094
|
get: function() {
|
|
@@ -9110,6 +9191,12 @@ Object.defineProperty(exports, "registerQueueDepthGauge", {
|
|
|
9110
9191
|
return registerQueueDepthGauge;
|
|
9111
9192
|
}
|
|
9112
9193
|
});
|
|
9194
|
+
Object.defineProperty(exports, "selectRequestSignature", {
|
|
9195
|
+
enumerable: true,
|
|
9196
|
+
get: function() {
|
|
9197
|
+
return selectRequestSignature;
|
|
9198
|
+
}
|
|
9199
|
+
});
|
|
9113
9200
|
Object.defineProperty(exports, "signJsonLd", {
|
|
9114
9201
|
enumerable: true,
|
|
9115
9202
|
get: function() {
|
|
@@ -14,7 +14,7 @@ import serialize from "json-canon";
|
|
|
14
14
|
import { ATTR_HTTP_REQUEST_HEADER, ATTR_HTTP_REQUEST_METHOD, ATTR_URL_FULL } from "@opentelemetry/semantic-conventions";
|
|
15
15
|
//#region deno.json
|
|
16
16
|
var name = "@fedify/fedify";
|
|
17
|
-
var version = "2.4.0-dev.
|
|
17
|
+
var version = "2.4.0-dev.2099+cd074fe2";
|
|
18
18
|
//#endregion
|
|
19
19
|
//#region src/sig/portable-key-id.ts
|
|
20
20
|
const COMPATIBLE_KEY_ID_PATH_PATTERN = /^\/\.well-known\/apgateway\/did(?::|%3A)/i;
|
|
@@ -4308,6 +4308,81 @@ function parseRfc9421Signature(signature) {
|
|
|
4308
4308
|
for (const [key, value] of Object.entries(dict)) if (value.value instanceof Uint8Array) result[key] = value.value;
|
|
4309
4309
|
return result;
|
|
4310
4310
|
}
|
|
4311
|
+
/**
|
|
4312
|
+
* Parses the `Signature` header of draft-cavage HTTP Signatures into its
|
|
4313
|
+
* fields, e.g., `keyId` and `headers`.
|
|
4314
|
+
*/
|
|
4315
|
+
function parseDraftSignature(signature) {
|
|
4316
|
+
return Object.fromEntries(signature.split(",").map((pair) => pair.match(/^\s*([A-Za-z]+)=(?:"([^"]*)"|(\d+))\s*$/)).filter((m) => m != null).map((m) => [m[1], m[2] ?? m[3]]));
|
|
4317
|
+
}
|
|
4318
|
+
/**
|
|
4319
|
+
* Lists the HTTP Signatures that a request claims to carry, without verifying
|
|
4320
|
+
* any of them. Signatures whose key IDs are not URLs are left out.
|
|
4321
|
+
* @param request The request.
|
|
4322
|
+
* @returns The signatures; RFC 9421 ones if the request has
|
|
4323
|
+
* a `Signature-Input` header, or a draft-cavage one otherwise.
|
|
4324
|
+
* @internal
|
|
4325
|
+
*/
|
|
4326
|
+
function listRequestSignatures(request) {
|
|
4327
|
+
const signatureInput = request.headers.get("Signature-Input");
|
|
4328
|
+
if (signatureInput != null) {
|
|
4329
|
+
const signatures = [];
|
|
4330
|
+
const inputs = parseRfc9421SignatureInput(signatureInput);
|
|
4331
|
+
for (const [label, input] of Object.entries(inputs)) {
|
|
4332
|
+
const keyId = parseKeyId(input.keyId);
|
|
4333
|
+
if (keyId == null) continue;
|
|
4334
|
+
signatures.push({
|
|
4335
|
+
keyId,
|
|
4336
|
+
label,
|
|
4337
|
+
components: input.components
|
|
4338
|
+
});
|
|
4339
|
+
}
|
|
4340
|
+
return signatures;
|
|
4341
|
+
}
|
|
4342
|
+
const signature = request.headers.get("Signature");
|
|
4343
|
+
if (signature == null) return [];
|
|
4344
|
+
const values = parseDraftSignature(signature);
|
|
4345
|
+
const keyId = parseKeyId(values.keyId);
|
|
4346
|
+
if (keyId == null) return [];
|
|
4347
|
+
return [{
|
|
4348
|
+
keyId,
|
|
4349
|
+
label: null,
|
|
4350
|
+
components: (values.headers ?? "").split(/\s+/g).filter((name) => name !== "").map((name) => ({
|
|
4351
|
+
value: name,
|
|
4352
|
+
params: {}
|
|
4353
|
+
}))
|
|
4354
|
+
}];
|
|
4355
|
+
}
|
|
4356
|
+
/**
|
|
4357
|
+
* Makes a copy of a request that carries only one of its RFC 9421 signatures,
|
|
4358
|
+
* so that verifying the copy verifies that signature and no other.
|
|
4359
|
+
* A draft-cavage signature is the only one in its request, so the request is
|
|
4360
|
+
* just copied.
|
|
4361
|
+
* @param request The request, whose body must not be consumed.
|
|
4362
|
+
* @param signature One of the signatures that {@link listRequestSignatures}
|
|
4363
|
+
* lists for the request.
|
|
4364
|
+
* @returns The copy of the request.
|
|
4365
|
+
* @internal
|
|
4366
|
+
*/
|
|
4367
|
+
function selectRequestSignature(request, signature) {
|
|
4368
|
+
const copy = request.clone();
|
|
4369
|
+
if (signature.label == null) return copy;
|
|
4370
|
+
const { label } = signature;
|
|
4371
|
+
const pick = (header) => {
|
|
4372
|
+
if (header == null) return "";
|
|
4373
|
+
let dict;
|
|
4374
|
+
try {
|
|
4375
|
+
dict = decodeDict(header);
|
|
4376
|
+
} catch {
|
|
4377
|
+
return "";
|
|
4378
|
+
}
|
|
4379
|
+
return Object.hasOwn(dict, label) ? encodeDict({ [label]: dict[label] }) : "";
|
|
4380
|
+
};
|
|
4381
|
+
const headers = new Headers(copy.headers);
|
|
4382
|
+
headers.set("Signature-Input", pick(headers.get("Signature-Input")));
|
|
4383
|
+
headers.set("Signature", pick(headers.get("Signature")));
|
|
4384
|
+
return new Request(copy, { headers });
|
|
4385
|
+
}
|
|
4311
4386
|
async function signRequestRfc9421(request, privateKey, keyId, span, currentTime, bodyBuffer, rfc9421Options) {
|
|
4312
4387
|
if (privateKey.algorithm.name !== "RSASSA-PKCS1-v1_5") throw new TypeError("Unsupported algorithm: " + privateKey.algorithm.name);
|
|
4313
4388
|
const url = new URL(request.url);
|
|
@@ -4539,7 +4614,7 @@ async function verifyRequestDraft(request, span, metricsContext, { documentLoade
|
|
|
4539
4614
|
logger.debug("Failed to verify; no Signature header found.", { headers: Object.fromEntries(request.headers.entries()) });
|
|
4540
4615
|
return noSignatureResult();
|
|
4541
4616
|
}
|
|
4542
|
-
const sigValues =
|
|
4617
|
+
const sigValues = parseDraftSignature(sigHeader);
|
|
4543
4618
|
const parsedKeyId = parseKeyId(sigValues.keyId);
|
|
4544
4619
|
const dateHeader = request.headers.get("Date");
|
|
4545
4620
|
if (dateHeader == null) {
|
|
@@ -5212,4 +5287,4 @@ function timingSafeEqual(a, b) {
|
|
|
5212
5287
|
return result === 0;
|
|
5213
5288
|
}
|
|
5214
5289
|
//#endregion
|
|
5215
|
-
export {
|
|
5290
|
+
export { recordCollectionTotalItems as $, isInvalidUrlTypeError as A, generateCryptoKeyPair as B, compactJsonLd as C, hasSignature as D, getNormalizationContextLoader as E, wrapContextLoaderForJsonLd as F, getFederationMetrics as G, validateCryptoKey as H, exportJwk as I, isAbortError$1 as J, getRemoteHost as K, fetchActorDocument as L, verifyCompactJsonLd as M, verifyJsonLd as N, hasSignatureLike as O, verifySignature as P, recordCollectionRequest as Q, fetchKey as R, attachSignature as S, detachSignature as T, verifyKeyOwnership as U, importJwk as V, getDurationMs as W, recordCollectionDispatchDuration as X, recordCircuitBreakerStateChange as Y, recordCollectionPageItems as Z, verifyPortableObjectProofWithRoot as _, isPortableId as _t, signRequest as a, recordWebFingerHandle as at, InvalidContextReferenceError as b, name as bt, fetchPortableGatewayKey as c, formatAcceptSignature as ct, hasProofLike as d, validateAcceptSignature as dt, recordDocumentCache as et, signObject as f, getCanonicalPortableId as ft, verifyPortableObjectProofPolicy as g, isCompatibleKeyId as gt, verifyPortableObjectProof as h, hasPortableActor as ht, selectRequestSignature as i, recordOutboxEnqueue as it, signJsonLd as j, isClearlyMalformedContextReference as k, InvalidPortableObjectIdError as l, fulfillAcceptSignature as lt, verifyObject as m, getPortableDid as mt, listRequestSignatures as n, recordInboxActivity as nt, verifyRequest as o, registerQueueDepthGauge as ot, verifyMapLocalProof as p, getGatewayKeyBase as pt, instrumentDocumentLoader as q, parseRfc9421SignatureInput as r, recordOutboxActivity as rt, verifyRequestDetailed as s, preloadedOnlyDocumentLoader as st, doubleKnock as t, recordFanoutRecipients as tt, createProof as u, parseAcceptSignature as ut, verifyProof as v, isPortableUri as vt, createSignature as w, assertSafeJsonLd as x, version as xt, normalizeOutgoingActivityJsonLd as y, isSamePublicKey as yt, fetchKeyDetailed as z };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Temporal } from "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-
|
|
4
|
+
import { n as version, t as name } from "./deno-dxdvl2XZ.mjs";
|
|
5
|
+
import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-BP3vdBpb.mjs";
|
|
6
6
|
import { i as validateAcceptSignature, n as fulfillAcceptSignature, r as parseAcceptSignature } from "./accept-CPVqki78.mjs";
|
|
7
|
-
import { i as fetchKeyDetailed, s as validateCryptoKey } from "./key-
|
|
8
|
-
import { n as verifyPortableGatewayKeyDocument } from "./portable-key-
|
|
7
|
+
import { i as fetchKeyDetailed, s as validateCryptoKey } from "./key-DYfmjnmp.mjs";
|
|
8
|
+
import { n as verifyPortableGatewayKeyDocument } from "./portable-key-D0mWbV9G.mjs";
|
|
9
9
|
import { getLogger } from "@logtape/logtape";
|
|
10
10
|
import { CryptographicKey } from "@fedify/vocab";
|
|
11
11
|
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
|
@@ -13,7 +13,7 @@ import { FetchError } from "@fedify/vocab-runtime";
|
|
|
13
13
|
import { ATTR_HTTP_REQUEST_HEADER, ATTR_HTTP_REQUEST_METHOD, ATTR_URL_FULL } from "@opentelemetry/semantic-conventions";
|
|
14
14
|
import { decodeBase64, encodeBase64 } from "byte-encodings/base64";
|
|
15
15
|
import { encodeHex } from "byte-encodings/hex";
|
|
16
|
-
import { Item, decodeDict, encodeItem } from "structured-field-values";
|
|
16
|
+
import { Item, decodeDict, encodeDict, encodeItem } from "structured-field-values";
|
|
17
17
|
//#region src/sig/http.ts
|
|
18
18
|
const DEFAULT_MAX_REDIRECTION = 20;
|
|
19
19
|
const DOUBLE_KNOCK_TRANSPORT_RETRY_DELAY_MS = 100;
|
|
@@ -202,6 +202,81 @@ function parseRfc9421Signature(signature) {
|
|
|
202
202
|
for (const [key, value] of Object.entries(dict)) if (value.value instanceof Uint8Array) result[key] = value.value;
|
|
203
203
|
return result;
|
|
204
204
|
}
|
|
205
|
+
/**
|
|
206
|
+
* Parses the `Signature` header of draft-cavage HTTP Signatures into its
|
|
207
|
+
* fields, e.g., `keyId` and `headers`.
|
|
208
|
+
*/
|
|
209
|
+
function parseDraftSignature(signature) {
|
|
210
|
+
return Object.fromEntries(signature.split(",").map((pair) => pair.match(/^\s*([A-Za-z]+)=(?:"([^"]*)"|(\d+))\s*$/)).filter((m) => m != null).map((m) => [m[1], m[2] ?? m[3]]));
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Lists the HTTP Signatures that a request claims to carry, without verifying
|
|
214
|
+
* any of them. Signatures whose key IDs are not URLs are left out.
|
|
215
|
+
* @param request The request.
|
|
216
|
+
* @returns The signatures; RFC 9421 ones if the request has
|
|
217
|
+
* a `Signature-Input` header, or a draft-cavage one otherwise.
|
|
218
|
+
* @internal
|
|
219
|
+
*/
|
|
220
|
+
function listRequestSignatures(request) {
|
|
221
|
+
const signatureInput = request.headers.get("Signature-Input");
|
|
222
|
+
if (signatureInput != null) {
|
|
223
|
+
const signatures = [];
|
|
224
|
+
const inputs = parseRfc9421SignatureInput(signatureInput);
|
|
225
|
+
for (const [label, input] of Object.entries(inputs)) {
|
|
226
|
+
const keyId = parseKeyId(input.keyId);
|
|
227
|
+
if (keyId == null) continue;
|
|
228
|
+
signatures.push({
|
|
229
|
+
keyId,
|
|
230
|
+
label,
|
|
231
|
+
components: input.components
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
return signatures;
|
|
235
|
+
}
|
|
236
|
+
const signature = request.headers.get("Signature");
|
|
237
|
+
if (signature == null) return [];
|
|
238
|
+
const values = parseDraftSignature(signature);
|
|
239
|
+
const keyId = parseKeyId(values.keyId);
|
|
240
|
+
if (keyId == null) return [];
|
|
241
|
+
return [{
|
|
242
|
+
keyId,
|
|
243
|
+
label: null,
|
|
244
|
+
components: (values.headers ?? "").split(/\s+/g).filter((name) => name !== "").map((name) => ({
|
|
245
|
+
value: name,
|
|
246
|
+
params: {}
|
|
247
|
+
}))
|
|
248
|
+
}];
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Makes a copy of a request that carries only one of its RFC 9421 signatures,
|
|
252
|
+
* so that verifying the copy verifies that signature and no other.
|
|
253
|
+
* A draft-cavage signature is the only one in its request, so the request is
|
|
254
|
+
* just copied.
|
|
255
|
+
* @param request The request, whose body must not be consumed.
|
|
256
|
+
* @param signature One of the signatures that {@link listRequestSignatures}
|
|
257
|
+
* lists for the request.
|
|
258
|
+
* @returns The copy of the request.
|
|
259
|
+
* @internal
|
|
260
|
+
*/
|
|
261
|
+
function selectRequestSignature(request, signature) {
|
|
262
|
+
const copy = request.clone();
|
|
263
|
+
if (signature.label == null) return copy;
|
|
264
|
+
const { label } = signature;
|
|
265
|
+
const pick = (header) => {
|
|
266
|
+
if (header == null) return "";
|
|
267
|
+
let dict;
|
|
268
|
+
try {
|
|
269
|
+
dict = decodeDict(header);
|
|
270
|
+
} catch {
|
|
271
|
+
return "";
|
|
272
|
+
}
|
|
273
|
+
return Object.hasOwn(dict, label) ? encodeDict({ [label]: dict[label] }) : "";
|
|
274
|
+
};
|
|
275
|
+
const headers = new Headers(copy.headers);
|
|
276
|
+
headers.set("Signature-Input", pick(headers.get("Signature-Input")));
|
|
277
|
+
headers.set("Signature", pick(headers.get("Signature")));
|
|
278
|
+
return new Request(copy, { headers });
|
|
279
|
+
}
|
|
205
280
|
async function signRequestRfc9421(request, privateKey, keyId, span, currentTime, bodyBuffer, rfc9421Options) {
|
|
206
281
|
if (privateKey.algorithm.name !== "RSASSA-PKCS1-v1_5") throw new TypeError("Unsupported algorithm: " + privateKey.algorithm.name);
|
|
207
282
|
const url = new URL(request.url);
|
|
@@ -433,7 +508,7 @@ async function verifyRequestDraft(request, span, metricsContext, { documentLoade
|
|
|
433
508
|
logger.debug("Failed to verify; no Signature header found.", { headers: Object.fromEntries(request.headers.entries()) });
|
|
434
509
|
return noSignatureResult();
|
|
435
510
|
}
|
|
436
|
-
const sigValues =
|
|
511
|
+
const sigValues = parseDraftSignature(sigHeader);
|
|
437
512
|
const parsedKeyId = parseKeyId(sigValues.keyId);
|
|
438
513
|
const dateHeader = request.headers.get("Date");
|
|
439
514
|
if (dateHeader == null) {
|
|
@@ -1106,4 +1181,4 @@ function timingSafeEqual(a, b) {
|
|
|
1106
1181
|
return result === 0;
|
|
1107
1182
|
}
|
|
1108
1183
|
//#endregion
|
|
1109
|
-
export {
|
|
1184
|
+
export { listRequestSignatures as a, selectRequestSignature as c, verifyRequest as d, verifyRequestDetailed as f, formatRfc9421SignatureParameters as i, signRequest as l, doubleKnock as n, parseRfc9421Signature as o, formatRfc9421Signature as r, parseRfc9421SignatureInput as s, createRfc9421SignatureBase as t, timingSafeEqual as u };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "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-dxdvl2XZ.mjs";
|
|
5
|
+
import { _ as recordKeyLookup, n as getDurationMs, t as classifyFetchError } from "./metrics-BP3vdBpb.mjs";
|
|
6
6
|
import { a as isCompatibleKeyId, o as isPortableActorDocument, s as isPortableId } from "./portable-key-id-Bva5iT3W.mjs";
|
|
7
7
|
import { getLogger } from "@logtape/logtape";
|
|
8
8
|
import { CryptographicKey, Multikey, Object as Object$1, isActor } from "@fedify/vocab";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Temporal } from "temporal-polyfill";
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
|
-
import {
|
|
3
|
+
import { H as validateCryptoKey, et as recordDocumentCache, t as doubleKnock } from "./http-D-rbr_Sy.js";
|
|
4
4
|
import { getLogger } from "@logtape/logtape";
|
|
5
5
|
import { UrlError, createActivityPubRequest, getRemoteDocument, logRequest, preloadedContexts, validatePublicUrl } from "@fedify/vocab-runtime";
|
|
6
6
|
import { curry } from "es-toolkit";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
2
|
-
const require_http = require("./http-
|
|
2
|
+
const require_http = require("./http-C8cZTE3Y.cjs");
|
|
3
3
|
let _logtape_logtape = require("@logtape/logtape");
|
|
4
4
|
let _fedify_vocab_runtime = require("@fedify/vocab-runtime");
|
|
5
5
|
let es_toolkit = require("es-toolkit");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Temporal } from "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-BP3vdBpb.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 "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 { r as fetchKey, s as validateCryptoKey } from "./key-
|
|
4
|
+
import { n as version, t as name } from "./deno-dxdvl2XZ.mjs";
|
|
5
|
+
import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-BP3vdBpb.mjs";
|
|
6
|
+
import { r as fetchKey, s as validateCryptoKey } from "./key-DYfmjnmp.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 "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-dxdvl2XZ.mjs";
|
|
5
5
|
import { metrics } from "@opentelemetry/api";
|
|
6
6
|
import { FetchError } from "@fedify/vocab-runtime";
|
|
7
7
|
//#region src/federation/metrics.ts
|