@tinycloud/sdk-core 2.11.0-beta.8 → 2.11.0
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/bootstrap/index.cjs +0 -4
- package/dist/delegations/index.cjs +630 -314
- package/dist/delegations/index.cjs.map +1 -1
- package/dist/delegations/index.d.cts +32 -32
- package/dist/delegations/index.d.ts +32 -32
- package/dist/delegations/index.js +632 -231
- package/dist/delegations/index.js.map +1 -1
- package/dist/index.cjs +2923 -1500
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +583 -17
- package/dist/index.d.ts +583 -17
- package/dist/index.js +2892 -1151
- package/dist/index.js.map +1 -1
- package/dist/policy/index.cjs +878 -250
- package/dist/policy/index.cjs.map +1 -1
- package/dist/policy/index.d.cts +3 -2
- package/dist/policy/index.d.ts +3 -2
- package/dist/policy/index.js +878 -184
- package/dist/policy/index.js.map +1 -1
- package/dist/{recipient-types.schema-D5pDlIqn.d.cts → recipient-types.schema-CieclU3Z.d.cts} +232 -175
- package/dist/{recipient-types.schema-D5pDlIqn.d.ts → recipient-types.schema-CieclU3Z.d.ts} +232 -175
- package/dist/requester/index.cjs +10 -38
- package/dist/requester/index.cjs.map +1 -1
- package/dist/requester/index.js +11 -9
- package/dist/requester/index.js.map +1 -1
- package/dist/unified-BlXXf3l7.d.cts +429 -0
- package/dist/unified-HWqC-h7O.d.ts +429 -0
- package/package.json +5 -5
- package/dist/signed-object-C6mWbTbB.d.ts +0 -149
- package/dist/signed-object-IMAm5a32.d.cts +0 -149
package/dist/policy/index.js
CHANGED
|
@@ -323,16 +323,16 @@ function policyCapabilityContains(authority, request) {
|
|
|
323
323
|
return caveatsContain(auth.caveats, req.caveats);
|
|
324
324
|
}
|
|
325
325
|
function normalizePolicyCapabilityWithOptions(input, options) {
|
|
326
|
-
const
|
|
327
|
-
assertExactKeys(
|
|
328
|
-
const service = requiredString(
|
|
326
|
+
const object2 = expectObject(input, "$");
|
|
327
|
+
assertExactKeys(object2, ["service", "space", "path", "actions", "caveats"], "$");
|
|
328
|
+
const service = requiredString(object2, "service", "$", "policy-capability-malformed-service");
|
|
329
329
|
if (!CEILING_SERVICES.has(service)) {
|
|
330
330
|
throw new PolicyCapabilityError(
|
|
331
331
|
"policy-capability-malformed-service",
|
|
332
332
|
"$.service is outside the frozen permissionsCeiling vocabulary"
|
|
333
333
|
);
|
|
334
334
|
}
|
|
335
|
-
const space = requiredString(
|
|
335
|
+
const space = requiredString(object2, "space", "$", "policy-capability-malformed-space");
|
|
336
336
|
validateConcreteSpace(space);
|
|
337
337
|
const canonicalSpace = space.normalize("NFC");
|
|
338
338
|
if (options.requireCanonical && canonicalSpace !== space) {
|
|
@@ -341,7 +341,7 @@ function normalizePolicyCapabilityWithOptions(input, options) {
|
|
|
341
341
|
"$.space must already be canonical NFC"
|
|
342
342
|
);
|
|
343
343
|
}
|
|
344
|
-
const rawPath = requiredString(
|
|
344
|
+
const rawPath = requiredString(object2, "path", "$", "policy-capability-malformed-path");
|
|
345
345
|
validateRawPath(rawPath, options);
|
|
346
346
|
const path = normalizePath(rawPath);
|
|
347
347
|
if (options.requireCanonical && path !== rawPath) {
|
|
@@ -352,7 +352,7 @@ function normalizePolicyCapabilityWithOptions(input, options) {
|
|
|
352
352
|
}
|
|
353
353
|
validateRawPath(path, options);
|
|
354
354
|
const actions = normalizeActions(
|
|
355
|
-
requiredArray(
|
|
355
|
+
requiredArray(object2, "actions", "$", "policy-capability-malformed-action"),
|
|
356
356
|
service,
|
|
357
357
|
options
|
|
358
358
|
);
|
|
@@ -361,9 +361,9 @@ function normalizePolicyCapabilityWithOptions(input, options) {
|
|
|
361
361
|
output.space = canonicalSpace;
|
|
362
362
|
output.path = path;
|
|
363
363
|
output.actions = actions;
|
|
364
|
-
if (hasOwn(
|
|
364
|
+
if (hasOwn(object2, "caveats")) {
|
|
365
365
|
output.caveats = validateCaveats(
|
|
366
|
-
requiredValue(
|
|
366
|
+
requiredValue(object2, "caveats", "$", "policy-capability-malformed-caveats"),
|
|
367
367
|
output.service
|
|
368
368
|
);
|
|
369
369
|
}
|
|
@@ -386,9 +386,9 @@ function expectObject(input, path) {
|
|
|
386
386
|
);
|
|
387
387
|
}
|
|
388
388
|
}
|
|
389
|
-
function assertExactKeys(
|
|
389
|
+
function assertExactKeys(object2, allowed, path) {
|
|
390
390
|
const allowedSet = new Set(allowed);
|
|
391
|
-
for (const key of Object.keys(
|
|
391
|
+
for (const key of Object.keys(object2)) {
|
|
392
392
|
if (!allowedSet.has(key)) {
|
|
393
393
|
throw new PolicyCapabilityError(
|
|
394
394
|
key === "id" || key === "scope" ? "policy-capability-malformed" : "policy-capability-unknown-key",
|
|
@@ -397,21 +397,21 @@ function assertExactKeys(object, allowed, path) {
|
|
|
397
397
|
}
|
|
398
398
|
}
|
|
399
399
|
}
|
|
400
|
-
function requiredValue(
|
|
401
|
-
if (!hasOwn(
|
|
400
|
+
function requiredValue(object2, key, path, code2) {
|
|
401
|
+
if (!hasOwn(object2, key)) {
|
|
402
402
|
throw new PolicyCapabilityError(code2, `${path}.${key} is required`);
|
|
403
403
|
}
|
|
404
|
-
return
|
|
404
|
+
return object2[key];
|
|
405
405
|
}
|
|
406
|
-
function requiredString(
|
|
407
|
-
const value = requiredValue(
|
|
406
|
+
function requiredString(object2, key, path, code2) {
|
|
407
|
+
const value = requiredValue(object2, key, path, code2);
|
|
408
408
|
if (typeof value !== "string" || value.length === 0) {
|
|
409
409
|
throw new PolicyCapabilityError(code2, `${path}.${key} must be a non-empty string`);
|
|
410
410
|
}
|
|
411
411
|
return value;
|
|
412
412
|
}
|
|
413
|
-
function requiredArray(
|
|
414
|
-
const value = requiredValue(
|
|
413
|
+
function requiredArray(object2, key, path, code2) {
|
|
414
|
+
const value = requiredValue(object2, key, path, code2);
|
|
415
415
|
if (!Array.isArray(value)) {
|
|
416
416
|
throw new PolicyCapabilityError(code2, `${path}.${key} must be an array`);
|
|
417
417
|
}
|
|
@@ -556,11 +556,11 @@ function validateSqlStatement(input, path) {
|
|
|
556
556
|
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
557
557
|
throw new PolicyCapabilityError("policy-capability-malformed-caveats", `${path} must be an object`);
|
|
558
558
|
}
|
|
559
|
-
const
|
|
560
|
-
assertCaveatKeys(
|
|
561
|
-
caveatString(
|
|
562
|
-
caveatString(
|
|
563
|
-
const fixedParams = requiredCaveat(
|
|
559
|
+
const object2 = input;
|
|
560
|
+
assertCaveatKeys(object2, ["name", "sql", "fixedParams"], path);
|
|
561
|
+
caveatString(object2, "name", path);
|
|
562
|
+
caveatString(object2, "sql", path);
|
|
563
|
+
const fixedParams = requiredCaveat(object2, "fixedParams", path);
|
|
564
564
|
if (!Array.isArray(fixedParams)) {
|
|
565
565
|
throw new PolicyCapabilityError(
|
|
566
566
|
"policy-capability-malformed-caveats",
|
|
@@ -575,20 +575,20 @@ function validateFixedParam(input, path) {
|
|
|
575
575
|
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
576
576
|
throw new PolicyCapabilityError("policy-capability-malformed-caveats", `${path} must be an object`);
|
|
577
577
|
}
|
|
578
|
-
const
|
|
579
|
-
assertCaveatKeys(
|
|
580
|
-
const index = requiredCaveat(
|
|
578
|
+
const object2 = input;
|
|
579
|
+
assertCaveatKeys(object2, ["index", "value"], path);
|
|
580
|
+
const index = requiredCaveat(object2, "index", path);
|
|
581
581
|
if (typeof index !== "number" || !Number.isSafeInteger(index) || index < 0) {
|
|
582
582
|
throw new PolicyCapabilityError(
|
|
583
583
|
"policy-capability-malformed-caveats",
|
|
584
584
|
`${path}.index must be a non-negative integer`
|
|
585
585
|
);
|
|
586
586
|
}
|
|
587
|
-
requiredCaveat(
|
|
587
|
+
requiredCaveat(object2, "value", path);
|
|
588
588
|
}
|
|
589
|
-
function assertCaveatKeys(
|
|
589
|
+
function assertCaveatKeys(object2, allowed, path) {
|
|
590
590
|
const allowedSet = new Set(allowed);
|
|
591
|
-
for (const key of Object.keys(
|
|
591
|
+
for (const key of Object.keys(object2)) {
|
|
592
592
|
if (!allowedSet.has(key)) {
|
|
593
593
|
throw new PolicyCapabilityError(
|
|
594
594
|
"policy-capability-malformed-caveats",
|
|
@@ -597,17 +597,17 @@ function assertCaveatKeys(object, allowed, path) {
|
|
|
597
597
|
}
|
|
598
598
|
}
|
|
599
599
|
}
|
|
600
|
-
function requiredCaveat(
|
|
601
|
-
if (!hasOwn(
|
|
600
|
+
function requiredCaveat(object2, key, path) {
|
|
601
|
+
if (!hasOwn(object2, key)) {
|
|
602
602
|
throw new PolicyCapabilityError(
|
|
603
603
|
"policy-capability-malformed-caveats",
|
|
604
604
|
`${path}.${key} is required`
|
|
605
605
|
);
|
|
606
606
|
}
|
|
607
|
-
return
|
|
607
|
+
return object2[key];
|
|
608
608
|
}
|
|
609
|
-
function caveatString(
|
|
610
|
-
const value = requiredCaveat(
|
|
609
|
+
function caveatString(object2, key, path) {
|
|
610
|
+
const value = requiredCaveat(object2, key, path);
|
|
611
611
|
if (typeof value !== "string" || value.length === 0) {
|
|
612
612
|
throw new PolicyCapabilityError(
|
|
613
613
|
"policy-capability-malformed-caveats",
|
|
@@ -638,8 +638,8 @@ function caveatsContain(authority, request) {
|
|
|
638
638
|
(statement) => authorityStatements.some((candidate) => jcsCanonicalize(candidate) === jcsCanonicalize(statement))
|
|
639
639
|
);
|
|
640
640
|
}
|
|
641
|
-
function hasOwn(
|
|
642
|
-
return objectHasOwn2(
|
|
641
|
+
function hasOwn(object2, key) {
|
|
642
|
+
return objectHasOwn2(object2, key);
|
|
643
643
|
}
|
|
644
644
|
|
|
645
645
|
// src/policy/signed-object.ts
|
|
@@ -1383,13 +1383,12 @@ function digest(input, options) {
|
|
|
1383
1383
|
}
|
|
1384
1384
|
var identity2 = { code, name, encode: encode4, digest };
|
|
1385
1385
|
|
|
1386
|
-
// ../../node_modules/multiformats/dist/src/hashes/sha2.js
|
|
1387
|
-
var
|
|
1388
|
-
__export(
|
|
1386
|
+
// ../../node_modules/multiformats/dist/src/hashes/sha2-browser.js
|
|
1387
|
+
var sha2_browser_exports = {};
|
|
1388
|
+
__export(sha2_browser_exports, {
|
|
1389
1389
|
sha256: () => sha2562,
|
|
1390
1390
|
sha512: () => sha512
|
|
1391
1391
|
});
|
|
1392
|
-
import crypto from "crypto";
|
|
1393
1392
|
|
|
1394
1393
|
// ../../node_modules/multiformats/dist/src/hashes/hasher.js
|
|
1395
1394
|
var DEFAULT_MIN_DIGEST_LENGTH = 20;
|
|
@@ -1439,16 +1438,19 @@ function createDigest(digest2, code2, truncate) {
|
|
|
1439
1438
|
return create(code2, digest2);
|
|
1440
1439
|
}
|
|
1441
1440
|
|
|
1442
|
-
// ../../node_modules/multiformats/dist/src/hashes/sha2.js
|
|
1441
|
+
// ../../node_modules/multiformats/dist/src/hashes/sha2-browser.js
|
|
1442
|
+
function sha(name2) {
|
|
1443
|
+
return async (data) => new Uint8Array(await crypto.subtle.digest(name2, data));
|
|
1444
|
+
}
|
|
1443
1445
|
var sha2562 = from2({
|
|
1444
1446
|
name: "sha2-256",
|
|
1445
1447
|
code: 18,
|
|
1446
|
-
encode: (
|
|
1448
|
+
encode: sha("SHA-256")
|
|
1447
1449
|
});
|
|
1448
1450
|
var sha512 = from2({
|
|
1449
1451
|
name: "sha2-512",
|
|
1450
1452
|
code: 19,
|
|
1451
|
-
encode: (
|
|
1453
|
+
encode: sha("SHA-512")
|
|
1452
1454
|
});
|
|
1453
1455
|
|
|
1454
1456
|
// ../../node_modules/multiformats/dist/src/cid.js
|
|
@@ -1790,13 +1792,13 @@ var cidSymbol = /* @__PURE__ */ Symbol.for("@ipld/js-cid/CID");
|
|
|
1790
1792
|
|
|
1791
1793
|
// ../../node_modules/multiformats/dist/src/basics.js
|
|
1792
1794
|
var bases = { ...identity_exports, ...base2_exports, ...base8_exports, ...base10_exports, ...base16_exports, ...base32_exports, ...base36_exports, ...base58_exports, ...base64_exports, ...base256emoji_exports };
|
|
1793
|
-
var hashes = { ...
|
|
1795
|
+
var hashes = { ...sha2_browser_exports, ...identity_exports2 };
|
|
1794
1796
|
|
|
1795
1797
|
// src/policy/signed-object.ts
|
|
1796
1798
|
import { bytesToHex as bytesToHex2, sha256 as sha2563, verifyMessage } from "viem";
|
|
1797
1799
|
|
|
1798
1800
|
// src/identity.ts
|
|
1799
|
-
import { getAddress, isAddress } from "viem";
|
|
1801
|
+
import { getAddress, isAddress, recoverMessageAddress } from "viem";
|
|
1800
1802
|
var IdentityParseError = class extends Error {
|
|
1801
1803
|
constructor(message) {
|
|
1802
1804
|
super(message);
|
|
@@ -1907,17 +1909,17 @@ async function createAndSignSignedObject(input, signer) {
|
|
|
1907
1909
|
}
|
|
1908
1910
|
function createAndSignPolicy(input, signer) {
|
|
1909
1911
|
return createAndSignSignedObject(input, signer).then(
|
|
1910
|
-
(
|
|
1912
|
+
(object2) => validatePolicySignedShape(object2)
|
|
1911
1913
|
);
|
|
1912
1914
|
}
|
|
1913
1915
|
function createAndSignPolicyStatus(input, signer) {
|
|
1914
1916
|
return createAndSignSignedObject(input, signer).then(
|
|
1915
|
-
(
|
|
1917
|
+
(object2) => validatePolicyStatusSignedShape(object2)
|
|
1916
1918
|
);
|
|
1917
1919
|
}
|
|
1918
1920
|
function createAndSignPolicyEngineRecord(input, signer) {
|
|
1919
1921
|
return createAndSignSignedObject(input, signer).then(
|
|
1920
|
-
(
|
|
1922
|
+
(object2) => validatePolicyEngineRecordSignedShape(object2)
|
|
1921
1923
|
);
|
|
1922
1924
|
}
|
|
1923
1925
|
async function verifySignedObject(input) {
|
|
@@ -2021,9 +2023,9 @@ function validateUnsignedForDescriptor(input, descriptor) {
|
|
|
2021
2023
|
}
|
|
2022
2024
|
}
|
|
2023
2025
|
function validatePolicyShape(input, signed) {
|
|
2024
|
-
const
|
|
2026
|
+
const object2 = expectJsonObject(normalizeJson(input), "$");
|
|
2025
2027
|
assertExactKeys2(
|
|
2026
|
-
|
|
2028
|
+
object2,
|
|
2027
2029
|
signed ? [
|
|
2028
2030
|
"schema",
|
|
2029
2031
|
"policyId",
|
|
@@ -2051,30 +2053,30 @@ function validatePolicyShape(input, signed) {
|
|
|
2051
2053
|
],
|
|
2052
2054
|
"$"
|
|
2053
2055
|
);
|
|
2054
|
-
expectConst(requiredString2(
|
|
2056
|
+
expectConst(requiredString2(object2, "schema", "$"), POLICY_SCHEMA, "$.schema");
|
|
2055
2057
|
if (signed) {
|
|
2056
|
-
requiredString2(
|
|
2057
|
-
validateSignature(requiredValue2(
|
|
2058
|
+
requiredString2(object2, "policyId", "$");
|
|
2059
|
+
validateSignature(requiredValue2(object2, "signature", "$"));
|
|
2058
2060
|
}
|
|
2059
|
-
requiredString2(
|
|
2060
|
-
requiredString2(
|
|
2061
|
-
requiredDateString(
|
|
2062
|
-
optionalDateString(
|
|
2063
|
-
validatePolicyResource(requiredValue2(
|
|
2064
|
-
validateExpression(requiredValue2(
|
|
2065
|
-
validateGrant(requiredValue2(
|
|
2066
|
-
if (hasOwn2(
|
|
2067
|
-
validateDisclosure(requiredValue2(
|
|
2061
|
+
requiredString2(object2, "ownerDid", "$");
|
|
2062
|
+
requiredString2(object2, "signingKeyDid", "$");
|
|
2063
|
+
requiredDateString(object2, "createdAt", "$");
|
|
2064
|
+
optionalDateString(object2, "expiresAt", "$");
|
|
2065
|
+
validatePolicyResource(requiredValue2(object2, "resource", "$"), "$.resource");
|
|
2066
|
+
validateExpression(requiredValue2(object2, "when", "$"), "$.when");
|
|
2067
|
+
validateGrant(requiredValue2(object2, "grant", "$"), "$.grant");
|
|
2068
|
+
if (hasOwn2(object2, "disclosure")) {
|
|
2069
|
+
validateDisclosure(requiredValue2(object2, "disclosure", "$"), "$.disclosure");
|
|
2068
2070
|
}
|
|
2069
|
-
if (hasOwn2(
|
|
2070
|
-
validateAudit(requiredValue2(
|
|
2071
|
+
if (hasOwn2(object2, "audit")) {
|
|
2072
|
+
validateAudit(requiredValue2(object2, "audit", "$"), "$.audit");
|
|
2071
2073
|
}
|
|
2072
|
-
return
|
|
2074
|
+
return object2;
|
|
2073
2075
|
}
|
|
2074
2076
|
function validatePolicyStatusShape(input, signed) {
|
|
2075
|
-
const
|
|
2077
|
+
const object2 = expectJsonObject(normalizeJson(input), "$");
|
|
2076
2078
|
assertExactKeys2(
|
|
2077
|
-
|
|
2079
|
+
object2,
|
|
2078
2080
|
signed ? [
|
|
2079
2081
|
"schema",
|
|
2080
2082
|
"statusId",
|
|
@@ -2098,28 +2100,28 @@ function validatePolicyStatusShape(input, signed) {
|
|
|
2098
2100
|
],
|
|
2099
2101
|
"$"
|
|
2100
2102
|
);
|
|
2101
|
-
expectConst(requiredString2(
|
|
2103
|
+
expectConst(requiredString2(object2, "schema", "$"), POLICY_STATUS_SCHEMA, "$.schema");
|
|
2102
2104
|
if (signed) {
|
|
2103
|
-
requiredString2(
|
|
2104
|
-
validateSignature(requiredValue2(
|
|
2105
|
+
requiredString2(object2, "statusId", "$");
|
|
2106
|
+
validateSignature(requiredValue2(object2, "signature", "$"));
|
|
2105
2107
|
}
|
|
2106
|
-
requiredString2(
|
|
2107
|
-
requiredString2(
|
|
2108
|
-
requiredInteger(
|
|
2109
|
-
expectOneOf(requiredString2(
|
|
2108
|
+
requiredString2(object2, "policyId", "$");
|
|
2109
|
+
requiredString2(object2, "ownerDid", "$");
|
|
2110
|
+
requiredInteger(object2, "sequence", "$", 0);
|
|
2111
|
+
expectOneOf(requiredString2(object2, "disposition", "$"), [
|
|
2110
2112
|
"active",
|
|
2111
2113
|
"suspended",
|
|
2112
2114
|
"revoked"
|
|
2113
2115
|
], "$.disposition");
|
|
2114
|
-
requiredDateString(
|
|
2115
|
-
optionalString(
|
|
2116
|
-
requiredString2(
|
|
2117
|
-
return
|
|
2116
|
+
requiredDateString(object2, "effectiveAt", "$");
|
|
2117
|
+
optionalString(object2, "reasonCode", "$");
|
|
2118
|
+
requiredString2(object2, "signingKeyDid", "$");
|
|
2119
|
+
return object2;
|
|
2118
2120
|
}
|
|
2119
2121
|
function validatePolicyEngineRecordShape(input, signed) {
|
|
2120
|
-
const
|
|
2122
|
+
const object2 = expectJsonObject(normalizeJson(input), "$");
|
|
2121
2123
|
assertExactKeys2(
|
|
2122
|
-
|
|
2124
|
+
object2,
|
|
2123
2125
|
signed ? [
|
|
2124
2126
|
"schema",
|
|
2125
2127
|
"engineRecordId",
|
|
@@ -2144,44 +2146,44 @@ function validatePolicyEngineRecordShape(input, signed) {
|
|
|
2144
2146
|
"$"
|
|
2145
2147
|
);
|
|
2146
2148
|
expectConst(
|
|
2147
|
-
requiredString2(
|
|
2149
|
+
requiredString2(object2, "schema", "$"),
|
|
2148
2150
|
POLICY_ENGINE_RECORD_SCHEMA,
|
|
2149
2151
|
"$.schema"
|
|
2150
2152
|
);
|
|
2151
2153
|
if (signed) {
|
|
2152
|
-
requiredString2(
|
|
2153
|
-
validateSignature(requiredValue2(
|
|
2154
|
+
requiredString2(object2, "engineRecordId", "$");
|
|
2155
|
+
validateSignature(requiredValue2(object2, "signature", "$"));
|
|
2154
2156
|
}
|
|
2155
|
-
requiredString2(
|
|
2156
|
-
requiredString2(
|
|
2157
|
-
requiredString2(
|
|
2157
|
+
requiredString2(object2, "ownerDid", "$");
|
|
2158
|
+
requiredString2(object2, "endpoint", "$");
|
|
2159
|
+
requiredString2(object2, "audience", "$");
|
|
2158
2160
|
requiredStringArray(
|
|
2159
|
-
|
|
2161
|
+
object2,
|
|
2160
2162
|
"supportedPolicyVersions",
|
|
2161
2163
|
"$",
|
|
2162
2164
|
(value, path) => expectConst(value, "v0", path)
|
|
2163
2165
|
);
|
|
2164
|
-
requiredStringArray(
|
|
2165
|
-
requiredString2(
|
|
2166
|
-
requiredDateString(
|
|
2167
|
-
return
|
|
2166
|
+
requiredStringArray(object2, "supportedEvidenceVerifiers", "$");
|
|
2167
|
+
requiredString2(object2, "grantIssuerDid", "$");
|
|
2168
|
+
requiredDateString(object2, "expiresAt", "$");
|
|
2169
|
+
return object2;
|
|
2168
2170
|
}
|
|
2169
2171
|
function validateSignature(input) {
|
|
2170
|
-
const
|
|
2171
|
-
assertExactKeys2(
|
|
2172
|
-
const suite = requiredString2(
|
|
2172
|
+
const object2 = expectJsonObject(input, "$.signature");
|
|
2173
|
+
assertExactKeys2(object2, ["suite", "signerDid", "value"], "$.signature");
|
|
2174
|
+
const suite = requiredString2(object2, "suite", "$.signature");
|
|
2173
2175
|
assertSupportedSignatureSuite(suite);
|
|
2174
|
-
const signerDid = requiredString2(
|
|
2175
|
-
const value = requiredString2(
|
|
2176
|
+
const signerDid = requiredString2(object2, "signerDid", "$.signature");
|
|
2177
|
+
const value = requiredString2(object2, "value", "$.signature");
|
|
2176
2178
|
decodeSignatureValue(value, suite);
|
|
2177
2179
|
return { suite, signerDid, value };
|
|
2178
2180
|
}
|
|
2179
2181
|
function validatePolicyResource(input, path) {
|
|
2180
|
-
const
|
|
2181
|
-
assertExactKeys2(
|
|
2182
|
-
requiredString2(
|
|
2183
|
-
requiredString2(
|
|
2184
|
-
const ceiling = requiredArray2(
|
|
2182
|
+
const object2 = expectJsonObject(input, path);
|
|
2183
|
+
assertExactKeys2(object2, ["resourceType", "resourceId", "permissionsCeiling"], path);
|
|
2184
|
+
requiredString2(object2, "resourceType", path);
|
|
2185
|
+
requiredString2(object2, "resourceId", path);
|
|
2186
|
+
const ceiling = requiredArray2(object2, "permissionsCeiling", path, 1);
|
|
2185
2187
|
for (let index = 0; index < ceiling.length; index++) {
|
|
2186
2188
|
validatePolicyCapability(ceiling[index], `${path}.permissionsCeiling[${index}]`);
|
|
2187
2189
|
}
|
|
@@ -2197,10 +2199,10 @@ function validatePolicyPermissionsCeilingForSigning(input) {
|
|
|
2197
2199
|
}
|
|
2198
2200
|
}
|
|
2199
2201
|
function validatePolicyCapability(input, path) {
|
|
2200
|
-
const
|
|
2202
|
+
const object2 = expectJsonObject(input, path);
|
|
2201
2203
|
try {
|
|
2202
|
-
const canonical = canonicalizePolicyCapability(
|
|
2203
|
-
if (jcsCanonicalize(
|
|
2204
|
+
const canonical = canonicalizePolicyCapability(object2);
|
|
2205
|
+
if (jcsCanonicalize(object2) !== jcsCanonicalize(canonical)) {
|
|
2204
2206
|
throw new SignedObjectSchemaError(`${path} must be canonical PolicyCapability JSON`);
|
|
2205
2207
|
}
|
|
2206
2208
|
} catch (error) {
|
|
@@ -2213,10 +2215,10 @@ function validatePolicyCapability(input, path) {
|
|
|
2213
2215
|
}
|
|
2214
2216
|
}
|
|
2215
2217
|
function validatePolicyCapabilityForSigning(input, path) {
|
|
2216
|
-
const
|
|
2218
|
+
const object2 = expectJsonObject(input, path);
|
|
2217
2219
|
try {
|
|
2218
|
-
const canonical = normalizePolicyCapability(
|
|
2219
|
-
if (jcsCanonicalize(
|
|
2220
|
+
const canonical = normalizePolicyCapability(object2);
|
|
2221
|
+
if (jcsCanonicalize(object2) !== jcsCanonicalize(canonical)) {
|
|
2220
2222
|
throw new SignedObjectSchemaError(`${path} must be strict canonical PolicyCapability JSON`);
|
|
2221
2223
|
}
|
|
2222
2224
|
} catch (error) {
|
|
@@ -2229,43 +2231,43 @@ function validatePolicyCapabilityForSigning(input, path) {
|
|
|
2229
2231
|
}
|
|
2230
2232
|
}
|
|
2231
2233
|
function validateExpression(input, path) {
|
|
2232
|
-
const
|
|
2233
|
-
const keys = Object.keys(
|
|
2234
|
+
const object2 = expectJsonObject(input, path);
|
|
2235
|
+
const keys = Object.keys(object2);
|
|
2234
2236
|
if (keys.length !== 1) {
|
|
2235
2237
|
throw new SignedObjectSchemaError(`${path} must have exactly one expression key`);
|
|
2236
2238
|
}
|
|
2237
2239
|
const key = keys[0];
|
|
2238
2240
|
if (key === "allOf" || key === "anyOf") {
|
|
2239
|
-
const values = requiredArray2(
|
|
2241
|
+
const values = requiredArray2(object2, key, path, 1);
|
|
2240
2242
|
for (let index = 0; index < values.length; index++) {
|
|
2241
2243
|
validateExpression(values[index], `${path}.${key}[${index}]`);
|
|
2242
2244
|
}
|
|
2243
2245
|
return;
|
|
2244
2246
|
}
|
|
2245
2247
|
if (key === "subject") {
|
|
2246
|
-
const subject = expectJsonObject(requiredValue2(
|
|
2248
|
+
const subject = expectJsonObject(requiredValue2(object2, "subject", path), `${path}.subject`);
|
|
2247
2249
|
assertExactKeys2(subject, ["did"], `${path}.subject`);
|
|
2248
2250
|
requiredString2(subject, "did", `${path}.subject`);
|
|
2249
2251
|
return;
|
|
2250
2252
|
}
|
|
2251
2253
|
if (key === "evidence") {
|
|
2252
|
-
validateEvidenceRequirement(requiredValue2(
|
|
2254
|
+
validateEvidenceRequirement(requiredValue2(object2, "evidence", path), `${path}.evidence`);
|
|
2253
2255
|
return;
|
|
2254
2256
|
}
|
|
2255
2257
|
throw new SignedObjectSchemaError(`${path} has unknown expression key ${key}`);
|
|
2256
2258
|
}
|
|
2257
2259
|
function validateEvidenceRequirement(input, path) {
|
|
2258
|
-
const
|
|
2260
|
+
const object2 = expectJsonObject(input, path);
|
|
2259
2261
|
assertExactKeys2(
|
|
2260
|
-
|
|
2262
|
+
object2,
|
|
2261
2263
|
["requirementId", "verifier", "requirements", "authority", "freshness"],
|
|
2262
2264
|
path
|
|
2263
2265
|
);
|
|
2264
|
-
requiredString2(
|
|
2265
|
-
requiredString2(
|
|
2266
|
-
requiredValue2(
|
|
2267
|
-
if (hasOwn2(
|
|
2268
|
-
const authority = expectJsonObject(requiredValue2(
|
|
2266
|
+
requiredString2(object2, "requirementId", path);
|
|
2267
|
+
requiredString2(object2, "verifier", path);
|
|
2268
|
+
requiredValue2(object2, "requirements", path);
|
|
2269
|
+
if (hasOwn2(object2, "authority")) {
|
|
2270
|
+
const authority = expectJsonObject(requiredValue2(object2, "authority", path), `${path}.authority`);
|
|
2269
2271
|
assertExactKeys2(
|
|
2270
2272
|
authority,
|
|
2271
2273
|
["profile", "acceptedIssuers", "allowOwnerAuthorizedIssuer"],
|
|
@@ -2277,35 +2279,35 @@ function validateEvidenceRequirement(input, path) {
|
|
|
2277
2279
|
}
|
|
2278
2280
|
optionalBoolean(authority, "allowOwnerAuthorizedIssuer", `${path}.authority`);
|
|
2279
2281
|
}
|
|
2280
|
-
if (hasOwn2(
|
|
2281
|
-
const freshness = expectJsonObject(requiredValue2(
|
|
2282
|
+
if (hasOwn2(object2, "freshness")) {
|
|
2283
|
+
const freshness = expectJsonObject(requiredValue2(object2, "freshness", path), `${path}.freshness`);
|
|
2282
2284
|
assertExactKeys2(freshness, ["maxStatusAgeSeconds"], `${path}.freshness`);
|
|
2283
2285
|
requiredInteger(freshness, "maxStatusAgeSeconds", `${path}.freshness`, 0);
|
|
2284
2286
|
}
|
|
2285
2287
|
}
|
|
2286
2288
|
function validateGrant(input, path) {
|
|
2287
|
-
const
|
|
2288
|
-
assertExactKeys2(
|
|
2289
|
-
expectConst(requiredString2(
|
|
2290
|
-
requiredInteger(
|
|
2291
|
-
expectOneOf(requiredString2(
|
|
2289
|
+
const object2 = expectJsonObject(input, path);
|
|
2290
|
+
assertExactKeys2(object2, ["output", "maxTtlSeconds", "delegationMode", "revocation"], path);
|
|
2291
|
+
expectConst(requiredString2(object2, "output", path), "portable-delegation", `${path}.output`);
|
|
2292
|
+
requiredInteger(object2, "maxTtlSeconds", path, 1);
|
|
2293
|
+
expectOneOf(requiredString2(object2, "delegationMode", path), [
|
|
2292
2294
|
"terminal",
|
|
2293
2295
|
"attenuable"
|
|
2294
2296
|
], `${path}.delegationMode`);
|
|
2295
|
-
expectOneOf(requiredString2(
|
|
2297
|
+
expectOneOf(requiredString2(object2, "revocation", path), [
|
|
2296
2298
|
"refresh_only",
|
|
2297
2299
|
"active_cutoff"
|
|
2298
2300
|
], `${path}.revocation`);
|
|
2299
2301
|
}
|
|
2300
2302
|
function validateDisclosure(input, path) {
|
|
2301
|
-
const
|
|
2302
|
-
assertExactKeys2(
|
|
2303
|
-
expectOneOf(requiredString2(
|
|
2303
|
+
const object2 = expectJsonObject(input, path);
|
|
2304
|
+
assertExactKeys2(object2, ["denial"], path);
|
|
2305
|
+
expectOneOf(requiredString2(object2, "denial", path), ["none", "code", "debug"], `${path}.denial`);
|
|
2304
2306
|
}
|
|
2305
2307
|
function validateAudit(input, path) {
|
|
2306
|
-
const
|
|
2307
|
-
assertExactKeys2(
|
|
2308
|
-
expectOneOf(requiredString2(
|
|
2308
|
+
const object2 = expectJsonObject(input, path);
|
|
2309
|
+
assertExactKeys2(object2, ["issuance"], path);
|
|
2310
|
+
expectOneOf(requiredString2(object2, "issuance", path), ["off", "security", "full"], `${path}.issuance`);
|
|
2309
2311
|
}
|
|
2310
2312
|
function materialForUnsigned(unsigned, descriptor) {
|
|
2311
2313
|
const jcs = jcsCanonicalize(unsigned);
|
|
@@ -2454,9 +2456,9 @@ function encodeSignatureValue(value, suite) {
|
|
|
2454
2456
|
decodeSignatureValue(encoded, suite);
|
|
2455
2457
|
return encoded;
|
|
2456
2458
|
}
|
|
2457
|
-
function stripOwnIdAndSignature(
|
|
2459
|
+
function stripOwnIdAndSignature(object2, descriptor) {
|
|
2458
2460
|
const output = /* @__PURE__ */ Object.create(null);
|
|
2459
|
-
for (const [key, value] of Object.entries(
|
|
2461
|
+
for (const [key, value] of Object.entries(object2)) {
|
|
2460
2462
|
if (key === descriptor.idField || key === "signature") {
|
|
2461
2463
|
continue;
|
|
2462
2464
|
}
|
|
@@ -2465,8 +2467,8 @@ function stripOwnIdAndSignature(object, descriptor) {
|
|
|
2465
2467
|
return output;
|
|
2466
2468
|
}
|
|
2467
2469
|
function descriptorForUnsigned(input) {
|
|
2468
|
-
const
|
|
2469
|
-
return descriptorForSchema(requiredString2(
|
|
2470
|
+
const object2 = expectJsonObject(normalizeJson(input), "$");
|
|
2471
|
+
return descriptorForSchema(requiredString2(object2, "schema", "$"));
|
|
2470
2472
|
}
|
|
2471
2473
|
function descriptorForSchema(schema) {
|
|
2472
2474
|
if (schema === POLICY_SCHEMA) return DESCRIPTORS.Policy;
|
|
@@ -2480,28 +2482,28 @@ function expectJsonObject(input, path) {
|
|
|
2480
2482
|
}
|
|
2481
2483
|
return input;
|
|
2482
2484
|
}
|
|
2483
|
-
function assertExactKeys2(
|
|
2485
|
+
function assertExactKeys2(object2, allowed, path) {
|
|
2484
2486
|
const allowedSet = new Set(allowed);
|
|
2485
|
-
for (const key of Object.keys(
|
|
2487
|
+
for (const key of Object.keys(object2)) {
|
|
2486
2488
|
if (!allowedSet.has(key)) {
|
|
2487
2489
|
throw new SignedObjectSchemaError(`${path} has unknown field ${key}`);
|
|
2488
2490
|
}
|
|
2489
2491
|
}
|
|
2490
2492
|
}
|
|
2491
|
-
function requiredValue2(
|
|
2492
|
-
if (!hasOwn2(
|
|
2493
|
+
function requiredValue2(object2, key, path) {
|
|
2494
|
+
if (!hasOwn2(object2, key)) {
|
|
2493
2495
|
throw new SignedObjectSchemaError(`${path}.${key} is required`);
|
|
2494
2496
|
}
|
|
2495
|
-
return
|
|
2497
|
+
return object2[key];
|
|
2496
2498
|
}
|
|
2497
|
-
function requiredString2(
|
|
2498
|
-
return requireStringType(requiredValue2(
|
|
2499
|
+
function requiredString2(object2, key, path) {
|
|
2500
|
+
return requireStringType(requiredValue2(object2, key, path), `${path}.${key}`);
|
|
2499
2501
|
}
|
|
2500
|
-
function optionalString(
|
|
2501
|
-
if (!hasOwn2(
|
|
2502
|
+
function optionalString(object2, key, path) {
|
|
2503
|
+
if (!hasOwn2(object2, key)) {
|
|
2502
2504
|
return;
|
|
2503
2505
|
}
|
|
2504
|
-
requireStringType(requiredValue2(
|
|
2506
|
+
requireStringType(requiredValue2(object2, key, path), `${path}.${key}`);
|
|
2505
2507
|
}
|
|
2506
2508
|
function requireStringType(value, path) {
|
|
2507
2509
|
if (typeof value !== "string" || value.length === 0) {
|
|
@@ -2509,16 +2511,16 @@ function requireStringType(value, path) {
|
|
|
2509
2511
|
}
|
|
2510
2512
|
return value;
|
|
2511
2513
|
}
|
|
2512
|
-
function optionalBoolean(
|
|
2513
|
-
if (!hasOwn2(
|
|
2514
|
+
function optionalBoolean(object2, key, path) {
|
|
2515
|
+
if (!hasOwn2(object2, key)) {
|
|
2514
2516
|
return;
|
|
2515
2517
|
}
|
|
2516
|
-
if (typeof requiredValue2(
|
|
2518
|
+
if (typeof requiredValue2(object2, key, path) !== "boolean") {
|
|
2517
2519
|
throw new SignedObjectSchemaError(`${path}.${key} must be a boolean`);
|
|
2518
2520
|
}
|
|
2519
2521
|
}
|
|
2520
|
-
function requiredInteger(
|
|
2521
|
-
const value = requiredValue2(
|
|
2522
|
+
function requiredInteger(object2, key, path, minimum) {
|
|
2523
|
+
const value = requiredValue2(object2, key, path);
|
|
2522
2524
|
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < minimum) {
|
|
2523
2525
|
throw new SignedObjectSchemaError(
|
|
2524
2526
|
`${path}.${key} must be an integer >= ${minimum}`
|
|
@@ -2526,8 +2528,8 @@ function requiredInteger(object, key, path, minimum) {
|
|
|
2526
2528
|
}
|
|
2527
2529
|
return value;
|
|
2528
2530
|
}
|
|
2529
|
-
function requiredArray2(
|
|
2530
|
-
const value = requiredValue2(
|
|
2531
|
+
function requiredArray2(object2, key, path, minimum) {
|
|
2532
|
+
const value = requiredValue2(object2, key, path);
|
|
2531
2533
|
if (!Array.isArray(value) || value.length < minimum) {
|
|
2532
2534
|
throw new SignedObjectSchemaError(
|
|
2533
2535
|
`${path}.${key} must be an array with at least ${minimum} item(s)`
|
|
@@ -2535,22 +2537,22 @@ function requiredArray2(object, key, path, minimum) {
|
|
|
2535
2537
|
}
|
|
2536
2538
|
return value;
|
|
2537
2539
|
}
|
|
2538
|
-
function requiredStringArray(
|
|
2539
|
-
const values = requiredArray2(
|
|
2540
|
+
function requiredStringArray(object2, key, path, check) {
|
|
2541
|
+
const values = requiredArray2(object2, key, path, 0);
|
|
2540
2542
|
for (let index = 0; index < values.length; index++) {
|
|
2541
2543
|
const itemPath = `${path}.${key}[${index}]`;
|
|
2542
2544
|
const value = requireStringType(values[index], itemPath);
|
|
2543
2545
|
check?.(value, itemPath);
|
|
2544
2546
|
}
|
|
2545
2547
|
}
|
|
2546
|
-
function requiredDateString(
|
|
2547
|
-
assertRfc3339(requiredString2(
|
|
2548
|
+
function requiredDateString(object2, key, path) {
|
|
2549
|
+
assertRfc3339(requiredString2(object2, key, path), `${path}.${key}`);
|
|
2548
2550
|
}
|
|
2549
|
-
function optionalDateString(
|
|
2550
|
-
if (!hasOwn2(
|
|
2551
|
+
function optionalDateString(object2, key, path) {
|
|
2552
|
+
if (!hasOwn2(object2, key)) {
|
|
2551
2553
|
return;
|
|
2552
2554
|
}
|
|
2553
|
-
assertRfc3339(requiredString2(
|
|
2555
|
+
assertRfc3339(requiredString2(object2, key, path), `${path}.${key}`);
|
|
2554
2556
|
}
|
|
2555
2557
|
function assertRfc3339(value, path) {
|
|
2556
2558
|
const match = value.match(
|
|
@@ -2582,8 +2584,8 @@ function expectOneOf(actual, allowed, path) {
|
|
|
2582
2584
|
}
|
|
2583
2585
|
throw new SignedObjectSchemaError(`${path} has unsupported value ${actual}`);
|
|
2584
2586
|
}
|
|
2585
|
-
function hasOwn2(
|
|
2586
|
-
return objectHasOwn3(
|
|
2587
|
+
function hasOwn2(object2, key) {
|
|
2588
|
+
return objectHasOwn3(object2, key);
|
|
2587
2589
|
}
|
|
2588
2590
|
function assertSupportedSignatureSuite(suite) {
|
|
2589
2591
|
if (suite !== ED25519_JCS_SIGNATURE_SUITE && suite !== EIP191_JCS_SIGNATURE_SUITE) {
|
|
@@ -2662,13 +2664,13 @@ function base64UrlDecode(value) {
|
|
|
2662
2664
|
return decoded;
|
|
2663
2665
|
}
|
|
2664
2666
|
function hexToBytes(value) {
|
|
2665
|
-
const
|
|
2666
|
-
if (
|
|
2667
|
+
const hex2 = value.slice(2);
|
|
2668
|
+
if (hex2.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(hex2)) {
|
|
2667
2669
|
throw new SignatureMaterialError("hex signature must have even length");
|
|
2668
2670
|
}
|
|
2669
|
-
const output = new Uint8Array(
|
|
2671
|
+
const output = new Uint8Array(hex2.length / 2);
|
|
2670
2672
|
for (let index = 0; index < output.length; index++) {
|
|
2671
|
-
output[index] = Number.parseInt(
|
|
2673
|
+
output[index] = Number.parseInt(hex2.slice(index * 2, index * 2 + 2), 16);
|
|
2672
2674
|
}
|
|
2673
2675
|
return output;
|
|
2674
2676
|
}
|
|
@@ -3019,9 +3021,9 @@ function expectPolicyEngineRecord(input) {
|
|
|
3019
3021
|
);
|
|
3020
3022
|
}
|
|
3021
3023
|
}
|
|
3022
|
-
function assertExactKeys3(
|
|
3024
|
+
function assertExactKeys3(object2, allowed, path) {
|
|
3023
3025
|
const allowedSet = new Set(allowed);
|
|
3024
|
-
for (const key of Object.keys(
|
|
3026
|
+
for (const key of Object.keys(object2)) {
|
|
3025
3027
|
if (!allowedSet.has(key)) {
|
|
3026
3028
|
throw new PolicyAuthoringError(
|
|
3027
3029
|
"policy-authoring-unknown-key",
|
|
@@ -3030,17 +3032,17 @@ function assertExactKeys3(object, allowed, path) {
|
|
|
3030
3032
|
}
|
|
3031
3033
|
}
|
|
3032
3034
|
}
|
|
3033
|
-
function requiredValue3(
|
|
3034
|
-
if (!hasOwn3(
|
|
3035
|
+
function requiredValue3(object2, key, path) {
|
|
3036
|
+
if (!hasOwn3(object2, key)) {
|
|
3035
3037
|
throw new PolicyAuthoringError(
|
|
3036
3038
|
"policy-authoring-malformed",
|
|
3037
3039
|
`${path}.${key} is required`
|
|
3038
3040
|
);
|
|
3039
3041
|
}
|
|
3040
|
-
return
|
|
3042
|
+
return object2[key];
|
|
3041
3043
|
}
|
|
3042
|
-
function requiredString3(
|
|
3043
|
-
const value = requiredValue3(
|
|
3044
|
+
function requiredString3(object2, key, path) {
|
|
3045
|
+
const value = requiredValue3(object2, key, path);
|
|
3044
3046
|
if (typeof value !== "string" || value.length === 0) {
|
|
3045
3047
|
throw new PolicyAuthoringError(
|
|
3046
3048
|
"policy-authoring-malformed",
|
|
@@ -3049,11 +3051,11 @@ function requiredString3(object, key, path) {
|
|
|
3049
3051
|
}
|
|
3050
3052
|
return value;
|
|
3051
3053
|
}
|
|
3052
|
-
function fieldString(
|
|
3053
|
-
if (!hasOwn3(
|
|
3054
|
+
function fieldString(object2, key, path, code2) {
|
|
3055
|
+
if (!hasOwn3(object2, key)) {
|
|
3054
3056
|
throw new PolicyAuthoringError(code2, `${path}.${key} is required`);
|
|
3055
3057
|
}
|
|
3056
|
-
const value =
|
|
3058
|
+
const value = object2[key];
|
|
3057
3059
|
if (typeof value !== "string" || value.length === 0) {
|
|
3058
3060
|
throw new PolicyAuthoringError(
|
|
3059
3061
|
code2,
|
|
@@ -3062,8 +3064,8 @@ function fieldString(object, key, path, code2) {
|
|
|
3062
3064
|
}
|
|
3063
3065
|
return value;
|
|
3064
3066
|
}
|
|
3065
|
-
function requiredObject(
|
|
3066
|
-
const value = requiredValue3(
|
|
3067
|
+
function requiredObject(object2, key, path) {
|
|
3068
|
+
const value = requiredValue3(object2, key, path);
|
|
3067
3069
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
3068
3070
|
throw new PolicyAuthoringError(
|
|
3069
3071
|
"policy-authoring-malformed",
|
|
@@ -3072,8 +3074,8 @@ function requiredObject(object, key, path) {
|
|
|
3072
3074
|
}
|
|
3073
3075
|
return value;
|
|
3074
3076
|
}
|
|
3075
|
-
function requiredArray3(
|
|
3076
|
-
const value = requiredValue3(
|
|
3077
|
+
function requiredArray3(object2, key, path) {
|
|
3078
|
+
const value = requiredValue3(object2, key, path);
|
|
3077
3079
|
if (!Array.isArray(value)) {
|
|
3078
3080
|
throw new PolicyAuthoringError(
|
|
3079
3081
|
"policy-authoring-malformed",
|
|
@@ -3082,8 +3084,8 @@ function requiredArray3(object, key, path) {
|
|
|
3082
3084
|
}
|
|
3083
3085
|
return value;
|
|
3084
3086
|
}
|
|
3085
|
-
function requiredStringArray2(
|
|
3086
|
-
const values = requiredArray3(
|
|
3087
|
+
function requiredStringArray2(object2, key, path) {
|
|
3088
|
+
const values = requiredArray3(object2, key, path);
|
|
3087
3089
|
return values.map((value, index) => {
|
|
3088
3090
|
if (typeof value !== "string" || value.length === 0) {
|
|
3089
3091
|
throw new PolicyAuthoringError(
|
|
@@ -3180,19 +3182,686 @@ function parseStrictRfc3339(value, path) {
|
|
|
3180
3182
|
var objectHasOwn4 = Object.hasOwn ?? Object.prototype.hasOwnProperty.call.bind(
|
|
3181
3183
|
Object.prototype.hasOwnProperty
|
|
3182
3184
|
);
|
|
3183
|
-
function hasOwn3(
|
|
3184
|
-
return objectHasOwn4(
|
|
3185
|
+
function hasOwn3(object2, key) {
|
|
3186
|
+
return objectHasOwn4(object2, key);
|
|
3187
|
+
}
|
|
3188
|
+
|
|
3189
|
+
// src/policy/unified.ts
|
|
3190
|
+
import { sha256 as sha2564 } from "@noble/hashes/sha256";
|
|
3191
|
+
import { blake3 } from "@noble/hashes/blake3";
|
|
3192
|
+
import { ed25519 as ed255192 } from "@noble/curves/ed25519";
|
|
3193
|
+
import { z } from "zod";
|
|
3194
|
+
var POLICY_V1_SCHEMA = "xyz.tinycloud.policy/policy/v1";
|
|
3195
|
+
var POLICY_CAPABILITY_V1_SCHEMA = "xyz.tinycloud.policy/capability/v1";
|
|
3196
|
+
var POLICY_ENFORCEMENT_DELEGATION_V2_SCHEMA = "xyz.tinycloud.policy/enforcement-delegation/v2";
|
|
3197
|
+
var ATTESTED_ENFORCER_BINDING_V2_SCHEMA = "xyz.tinycloud.policy/attested-enforcer/v2";
|
|
3198
|
+
var ROOT_STATUS_CHECKPOINT_V1_SCHEMA = "xyz.tinycloud.policy/root-status/v1";
|
|
3199
|
+
var ROOT_REVOCATION_V1_SCHEMA = "xyz.tinycloud.policy/root-revocation/v1";
|
|
3200
|
+
var POLICY_SESSION_UCAN_V1_PROFILE = "policy-session-ucan/v1";
|
|
3201
|
+
var POLICY_V1_DOMAIN = "xyz.tinycloud.policy/policy/v1\0";
|
|
3202
|
+
var POLICY_CAPABILITY_V1_DOMAIN = "xyz.tinycloud.policy/PolicyCapability/v1\0";
|
|
3203
|
+
var CONTENT_SOURCE_V1_DOMAIN = "xyz.tinycloud.policy/ContentSource/v1\0";
|
|
3204
|
+
var NATIVE_PROJECTION_V1_DOMAIN = "xyz.tinycloud.policy/NativeProjection/v1\0";
|
|
3205
|
+
var ROOT_STATUS_V1_DOMAIN = "xyz.tinycloud.policy/RootStatusCheckpoint/v1\0";
|
|
3206
|
+
var ROOT_STATUS_RENEWAL_V1_DOMAIN = "xyz.tinycloud.policy/RootStatusRenewal/v1\0";
|
|
3207
|
+
var ROOT_REVOCATION_V1_DOMAIN = "xyz.tinycloud.policy/RootRevocation/v1\0";
|
|
3208
|
+
var LAST_V2_CREATE_AT = "2026-09-30T00:00:00Z";
|
|
3209
|
+
var MAX_LEGACY_ENVELOPE_EXPIRES_AT = "2026-12-29T00:00:00Z";
|
|
3210
|
+
var LAST_V2_READ_AT = "2027-01-05T00:00:00Z";
|
|
3211
|
+
async function requestPolicyChallengeV3(input) {
|
|
3212
|
+
const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
|
|
3213
|
+
const response = await fetchFn(new URL("/share/v3/policy/challenges", input.nodeOrigin), {
|
|
3214
|
+
method: "POST",
|
|
3215
|
+
redirect: "error",
|
|
3216
|
+
headers: { accept: "application/json", "content-type": "application/json" },
|
|
3217
|
+
body: JSON.stringify({ policyCid: input.policyCid, recipientDid: input.recipientDid, requestedCapabilities: input.requestedCapabilities.map(normalizeUnifiedPolicyCapability) })
|
|
3218
|
+
});
|
|
3219
|
+
if (!response.ok) throw new Error(`policy challenge rejected (${response.status})`);
|
|
3220
|
+
const value = object(await response.json(), "policy challenge");
|
|
3221
|
+
if (typeof value.challengeId !== "string" || typeof value.nonce !== "string" || value.policyCid !== input.policyCid || value.recipientDid !== input.recipientDid)
|
|
3222
|
+
throw new Error("policy challenge binding is invalid");
|
|
3223
|
+
return value;
|
|
3224
|
+
}
|
|
3225
|
+
async function mintPolicySessionV3(input) {
|
|
3226
|
+
const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
|
|
3227
|
+
const challenge = input.challenge ?? await requestPolicyChallengeV3(input);
|
|
3228
|
+
if (challenge.policyCid !== input.policyCid || challenge.recipientDid !== input.recipientDid)
|
|
3229
|
+
throw new Error("policy challenge binding is invalid");
|
|
3230
|
+
const response = await fetchFn(new URL("/share/v3/policy/delegations", input.nodeOrigin), {
|
|
3231
|
+
method: "POST",
|
|
3232
|
+
redirect: "error",
|
|
3233
|
+
headers: { accept: "application/json", "content-type": "application/json" },
|
|
3234
|
+
body: JSON.stringify({ policyCid: input.policyCid, challengeId: challenge.challengeId, nonce: challenge.nonce, claim: input.claim, presentation: input.presentation })
|
|
3235
|
+
});
|
|
3236
|
+
if (!response.ok) throw new Error(`policy delegation rejected (${response.status})`);
|
|
3237
|
+
const value = object(await response.json(), "policy delegation");
|
|
3238
|
+
if (value.admitted !== true || typeof value.sessionCid !== "string" || typeof value.authorization !== "string")
|
|
3239
|
+
throw new Error("policy delegation response is invalid");
|
|
3240
|
+
const session = parsePolicySessionUcan(value.authorization, [input.policyRootCid, input.enforcementRootCid]);
|
|
3241
|
+
const expectedAttenuation = compactAttenuationForPolicyCapabilities(input.requestedCapabilities);
|
|
3242
|
+
if (session.cid !== value.sessionCid || session.aud !== input.recipientDid || session.fact.policyCid !== input.policyCid || session.fact.recipientDid !== input.recipientDid || session.fact.policyDelegationCid !== input.policyRootCid || session.fact.enforcementDelegationCid !== input.enforcementRootCid || jcsCanonicalize(session.att) !== jcsCanonicalize(expectedAttenuation) || Object.entries(input.expectedFacts ?? {}).some(([key, expected]) => session.fact[key] !== expected))
|
|
3243
|
+
throw new Error("policy delegation signed binding is invalid");
|
|
3244
|
+
return session;
|
|
3245
|
+
}
|
|
3246
|
+
function compactAttenuationForPolicyCapabilities(input) {
|
|
3247
|
+
const attenuation = {};
|
|
3248
|
+
for (const raw of input) {
|
|
3249
|
+
const capability = normalizeUnifiedPolicyCapability(raw);
|
|
3250
|
+
if (attenuation[capability.resource] !== void 0)
|
|
3251
|
+
throw new Error("policy capabilities contain a duplicate resource");
|
|
3252
|
+
attenuation[capability.resource] = capability.kind === "encryption" ? { [capability.action]: [{}] } : Object.fromEntries(capability.actions.map((action) => [action, [{
|
|
3253
|
+
type: "xyz.tinycloud.resource/selector",
|
|
3254
|
+
kind: capability.selector,
|
|
3255
|
+
value: capability.resource
|
|
3256
|
+
}]]));
|
|
3257
|
+
}
|
|
3258
|
+
return attenuation;
|
|
3259
|
+
}
|
|
3260
|
+
function verifyPolicyRootStatusCheckpointV3(input) {
|
|
3261
|
+
const checkpoint = input.checkpoint;
|
|
3262
|
+
const allowed = /* @__PURE__ */ new Set(["schema", "targetCid", "targetRole", "ownerDid", "nodeAudience", "state", "sequence", "checkedAt", "freshUntil", "revokedAt", "revocationCid", "previousCheckpointDigestHex", "issuerDid", "signature"]);
|
|
3263
|
+
if (Object.keys(checkpoint).some((key) => !allowed.has(key)) || checkpoint.schema !== ROOT_STATUS_CHECKPOINT_V1_SCHEMA || checkpoint.targetCid !== input.rootCid || checkpoint.targetRole !== "policy-authority" && checkpoint.targetRole !== "policy-enforcement" || checkpoint.state !== "active" && checkpoint.state !== "revoked" || typeof checkpoint.ownerDid !== "string" || typeof checkpoint.nodeAudience !== "string" || checkpoint.issuerDid !== checkpoint.nodeAudience || input.expectedNodeAudience !== void 0 && checkpoint.nodeAudience !== input.expectedNodeAudience || !Number.isInteger(checkpoint.sequence) || checkpoint.sequence < 1 || typeof checkpoint.checkedAt !== "string" || typeof checkpoint.freshUntil !== "string") return false;
|
|
3264
|
+
const checkedAt = Date.parse(checkpoint.checkedAt);
|
|
3265
|
+
const freshUntil = Date.parse(checkpoint.freshUntil);
|
|
3266
|
+
const now = (input.now ?? /* @__PURE__ */ new Date()).getTime();
|
|
3267
|
+
if (!Number.isFinite(checkedAt) || !Number.isFinite(freshUntil) || freshUntil < now || freshUntil <= checkedAt || freshUntil - checkedAt > 3e5) return false;
|
|
3268
|
+
if (checkpoint.sequence === 1 !== (checkpoint.previousCheckpointDigestHex === void 0)) return false;
|
|
3269
|
+
if (checkpoint.sequence !== 1 && (typeof checkpoint.previousCheckpointDigestHex !== "string" || !/^[0-9a-f]{64}$/.test(checkpoint.previousCheckpointDigestHex))) return false;
|
|
3270
|
+
if (checkpoint.state === "active" && (checkpoint.revokedAt !== void 0 || checkpoint.revocationCid !== void 0)) return false;
|
|
3271
|
+
if (checkpoint.state === "revoked" && (typeof checkpoint.revokedAt !== "string" || typeof checkpoint.revocationCid !== "string")) return false;
|
|
3272
|
+
const signature = checkpoint.signature;
|
|
3273
|
+
if (!isRecordValue(signature) || Object.keys(signature).length !== 3 || signature.suite !== "Ed25519" || signature.signerDid !== checkpoint.issuerDid || typeof signature.value !== "string") return false;
|
|
3274
|
+
try {
|
|
3275
|
+
const principal = checkpoint.issuerDid.split("#", 1)[0];
|
|
3276
|
+
const didMaterial = principal.startsWith("did:key:") ? base58btc.decode(principal.slice("did:key:".length)) : new Uint8Array();
|
|
3277
|
+
if (didMaterial.length !== 34 || didMaterial[0] !== 237 || didMaterial[1] !== 1) return false;
|
|
3278
|
+
const unsigned = { ...checkpoint };
|
|
3279
|
+
delete unsigned.signature;
|
|
3280
|
+
return ed255192.verify(
|
|
3281
|
+
decodeBase64Url(signature.value),
|
|
3282
|
+
sha2564(new TextEncoder().encode(ROOT_STATUS_V1_DOMAIN + jcsCanonicalize(unsigned))),
|
|
3283
|
+
didMaterial.slice(2)
|
|
3284
|
+
);
|
|
3285
|
+
} catch {
|
|
3286
|
+
return false;
|
|
3287
|
+
}
|
|
3288
|
+
}
|
|
3289
|
+
async function getPolicyRootStatusV3(input) {
|
|
3290
|
+
const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
|
|
3291
|
+
const response = await fetchFn(new URL(`/share/v3/policy/status/${encodeURIComponent(input.rootCid)}`, input.nodeOrigin), {
|
|
3292
|
+
method: "GET",
|
|
3293
|
+
redirect: "error",
|
|
3294
|
+
headers: { accept: "application/json" }
|
|
3295
|
+
});
|
|
3296
|
+
if (!response.ok) throw new Error(`policy root status rejected (${response.status})`);
|
|
3297
|
+
const value = object(await response.json(), "policy root status");
|
|
3298
|
+
const checkpoint = object(value.checkpoint, "policy root checkpoint");
|
|
3299
|
+
if (value.rootCid !== input.rootCid || value.state !== "active" && value.state !== "revoked" || value.state !== checkpoint.state || !verifyPolicyRootStatusCheckpointV3({ rootCid: input.rootCid, checkpoint, expectedNodeAudience: input.expectedNodeAudience, now: input.now }))
|
|
3300
|
+
throw new Error("policy root status binding is invalid");
|
|
3301
|
+
const revocation = value.revocation === void 0 ? void 0 : object(value.revocation, "policy root revocation");
|
|
3302
|
+
if (value.state === "revoked" !== (revocation !== void 0) || revocation !== void 0 && !verifyPolicyRootRevocationV3({
|
|
3303
|
+
rootCid: input.rootCid,
|
|
3304
|
+
checkpoint,
|
|
3305
|
+
revocation,
|
|
3306
|
+
expectedEnforcerDid: input.expectedEnforcerDid
|
|
3307
|
+
})) throw new Error("policy root status revocation evidence is invalid");
|
|
3308
|
+
return { rootCid: input.rootCid, state: value.state, checkpoint, ...revocation === void 0 ? {} : { revocation } };
|
|
3309
|
+
}
|
|
3310
|
+
function verifyPolicyRootRevocationV3(input) {
|
|
3311
|
+
const value = input.revocation;
|
|
3312
|
+
const allowed = ["schema", "targetCid", "targetRole", "ownerDid", "nodeAudience", "revokedAt", "reason", "issuerDid", "signature"];
|
|
3313
|
+
if (Object.keys(value).length !== allowed.length || Object.keys(value).some((key) => !allowed.includes(key)) || value.schema !== ROOT_REVOCATION_V1_SCHEMA || value.targetCid !== input.rootCid || value.targetRole !== input.checkpoint.targetRole || value.ownerDid !== input.checkpoint.ownerDid || value.nodeAudience !== input.checkpoint.nodeAudience || value.revokedAt !== input.checkpoint.revokedAt || typeof value.reason !== "string" || value.reason.length === 0 || typeof value.issuerDid !== "string") return false;
|
|
3314
|
+
const authorized = value.issuerDid === value.ownerDid || value.targetRole === "policy-enforcement" && value.issuerDid === input.expectedEnforcerDid;
|
|
3315
|
+
if (!authorized) return false;
|
|
3316
|
+
const signature = value.signature;
|
|
3317
|
+
if (!isRecordValue(signature) || Object.keys(signature).length !== 3 || signature.suite !== "Ed25519" || signature.signerDid !== value.issuerDid || typeof signature.value !== "string") return false;
|
|
3318
|
+
try {
|
|
3319
|
+
const principal = value.issuerDid.split("#", 1)[0];
|
|
3320
|
+
const didMaterial = principal.startsWith("did:key:") ? base58btc.decode(principal.slice("did:key:".length)) : new Uint8Array();
|
|
3321
|
+
if (didMaterial.length !== 34 || didMaterial[0] !== 237 || didMaterial[1] !== 1) return false;
|
|
3322
|
+
const unsigned = { ...value };
|
|
3323
|
+
delete unsigned.signature;
|
|
3324
|
+
const digest2 = sha2564(new TextEncoder().encode(ROOT_REVOCATION_V1_DOMAIN + jcsCanonicalize(unsigned)));
|
|
3325
|
+
return input.checkpoint.revocationCid === hex(digest2) && ed255192.verify(decodeBase64Url(signature.value), digest2, didMaterial.slice(2));
|
|
3326
|
+
} catch {
|
|
3327
|
+
return false;
|
|
3328
|
+
}
|
|
3329
|
+
}
|
|
3330
|
+
async function renewPolicyRootStatusV3(input) {
|
|
3331
|
+
const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
|
|
3332
|
+
const current = await getPolicyRootStatusV3({ nodeOrigin: input.nodeOrigin, rootCid: input.rootCid, expectedNodeAudience: input.nodeAudience, now: input.now, fetch: fetchFn });
|
|
3333
|
+
if (current.state !== "active" || current.checkpoint.ownerDid !== input.ownerDid || current.checkpoint.nodeAudience !== input.nodeAudience || current.checkpoint.state !== "active" || !Number.isInteger(current.checkpoint.sequence))
|
|
3334
|
+
throw new Error("policy root status cannot be renewed");
|
|
3335
|
+
const currentUnsigned = { ...current.checkpoint };
|
|
3336
|
+
delete currentUnsigned.signature;
|
|
3337
|
+
const previousCheckpointDigestHex = hex(sha2564(new TextEncoder().encode(ROOT_STATUS_V1_DOMAIN + jcsCanonicalize(currentUnsigned))));
|
|
3338
|
+
const unsigned = {
|
|
3339
|
+
schema: "xyz.tinycloud.policy/root-status-renewal/v1",
|
|
3340
|
+
targetCid: input.rootCid,
|
|
3341
|
+
ownerDid: input.ownerDid,
|
|
3342
|
+
nodeAudience: input.nodeAudience,
|
|
3343
|
+
issuedAt: (input.now ?? /* @__PURE__ */ new Date()).toISOString(),
|
|
3344
|
+
nonce: input.nonce ?? encodeBase64Url(crypto.getRandomValues(new Uint8Array(16))),
|
|
3345
|
+
sequence: current.checkpoint.sequence + 1,
|
|
3346
|
+
previousCheckpointDigestHex
|
|
3347
|
+
};
|
|
3348
|
+
const signature = await input.sign(sha2564(new TextEncoder().encode(ROOT_STATUS_RENEWAL_V1_DOMAIN + jcsCanonicalize(unsigned))));
|
|
3349
|
+
if (signature.length !== 64) throw new Error("policy root renewal signature must be Ed25519");
|
|
3350
|
+
const response = await fetchFn(new URL("/share/v3/policy/status", input.nodeOrigin), {
|
|
3351
|
+
method: "POST",
|
|
3352
|
+
redirect: "error",
|
|
3353
|
+
headers: { accept: "application/json", "content-type": "application/json" },
|
|
3354
|
+
body: JSON.stringify({ rootCid: input.rootCid, renewal: { ...unsigned, signature: { suite: "Ed25519", signerDid: input.ownerDid, value: encodeBase64Url(signature) } } })
|
|
3355
|
+
});
|
|
3356
|
+
if (!response.ok) throw new Error(`policy root renewal rejected (${response.status})`);
|
|
3357
|
+
return object(await response.json(), "policy root renewal");
|
|
3358
|
+
}
|
|
3359
|
+
async function revokePolicyRootV3(input) {
|
|
3360
|
+
if (input.reason.length === 0) throw new Error("policy root revocation reason is required");
|
|
3361
|
+
const unsigned = {
|
|
3362
|
+
schema: ROOT_REVOCATION_V1_SCHEMA,
|
|
3363
|
+
targetCid: input.rootCid,
|
|
3364
|
+
targetRole: input.targetRole,
|
|
3365
|
+
ownerDid: input.ownerDid,
|
|
3366
|
+
nodeAudience: input.nodeAudience,
|
|
3367
|
+
revokedAt: (input.now ?? /* @__PURE__ */ new Date()).toISOString(),
|
|
3368
|
+
reason: input.reason,
|
|
3369
|
+
issuerDid: input.issuerDid
|
|
3370
|
+
};
|
|
3371
|
+
const signature = await input.sign(sha2564(new TextEncoder().encode(ROOT_REVOCATION_V1_DOMAIN + jcsCanonicalize(unsigned))));
|
|
3372
|
+
if (signature.length !== 64) throw new Error("policy root revocation signature must be Ed25519");
|
|
3373
|
+
const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
|
|
3374
|
+
const response = await fetchFn(new URL("/revoke", input.nodeOrigin), {
|
|
3375
|
+
method: "POST",
|
|
3376
|
+
redirect: "error",
|
|
3377
|
+
headers: { accept: "application/json", "content-type": "application/json" },
|
|
3378
|
+
body: JSON.stringify({ revocation: { ...unsigned, signature: { suite: "Ed25519", signerDid: input.issuerDid, value: encodeBase64Url(signature) } } })
|
|
3379
|
+
});
|
|
3380
|
+
if (!response.ok) throw new Error(`policy root revocation rejected (${response.status})`);
|
|
3381
|
+
return object(await response.json(), "policy root revocation");
|
|
3382
|
+
}
|
|
3383
|
+
var POLICY_SESSION_FACT_KEYS = [
|
|
3384
|
+
"profile",
|
|
3385
|
+
"ownerDid",
|
|
3386
|
+
"policyId",
|
|
3387
|
+
"policyDigestHex",
|
|
3388
|
+
"policyCid",
|
|
3389
|
+
"policyDelegationCid",
|
|
3390
|
+
"enforcementDelegationCid",
|
|
3391
|
+
"contentSourceDigestHex",
|
|
3392
|
+
"capabilityCeilingHashHex",
|
|
3393
|
+
"nativeProjectionHashHex",
|
|
3394
|
+
"enforcerDid",
|
|
3395
|
+
"nodeAudience",
|
|
3396
|
+
"recipientDid",
|
|
3397
|
+
"challengeId",
|
|
3398
|
+
"claimDigestHex",
|
|
3399
|
+
"claimJti",
|
|
3400
|
+
"vpDigestHex",
|
|
3401
|
+
"credentialEvidenceDigestHex",
|
|
3402
|
+
"decisionContextDigestHex",
|
|
3403
|
+
"issuanceAuditDigestHex",
|
|
3404
|
+
"remainingRedelegationDepth"
|
|
3405
|
+
];
|
|
3406
|
+
var KV_ACTIONS = /* @__PURE__ */ new Set([
|
|
3407
|
+
"tinycloud.kv/get",
|
|
3408
|
+
"tinycloud.kv/list",
|
|
3409
|
+
"tinycloud.kv/metadata",
|
|
3410
|
+
"tinycloud.kv/put"
|
|
3411
|
+
]);
|
|
3412
|
+
function object(value, label) {
|
|
3413
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
3414
|
+
throw new Error(`${label} must be an object`);
|
|
3415
|
+
}
|
|
3416
|
+
return value;
|
|
3417
|
+
}
|
|
3418
|
+
function exactKeys(value, allowed, label) {
|
|
3419
|
+
const keys = new Set(allowed);
|
|
3420
|
+
if (Object.keys(value).some((key) => !keys.has(key)))
|
|
3421
|
+
throw new Error(`${label} contains an unknown field`);
|
|
3422
|
+
}
|
|
3423
|
+
function nonEmptyString(value, label) {
|
|
3424
|
+
if (typeof value !== "string" || value.length === 0)
|
|
3425
|
+
throw new Error(`${label} must be a non-empty string`);
|
|
3426
|
+
return value;
|
|
3427
|
+
}
|
|
3428
|
+
function parseKvResource(resource) {
|
|
3429
|
+
const match = /^tinycloud:\/\/([^/]+)\/kv\/(.+)$/.exec(resource);
|
|
3430
|
+
if (!match || match[1].includes(":") || match[1].includes("?") || match[1].includes("#") || match[1].includes("%") || match[2].startsWith("/") || match[2].endsWith("/") || match[2].includes("//") || match[2].split("/").some((part) => part === "." || part === ".." || part.length === 0)) {
|
|
3431
|
+
throw new Error("KV resource is not canonical");
|
|
3432
|
+
}
|
|
3433
|
+
return { space: match[1], path: match[2] };
|
|
3434
|
+
}
|
|
3435
|
+
function parseEncryptionResource(resource) {
|
|
3436
|
+
if (!resource.startsWith("urn:tinycloud:encryption:")) throw new Error("encryption capability is invalid");
|
|
3437
|
+
const rest = resource.slice("urn:tinycloud:encryption:".length);
|
|
3438
|
+
const separator = rest.lastIndexOf(":");
|
|
3439
|
+
const ownerDid = separator < 0 ? "" : rest.slice(0, separator);
|
|
3440
|
+
const network = separator < 0 ? "" : rest.slice(separator + 1);
|
|
3441
|
+
if (!ownerDid.startsWith("did:") || network.length === 0 || network.includes(":") || network.includes("/") || network.includes("%") || network.includes("?") || network.includes("#")) {
|
|
3442
|
+
throw new Error("encryption capability is invalid");
|
|
3443
|
+
}
|
|
3444
|
+
}
|
|
3445
|
+
function normalizeUnifiedPolicyCapability(input) {
|
|
3446
|
+
const value = object(input, "capability");
|
|
3447
|
+
const kind = nonEmptyString(value.kind, "capability.kind");
|
|
3448
|
+
if (kind === "kv") {
|
|
3449
|
+
exactKeys(
|
|
3450
|
+
value,
|
|
3451
|
+
["kind", "resource", "selector", "actions"],
|
|
3452
|
+
"KV capability"
|
|
3453
|
+
);
|
|
3454
|
+
const resource = nonEmptyString(value.resource, "capability.resource");
|
|
3455
|
+
parseKvResource(resource);
|
|
3456
|
+
if (value.selector !== "exact" && value.selector !== "prefix")
|
|
3457
|
+
throw new Error("capability.selector is invalid");
|
|
3458
|
+
if (!Array.isArray(value.actions) || value.actions.length === 0)
|
|
3459
|
+
throw new Error("capability.actions is invalid");
|
|
3460
|
+
const actions = value.actions.map(
|
|
3461
|
+
(action) => nonEmptyString(action, "capability.actions[]")
|
|
3462
|
+
);
|
|
3463
|
+
if (new Set(actions).size !== actions.length || actions.some((action) => !KV_ACTIONS.has(action)))
|
|
3464
|
+
throw new Error("capability.actions is invalid");
|
|
3465
|
+
return {
|
|
3466
|
+
kind: "kv",
|
|
3467
|
+
resource,
|
|
3468
|
+
selector: value.selector,
|
|
3469
|
+
actions: [...actions].sort()
|
|
3470
|
+
};
|
|
3471
|
+
}
|
|
3472
|
+
if (kind === "encryption") {
|
|
3473
|
+
exactKeys(value, ["kind", "resource", "action"], "encryption capability");
|
|
3474
|
+
const resource = nonEmptyString(value.resource, "capability.resource");
|
|
3475
|
+
if (value.action !== "tinycloud.encryption/decrypt")
|
|
3476
|
+
throw new Error("encryption capability is invalid");
|
|
3477
|
+
parseEncryptionResource(resource);
|
|
3478
|
+
return {
|
|
3479
|
+
kind: "encryption",
|
|
3480
|
+
resource,
|
|
3481
|
+
action: "tinycloud.encryption/decrypt"
|
|
3482
|
+
};
|
|
3483
|
+
}
|
|
3484
|
+
throw new Error("capability.kind is invalid");
|
|
3485
|
+
}
|
|
3486
|
+
function canonicalizeUnifiedPolicyCapability(input) {
|
|
3487
|
+
return normalizeUnifiedPolicyCapability(input);
|
|
3488
|
+
}
|
|
3489
|
+
function unifiedPolicyCapabilityDigestHex(input) {
|
|
3490
|
+
return hex(
|
|
3491
|
+
sha2564(
|
|
3492
|
+
new TextEncoder().encode(
|
|
3493
|
+
POLICY_CAPABILITY_V1_DOMAIN + jcsCanonicalize(normalizeUnifiedPolicyCapability(input))
|
|
3494
|
+
)
|
|
3495
|
+
)
|
|
3496
|
+
);
|
|
3497
|
+
}
|
|
3498
|
+
function unifiedPolicyCapabilityContains(authorityInput, requestedInput) {
|
|
3499
|
+
try {
|
|
3500
|
+
const authority = normalizeUnifiedPolicyCapability(authorityInput);
|
|
3501
|
+
const requested = normalizeUnifiedPolicyCapability(requestedInput);
|
|
3502
|
+
if (authority.kind !== requested.kind) return false;
|
|
3503
|
+
if (authority.kind === "encryption" && requested.kind === "encryption")
|
|
3504
|
+
return authority.resource === requested.resource && authority.action === requested.action;
|
|
3505
|
+
if (authority.kind !== "kv" || requested.kind !== "kv") return false;
|
|
3506
|
+
const { resource: authorized } = authority;
|
|
3507
|
+
const { resource: requestedResource } = requested;
|
|
3508
|
+
const pathContained = authority.selector === "exact" ? authorized === requestedResource : authorized === requestedResource || requestedResource.startsWith(`${authorized}/`);
|
|
3509
|
+
if (!pathContained || authority.selector === "exact" && requested.selector === "prefix")
|
|
3510
|
+
return false;
|
|
3511
|
+
return requested.actions.every(
|
|
3512
|
+
(action) => authority.actions.includes(action)
|
|
3513
|
+
);
|
|
3514
|
+
} catch {
|
|
3515
|
+
return false;
|
|
3516
|
+
}
|
|
3517
|
+
}
|
|
3518
|
+
function projectUnifiedPolicyCapability(input) {
|
|
3519
|
+
const capability = normalizeUnifiedPolicyCapability(input);
|
|
3520
|
+
if (capability.kind === "encryption") {
|
|
3521
|
+
return {
|
|
3522
|
+
service: "tinycloud.encryption",
|
|
3523
|
+
space: capability.resource,
|
|
3524
|
+
path: capability.resource,
|
|
3525
|
+
actions: [capability.action]
|
|
3526
|
+
};
|
|
3527
|
+
}
|
|
3528
|
+
const { space, path } = parseKvResource(capability.resource);
|
|
3529
|
+
return {
|
|
3530
|
+
service: "tinycloud.kv",
|
|
3531
|
+
space,
|
|
3532
|
+
path,
|
|
3533
|
+
actions: [...capability.actions],
|
|
3534
|
+
caveat: {
|
|
3535
|
+
type: "xyz.tinycloud.resource/selector",
|
|
3536
|
+
kind: capability.selector,
|
|
3537
|
+
value: capability.resource
|
|
3538
|
+
}
|
|
3539
|
+
};
|
|
3540
|
+
}
|
|
3541
|
+
function projectUnifiedPolicyCapabilities(input) {
|
|
3542
|
+
return input.map(projectUnifiedPolicyCapability).sort((left, right) => {
|
|
3543
|
+
const a = jcsCanonicalize(left);
|
|
3544
|
+
const b = jcsCanonicalize(right);
|
|
3545
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
3546
|
+
});
|
|
3547
|
+
}
|
|
3548
|
+
function unifiedNativeProjectionHashHex(input) {
|
|
3549
|
+
return hex(
|
|
3550
|
+
sha2564(
|
|
3551
|
+
new TextEncoder().encode(
|
|
3552
|
+
NATIVE_PROJECTION_V1_DOMAIN + jcsCanonicalize(projectUnifiedPolicyCapabilities(input))
|
|
3553
|
+
)
|
|
3554
|
+
)
|
|
3555
|
+
);
|
|
3556
|
+
}
|
|
3557
|
+
function unifiedPolicyCapabilityFromNative(input) {
|
|
3558
|
+
const value = object(input, "native capability");
|
|
3559
|
+
exactKeys(
|
|
3560
|
+
value,
|
|
3561
|
+
["service", "space", "path", "actions", "caveat"],
|
|
3562
|
+
"native capability"
|
|
3563
|
+
);
|
|
3564
|
+
const service = nonEmptyString(value.service, "native.service");
|
|
3565
|
+
const actions = value.actions;
|
|
3566
|
+
if (!Array.isArray(actions)) throw new Error("native.actions is invalid");
|
|
3567
|
+
if (service === "tinycloud.encryption" && value.caveat === void 0 && value.space === value.path && actions.length === 1 && actions[0] === "tinycloud.encryption/decrypt") {
|
|
3568
|
+
return normalizeUnifiedPolicyCapability({
|
|
3569
|
+
kind: "encryption",
|
|
3570
|
+
resource: value.space,
|
|
3571
|
+
action: actions[0]
|
|
3572
|
+
});
|
|
3573
|
+
}
|
|
3574
|
+
if (service !== "tinycloud.kv" || typeof value.space !== "string" || typeof value.path !== "string")
|
|
3575
|
+
throw new Error("native capability is not supported");
|
|
3576
|
+
const caveat = object(value.caveat, "native.caveat");
|
|
3577
|
+
exactKeys(caveat, ["type", "kind", "value"], "native selector caveat");
|
|
3578
|
+
if (caveat.type !== "xyz.tinycloud.resource/selector" || caveat.kind !== "exact" && caveat.kind !== "prefix" || caveat.value !== `tinycloud://${value.space}/kv/${value.path}`)
|
|
3579
|
+
throw new Error("native selector caveat does not match capability");
|
|
3580
|
+
return normalizeUnifiedPolicyCapability({
|
|
3581
|
+
kind: "kv",
|
|
3582
|
+
resource: caveat.value,
|
|
3583
|
+
selector: caveat.kind,
|
|
3584
|
+
actions
|
|
3585
|
+
});
|
|
3586
|
+
}
|
|
3587
|
+
function contentSourceDigestHex(input) {
|
|
3588
|
+
return hex(
|
|
3589
|
+
sha2564(
|
|
3590
|
+
new TextEncoder().encode(
|
|
3591
|
+
CONTENT_SOURCE_V1_DOMAIN + jcsCanonicalize(input)
|
|
3592
|
+
)
|
|
3593
|
+
)
|
|
3594
|
+
);
|
|
3595
|
+
}
|
|
3596
|
+
function policyDigestHex(policy) {
|
|
3597
|
+
const canonicalPolicy = {
|
|
3598
|
+
...policy,
|
|
3599
|
+
capabilityCeiling: policy.capabilityCeiling.map(
|
|
3600
|
+
normalizeUnifiedPolicyCapability
|
|
3601
|
+
)
|
|
3602
|
+
};
|
|
3603
|
+
return hex(
|
|
3604
|
+
sha2564(
|
|
3605
|
+
new TextEncoder().encode(
|
|
3606
|
+
POLICY_V1_DOMAIN + jcsCanonicalize(canonicalPolicy)
|
|
3607
|
+
)
|
|
3608
|
+
)
|
|
3609
|
+
);
|
|
3610
|
+
}
|
|
3611
|
+
function policyIdForDigestHex(digestHex) {
|
|
3612
|
+
const digest2 = Uint8Array.from(
|
|
3613
|
+
(digestHex.match(/.{2}/g) ?? []).map((byte) => Number.parseInt(byte, 16))
|
|
3614
|
+
);
|
|
3615
|
+
if (digest2.length !== 32) throw new Error("policy digest must be 32 bytes");
|
|
3616
|
+
return `pol_${base32Lower(digest2)}`;
|
|
3617
|
+
}
|
|
3618
|
+
function policyCidFromCanonicalBytes(bytes) {
|
|
3619
|
+
return CID.createV1(85, create(18, sha2564(bytes))).toString();
|
|
3620
|
+
}
|
|
3621
|
+
var CompactHeaderSchema = z.object({
|
|
3622
|
+
alg: z.literal("EdDSA"),
|
|
3623
|
+
jwk: z.object({ alg: z.literal("EdDSA"), crv: z.literal("Ed25519"), kty: z.literal("OKP"), x: z.string().min(1) }).strict(),
|
|
3624
|
+
typ: z.literal("JWT"),
|
|
3625
|
+
ucv: z.literal("0.10.0")
|
|
3626
|
+
}).strict();
|
|
3627
|
+
var CompactPayloadSchema = z.object({
|
|
3628
|
+
att: z.record(z.record(z.array(z.unknown()).min(1))),
|
|
3629
|
+
aud: z.string().min(1),
|
|
3630
|
+
exp: z.number().int(),
|
|
3631
|
+
fct: z.array(z.record(z.unknown())).length(1),
|
|
3632
|
+
iss: z.string().min(1),
|
|
3633
|
+
nbf: z.number().int(),
|
|
3634
|
+
nnc: z.string().min(1),
|
|
3635
|
+
prf: z.array(z.string().min(1))
|
|
3636
|
+
}).strict();
|
|
3637
|
+
async function signCompactUcanAuthorization(input) {
|
|
3638
|
+
if (input.notBefore >= input.expiresAt || input.expiresAt - input.notBefore > 60)
|
|
3639
|
+
throw new Error("compact invocation lifetime must be between one and 60 seconds");
|
|
3640
|
+
const principal = input.issuerDid.split("#", 1)[0];
|
|
3641
|
+
const didMaterial = principal.startsWith("did:key:") ? base58btc.decode(principal.slice("did:key:".length)) : new Uint8Array();
|
|
3642
|
+
if (didMaterial.length !== 34 || didMaterial[0] !== 237 || didMaterial[1] !== 1)
|
|
3643
|
+
throw new Error("compact UCAN signer must be did:key Ed25519");
|
|
3644
|
+
const header = { alg: "EdDSA", jwk: { alg: "EdDSA", crv: "Ed25519", kty: "OKP", x: encodeBase64Url(didMaterial.slice(2)) }, typ: "JWT", ucv: "0.10.0" };
|
|
3645
|
+
const payload = {
|
|
3646
|
+
att: input.attenuation,
|
|
3647
|
+
aud: input.audienceDid,
|
|
3648
|
+
exp: input.expiresAt,
|
|
3649
|
+
fct: input.facts,
|
|
3650
|
+
iss: input.issuerDid.includes("#") ? input.issuerDid : `${principal}#${principal.slice("did:key:".length)}`,
|
|
3651
|
+
nbf: input.notBefore,
|
|
3652
|
+
nnc: input.nonce,
|
|
3653
|
+
prf: input.proofs
|
|
3654
|
+
};
|
|
3655
|
+
const protectedSegment = encodeBase64Url(new TextEncoder().encode(jcsCanonicalize(header)));
|
|
3656
|
+
const payloadSegment = encodeBase64Url(new TextEncoder().encode(jcsCanonicalize(payload)));
|
|
3657
|
+
const signature = await input.sign(new TextEncoder().encode(`${protectedSegment}.${payloadSegment}`));
|
|
3658
|
+
if (signature.length !== 64) throw new Error("compact Authorization signature must be Ed25519");
|
|
3659
|
+
return parseCompactUcanAuthorization(`${protectedSegment}.${payloadSegment}.${encodeBase64Url(signature)}`);
|
|
3660
|
+
}
|
|
3661
|
+
function createCompactPolicyInvocation(input) {
|
|
3662
|
+
const session = parsePolicySessionUcan(input.sessionAuthorization);
|
|
3663
|
+
if (session.cid !== input.sessionCid || session.aud !== input.recipientDid)
|
|
3664
|
+
throw new Error("policy session does not bind the recipient signer");
|
|
3665
|
+
const principal = input.recipientDid.split("#", 1)[0];
|
|
3666
|
+
const didMaterial = base58btc.decode(principal.slice("did:key:".length));
|
|
3667
|
+
if (didMaterial.length !== 34 || didMaterial[0] !== 237 || didMaterial[1] !== 1)
|
|
3668
|
+
throw new Error("policy invocation signer must be did:key Ed25519");
|
|
3669
|
+
const publicKey = ed255192.getPublicKey(input.privateKey);
|
|
3670
|
+
if (!equalBytes(publicKey, didMaterial.slice(2)))
|
|
3671
|
+
throw new Error("policy invocation private key does not bind recipient DID");
|
|
3672
|
+
const now = input.now ?? Math.floor(Date.now() / 1e3);
|
|
3673
|
+
const exp = Math.min(now + 60, session.exp);
|
|
3674
|
+
if (exp <= now) throw new Error("policy session has expired");
|
|
3675
|
+
const header = { alg: "EdDSA", jwk: { alg: "EdDSA", crv: "Ed25519", kty: "OKP", x: encodeBase64Url(publicKey) }, typ: "JWT", ucv: "0.10.0" };
|
|
3676
|
+
const payload = {
|
|
3677
|
+
att: { [input.resource]: { [input.action]: [input.caveat ?? {}] } },
|
|
3678
|
+
aud: input.audienceDid,
|
|
3679
|
+
exp,
|
|
3680
|
+
fct: [input.facts ?? { type: "tinycloud.policy.invocation/v1", policyCid: session.fact.policyCid, sessionCid: session.cid }],
|
|
3681
|
+
iss: input.recipientDid.includes("#") ? input.recipientDid : `${principal}#${principal.slice("did:key:".length)}`,
|
|
3682
|
+
nbf: now,
|
|
3683
|
+
nnc: input.nonce ?? encodeBase64Url(crypto.getRandomValues(new Uint8Array(16))),
|
|
3684
|
+
prf: [session.cid]
|
|
3685
|
+
};
|
|
3686
|
+
const protectedSegment = encodeBase64Url(new TextEncoder().encode(jcsCanonicalize(header)));
|
|
3687
|
+
const payloadSegment = encodeBase64Url(new TextEncoder().encode(jcsCanonicalize(payload)));
|
|
3688
|
+
const signingInput = new TextEncoder().encode(`${protectedSegment}.${payloadSegment}`);
|
|
3689
|
+
const signature = ed255192.sign(signingInput, input.privateKey);
|
|
3690
|
+
return parseCompactUcanAuthorization(`${protectedSegment}.${payloadSegment}.${encodeBase64Url(signature)}`);
|
|
3691
|
+
}
|
|
3692
|
+
function createCompactPolicyDescendant(input) {
|
|
3693
|
+
const parent = parseCompactUcanAuthorization(input.parentAuthorization, input.parentCid);
|
|
3694
|
+
if (parent.payload.aud !== input.issuerDid) throw new Error("policy descendant issuer is not the parent audience");
|
|
3695
|
+
const parentFact = parent.payload.fct[0];
|
|
3696
|
+
const depth = parentFact.remainingRedelegationDepth;
|
|
3697
|
+
if (!Number.isInteger(depth) || depth <= 0) throw new Error("policy descendant depth is exhausted");
|
|
3698
|
+
if (!compactAttenuationContains(parent.payload.att, input.attenuation))
|
|
3699
|
+
throw new Error("policy descendant exceeds the parent attenuation");
|
|
3700
|
+
const principal = input.issuerDid.split("#", 1)[0];
|
|
3701
|
+
const didMaterial = base58btc.decode(principal.slice("did:key:".length));
|
|
3702
|
+
const publicKey = ed255192.getPublicKey(input.privateKey);
|
|
3703
|
+
if (didMaterial.length !== 34 || !equalBytes(publicKey, didMaterial.slice(2))) throw new Error("policy descendant signer does not bind issuer DID");
|
|
3704
|
+
const now = Math.max(input.now ?? Math.floor(Date.now() / 1e3), parent.payload.nbf + 1);
|
|
3705
|
+
const exp = Math.min(input.expiresAt ?? now + 60, now + 60, parent.payload.exp - 1);
|
|
3706
|
+
if (exp <= now) throw new Error("policy parent has no strictly narrower validity window");
|
|
3707
|
+
const header = { alg: "EdDSA", jwk: { alg: "EdDSA", crv: "Ed25519", kty: "OKP", x: encodeBase64Url(publicKey) }, typ: "JWT", ucv: "0.10.0" };
|
|
3708
|
+
const payload = {
|
|
3709
|
+
att: input.attenuation,
|
|
3710
|
+
aud: input.audienceDid,
|
|
3711
|
+
exp,
|
|
3712
|
+
fct: [{ ...parentFact, remainingRedelegationDepth: depth - 1 }],
|
|
3713
|
+
iss: input.issuerDid.includes("#") ? input.issuerDid : `${principal}#${principal.slice("did:key:".length)}`,
|
|
3714
|
+
nbf: now,
|
|
3715
|
+
nnc: input.nonce ?? encodeBase64Url(crypto.getRandomValues(new Uint8Array(16))),
|
|
3716
|
+
prf: [parent.cid]
|
|
3717
|
+
};
|
|
3718
|
+
const protectedSegment = encodeBase64Url(new TextEncoder().encode(jcsCanonicalize(header)));
|
|
3719
|
+
const payloadSegment = encodeBase64Url(new TextEncoder().encode(jcsCanonicalize(payload)));
|
|
3720
|
+
const signature = ed255192.sign(new TextEncoder().encode(`${protectedSegment}.${payloadSegment}`), input.privateKey);
|
|
3721
|
+
return parseCompactUcanAuthorization(`${protectedSegment}.${payloadSegment}.${encodeBase64Url(signature)}`);
|
|
3722
|
+
}
|
|
3723
|
+
function compactAttenuationContains(parent, child) {
|
|
3724
|
+
const selector = (value) => {
|
|
3725
|
+
if (value.length !== 1 || !isRecordValue(value[0])) return void 0;
|
|
3726
|
+
const caveat = value[0];
|
|
3727
|
+
if (Object.keys(caveat).length !== 3 || caveat.type !== "xyz.tinycloud.resource/selector" || caveat.kind !== "exact" && caveat.kind !== "prefix" || typeof caveat.value !== "string") return void 0;
|
|
3728
|
+
return { kind: caveat.kind, value: caveat.value };
|
|
3729
|
+
};
|
|
3730
|
+
const equal = (left, right) => jcsCanonicalize(left) === jcsCanonicalize(right);
|
|
3731
|
+
return Object.entries(child).every(
|
|
3732
|
+
([childResource, childActions]) => Object.entries(childActions).every(
|
|
3733
|
+
([action, childCaveats]) => Object.entries(parent).some(([parentResource, parentActions]) => {
|
|
3734
|
+
const parentCaveats = parentActions[action];
|
|
3735
|
+
if (parentCaveats === void 0) return false;
|
|
3736
|
+
if (parentResource === childResource && equal(parentCaveats, childCaveats)) return true;
|
|
3737
|
+
const parentSelector = selector(parentCaveats);
|
|
3738
|
+
const childSelector = selector(childCaveats);
|
|
3739
|
+
return parentSelector?.kind === "prefix" && childSelector !== void 0 && parentSelector.value === parentResource && childSelector.value === childResource && (childResource === parentResource || childResource.startsWith(`${parentResource}/`));
|
|
3740
|
+
})
|
|
3741
|
+
)
|
|
3742
|
+
);
|
|
3743
|
+
}
|
|
3744
|
+
function isRecordValue(value) {
|
|
3745
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3746
|
+
}
|
|
3747
|
+
function parseCompactUcanAuthorization(input, expectedCid) {
|
|
3748
|
+
if (typeof input !== "string" || /\s/.test(input))
|
|
3749
|
+
throw new Error("Authorization must be compact UCAN bytes");
|
|
3750
|
+
const segments = input.split(".");
|
|
3751
|
+
if (segments.length !== 3 || segments.some((segment) => segment.length === 0))
|
|
3752
|
+
throw new Error("Authorization must have three compact segments");
|
|
3753
|
+
const [headerSegment, payloadSegment, signatureSegment] = segments;
|
|
3754
|
+
const headerBytes = decodeBase64Url(headerSegment);
|
|
3755
|
+
const payloadBytes = decodeBase64Url(payloadSegment);
|
|
3756
|
+
const signature = decodeBase64Url(signatureSegment);
|
|
3757
|
+
const headerValue = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(headerBytes));
|
|
3758
|
+
const payloadValue = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(payloadBytes));
|
|
3759
|
+
if (jcsCanonicalize(headerValue) !== new TextDecoder().decode(headerBytes) || jcsCanonicalize(payloadValue) !== new TextDecoder().decode(payloadBytes))
|
|
3760
|
+
throw new Error("compact UCAN segments are not canonical JCS");
|
|
3761
|
+
const header = CompactHeaderSchema.parse(headerValue);
|
|
3762
|
+
const payload = CompactPayloadSchema.parse(payloadValue);
|
|
3763
|
+
if (payload.nbf >= payload.exp) throw new Error("compact UCAN validity is empty");
|
|
3764
|
+
const principal = payload.iss.split("#", 1)[0];
|
|
3765
|
+
const didMaterial = principal.startsWith("did:key:") ? base58btc.decode(principal.slice("did:key:".length)) : new Uint8Array();
|
|
3766
|
+
if (didMaterial.length !== 34 || didMaterial[0] !== 237 || didMaterial[1] !== 1)
|
|
3767
|
+
throw new Error("compact UCAN issuer must be did:key Ed25519");
|
|
3768
|
+
const publicKey = didMaterial.slice(2);
|
|
3769
|
+
if (!equalBytes(publicKey, decodeBase64Url(header.jwk.x)))
|
|
3770
|
+
throw new Error("compact UCAN JWK does not bind issuer");
|
|
3771
|
+
if (!ed255192.verify(signature, new TextEncoder().encode(`${headerSegment}.${payloadSegment}`), publicKey))
|
|
3772
|
+
throw new Error("compact UCAN signature is invalid");
|
|
3773
|
+
const cid = CID.createV1(85, create(30, blake3(new TextEncoder().encode(input)))).toString();
|
|
3774
|
+
if (expectedCid !== void 0 && cid !== expectedCid)
|
|
3775
|
+
throw new Error("compact UCAN CID does not match exact Authorization bytes");
|
|
3776
|
+
return { authorization: input, cid, header, payload };
|
|
3777
|
+
}
|
|
3778
|
+
function parsePolicySessionUcan(authorization, expectedProofs) {
|
|
3779
|
+
const parsed = parseCompactUcanAuthorization(authorization);
|
|
3780
|
+
const fact = parsed.payload.fct[0];
|
|
3781
|
+
if (parsed.payload.prf.length !== 2 || parsed.payload.prf[0] === parsed.payload.prf[1])
|
|
3782
|
+
throw new Error("policy session UCAN requires two distinct ordered proofs");
|
|
3783
|
+
if (expectedProofs !== void 0 && (parsed.payload.prf[0] !== expectedProofs[0] || parsed.payload.prf[1] !== expectedProofs[1]))
|
|
3784
|
+
throw new Error("policy session UCAN ordered proofs do not match");
|
|
3785
|
+
const factKeys = Object.keys(fact);
|
|
3786
|
+
if (factKeys.length !== POLICY_SESSION_FACT_KEYS.length || factKeys.some((key) => !POLICY_SESSION_FACT_KEYS.includes(key)) || POLICY_SESSION_FACT_KEYS.some((key) => !(key in fact)))
|
|
3787
|
+
throw new Error("policy session UCAN fact is incomplete");
|
|
3788
|
+
if (fact.profile !== POLICY_SESSION_UCAN_V1_PROFILE || typeof fact.remainingRedelegationDepth !== "number" || !Number.isInteger(fact.remainingRedelegationDepth) || fact.remainingRedelegationDepth < 0 || fact.remainingRedelegationDepth > 8 || parsed.payload.exp - parsed.payload.nbf > 60 || parsed.payload.iss.split("#", 1)[0] !== fact.enforcerDid || parsed.payload.aud !== fact.recipientDid)
|
|
3789
|
+
throw new Error("policy session UCAN fact is invalid");
|
|
3790
|
+
return {
|
|
3791
|
+
authorization,
|
|
3792
|
+
cid: parsed.cid,
|
|
3793
|
+
iss: parsed.payload.iss,
|
|
3794
|
+
aud: parsed.payload.aud,
|
|
3795
|
+
prf: parsed.payload.prf,
|
|
3796
|
+
att: parsed.payload.att,
|
|
3797
|
+
nbf: parsed.payload.nbf,
|
|
3798
|
+
exp: parsed.payload.exp,
|
|
3799
|
+
nnc: parsed.payload.nnc,
|
|
3800
|
+
fact
|
|
3801
|
+
};
|
|
3802
|
+
}
|
|
3803
|
+
function decodeBase64Url(value) {
|
|
3804
|
+
if (!/^[A-Za-z0-9_-]+$/.test(value) || value.length % 4 === 1)
|
|
3805
|
+
throw new Error("value is not canonical base64url");
|
|
3806
|
+
const normalized = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
3807
|
+
const binary = typeof Buffer !== "undefined" ? Buffer.from(normalized, "base64").toString("binary") : atob(normalized.padEnd(Math.ceil(normalized.length / 4) * 4, "="));
|
|
3808
|
+
const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));
|
|
3809
|
+
const encoded = typeof Buffer !== "undefined" ? Buffer.from(bytes).toString("base64url") : btoa(String.fromCharCode(...bytes)).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
3810
|
+
if (encoded !== value) throw new Error("value is not canonical base64url");
|
|
3811
|
+
return bytes;
|
|
3812
|
+
}
|
|
3813
|
+
function encodeBase64Url(value) {
|
|
3814
|
+
return typeof Buffer !== "undefined" ? Buffer.from(value).toString("base64url") : btoa(String.fromCharCode(...value)).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
3815
|
+
}
|
|
3816
|
+
function equalBytes(left, right) {
|
|
3817
|
+
return left.length === right.length && left.every((byte, index) => byte === right[index]);
|
|
3818
|
+
}
|
|
3819
|
+
function hex(bytes) {
|
|
3820
|
+
return [...bytes].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
3821
|
+
}
|
|
3822
|
+
function base32Lower(bytes) {
|
|
3823
|
+
const alphabet2 = "abcdefghijklmnopqrstuvwxyz234567";
|
|
3824
|
+
let output = "";
|
|
3825
|
+
let buffer = 0;
|
|
3826
|
+
let bits = 0;
|
|
3827
|
+
for (const byte of bytes) {
|
|
3828
|
+
buffer = buffer << 8 | byte;
|
|
3829
|
+
bits += 8;
|
|
3830
|
+
while (bits >= 5) {
|
|
3831
|
+
output += alphabet2[buffer >>> bits - 5 & 31];
|
|
3832
|
+
bits -= 5;
|
|
3833
|
+
}
|
|
3834
|
+
}
|
|
3835
|
+
if (bits > 0) output += alphabet2[buffer << 5 - bits & 31];
|
|
3836
|
+
return output;
|
|
3185
3837
|
}
|
|
3186
3838
|
export {
|
|
3839
|
+
ATTESTED_ENFORCER_BINDING_V2_SCHEMA,
|
|
3840
|
+
CONTENT_SOURCE_V1_DOMAIN,
|
|
3187
3841
|
ED25519_JCS_SIGNATURE_SUITE,
|
|
3188
3842
|
EIP191_JCS_SIGNATURE_SUITE,
|
|
3843
|
+
LAST_V2_CREATE_AT,
|
|
3844
|
+
LAST_V2_READ_AT,
|
|
3845
|
+
MAX_LEGACY_ENVELOPE_EXPIRES_AT,
|
|
3846
|
+
NATIVE_PROJECTION_V1_DOMAIN,
|
|
3189
3847
|
OWNER_NODE_ENDPOINT_SCHEMA,
|
|
3848
|
+
POLICY_CAPABILITY_V1_DOMAIN,
|
|
3849
|
+
POLICY_CAPABILITY_V1_SCHEMA,
|
|
3850
|
+
POLICY_ENFORCEMENT_DELEGATION_V2_SCHEMA,
|
|
3190
3851
|
POLICY_ENGINE_RECORD_SCHEMA,
|
|
3191
3852
|
POLICY_SCHEMA,
|
|
3853
|
+
POLICY_SESSION_UCAN_V1_PROFILE,
|
|
3192
3854
|
POLICY_STATUS_SCHEMA,
|
|
3855
|
+
POLICY_V1_DOMAIN,
|
|
3856
|
+
POLICY_V1_SCHEMA,
|
|
3193
3857
|
POLICY_VERSION_V0,
|
|
3194
3858
|
PolicyAuthoringError,
|
|
3195
3859
|
PolicyCapabilityError,
|
|
3860
|
+
ROOT_REVOCATION_V1_DOMAIN,
|
|
3861
|
+
ROOT_REVOCATION_V1_SCHEMA,
|
|
3862
|
+
ROOT_STATUS_CHECKPOINT_V1_SCHEMA,
|
|
3863
|
+
ROOT_STATUS_RENEWAL_V1_DOMAIN,
|
|
3864
|
+
ROOT_STATUS_V1_DOMAIN,
|
|
3196
3865
|
SignatureMaterialError,
|
|
3197
3866
|
SignatureVerificationError,
|
|
3198
3867
|
SignedObjectCanonicalizationError,
|
|
@@ -3206,23 +3875,46 @@ export {
|
|
|
3206
3875
|
W3C_VC_CREDENTIAL_VERIFIER,
|
|
3207
3876
|
canonicalizePolicyCapability,
|
|
3208
3877
|
canonicalizeSignedObjectUnsigned,
|
|
3878
|
+
canonicalizeUnifiedPolicyCapability,
|
|
3879
|
+
compactAttenuationContains,
|
|
3209
3880
|
composeTranscriptShareBootstrap,
|
|
3881
|
+
contentSourceDigestHex,
|
|
3210
3882
|
createAndSignPolicy,
|
|
3211
3883
|
createAndSignPolicyEngineRecord,
|
|
3212
3884
|
createAndSignPolicyStatus,
|
|
3213
3885
|
createAndSignRequesterPolicyEngineRecord,
|
|
3214
3886
|
createAndSignSignedObject,
|
|
3215
3887
|
createAndSignTranscriptSharePolicy,
|
|
3888
|
+
createCompactPolicyDescendant,
|
|
3889
|
+
createCompactPolicyInvocation,
|
|
3216
3890
|
createUnsignedPolicyEngineRecord,
|
|
3217
3891
|
deriveSignedObjectMaterial,
|
|
3892
|
+
getPolicyRootStatusV3,
|
|
3218
3893
|
jcsCanonicalize,
|
|
3894
|
+
mintPolicySessionV3,
|
|
3219
3895
|
normalizeJson,
|
|
3220
3896
|
normalizePolicyCapability,
|
|
3897
|
+
normalizeUnifiedPolicyCapability,
|
|
3898
|
+
parseCompactUcanAuthorization,
|
|
3899
|
+
parsePolicySessionUcan,
|
|
3221
3900
|
policyCapabilityContains,
|
|
3222
3901
|
policyCapabilityDigestHex,
|
|
3902
|
+
policyCidFromCanonicalBytes,
|
|
3903
|
+
policyDigestHex,
|
|
3904
|
+
policyIdForDigestHex,
|
|
3905
|
+
projectUnifiedPolicyCapabilities,
|
|
3906
|
+
projectUnifiedPolicyCapability,
|
|
3907
|
+
renewPolicyRootStatusV3,
|
|
3908
|
+
requestPolicyChallengeV3,
|
|
3909
|
+
revokePolicyRootV3,
|
|
3223
3910
|
serialize as serializeJcsJson,
|
|
3911
|
+
signCompactUcanAuthorization,
|
|
3224
3912
|
signedObjectIdFor,
|
|
3225
3913
|
toSignedObjectError,
|
|
3914
|
+
unifiedNativeProjectionHashHex,
|
|
3915
|
+
unifiedPolicyCapabilityContains,
|
|
3916
|
+
unifiedPolicyCapabilityDigestHex,
|
|
3917
|
+
unifiedPolicyCapabilityFromNative,
|
|
3226
3918
|
validatePolicyEngineRecordSigned,
|
|
3227
3919
|
validatePolicyEngineRecordSignedShape,
|
|
3228
3920
|
validatePolicyEngineRecordUnsigned,
|
|
@@ -3235,6 +3927,8 @@ export {
|
|
|
3235
3927
|
verifyPolicy,
|
|
3236
3928
|
verifyPolicyEngineRecord,
|
|
3237
3929
|
verifyPolicyEngineRecordForRequester,
|
|
3930
|
+
verifyPolicyRootRevocationV3,
|
|
3931
|
+
verifyPolicyRootStatusCheckpointV3,
|
|
3238
3932
|
verifyPolicyStatus,
|
|
3239
3933
|
verifySignedObject
|
|
3240
3934
|
};
|