@fedify/fedify 2.4.0-dev.2010 → 2.4.0-dev.2030
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-CebeUf0C.mjs → assert-D1Eafmd_.mjs} +1 -1
- package/dist/{assert_equals-CBlRfA-_.mjs → assert_equals-Z6IcEbWU.mjs} +2 -28
- package/dist/{assert_exists-DtzkXC47.mjs → assert_exists-cffSpJ7X.mjs} +1 -1
- package/dist/{assert_false-3pLLLsO4.mjs → assert_false-CPdRnc3E.mjs} +1 -1
- package/dist/{assert_greater_or_equal-BApOTh1h.mjs → assert_greater_or_equal-BlafOF4-.mjs} +2 -1
- package/dist/{assert_instance_of-g3WcyYNR.mjs → assert_instance_of-mrXWWNY-.mjs} +1 -1
- package/dist/{assert_not_equals-BN7yDMWe.mjs → assert_not_equals-CpPK2t89.mjs} +2 -1
- package/dist/{assert_rejects-wFbSPn1O.mjs → assert_rejects-CTptdYck.mjs} +2 -2
- package/dist/{assert_strict_equals-Bpjl4Psw.mjs → assert_strict_equals-CYvBmkpC.mjs} +2 -1
- package/dist/{assert_throws-BJ5wuvR2.mjs → assert_throws-BYITOvPO.mjs} +2 -1
- package/dist/assertion_error-B-cx0fFA.mjs +31 -0
- package/dist/{builder-asm96yV1.mjs → builder-BYJ5otJa.mjs} +2 -2
- package/dist/compat/outgoing-jsonld.test.mjs +71 -3
- package/dist/compat/public-audience.test.mjs +3 -3
- package/dist/compat/secured-document.test.d.mts +2 -0
- package/dist/compat/secured-document.test.mjs +58 -0
- package/dist/compat/transformers.test.mjs +4 -4
- package/dist/{compound-proof-7UIAueLV.mjs → compound-proof-BIvUoJxm.mjs} +74 -2
- package/dist/{deno-Ckq9TwCv.mjs → deno-Vj_9wePq.mjs} +1 -1
- package/dist/{docloader-DUKEPG-O.mjs → docloader-qUudHZVH.mjs} +2 -2
- package/dist/federation/builder.test.mjs +5 -5
- package/dist/federation/circuit-breaker.test.mjs +3 -3
- package/dist/federation/collection.test.mjs +2 -2
- package/dist/federation/compound-fanout.test.d.mts +2 -0
- package/dist/federation/compound-fanout.test.mjs +228 -0
- package/dist/federation/handler-compound-proof.test.mjs +5 -5
- package/dist/federation/handler.test.mjs +11 -11
- package/dist/federation/idempotency.test.mjs +4 -4
- package/dist/federation/inbox.test.mjs +2 -2
- package/dist/federation/keycache.test.mjs +3 -3
- package/dist/federation/kv.test.mjs +2 -2
- package/dist/federation/metrics.test.mjs +4 -4
- package/dist/federation/middleware.test.mjs +17 -17
- package/dist/federation/mod.cjs +1 -1
- package/dist/federation/mod.js +1 -1
- package/dist/federation/mq.test.mjs +7 -6
- package/dist/federation/negotiation.test.mjs +3 -3
- package/dist/federation/outgoing-proof.test.d.mts +2 -0
- package/dist/federation/outgoing-proof.test.mjs +396 -0
- package/dist/federation/retry.test.mjs +3 -2
- package/dist/federation/router.test.mjs +5 -5
- package/dist/federation/send.test.mjs +11 -11
- package/dist/federation/tasks/enqueue.test.mjs +1 -1
- package/dist/federation/tasks/tasks.test.mjs +2 -2
- package/dist/federation/temporal.test.mjs +4 -4
- package/dist/federation/webfinger.test.mjs +4 -4
- package/dist/{federation-CgbvMauV.cjs → federation-CTnaljmy.cjs} +203 -37
- package/dist/{http-DQBfmkrS.cjs → http-B5F1JMh0.cjs} +1 -1
- package/dist/{http-DQA2JOEJ.js → http-By8tnmEr.js} +1 -1
- package/dist/{http-DZaAutqg.mjs → http-D4WPcJUe.mjs} +3 -3
- package/dist/{key-zxzx01Ec.mjs → key-B_Zc5Jbd.mjs} +2 -2
- package/dist/{kv-cache-sy8OMNT8.cjs → kv-cache-8K70pjtX.cjs} +1 -1
- package/dist/{kv-cache-CbrUX90H.mjs → kv-cache-BXdT7pJQ.mjs} +1 -1
- package/dist/{kv-cache-BBoePTOJ.js → kv-cache-BswMKQjC.js} +1 -1
- package/dist/{ld-CD_TN0e8.mjs → ld-B16KUSIQ.mjs} +3 -3
- package/dist/{metrics-B47Cm5gK.mjs → metrics-DpQqUAmh.mjs} +1 -1
- package/dist/{middleware-U_Gannqi.mjs → middleware-BL5HFFVU.mjs} +1 -1
- package/dist/{middleware-pHwDTAnq.mjs → middleware-C7_hqDnl.mjs} +143 -49
- package/dist/{middleware-U0OIuqwD.js → middleware-Cxto6Bq2.js} +204 -38
- package/dist/{mod-UDwMjuHM.d.ts → mod-CNRAxXEb.d.ts} +1 -5
- package/dist/{mod-CbKDOnCt.d.cts → mod-CVQFWefn.d.cts} +1 -5
- package/dist/mod.cjs +4 -4
- package/dist/mod.d.cts +1 -1
- package/dist/mod.d.ts +1 -1
- 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 +3 -3
- package/dist/otel/exporter.test.mjs +2 -2
- package/dist/{outgoing-jsonld-B5Ne7JoL.mjs → outgoing-jsonld-4IJqPYos.mjs} +11 -9
- package/dist/{owner-u3IJRhVx.mjs → owner-BIOIhZoM.mjs} +2 -2
- package/dist/{owner-BNKC3s6G.js → owner-D-E0bT2O.js} +127 -35
- package/dist/{owner--mNatWct.cjs → owner-WUYke16i.cjs} +126 -34
- package/dist/{proof-D3te0SP-.mjs → proof-BVxJu5vv.mjs} +80 -23
- package/dist/{public-audience-Cc2YJ3ip.mjs → public-audience--klBIOk1.mjs} +13 -9
- package/dist/secured-document-CxzZZ9nL.mjs +35 -0
- package/dist/{send-CDr0Zivk.mjs → send-Cr5FJ7iu.mjs} +3 -3
- package/dist/sig/compound-proof-discovery.test.mjs +3 -3
- package/dist/sig/compound-proof-producer.test.d.mts +2 -0
- package/dist/sig/compound-proof-producer.test.mjs +107 -0
- package/dist/sig/compound-proof-verification.test.mjs +5 -5
- package/dist/sig/compound-proof.test.mjs +145 -58
- package/dist/sig/http.test.mjs +11 -10
- package/dist/sig/key.test.mjs +6 -6
- package/dist/sig/ld.test.mjs +9 -9
- package/dist/sig/mod.cjs +2 -2
- package/dist/sig/mod.d.cts +1 -1
- package/dist/sig/mod.d.ts +1 -1
- package/dist/sig/mod.js +2 -2
- package/dist/sig/owner.test.mjs +5 -5
- package/dist/sig/proof.test.mjs +9 -9
- package/dist/std__assert-DvMDRPes.mjs +8 -0
- package/dist/{temporal-DKhVF_Uk.mjs → temporal-CCf0lZV3.mjs} +1 -1
- package/dist/testing/kv.test.mjs +2 -2
- 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.js +1 -1
- package/package.json +6 -6
- package/dist/std__assert-CxFT0MNt.mjs +0 -8
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
const { URLPattern } = require("urlpattern-polyfill");
|
|
2
2
|
const require_rolldown_runtime = require("./rolldown-runtime-Dmm3t92W.cjs");
|
|
3
|
-
const require_http = require("./http-
|
|
3
|
+
const require_http = require("./http-B5F1JMh0.cjs");
|
|
4
4
|
let _logtape_logtape = require("@logtape/logtape");
|
|
5
5
|
let _fedify_vocab = require("@fedify/vocab");
|
|
6
6
|
let _opentelemetry_api = require("@opentelemetry/api");
|
|
7
7
|
let byte_encodings_hex = require("byte-encodings/hex");
|
|
8
8
|
let _fedify_vocab_runtime = require("@fedify/vocab-runtime");
|
|
9
|
+
let _fedify_vocab_runtime_internal_signed_representation = require("@fedify/vocab-runtime/internal/signed-representation");
|
|
9
10
|
let _fedify_vocab_runtime_jsonld = require("@fedify/vocab-runtime/jsonld");
|
|
10
11
|
_fedify_vocab_runtime_jsonld = require_rolldown_runtime.__toESM(_fedify_vocab_runtime_jsonld, 1);
|
|
11
12
|
let json_canon = require("json-canon");
|
|
@@ -30,6 +31,37 @@ const preloadedOnlyDocumentLoader = (url) => {
|
|
|
30
31
|
return Promise.reject(/* @__PURE__ */ new Error("Refusing to fetch a non-preloaded JSON-LD context: " + url));
|
|
31
32
|
};
|
|
32
33
|
//#endregion
|
|
34
|
+
//#region src/compat/secured-document.ts
|
|
35
|
+
function isJsonMap$1(value) {
|
|
36
|
+
return typeof value === "object" && value != null && !Array.isArray(value);
|
|
37
|
+
}
|
|
38
|
+
function isNonEmptyString(value) {
|
|
39
|
+
return typeof value === "string" && value.length > 0;
|
|
40
|
+
}
|
|
41
|
+
function hasDataIntegrityProofType(value) {
|
|
42
|
+
return (Array.isArray(value) ? value : [value]).some((type) => type === "DataIntegrityProof" || type === "https://w3id.org/security#DataIntegrityProof");
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Checks whether a JSON value is a complete, self-contained secured document:
|
|
46
|
+
* a map with its own `@context` and exactly one direct, map-valued `proof`
|
|
47
|
+
* that carries every member `eddsa-jcs-2022` proof generation produces.
|
|
48
|
+
*
|
|
49
|
+
* This is deliberately stricter than {@link hasProofLike}, which exists to
|
|
50
|
+
* decide whether a document is worth verifying. Here a false positive would
|
|
51
|
+
* silently suppress a wire-compatibility fix on an ordinary document, so a
|
|
52
|
+
* partial or malformed proof does not qualify.
|
|
53
|
+
*
|
|
54
|
+
* @internal
|
|
55
|
+
*/
|
|
56
|
+
function isSelfContainedSecuredDocument(value) {
|
|
57
|
+
if (!isJsonMap$1(value)) return false;
|
|
58
|
+
if (!Object.hasOwn(value, "@context") || value["@context"] == null) return false;
|
|
59
|
+
if (!Object.hasOwn(value, "proof")) return false;
|
|
60
|
+
const proof = value.proof;
|
|
61
|
+
if (!isJsonMap$1(proof)) return false;
|
|
62
|
+
return hasDataIntegrityProofType(proof.type) && isNonEmptyString(proof.cryptosuite) && isNonEmptyString(proof.created) && isNonEmptyString(proof.verificationMethod) && isNonEmptyString(proof.proofPurpose) && isNonEmptyString(proof.proofValue);
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
33
65
|
//#region src/compat/public-audience.ts
|
|
34
66
|
const logger$4 = (0, _logtape_logtape.getLogger)([
|
|
35
67
|
"fedify",
|
|
@@ -46,37 +78,39 @@ const PUBLIC_ADDRESSING_FIELDS = /* @__PURE__ */ new Set([
|
|
|
46
78
|
const AS_CONTEXT_URL$1 = "https://www.w3.org/ns/activitystreams";
|
|
47
79
|
const MAX_TRAVERSAL_DEPTH$1 = 64;
|
|
48
80
|
const KNOWN_SAFE_CONTEXT_URLS$1 = new Set(Object.keys(_fedify_vocab_runtime.preloadedContexts));
|
|
49
|
-
function hasPublicCurieInAddressing(value, parentKey, depth = 0) {
|
|
81
|
+
function hasPublicCurieInAddressing(value, preserveSecured, parentKey, depth = 0) {
|
|
50
82
|
if (typeof value === "string") return parentKey != null && PUBLIC_ADDRESSING_FIELDS.has(parentKey) && (value === "as:Public" || value === "Public");
|
|
51
83
|
if (depth >= MAX_TRAVERSAL_DEPTH$1) return false;
|
|
52
|
-
if (Array.isArray(value)) return value.some((item) => hasPublicCurieInAddressing(item, parentKey, depth + 1));
|
|
84
|
+
if (Array.isArray(value)) return value.some((item) => hasPublicCurieInAddressing(item, preserveSecured, parentKey, depth + 1));
|
|
53
85
|
if (typeof value !== "object" || value == null) return false;
|
|
86
|
+
if (preserveSecured && depth > 0 && isSelfContainedSecuredDocument(value)) return false;
|
|
54
87
|
const record = value;
|
|
55
88
|
for (const key of Object.keys(record)) {
|
|
56
89
|
if (record.type === "Follow" && key === "object" && (record[key] === "as:Public" || record[key] === "Public")) return true;
|
|
57
90
|
if (key === "@context") continue;
|
|
58
|
-
if (hasPublicCurieInAddressing(record[key], key, depth + 1)) return true;
|
|
91
|
+
if (hasPublicCurieInAddressing(record[key], preserveSecured, key, depth + 1)) return true;
|
|
59
92
|
}
|
|
60
93
|
return false;
|
|
61
94
|
}
|
|
62
|
-
function rewritePublicAudience(value, parentKey, depth = 0) {
|
|
95
|
+
function rewritePublicAudience(value, preserveSecured, parentKey, depth = 0) {
|
|
63
96
|
if (typeof value === "string" && parentKey != null && PUBLIC_ADDRESSING_FIELDS.has(parentKey) && (value === "as:Public" || value === "Public")) return _fedify_vocab.PUBLIC_COLLECTION.href;
|
|
64
97
|
if (depth >= MAX_TRAVERSAL_DEPTH$1) return value;
|
|
65
98
|
if (Array.isArray(value)) {
|
|
66
99
|
let changed = false;
|
|
67
100
|
const mapped = value.map((item) => {
|
|
68
|
-
const rewritten = rewritePublicAudience(item, parentKey, depth + 1);
|
|
101
|
+
const rewritten = rewritePublicAudience(item, preserveSecured, parentKey, depth + 1);
|
|
69
102
|
if (rewritten !== item) changed = true;
|
|
70
103
|
return rewritten;
|
|
71
104
|
});
|
|
72
105
|
return changed ? mapped : value;
|
|
73
106
|
}
|
|
74
107
|
if (typeof value !== "object" || value == null) return value;
|
|
108
|
+
if (preserveSecured && depth > 0 && isSelfContainedSecuredDocument(value)) return value;
|
|
75
109
|
const record = value;
|
|
76
110
|
let changed = false;
|
|
77
111
|
const normalized = Object.create(null);
|
|
78
112
|
for (const key of Object.keys(record)) {
|
|
79
|
-
const rewritten = key === "@context" ? record[key] : record.type === "Follow" && key === "object" && (record[key] === "as:Public" || record[key] === "Public") ? _fedify_vocab.PUBLIC_COLLECTION.href : rewritePublicAudience(record[key], key, depth + 1);
|
|
113
|
+
const rewritten = key === "@context" ? record[key] : record.type === "Follow" && key === "object" && (record[key] === "as:Public" || record[key] === "Public") ? _fedify_vocab.PUBLIC_COLLECTION.href : rewritePublicAudience(record[key], preserveSecured, key, depth + 1);
|
|
80
114
|
if (rewritten !== record[key]) changed = true;
|
|
81
115
|
normalized[key] = rewritten;
|
|
82
116
|
}
|
|
@@ -175,9 +209,10 @@ function hasKnownSafeContext$1(jsonLd) {
|
|
|
175
209
|
* using the `eddsa-jcs-2022` cryptosuite), so the signed payload
|
|
176
210
|
* matches what is sent on the wire.
|
|
177
211
|
*/
|
|
178
|
-
async function normalizePublicAudience(jsonLd, contextLoader) {
|
|
179
|
-
|
|
180
|
-
|
|
212
|
+
async function normalizePublicAudience(jsonLd, contextLoader, options = {}) {
|
|
213
|
+
const preserveSecured = options.preserveNestedSecuredDocuments ?? false;
|
|
214
|
+
if (!hasPublicCurieInAddressing(jsonLd, preserveSecured)) return jsonLd;
|
|
215
|
+
const normalized = rewritePublicAudience(jsonLd, preserveSecured);
|
|
181
216
|
if (hasKnownSafeContext$1(jsonLd)) return normalized;
|
|
182
217
|
const loader = contextLoader ?? preloadedOnlyDocumentLoader;
|
|
183
218
|
try {
|
|
@@ -255,13 +290,14 @@ function getKnownSafeContextUrls() {
|
|
|
255
290
|
/**
|
|
256
291
|
* Wraps scalar ActivityStreams attachment properties in arrays.
|
|
257
292
|
*/
|
|
258
|
-
function wrapScalarAttachments(jsonLd, depth = 0) {
|
|
293
|
+
function wrapScalarAttachments(jsonLd, preserveSecured, depth = 0) {
|
|
259
294
|
if (depth >= MAX_TRAVERSAL_DEPTH) return jsonLd;
|
|
295
|
+
if (preserveSecured && depth > 0 && isSelfContainedSecuredDocument(jsonLd)) return jsonLd;
|
|
260
296
|
if (Array.isArray(jsonLd)) {
|
|
261
297
|
let normalized = null;
|
|
262
298
|
for (let i = 0; i < jsonLd.length; i++) {
|
|
263
299
|
const item = jsonLd[i];
|
|
264
|
-
const next = wrapScalarAttachments(item, depth + 1);
|
|
300
|
+
const next = wrapScalarAttachments(item, preserveSecured, depth + 1);
|
|
265
301
|
if (normalized == null && next !== item) normalized = jsonLd.slice(0, i);
|
|
266
302
|
if (normalized != null) normalized[i] = next;
|
|
267
303
|
}
|
|
@@ -274,7 +310,7 @@ function wrapScalarAttachments(jsonLd, depth = 0) {
|
|
|
274
310
|
for (let i = 0; i < keys.length; i++) {
|
|
275
311
|
const key = keys[i];
|
|
276
312
|
const value = record[key];
|
|
277
|
-
const next = key === "@context" || key === "@value" && isJsonLdValueObject(jsonLd) ? value : wrapScalarAttachments(value, depth + 1);
|
|
313
|
+
const next = key === "@context" || key === "@value" && isJsonLdValueObject(jsonLd) ? value : wrapScalarAttachments(value, preserveSecured, depth + 1);
|
|
278
314
|
const output = ATTACHMENT_FIELDS.has(key) && next != null && !Array.isArray(next) && !isJsonLdListObject(next) ? [next] : next;
|
|
279
315
|
if (normalized == null && output !== value) {
|
|
280
316
|
const cloned = Object.create(null);
|
|
@@ -357,8 +393,8 @@ function getLogSafeJsonLdMetadata(jsonLd) {
|
|
|
357
393
|
* the semantic-preservation check to succeed; otherwise canonicalization
|
|
358
394
|
* failures leave the original document unchanged.
|
|
359
395
|
*/
|
|
360
|
-
async function normalizeAttachmentArrays(jsonLd, contextLoader) {
|
|
361
|
-
const normalized = wrapScalarAttachments(jsonLd);
|
|
396
|
+
async function normalizeAttachmentArrays(jsonLd, contextLoader, options = {}) {
|
|
397
|
+
const normalized = wrapScalarAttachments(jsonLd, options.preserveNestedSecuredDocuments ?? false);
|
|
362
398
|
if (normalized === jsonLd) return jsonLd;
|
|
363
399
|
if (exceedsTraversalDepth(jsonLd)) {
|
|
364
400
|
logger$3.debug("Skipping attachment array normalization because the JSON-LD document exceeds the safe traversal depth; leaving it unchanged.");
|
|
@@ -386,9 +422,9 @@ async function normalizeAttachmentArrays(jsonLd, contextLoader) {
|
|
|
386
422
|
* to locally generated outgoing activities before they are signed, enqueued,
|
|
387
423
|
* or sent.
|
|
388
424
|
*/
|
|
389
|
-
async function normalizeOutgoingActivityJsonLd(jsonLd, contextLoader) {
|
|
390
|
-
jsonLd = await normalizePublicAudience(jsonLd, contextLoader);
|
|
391
|
-
return await normalizeAttachmentArrays(jsonLd, contextLoader);
|
|
425
|
+
async function normalizeOutgoingActivityJsonLd(jsonLd, contextLoader, options = {}) {
|
|
426
|
+
jsonLd = await normalizePublicAudience(jsonLd, contextLoader, options);
|
|
427
|
+
return await normalizeAttachmentArrays(jsonLd, contextLoader, options);
|
|
392
428
|
}
|
|
393
429
|
//#endregion
|
|
394
430
|
//#region src/sig/ld.ts
|
|
@@ -1058,17 +1094,49 @@ function hasProofLike(jsonLd) {
|
|
|
1058
1094
|
};
|
|
1059
1095
|
return Array.isArray(proof) ? proof.some(isProofLike) : isProofLike(proof);
|
|
1060
1096
|
}
|
|
1097
|
+
function isJsonMap(value) {
|
|
1098
|
+
return typeof value === "object" && value != null && !Array.isArray(value);
|
|
1099
|
+
}
|
|
1061
1100
|
/**
|
|
1062
|
-
*
|
|
1063
|
-
*
|
|
1064
|
-
*
|
|
1065
|
-
*
|
|
1066
|
-
*
|
|
1067
|
-
* @
|
|
1068
|
-
*
|
|
1069
|
-
*
|
|
1101
|
+
* Assembles the secured JSON document from the bytes that were just signed.
|
|
1102
|
+
*
|
|
1103
|
+
* The document is not re-derived from the vocabulary object: it is
|
|
1104
|
+
* `compactMsg`, the value whose JCS form was hashed, with the serialized
|
|
1105
|
+
* proof added. Every part of it is then checked against the digests and the
|
|
1106
|
+
* signature that {@link createProofInternal} produced, so a document that is
|
|
1107
|
+
* returned verifies under the map-local compound-proof profile by
|
|
1108
|
+
* construction. Anything that does not check out yields `null`, and the
|
|
1109
|
+
* caller simply does not retain a representation.
|
|
1070
1110
|
*/
|
|
1071
|
-
async function
|
|
1111
|
+
async function captureSecuredDocument(proof, compactMsg, msgCanon, proofCanon, proofValue, contextLoader) {
|
|
1112
|
+
if (!isJsonMap(compactMsg)) return null;
|
|
1113
|
+
const documentContext = compactMsg["@context"];
|
|
1114
|
+
if (documentContext == null) return null;
|
|
1115
|
+
if (globalThis.Object.hasOwn(compactMsg, "proof")) return null;
|
|
1116
|
+
try {
|
|
1117
|
+
const proofJson = await proof.toJsonLd({
|
|
1118
|
+
format: "compact",
|
|
1119
|
+
contextLoader,
|
|
1120
|
+
context: documentContext
|
|
1121
|
+
});
|
|
1122
|
+
if (!isJsonMap(proofJson)) return null;
|
|
1123
|
+
const { proofValue: serializedProofValue, ...proofConfiguration } = proofJson;
|
|
1124
|
+
if (serializedProofValue !== proofValue) return null;
|
|
1125
|
+
if ((0, json_canon.default)(proofConfiguration) !== proofCanon) return null;
|
|
1126
|
+
const securedDocument = {
|
|
1127
|
+
...structuredClone(compactMsg),
|
|
1128
|
+
proof: structuredClone(proofJson)
|
|
1129
|
+
};
|
|
1130
|
+
const { proof: _embeddedProof, ...unsecuredDocument } = securedDocument;
|
|
1131
|
+
if ((0, json_canon.default)(unsecuredDocument) !== msgCanon) return null;
|
|
1132
|
+
if (!(0, _fedify_vocab_runtime_internal_signed_representation.isPlainJsonTree)(securedDocument)) return null;
|
|
1133
|
+
return securedDocument;
|
|
1134
|
+
} catch (error) {
|
|
1135
|
+
logger$1.debug("Failed to capture the secured JSON document for a created proof; the signed object will not preserve its representation when it is embedded in another object.\n{error}", { error });
|
|
1136
|
+
return null;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
async function createProofInternal(object, privateKey, keyId, { contextLoader, context, created } = {}, capture = false) {
|
|
1072
1140
|
require_http.validateCryptoKey(privateKey, "private");
|
|
1073
1141
|
if (privateKey.algorithm.name !== "Ed25519") throw new TypeError("Unsupported algorithm: " + privateKey.algorithm.name);
|
|
1074
1142
|
let compactMsg = await object.clone({ proofs: [] }).toJsonLd({
|
|
@@ -1076,7 +1144,7 @@ async function createProof(object, privateKey, keyId, { contextLoader, context,
|
|
|
1076
1144
|
contextLoader,
|
|
1077
1145
|
context
|
|
1078
1146
|
});
|
|
1079
|
-
compactMsg = await normalizeOutgoingActivityJsonLd(compactMsg, contextLoader);
|
|
1147
|
+
compactMsg = await normalizeOutgoingActivityJsonLd(compactMsg, contextLoader, { preserveNestedSecuredDocuments: true });
|
|
1080
1148
|
const msgCanon = (0, json_canon.default)(compactMsg);
|
|
1081
1149
|
const encoder = new TextEncoder();
|
|
1082
1150
|
const msgBytes = encoder.encode(msgCanon);
|
|
@@ -1095,14 +1163,32 @@ async function createProof(object, privateKey, keyId, { contextLoader, context,
|
|
|
1095
1163
|
const digest = new Uint8Array(proofDigest.byteLength + msgDigest.byteLength);
|
|
1096
1164
|
digest.set(new Uint8Array(proofDigest), 0);
|
|
1097
1165
|
digest.set(new Uint8Array(msgDigest), proofDigest.byteLength);
|
|
1098
|
-
const sig = await crypto.subtle.sign("Ed25519", privateKey, digest);
|
|
1099
|
-
|
|
1166
|
+
const sig = new Uint8Array(await crypto.subtle.sign("Ed25519", privateKey, digest));
|
|
1167
|
+
const proof = new _fedify_vocab.DataIntegrityProof({
|
|
1100
1168
|
cryptosuite: "eddsa-jcs-2022",
|
|
1101
1169
|
verificationMethod: keyId,
|
|
1102
1170
|
proofPurpose: "assertionMethod",
|
|
1103
|
-
created
|
|
1104
|
-
proofValue:
|
|
1171
|
+
created,
|
|
1172
|
+
proofValue: sig
|
|
1105
1173
|
});
|
|
1174
|
+
return {
|
|
1175
|
+
proof,
|
|
1176
|
+
securedDocument: capture ? await captureSecuredDocument(proof, compactMsg, msgCanon, proofCanon, new TextDecoder().decode((0, _fedify_vocab_runtime.encodeMultibase)("base58btc", sig)), contextLoader) : null
|
|
1177
|
+
};
|
|
1178
|
+
}
|
|
1179
|
+
/**
|
|
1180
|
+
* Creates a proof for the given object.
|
|
1181
|
+
* @param object The object to create a proof for.
|
|
1182
|
+
* @param privateKey The private key to sign the proof with.
|
|
1183
|
+
* @param keyId The key ID to use in the proof. It will be used by the verifier.
|
|
1184
|
+
* @param options Additional options. See also {@link CreateProofOptions}.
|
|
1185
|
+
* @returns The created proof.
|
|
1186
|
+
* @throws {TypeError} If the private key is invalid or unsupported.
|
|
1187
|
+
* @since 0.10.0
|
|
1188
|
+
*/
|
|
1189
|
+
async function createProof(object, privateKey, keyId, options = {}) {
|
|
1190
|
+
const { proof } = await createProofInternal(object, privateKey, keyId, options);
|
|
1191
|
+
return proof;
|
|
1106
1192
|
}
|
|
1107
1193
|
/**
|
|
1108
1194
|
* Signs the given object with the private key and returns the signed object.
|
|
@@ -1120,13 +1206,19 @@ async function signObject(object, privateKey, keyId, options = {}) {
|
|
|
1120
1206
|
if (object.id != null) span.setAttribute("activitypub.object.id", object.id.href);
|
|
1121
1207
|
const existingProofs = [];
|
|
1122
1208
|
for await (const proof of object.getProofs(options)) existingProofs.push(proof);
|
|
1123
|
-
const proof = await
|
|
1209
|
+
const { proof, securedDocument } = await createProofInternal(object, privateKey, keyId, options, existingProofs.length < 1);
|
|
1124
1210
|
if (span.isRecording()) {
|
|
1125
1211
|
if (proof.cryptosuite != null) span.setAttribute("object_integrity_proofs.cryptosuite", proof.cryptosuite);
|
|
1126
1212
|
if (proof.verificationMethodId != null) span.setAttribute("object_integrity_proofs.key_id", proof.verificationMethodId.href);
|
|
1127
1213
|
if (proof.proofValue != null) span.setAttribute("object_integrity_proofs.signature", (0, byte_encodings_hex.encodeHex)(proof.proofValue));
|
|
1128
1214
|
}
|
|
1129
|
-
|
|
1215
|
+
const signed = object.clone({ proofs: [...existingProofs, proof] });
|
|
1216
|
+
if (securedDocument != null) (0, _fedify_vocab_runtime_internal_signed_representation.retainSignedRepresentation)(signed, securedDocument);
|
|
1217
|
+
else if (existingProofs.length > 0) logger$1.debug("The object {objectId} already had {proofCount} proof(s), so its signed representation is not retained for embedding; the map-local compound-proof profile accepts exactly one direct proof per map.", {
|
|
1218
|
+
objectId: object.id?.href,
|
|
1219
|
+
proofCount: existingProofs.length
|
|
1220
|
+
});
|
|
1221
|
+
return signed;
|
|
1130
1222
|
} catch (error) {
|
|
1131
1223
|
span.setStatus({
|
|
1132
1224
|
code: _opentelemetry_api.SpanStatusCode.ERROR,
|
|
@@ -1,18 +1,19 @@
|
|
|
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-
|
|
6
|
-
import { r as fetchKey, s as validateCryptoKey } from "./key-
|
|
7
|
-
import { n as preloadedOnlyDocumentLoader } from "./public-audience
|
|
8
|
-
import { r as normalizeOutgoingActivityJsonLd } from "./outgoing-jsonld-
|
|
9
|
-
import { c as getNormalizationContextLoader } from "./ld-
|
|
4
|
+
import { n as version, t as name } from "./deno-Vj_9wePq.mjs";
|
|
5
|
+
import { n as getDurationMs, r as getFederationMetrics, s as measureSignatureKeyFetch } from "./metrics-DpQqUAmh.mjs";
|
|
6
|
+
import { r as fetchKey, s as validateCryptoKey } from "./key-B_Zc5Jbd.mjs";
|
|
7
|
+
import { n as preloadedOnlyDocumentLoader } from "./public-audience--klBIOk1.mjs";
|
|
8
|
+
import { r as normalizeOutgoingActivityJsonLd } from "./outgoing-jsonld-4IJqPYos.mjs";
|
|
9
|
+
import { c as getNormalizationContextLoader } from "./ld-B16KUSIQ.mjs";
|
|
10
10
|
import { getLogger } from "@logtape/logtape";
|
|
11
11
|
import { Activity, DataIntegrityProof, Multikey, getTypeId } from "@fedify/vocab";
|
|
12
12
|
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
|
13
|
-
import { formatIri, getDocumentLoader, getFe34Origin, haveSameFe34Origin, parseIri } from "@fedify/vocab-runtime";
|
|
13
|
+
import { encodeMultibase, formatIri, getDocumentLoader, getFe34Origin, haveSameFe34Origin, parseIri } from "@fedify/vocab-runtime";
|
|
14
14
|
import { encodeHex } from "byte-encodings/hex";
|
|
15
15
|
import jsonld from "@fedify/vocab-runtime/jsonld";
|
|
16
|
+
import { isPlainJsonTree, retainSignedRepresentation } from "@fedify/vocab-runtime/internal/signed-representation";
|
|
16
17
|
import serialize from "json-canon";
|
|
17
18
|
//#region src/sig/proof.ts
|
|
18
19
|
/**
|
|
@@ -68,17 +69,49 @@ function hasProofLike(jsonLd) {
|
|
|
68
69
|
};
|
|
69
70
|
return Array.isArray(proof) ? proof.some(isProofLike) : isProofLike(proof);
|
|
70
71
|
}
|
|
72
|
+
function isJsonMap(value) {
|
|
73
|
+
return typeof value === "object" && value != null && !Array.isArray(value);
|
|
74
|
+
}
|
|
71
75
|
/**
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
* @
|
|
78
|
-
*
|
|
79
|
-
*
|
|
76
|
+
* Assembles the secured JSON document from the bytes that were just signed.
|
|
77
|
+
*
|
|
78
|
+
* The document is not re-derived from the vocabulary object: it is
|
|
79
|
+
* `compactMsg`, the value whose JCS form was hashed, with the serialized
|
|
80
|
+
* proof added. Every part of it is then checked against the digests and the
|
|
81
|
+
* signature that {@link createProofInternal} produced, so a document that is
|
|
82
|
+
* returned verifies under the map-local compound-proof profile by
|
|
83
|
+
* construction. Anything that does not check out yields `null`, and the
|
|
84
|
+
* caller simply does not retain a representation.
|
|
80
85
|
*/
|
|
81
|
-
async function
|
|
86
|
+
async function captureSecuredDocument(proof, compactMsg, msgCanon, proofCanon, proofValue, contextLoader) {
|
|
87
|
+
if (!isJsonMap(compactMsg)) return null;
|
|
88
|
+
const documentContext = compactMsg["@context"];
|
|
89
|
+
if (documentContext == null) return null;
|
|
90
|
+
if (globalThis.Object.hasOwn(compactMsg, "proof")) return null;
|
|
91
|
+
try {
|
|
92
|
+
const proofJson = await proof.toJsonLd({
|
|
93
|
+
format: "compact",
|
|
94
|
+
contextLoader,
|
|
95
|
+
context: documentContext
|
|
96
|
+
});
|
|
97
|
+
if (!isJsonMap(proofJson)) return null;
|
|
98
|
+
const { proofValue: serializedProofValue, ...proofConfiguration } = proofJson;
|
|
99
|
+
if (serializedProofValue !== proofValue) return null;
|
|
100
|
+
if (serialize(proofConfiguration) !== proofCanon) return null;
|
|
101
|
+
const securedDocument = {
|
|
102
|
+
...structuredClone(compactMsg),
|
|
103
|
+
proof: structuredClone(proofJson)
|
|
104
|
+
};
|
|
105
|
+
const { proof: _embeddedProof, ...unsecuredDocument } = securedDocument;
|
|
106
|
+
if (serialize(unsecuredDocument) !== msgCanon) return null;
|
|
107
|
+
if (!isPlainJsonTree(securedDocument)) return null;
|
|
108
|
+
return securedDocument;
|
|
109
|
+
} catch (error) {
|
|
110
|
+
logger.debug("Failed to capture the secured JSON document for a created proof; the signed object will not preserve its representation when it is embedded in another object.\n{error}", { error });
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async function createProofInternal(object, privateKey, keyId, { contextLoader, context, created } = {}, capture = false) {
|
|
82
115
|
validateCryptoKey(privateKey, "private");
|
|
83
116
|
if (privateKey.algorithm.name !== "Ed25519") throw new TypeError("Unsupported algorithm: " + privateKey.algorithm.name);
|
|
84
117
|
let compactMsg = await object.clone({ proofs: [] }).toJsonLd({
|
|
@@ -86,7 +119,7 @@ async function createProof(object, privateKey, keyId, { contextLoader, context,
|
|
|
86
119
|
contextLoader,
|
|
87
120
|
context
|
|
88
121
|
});
|
|
89
|
-
compactMsg = await normalizeOutgoingActivityJsonLd(compactMsg, contextLoader);
|
|
122
|
+
compactMsg = await normalizeOutgoingActivityJsonLd(compactMsg, contextLoader, { preserveNestedSecuredDocuments: true });
|
|
90
123
|
const msgCanon = serialize(compactMsg);
|
|
91
124
|
const encoder = new TextEncoder();
|
|
92
125
|
const msgBytes = encoder.encode(msgCanon);
|
|
@@ -105,14 +138,32 @@ async function createProof(object, privateKey, keyId, { contextLoader, context,
|
|
|
105
138
|
const digest = new Uint8Array(proofDigest.byteLength + msgDigest.byteLength);
|
|
106
139
|
digest.set(new Uint8Array(proofDigest), 0);
|
|
107
140
|
digest.set(new Uint8Array(msgDigest), proofDigest.byteLength);
|
|
108
|
-
const sig = await crypto.subtle.sign("Ed25519", privateKey, digest);
|
|
109
|
-
|
|
141
|
+
const sig = new Uint8Array(await crypto.subtle.sign("Ed25519", privateKey, digest));
|
|
142
|
+
const proof = new DataIntegrityProof({
|
|
110
143
|
cryptosuite: "eddsa-jcs-2022",
|
|
111
144
|
verificationMethod: keyId,
|
|
112
145
|
proofPurpose: "assertionMethod",
|
|
113
|
-
created
|
|
114
|
-
proofValue:
|
|
146
|
+
created,
|
|
147
|
+
proofValue: sig
|
|
115
148
|
});
|
|
149
|
+
return {
|
|
150
|
+
proof,
|
|
151
|
+
securedDocument: capture ? await captureSecuredDocument(proof, compactMsg, msgCanon, proofCanon, new TextDecoder().decode(encodeMultibase("base58btc", sig)), contextLoader) : null
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Creates a proof for the given object.
|
|
156
|
+
* @param object The object to create a proof for.
|
|
157
|
+
* @param privateKey The private key to sign the proof with.
|
|
158
|
+
* @param keyId The key ID to use in the proof. It will be used by the verifier.
|
|
159
|
+
* @param options Additional options. See also {@link CreateProofOptions}.
|
|
160
|
+
* @returns The created proof.
|
|
161
|
+
* @throws {TypeError} If the private key is invalid or unsupported.
|
|
162
|
+
* @since 0.10.0
|
|
163
|
+
*/
|
|
164
|
+
async function createProof(object, privateKey, keyId, options = {}) {
|
|
165
|
+
const { proof } = await createProofInternal(object, privateKey, keyId, options);
|
|
166
|
+
return proof;
|
|
116
167
|
}
|
|
117
168
|
/**
|
|
118
169
|
* Signs the given object with the private key and returns the signed object.
|
|
@@ -130,13 +181,19 @@ async function signObject(object, privateKey, keyId, options = {}) {
|
|
|
130
181
|
if (object.id != null) span.setAttribute("activitypub.object.id", object.id.href);
|
|
131
182
|
const existingProofs = [];
|
|
132
183
|
for await (const proof of object.getProofs(options)) existingProofs.push(proof);
|
|
133
|
-
const proof = await
|
|
184
|
+
const { proof, securedDocument } = await createProofInternal(object, privateKey, keyId, options, existingProofs.length < 1);
|
|
134
185
|
if (span.isRecording()) {
|
|
135
186
|
if (proof.cryptosuite != null) span.setAttribute("object_integrity_proofs.cryptosuite", proof.cryptosuite);
|
|
136
187
|
if (proof.verificationMethodId != null) span.setAttribute("object_integrity_proofs.key_id", proof.verificationMethodId.href);
|
|
137
188
|
if (proof.proofValue != null) span.setAttribute("object_integrity_proofs.signature", encodeHex(proof.proofValue));
|
|
138
189
|
}
|
|
139
|
-
|
|
190
|
+
const signed = object.clone({ proofs: [...existingProofs, proof] });
|
|
191
|
+
if (securedDocument != null) retainSignedRepresentation(signed, securedDocument);
|
|
192
|
+
else if (existingProofs.length > 0) logger.debug("The object {objectId} already had {proofCount} proof(s), so its signed representation is not retained for embedding; the map-local compound-proof profile accepts exactly one direct proof per map.", {
|
|
193
|
+
objectId: object.id?.href,
|
|
194
|
+
proofCount: existingProofs.length
|
|
195
|
+
});
|
|
196
|
+
return signed;
|
|
140
197
|
} catch (error) {
|
|
141
198
|
span.setStatus({
|
|
142
199
|
code: SpanStatusCode.ERROR,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
+
import { t as isSelfContainedSecuredDocument } from "./secured-document-CxzZZ9nL.mjs";
|
|
4
5
|
import { getLogger } from "@logtape/logtape";
|
|
5
6
|
import { PUBLIC_COLLECTION } from "@fedify/vocab";
|
|
6
7
|
import { preloadedContexts } from "@fedify/vocab-runtime";
|
|
@@ -40,37 +41,39 @@ const PUBLIC_ADDRESSING_FIELDS = /* @__PURE__ */ new Set([
|
|
|
40
41
|
const AS_CONTEXT_URL = "https://www.w3.org/ns/activitystreams";
|
|
41
42
|
const MAX_TRAVERSAL_DEPTH = 64;
|
|
42
43
|
const KNOWN_SAFE_CONTEXT_URLS = new Set(Object.keys(preloadedContexts));
|
|
43
|
-
function hasPublicCurieInAddressing(value, parentKey, depth = 0) {
|
|
44
|
+
function hasPublicCurieInAddressing(value, preserveSecured, parentKey, depth = 0) {
|
|
44
45
|
if (typeof value === "string") return parentKey != null && PUBLIC_ADDRESSING_FIELDS.has(parentKey) && (value === "as:Public" || value === "Public");
|
|
45
46
|
if (depth >= MAX_TRAVERSAL_DEPTH) return false;
|
|
46
|
-
if (Array.isArray(value)) return value.some((item) => hasPublicCurieInAddressing(item, parentKey, depth + 1));
|
|
47
|
+
if (Array.isArray(value)) return value.some((item) => hasPublicCurieInAddressing(item, preserveSecured, parentKey, depth + 1));
|
|
47
48
|
if (typeof value !== "object" || value == null) return false;
|
|
49
|
+
if (preserveSecured && depth > 0 && isSelfContainedSecuredDocument(value)) return false;
|
|
48
50
|
const record = value;
|
|
49
51
|
for (const key of Object.keys(record)) {
|
|
50
52
|
if (record.type === "Follow" && key === "object" && (record[key] === "as:Public" || record[key] === "Public")) return true;
|
|
51
53
|
if (key === "@context") continue;
|
|
52
|
-
if (hasPublicCurieInAddressing(record[key], key, depth + 1)) return true;
|
|
54
|
+
if (hasPublicCurieInAddressing(record[key], preserveSecured, key, depth + 1)) return true;
|
|
53
55
|
}
|
|
54
56
|
return false;
|
|
55
57
|
}
|
|
56
|
-
function rewritePublicAudience(value, parentKey, depth = 0) {
|
|
58
|
+
function rewritePublicAudience(value, preserveSecured, parentKey, depth = 0) {
|
|
57
59
|
if (typeof value === "string" && parentKey != null && PUBLIC_ADDRESSING_FIELDS.has(parentKey) && (value === "as:Public" || value === "Public")) return PUBLIC_COLLECTION.href;
|
|
58
60
|
if (depth >= MAX_TRAVERSAL_DEPTH) return value;
|
|
59
61
|
if (Array.isArray(value)) {
|
|
60
62
|
let changed = false;
|
|
61
63
|
const mapped = value.map((item) => {
|
|
62
|
-
const rewritten = rewritePublicAudience(item, parentKey, depth + 1);
|
|
64
|
+
const rewritten = rewritePublicAudience(item, preserveSecured, parentKey, depth + 1);
|
|
63
65
|
if (rewritten !== item) changed = true;
|
|
64
66
|
return rewritten;
|
|
65
67
|
});
|
|
66
68
|
return changed ? mapped : value;
|
|
67
69
|
}
|
|
68
70
|
if (typeof value !== "object" || value == null) return value;
|
|
71
|
+
if (preserveSecured && depth > 0 && isSelfContainedSecuredDocument(value)) return value;
|
|
69
72
|
const record = value;
|
|
70
73
|
let changed = false;
|
|
71
74
|
const normalized = Object.create(null);
|
|
72
75
|
for (const key of Object.keys(record)) {
|
|
73
|
-
const rewritten = key === "@context" ? record[key] : record.type === "Follow" && key === "object" && (record[key] === "as:Public" || record[key] === "Public") ? PUBLIC_COLLECTION.href : rewritePublicAudience(record[key], key, depth + 1);
|
|
76
|
+
const rewritten = key === "@context" ? record[key] : record.type === "Follow" && key === "object" && (record[key] === "as:Public" || record[key] === "Public") ? PUBLIC_COLLECTION.href : rewritePublicAudience(record[key], preserveSecured, key, depth + 1);
|
|
74
77
|
if (rewritten !== record[key]) changed = true;
|
|
75
78
|
normalized[key] = rewritten;
|
|
76
79
|
}
|
|
@@ -169,9 +172,10 @@ function hasKnownSafeContext(jsonLd) {
|
|
|
169
172
|
* using the `eddsa-jcs-2022` cryptosuite), so the signed payload
|
|
170
173
|
* matches what is sent on the wire.
|
|
171
174
|
*/
|
|
172
|
-
async function normalizePublicAudience(jsonLd, contextLoader) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
+
async function normalizePublicAudience(jsonLd, contextLoader, options = {}) {
|
|
176
|
+
const preserveSecured = options.preserveNestedSecuredDocuments ?? false;
|
|
177
|
+
if (!hasPublicCurieInAddressing(jsonLd, preserveSecured)) return jsonLd;
|
|
178
|
+
const normalized = rewritePublicAudience(jsonLd, preserveSecured);
|
|
175
179
|
if (hasKnownSafeContext(jsonLd)) return normalized;
|
|
176
180
|
const loader = contextLoader ?? preloadedOnlyDocumentLoader;
|
|
177
181
|
try {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import "temporal-polyfill";
|
|
2
|
+
import "urlpattern-polyfill";
|
|
3
|
+
globalThis.addEventListener = () => {};
|
|
4
|
+
//#region src/compat/secured-document.ts
|
|
5
|
+
function isJsonMap(value) {
|
|
6
|
+
return typeof value === "object" && value != null && !Array.isArray(value);
|
|
7
|
+
}
|
|
8
|
+
function isNonEmptyString(value) {
|
|
9
|
+
return typeof value === "string" && value.length > 0;
|
|
10
|
+
}
|
|
11
|
+
function hasDataIntegrityProofType(value) {
|
|
12
|
+
return (Array.isArray(value) ? value : [value]).some((type) => type === "DataIntegrityProof" || type === "https://w3id.org/security#DataIntegrityProof");
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Checks whether a JSON value is a complete, self-contained secured document:
|
|
16
|
+
* a map with its own `@context` and exactly one direct, map-valued `proof`
|
|
17
|
+
* that carries every member `eddsa-jcs-2022` proof generation produces.
|
|
18
|
+
*
|
|
19
|
+
* This is deliberately stricter than {@link hasProofLike}, which exists to
|
|
20
|
+
* decide whether a document is worth verifying. Here a false positive would
|
|
21
|
+
* silently suppress a wire-compatibility fix on an ordinary document, so a
|
|
22
|
+
* partial or malformed proof does not qualify.
|
|
23
|
+
*
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
function isSelfContainedSecuredDocument(value) {
|
|
27
|
+
if (!isJsonMap(value)) return false;
|
|
28
|
+
if (!Object.hasOwn(value, "@context") || value["@context"] == null) return false;
|
|
29
|
+
if (!Object.hasOwn(value, "proof")) return false;
|
|
30
|
+
const proof = value.proof;
|
|
31
|
+
if (!isJsonMap(proof)) return false;
|
|
32
|
+
return hasDataIntegrityProofType(proof.type) && isNonEmptyString(proof.cryptosuite) && isNonEmptyString(proof.created) && isNonEmptyString(proof.verificationMethod) && isNonEmptyString(proof.proofPurpose) && isNonEmptyString(proof.proofValue);
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { isSelfContainedSecuredDocument as t };
|
|
@@ -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 } from "./metrics-
|
|
6
|
-
import { n as doubleKnock } from "./http-
|
|
4
|
+
import { n as version, t as name } from "./deno-Vj_9wePq.mjs";
|
|
5
|
+
import { n as getDurationMs, r as getFederationMetrics } from "./metrics-DpQqUAmh.mjs";
|
|
6
|
+
import { n as doubleKnock } from "./http-D4WPcJUe.mjs";
|
|
7
7
|
import { getLogger } from "@logtape/logtape";
|
|
8
8
|
import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
|
|
9
9
|
import { FetchError, UrlError, validatePublicUrl } from "@fedify/vocab-runtime";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import "temporal-polyfill";
|
|
2
2
|
import "urlpattern-polyfill";
|
|
3
3
|
globalThis.addEventListener = () => {};
|
|
4
|
-
import { t as assertEquals } from "../assert_equals-
|
|
5
|
-
import "../std__assert-
|
|
6
|
-
import {
|
|
4
|
+
import { t as assertEquals } from "../assert_equals-Z6IcEbWU.mjs";
|
|
5
|
+
import "../std__assert-DvMDRPes.mjs";
|
|
6
|
+
import { i as inspectCompoundPortableObjectApplicability, n as discoverCompoundProofDocuments } from "../compound-proof-BIvUoJxm.mjs";
|
|
7
7
|
import { t as map_local_create_note_default } from "../map-local-create-note-B0SeXJms.mjs";
|
|
8
8
|
import { test } from "@fedify/fixture";
|
|
9
9
|
//#region src/sig/compound-proof-discovery.test.ts
|