@fedify/fedify 2.3.0-dev.1110 → 2.3.0-dev.1119
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_rejects-B-qJtC9Z.mjs → assert_rejects-DQP-q39h.mjs} +27 -2
- package/dist/{builder-B-Y6fwSu.mjs → builder-Ond_h57y.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.mjs +1 -1
- package/dist/compat/public-audience.test.mjs +1 -1
- package/dist/compat/transformers.test.mjs +2 -2
- package/dist/{context-C0C_sRha.d.cts → context-Ch-ZLyTQ.d.cts} +1 -1
- package/dist/{context-Dqgt8saU.d.ts → context-cSUMk2da.d.ts} +1 -1
- package/dist/{deno-hqC7tKJn.mjs → deno-DVsHS7rA.mjs} +1 -1
- package/dist/{docloader-BOEuuXkX.mjs → docloader-WsWfKaE5.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 -7
- package/dist/federation/idempotency.test.mjs +5 -5
- package/dist/federation/inbox.test.mjs +1 -1
- package/dist/federation/keycache.test.mjs +1 -1
- package/dist/federation/kv.test.mjs +2 -2
- package/dist/federation/metrics.test.d.mts +2 -0
- package/dist/federation/metrics.test.mjs +107 -0
- package/dist/federation/middleware.test.mjs +390 -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 +2 -2
- package/dist/federation/negotiation.test.mjs +2 -2
- package/dist/federation/router.test.mjs +2 -2
- package/dist/federation/send.test.mjs +11 -11
- package/dist/federation/webfinger.test.mjs +3 -3
- package/dist/{getMachineId-bsd-etIyxDet.mjs → getMachineId-bsd-BY01PL1n.mjs} +1 -1
- package/dist/{getMachineId-darwin-D23zTf4g.mjs → getMachineId-darwin-Dr1gkBkp.mjs} +1 -1
- package/dist/{getMachineId-win-Dpap6v5i.mjs → getMachineId-win-QEYwcJiy.mjs} +1 -1
- package/dist/{http-O8MYWwk8.js → http-CouJSFVK.js} +461 -37
- package/dist/{http-DV0il3vk.cjs → http-CubOB9wq.cjs} +513 -35
- package/dist/{http-BDZeS5om.d.ts → http-D6LP89UO.d.ts} +7 -1
- package/dist/{http-C87EWkO0.d.cts → http-D6aw3j2U.d.cts} +7 -1
- package/dist/{http-BLopFpvC.mjs → http-DUV8ysti.mjs} +86 -37
- package/dist/{key-DW1EVmtP.mjs → key-BoWaYRHm.mjs} +1 -1
- package/dist/{kv-cache-C3NWWiTg.js → kv-cache-DBNpsneh.js} +1 -1
- package/dist/{kv-cache-Dya-TWMe.cjs → kv-cache-Dz31ATUT.cjs} +1 -1
- package/dist/{ld-BNkk2Yal.mjs → ld-B5K1mSuG.mjs} +60 -9
- package/dist/{send-hokVCPu6.mjs → metrics-C4attqv0.mjs} +124 -224
- package/dist/{middleware-D6FbOjuK.mjs → middleware-BDKFRjue.mjs} +1 -1
- package/dist/{middleware-DUWeXjZR.cjs → middleware-CmsDtIHI.cjs} +75 -309
- package/dist/{middleware-CjzI3aYo.js → middleware-Dtjz-hSk.js} +46 -280
- package/dist/{middleware-DA2WTBr4.mjs → middleware-t0jC8I99.mjs} +59 -34
- package/dist/{mod-DXY9JF28.d.cts → mod-B-Lin9Sy.d.ts} +25 -2
- package/dist/{mod-DHO9lk3D.d.ts → mod-BDhgfjP7.d.cts} +25 -2
- package/dist/{mod-B0rWmfW5.d.cts → mod-BR_BB0bh.d.cts} +1 -1
- package/dist/{mod-Dx3-hqyo.d.ts → mod-C6E8rkcz.d.ts} +1 -1
- package/dist/{mod-BhU_H1I_.d.ts → mod-DLrRb0dx.d.ts} +1 -1
- package/dist/{mod-CLPnQPsv.d.cts → mod-P9tE2WmM.d.cts} +1 -1
- package/dist/mod.cjs +4 -4
- package/dist/mod.d.cts +5 -5
- package/dist/mod.d.ts +5 -5
- 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-BgFLCJQ_.mjs → outgoing-jsonld-BNL8AC14.mjs} +1 -1
- package/dist/{owner-jvJAtR5O.mjs → owner-hDxI0ufu.mjs} +2 -2
- package/dist/{proof-BD92WeqV.cjs → proof-BUWfVr6Q.cjs} +78 -11
- package/dist/{proof-mfmHH9j0.mjs → proof-DhVuz4bc.mjs} +25 -7
- package/dist/{proof-5kT7OUPV.js → proof-n60t8o9P.js} +78 -11
- package/dist/send-BPhyR5Oo.mjs +225 -0
- package/dist/sig/accept.test.mjs +1 -1
- package/dist/sig/http.test.mjs +212 -6
- package/dist/sig/key.test.mjs +4 -4
- package/dist/sig/ld.test.mjs +138 -5
- package/dist/sig/mod.cjs +2 -2
- package/dist/sig/mod.d.cts +2 -2
- package/dist/sig/mod.d.ts +2 -2
- package/dist/sig/mod.js +2 -2
- package/dist/sig/owner.test.mjs +4 -4
- package/dist/sig/proof.test.mjs +167 -6
- package/dist/{std__assert-CRDpx_HF.mjs → std__assert-BTEgfoJo.mjs} +2 -27
- package/dist/utils/docloader.test.mjs +5 -5
- 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 +5 -5
- /package/dist/{accept-CceiKpCy.mjs → accept-CgDcxvjV.mjs} +0 -0
- /package/dist/{activity-listener-tztVvlNb.mjs → activity-listener-BeTGV3wc.mjs} +0 -0
- /package/dist/{client-B_A6mfn3.mjs → client-Bneh_DYR.mjs} +0 -0
- /package/dist/{collection-CA3V5zyK.mjs → collection-Cc3DVAhE.mjs} +0 -0
- /package/dist/{execAsync-DCBrgFiV.mjs → execAsync-Dxb7rNf3.mjs} +0 -0
- /package/dist/{getMachineId-linux-ObI47Hql.mjs → getMachineId-linux-Bbhofx-s.mjs} +0 -0
- /package/dist/{getMachineId-unsupported-Ddu-PFeh.mjs → getMachineId-unsupported-dIOte2Ct.mjs} +0 -0
- /package/dist/{keys-C3kae-6B.mjs → keys-CSYsOMFG.mjs} +0 -0
- /package/dist/{kv-x2IvBUyq.mjs → kv-QHE0oeM3.mjs} +0 -0
- /package/dist/{kv-cache-CiiNwT6W.mjs → kv-cache-DihufyAQ.mjs} +0 -0
- /package/dist/{public-audience-N3pyOx2p.mjs → public-audience-c9zmYKgA.mjs} +0 -0
- /package/dist/{types-BFowWFTT.mjs → types-D09GN0uZ.mjs} +0 -0
|
@@ -2,7 +2,7 @@ import { Temporal } from "@js-temporal/polyfill";
|
|
|
2
2
|
import { URLPattern } from "urlpattern-polyfill";
|
|
3
3
|
import { getLogger } from "@logtape/logtape";
|
|
4
4
|
import { CryptographicKey, Object as Object$1, isActor } from "@fedify/vocab";
|
|
5
|
-
import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
5
|
+
import { SpanKind, SpanStatusCode, metrics, trace } from "@opentelemetry/api";
|
|
6
6
|
import { encodeHex } from "byte-encodings/hex";
|
|
7
7
|
import { Item, decodeDict, encodeDict, encodeItem } from "structured-field-values";
|
|
8
8
|
import { FetchError, getDocumentLoader } from "@fedify/vocab-runtime";
|
|
@@ -10,7 +10,7 @@ import { ATTR_HTTP_REQUEST_HEADER, ATTR_HTTP_REQUEST_METHOD, ATTR_URL_FULL } fro
|
|
|
10
10
|
import { decodeBase64, encodeBase64 } from "byte-encodings/base64";
|
|
11
11
|
//#region deno.json
|
|
12
12
|
var name = "@fedify/fedify";
|
|
13
|
-
var version = "2.3.0-dev.
|
|
13
|
+
var version = "2.3.0-dev.1119+6cc02662";
|
|
14
14
|
//#endregion
|
|
15
15
|
//#region src/sig/accept.ts
|
|
16
16
|
/**
|
|
@@ -151,6 +151,382 @@ function fulfillAcceptSignature(entry, localKeyId, localAlg) {
|
|
|
151
151
|
};
|
|
152
152
|
}
|
|
153
153
|
//#endregion
|
|
154
|
+
//#region src/federation/metrics.ts
|
|
155
|
+
var FederationMetrics = class {
|
|
156
|
+
deliverySent;
|
|
157
|
+
deliveryPermanentFailure;
|
|
158
|
+
signatureVerificationFailure;
|
|
159
|
+
signatureVerificationDuration;
|
|
160
|
+
signatureKeyFetchDuration;
|
|
161
|
+
deliveryDuration;
|
|
162
|
+
inboxProcessingDuration;
|
|
163
|
+
httpServerRequestCount;
|
|
164
|
+
httpServerRequestDuration;
|
|
165
|
+
queueTaskEnqueued;
|
|
166
|
+
queueTaskStarted;
|
|
167
|
+
queueTaskCompleted;
|
|
168
|
+
queueTaskFailed;
|
|
169
|
+
queueTaskDuration;
|
|
170
|
+
queueTaskInFlight;
|
|
171
|
+
fanoutRecipients;
|
|
172
|
+
inboxActivity;
|
|
173
|
+
outboxActivity;
|
|
174
|
+
constructor(meterProvider) {
|
|
175
|
+
const meter = meterProvider.getMeter(name, version);
|
|
176
|
+
this.deliverySent = meter.createCounter("activitypub.delivery.sent", {
|
|
177
|
+
description: "ActivityPub delivery attempts.",
|
|
178
|
+
unit: "{attempt}"
|
|
179
|
+
});
|
|
180
|
+
this.deliveryPermanentFailure = meter.createCounter("activitypub.delivery.permanent_failure", {
|
|
181
|
+
description: "ActivityPub deliveries abandoned as permanent failures.",
|
|
182
|
+
unit: "{failure}"
|
|
183
|
+
});
|
|
184
|
+
this.signatureVerificationFailure = meter.createCounter("activitypub.signature.verification_failure", {
|
|
185
|
+
description: "ActivityPub signature verification failures.",
|
|
186
|
+
unit: "{failure}"
|
|
187
|
+
});
|
|
188
|
+
this.signatureVerificationDuration = meter.createHistogram("activitypub.signature.verification.duration", {
|
|
189
|
+
description: "Duration of ActivityPub signature verification, including local key lookup and remote key fetches.",
|
|
190
|
+
unit: "ms"
|
|
191
|
+
});
|
|
192
|
+
this.signatureKeyFetchDuration = meter.createHistogram("activitypub.signature.key_fetch.duration", {
|
|
193
|
+
description: "Duration of public key lookup performed during ActivityPub signature verification.",
|
|
194
|
+
unit: "ms"
|
|
195
|
+
});
|
|
196
|
+
this.deliveryDuration = meter.createHistogram("activitypub.delivery.duration", {
|
|
197
|
+
description: "Duration of ActivityPub delivery attempts.",
|
|
198
|
+
unit: "ms"
|
|
199
|
+
});
|
|
200
|
+
this.inboxProcessingDuration = meter.createHistogram("activitypub.inbox.processing_duration", {
|
|
201
|
+
description: "Duration of ActivityPub inbox listener processing.",
|
|
202
|
+
unit: "ms"
|
|
203
|
+
});
|
|
204
|
+
this.httpServerRequestCount = meter.createCounter("fedify.http.server.request.count", {
|
|
205
|
+
description: "HTTP requests handled by Federation.fetch().",
|
|
206
|
+
unit: "{request}"
|
|
207
|
+
});
|
|
208
|
+
this.httpServerRequestDuration = meter.createHistogram("fedify.http.server.request.duration", {
|
|
209
|
+
description: "Duration of HTTP requests handled by Federation.fetch().",
|
|
210
|
+
unit: "ms",
|
|
211
|
+
advice: { explicitBucketBoundaries: [
|
|
212
|
+
5,
|
|
213
|
+
10,
|
|
214
|
+
25,
|
|
215
|
+
50,
|
|
216
|
+
75,
|
|
217
|
+
100,
|
|
218
|
+
250,
|
|
219
|
+
500,
|
|
220
|
+
750,
|
|
221
|
+
1e3,
|
|
222
|
+
2500,
|
|
223
|
+
5e3,
|
|
224
|
+
7500,
|
|
225
|
+
1e4
|
|
226
|
+
] }
|
|
227
|
+
});
|
|
228
|
+
this.queueTaskEnqueued = meter.createCounter("fedify.queue.task.enqueued", {
|
|
229
|
+
description: "Tasks Fedify enqueued for inbox, outbox, or fanout work.",
|
|
230
|
+
unit: "{task}"
|
|
231
|
+
});
|
|
232
|
+
this.queueTaskStarted = meter.createCounter("fedify.queue.task.started", {
|
|
233
|
+
description: "Tasks Fedify began processing as a queue worker.",
|
|
234
|
+
unit: "{task}"
|
|
235
|
+
});
|
|
236
|
+
this.queueTaskCompleted = meter.createCounter("fedify.queue.task.completed", {
|
|
237
|
+
description: "Queue tasks Fedify finished processing without throwing.",
|
|
238
|
+
unit: "{task}"
|
|
239
|
+
});
|
|
240
|
+
this.queueTaskFailed = meter.createCounter("fedify.queue.task.failed", {
|
|
241
|
+
description: "Queue tasks Fedify abandoned because processing threw.",
|
|
242
|
+
unit: "{task}"
|
|
243
|
+
});
|
|
244
|
+
this.queueTaskDuration = meter.createHistogram("fedify.queue.task.duration", {
|
|
245
|
+
description: "Duration of queue task processing in Fedify workers.",
|
|
246
|
+
unit: "ms",
|
|
247
|
+
advice: { explicitBucketBoundaries: [
|
|
248
|
+
5,
|
|
249
|
+
10,
|
|
250
|
+
25,
|
|
251
|
+
50,
|
|
252
|
+
75,
|
|
253
|
+
100,
|
|
254
|
+
250,
|
|
255
|
+
500,
|
|
256
|
+
750,
|
|
257
|
+
1e3,
|
|
258
|
+
2500,
|
|
259
|
+
5e3,
|
|
260
|
+
7500,
|
|
261
|
+
1e4
|
|
262
|
+
] }
|
|
263
|
+
});
|
|
264
|
+
this.queueTaskInFlight = meter.createUpDownCounter("fedify.queue.task.in_flight", {
|
|
265
|
+
description: "Queue tasks currently being processed in this Fedify process.",
|
|
266
|
+
unit: "{task}"
|
|
267
|
+
});
|
|
268
|
+
this.fanoutRecipients = meter.createHistogram("activitypub.fanout.recipients", {
|
|
269
|
+
description: "Number of recipient inboxes produced by an ActivityPub fanout task.",
|
|
270
|
+
unit: "{recipient}"
|
|
271
|
+
});
|
|
272
|
+
this.inboxActivity = meter.createCounter("activitypub.inbox.activity", {
|
|
273
|
+
description: "ActivityPub activities observed at the inbox lifecycle level: queued, processed, retried, rejected, or abandoned.",
|
|
274
|
+
unit: "{activity}"
|
|
275
|
+
});
|
|
276
|
+
this.outboxActivity = meter.createCounter("activitypub.outbox.activity", {
|
|
277
|
+
description: "ActivityPub activities observed at the outbox lifecycle level: queued, retried, or abandoned. Per-recipient delivery counters live on `activitypub.delivery.*`.",
|
|
278
|
+
unit: "{activity}"
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
recordDelivery(inbox, durationMs, success, activityType) {
|
|
282
|
+
const deliveryAttributes = {
|
|
283
|
+
"activitypub.remote.host": getRemoteHost(inbox),
|
|
284
|
+
"activitypub.delivery.success": success
|
|
285
|
+
};
|
|
286
|
+
if (activityType != null) deliveryAttributes["activitypub.activity.type"] = activityType;
|
|
287
|
+
this.deliverySent.add(1, deliveryAttributes);
|
|
288
|
+
this.deliveryDuration.record(durationMs, deliveryAttributes);
|
|
289
|
+
}
|
|
290
|
+
recordPermanentFailure(inbox, statusCode) {
|
|
291
|
+
this.deliveryPermanentFailure.add(1, {
|
|
292
|
+
"activitypub.remote.host": getRemoteHost(inbox),
|
|
293
|
+
"http.response.status_code": statusCode
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
recordSignatureVerificationFailure(reason, remoteHost) {
|
|
297
|
+
const attributes = { "activitypub.verification.failure_reason": reason };
|
|
298
|
+
if (remoteHost != null) attributes["activitypub.remote.host"] = remoteHost;
|
|
299
|
+
this.signatureVerificationFailure.add(1, attributes);
|
|
300
|
+
}
|
|
301
|
+
recordSignatureVerificationDuration(durationMs, kind, result, extra = {}) {
|
|
302
|
+
const attributes = {
|
|
303
|
+
"activitypub.signature.kind": kind,
|
|
304
|
+
"activitypub.signature.result": result
|
|
305
|
+
};
|
|
306
|
+
if (extra.algorithm != null) attributes["http_signatures.algorithm"] = extra.algorithm;
|
|
307
|
+
if (extra.failureReason != null) attributes["http_signatures.failure_reason"] = extra.failureReason;
|
|
308
|
+
if (extra.ldType != null) attributes["ld_signatures.type"] = extra.ldType;
|
|
309
|
+
if (extra.cryptosuite != null) attributes["object_integrity_proofs.cryptosuite"] = extra.cryptosuite;
|
|
310
|
+
this.signatureVerificationDuration.record(durationMs, attributes);
|
|
311
|
+
}
|
|
312
|
+
recordSignatureKeyFetchDuration(durationMs, kind, result) {
|
|
313
|
+
this.signatureKeyFetchDuration.record(durationMs, {
|
|
314
|
+
"activitypub.signature.kind": kind,
|
|
315
|
+
"activitypub.signature.key_fetch.result": result
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
recordInboxProcessingDuration(activityType, durationMs) {
|
|
319
|
+
this.inboxProcessingDuration.record(durationMs, { "activitypub.activity.type": activityType });
|
|
320
|
+
}
|
|
321
|
+
recordHttpServerRequest(method, endpoint, durationMs, options = {}) {
|
|
322
|
+
const attributes = {
|
|
323
|
+
"http.request.method": normalizeHttpMethod(method),
|
|
324
|
+
"fedify.endpoint": endpoint
|
|
325
|
+
};
|
|
326
|
+
if (options.statusCode != null) attributes["http.response.status_code"] = options.statusCode;
|
|
327
|
+
if (options.routeTemplate != null) attributes["fedify.route.template"] = options.routeTemplate;
|
|
328
|
+
this.httpServerRequestCount.add(1, attributes);
|
|
329
|
+
this.httpServerRequestDuration.record(durationMs, attributes);
|
|
330
|
+
}
|
|
331
|
+
recordQueueTaskEnqueued(common, attempt) {
|
|
332
|
+
const attributes = buildQueueTaskAttributes(common);
|
|
333
|
+
attributes["fedify.queue.task.attempt"] = attempt;
|
|
334
|
+
this.queueTaskEnqueued.add(1, attributes);
|
|
335
|
+
}
|
|
336
|
+
recordQueueTaskStarted(common) {
|
|
337
|
+
this.queueTaskStarted.add(1, buildQueueTaskAttributes(common));
|
|
338
|
+
}
|
|
339
|
+
incrementQueueTaskInFlight(common) {
|
|
340
|
+
this.queueTaskInFlight.add(1, buildQueueTaskInFlightAttributes(common));
|
|
341
|
+
}
|
|
342
|
+
decrementQueueTaskInFlight(common) {
|
|
343
|
+
this.queueTaskInFlight.add(-1, buildQueueTaskInFlightAttributes(common));
|
|
344
|
+
}
|
|
345
|
+
recordQueueTaskOutcome(common, result, durationMs) {
|
|
346
|
+
const attributes = buildQueueTaskAttributes(common);
|
|
347
|
+
attributes["fedify.queue.task.result"] = result;
|
|
348
|
+
if (result === "completed") this.queueTaskCompleted.add(1, attributes);
|
|
349
|
+
else if (result === "failed") this.queueTaskFailed.add(1, attributes);
|
|
350
|
+
this.queueTaskDuration.record(durationMs, attributes);
|
|
351
|
+
}
|
|
352
|
+
recordFanoutRecipients(recipientCount, activityType) {
|
|
353
|
+
const attributes = {};
|
|
354
|
+
if (activityType != null) attributes["activitypub.activity.type"] = activityType;
|
|
355
|
+
this.fanoutRecipients.record(recipientCount, attributes);
|
|
356
|
+
}
|
|
357
|
+
recordInboxActivity(result, activityType) {
|
|
358
|
+
this.inboxActivity.add(1, buildActivityLifecycleAttributes(result, activityType));
|
|
359
|
+
}
|
|
360
|
+
recordOutboxActivity(result, activityType) {
|
|
361
|
+
this.outboxActivity.add(1, buildActivityLifecycleAttributes(result, activityType));
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
function buildActivityLifecycleAttributes(result, activityType) {
|
|
365
|
+
const attributes = { "activitypub.processing.result": result };
|
|
366
|
+
if (activityType != null) attributes["activitypub.activity.type"] = activityType;
|
|
367
|
+
return attributes;
|
|
368
|
+
}
|
|
369
|
+
function buildQueueTaskAttributes(common) {
|
|
370
|
+
const attributes = { "fedify.queue.role": common.role };
|
|
371
|
+
const backend = getQueueBackend(common.queue);
|
|
372
|
+
if (backend != null) attributes["fedify.queue.backend"] = backend;
|
|
373
|
+
const nativeRetrial = common.queue?.nativeRetrial;
|
|
374
|
+
if (typeof nativeRetrial === "boolean") attributes["fedify.queue.native_retrial"] = nativeRetrial;
|
|
375
|
+
if (common.activityType != null) attributes["activitypub.activity.type"] = common.activityType;
|
|
376
|
+
return attributes;
|
|
377
|
+
}
|
|
378
|
+
function buildQueueTaskInFlightAttributes(common) {
|
|
379
|
+
return buildQueueTaskAttributes({
|
|
380
|
+
role: common.role,
|
|
381
|
+
queue: common.queue
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Returns the constructor name of the given message queue, when it is a
|
|
386
|
+
* meaningful identifier. Used as a best-effort `fedify.queue.backend`
|
|
387
|
+
* attribute on queue task metrics; returns `undefined` for plain object
|
|
388
|
+
* literals (whose constructor is `Object`) so the attribute does not appear
|
|
389
|
+
* with a non-informative value.
|
|
390
|
+
* @since 2.3.0
|
|
391
|
+
*/
|
|
392
|
+
function getQueueBackend(queue) {
|
|
393
|
+
const name = queue?.constructor?.name;
|
|
394
|
+
if (name == null || name === "" || name === "Object") return void 0;
|
|
395
|
+
return name;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Records `fedify.queue.task.enqueued` for an outgoing outbox enqueue and,
|
|
399
|
+
* for the initial attempt, also records
|
|
400
|
+
* `activitypub.outbox.activity{queued}`.
|
|
401
|
+
*
|
|
402
|
+
* Both `Context.sendActivity()` and `OutboxContext.forwardActivity()` enqueue
|
|
403
|
+
* outbox messages with the same metric attributes (role, queue, activity
|
|
404
|
+
* type, attempt), so they share this helper rather than each defining a local
|
|
405
|
+
* closure. Retry enqueues (attempt > 0) intentionally do not record a
|
|
406
|
+
* second `activitypub.outbox.activity{queued}`; retries are reported as
|
|
407
|
+
* `result=retried` from the retry-scheduling site, which has the failure
|
|
408
|
+
* context.
|
|
409
|
+
* @since 2.3.0
|
|
410
|
+
*/
|
|
411
|
+
function recordOutboxEnqueue(meterProvider, outboxQueue, message) {
|
|
412
|
+
const metrics = getFederationMetrics(meterProvider);
|
|
413
|
+
metrics.recordQueueTaskEnqueued({
|
|
414
|
+
role: "outbox",
|
|
415
|
+
queue: outboxQueue,
|
|
416
|
+
activityType: message.activityType
|
|
417
|
+
}, message.attempt);
|
|
418
|
+
if (message.attempt === 0) metrics.recordOutboxActivity("queued", message.activityType);
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Records `activitypub.fanout.recipients` with the number of recipient
|
|
422
|
+
* inboxes a single fanout produced. The histogram is unitless count
|
|
423
|
+
* (one measurement per fanout enqueue). Recipient URLs are deliberately
|
|
424
|
+
* not recorded; only the activity type, when known.
|
|
425
|
+
* @since 2.3.0
|
|
426
|
+
*/
|
|
427
|
+
function recordFanoutRecipients(meterProvider, recipientCount, activityType) {
|
|
428
|
+
getFederationMetrics(meterProvider).recordFanoutRecipients(recipientCount, activityType);
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Records one `activitypub.inbox.activity` measurement. The
|
|
432
|
+
* `activitypub.processing.result` attribute is always present;
|
|
433
|
+
* `activitypub.activity.type` is recorded only when Fedify already knows
|
|
434
|
+
* the activity type.
|
|
435
|
+
* @since 2.3.0
|
|
436
|
+
*/
|
|
437
|
+
function recordInboxActivity(meterProvider, result, activityType) {
|
|
438
|
+
getFederationMetrics(meterProvider).recordInboxActivity(result, activityType);
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Records one `activitypub.outbox.activity` measurement. The
|
|
442
|
+
* `activitypub.processing.result` attribute is always present;
|
|
443
|
+
* `activitypub.activity.type` is recorded only when Fedify already knows
|
|
444
|
+
* the activity type (it is always known for outbox lifecycle events).
|
|
445
|
+
* @since 2.3.0
|
|
446
|
+
*/
|
|
447
|
+
function recordOutboxActivity(meterProvider, result, activityType) {
|
|
448
|
+
getFederationMetrics(meterProvider).recordOutboxActivity(result, activityType);
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Times an awaited public key fetch and records exactly one
|
|
452
|
+
* `activitypub.signature.key_fetch.duration` measurement, classifying the
|
|
453
|
+
* outcome as `hit`, `fetched`, or `error` based on the `cached` flag and
|
|
454
|
+
* whether the returned key is non-null. Errors thrown by the fetch are
|
|
455
|
+
* reported as `error` and rethrown, so verifier behavior is unchanged.
|
|
456
|
+
*
|
|
457
|
+
* Shared by the three signature verifiers (HTTP, Linked Data, Object
|
|
458
|
+
* Integrity Proofs); the only per-call variation is the
|
|
459
|
+
* `activitypub.signature.kind` attribute value.
|
|
460
|
+
* @since 2.3.0
|
|
461
|
+
*/
|
|
462
|
+
async function measureSignatureKeyFetch(meterProvider, kind, fetch) {
|
|
463
|
+
const start = performance.now();
|
|
464
|
+
try {
|
|
465
|
+
const result = await fetch();
|
|
466
|
+
getFederationMetrics(meterProvider).recordSignatureKeyFetchDuration(getDurationMs(start), kind, result.key != null ? result.cached ? "hit" : "fetched" : "error");
|
|
467
|
+
return result;
|
|
468
|
+
} catch (error) {
|
|
469
|
+
getFederationMetrics(meterProvider).recordSignatureKeyFetchDuration(getDurationMs(start), kind, "error");
|
|
470
|
+
throw error;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Whether the given thrown value is an `AbortError`.
|
|
475
|
+
*
|
|
476
|
+
* `processQueuedTask` distinguishes aborted tasks (recorded as
|
|
477
|
+
* `fedify.queue.task.result=aborted`) from other failures so that backend
|
|
478
|
+
* shutdown signals do not inflate the `fedify.queue.task.failed` counter.
|
|
479
|
+
* @since 2.3.0
|
|
480
|
+
*/
|
|
481
|
+
function isAbortError$1(error) {
|
|
482
|
+
if (error == null || typeof error !== "object") return false;
|
|
483
|
+
const name = error.name;
|
|
484
|
+
return typeof name === "string" && name === "AbortError";
|
|
485
|
+
}
|
|
486
|
+
const KNOWN_HTTP_METHODS = new Set([
|
|
487
|
+
"CONNECT",
|
|
488
|
+
"DELETE",
|
|
489
|
+
"GET",
|
|
490
|
+
"HEAD",
|
|
491
|
+
"OPTIONS",
|
|
492
|
+
"PATCH",
|
|
493
|
+
"POST",
|
|
494
|
+
"PUT",
|
|
495
|
+
"QUERY",
|
|
496
|
+
"TRACE"
|
|
497
|
+
]);
|
|
498
|
+
function normalizeHttpMethod(method) {
|
|
499
|
+
const upper = method.toUpperCase();
|
|
500
|
+
return KNOWN_HTTP_METHODS.has(upper) ? upper : "_OTHER";
|
|
501
|
+
}
|
|
502
|
+
const federationMetrics = /* @__PURE__ */ new WeakMap();
|
|
503
|
+
/**
|
|
504
|
+
* Gets the cached Fedify metric instruments for a meter provider.
|
|
505
|
+
* @since 2.3.0
|
|
506
|
+
*/
|
|
507
|
+
function getFederationMetrics(meterProvider = metrics.getMeterProvider()) {
|
|
508
|
+
let instruments = federationMetrics.get(meterProvider);
|
|
509
|
+
if (instruments == null) {
|
|
510
|
+
instruments = new FederationMetrics(meterProvider);
|
|
511
|
+
federationMetrics.set(meterProvider, instruments);
|
|
512
|
+
}
|
|
513
|
+
return instruments;
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Gets the bounded remote host attribute value for a URL.
|
|
517
|
+
* @since 2.3.0
|
|
518
|
+
*/
|
|
519
|
+
function getRemoteHost(url) {
|
|
520
|
+
return url.hostname;
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Gets an elapsed duration in milliseconds from a `performance.now()` value.
|
|
524
|
+
* @since 2.3.0
|
|
525
|
+
*/
|
|
526
|
+
function getDurationMs(start) {
|
|
527
|
+
return Math.max(0, performance.now() - start);
|
|
528
|
+
}
|
|
529
|
+
//#endregion
|
|
154
530
|
//#region src/sig/key.ts
|
|
155
531
|
/**
|
|
156
532
|
* Checks if the given key is valid and supported. No-op if the key is valid,
|
|
@@ -799,6 +1175,27 @@ function parseKeyId(value) {
|
|
|
799
1175
|
function getKeyFetchErrorName(error) {
|
|
800
1176
|
return error.name || error.constructor.name || "Error";
|
|
801
1177
|
}
|
|
1178
|
+
/**
|
|
1179
|
+
* Known draft-cavage `algorithm` parameter values, used to keep the
|
|
1180
|
+
* `http_signatures.algorithm` metric attribute on a bounded set. The header
|
|
1181
|
+
* field is attacker-controlled and not used to select the verification
|
|
1182
|
+
* algorithm, so unknown values are dropped from the metric to prevent
|
|
1183
|
+
* cardinality blow-up.
|
|
1184
|
+
*/
|
|
1185
|
+
const DRAFT_KNOWN_ALGORITHMS = new Set([
|
|
1186
|
+
"ecdsa-sha256",
|
|
1187
|
+
"ecdsa-sha384",
|
|
1188
|
+
"ecdsa-sha512",
|
|
1189
|
+
"ed25519",
|
|
1190
|
+
"hs2019",
|
|
1191
|
+
"rsa-sha1",
|
|
1192
|
+
"rsa-sha256",
|
|
1193
|
+
"rsa-sha512"
|
|
1194
|
+
]);
|
|
1195
|
+
function classifyHttpVerifyResult(result) {
|
|
1196
|
+
if (result.verified) return "verified";
|
|
1197
|
+
return result.reason.type === "noSignature" ? "missing" : "rejected";
|
|
1198
|
+
}
|
|
802
1199
|
function recordVerificationResult(span, result) {
|
|
803
1200
|
span.setAttribute("http_signatures.verified", result.verified);
|
|
804
1201
|
if (result.verified === true) return;
|
|
@@ -842,27 +1239,37 @@ async function verifyRequestDetailed(request, options = {}) {
|
|
|
842
1239
|
span.setAttribute(ATTR_URL_FULL, request.url);
|
|
843
1240
|
for (const [name, value] of request.headers) span.setAttribute(ATTR_HTTP_REQUEST_HEADER(name), value);
|
|
844
1241
|
}
|
|
1242
|
+
const start = performance.now();
|
|
1243
|
+
const metricsContext = {};
|
|
1244
|
+
let result;
|
|
1245
|
+
let threw = false;
|
|
845
1246
|
try {
|
|
846
1247
|
let spec = options.spec;
|
|
847
1248
|
if (spec == null) spec = request.headers.has("Signature-Input") ? "rfc9421" : "draft-cavage-http-signatures-12";
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
else result = await verifyRequestDraft(request, span, options);
|
|
1249
|
+
if (spec === "rfc9421") result = await verifyRequestRfc9421(request, span, metricsContext, options);
|
|
1250
|
+
else result = await verifyRequestDraft(request, span, metricsContext, options);
|
|
851
1251
|
recordVerificationResult(span, result);
|
|
852
1252
|
if (!result.verified) span.setStatus({ code: SpanStatusCode.ERROR });
|
|
853
1253
|
return result;
|
|
854
1254
|
} catch (error) {
|
|
1255
|
+
threw = true;
|
|
855
1256
|
span.setStatus({
|
|
856
1257
|
code: SpanStatusCode.ERROR,
|
|
857
1258
|
message: String(error)
|
|
858
1259
|
});
|
|
859
1260
|
throw error;
|
|
860
1261
|
} finally {
|
|
1262
|
+
const classified = threw ? "error" : classifyHttpVerifyResult(result);
|
|
1263
|
+
const failureReason = result != null && !result.verified && result.reason.type !== "noSignature" ? result.reason.type : void 0;
|
|
1264
|
+
getFederationMetrics(options.meterProvider).recordSignatureVerificationDuration(getDurationMs(start), "http", classified, {
|
|
1265
|
+
algorithm: metricsContext.algorithm,
|
|
1266
|
+
failureReason
|
|
1267
|
+
});
|
|
861
1268
|
span.end();
|
|
862
1269
|
}
|
|
863
1270
|
});
|
|
864
1271
|
}
|
|
865
|
-
async function verifyRequestDraft(request, span, { documentLoader, contextLoader, timeWindow, currentTime, keyCache, tracerProvider } = {}) {
|
|
1272
|
+
async function verifyRequestDraft(request, span, metricsContext, { documentLoader, contextLoader, timeWindow, currentTime, keyCache, meterProvider, tracerProvider } = {}) {
|
|
866
1273
|
const logger = getLogger([
|
|
867
1274
|
"fedify",
|
|
868
1275
|
"sig",
|
|
@@ -1010,13 +1417,17 @@ async function verifyRequestDraft(request, span, { documentLoader, contextLoader
|
|
|
1010
1417
|
const keyIdUrl = parseKeyId(keyId);
|
|
1011
1418
|
if (keyIdUrl == null) return invalidSignatureResult(null);
|
|
1012
1419
|
span?.setAttribute("http_signatures.key_id", keyId);
|
|
1013
|
-
if ("algorithm" in sigValues)
|
|
1014
|
-
|
|
1420
|
+
if ("algorithm" in sigValues) {
|
|
1421
|
+
span?.setAttribute("http_signatures.algorithm", sigValues.algorithm);
|
|
1422
|
+
const normalizedAlgorithm = sigValues.algorithm.toLowerCase();
|
|
1423
|
+
if (DRAFT_KNOWN_ALGORITHMS.has(normalizedAlgorithm)) metricsContext.algorithm = normalizedAlgorithm;
|
|
1424
|
+
}
|
|
1425
|
+
const { key, cached, fetchError } = await measureSignatureKeyFetch(meterProvider, "http", () => fetchKeyDetailed(keyIdUrl, CryptographicKey, {
|
|
1015
1426
|
documentLoader,
|
|
1016
1427
|
contextLoader,
|
|
1017
1428
|
keyCache,
|
|
1018
1429
|
tracerProvider
|
|
1019
|
-
});
|
|
1430
|
+
}));
|
|
1020
1431
|
if (fetchError != null) return keyFetchErrorResult(keyIdUrl, fetchError);
|
|
1021
1432
|
if (key == null) return invalidSignatureResult(keyIdUrl);
|
|
1022
1433
|
const headerNames = headers.split(/\s+/g);
|
|
@@ -1038,7 +1449,7 @@ async function verifyRequestDraft(request, span, { documentLoader, contextLoader
|
|
|
1038
1449
|
signature,
|
|
1039
1450
|
message
|
|
1040
1451
|
});
|
|
1041
|
-
return await
|
|
1452
|
+
return await verifyRequestDraft(originalRequest, span, metricsContext, {
|
|
1042
1453
|
documentLoader,
|
|
1043
1454
|
contextLoader,
|
|
1044
1455
|
timeWindow,
|
|
@@ -1046,7 +1457,9 @@ async function verifyRequestDraft(request, span, { documentLoader, contextLoader
|
|
|
1046
1457
|
keyCache: {
|
|
1047
1458
|
get: () => Promise.resolve(void 0),
|
|
1048
1459
|
set: async (keyId, key) => await keyCache?.set(keyId, key)
|
|
1049
|
-
}
|
|
1460
|
+
},
|
|
1461
|
+
meterProvider,
|
|
1462
|
+
tracerProvider
|
|
1050
1463
|
});
|
|
1051
1464
|
}
|
|
1052
1465
|
logger.debug("Failed to verify with the fetched key {keyId}; signature {signature} is invalid. Check if the key is correct or if the signed message is correct. The message to sign is:\n{message}", {
|
|
@@ -1122,7 +1535,7 @@ async function verifyRfc9421ContentDigest(digestHeader, body) {
|
|
|
1122
1535
|
}
|
|
1123
1536
|
return false;
|
|
1124
1537
|
}
|
|
1125
|
-
async function verifyRequestRfc9421(request, span, { documentLoader, contextLoader, timeWindow, currentTime, keyCache, tracerProvider } = {}) {
|
|
1538
|
+
async function verifyRequestRfc9421(request, span, metricsContext, { documentLoader, contextLoader, timeWindow, currentTime, keyCache, meterProvider, tracerProvider } = {}) {
|
|
1126
1539
|
const logger = getLogger([
|
|
1127
1540
|
"fedify",
|
|
1128
1541
|
"sig",
|
|
@@ -1156,9 +1569,14 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
|
|
|
1156
1569
|
return invalidSignatureResult(null);
|
|
1157
1570
|
}
|
|
1158
1571
|
let failure = noSignatureResult();
|
|
1572
|
+
let failureAlgorithm;
|
|
1573
|
+
const setFailure = (result, algorithm) => {
|
|
1574
|
+
failure = result;
|
|
1575
|
+
failureAlgorithm = algorithm;
|
|
1576
|
+
};
|
|
1159
1577
|
for (const sigName of signatureNames) {
|
|
1160
1578
|
if (!signatures[sigName]) {
|
|
1161
|
-
|
|
1579
|
+
setFailure(invalidSignatureResult(parseKeyId(signatureInputs[sigName]?.keyId)));
|
|
1162
1580
|
continue;
|
|
1163
1581
|
}
|
|
1164
1582
|
const sigInput = signatureInputs[sigName];
|
|
@@ -1169,7 +1587,7 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
|
|
|
1169
1587
|
signatureName: sigName,
|
|
1170
1588
|
signatureInput: signatureInputHeader
|
|
1171
1589
|
});
|
|
1172
|
-
|
|
1590
|
+
setFailure(invalidSignatureResult(null));
|
|
1173
1591
|
continue;
|
|
1174
1592
|
}
|
|
1175
1593
|
if (!sigInput.created) {
|
|
@@ -1177,7 +1595,7 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
|
|
|
1177
1595
|
signatureName: sigName,
|
|
1178
1596
|
signatureInput: signatureInputHeader
|
|
1179
1597
|
});
|
|
1180
|
-
|
|
1598
|
+
setFailure(invalidSignatureResult(keyId));
|
|
1181
1599
|
continue;
|
|
1182
1600
|
}
|
|
1183
1601
|
const signatureCreated = Temporal.Instant.fromEpochMilliseconds(sigInput.created * 1e3);
|
|
@@ -1189,14 +1607,14 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
|
|
|
1189
1607
|
created: signatureCreated.toString(),
|
|
1190
1608
|
now: now.toString()
|
|
1191
1609
|
});
|
|
1192
|
-
|
|
1610
|
+
setFailure(invalidSignatureResult(keyId));
|
|
1193
1611
|
continue;
|
|
1194
1612
|
} else if (Temporal.Instant.compare(signatureCreated, now.subtract(tw)) < 0) {
|
|
1195
1613
|
logger.debug("Failed to verify; signature created time is too far in the past.", {
|
|
1196
1614
|
created: signatureCreated.toString(),
|
|
1197
1615
|
now: now.toString()
|
|
1198
1616
|
});
|
|
1199
|
-
|
|
1617
|
+
setFailure(invalidSignatureResult(keyId));
|
|
1200
1618
|
continue;
|
|
1201
1619
|
}
|
|
1202
1620
|
}
|
|
@@ -1204,34 +1622,34 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
|
|
|
1204
1622
|
const contentDigestHeader = request.headers.get("Content-Digest");
|
|
1205
1623
|
if (!contentDigestHeader) {
|
|
1206
1624
|
logger.debug("Failed to verify; Content-Digest header required but not found.", { components: sigInput.components });
|
|
1207
|
-
|
|
1625
|
+
setFailure(invalidSignatureResult(keyId));
|
|
1208
1626
|
continue;
|
|
1209
1627
|
}
|
|
1210
1628
|
if (!await verifyRfc9421ContentDigest(contentDigestHeader, await request.arrayBuffer())) {
|
|
1211
1629
|
logger.debug("Failed to verify; Content-Digest verification failed.", { contentDigest: contentDigestHeader });
|
|
1212
|
-
|
|
1630
|
+
setFailure(invalidSignatureResult(keyId));
|
|
1213
1631
|
continue;
|
|
1214
1632
|
}
|
|
1215
1633
|
}
|
|
1216
1634
|
span?.setAttribute("http_signatures.key_id", sigInput.keyId);
|
|
1217
1635
|
span?.setAttribute("http_signatures.created", sigInput.created.toString());
|
|
1218
1636
|
if (keyId == null) {
|
|
1219
|
-
|
|
1637
|
+
setFailure(invalidSignatureResult(null));
|
|
1220
1638
|
continue;
|
|
1221
1639
|
}
|
|
1222
|
-
const { key, cached, fetchError } = await fetchKeyDetailed(keyId, CryptographicKey, {
|
|
1640
|
+
const { key, cached, fetchError } = await measureSignatureKeyFetch(meterProvider, "http", () => fetchKeyDetailed(keyId, CryptographicKey, {
|
|
1223
1641
|
documentLoader,
|
|
1224
1642
|
contextLoader,
|
|
1225
1643
|
keyCache,
|
|
1226
1644
|
tracerProvider
|
|
1227
|
-
});
|
|
1645
|
+
}));
|
|
1228
1646
|
if (fetchError != null) {
|
|
1229
|
-
|
|
1647
|
+
setFailure(keyFetchErrorResult(keyId, fetchError));
|
|
1230
1648
|
continue;
|
|
1231
1649
|
}
|
|
1232
1650
|
if (!key) {
|
|
1233
1651
|
logger.debug("Failed to fetch key: {keyId}", { keyId: sigInput.keyId });
|
|
1234
|
-
|
|
1652
|
+
setFailure(invalidSignatureResult(keyId));
|
|
1235
1653
|
continue;
|
|
1236
1654
|
}
|
|
1237
1655
|
let alg = sigInput.alg?.toLowerCase();
|
|
@@ -1243,12 +1661,13 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
|
|
|
1243
1661
|
}
|
|
1244
1662
|
if (alg) span?.setAttribute("http_signatures.algorithm", alg);
|
|
1245
1663
|
const algorithm = alg && rfc9421AlgorithmMap[alg];
|
|
1664
|
+
const candidateAlgorithm = algorithm ? alg : void 0;
|
|
1246
1665
|
if (!algorithm) {
|
|
1247
1666
|
logger.debug("Failed to verify; unsupported algorithm: {algorithm}", {
|
|
1248
1667
|
algorithm: sigInput.alg,
|
|
1249
1668
|
supported: Object.keys(rfc9421AlgorithmMap)
|
|
1250
1669
|
});
|
|
1251
|
-
|
|
1670
|
+
setFailure(invalidSignatureResult(keyId));
|
|
1252
1671
|
continue;
|
|
1253
1672
|
}
|
|
1254
1673
|
let signatureBase;
|
|
@@ -1259,20 +1678,22 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
|
|
|
1259
1678
|
error,
|
|
1260
1679
|
signatureInput: sigInput
|
|
1261
1680
|
});
|
|
1262
|
-
|
|
1681
|
+
setFailure(invalidSignatureResult(keyId), candidateAlgorithm);
|
|
1263
1682
|
continue;
|
|
1264
1683
|
}
|
|
1265
1684
|
const signatureBaseBytes = new TextEncoder().encode(signatureBase);
|
|
1266
1685
|
span?.setAttribute("http_signatures.signature", encodeHex(sigBytes));
|
|
1267
1686
|
try {
|
|
1268
|
-
if (await crypto.subtle.verify(algorithm, key.publicKey, sigBytes.slice(), signatureBaseBytes))
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1687
|
+
if (await crypto.subtle.verify(algorithm, key.publicKey, sigBytes.slice(), signatureBaseBytes)) {
|
|
1688
|
+
metricsContext.algorithm = candidateAlgorithm;
|
|
1689
|
+
return {
|
|
1690
|
+
verified: true,
|
|
1691
|
+
key,
|
|
1692
|
+
signatureLabel: sigName
|
|
1693
|
+
};
|
|
1694
|
+
} else if (cached) {
|
|
1274
1695
|
logger.debug("Failed to verify with cached key {keyId}; retrying with fresh key...", { keyId: sigInput.keyId });
|
|
1275
|
-
return await
|
|
1696
|
+
return await verifyRequestRfc9421(originalRequest, span, metricsContext, {
|
|
1276
1697
|
documentLoader,
|
|
1277
1698
|
contextLoader,
|
|
1278
1699
|
timeWindow,
|
|
@@ -1281,14 +1702,16 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
|
|
|
1281
1702
|
get: () => Promise.resolve(void 0),
|
|
1282
1703
|
set: async (keyId, key) => await keyCache?.set(keyId, key)
|
|
1283
1704
|
},
|
|
1284
|
-
spec: "rfc9421"
|
|
1705
|
+
spec: "rfc9421",
|
|
1706
|
+
meterProvider,
|
|
1707
|
+
tracerProvider
|
|
1285
1708
|
});
|
|
1286
1709
|
} else {
|
|
1287
1710
|
logger.debug("Failed to verify signature with fetched key {keyId}; signature invalid.", {
|
|
1288
1711
|
keyId: sigInput.keyId,
|
|
1289
1712
|
signatureBase
|
|
1290
1713
|
});
|
|
1291
|
-
|
|
1714
|
+
setFailure(invalidSignatureResult(keyId), candidateAlgorithm);
|
|
1292
1715
|
}
|
|
1293
1716
|
} catch (error) {
|
|
1294
1717
|
logger.debug("Error during signature verification: {error}", {
|
|
@@ -1296,9 +1719,10 @@ async function verifyRequestRfc9421(request, span, { documentLoader, contextLoad
|
|
|
1296
1719
|
keyId: sigInput.keyId,
|
|
1297
1720
|
algorithm: sigInput.alg
|
|
1298
1721
|
});
|
|
1299
|
-
|
|
1722
|
+
setFailure(invalidSignatureResult(keyId), candidateAlgorithm);
|
|
1300
1723
|
}
|
|
1301
1724
|
}
|
|
1725
|
+
metricsContext.algorithm = failureAlgorithm;
|
|
1302
1726
|
return failure;
|
|
1303
1727
|
}
|
|
1304
1728
|
/**
|
|
@@ -1520,4 +1944,4 @@ function timingSafeEqual(a, b) {
|
|
|
1520
1944
|
return result === 0;
|
|
1521
1945
|
}
|
|
1522
1946
|
//#endregion
|
|
1523
|
-
export { version as _, verifyRequestDetailed as a, fetchKeyDetailed as c, validateCryptoKey as d,
|
|
1947
|
+
export { parseAcceptSignature as C, version as E, fulfillAcceptSignature as S, name as T, recordFanoutRecipients as _, verifyRequestDetailed as a, recordOutboxEnqueue as b, fetchKeyDetailed as c, validateCryptoKey as d, getDurationMs as f, measureSignatureKeyFetch as g, isAbortError$1 as h, verifyRequest as i, generateCryptoKeyPair as l, getRemoteHost as m, parseRfc9421SignatureInput as n, exportJwk as o, getFederationMetrics as p, signRequest as r, fetchKey as s, doubleKnock as t, importJwk as u, recordInboxActivity as v, validateAcceptSignature as w, formatAcceptSignature as x, recordOutboxActivity as y };
|