@fedify/fedify 2.3.0-dev.994 → 2.3.0-pr.809.36
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/README.md +16 -7
- package/dist/{assert-DikXweDx.mjs → assert-OguE97r2.mjs} +1 -1
- package/dist/{assert_instance_of-C4Ri6VuN.mjs → assert_instance_of-DBC5X09g.mjs} +1 -1
- package/dist/{assert_not_equals--wG9hV7u.mjs → assert_not_equals-DkVK8oqV.mjs} +1 -1
- package/dist/{assert_rejects-B-qJtC9Z.mjs → assert_rejects-DN60FHPX.mjs} +28 -3
- package/dist/{assert_strict_equals-Dmjbg-bA.mjs → assert_strict_equals-XEgZAlrj.mjs} +1 -1
- package/dist/{assert_throws-4NwKEy2q.mjs → assert_throws-BOkhLGYc.mjs} +1 -1
- package/dist/{builder-yAlpiIqP.mjs → builder-DSZ7FZmg.mjs} +96 -42
- package/dist/{chunk-nlSIicah.js → chunk-CRNNMoPX.js} +2 -2
- package/dist/circuit-breaker-CSWsyoef.mjs +337 -0
- package/dist/{client-z-8dc-e1.d.cts → client-CAM_bQXx.d.cts} +1 -0
- package/dist/{client-AtlibPOU.d.ts → client-CSddvgWN.d.ts} +1 -2
- package/dist/compat/mod.d.cts +2 -1
- package/dist/compat/mod.d.ts +2 -3
- package/dist/compat/mod.js +3 -3
- package/dist/compat/outgoing-jsonld.test.mjs +4 -4
- package/dist/compat/public-audience.test.mjs +4 -4
- package/dist/compat/transformers.test.mjs +5 -5
- package/dist/{context-BzH2-ajs.d.ts → context-BBVLF7lx.d.cts} +342 -269
- package/dist/{context-DJGagtNd.d.cts → context-BU6jSQdo.d.ts} +344 -266
- package/dist/{context-Dk_tacqz.mjs → context-DVoTs_wM.mjs} +64 -5
- package/dist/{deno-XBVlKnOX.mjs → deno-DCdM7d93.mjs} +1 -1
- package/dist/{docloader-DPp-X6gk.mjs → docloader-B7mVwA5_.mjs} +4 -4
- package/dist/{esm-DVILvP5e.mjs → esm-vrlUxr60.mjs} +4 -7
- package/dist/federation/builder.test.mjs +163 -11
- package/dist/federation/circuit-breaker.test.d.mts +2 -0
- package/dist/federation/circuit-breaker.test.mjs +446 -0
- package/dist/federation/collection.test.mjs +3 -3
- package/dist/federation/handler.test.mjs +1770 -29
- package/dist/federation/idempotency.test.mjs +5 -5
- package/dist/federation/inbox.test.mjs +4 -4
- package/dist/federation/keycache.test.mjs +5 -5
- package/dist/federation/kv.test.mjs +2 -2
- package/dist/federation/metrics.test.d.mts +2 -0
- package/dist/federation/metrics.test.mjs +634 -0
- package/dist/federation/middleware.test.mjs +4036 -146
- package/dist/federation/mod.cjs +195 -14
- package/dist/federation/mod.d.cts +6 -4
- package/dist/federation/mod.d.ts +6 -6
- package/dist/federation/mod.js +192 -14
- package/dist/federation/mq.test.mjs +176 -15
- package/dist/federation/negotiation.test.mjs +4 -4
- package/dist/federation/retry.test.mjs +3 -3
- package/dist/federation/router.test.mjs +190 -9
- package/dist/federation/send.test.mjs +153 -15
- package/dist/federation/temporal.test.d.mts +2 -0
- package/dist/federation/temporal.test.mjs +71 -0
- package/dist/federation/webfinger.test.mjs +150 -5
- package/dist/{http-CSlLA54v.mjs → http-BufbkLuW.mjs} +146 -47
- package/dist/{http-B4rrzxtg.js → http-Dh18nwJg.js} +994 -64
- package/dist/{http-aQzN9Ayi.d.ts → http-VyDTd4G3.d.cts} +15 -3
- package/dist/{http-BrGqJDXL.cjs → http-gOiudB3g.cjs} +1099 -61
- package/dist/{http-CrGuipxe.d.cts → http-lf8Hsd91.d.ts} +15 -1
- package/dist/{key-Bzx--sHD.mjs → key-DZdKLJXT.mjs} +43 -18
- package/dist/{kv-CbLNp3zQ.d.cts → kv-D6hNiMTK.d.ts} +1 -0
- package/dist/{kv-cache-DI-Sk7-I.cjs → kv-cache-BuK_nlpY.cjs} +20 -3
- package/dist/{kv-cache-U__xU4qR.mjs → kv-cache-C7SQnkGI.mjs} +21 -3
- package/dist/{kv-cache-EMIqoIuB.js → kv-cache-DNDSb6Po.js} +20 -3
- package/dist/{kv-GFYnFoOl.d.ts → kv-gJ8LYbxX.d.cts} +1 -3
- package/dist/ld-0Lsznacf.mjs +626 -0
- package/dist/metrics-BHeWd24f.mjs +815 -0
- package/dist/{middleware-zjZ6AFCW.mjs → middleware-BNANvDh2.mjs} +1 -1
- package/dist/{middleware-nidH7VZH.js → middleware-BgzRkDcm.js} +2260 -556
- package/dist/{middleware-An4DjES4.cjs → middleware-D-iES1nQ.cjs} +2318 -623
- package/dist/{middleware-K1g6bEkV.mjs → middleware-EV6J_eAc.mjs} +1639 -373
- package/dist/{mod-CR8soWa9.d.ts → mod-B0hW12_O.d.cts} +26 -4
- package/dist/mod-C0F6kvgS.d.cts +182 -0
- package/dist/{mod-Cr3f-ACa.d.cts → mod-COIAjwRS.d.ts} +26 -2
- package/dist/{mod-CMEbIaNh.d.cts → mod-DFvNJcNb.d.ts} +56 -4
- package/dist/mod-vPYVoa5n.d.ts +182 -0
- package/dist/{mod-CLgIXe9w.d.ts → mod-yvIXFAEi.d.cts} +56 -6
- package/dist/mod.cjs +9 -6
- package/dist/mod.d.cts +12 -10
- package/dist/mod.d.ts +12 -12
- package/dist/mod.js +11 -11
- package/dist/mq-D-nlpY04.d.ts +208 -0
- package/dist/mq-D8uSFzxe.d.cts +208 -0
- package/dist/{negotiation-SQvQgUqe.mjs → negotiation-DDstyBvc.mjs} +29 -0
- package/dist/nodeinfo/client.test.mjs +4 -4
- package/dist/nodeinfo/handler.test.mjs +4 -4
- package/dist/nodeinfo/mod.d.cts +2 -1
- package/dist/nodeinfo/mod.d.ts +2 -3
- package/dist/nodeinfo/mod.js +3 -3
- package/dist/nodeinfo/types.test.mjs +3 -3
- package/dist/otel/exporter.test.mjs +28 -25
- package/dist/otel/mod.cjs +6 -5
- package/dist/otel/mod.d.cts +5 -3
- package/dist/otel/mod.d.ts +5 -5
- package/dist/otel/mod.js +8 -7
- package/dist/{outgoing-jsonld-CNmZLixq.mjs → outgoing-jsonld-L_DbOaFe.mjs} +2 -2
- package/dist/{owner-C-tqfvxn.mjs → owner-Cl-1cAR8.mjs} +2 -2
- package/dist/{owner-CptqhsOy.d.cts → owner-CnngXDNJ.d.ts} +2 -1
- package/dist/{owner-74ARJ5TL.d.ts → owner-DEvZuyOE.d.cts} +2 -3
- package/dist/{proof-Bbbwf8_x.js → proof-CyXndf6-.js} +378 -15
- package/dist/{proof-BlmRPzrK.mjs → proof-Dnz8jtiQ.mjs} +26 -8
- package/dist/{proof-BW89QMVB.cjs → proof-tz35unOj.cjs} +432 -15
- package/dist/runtime/mod.d.cts +1 -0
- package/dist/runtime/mod.d.ts +1 -2
- package/dist/runtime/mod.js +3 -3
- package/dist/{send-05pJLcb6.mjs → send-DIbBYN5P.mjs} +72 -26
- package/dist/sig/http.test.mjs +356 -33
- package/dist/sig/key.test.mjs +103 -6
- package/dist/sig/ld.test.mjs +696 -7
- package/dist/sig/mod.cjs +2 -2
- package/dist/sig/mod.d.cts +4 -3
- package/dist/sig/mod.d.ts +4 -5
- package/dist/sig/mod.js +4 -4
- package/dist/sig/owner.test.mjs +6 -6
- package/dist/sig/proof.test.mjs +169 -8
- package/dist/{std__assert-CRDpx_HF.mjs → std__assert-BBjXFNOb.mjs} +5 -30
- package/dist/temporal-BEwob1Vg.mjs +95 -0
- package/dist/testing/mod.d.mts +110 -10
- package/dist/testing/mod.mjs +1 -2
- package/dist/{transformers-ve6e2xcg.js → transformers-BGMIq1cs.js} +2 -2
- package/dist/{types-hvL8ElAs.js → types-CAY3OdLq.js} +2 -2
- package/dist/utils/docloader.test.mjs +6 -6
- package/dist/utils/kv-cache.test.mjs +67 -2
- package/dist/utils/mod.cjs +1 -1
- package/dist/utils/mod.d.cts +2 -1
- package/dist/utils/mod.d.ts +2 -3
- package/dist/utils/mod.js +3 -3
- package/dist/vocab/cjs.test.mjs +1 -1
- package/dist/vocab/mod.d.cts +1 -0
- package/dist/vocab/mod.d.ts +1 -2
- package/dist/vocab/mod.js +2 -2
- package/package.json +16 -16
- package/dist/ld-DR78beiv.mjs +0 -279
- package/dist/middleware-BFBaR0mF.cjs +0 -4
- package/dist/mod-2d12ffz3.d.ts +0 -64
- package/dist/mod-D35TRn09.d.cts +0 -62
- package/dist/router-CrMLXoOr.mjs +0 -114
- package/dist/{activity-listener-ell7W1s9.mjs → activity-listener-tztVvlNb.mjs} +0 -0
- package/dist/{assert_equals-Ew3jOFa3.mjs → assert_equals-C-ZRDbaf.mjs} +0 -0
- package/dist/{client-D_1QpnWt.mjs → client-ByXmQhYD.mjs} +1 -1
- package/dist/{collection-D-HqUuA2.mjs → collection-Cc3DVAhE.mjs} +0 -0
- package/dist/{keycache-EGATflN-.mjs → keycache-BeU0LCII.mjs} +0 -0
- package/dist/{public-audience-DYFHzm_c.mjs → public-audience-Cvbr2Gzt.mjs} +1 -1
- /package/dist/{retry-bMXBL97A.mjs → retry-CXg_MBI-.mjs} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Temporal } from "@js-temporal/polyfill";
|
|
2
|
-
import "urlpattern-polyfill";
|
|
3
|
-
import {
|
|
2
|
+
import { URLPattern } from "urlpattern-polyfill";
|
|
3
|
+
import { F as version, P as name, _ as measureSignatureKeyFetch, d as validateCryptoKey, f as getDurationMs, p as getFederationMetrics, s as fetchKey } from "./http-Dh18nwJg.js";
|
|
4
4
|
import { getLogger } from "@logtape/logtape";
|
|
5
5
|
import { Activity, CryptographicKey, DataIntegrityProof, Multikey, Object as Object$1, PUBLIC_COLLECTION, getTypeId, isActor } from "@fedify/vocab";
|
|
6
6
|
import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
@@ -15,6 +15,290 @@ const logger$3 = getLogger([
|
|
|
15
15
|
"sig",
|
|
16
16
|
"ld"
|
|
17
17
|
]);
|
|
18
|
+
const localContext = [
|
|
19
|
+
"https://w3id.org/identity/v1",
|
|
20
|
+
"https://www.w3.org/ns/activitystreams",
|
|
21
|
+
"https://w3id.org/security/v1",
|
|
22
|
+
"https://w3id.org/security/data-integrity/v1"
|
|
23
|
+
];
|
|
24
|
+
const localContextUrls = new Set(localContext);
|
|
25
|
+
const builtInContextLoader = getDocumentLoader();
|
|
26
|
+
const disallowedJsonLdKeywords = new Set([
|
|
27
|
+
"@graph",
|
|
28
|
+
"@included",
|
|
29
|
+
"@reverse"
|
|
30
|
+
]);
|
|
31
|
+
/** @internal */
|
|
32
|
+
var UnsafeJsonLdError = class extends TypeError {
|
|
33
|
+
keyword;
|
|
34
|
+
constructor(keyword) {
|
|
35
|
+
super(`Unsupported JSON-LD keyword: ${keyword}.`);
|
|
36
|
+
this.keyword = keyword;
|
|
37
|
+
this.name = "UnsafeJsonLdError";
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
/** @internal */
|
|
41
|
+
var InvalidContextReferenceError = class extends TypeError {
|
|
42
|
+
reference;
|
|
43
|
+
constructor(reference) {
|
|
44
|
+
super(`Invalid JSON-LD context reference: ${reference}.`);
|
|
45
|
+
this.reference = reference;
|
|
46
|
+
this.name = "InvalidContextReferenceError";
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
function createLoadingRemoteContextFailedError(reference, cause) {
|
|
50
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
51
|
+
const error = /* @__PURE__ */ new Error(`Dereferencing a URL did not result in a valid JSON-LD context: ${reference}. ${message}`);
|
|
52
|
+
error.name = "jsonld.InvalidUrl";
|
|
53
|
+
error.details = {
|
|
54
|
+
code: "loading remote context failed",
|
|
55
|
+
url: reference
|
|
56
|
+
};
|
|
57
|
+
error.cause = cause;
|
|
58
|
+
return error;
|
|
59
|
+
}
|
|
60
|
+
/** @internal */
|
|
61
|
+
function isClearlyMalformedContextReference(reference) {
|
|
62
|
+
for (const char of reference) {
|
|
63
|
+
const code = char.charCodeAt(0);
|
|
64
|
+
if (code <= 32 || code === 127) return true;
|
|
65
|
+
}
|
|
66
|
+
if (/^[A-Za-z][A-Za-z0-9+.-]*:/.test(reference) && !URL.canParse(reference)) return true;
|
|
67
|
+
for (let i = 0; i < reference.length; i++) {
|
|
68
|
+
if (reference[i] !== "%") continue;
|
|
69
|
+
if (i + 2 >= reference.length || !/[0-9A-Fa-f]/.test(reference[i + 1]) || !/[0-9A-Fa-f]/.test(reference[i + 2])) return true;
|
|
70
|
+
i += 2;
|
|
71
|
+
}
|
|
72
|
+
if (reference.startsWith("./") || reference.startsWith("../") || reference.startsWith("/") || reference.startsWith("//")) {
|
|
73
|
+
for (const char of reference) if ("[]<>\"\\^`{|}".includes(char)) return true;
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
function cloneRemoteDocument(remoteDocument) {
|
|
78
|
+
return structuredClone(remoteDocument);
|
|
79
|
+
}
|
|
80
|
+
function createMemoizedDocumentLoader(documentLoader) {
|
|
81
|
+
const cache = /* @__PURE__ */ new Map();
|
|
82
|
+
return async (url, options) => {
|
|
83
|
+
const cacheKey = URL.canParse(url) ? new URL(url).href : url;
|
|
84
|
+
let remoteDocument = cache.get(cacheKey);
|
|
85
|
+
if (remoteDocument == null) {
|
|
86
|
+
remoteDocument = Promise.resolve(documentLoader(url, options)).then(cloneRemoteDocument);
|
|
87
|
+
remoteDocument.catch(() => {
|
|
88
|
+
if (cache.get(cacheKey) === remoteDocument) cache.delete(cacheKey);
|
|
89
|
+
});
|
|
90
|
+
cache.set(cacheKey, remoteDocument);
|
|
91
|
+
}
|
|
92
|
+
return cloneRemoteDocument(await remoteDocument);
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/** @internal */
|
|
96
|
+
function wrapContextLoaderForJsonLd(contextLoader) {
|
|
97
|
+
const loader = contextLoader ?? builtInContextLoader;
|
|
98
|
+
return async (url, options) => {
|
|
99
|
+
try {
|
|
100
|
+
return await loader(url, options);
|
|
101
|
+
} catch (error) {
|
|
102
|
+
if (!isInvalidUrlTypeError(error)) throw error;
|
|
103
|
+
if (isClearlyMalformedContextReference(url)) throw new InvalidContextReferenceError(url);
|
|
104
|
+
throw createLoadingRemoteContextFailedError(url, error);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/** @internal */
|
|
109
|
+
function getNormalizationContextLoader(contextLoader) {
|
|
110
|
+
const loader = wrapContextLoaderForJsonLd(contextLoader);
|
|
111
|
+
return createMemoizedDocumentLoader(async (url, options) => {
|
|
112
|
+
if (URL.canParse(url)) {
|
|
113
|
+
const normalizedUrl = new URL(url).href;
|
|
114
|
+
if (localContextUrls.has(normalizedUrl)) return await builtInContextLoader(normalizedUrl, options);
|
|
115
|
+
}
|
|
116
|
+
return await loader(url, options);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/** @internal */
|
|
120
|
+
async function compactJsonLd(jsonLd, contextLoader) {
|
|
121
|
+
const hasLds = typeof jsonLd === "object" && jsonLd != null && "signature" in jsonLd;
|
|
122
|
+
const signature = hasLds ? jsonLd.signature : void 0;
|
|
123
|
+
const normalizationContextLoader = getNormalizationContextLoader(contextLoader);
|
|
124
|
+
const document = hasLds ? detachSignature(jsonLd) : jsonLd;
|
|
125
|
+
await assertNoGraphBeforeCompaction(document, normalizationContextLoader);
|
|
126
|
+
const compacted = await jsonld.compact(document, localContext, { documentLoader: normalizationContextLoader });
|
|
127
|
+
if (hasLds && typeof compacted === "object" && compacted != null) compacted.signature = signature;
|
|
128
|
+
assertSafeJsonLd(compacted);
|
|
129
|
+
return compacted;
|
|
130
|
+
}
|
|
131
|
+
function createInvalidRemoteContextError(reference) {
|
|
132
|
+
const error = /* @__PURE__ */ new Error(`Dereferencing a URL did not result in a JSON object. The response was valid JSON, but it was not a JSON object. URL: "${reference}".`);
|
|
133
|
+
error.name = "jsonld.InvalidUrl";
|
|
134
|
+
error.details = {
|
|
135
|
+
code: "invalid remote context",
|
|
136
|
+
url: reference
|
|
137
|
+
};
|
|
138
|
+
return error;
|
|
139
|
+
}
|
|
140
|
+
function getRemoteContext(remoteDocument, reference) {
|
|
141
|
+
const { contextUrl, documentUrl } = remoteDocument;
|
|
142
|
+
let { document } = remoteDocument;
|
|
143
|
+
if (typeof document === "string") document = JSON.parse(document);
|
|
144
|
+
if (typeof document !== "object" || document == null || Array.isArray(document)) throw createInvalidRemoteContextError(reference);
|
|
145
|
+
let context = "@context" in document ? document["@context"] : {};
|
|
146
|
+
if (contextUrl != null) context = Array.isArray(context) ? [...context, contextUrl] : [context, contextUrl];
|
|
147
|
+
return {
|
|
148
|
+
context,
|
|
149
|
+
baseUrl: documentUrl ?? reference
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function createGraphAliasContextState() {
|
|
153
|
+
return {
|
|
154
|
+
graphTerms: /* @__PURE__ */ new Set(),
|
|
155
|
+
jsonTerms: /* @__PURE__ */ new Set(),
|
|
156
|
+
propertyContexts: /* @__PURE__ */ new Map(),
|
|
157
|
+
termTargets: /* @__PURE__ */ new Map()
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function cloneGraphAliasContextState(state) {
|
|
161
|
+
return {
|
|
162
|
+
graphTerms: new Set(state.graphTerms),
|
|
163
|
+
jsonTerms: new Set(state.jsonTerms),
|
|
164
|
+
propertyContexts: new Map(state.propertyContexts),
|
|
165
|
+
termTargets: new Map(state.termTargets)
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
function resolveContextTarget(target, state) {
|
|
169
|
+
if (target === "@graph") return target;
|
|
170
|
+
const mapped = state.termTargets.get(target);
|
|
171
|
+
if (mapped == null) return target;
|
|
172
|
+
return mapped;
|
|
173
|
+
}
|
|
174
|
+
function getDirectContextTarget(definition) {
|
|
175
|
+
if (definition === null) return null;
|
|
176
|
+
if (typeof definition === "string") return definition;
|
|
177
|
+
if (typeof definition === "object" && definition != null && "@id" in definition) {
|
|
178
|
+
const id = definition["@id"];
|
|
179
|
+
if (id === null) return null;
|
|
180
|
+
if (typeof id === "string") return id;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function isJsonTypedDefinition(definition) {
|
|
184
|
+
return typeof definition === "object" && definition != null && "@type" in definition && definition["@type"] === "@json";
|
|
185
|
+
}
|
|
186
|
+
function resolveLocalContextTarget(target, state, localTargets, seen = /* @__PURE__ */ new Set()) {
|
|
187
|
+
if (target === "@graph") return target;
|
|
188
|
+
if (seen.has(target)) return target;
|
|
189
|
+
seen.add(target);
|
|
190
|
+
if (localTargets.has(target)) {
|
|
191
|
+
const localTarget = localTargets.get(target);
|
|
192
|
+
return localTarget == null ? target : resolveLocalContextTarget(localTarget, state, localTargets, seen);
|
|
193
|
+
}
|
|
194
|
+
return resolveContextTarget(target, state);
|
|
195
|
+
}
|
|
196
|
+
function refreshGraphAliases(state) {
|
|
197
|
+
state.graphTerms.clear();
|
|
198
|
+
for (const [term, target] of state.termTargets) if (target === "@graph") state.graphTerms.add(term);
|
|
199
|
+
}
|
|
200
|
+
function normalizeContextReference(reference, baseUrl) {
|
|
201
|
+
if (baseUrl != null) return new URL(reference, baseUrl).href;
|
|
202
|
+
return URL.canParse(reference) ? new URL(reference).href : reference;
|
|
203
|
+
}
|
|
204
|
+
/** @internal */
|
|
205
|
+
function isInvalidUrlTypeError(error) {
|
|
206
|
+
const code = error.code;
|
|
207
|
+
return error instanceof TypeError && (code === "ERR_INVALID_URL" || /^Invalid URL(?::|$)/.test(error.message) || / cannot be parsed as a URL\.?$/.test(error.message));
|
|
208
|
+
}
|
|
209
|
+
async function applyGraphAliasContext(state, context, documentLoader, remoteContextCache, baseUrl = null, processingContexts = /* @__PURE__ */ new Set()) {
|
|
210
|
+
if (context === null) return createGraphAliasContextState();
|
|
211
|
+
let nextState = cloneGraphAliasContextState(state);
|
|
212
|
+
if (Array.isArray(context)) {
|
|
213
|
+
for (const item of context) nextState = await applyGraphAliasContext(nextState, item, documentLoader, remoteContextCache, baseUrl, processingContexts);
|
|
214
|
+
return nextState;
|
|
215
|
+
}
|
|
216
|
+
if (typeof context === "string") {
|
|
217
|
+
const reference = normalizeContextReference(context, baseUrl);
|
|
218
|
+
const cacheKey = `${baseUrl ?? ""}\n${reference}`;
|
|
219
|
+
if (processingContexts.has(cacheKey)) return nextState;
|
|
220
|
+
processingContexts.add(cacheKey);
|
|
221
|
+
try {
|
|
222
|
+
let remoteContext = remoteContextCache.get(cacheKey);
|
|
223
|
+
if (remoteContext == null) {
|
|
224
|
+
remoteContext = (async () => {
|
|
225
|
+
try {
|
|
226
|
+
return getRemoteContext(await documentLoader(reference), reference);
|
|
227
|
+
} catch (error) {
|
|
228
|
+
if (reference === context && isInvalidUrlTypeError(error) && isClearlyMalformedContextReference(context)) throw new InvalidContextReferenceError(context);
|
|
229
|
+
throw error;
|
|
230
|
+
}
|
|
231
|
+
})();
|
|
232
|
+
remoteContextCache.set(cacheKey, remoteContext);
|
|
233
|
+
}
|
|
234
|
+
const loadedRemoteContext = await remoteContext;
|
|
235
|
+
return await applyGraphAliasContext(nextState, loadedRemoteContext.context, documentLoader, remoteContextCache, loadedRemoteContext.baseUrl, processingContexts);
|
|
236
|
+
} finally {
|
|
237
|
+
processingContexts.delete(cacheKey);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (typeof context === "object" && context != null) {
|
|
241
|
+
if ("@import" in context && typeof context["@import"] === "string") nextState = await applyGraphAliasContext(nextState, context["@import"], documentLoader, remoteContextCache, baseUrl, processingContexts);
|
|
242
|
+
const localTargets = /* @__PURE__ */ new Map();
|
|
243
|
+
for (const [term, definition] of globalThis.Object.entries(context)) {
|
|
244
|
+
if (term.startsWith("@")) continue;
|
|
245
|
+
const target = getDirectContextTarget(definition);
|
|
246
|
+
if (target == null) localTargets.set(term, null);
|
|
247
|
+
else if (typeof target === "string") localTargets.set(term, target);
|
|
248
|
+
else localTargets.delete(term);
|
|
249
|
+
}
|
|
250
|
+
for (const [term, definition] of globalThis.Object.entries(context)) {
|
|
251
|
+
if (term.startsWith("@")) continue;
|
|
252
|
+
if (localTargets.has(term)) {
|
|
253
|
+
const directTarget = localTargets.get(term);
|
|
254
|
+
if (directTarget == null) nextState.termTargets.set(term, null);
|
|
255
|
+
else nextState.termTargets.set(term, resolveLocalContextTarget(directTarget, nextState, localTargets));
|
|
256
|
+
} else nextState.termTargets.delete(term);
|
|
257
|
+
if (typeof definition === "object" && definition != null && "@context" in definition) nextState.propertyContexts.set(term, {
|
|
258
|
+
context: definition["@context"],
|
|
259
|
+
baseUrl
|
|
260
|
+
});
|
|
261
|
+
else nextState.propertyContexts.delete(term);
|
|
262
|
+
if (isJsonTypedDefinition(definition)) nextState.jsonTerms.add(term);
|
|
263
|
+
else nextState.jsonTerms.delete(term);
|
|
264
|
+
}
|
|
265
|
+
refreshGraphAliases(nextState);
|
|
266
|
+
}
|
|
267
|
+
return nextState;
|
|
268
|
+
}
|
|
269
|
+
async function assertNoGraphBeforeCompaction(jsonLd, documentLoader, inheritedState = createGraphAliasContextState(), propertyContext, remoteContextCache = /* @__PURE__ */ new Map()) {
|
|
270
|
+
if (Array.isArray(jsonLd)) {
|
|
271
|
+
for (const item of jsonLd) await assertNoGraphBeforeCompaction(item, documentLoader, inheritedState, propertyContext, remoteContextCache);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
if (typeof jsonLd !== "object" || jsonLd == null) return;
|
|
275
|
+
const jsonLiteralWrapper = isJsonLiteralWrapper(jsonLd);
|
|
276
|
+
let state = inheritedState;
|
|
277
|
+
if (propertyContext !== void 0) state = await applyGraphAliasContext(state, propertyContext.context, documentLoader, remoteContextCache, propertyContext.baseUrl);
|
|
278
|
+
if ("@context" in jsonLd) state = await applyGraphAliasContext(state, jsonLd["@context"], documentLoader, remoteContextCache);
|
|
279
|
+
for (const [key, value] of globalThis.Object.entries(jsonLd)) {
|
|
280
|
+
if (key === "@context") continue;
|
|
281
|
+
if (jsonLiteralWrapper && key === "@value") continue;
|
|
282
|
+
if (key === "@graph" || state.graphTerms.has(key)) throw new UnsafeJsonLdError("@graph");
|
|
283
|
+
if (state.jsonTerms.has(key)) continue;
|
|
284
|
+
await assertNoGraphBeforeCompaction(value, documentLoader, state, state.propertyContexts.get(key), remoteContextCache);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
function isJsonLiteralWrapper(value) {
|
|
288
|
+
return "@value" in value && (value["@type"] === "@json" || value.type === "@json");
|
|
289
|
+
}
|
|
290
|
+
/** @internal */
|
|
291
|
+
function assertSafeJsonLd(jsonLd) {
|
|
292
|
+
if (Array.isArray(jsonLd)) for (const item of jsonLd) assertSafeJsonLd(item);
|
|
293
|
+
else if (typeof jsonLd === "object" && jsonLd != null) {
|
|
294
|
+
const jsonLiteralWrapper = isJsonLiteralWrapper(jsonLd);
|
|
295
|
+
for (const [key, value] of globalThis.Object.entries(jsonLd)) {
|
|
296
|
+
if (disallowedJsonLdKeywords.has(key)) throw new UnsafeJsonLdError(key);
|
|
297
|
+
if (jsonLiteralWrapper && key === "@value") continue;
|
|
298
|
+
assertSafeJsonLd(value);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
18
302
|
/**
|
|
19
303
|
* Attaches a LD signature to the given JSON-LD document.
|
|
20
304
|
* @param jsonLd The JSON-LD document to attach the signature to. It is not
|
|
@@ -145,6 +429,17 @@ function detachSignature(jsonLd) {
|
|
|
145
429
|
}
|
|
146
430
|
/**
|
|
147
431
|
* Verifies Linked Data Signatures of the given JSON-LD document.
|
|
432
|
+
*
|
|
433
|
+
* This is a low-level utility that only checks the cryptographic signature
|
|
434
|
+
* and (optionally) the cached key. It does not run the JSON-LD parsing,
|
|
435
|
+
* attribution, and owner checks that a complete inbound LD verification
|
|
436
|
+
* needs. For incoming activities, prefer {@link verifyJsonLd}, which is
|
|
437
|
+
* the public verification entry point and the one that emits the
|
|
438
|
+
* `activitypub.signature.verification.duration` metric for the LD path.
|
|
439
|
+
* `verifySignature` itself only emits
|
|
440
|
+
* `activitypub.signature.key_fetch.duration`, since the rest of the work
|
|
441
|
+
* that the verification-duration metric is meant to cover happens in
|
|
442
|
+
* `verifyJsonLd`.
|
|
148
443
|
* @param jsonLd The JSON-LD document to verify.
|
|
149
444
|
* @param options Options for verifying the signature.
|
|
150
445
|
* @returns The public key that signed the document or `null` if the signature
|
|
@@ -164,7 +459,7 @@ async function verifySignature(jsonLd, options = {}) {
|
|
|
164
459
|
});
|
|
165
460
|
return null;
|
|
166
461
|
}
|
|
167
|
-
const { key, cached } = await fetchKey(new URL(sig.creator), CryptographicKey, options);
|
|
462
|
+
const { key, cached } = await measureSignatureKeyFetch(options.meterProvider, "linked_data", () => fetchKey(new URL(sig.creator), CryptographicKey, options));
|
|
168
463
|
if (key == null) return null;
|
|
169
464
|
const sigOpts = {
|
|
170
465
|
...sig,
|
|
@@ -204,13 +499,13 @@ async function verifySignature(jsonLd, options = {}) {
|
|
|
204
499
|
keyId: sig.creator,
|
|
205
500
|
...sig
|
|
206
501
|
});
|
|
207
|
-
const { key } = await fetchKey(new URL(sig.creator), CryptographicKey, {
|
|
502
|
+
const { key } = await measureSignatureKeyFetch(options.meterProvider, "linked_data", () => fetchKey(new URL(sig.creator), CryptographicKey, {
|
|
208
503
|
...options,
|
|
209
504
|
keyCache: {
|
|
210
505
|
get: () => Promise.resolve(void 0),
|
|
211
506
|
set: async (keyId, key) => await options.keyCache?.set(keyId, key)
|
|
212
507
|
}
|
|
213
|
-
});
|
|
508
|
+
}));
|
|
214
509
|
if (key == null) return null;
|
|
215
510
|
return await crypto.subtle.verify("RSASSA-PKCS1-v1_5", key.publicKey, signature.slice(), messageBytes) ? key : null;
|
|
216
511
|
}
|
|
@@ -222,6 +517,33 @@ async function verifySignature(jsonLd, options = {}) {
|
|
|
222
517
|
return null;
|
|
223
518
|
}
|
|
224
519
|
/**
|
|
520
|
+
* Known Linked Data Signature `type` values, used to keep
|
|
521
|
+
* `ld_signatures.type` on a bounded set of spec-defined string values.
|
|
522
|
+
* Fedify only signs and verifies `RsaSignature2017`; other values come in
|
|
523
|
+
* only from external documents and are dropped from the metric attribute to
|
|
524
|
+
* avoid attacker-controlled cardinality.
|
|
525
|
+
*/
|
|
526
|
+
const LD_KNOWN_SIGNATURE_TYPES = new Set(["RsaSignature2017"]);
|
|
527
|
+
/**
|
|
528
|
+
* Reports only whether a `signature` key is present on the document, with
|
|
529
|
+
* no shape check on its value. This is intentionally looser than
|
|
530
|
+
* {@link hasSignature} (which validates a full `RsaSignature2017` shape)
|
|
531
|
+
* and {@link hasSignatureLike} (which structurally accepts several known
|
|
532
|
+
* suites): `verifyJsonLd` needs to tell a document with a malformed or
|
|
533
|
+
* unsupported signature payload (classified as `rejected`) apart from a
|
|
534
|
+
* truly unsigned document (classified as `missing`), and only this
|
|
535
|
+
* presence-only check captures both cases.
|
|
536
|
+
*/
|
|
537
|
+
function hasLdSignatureProperty(jsonLd) {
|
|
538
|
+
return typeof jsonLd === "object" && jsonLd != null && "signature" in jsonLd;
|
|
539
|
+
}
|
|
540
|
+
function getLdSignatureObject(jsonLd) {
|
|
541
|
+
if (!hasLdSignatureProperty(jsonLd)) return void 0;
|
|
542
|
+
const { signature } = jsonLd;
|
|
543
|
+
if (typeof signature !== "object" || signature == null || Array.isArray(signature)) return;
|
|
544
|
+
return signature;
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
225
547
|
* Verify the authenticity of the given JSON-LD document using Linked Data
|
|
226
548
|
* Signatures. If the document is signed, this function verifies the signature
|
|
227
549
|
* and checks if the document is attributed to the owner of the public key.
|
|
@@ -231,19 +553,39 @@ async function verifySignature(jsonLd, options = {}) {
|
|
|
231
553
|
* @returns `true` if the document is authentic; `false` otherwise.
|
|
232
554
|
*/
|
|
233
555
|
async function verifyJsonLd(jsonLd, options = {}) {
|
|
556
|
+
return await verifyJsonLdInternal(jsonLd, options, true);
|
|
557
|
+
}
|
|
558
|
+
/** @internal */
|
|
559
|
+
async function verifyCompactJsonLd(jsonLd, options = {}) {
|
|
560
|
+
return await verifyJsonLdInternal(jsonLd, options, false);
|
|
561
|
+
}
|
|
562
|
+
async function verifyJsonLdInternal(jsonLd, options, compact) {
|
|
234
563
|
return await (options.tracerProvider ?? trace.getTracerProvider()).getTracer(name, version).startActiveSpan("ld_signatures.verify", async (span) => {
|
|
564
|
+
const start = performance.now();
|
|
565
|
+
let verified = false;
|
|
566
|
+
let threw = false;
|
|
567
|
+
let signatureType;
|
|
235
568
|
try {
|
|
236
|
-
const
|
|
569
|
+
const verificationOptions = hasSignature(jsonLd) ? {
|
|
570
|
+
...options,
|
|
571
|
+
contextLoader: getNormalizationContextLoader(options.contextLoader)
|
|
572
|
+
} : options;
|
|
573
|
+
const compacted = compact ? hasSignature(jsonLd) ? await compactJsonLd(jsonLd, options.contextLoader) : jsonLd : jsonLd;
|
|
574
|
+
const object = await Object$1.fromJsonLd(compacted, verificationOptions);
|
|
237
575
|
if (object.id != null) span.setAttribute("activitypub.object.id", object.id.href);
|
|
238
576
|
span.setAttribute("activitypub.object.type", getTypeId(object).href);
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
if (
|
|
242
|
-
if (
|
|
577
|
+
const sig = getLdSignatureObject(jsonLd);
|
|
578
|
+
if (sig != null) {
|
|
579
|
+
if (typeof sig.creator === "string") span.setAttribute("ld_signatures.key_id", sig.creator);
|
|
580
|
+
if (typeof sig.signatureValue === "string") span.setAttribute("ld_signatures.signature", sig.signatureValue);
|
|
581
|
+
if (typeof sig.type === "string") {
|
|
582
|
+
span.setAttribute("ld_signatures.type", sig.type);
|
|
583
|
+
if (LD_KNOWN_SIGNATURE_TYPES.has(sig.type)) signatureType = sig.type;
|
|
584
|
+
}
|
|
243
585
|
}
|
|
244
586
|
const attributions = new Set(object.attributionIds.map((uri) => uri.href));
|
|
245
587
|
if (object instanceof Activity) for (const uri of object.actorIds) attributions.add(uri.href);
|
|
246
|
-
const key = await verifySignature(
|
|
588
|
+
const key = await verifySignature(compacted, verificationOptions);
|
|
247
589
|
if (key == null) return false;
|
|
248
590
|
if (key.ownerId == null) {
|
|
249
591
|
logger$3.debug("Key {keyId} has no owner.", { keyId: key.id?.href });
|
|
@@ -254,14 +596,18 @@ async function verifyJsonLd(jsonLd, options = {}) {
|
|
|
254
596
|
logger$3.debug("Some attributions are not authenticated by the Linked Data Signatures: {attributions}.", { attributions: [...attributions] });
|
|
255
597
|
return false;
|
|
256
598
|
}
|
|
599
|
+
verified = true;
|
|
257
600
|
return true;
|
|
258
601
|
} catch (error) {
|
|
602
|
+
threw = true;
|
|
259
603
|
span.setStatus({
|
|
260
604
|
code: SpanStatusCode.ERROR,
|
|
261
605
|
message: String(error)
|
|
262
606
|
});
|
|
263
607
|
throw error;
|
|
264
608
|
} finally {
|
|
609
|
+
const classified = threw ? "error" : verified ? "verified" : hasLdSignatureProperty(jsonLd) ? "rejected" : "missing";
|
|
610
|
+
getFederationMetrics(options.meterProvider).recordSignatureVerificationDuration(getDurationMs(start), "linked_data", classified, { ldType: signatureType });
|
|
265
611
|
span.end();
|
|
266
612
|
}
|
|
267
613
|
});
|
|
@@ -766,6 +1112,15 @@ async function normalizeOutgoingActivityJsonLd(jsonLd, contextLoader) {
|
|
|
766
1112
|
}
|
|
767
1113
|
//#endregion
|
|
768
1114
|
//#region src/sig/proof.ts
|
|
1115
|
+
/**
|
|
1116
|
+
* Known Object Integrity Proof `cryptosuite` values, used to keep
|
|
1117
|
+
* `object_integrity_proofs.cryptosuite` on a bounded set of spec-defined
|
|
1118
|
+
* string values. Fedify currently signs and verifies only
|
|
1119
|
+
* `eddsa-jcs-2022`; other values come in only from external proofs and are
|
|
1120
|
+
* dropped from the metric attribute to avoid attacker-controlled
|
|
1121
|
+
* cardinality.
|
|
1122
|
+
*/
|
|
1123
|
+
const OIP_KNOWN_CRYPTOSUITES = new Set(["eddsa-jcs-2022"]);
|
|
769
1124
|
const logger = getLogger([
|
|
770
1125
|
"fedify",
|
|
771
1126
|
"sig",
|
|
@@ -892,6 +1247,10 @@ async function signObject(object, privateKey, keyId, options = {}) {
|
|
|
892
1247
|
*/
|
|
893
1248
|
async function verifyProof(jsonLd, proof, options = {}) {
|
|
894
1249
|
return await (options.tracerProvider ?? trace.getTracerProvider()).getTracer(name, version).startActiveSpan("object_integrity_proofs.verify", async (span) => {
|
|
1250
|
+
const start = performance.now();
|
|
1251
|
+
let verified = false;
|
|
1252
|
+
let threw = false;
|
|
1253
|
+
const cryptosuite = proof.cryptosuite != null && OIP_KNOWN_CRYPTOSUITES.has(proof.cryptosuite) ? proof.cryptosuite : void 0;
|
|
895
1254
|
if (span.isRecording()) {
|
|
896
1255
|
if (proof.cryptosuite != null) span.setAttribute("object_integrity_proofs.cryptosuite", proof.cryptosuite);
|
|
897
1256
|
if (proof.verificationMethodId != null) span.setAttribute("object_integrity_proofs.key_id", proof.verificationMethodId.href);
|
|
@@ -900,21 +1259,25 @@ async function verifyProof(jsonLd, proof, options = {}) {
|
|
|
900
1259
|
try {
|
|
901
1260
|
const key = await verifyProofInternal(jsonLd, proof, options);
|
|
902
1261
|
if (key == null) span.setStatus({ code: SpanStatusCode.ERROR });
|
|
1262
|
+
else verified = true;
|
|
903
1263
|
return key;
|
|
904
1264
|
} catch (error) {
|
|
1265
|
+
threw = true;
|
|
905
1266
|
span.setStatus({
|
|
906
1267
|
code: SpanStatusCode.ERROR,
|
|
907
1268
|
message: String(error)
|
|
908
1269
|
});
|
|
909
1270
|
throw error;
|
|
910
1271
|
} finally {
|
|
1272
|
+
const classified = threw ? "error" : verified ? "verified" : "rejected";
|
|
1273
|
+
getFederationMetrics(options.meterProvider).recordSignatureVerificationDuration(getDurationMs(start), "object_integrity", classified, { cryptosuite });
|
|
911
1274
|
span.end();
|
|
912
1275
|
}
|
|
913
1276
|
});
|
|
914
1277
|
}
|
|
915
1278
|
async function verifyProofInternal(jsonLd, proof, options) {
|
|
916
1279
|
if (typeof jsonLd !== "object" || jsonLd == null || Array.isArray(jsonLd) || proof.cryptosuite !== "eddsa-jcs-2022" || proof.verificationMethodId == null || proof.proofPurpose !== "assertionMethod" || proof.proofValue == null || proof.created == null) return null;
|
|
917
|
-
const publicKeyPromise = fetchKey(proof.verificationMethodId, Multikey, options);
|
|
1280
|
+
const publicKeyPromise = measureSignatureKeyFetch(options.meterProvider, "object_integrity", () => fetchKey(proof.verificationMethodId, Multikey, options));
|
|
918
1281
|
const proofConfig = {
|
|
919
1282
|
"@context": jsonLd["@context"],
|
|
920
1283
|
type: "DataIntegrityProof",
|
|
@@ -954,7 +1317,7 @@ async function verifyProofInternal(jsonLd, proof, options) {
|
|
|
954
1317
|
proof,
|
|
955
1318
|
keyId: proof.verificationMethodId.href
|
|
956
1319
|
});
|
|
957
|
-
return await
|
|
1320
|
+
return await verifyProofInternal(jsonLd, proof, {
|
|
958
1321
|
...options,
|
|
959
1322
|
keyCache: {
|
|
960
1323
|
get: () => Promise.resolve(void 0),
|
|
@@ -985,7 +1348,7 @@ async function verifyProofInternal(jsonLd, proof, options) {
|
|
|
985
1348
|
keyId: proof.verificationMethodId.href,
|
|
986
1349
|
proof
|
|
987
1350
|
});
|
|
988
|
-
return await
|
|
1351
|
+
return await verifyProofInternal(jsonLd, proof, {
|
|
989
1352
|
...options,
|
|
990
1353
|
keyCache: {
|
|
991
1354
|
get: () => Promise.resolve(void 0),
|
|
@@ -1038,4 +1401,4 @@ async function verifyObject(cls, jsonLd, options = {}) {
|
|
|
1038
1401
|
return object;
|
|
1039
1402
|
}
|
|
1040
1403
|
//#endregion
|
|
1041
|
-
export { verifyProof as a, getKeyOwner as c,
|
|
1404
|
+
export { verifySignature as C, verifyJsonLd as S, hasSignatureLike as _, verifyProof as a, signJsonLd as b, getKeyOwner as c, attachSignature as d, compactJsonLd as f, hasSignature as g, getNormalizationContextLoader as h, verifyObject as i, InvalidContextReferenceError as l, detachSignature as m, hasProofLike as n, normalizeOutgoingActivityJsonLd as o, createSignature as p, signObject as r, doesActorOwnKey as s, createProof as t, assertSafeJsonLd as u, isClearlyMalformedContextReference as v, wrapContextLoaderForJsonLd as w, verifyCompactJsonLd as x, isInvalidUrlTypeError as y };
|
|
@@ -1,16 +1,26 @@
|
|
|
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 { n as
|
|
6
|
-
import { n as
|
|
7
|
-
import {
|
|
4
|
+
import { n as version, t as name } from "./deno-DCdM7d93.mjs";
|
|
5
|
+
import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-BHeWd24f.mjs";
|
|
6
|
+
import { n as fetchKey, o as validateCryptoKey } from "./key-DZdKLJXT.mjs";
|
|
7
|
+
import { n as preloadedOnlyDocumentLoader } from "./public-audience-Cvbr2Gzt.mjs";
|
|
8
|
+
import { r as normalizeOutgoingActivityJsonLd } from "./outgoing-jsonld-L_DbOaFe.mjs";
|
|
9
|
+
import { getLogger } from "@logtape/logtape";
|
|
8
10
|
import { Activity, DataIntegrityProof, Multikey, getTypeId } from "@fedify/vocab";
|
|
9
11
|
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
|
10
|
-
import { getLogger } from "@logtape/logtape";
|
|
11
12
|
import { encodeHex } from "byte-encodings/hex";
|
|
12
13
|
import serialize from "json-canon";
|
|
13
14
|
//#region src/sig/proof.ts
|
|
15
|
+
/**
|
|
16
|
+
* Known Object Integrity Proof `cryptosuite` values, used to keep
|
|
17
|
+
* `object_integrity_proofs.cryptosuite` on a bounded set of spec-defined
|
|
18
|
+
* string values. Fedify currently signs and verifies only
|
|
19
|
+
* `eddsa-jcs-2022`; other values come in only from external proofs and are
|
|
20
|
+
* dropped from the metric attribute to avoid attacker-controlled
|
|
21
|
+
* cardinality.
|
|
22
|
+
*/
|
|
23
|
+
const OIP_KNOWN_CRYPTOSUITES = new Set(["eddsa-jcs-2022"]);
|
|
14
24
|
const logger = getLogger([
|
|
15
25
|
"fedify",
|
|
16
26
|
"sig",
|
|
@@ -137,6 +147,10 @@ async function signObject(object, privateKey, keyId, options = {}) {
|
|
|
137
147
|
*/
|
|
138
148
|
async function verifyProof(jsonLd, proof, options = {}) {
|
|
139
149
|
return await (options.tracerProvider ?? trace.getTracerProvider()).getTracer(name, version).startActiveSpan("object_integrity_proofs.verify", async (span) => {
|
|
150
|
+
const start = performance.now();
|
|
151
|
+
let verified = false;
|
|
152
|
+
let threw = false;
|
|
153
|
+
const cryptosuite = proof.cryptosuite != null && OIP_KNOWN_CRYPTOSUITES.has(proof.cryptosuite) ? proof.cryptosuite : void 0;
|
|
140
154
|
if (span.isRecording()) {
|
|
141
155
|
if (proof.cryptosuite != null) span.setAttribute("object_integrity_proofs.cryptosuite", proof.cryptosuite);
|
|
142
156
|
if (proof.verificationMethodId != null) span.setAttribute("object_integrity_proofs.key_id", proof.verificationMethodId.href);
|
|
@@ -145,21 +159,25 @@ async function verifyProof(jsonLd, proof, options = {}) {
|
|
|
145
159
|
try {
|
|
146
160
|
const key = await verifyProofInternal(jsonLd, proof, options);
|
|
147
161
|
if (key == null) span.setStatus({ code: SpanStatusCode.ERROR });
|
|
162
|
+
else verified = true;
|
|
148
163
|
return key;
|
|
149
164
|
} catch (error) {
|
|
165
|
+
threw = true;
|
|
150
166
|
span.setStatus({
|
|
151
167
|
code: SpanStatusCode.ERROR,
|
|
152
168
|
message: String(error)
|
|
153
169
|
});
|
|
154
170
|
throw error;
|
|
155
171
|
} finally {
|
|
172
|
+
const classified = threw ? "error" : verified ? "verified" : "rejected";
|
|
173
|
+
getFederationMetrics(options.meterProvider).recordSignatureVerificationDuration(getDurationMs(start), "object_integrity", classified, { cryptosuite });
|
|
156
174
|
span.end();
|
|
157
175
|
}
|
|
158
176
|
});
|
|
159
177
|
}
|
|
160
178
|
async function verifyProofInternal(jsonLd, proof, options) {
|
|
161
179
|
if (typeof jsonLd !== "object" || jsonLd == null || Array.isArray(jsonLd) || proof.cryptosuite !== "eddsa-jcs-2022" || proof.verificationMethodId == null || proof.proofPurpose !== "assertionMethod" || proof.proofValue == null || proof.created == null) return null;
|
|
162
|
-
const publicKeyPromise = fetchKey(proof.verificationMethodId, Multikey, options);
|
|
180
|
+
const publicKeyPromise = measureSignatureKeyFetch(options.meterProvider, "object_integrity", () => fetchKey(proof.verificationMethodId, Multikey, options));
|
|
163
181
|
const proofConfig = {
|
|
164
182
|
"@context": jsonLd["@context"],
|
|
165
183
|
type: "DataIntegrityProof",
|
|
@@ -199,7 +217,7 @@ async function verifyProofInternal(jsonLd, proof, options) {
|
|
|
199
217
|
proof,
|
|
200
218
|
keyId: proof.verificationMethodId.href
|
|
201
219
|
});
|
|
202
|
-
return await
|
|
220
|
+
return await verifyProofInternal(jsonLd, proof, {
|
|
203
221
|
...options,
|
|
204
222
|
keyCache: {
|
|
205
223
|
get: () => Promise.resolve(void 0),
|
|
@@ -230,7 +248,7 @@ async function verifyProofInternal(jsonLd, proof, options) {
|
|
|
230
248
|
keyId: proof.verificationMethodId.href,
|
|
231
249
|
proof
|
|
232
250
|
});
|
|
233
|
-
return await
|
|
251
|
+
return await verifyProofInternal(jsonLd, proof, {
|
|
234
252
|
...options,
|
|
235
253
|
keyCache: {
|
|
236
254
|
get: () => Promise.resolve(void 0),
|