@tinycloud/sdk-core 2.11.0-beta.10 → 2.11.0-beta.11
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/delegations/index.cjs +620 -221
- package/dist/delegations/index.cjs.map +1 -1
- package/dist/delegations/index.d.cts +8 -8
- package/dist/delegations/index.d.ts +8 -8
- package/dist/delegations/index.js +621 -222
- package/dist/delegations/index.js.map +1 -1
- package/dist/index.cjs +1576 -762
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -14
- package/dist/index.d.ts +14 -14
- package/dist/index.js +1548 -732
- package/dist/index.js.map +1 -1
- package/dist/policy/index.cjs +867 -175
- 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 +867 -175
- package/dist/policy/index.js.map +1 -1
- package/dist/{recipient-types.schema-D5pDlIqn.d.cts → recipient-types.schema-CuDpskPd.d.cts} +172 -115
- package/dist/{recipient-types.schema-D5pDlIqn.d.ts → recipient-types.schema-CuDpskPd.d.ts} +172 -115
- package/dist/unified-BYPfXp5S.d.ts +429 -0
- package/dist/unified-BdfNHNrx.d.cts +429 -0
- package/package.json +4 -4
- package/dist/signed-object-C6mWbTbB.d.ts +0 -149
- package/dist/signed-object-IMAm5a32.d.cts +0 -149
package/dist/policy/index.cjs
CHANGED
|
@@ -22,15 +22,32 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
22
22
|
// src/policy/index.ts
|
|
23
23
|
var policy_exports = {};
|
|
24
24
|
__export(policy_exports, {
|
|
25
|
+
ATTESTED_ENFORCER_BINDING_V2_SCHEMA: () => ATTESTED_ENFORCER_BINDING_V2_SCHEMA,
|
|
26
|
+
CONTENT_SOURCE_V1_DOMAIN: () => CONTENT_SOURCE_V1_DOMAIN,
|
|
25
27
|
ED25519_JCS_SIGNATURE_SUITE: () => ED25519_JCS_SIGNATURE_SUITE,
|
|
26
28
|
EIP191_JCS_SIGNATURE_SUITE: () => EIP191_JCS_SIGNATURE_SUITE,
|
|
29
|
+
LAST_V2_CREATE_AT: () => LAST_V2_CREATE_AT,
|
|
30
|
+
LAST_V2_READ_AT: () => LAST_V2_READ_AT,
|
|
31
|
+
MAX_LEGACY_ENVELOPE_EXPIRES_AT: () => MAX_LEGACY_ENVELOPE_EXPIRES_AT,
|
|
32
|
+
NATIVE_PROJECTION_V1_DOMAIN: () => NATIVE_PROJECTION_V1_DOMAIN,
|
|
27
33
|
OWNER_NODE_ENDPOINT_SCHEMA: () => OWNER_NODE_ENDPOINT_SCHEMA,
|
|
34
|
+
POLICY_CAPABILITY_V1_DOMAIN: () => POLICY_CAPABILITY_V1_DOMAIN,
|
|
35
|
+
POLICY_CAPABILITY_V1_SCHEMA: () => POLICY_CAPABILITY_V1_SCHEMA,
|
|
36
|
+
POLICY_ENFORCEMENT_DELEGATION_V2_SCHEMA: () => POLICY_ENFORCEMENT_DELEGATION_V2_SCHEMA,
|
|
28
37
|
POLICY_ENGINE_RECORD_SCHEMA: () => POLICY_ENGINE_RECORD_SCHEMA,
|
|
29
38
|
POLICY_SCHEMA: () => POLICY_SCHEMA,
|
|
39
|
+
POLICY_SESSION_UCAN_V1_PROFILE: () => POLICY_SESSION_UCAN_V1_PROFILE,
|
|
30
40
|
POLICY_STATUS_SCHEMA: () => POLICY_STATUS_SCHEMA,
|
|
41
|
+
POLICY_V1_DOMAIN: () => POLICY_V1_DOMAIN,
|
|
42
|
+
POLICY_V1_SCHEMA: () => POLICY_V1_SCHEMA,
|
|
31
43
|
POLICY_VERSION_V0: () => POLICY_VERSION_V0,
|
|
32
44
|
PolicyAuthoringError: () => PolicyAuthoringError,
|
|
33
45
|
PolicyCapabilityError: () => PolicyCapabilityError,
|
|
46
|
+
ROOT_REVOCATION_V1_DOMAIN: () => ROOT_REVOCATION_V1_DOMAIN,
|
|
47
|
+
ROOT_REVOCATION_V1_SCHEMA: () => ROOT_REVOCATION_V1_SCHEMA,
|
|
48
|
+
ROOT_STATUS_CHECKPOINT_V1_SCHEMA: () => ROOT_STATUS_CHECKPOINT_V1_SCHEMA,
|
|
49
|
+
ROOT_STATUS_RENEWAL_V1_DOMAIN: () => ROOT_STATUS_RENEWAL_V1_DOMAIN,
|
|
50
|
+
ROOT_STATUS_V1_DOMAIN: () => ROOT_STATUS_V1_DOMAIN,
|
|
34
51
|
SignatureMaterialError: () => SignatureMaterialError,
|
|
35
52
|
SignatureVerificationError: () => SignatureVerificationError,
|
|
36
53
|
SignedObjectCanonicalizationError: () => SignedObjectCanonicalizationError,
|
|
@@ -44,23 +61,46 @@ __export(policy_exports, {
|
|
|
44
61
|
W3C_VC_CREDENTIAL_VERIFIER: () => W3C_VC_CREDENTIAL_VERIFIER,
|
|
45
62
|
canonicalizePolicyCapability: () => canonicalizePolicyCapability,
|
|
46
63
|
canonicalizeSignedObjectUnsigned: () => canonicalizeSignedObjectUnsigned,
|
|
64
|
+
canonicalizeUnifiedPolicyCapability: () => canonicalizeUnifiedPolicyCapability,
|
|
65
|
+
compactAttenuationContains: () => compactAttenuationContains,
|
|
47
66
|
composeTranscriptShareBootstrap: () => composeTranscriptShareBootstrap,
|
|
67
|
+
contentSourceDigestHex: () => contentSourceDigestHex,
|
|
48
68
|
createAndSignPolicy: () => createAndSignPolicy,
|
|
49
69
|
createAndSignPolicyEngineRecord: () => createAndSignPolicyEngineRecord,
|
|
50
70
|
createAndSignPolicyStatus: () => createAndSignPolicyStatus,
|
|
51
71
|
createAndSignRequesterPolicyEngineRecord: () => createAndSignRequesterPolicyEngineRecord,
|
|
52
72
|
createAndSignSignedObject: () => createAndSignSignedObject,
|
|
53
73
|
createAndSignTranscriptSharePolicy: () => createAndSignTranscriptSharePolicy,
|
|
74
|
+
createCompactPolicyDescendant: () => createCompactPolicyDescendant,
|
|
75
|
+
createCompactPolicyInvocation: () => createCompactPolicyInvocation,
|
|
54
76
|
createUnsignedPolicyEngineRecord: () => createUnsignedPolicyEngineRecord,
|
|
55
77
|
deriveSignedObjectMaterial: () => deriveSignedObjectMaterial,
|
|
78
|
+
getPolicyRootStatusV3: () => getPolicyRootStatusV3,
|
|
56
79
|
jcsCanonicalize: () => jcsCanonicalize,
|
|
80
|
+
mintPolicySessionV3: () => mintPolicySessionV3,
|
|
57
81
|
normalizeJson: () => normalizeJson,
|
|
58
82
|
normalizePolicyCapability: () => normalizePolicyCapability,
|
|
83
|
+
normalizeUnifiedPolicyCapability: () => normalizeUnifiedPolicyCapability,
|
|
84
|
+
parseCompactUcanAuthorization: () => parseCompactUcanAuthorization,
|
|
85
|
+
parsePolicySessionUcan: () => parsePolicySessionUcan,
|
|
59
86
|
policyCapabilityContains: () => policyCapabilityContains,
|
|
60
87
|
policyCapabilityDigestHex: () => policyCapabilityDigestHex,
|
|
88
|
+
policyCidFromCanonicalBytes: () => policyCidFromCanonicalBytes,
|
|
89
|
+
policyDigestHex: () => policyDigestHex,
|
|
90
|
+
policyIdForDigestHex: () => policyIdForDigestHex,
|
|
91
|
+
projectUnifiedPolicyCapabilities: () => projectUnifiedPolicyCapabilities,
|
|
92
|
+
projectUnifiedPolicyCapability: () => projectUnifiedPolicyCapability,
|
|
93
|
+
renewPolicyRootStatusV3: () => renewPolicyRootStatusV3,
|
|
94
|
+
requestPolicyChallengeV3: () => requestPolicyChallengeV3,
|
|
95
|
+
revokePolicyRootV3: () => revokePolicyRootV3,
|
|
61
96
|
serializeJcsJson: () => serialize,
|
|
97
|
+
signCompactUcanAuthorization: () => signCompactUcanAuthorization,
|
|
62
98
|
signedObjectIdFor: () => signedObjectIdFor,
|
|
63
99
|
toSignedObjectError: () => toSignedObjectError,
|
|
100
|
+
unifiedNativeProjectionHashHex: () => unifiedNativeProjectionHashHex,
|
|
101
|
+
unifiedPolicyCapabilityContains: () => unifiedPolicyCapabilityContains,
|
|
102
|
+
unifiedPolicyCapabilityDigestHex: () => unifiedPolicyCapabilityDigestHex,
|
|
103
|
+
unifiedPolicyCapabilityFromNative: () => unifiedPolicyCapabilityFromNative,
|
|
64
104
|
validatePolicyEngineRecordSigned: () => validatePolicyEngineRecordSigned,
|
|
65
105
|
validatePolicyEngineRecordSignedShape: () => validatePolicyEngineRecordSignedShape,
|
|
66
106
|
validatePolicyEngineRecordUnsigned: () => validatePolicyEngineRecordUnsigned,
|
|
@@ -73,6 +113,8 @@ __export(policy_exports, {
|
|
|
73
113
|
verifyPolicy: () => verifyPolicy,
|
|
74
114
|
verifyPolicyEngineRecord: () => verifyPolicyEngineRecord,
|
|
75
115
|
verifyPolicyEngineRecordForRequester: () => verifyPolicyEngineRecordForRequester,
|
|
116
|
+
verifyPolicyRootRevocationV3: () => verifyPolicyRootRevocationV3,
|
|
117
|
+
verifyPolicyRootStatusCheckpointV3: () => verifyPolicyRootStatusCheckpointV3,
|
|
76
118
|
verifyPolicyStatus: () => verifyPolicyStatus,
|
|
77
119
|
verifySignedObject: () => verifySignedObject
|
|
78
120
|
});
|
|
@@ -395,16 +437,16 @@ function policyCapabilityContains(authority, request) {
|
|
|
395
437
|
return caveatsContain(auth.caveats, req.caveats);
|
|
396
438
|
}
|
|
397
439
|
function normalizePolicyCapabilityWithOptions(input, options) {
|
|
398
|
-
const
|
|
399
|
-
assertExactKeys(
|
|
400
|
-
const service = requiredString(
|
|
440
|
+
const object2 = expectObject(input, "$");
|
|
441
|
+
assertExactKeys(object2, ["service", "space", "path", "actions", "caveats"], "$");
|
|
442
|
+
const service = requiredString(object2, "service", "$", "policy-capability-malformed-service");
|
|
401
443
|
if (!CEILING_SERVICES.has(service)) {
|
|
402
444
|
throw new PolicyCapabilityError(
|
|
403
445
|
"policy-capability-malformed-service",
|
|
404
446
|
"$.service is outside the frozen permissionsCeiling vocabulary"
|
|
405
447
|
);
|
|
406
448
|
}
|
|
407
|
-
const space = requiredString(
|
|
449
|
+
const space = requiredString(object2, "space", "$", "policy-capability-malformed-space");
|
|
408
450
|
validateConcreteSpace(space);
|
|
409
451
|
const canonicalSpace = space.normalize("NFC");
|
|
410
452
|
if (options.requireCanonical && canonicalSpace !== space) {
|
|
@@ -413,7 +455,7 @@ function normalizePolicyCapabilityWithOptions(input, options) {
|
|
|
413
455
|
"$.space must already be canonical NFC"
|
|
414
456
|
);
|
|
415
457
|
}
|
|
416
|
-
const rawPath = requiredString(
|
|
458
|
+
const rawPath = requiredString(object2, "path", "$", "policy-capability-malformed-path");
|
|
417
459
|
validateRawPath(rawPath, options);
|
|
418
460
|
const path = normalizePath(rawPath);
|
|
419
461
|
if (options.requireCanonical && path !== rawPath) {
|
|
@@ -424,7 +466,7 @@ function normalizePolicyCapabilityWithOptions(input, options) {
|
|
|
424
466
|
}
|
|
425
467
|
validateRawPath(path, options);
|
|
426
468
|
const actions = normalizeActions(
|
|
427
|
-
requiredArray(
|
|
469
|
+
requiredArray(object2, "actions", "$", "policy-capability-malformed-action"),
|
|
428
470
|
service,
|
|
429
471
|
options
|
|
430
472
|
);
|
|
@@ -433,9 +475,9 @@ function normalizePolicyCapabilityWithOptions(input, options) {
|
|
|
433
475
|
output.space = canonicalSpace;
|
|
434
476
|
output.path = path;
|
|
435
477
|
output.actions = actions;
|
|
436
|
-
if (hasOwn(
|
|
478
|
+
if (hasOwn(object2, "caveats")) {
|
|
437
479
|
output.caveats = validateCaveats(
|
|
438
|
-
requiredValue(
|
|
480
|
+
requiredValue(object2, "caveats", "$", "policy-capability-malformed-caveats"),
|
|
439
481
|
output.service
|
|
440
482
|
);
|
|
441
483
|
}
|
|
@@ -458,9 +500,9 @@ function expectObject(input, path) {
|
|
|
458
500
|
);
|
|
459
501
|
}
|
|
460
502
|
}
|
|
461
|
-
function assertExactKeys(
|
|
503
|
+
function assertExactKeys(object2, allowed, path) {
|
|
462
504
|
const allowedSet = new Set(allowed);
|
|
463
|
-
for (const key of Object.keys(
|
|
505
|
+
for (const key of Object.keys(object2)) {
|
|
464
506
|
if (!allowedSet.has(key)) {
|
|
465
507
|
throw new PolicyCapabilityError(
|
|
466
508
|
key === "id" || key === "scope" ? "policy-capability-malformed" : "policy-capability-unknown-key",
|
|
@@ -469,21 +511,21 @@ function assertExactKeys(object, allowed, path) {
|
|
|
469
511
|
}
|
|
470
512
|
}
|
|
471
513
|
}
|
|
472
|
-
function requiredValue(
|
|
473
|
-
if (!hasOwn(
|
|
514
|
+
function requiredValue(object2, key, path, code2) {
|
|
515
|
+
if (!hasOwn(object2, key)) {
|
|
474
516
|
throw new PolicyCapabilityError(code2, `${path}.${key} is required`);
|
|
475
517
|
}
|
|
476
|
-
return
|
|
518
|
+
return object2[key];
|
|
477
519
|
}
|
|
478
|
-
function requiredString(
|
|
479
|
-
const value = requiredValue(
|
|
520
|
+
function requiredString(object2, key, path, code2) {
|
|
521
|
+
const value = requiredValue(object2, key, path, code2);
|
|
480
522
|
if (typeof value !== "string" || value.length === 0) {
|
|
481
523
|
throw new PolicyCapabilityError(code2, `${path}.${key} must be a non-empty string`);
|
|
482
524
|
}
|
|
483
525
|
return value;
|
|
484
526
|
}
|
|
485
|
-
function requiredArray(
|
|
486
|
-
const value = requiredValue(
|
|
527
|
+
function requiredArray(object2, key, path, code2) {
|
|
528
|
+
const value = requiredValue(object2, key, path, code2);
|
|
487
529
|
if (!Array.isArray(value)) {
|
|
488
530
|
throw new PolicyCapabilityError(code2, `${path}.${key} must be an array`);
|
|
489
531
|
}
|
|
@@ -628,11 +670,11 @@ function validateSqlStatement(input, path) {
|
|
|
628
670
|
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
629
671
|
throw new PolicyCapabilityError("policy-capability-malformed-caveats", `${path} must be an object`);
|
|
630
672
|
}
|
|
631
|
-
const
|
|
632
|
-
assertCaveatKeys(
|
|
633
|
-
caveatString(
|
|
634
|
-
caveatString(
|
|
635
|
-
const fixedParams = requiredCaveat(
|
|
673
|
+
const object2 = input;
|
|
674
|
+
assertCaveatKeys(object2, ["name", "sql", "fixedParams"], path);
|
|
675
|
+
caveatString(object2, "name", path);
|
|
676
|
+
caveatString(object2, "sql", path);
|
|
677
|
+
const fixedParams = requiredCaveat(object2, "fixedParams", path);
|
|
636
678
|
if (!Array.isArray(fixedParams)) {
|
|
637
679
|
throw new PolicyCapabilityError(
|
|
638
680
|
"policy-capability-malformed-caveats",
|
|
@@ -647,20 +689,20 @@ function validateFixedParam(input, path) {
|
|
|
647
689
|
if (input === null || typeof input !== "object" || Array.isArray(input)) {
|
|
648
690
|
throw new PolicyCapabilityError("policy-capability-malformed-caveats", `${path} must be an object`);
|
|
649
691
|
}
|
|
650
|
-
const
|
|
651
|
-
assertCaveatKeys(
|
|
652
|
-
const index = requiredCaveat(
|
|
692
|
+
const object2 = input;
|
|
693
|
+
assertCaveatKeys(object2, ["index", "value"], path);
|
|
694
|
+
const index = requiredCaveat(object2, "index", path);
|
|
653
695
|
if (typeof index !== "number" || !Number.isSafeInteger(index) || index < 0) {
|
|
654
696
|
throw new PolicyCapabilityError(
|
|
655
697
|
"policy-capability-malformed-caveats",
|
|
656
698
|
`${path}.index must be a non-negative integer`
|
|
657
699
|
);
|
|
658
700
|
}
|
|
659
|
-
requiredCaveat(
|
|
701
|
+
requiredCaveat(object2, "value", path);
|
|
660
702
|
}
|
|
661
|
-
function assertCaveatKeys(
|
|
703
|
+
function assertCaveatKeys(object2, allowed, path) {
|
|
662
704
|
const allowedSet = new Set(allowed);
|
|
663
|
-
for (const key of Object.keys(
|
|
705
|
+
for (const key of Object.keys(object2)) {
|
|
664
706
|
if (!allowedSet.has(key)) {
|
|
665
707
|
throw new PolicyCapabilityError(
|
|
666
708
|
"policy-capability-malformed-caveats",
|
|
@@ -669,17 +711,17 @@ function assertCaveatKeys(object, allowed, path) {
|
|
|
669
711
|
}
|
|
670
712
|
}
|
|
671
713
|
}
|
|
672
|
-
function requiredCaveat(
|
|
673
|
-
if (!hasOwn(
|
|
714
|
+
function requiredCaveat(object2, key, path) {
|
|
715
|
+
if (!hasOwn(object2, key)) {
|
|
674
716
|
throw new PolicyCapabilityError(
|
|
675
717
|
"policy-capability-malformed-caveats",
|
|
676
718
|
`${path}.${key} is required`
|
|
677
719
|
);
|
|
678
720
|
}
|
|
679
|
-
return
|
|
721
|
+
return object2[key];
|
|
680
722
|
}
|
|
681
|
-
function caveatString(
|
|
682
|
-
const value = requiredCaveat(
|
|
723
|
+
function caveatString(object2, key, path) {
|
|
724
|
+
const value = requiredCaveat(object2, key, path);
|
|
683
725
|
if (typeof value !== "string" || value.length === 0) {
|
|
684
726
|
throw new PolicyCapabilityError(
|
|
685
727
|
"policy-capability-malformed-caveats",
|
|
@@ -710,8 +752,8 @@ function caveatsContain(authority, request) {
|
|
|
710
752
|
(statement) => authorityStatements.some((candidate) => jcsCanonicalize(candidate) === jcsCanonicalize(statement))
|
|
711
753
|
);
|
|
712
754
|
}
|
|
713
|
-
function hasOwn(
|
|
714
|
-
return objectHasOwn2(
|
|
755
|
+
function hasOwn(object2, key) {
|
|
756
|
+
return objectHasOwn2(object2, key);
|
|
715
757
|
}
|
|
716
758
|
|
|
717
759
|
// src/policy/signed-object.ts
|
|
@@ -1981,17 +2023,17 @@ async function createAndSignSignedObject(input, signer) {
|
|
|
1981
2023
|
}
|
|
1982
2024
|
function createAndSignPolicy(input, signer) {
|
|
1983
2025
|
return createAndSignSignedObject(input, signer).then(
|
|
1984
|
-
(
|
|
2026
|
+
(object2) => validatePolicySignedShape(object2)
|
|
1985
2027
|
);
|
|
1986
2028
|
}
|
|
1987
2029
|
function createAndSignPolicyStatus(input, signer) {
|
|
1988
2030
|
return createAndSignSignedObject(input, signer).then(
|
|
1989
|
-
(
|
|
2031
|
+
(object2) => validatePolicyStatusSignedShape(object2)
|
|
1990
2032
|
);
|
|
1991
2033
|
}
|
|
1992
2034
|
function createAndSignPolicyEngineRecord(input, signer) {
|
|
1993
2035
|
return createAndSignSignedObject(input, signer).then(
|
|
1994
|
-
(
|
|
2036
|
+
(object2) => validatePolicyEngineRecordSignedShape(object2)
|
|
1995
2037
|
);
|
|
1996
2038
|
}
|
|
1997
2039
|
async function verifySignedObject(input) {
|
|
@@ -2095,9 +2137,9 @@ function validateUnsignedForDescriptor(input, descriptor) {
|
|
|
2095
2137
|
}
|
|
2096
2138
|
}
|
|
2097
2139
|
function validatePolicyShape(input, signed) {
|
|
2098
|
-
const
|
|
2140
|
+
const object2 = expectJsonObject(normalizeJson(input), "$");
|
|
2099
2141
|
assertExactKeys2(
|
|
2100
|
-
|
|
2142
|
+
object2,
|
|
2101
2143
|
signed ? [
|
|
2102
2144
|
"schema",
|
|
2103
2145
|
"policyId",
|
|
@@ -2125,30 +2167,30 @@ function validatePolicyShape(input, signed) {
|
|
|
2125
2167
|
],
|
|
2126
2168
|
"$"
|
|
2127
2169
|
);
|
|
2128
|
-
expectConst(requiredString2(
|
|
2170
|
+
expectConst(requiredString2(object2, "schema", "$"), POLICY_SCHEMA, "$.schema");
|
|
2129
2171
|
if (signed) {
|
|
2130
|
-
requiredString2(
|
|
2131
|
-
validateSignature(requiredValue2(
|
|
2172
|
+
requiredString2(object2, "policyId", "$");
|
|
2173
|
+
validateSignature(requiredValue2(object2, "signature", "$"));
|
|
2132
2174
|
}
|
|
2133
|
-
requiredString2(
|
|
2134
|
-
requiredString2(
|
|
2135
|
-
requiredDateString(
|
|
2136
|
-
optionalDateString(
|
|
2137
|
-
validatePolicyResource(requiredValue2(
|
|
2138
|
-
validateExpression(requiredValue2(
|
|
2139
|
-
validateGrant(requiredValue2(
|
|
2140
|
-
if (hasOwn2(
|
|
2141
|
-
validateDisclosure(requiredValue2(
|
|
2175
|
+
requiredString2(object2, "ownerDid", "$");
|
|
2176
|
+
requiredString2(object2, "signingKeyDid", "$");
|
|
2177
|
+
requiredDateString(object2, "createdAt", "$");
|
|
2178
|
+
optionalDateString(object2, "expiresAt", "$");
|
|
2179
|
+
validatePolicyResource(requiredValue2(object2, "resource", "$"), "$.resource");
|
|
2180
|
+
validateExpression(requiredValue2(object2, "when", "$"), "$.when");
|
|
2181
|
+
validateGrant(requiredValue2(object2, "grant", "$"), "$.grant");
|
|
2182
|
+
if (hasOwn2(object2, "disclosure")) {
|
|
2183
|
+
validateDisclosure(requiredValue2(object2, "disclosure", "$"), "$.disclosure");
|
|
2142
2184
|
}
|
|
2143
|
-
if (hasOwn2(
|
|
2144
|
-
validateAudit(requiredValue2(
|
|
2185
|
+
if (hasOwn2(object2, "audit")) {
|
|
2186
|
+
validateAudit(requiredValue2(object2, "audit", "$"), "$.audit");
|
|
2145
2187
|
}
|
|
2146
|
-
return
|
|
2188
|
+
return object2;
|
|
2147
2189
|
}
|
|
2148
2190
|
function validatePolicyStatusShape(input, signed) {
|
|
2149
|
-
const
|
|
2191
|
+
const object2 = expectJsonObject(normalizeJson(input), "$");
|
|
2150
2192
|
assertExactKeys2(
|
|
2151
|
-
|
|
2193
|
+
object2,
|
|
2152
2194
|
signed ? [
|
|
2153
2195
|
"schema",
|
|
2154
2196
|
"statusId",
|
|
@@ -2172,28 +2214,28 @@ function validatePolicyStatusShape(input, signed) {
|
|
|
2172
2214
|
],
|
|
2173
2215
|
"$"
|
|
2174
2216
|
);
|
|
2175
|
-
expectConst(requiredString2(
|
|
2217
|
+
expectConst(requiredString2(object2, "schema", "$"), POLICY_STATUS_SCHEMA, "$.schema");
|
|
2176
2218
|
if (signed) {
|
|
2177
|
-
requiredString2(
|
|
2178
|
-
validateSignature(requiredValue2(
|
|
2219
|
+
requiredString2(object2, "statusId", "$");
|
|
2220
|
+
validateSignature(requiredValue2(object2, "signature", "$"));
|
|
2179
2221
|
}
|
|
2180
|
-
requiredString2(
|
|
2181
|
-
requiredString2(
|
|
2182
|
-
requiredInteger(
|
|
2183
|
-
expectOneOf(requiredString2(
|
|
2222
|
+
requiredString2(object2, "policyId", "$");
|
|
2223
|
+
requiredString2(object2, "ownerDid", "$");
|
|
2224
|
+
requiredInteger(object2, "sequence", "$", 0);
|
|
2225
|
+
expectOneOf(requiredString2(object2, "disposition", "$"), [
|
|
2184
2226
|
"active",
|
|
2185
2227
|
"suspended",
|
|
2186
2228
|
"revoked"
|
|
2187
2229
|
], "$.disposition");
|
|
2188
|
-
requiredDateString(
|
|
2189
|
-
optionalString(
|
|
2190
|
-
requiredString2(
|
|
2191
|
-
return
|
|
2230
|
+
requiredDateString(object2, "effectiveAt", "$");
|
|
2231
|
+
optionalString(object2, "reasonCode", "$");
|
|
2232
|
+
requiredString2(object2, "signingKeyDid", "$");
|
|
2233
|
+
return object2;
|
|
2192
2234
|
}
|
|
2193
2235
|
function validatePolicyEngineRecordShape(input, signed) {
|
|
2194
|
-
const
|
|
2236
|
+
const object2 = expectJsonObject(normalizeJson(input), "$");
|
|
2195
2237
|
assertExactKeys2(
|
|
2196
|
-
|
|
2238
|
+
object2,
|
|
2197
2239
|
signed ? [
|
|
2198
2240
|
"schema",
|
|
2199
2241
|
"engineRecordId",
|
|
@@ -2218,44 +2260,44 @@ function validatePolicyEngineRecordShape(input, signed) {
|
|
|
2218
2260
|
"$"
|
|
2219
2261
|
);
|
|
2220
2262
|
expectConst(
|
|
2221
|
-
requiredString2(
|
|
2263
|
+
requiredString2(object2, "schema", "$"),
|
|
2222
2264
|
POLICY_ENGINE_RECORD_SCHEMA,
|
|
2223
2265
|
"$.schema"
|
|
2224
2266
|
);
|
|
2225
2267
|
if (signed) {
|
|
2226
|
-
requiredString2(
|
|
2227
|
-
validateSignature(requiredValue2(
|
|
2268
|
+
requiredString2(object2, "engineRecordId", "$");
|
|
2269
|
+
validateSignature(requiredValue2(object2, "signature", "$"));
|
|
2228
2270
|
}
|
|
2229
|
-
requiredString2(
|
|
2230
|
-
requiredString2(
|
|
2231
|
-
requiredString2(
|
|
2271
|
+
requiredString2(object2, "ownerDid", "$");
|
|
2272
|
+
requiredString2(object2, "endpoint", "$");
|
|
2273
|
+
requiredString2(object2, "audience", "$");
|
|
2232
2274
|
requiredStringArray(
|
|
2233
|
-
|
|
2275
|
+
object2,
|
|
2234
2276
|
"supportedPolicyVersions",
|
|
2235
2277
|
"$",
|
|
2236
2278
|
(value, path) => expectConst(value, "v0", path)
|
|
2237
2279
|
);
|
|
2238
|
-
requiredStringArray(
|
|
2239
|
-
requiredString2(
|
|
2240
|
-
requiredDateString(
|
|
2241
|
-
return
|
|
2280
|
+
requiredStringArray(object2, "supportedEvidenceVerifiers", "$");
|
|
2281
|
+
requiredString2(object2, "grantIssuerDid", "$");
|
|
2282
|
+
requiredDateString(object2, "expiresAt", "$");
|
|
2283
|
+
return object2;
|
|
2242
2284
|
}
|
|
2243
2285
|
function validateSignature(input) {
|
|
2244
|
-
const
|
|
2245
|
-
assertExactKeys2(
|
|
2246
|
-
const suite = requiredString2(
|
|
2286
|
+
const object2 = expectJsonObject(input, "$.signature");
|
|
2287
|
+
assertExactKeys2(object2, ["suite", "signerDid", "value"], "$.signature");
|
|
2288
|
+
const suite = requiredString2(object2, "suite", "$.signature");
|
|
2247
2289
|
assertSupportedSignatureSuite(suite);
|
|
2248
|
-
const signerDid = requiredString2(
|
|
2249
|
-
const value = requiredString2(
|
|
2290
|
+
const signerDid = requiredString2(object2, "signerDid", "$.signature");
|
|
2291
|
+
const value = requiredString2(object2, "value", "$.signature");
|
|
2250
2292
|
decodeSignatureValue(value, suite);
|
|
2251
2293
|
return { suite, signerDid, value };
|
|
2252
2294
|
}
|
|
2253
2295
|
function validatePolicyResource(input, path) {
|
|
2254
|
-
const
|
|
2255
|
-
assertExactKeys2(
|
|
2256
|
-
requiredString2(
|
|
2257
|
-
requiredString2(
|
|
2258
|
-
const ceiling = requiredArray2(
|
|
2296
|
+
const object2 = expectJsonObject(input, path);
|
|
2297
|
+
assertExactKeys2(object2, ["resourceType", "resourceId", "permissionsCeiling"], path);
|
|
2298
|
+
requiredString2(object2, "resourceType", path);
|
|
2299
|
+
requiredString2(object2, "resourceId", path);
|
|
2300
|
+
const ceiling = requiredArray2(object2, "permissionsCeiling", path, 1);
|
|
2259
2301
|
for (let index = 0; index < ceiling.length; index++) {
|
|
2260
2302
|
validatePolicyCapability(ceiling[index], `${path}.permissionsCeiling[${index}]`);
|
|
2261
2303
|
}
|
|
@@ -2271,10 +2313,10 @@ function validatePolicyPermissionsCeilingForSigning(input) {
|
|
|
2271
2313
|
}
|
|
2272
2314
|
}
|
|
2273
2315
|
function validatePolicyCapability(input, path) {
|
|
2274
|
-
const
|
|
2316
|
+
const object2 = expectJsonObject(input, path);
|
|
2275
2317
|
try {
|
|
2276
|
-
const canonical = canonicalizePolicyCapability(
|
|
2277
|
-
if (jcsCanonicalize(
|
|
2318
|
+
const canonical = canonicalizePolicyCapability(object2);
|
|
2319
|
+
if (jcsCanonicalize(object2) !== jcsCanonicalize(canonical)) {
|
|
2278
2320
|
throw new SignedObjectSchemaError(`${path} must be canonical PolicyCapability JSON`);
|
|
2279
2321
|
}
|
|
2280
2322
|
} catch (error) {
|
|
@@ -2287,10 +2329,10 @@ function validatePolicyCapability(input, path) {
|
|
|
2287
2329
|
}
|
|
2288
2330
|
}
|
|
2289
2331
|
function validatePolicyCapabilityForSigning(input, path) {
|
|
2290
|
-
const
|
|
2332
|
+
const object2 = expectJsonObject(input, path);
|
|
2291
2333
|
try {
|
|
2292
|
-
const canonical = normalizePolicyCapability(
|
|
2293
|
-
if (jcsCanonicalize(
|
|
2334
|
+
const canonical = normalizePolicyCapability(object2);
|
|
2335
|
+
if (jcsCanonicalize(object2) !== jcsCanonicalize(canonical)) {
|
|
2294
2336
|
throw new SignedObjectSchemaError(`${path} must be strict canonical PolicyCapability JSON`);
|
|
2295
2337
|
}
|
|
2296
2338
|
} catch (error) {
|
|
@@ -2303,43 +2345,43 @@ function validatePolicyCapabilityForSigning(input, path) {
|
|
|
2303
2345
|
}
|
|
2304
2346
|
}
|
|
2305
2347
|
function validateExpression(input, path) {
|
|
2306
|
-
const
|
|
2307
|
-
const keys = Object.keys(
|
|
2348
|
+
const object2 = expectJsonObject(input, path);
|
|
2349
|
+
const keys = Object.keys(object2);
|
|
2308
2350
|
if (keys.length !== 1) {
|
|
2309
2351
|
throw new SignedObjectSchemaError(`${path} must have exactly one expression key`);
|
|
2310
2352
|
}
|
|
2311
2353
|
const key = keys[0];
|
|
2312
2354
|
if (key === "allOf" || key === "anyOf") {
|
|
2313
|
-
const values = requiredArray2(
|
|
2355
|
+
const values = requiredArray2(object2, key, path, 1);
|
|
2314
2356
|
for (let index = 0; index < values.length; index++) {
|
|
2315
2357
|
validateExpression(values[index], `${path}.${key}[${index}]`);
|
|
2316
2358
|
}
|
|
2317
2359
|
return;
|
|
2318
2360
|
}
|
|
2319
2361
|
if (key === "subject") {
|
|
2320
|
-
const subject = expectJsonObject(requiredValue2(
|
|
2362
|
+
const subject = expectJsonObject(requiredValue2(object2, "subject", path), `${path}.subject`);
|
|
2321
2363
|
assertExactKeys2(subject, ["did"], `${path}.subject`);
|
|
2322
2364
|
requiredString2(subject, "did", `${path}.subject`);
|
|
2323
2365
|
return;
|
|
2324
2366
|
}
|
|
2325
2367
|
if (key === "evidence") {
|
|
2326
|
-
validateEvidenceRequirement(requiredValue2(
|
|
2368
|
+
validateEvidenceRequirement(requiredValue2(object2, "evidence", path), `${path}.evidence`);
|
|
2327
2369
|
return;
|
|
2328
2370
|
}
|
|
2329
2371
|
throw new SignedObjectSchemaError(`${path} has unknown expression key ${key}`);
|
|
2330
2372
|
}
|
|
2331
2373
|
function validateEvidenceRequirement(input, path) {
|
|
2332
|
-
const
|
|
2374
|
+
const object2 = expectJsonObject(input, path);
|
|
2333
2375
|
assertExactKeys2(
|
|
2334
|
-
|
|
2376
|
+
object2,
|
|
2335
2377
|
["requirementId", "verifier", "requirements", "authority", "freshness"],
|
|
2336
2378
|
path
|
|
2337
2379
|
);
|
|
2338
|
-
requiredString2(
|
|
2339
|
-
requiredString2(
|
|
2340
|
-
requiredValue2(
|
|
2341
|
-
if (hasOwn2(
|
|
2342
|
-
const authority = expectJsonObject(requiredValue2(
|
|
2380
|
+
requiredString2(object2, "requirementId", path);
|
|
2381
|
+
requiredString2(object2, "verifier", path);
|
|
2382
|
+
requiredValue2(object2, "requirements", path);
|
|
2383
|
+
if (hasOwn2(object2, "authority")) {
|
|
2384
|
+
const authority = expectJsonObject(requiredValue2(object2, "authority", path), `${path}.authority`);
|
|
2343
2385
|
assertExactKeys2(
|
|
2344
2386
|
authority,
|
|
2345
2387
|
["profile", "acceptedIssuers", "allowOwnerAuthorizedIssuer"],
|
|
@@ -2351,35 +2393,35 @@ function validateEvidenceRequirement(input, path) {
|
|
|
2351
2393
|
}
|
|
2352
2394
|
optionalBoolean(authority, "allowOwnerAuthorizedIssuer", `${path}.authority`);
|
|
2353
2395
|
}
|
|
2354
|
-
if (hasOwn2(
|
|
2355
|
-
const freshness = expectJsonObject(requiredValue2(
|
|
2396
|
+
if (hasOwn2(object2, "freshness")) {
|
|
2397
|
+
const freshness = expectJsonObject(requiredValue2(object2, "freshness", path), `${path}.freshness`);
|
|
2356
2398
|
assertExactKeys2(freshness, ["maxStatusAgeSeconds"], `${path}.freshness`);
|
|
2357
2399
|
requiredInteger(freshness, "maxStatusAgeSeconds", `${path}.freshness`, 0);
|
|
2358
2400
|
}
|
|
2359
2401
|
}
|
|
2360
2402
|
function validateGrant(input, path) {
|
|
2361
|
-
const
|
|
2362
|
-
assertExactKeys2(
|
|
2363
|
-
expectConst(requiredString2(
|
|
2364
|
-
requiredInteger(
|
|
2365
|
-
expectOneOf(requiredString2(
|
|
2403
|
+
const object2 = expectJsonObject(input, path);
|
|
2404
|
+
assertExactKeys2(object2, ["output", "maxTtlSeconds", "delegationMode", "revocation"], path);
|
|
2405
|
+
expectConst(requiredString2(object2, "output", path), "portable-delegation", `${path}.output`);
|
|
2406
|
+
requiredInteger(object2, "maxTtlSeconds", path, 1);
|
|
2407
|
+
expectOneOf(requiredString2(object2, "delegationMode", path), [
|
|
2366
2408
|
"terminal",
|
|
2367
2409
|
"attenuable"
|
|
2368
2410
|
], `${path}.delegationMode`);
|
|
2369
|
-
expectOneOf(requiredString2(
|
|
2411
|
+
expectOneOf(requiredString2(object2, "revocation", path), [
|
|
2370
2412
|
"refresh_only",
|
|
2371
2413
|
"active_cutoff"
|
|
2372
2414
|
], `${path}.revocation`);
|
|
2373
2415
|
}
|
|
2374
2416
|
function validateDisclosure(input, path) {
|
|
2375
|
-
const
|
|
2376
|
-
assertExactKeys2(
|
|
2377
|
-
expectOneOf(requiredString2(
|
|
2417
|
+
const object2 = expectJsonObject(input, path);
|
|
2418
|
+
assertExactKeys2(object2, ["denial"], path);
|
|
2419
|
+
expectOneOf(requiredString2(object2, "denial", path), ["none", "code", "debug"], `${path}.denial`);
|
|
2378
2420
|
}
|
|
2379
2421
|
function validateAudit(input, path) {
|
|
2380
|
-
const
|
|
2381
|
-
assertExactKeys2(
|
|
2382
|
-
expectOneOf(requiredString2(
|
|
2422
|
+
const object2 = expectJsonObject(input, path);
|
|
2423
|
+
assertExactKeys2(object2, ["issuance"], path);
|
|
2424
|
+
expectOneOf(requiredString2(object2, "issuance", path), ["off", "security", "full"], `${path}.issuance`);
|
|
2383
2425
|
}
|
|
2384
2426
|
function materialForUnsigned(unsigned, descriptor) {
|
|
2385
2427
|
const jcs = jcsCanonicalize(unsigned);
|
|
@@ -2528,9 +2570,9 @@ function encodeSignatureValue(value, suite) {
|
|
|
2528
2570
|
decodeSignatureValue(encoded, suite);
|
|
2529
2571
|
return encoded;
|
|
2530
2572
|
}
|
|
2531
|
-
function stripOwnIdAndSignature(
|
|
2573
|
+
function stripOwnIdAndSignature(object2, descriptor) {
|
|
2532
2574
|
const output = /* @__PURE__ */ Object.create(null);
|
|
2533
|
-
for (const [key, value] of Object.entries(
|
|
2575
|
+
for (const [key, value] of Object.entries(object2)) {
|
|
2534
2576
|
if (key === descriptor.idField || key === "signature") {
|
|
2535
2577
|
continue;
|
|
2536
2578
|
}
|
|
@@ -2539,8 +2581,8 @@ function stripOwnIdAndSignature(object, descriptor) {
|
|
|
2539
2581
|
return output;
|
|
2540
2582
|
}
|
|
2541
2583
|
function descriptorForUnsigned(input) {
|
|
2542
|
-
const
|
|
2543
|
-
return descriptorForSchema(requiredString2(
|
|
2584
|
+
const object2 = expectJsonObject(normalizeJson(input), "$");
|
|
2585
|
+
return descriptorForSchema(requiredString2(object2, "schema", "$"));
|
|
2544
2586
|
}
|
|
2545
2587
|
function descriptorForSchema(schema) {
|
|
2546
2588
|
if (schema === POLICY_SCHEMA) return DESCRIPTORS.Policy;
|
|
@@ -2554,28 +2596,28 @@ function expectJsonObject(input, path) {
|
|
|
2554
2596
|
}
|
|
2555
2597
|
return input;
|
|
2556
2598
|
}
|
|
2557
|
-
function assertExactKeys2(
|
|
2599
|
+
function assertExactKeys2(object2, allowed, path) {
|
|
2558
2600
|
const allowedSet = new Set(allowed);
|
|
2559
|
-
for (const key of Object.keys(
|
|
2601
|
+
for (const key of Object.keys(object2)) {
|
|
2560
2602
|
if (!allowedSet.has(key)) {
|
|
2561
2603
|
throw new SignedObjectSchemaError(`${path} has unknown field ${key}`);
|
|
2562
2604
|
}
|
|
2563
2605
|
}
|
|
2564
2606
|
}
|
|
2565
|
-
function requiredValue2(
|
|
2566
|
-
if (!hasOwn2(
|
|
2607
|
+
function requiredValue2(object2, key, path) {
|
|
2608
|
+
if (!hasOwn2(object2, key)) {
|
|
2567
2609
|
throw new SignedObjectSchemaError(`${path}.${key} is required`);
|
|
2568
2610
|
}
|
|
2569
|
-
return
|
|
2611
|
+
return object2[key];
|
|
2570
2612
|
}
|
|
2571
|
-
function requiredString2(
|
|
2572
|
-
return requireStringType(requiredValue2(
|
|
2613
|
+
function requiredString2(object2, key, path) {
|
|
2614
|
+
return requireStringType(requiredValue2(object2, key, path), `${path}.${key}`);
|
|
2573
2615
|
}
|
|
2574
|
-
function optionalString(
|
|
2575
|
-
if (!hasOwn2(
|
|
2616
|
+
function optionalString(object2, key, path) {
|
|
2617
|
+
if (!hasOwn2(object2, key)) {
|
|
2576
2618
|
return;
|
|
2577
2619
|
}
|
|
2578
|
-
requireStringType(requiredValue2(
|
|
2620
|
+
requireStringType(requiredValue2(object2, key, path), `${path}.${key}`);
|
|
2579
2621
|
}
|
|
2580
2622
|
function requireStringType(value, path) {
|
|
2581
2623
|
if (typeof value !== "string" || value.length === 0) {
|
|
@@ -2583,16 +2625,16 @@ function requireStringType(value, path) {
|
|
|
2583
2625
|
}
|
|
2584
2626
|
return value;
|
|
2585
2627
|
}
|
|
2586
|
-
function optionalBoolean(
|
|
2587
|
-
if (!hasOwn2(
|
|
2628
|
+
function optionalBoolean(object2, key, path) {
|
|
2629
|
+
if (!hasOwn2(object2, key)) {
|
|
2588
2630
|
return;
|
|
2589
2631
|
}
|
|
2590
|
-
if (typeof requiredValue2(
|
|
2632
|
+
if (typeof requiredValue2(object2, key, path) !== "boolean") {
|
|
2591
2633
|
throw new SignedObjectSchemaError(`${path}.${key} must be a boolean`);
|
|
2592
2634
|
}
|
|
2593
2635
|
}
|
|
2594
|
-
function requiredInteger(
|
|
2595
|
-
const value = requiredValue2(
|
|
2636
|
+
function requiredInteger(object2, key, path, minimum) {
|
|
2637
|
+
const value = requiredValue2(object2, key, path);
|
|
2596
2638
|
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < minimum) {
|
|
2597
2639
|
throw new SignedObjectSchemaError(
|
|
2598
2640
|
`${path}.${key} must be an integer >= ${minimum}`
|
|
@@ -2600,8 +2642,8 @@ function requiredInteger(object, key, path, minimum) {
|
|
|
2600
2642
|
}
|
|
2601
2643
|
return value;
|
|
2602
2644
|
}
|
|
2603
|
-
function requiredArray2(
|
|
2604
|
-
const value = requiredValue2(
|
|
2645
|
+
function requiredArray2(object2, key, path, minimum) {
|
|
2646
|
+
const value = requiredValue2(object2, key, path);
|
|
2605
2647
|
if (!Array.isArray(value) || value.length < minimum) {
|
|
2606
2648
|
throw new SignedObjectSchemaError(
|
|
2607
2649
|
`${path}.${key} must be an array with at least ${minimum} item(s)`
|
|
@@ -2609,22 +2651,22 @@ function requiredArray2(object, key, path, minimum) {
|
|
|
2609
2651
|
}
|
|
2610
2652
|
return value;
|
|
2611
2653
|
}
|
|
2612
|
-
function requiredStringArray(
|
|
2613
|
-
const values = requiredArray2(
|
|
2654
|
+
function requiredStringArray(object2, key, path, check) {
|
|
2655
|
+
const values = requiredArray2(object2, key, path, 0);
|
|
2614
2656
|
for (let index = 0; index < values.length; index++) {
|
|
2615
2657
|
const itemPath = `${path}.${key}[${index}]`;
|
|
2616
2658
|
const value = requireStringType(values[index], itemPath);
|
|
2617
2659
|
check?.(value, itemPath);
|
|
2618
2660
|
}
|
|
2619
2661
|
}
|
|
2620
|
-
function requiredDateString(
|
|
2621
|
-
assertRfc3339(requiredString2(
|
|
2662
|
+
function requiredDateString(object2, key, path) {
|
|
2663
|
+
assertRfc3339(requiredString2(object2, key, path), `${path}.${key}`);
|
|
2622
2664
|
}
|
|
2623
|
-
function optionalDateString(
|
|
2624
|
-
if (!hasOwn2(
|
|
2665
|
+
function optionalDateString(object2, key, path) {
|
|
2666
|
+
if (!hasOwn2(object2, key)) {
|
|
2625
2667
|
return;
|
|
2626
2668
|
}
|
|
2627
|
-
assertRfc3339(requiredString2(
|
|
2669
|
+
assertRfc3339(requiredString2(object2, key, path), `${path}.${key}`);
|
|
2628
2670
|
}
|
|
2629
2671
|
function assertRfc3339(value, path) {
|
|
2630
2672
|
const match = value.match(
|
|
@@ -2656,8 +2698,8 @@ function expectOneOf(actual, allowed, path) {
|
|
|
2656
2698
|
}
|
|
2657
2699
|
throw new SignedObjectSchemaError(`${path} has unsupported value ${actual}`);
|
|
2658
2700
|
}
|
|
2659
|
-
function hasOwn2(
|
|
2660
|
-
return objectHasOwn3(
|
|
2701
|
+
function hasOwn2(object2, key) {
|
|
2702
|
+
return objectHasOwn3(object2, key);
|
|
2661
2703
|
}
|
|
2662
2704
|
function assertSupportedSignatureSuite(suite) {
|
|
2663
2705
|
if (suite !== ED25519_JCS_SIGNATURE_SUITE && suite !== EIP191_JCS_SIGNATURE_SUITE) {
|
|
@@ -2736,13 +2778,13 @@ function base64UrlDecode(value) {
|
|
|
2736
2778
|
return decoded;
|
|
2737
2779
|
}
|
|
2738
2780
|
function hexToBytes(value) {
|
|
2739
|
-
const
|
|
2740
|
-
if (
|
|
2781
|
+
const hex2 = value.slice(2);
|
|
2782
|
+
if (hex2.length % 2 !== 0 || !/^[0-9a-fA-F]*$/.test(hex2)) {
|
|
2741
2783
|
throw new SignatureMaterialError("hex signature must have even length");
|
|
2742
2784
|
}
|
|
2743
|
-
const output = new Uint8Array(
|
|
2785
|
+
const output = new Uint8Array(hex2.length / 2);
|
|
2744
2786
|
for (let index = 0; index < output.length; index++) {
|
|
2745
|
-
output[index] = Number.parseInt(
|
|
2787
|
+
output[index] = Number.parseInt(hex2.slice(index * 2, index * 2 + 2), 16);
|
|
2746
2788
|
}
|
|
2747
2789
|
return output;
|
|
2748
2790
|
}
|
|
@@ -3093,9 +3135,9 @@ function expectPolicyEngineRecord(input) {
|
|
|
3093
3135
|
);
|
|
3094
3136
|
}
|
|
3095
3137
|
}
|
|
3096
|
-
function assertExactKeys3(
|
|
3138
|
+
function assertExactKeys3(object2, allowed, path) {
|
|
3097
3139
|
const allowedSet = new Set(allowed);
|
|
3098
|
-
for (const key of Object.keys(
|
|
3140
|
+
for (const key of Object.keys(object2)) {
|
|
3099
3141
|
if (!allowedSet.has(key)) {
|
|
3100
3142
|
throw new PolicyAuthoringError(
|
|
3101
3143
|
"policy-authoring-unknown-key",
|
|
@@ -3104,17 +3146,17 @@ function assertExactKeys3(object, allowed, path) {
|
|
|
3104
3146
|
}
|
|
3105
3147
|
}
|
|
3106
3148
|
}
|
|
3107
|
-
function requiredValue3(
|
|
3108
|
-
if (!hasOwn3(
|
|
3149
|
+
function requiredValue3(object2, key, path) {
|
|
3150
|
+
if (!hasOwn3(object2, key)) {
|
|
3109
3151
|
throw new PolicyAuthoringError(
|
|
3110
3152
|
"policy-authoring-malformed",
|
|
3111
3153
|
`${path}.${key} is required`
|
|
3112
3154
|
);
|
|
3113
3155
|
}
|
|
3114
|
-
return
|
|
3156
|
+
return object2[key];
|
|
3115
3157
|
}
|
|
3116
|
-
function requiredString3(
|
|
3117
|
-
const value = requiredValue3(
|
|
3158
|
+
function requiredString3(object2, key, path) {
|
|
3159
|
+
const value = requiredValue3(object2, key, path);
|
|
3118
3160
|
if (typeof value !== "string" || value.length === 0) {
|
|
3119
3161
|
throw new PolicyAuthoringError(
|
|
3120
3162
|
"policy-authoring-malformed",
|
|
@@ -3123,11 +3165,11 @@ function requiredString3(object, key, path) {
|
|
|
3123
3165
|
}
|
|
3124
3166
|
return value;
|
|
3125
3167
|
}
|
|
3126
|
-
function fieldString(
|
|
3127
|
-
if (!hasOwn3(
|
|
3168
|
+
function fieldString(object2, key, path, code2) {
|
|
3169
|
+
if (!hasOwn3(object2, key)) {
|
|
3128
3170
|
throw new PolicyAuthoringError(code2, `${path}.${key} is required`);
|
|
3129
3171
|
}
|
|
3130
|
-
const value =
|
|
3172
|
+
const value = object2[key];
|
|
3131
3173
|
if (typeof value !== "string" || value.length === 0) {
|
|
3132
3174
|
throw new PolicyAuthoringError(
|
|
3133
3175
|
code2,
|
|
@@ -3136,8 +3178,8 @@ function fieldString(object, key, path, code2) {
|
|
|
3136
3178
|
}
|
|
3137
3179
|
return value;
|
|
3138
3180
|
}
|
|
3139
|
-
function requiredObject(
|
|
3140
|
-
const value = requiredValue3(
|
|
3181
|
+
function requiredObject(object2, key, path) {
|
|
3182
|
+
const value = requiredValue3(object2, key, path);
|
|
3141
3183
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
3142
3184
|
throw new PolicyAuthoringError(
|
|
3143
3185
|
"policy-authoring-malformed",
|
|
@@ -3146,8 +3188,8 @@ function requiredObject(object, key, path) {
|
|
|
3146
3188
|
}
|
|
3147
3189
|
return value;
|
|
3148
3190
|
}
|
|
3149
|
-
function requiredArray3(
|
|
3150
|
-
const value = requiredValue3(
|
|
3191
|
+
function requiredArray3(object2, key, path) {
|
|
3192
|
+
const value = requiredValue3(object2, key, path);
|
|
3151
3193
|
if (!Array.isArray(value)) {
|
|
3152
3194
|
throw new PolicyAuthoringError(
|
|
3153
3195
|
"policy-authoring-malformed",
|
|
@@ -3156,8 +3198,8 @@ function requiredArray3(object, key, path) {
|
|
|
3156
3198
|
}
|
|
3157
3199
|
return value;
|
|
3158
3200
|
}
|
|
3159
|
-
function requiredStringArray2(
|
|
3160
|
-
const values = requiredArray3(
|
|
3201
|
+
function requiredStringArray2(object2, key, path) {
|
|
3202
|
+
const values = requiredArray3(object2, key, path);
|
|
3161
3203
|
return values.map((value, index) => {
|
|
3162
3204
|
if (typeof value !== "string" || value.length === 0) {
|
|
3163
3205
|
throw new PolicyAuthoringError(
|
|
@@ -3254,7 +3296,657 @@ function parseStrictRfc3339(value, path) {
|
|
|
3254
3296
|
var objectHasOwn4 = Object.hasOwn ?? Object.prototype.hasOwnProperty.call.bind(
|
|
3255
3297
|
Object.prototype.hasOwnProperty
|
|
3256
3298
|
);
|
|
3257
|
-
function hasOwn3(
|
|
3258
|
-
return objectHasOwn4(
|
|
3299
|
+
function hasOwn3(object2, key) {
|
|
3300
|
+
return objectHasOwn4(object2, key);
|
|
3301
|
+
}
|
|
3302
|
+
|
|
3303
|
+
// src/policy/unified.ts
|
|
3304
|
+
var import_sha256 = require("@noble/hashes/sha256");
|
|
3305
|
+
var import_blake3 = require("@noble/hashes/blake3");
|
|
3306
|
+
var import_ed255192 = require("@noble/curves/ed25519");
|
|
3307
|
+
var import_zod = require("zod");
|
|
3308
|
+
var POLICY_V1_SCHEMA = "xyz.tinycloud.policy/policy/v1";
|
|
3309
|
+
var POLICY_CAPABILITY_V1_SCHEMA = "xyz.tinycloud.policy/capability/v1";
|
|
3310
|
+
var POLICY_ENFORCEMENT_DELEGATION_V2_SCHEMA = "xyz.tinycloud.policy/enforcement-delegation/v2";
|
|
3311
|
+
var ATTESTED_ENFORCER_BINDING_V2_SCHEMA = "xyz.tinycloud.policy/attested-enforcer/v2";
|
|
3312
|
+
var ROOT_STATUS_CHECKPOINT_V1_SCHEMA = "xyz.tinycloud.policy/root-status/v1";
|
|
3313
|
+
var ROOT_REVOCATION_V1_SCHEMA = "xyz.tinycloud.policy/root-revocation/v1";
|
|
3314
|
+
var POLICY_SESSION_UCAN_V1_PROFILE = "policy-session-ucan/v1";
|
|
3315
|
+
var POLICY_V1_DOMAIN = "xyz.tinycloud.policy/policy/v1\0";
|
|
3316
|
+
var POLICY_CAPABILITY_V1_DOMAIN = "xyz.tinycloud.policy/PolicyCapability/v1\0";
|
|
3317
|
+
var CONTENT_SOURCE_V1_DOMAIN = "xyz.tinycloud.policy/ContentSource/v1\0";
|
|
3318
|
+
var NATIVE_PROJECTION_V1_DOMAIN = "xyz.tinycloud.policy/NativeProjection/v1\0";
|
|
3319
|
+
var ROOT_STATUS_V1_DOMAIN = "xyz.tinycloud.policy/RootStatusCheckpoint/v1\0";
|
|
3320
|
+
var ROOT_STATUS_RENEWAL_V1_DOMAIN = "xyz.tinycloud.policy/RootStatusRenewal/v1\0";
|
|
3321
|
+
var ROOT_REVOCATION_V1_DOMAIN = "xyz.tinycloud.policy/RootRevocation/v1\0";
|
|
3322
|
+
var LAST_V2_CREATE_AT = "2026-09-30T00:00:00Z";
|
|
3323
|
+
var MAX_LEGACY_ENVELOPE_EXPIRES_AT = "2026-12-29T00:00:00Z";
|
|
3324
|
+
var LAST_V2_READ_AT = "2027-01-05T00:00:00Z";
|
|
3325
|
+
async function requestPolicyChallengeV3(input) {
|
|
3326
|
+
const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
|
|
3327
|
+
const response = await fetchFn(new URL("/share/v3/policy/challenges", input.nodeOrigin), {
|
|
3328
|
+
method: "POST",
|
|
3329
|
+
redirect: "error",
|
|
3330
|
+
headers: { accept: "application/json", "content-type": "application/json" },
|
|
3331
|
+
body: JSON.stringify({ policyCid: input.policyCid, recipientDid: input.recipientDid, requestedCapabilities: input.requestedCapabilities.map(normalizeUnifiedPolicyCapability) })
|
|
3332
|
+
});
|
|
3333
|
+
if (!response.ok) throw new Error(`policy challenge rejected (${response.status})`);
|
|
3334
|
+
const value = object(await response.json(), "policy challenge");
|
|
3335
|
+
if (typeof value.challengeId !== "string" || typeof value.nonce !== "string" || value.policyCid !== input.policyCid || value.recipientDid !== input.recipientDid)
|
|
3336
|
+
throw new Error("policy challenge binding is invalid");
|
|
3337
|
+
return value;
|
|
3338
|
+
}
|
|
3339
|
+
async function mintPolicySessionV3(input) {
|
|
3340
|
+
const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
|
|
3341
|
+
const challenge = input.challenge ?? await requestPolicyChallengeV3(input);
|
|
3342
|
+
if (challenge.policyCid !== input.policyCid || challenge.recipientDid !== input.recipientDid)
|
|
3343
|
+
throw new Error("policy challenge binding is invalid");
|
|
3344
|
+
const response = await fetchFn(new URL("/share/v3/policy/delegations", input.nodeOrigin), {
|
|
3345
|
+
method: "POST",
|
|
3346
|
+
redirect: "error",
|
|
3347
|
+
headers: { accept: "application/json", "content-type": "application/json" },
|
|
3348
|
+
body: JSON.stringify({ policyCid: input.policyCid, challengeId: challenge.challengeId, nonce: challenge.nonce, claim: input.claim, presentation: input.presentation })
|
|
3349
|
+
});
|
|
3350
|
+
if (!response.ok) throw new Error(`policy delegation rejected (${response.status})`);
|
|
3351
|
+
const value = object(await response.json(), "policy delegation");
|
|
3352
|
+
if (value.admitted !== true || typeof value.sessionCid !== "string" || typeof value.authorization !== "string")
|
|
3353
|
+
throw new Error("policy delegation response is invalid");
|
|
3354
|
+
const session = parsePolicySessionUcan(value.authorization, [input.policyRootCid, input.enforcementRootCid]);
|
|
3355
|
+
const expectedAttenuation = compactAttenuationForPolicyCapabilities(input.requestedCapabilities);
|
|
3356
|
+
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))
|
|
3357
|
+
throw new Error("policy delegation signed binding is invalid");
|
|
3358
|
+
return session;
|
|
3359
|
+
}
|
|
3360
|
+
function compactAttenuationForPolicyCapabilities(input) {
|
|
3361
|
+
const attenuation = {};
|
|
3362
|
+
for (const raw of input) {
|
|
3363
|
+
const capability = normalizeUnifiedPolicyCapability(raw);
|
|
3364
|
+
if (attenuation[capability.resource] !== void 0)
|
|
3365
|
+
throw new Error("policy capabilities contain a duplicate resource");
|
|
3366
|
+
attenuation[capability.resource] = capability.kind === "encryption" ? { [capability.action]: [{}] } : Object.fromEntries(capability.actions.map((action) => [action, [{
|
|
3367
|
+
type: "xyz.tinycloud.resource/selector",
|
|
3368
|
+
kind: capability.selector,
|
|
3369
|
+
value: capability.resource
|
|
3370
|
+
}]]));
|
|
3371
|
+
}
|
|
3372
|
+
return attenuation;
|
|
3373
|
+
}
|
|
3374
|
+
function verifyPolicyRootStatusCheckpointV3(input) {
|
|
3375
|
+
const checkpoint = input.checkpoint;
|
|
3376
|
+
const allowed = /* @__PURE__ */ new Set(["schema", "targetCid", "targetRole", "ownerDid", "nodeAudience", "state", "sequence", "checkedAt", "freshUntil", "revokedAt", "revocationCid", "previousCheckpointDigestHex", "issuerDid", "signature"]);
|
|
3377
|
+
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;
|
|
3378
|
+
const checkedAt = Date.parse(checkpoint.checkedAt);
|
|
3379
|
+
const freshUntil = Date.parse(checkpoint.freshUntil);
|
|
3380
|
+
const now = (input.now ?? /* @__PURE__ */ new Date()).getTime();
|
|
3381
|
+
if (!Number.isFinite(checkedAt) || !Number.isFinite(freshUntil) || freshUntil < now || freshUntil <= checkedAt || freshUntil - checkedAt > 3e5) return false;
|
|
3382
|
+
if (checkpoint.sequence === 1 !== (checkpoint.previousCheckpointDigestHex === void 0)) return false;
|
|
3383
|
+
if (checkpoint.sequence !== 1 && (typeof checkpoint.previousCheckpointDigestHex !== "string" || !/^[0-9a-f]{64}$/.test(checkpoint.previousCheckpointDigestHex))) return false;
|
|
3384
|
+
if (checkpoint.state === "active" && (checkpoint.revokedAt !== void 0 || checkpoint.revocationCid !== void 0)) return false;
|
|
3385
|
+
if (checkpoint.state === "revoked" && (typeof checkpoint.revokedAt !== "string" || typeof checkpoint.revocationCid !== "string")) return false;
|
|
3386
|
+
const signature = checkpoint.signature;
|
|
3387
|
+
if (!isRecordValue(signature) || Object.keys(signature).length !== 3 || signature.suite !== "Ed25519" || signature.signerDid !== checkpoint.issuerDid || typeof signature.value !== "string") return false;
|
|
3388
|
+
try {
|
|
3389
|
+
const principal = checkpoint.issuerDid.split("#", 1)[0];
|
|
3390
|
+
const didMaterial = principal.startsWith("did:key:") ? base58btc.decode(principal.slice("did:key:".length)) : new Uint8Array();
|
|
3391
|
+
if (didMaterial.length !== 34 || didMaterial[0] !== 237 || didMaterial[1] !== 1) return false;
|
|
3392
|
+
const unsigned = { ...checkpoint };
|
|
3393
|
+
delete unsigned.signature;
|
|
3394
|
+
return import_ed255192.ed25519.verify(
|
|
3395
|
+
decodeBase64Url(signature.value),
|
|
3396
|
+
(0, import_sha256.sha256)(new TextEncoder().encode(ROOT_STATUS_V1_DOMAIN + jcsCanonicalize(unsigned))),
|
|
3397
|
+
didMaterial.slice(2)
|
|
3398
|
+
);
|
|
3399
|
+
} catch {
|
|
3400
|
+
return false;
|
|
3401
|
+
}
|
|
3402
|
+
}
|
|
3403
|
+
async function getPolicyRootStatusV3(input) {
|
|
3404
|
+
const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
|
|
3405
|
+
const response = await fetchFn(new URL(`/share/v3/policy/status/${encodeURIComponent(input.rootCid)}`, input.nodeOrigin), {
|
|
3406
|
+
method: "GET",
|
|
3407
|
+
redirect: "error",
|
|
3408
|
+
headers: { accept: "application/json" }
|
|
3409
|
+
});
|
|
3410
|
+
if (!response.ok) throw new Error(`policy root status rejected (${response.status})`);
|
|
3411
|
+
const value = object(await response.json(), "policy root status");
|
|
3412
|
+
const checkpoint = object(value.checkpoint, "policy root checkpoint");
|
|
3413
|
+
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 }))
|
|
3414
|
+
throw new Error("policy root status binding is invalid");
|
|
3415
|
+
const revocation = value.revocation === void 0 ? void 0 : object(value.revocation, "policy root revocation");
|
|
3416
|
+
if (value.state === "revoked" !== (revocation !== void 0) || revocation !== void 0 && !verifyPolicyRootRevocationV3({
|
|
3417
|
+
rootCid: input.rootCid,
|
|
3418
|
+
checkpoint,
|
|
3419
|
+
revocation,
|
|
3420
|
+
expectedEnforcerDid: input.expectedEnforcerDid
|
|
3421
|
+
})) throw new Error("policy root status revocation evidence is invalid");
|
|
3422
|
+
return { rootCid: input.rootCid, state: value.state, checkpoint, ...revocation === void 0 ? {} : { revocation } };
|
|
3423
|
+
}
|
|
3424
|
+
function verifyPolicyRootRevocationV3(input) {
|
|
3425
|
+
const value = input.revocation;
|
|
3426
|
+
const allowed = ["schema", "targetCid", "targetRole", "ownerDid", "nodeAudience", "revokedAt", "reason", "issuerDid", "signature"];
|
|
3427
|
+
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;
|
|
3428
|
+
const authorized = value.issuerDid === value.ownerDid || value.targetRole === "policy-enforcement" && value.issuerDid === input.expectedEnforcerDid;
|
|
3429
|
+
if (!authorized) return false;
|
|
3430
|
+
const signature = value.signature;
|
|
3431
|
+
if (!isRecordValue(signature) || Object.keys(signature).length !== 3 || signature.suite !== "Ed25519" || signature.signerDid !== value.issuerDid || typeof signature.value !== "string") return false;
|
|
3432
|
+
try {
|
|
3433
|
+
const principal = value.issuerDid.split("#", 1)[0];
|
|
3434
|
+
const didMaterial = principal.startsWith("did:key:") ? base58btc.decode(principal.slice("did:key:".length)) : new Uint8Array();
|
|
3435
|
+
if (didMaterial.length !== 34 || didMaterial[0] !== 237 || didMaterial[1] !== 1) return false;
|
|
3436
|
+
const unsigned = { ...value };
|
|
3437
|
+
delete unsigned.signature;
|
|
3438
|
+
const digest2 = (0, import_sha256.sha256)(new TextEncoder().encode(ROOT_REVOCATION_V1_DOMAIN + jcsCanonicalize(unsigned)));
|
|
3439
|
+
return input.checkpoint.revocationCid === hex(digest2) && import_ed255192.ed25519.verify(decodeBase64Url(signature.value), digest2, didMaterial.slice(2));
|
|
3440
|
+
} catch {
|
|
3441
|
+
return false;
|
|
3442
|
+
}
|
|
3443
|
+
}
|
|
3444
|
+
async function renewPolicyRootStatusV3(input) {
|
|
3445
|
+
const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
|
|
3446
|
+
const current = await getPolicyRootStatusV3({ nodeOrigin: input.nodeOrigin, rootCid: input.rootCid, expectedNodeAudience: input.nodeAudience, now: input.now, fetch: fetchFn });
|
|
3447
|
+
if (current.state !== "active" || current.checkpoint.ownerDid !== input.ownerDid || current.checkpoint.nodeAudience !== input.nodeAudience || current.checkpoint.state !== "active" || !Number.isInteger(current.checkpoint.sequence))
|
|
3448
|
+
throw new Error("policy root status cannot be renewed");
|
|
3449
|
+
const currentUnsigned = { ...current.checkpoint };
|
|
3450
|
+
delete currentUnsigned.signature;
|
|
3451
|
+
const previousCheckpointDigestHex = hex((0, import_sha256.sha256)(new TextEncoder().encode(ROOT_STATUS_V1_DOMAIN + jcsCanonicalize(currentUnsigned))));
|
|
3452
|
+
const unsigned = {
|
|
3453
|
+
schema: "xyz.tinycloud.policy/root-status-renewal/v1",
|
|
3454
|
+
targetCid: input.rootCid,
|
|
3455
|
+
ownerDid: input.ownerDid,
|
|
3456
|
+
nodeAudience: input.nodeAudience,
|
|
3457
|
+
issuedAt: (input.now ?? /* @__PURE__ */ new Date()).toISOString(),
|
|
3458
|
+
nonce: input.nonce ?? encodeBase64Url(crypto.getRandomValues(new Uint8Array(16))),
|
|
3459
|
+
sequence: current.checkpoint.sequence + 1,
|
|
3460
|
+
previousCheckpointDigestHex
|
|
3461
|
+
};
|
|
3462
|
+
const signature = await input.sign((0, import_sha256.sha256)(new TextEncoder().encode(ROOT_STATUS_RENEWAL_V1_DOMAIN + jcsCanonicalize(unsigned))));
|
|
3463
|
+
if (signature.length !== 64) throw new Error("policy root renewal signature must be Ed25519");
|
|
3464
|
+
const response = await fetchFn(new URL("/share/v3/policy/status", input.nodeOrigin), {
|
|
3465
|
+
method: "POST",
|
|
3466
|
+
redirect: "error",
|
|
3467
|
+
headers: { accept: "application/json", "content-type": "application/json" },
|
|
3468
|
+
body: JSON.stringify({ rootCid: input.rootCid, renewal: { ...unsigned, signature: { suite: "Ed25519", signerDid: input.ownerDid, value: encodeBase64Url(signature) } } })
|
|
3469
|
+
});
|
|
3470
|
+
if (!response.ok) throw new Error(`policy root renewal rejected (${response.status})`);
|
|
3471
|
+
return object(await response.json(), "policy root renewal");
|
|
3472
|
+
}
|
|
3473
|
+
async function revokePolicyRootV3(input) {
|
|
3474
|
+
if (input.reason.length === 0) throw new Error("policy root revocation reason is required");
|
|
3475
|
+
const unsigned = {
|
|
3476
|
+
schema: ROOT_REVOCATION_V1_SCHEMA,
|
|
3477
|
+
targetCid: input.rootCid,
|
|
3478
|
+
targetRole: input.targetRole,
|
|
3479
|
+
ownerDid: input.ownerDid,
|
|
3480
|
+
nodeAudience: input.nodeAudience,
|
|
3481
|
+
revokedAt: (input.now ?? /* @__PURE__ */ new Date()).toISOString(),
|
|
3482
|
+
reason: input.reason,
|
|
3483
|
+
issuerDid: input.issuerDid
|
|
3484
|
+
};
|
|
3485
|
+
const signature = await input.sign((0, import_sha256.sha256)(new TextEncoder().encode(ROOT_REVOCATION_V1_DOMAIN + jcsCanonicalize(unsigned))));
|
|
3486
|
+
if (signature.length !== 64) throw new Error("policy root revocation signature must be Ed25519");
|
|
3487
|
+
const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
|
|
3488
|
+
const response = await fetchFn(new URL("/revoke", input.nodeOrigin), {
|
|
3489
|
+
method: "POST",
|
|
3490
|
+
redirect: "error",
|
|
3491
|
+
headers: { accept: "application/json", "content-type": "application/json" },
|
|
3492
|
+
body: JSON.stringify({ revocation: { ...unsigned, signature: { suite: "Ed25519", signerDid: input.issuerDid, value: encodeBase64Url(signature) } } })
|
|
3493
|
+
});
|
|
3494
|
+
if (!response.ok) throw new Error(`policy root revocation rejected (${response.status})`);
|
|
3495
|
+
return object(await response.json(), "policy root revocation");
|
|
3496
|
+
}
|
|
3497
|
+
var POLICY_SESSION_FACT_KEYS = [
|
|
3498
|
+
"profile",
|
|
3499
|
+
"ownerDid",
|
|
3500
|
+
"policyId",
|
|
3501
|
+
"policyDigestHex",
|
|
3502
|
+
"policyCid",
|
|
3503
|
+
"policyDelegationCid",
|
|
3504
|
+
"enforcementDelegationCid",
|
|
3505
|
+
"contentSourceDigestHex",
|
|
3506
|
+
"capabilityCeilingHashHex",
|
|
3507
|
+
"nativeProjectionHashHex",
|
|
3508
|
+
"enforcerDid",
|
|
3509
|
+
"nodeAudience",
|
|
3510
|
+
"recipientDid",
|
|
3511
|
+
"challengeId",
|
|
3512
|
+
"claimDigestHex",
|
|
3513
|
+
"claimJti",
|
|
3514
|
+
"vpDigestHex",
|
|
3515
|
+
"credentialEvidenceDigestHex",
|
|
3516
|
+
"decisionContextDigestHex",
|
|
3517
|
+
"issuanceAuditDigestHex",
|
|
3518
|
+
"remainingRedelegationDepth"
|
|
3519
|
+
];
|
|
3520
|
+
var KV_ACTIONS = /* @__PURE__ */ new Set([
|
|
3521
|
+
"tinycloud.kv/get",
|
|
3522
|
+
"tinycloud.kv/list",
|
|
3523
|
+
"tinycloud.kv/metadata",
|
|
3524
|
+
"tinycloud.kv/put"
|
|
3525
|
+
]);
|
|
3526
|
+
function object(value, label) {
|
|
3527
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
3528
|
+
throw new Error(`${label} must be an object`);
|
|
3529
|
+
}
|
|
3530
|
+
return value;
|
|
3531
|
+
}
|
|
3532
|
+
function exactKeys(value, allowed, label) {
|
|
3533
|
+
const keys = new Set(allowed);
|
|
3534
|
+
if (Object.keys(value).some((key) => !keys.has(key)))
|
|
3535
|
+
throw new Error(`${label} contains an unknown field`);
|
|
3536
|
+
}
|
|
3537
|
+
function nonEmptyString(value, label) {
|
|
3538
|
+
if (typeof value !== "string" || value.length === 0)
|
|
3539
|
+
throw new Error(`${label} must be a non-empty string`);
|
|
3540
|
+
return value;
|
|
3541
|
+
}
|
|
3542
|
+
function parseKvResource(resource) {
|
|
3543
|
+
const match = /^tinycloud:\/\/([^/]+)\/kv\/(.+)$/.exec(resource);
|
|
3544
|
+
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)) {
|
|
3545
|
+
throw new Error("KV resource is not canonical");
|
|
3546
|
+
}
|
|
3547
|
+
return { space: match[1], path: match[2] };
|
|
3548
|
+
}
|
|
3549
|
+
function parseEncryptionResource(resource) {
|
|
3550
|
+
if (!resource.startsWith("urn:tinycloud:encryption:")) throw new Error("encryption capability is invalid");
|
|
3551
|
+
const rest = resource.slice("urn:tinycloud:encryption:".length);
|
|
3552
|
+
const separator = rest.lastIndexOf(":");
|
|
3553
|
+
const ownerDid = separator < 0 ? "" : rest.slice(0, separator);
|
|
3554
|
+
const network = separator < 0 ? "" : rest.slice(separator + 1);
|
|
3555
|
+
if (!ownerDid.startsWith("did:") || network.length === 0 || network.includes(":") || network.includes("/") || network.includes("%") || network.includes("?") || network.includes("#")) {
|
|
3556
|
+
throw new Error("encryption capability is invalid");
|
|
3557
|
+
}
|
|
3558
|
+
}
|
|
3559
|
+
function normalizeUnifiedPolicyCapability(input) {
|
|
3560
|
+
const value = object(input, "capability");
|
|
3561
|
+
const kind = nonEmptyString(value.kind, "capability.kind");
|
|
3562
|
+
if (kind === "kv") {
|
|
3563
|
+
exactKeys(
|
|
3564
|
+
value,
|
|
3565
|
+
["kind", "resource", "selector", "actions"],
|
|
3566
|
+
"KV capability"
|
|
3567
|
+
);
|
|
3568
|
+
const resource = nonEmptyString(value.resource, "capability.resource");
|
|
3569
|
+
parseKvResource(resource);
|
|
3570
|
+
if (value.selector !== "exact" && value.selector !== "prefix")
|
|
3571
|
+
throw new Error("capability.selector is invalid");
|
|
3572
|
+
if (!Array.isArray(value.actions) || value.actions.length === 0)
|
|
3573
|
+
throw new Error("capability.actions is invalid");
|
|
3574
|
+
const actions = value.actions.map(
|
|
3575
|
+
(action) => nonEmptyString(action, "capability.actions[]")
|
|
3576
|
+
);
|
|
3577
|
+
if (new Set(actions).size !== actions.length || actions.some((action) => !KV_ACTIONS.has(action)))
|
|
3578
|
+
throw new Error("capability.actions is invalid");
|
|
3579
|
+
return {
|
|
3580
|
+
kind: "kv",
|
|
3581
|
+
resource,
|
|
3582
|
+
selector: value.selector,
|
|
3583
|
+
actions: [...actions].sort()
|
|
3584
|
+
};
|
|
3585
|
+
}
|
|
3586
|
+
if (kind === "encryption") {
|
|
3587
|
+
exactKeys(value, ["kind", "resource", "action"], "encryption capability");
|
|
3588
|
+
const resource = nonEmptyString(value.resource, "capability.resource");
|
|
3589
|
+
if (value.action !== "tinycloud.encryption/decrypt")
|
|
3590
|
+
throw new Error("encryption capability is invalid");
|
|
3591
|
+
parseEncryptionResource(resource);
|
|
3592
|
+
return {
|
|
3593
|
+
kind: "encryption",
|
|
3594
|
+
resource,
|
|
3595
|
+
action: "tinycloud.encryption/decrypt"
|
|
3596
|
+
};
|
|
3597
|
+
}
|
|
3598
|
+
throw new Error("capability.kind is invalid");
|
|
3599
|
+
}
|
|
3600
|
+
function canonicalizeUnifiedPolicyCapability(input) {
|
|
3601
|
+
return normalizeUnifiedPolicyCapability(input);
|
|
3602
|
+
}
|
|
3603
|
+
function unifiedPolicyCapabilityDigestHex(input) {
|
|
3604
|
+
return hex(
|
|
3605
|
+
(0, import_sha256.sha256)(
|
|
3606
|
+
new TextEncoder().encode(
|
|
3607
|
+
POLICY_CAPABILITY_V1_DOMAIN + jcsCanonicalize(normalizeUnifiedPolicyCapability(input))
|
|
3608
|
+
)
|
|
3609
|
+
)
|
|
3610
|
+
);
|
|
3611
|
+
}
|
|
3612
|
+
function unifiedPolicyCapabilityContains(authorityInput, requestedInput) {
|
|
3613
|
+
try {
|
|
3614
|
+
const authority = normalizeUnifiedPolicyCapability(authorityInput);
|
|
3615
|
+
const requested = normalizeUnifiedPolicyCapability(requestedInput);
|
|
3616
|
+
if (authority.kind !== requested.kind) return false;
|
|
3617
|
+
if (authority.kind === "encryption" && requested.kind === "encryption")
|
|
3618
|
+
return authority.resource === requested.resource && authority.action === requested.action;
|
|
3619
|
+
if (authority.kind !== "kv" || requested.kind !== "kv") return false;
|
|
3620
|
+
const { resource: authorized } = authority;
|
|
3621
|
+
const { resource: requestedResource } = requested;
|
|
3622
|
+
const pathContained = authority.selector === "exact" ? authorized === requestedResource : authorized === requestedResource || requestedResource.startsWith(`${authorized}/`);
|
|
3623
|
+
if (!pathContained || authority.selector === "exact" && requested.selector === "prefix")
|
|
3624
|
+
return false;
|
|
3625
|
+
return requested.actions.every(
|
|
3626
|
+
(action) => authority.actions.includes(action)
|
|
3627
|
+
);
|
|
3628
|
+
} catch {
|
|
3629
|
+
return false;
|
|
3630
|
+
}
|
|
3631
|
+
}
|
|
3632
|
+
function projectUnifiedPolicyCapability(input) {
|
|
3633
|
+
const capability = normalizeUnifiedPolicyCapability(input);
|
|
3634
|
+
if (capability.kind === "encryption") {
|
|
3635
|
+
return {
|
|
3636
|
+
service: "tinycloud.encryption",
|
|
3637
|
+
space: capability.resource,
|
|
3638
|
+
path: capability.resource,
|
|
3639
|
+
actions: [capability.action]
|
|
3640
|
+
};
|
|
3641
|
+
}
|
|
3642
|
+
const { space, path } = parseKvResource(capability.resource);
|
|
3643
|
+
return {
|
|
3644
|
+
service: "tinycloud.kv",
|
|
3645
|
+
space,
|
|
3646
|
+
path,
|
|
3647
|
+
actions: [...capability.actions],
|
|
3648
|
+
caveat: {
|
|
3649
|
+
type: "xyz.tinycloud.resource/selector",
|
|
3650
|
+
kind: capability.selector,
|
|
3651
|
+
value: capability.resource
|
|
3652
|
+
}
|
|
3653
|
+
};
|
|
3654
|
+
}
|
|
3655
|
+
function projectUnifiedPolicyCapabilities(input) {
|
|
3656
|
+
return input.map(projectUnifiedPolicyCapability).sort((left, right) => {
|
|
3657
|
+
const a = jcsCanonicalize(left);
|
|
3658
|
+
const b = jcsCanonicalize(right);
|
|
3659
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
3660
|
+
});
|
|
3661
|
+
}
|
|
3662
|
+
function unifiedNativeProjectionHashHex(input) {
|
|
3663
|
+
return hex(
|
|
3664
|
+
(0, import_sha256.sha256)(
|
|
3665
|
+
new TextEncoder().encode(
|
|
3666
|
+
NATIVE_PROJECTION_V1_DOMAIN + jcsCanonicalize(projectUnifiedPolicyCapabilities(input))
|
|
3667
|
+
)
|
|
3668
|
+
)
|
|
3669
|
+
);
|
|
3670
|
+
}
|
|
3671
|
+
function unifiedPolicyCapabilityFromNative(input) {
|
|
3672
|
+
const value = object(input, "native capability");
|
|
3673
|
+
exactKeys(
|
|
3674
|
+
value,
|
|
3675
|
+
["service", "space", "path", "actions", "caveat"],
|
|
3676
|
+
"native capability"
|
|
3677
|
+
);
|
|
3678
|
+
const service = nonEmptyString(value.service, "native.service");
|
|
3679
|
+
const actions = value.actions;
|
|
3680
|
+
if (!Array.isArray(actions)) throw new Error("native.actions is invalid");
|
|
3681
|
+
if (service === "tinycloud.encryption" && value.caveat === void 0 && value.space === value.path && actions.length === 1 && actions[0] === "tinycloud.encryption/decrypt") {
|
|
3682
|
+
return normalizeUnifiedPolicyCapability({
|
|
3683
|
+
kind: "encryption",
|
|
3684
|
+
resource: value.space,
|
|
3685
|
+
action: actions[0]
|
|
3686
|
+
});
|
|
3687
|
+
}
|
|
3688
|
+
if (service !== "tinycloud.kv" || typeof value.space !== "string" || typeof value.path !== "string")
|
|
3689
|
+
throw new Error("native capability is not supported");
|
|
3690
|
+
const caveat = object(value.caveat, "native.caveat");
|
|
3691
|
+
exactKeys(caveat, ["type", "kind", "value"], "native selector caveat");
|
|
3692
|
+
if (caveat.type !== "xyz.tinycloud.resource/selector" || caveat.kind !== "exact" && caveat.kind !== "prefix" || caveat.value !== `tinycloud://${value.space}/kv/${value.path}`)
|
|
3693
|
+
throw new Error("native selector caveat does not match capability");
|
|
3694
|
+
return normalizeUnifiedPolicyCapability({
|
|
3695
|
+
kind: "kv",
|
|
3696
|
+
resource: caveat.value,
|
|
3697
|
+
selector: caveat.kind,
|
|
3698
|
+
actions
|
|
3699
|
+
});
|
|
3700
|
+
}
|
|
3701
|
+
function contentSourceDigestHex(input) {
|
|
3702
|
+
return hex(
|
|
3703
|
+
(0, import_sha256.sha256)(
|
|
3704
|
+
new TextEncoder().encode(
|
|
3705
|
+
CONTENT_SOURCE_V1_DOMAIN + jcsCanonicalize(input)
|
|
3706
|
+
)
|
|
3707
|
+
)
|
|
3708
|
+
);
|
|
3709
|
+
}
|
|
3710
|
+
function policyDigestHex(policy) {
|
|
3711
|
+
const canonicalPolicy = {
|
|
3712
|
+
...policy,
|
|
3713
|
+
capabilityCeiling: policy.capabilityCeiling.map(
|
|
3714
|
+
normalizeUnifiedPolicyCapability
|
|
3715
|
+
)
|
|
3716
|
+
};
|
|
3717
|
+
return hex(
|
|
3718
|
+
(0, import_sha256.sha256)(
|
|
3719
|
+
new TextEncoder().encode(
|
|
3720
|
+
POLICY_V1_DOMAIN + jcsCanonicalize(canonicalPolicy)
|
|
3721
|
+
)
|
|
3722
|
+
)
|
|
3723
|
+
);
|
|
3724
|
+
}
|
|
3725
|
+
function policyIdForDigestHex(digestHex) {
|
|
3726
|
+
const digest2 = Uint8Array.from(
|
|
3727
|
+
(digestHex.match(/.{2}/g) ?? []).map((byte) => Number.parseInt(byte, 16))
|
|
3728
|
+
);
|
|
3729
|
+
if (digest2.length !== 32) throw new Error("policy digest must be 32 bytes");
|
|
3730
|
+
return `pol_${base32Lower(digest2)}`;
|
|
3731
|
+
}
|
|
3732
|
+
function policyCidFromCanonicalBytes(bytes) {
|
|
3733
|
+
return CID.createV1(85, create(18, (0, import_sha256.sha256)(bytes))).toString();
|
|
3734
|
+
}
|
|
3735
|
+
var CompactHeaderSchema = import_zod.z.object({
|
|
3736
|
+
alg: import_zod.z.literal("EdDSA"),
|
|
3737
|
+
jwk: import_zod.z.object({ alg: import_zod.z.literal("EdDSA"), crv: import_zod.z.literal("Ed25519"), kty: import_zod.z.literal("OKP"), x: import_zod.z.string().min(1) }).strict(),
|
|
3738
|
+
typ: import_zod.z.literal("JWT"),
|
|
3739
|
+
ucv: import_zod.z.literal("0.10.0")
|
|
3740
|
+
}).strict();
|
|
3741
|
+
var CompactPayloadSchema = import_zod.z.object({
|
|
3742
|
+
att: import_zod.z.record(import_zod.z.record(import_zod.z.array(import_zod.z.unknown()).min(1))),
|
|
3743
|
+
aud: import_zod.z.string().min(1),
|
|
3744
|
+
exp: import_zod.z.number().int(),
|
|
3745
|
+
fct: import_zod.z.array(import_zod.z.record(import_zod.z.unknown())).length(1),
|
|
3746
|
+
iss: import_zod.z.string().min(1),
|
|
3747
|
+
nbf: import_zod.z.number().int(),
|
|
3748
|
+
nnc: import_zod.z.string().min(1),
|
|
3749
|
+
prf: import_zod.z.array(import_zod.z.string().min(1))
|
|
3750
|
+
}).strict();
|
|
3751
|
+
async function signCompactUcanAuthorization(input) {
|
|
3752
|
+
if (input.notBefore >= input.expiresAt || input.expiresAt - input.notBefore > 60)
|
|
3753
|
+
throw new Error("compact invocation lifetime must be between one and 60 seconds");
|
|
3754
|
+
const principal = input.issuerDid.split("#", 1)[0];
|
|
3755
|
+
const didMaterial = principal.startsWith("did:key:") ? base58btc.decode(principal.slice("did:key:".length)) : new Uint8Array();
|
|
3756
|
+
if (didMaterial.length !== 34 || didMaterial[0] !== 237 || didMaterial[1] !== 1)
|
|
3757
|
+
throw new Error("compact UCAN signer must be did:key Ed25519");
|
|
3758
|
+
const header = { alg: "EdDSA", jwk: { alg: "EdDSA", crv: "Ed25519", kty: "OKP", x: encodeBase64Url(didMaterial.slice(2)) }, typ: "JWT", ucv: "0.10.0" };
|
|
3759
|
+
const payload = {
|
|
3760
|
+
att: input.attenuation,
|
|
3761
|
+
aud: input.audienceDid,
|
|
3762
|
+
exp: input.expiresAt,
|
|
3763
|
+
fct: input.facts,
|
|
3764
|
+
iss: input.issuerDid.includes("#") ? input.issuerDid : `${principal}#${principal.slice("did:key:".length)}`,
|
|
3765
|
+
nbf: input.notBefore,
|
|
3766
|
+
nnc: input.nonce,
|
|
3767
|
+
prf: input.proofs
|
|
3768
|
+
};
|
|
3769
|
+
const protectedSegment = encodeBase64Url(new TextEncoder().encode(jcsCanonicalize(header)));
|
|
3770
|
+
const payloadSegment = encodeBase64Url(new TextEncoder().encode(jcsCanonicalize(payload)));
|
|
3771
|
+
const signature = await input.sign(new TextEncoder().encode(`${protectedSegment}.${payloadSegment}`));
|
|
3772
|
+
if (signature.length !== 64) throw new Error("compact Authorization signature must be Ed25519");
|
|
3773
|
+
return parseCompactUcanAuthorization(`${protectedSegment}.${payloadSegment}.${encodeBase64Url(signature)}`);
|
|
3774
|
+
}
|
|
3775
|
+
function createCompactPolicyInvocation(input) {
|
|
3776
|
+
const session = parsePolicySessionUcan(input.sessionAuthorization);
|
|
3777
|
+
if (session.cid !== input.sessionCid || session.aud !== input.recipientDid)
|
|
3778
|
+
throw new Error("policy session does not bind the recipient signer");
|
|
3779
|
+
const principal = input.recipientDid.split("#", 1)[0];
|
|
3780
|
+
const didMaterial = base58btc.decode(principal.slice("did:key:".length));
|
|
3781
|
+
if (didMaterial.length !== 34 || didMaterial[0] !== 237 || didMaterial[1] !== 1)
|
|
3782
|
+
throw new Error("policy invocation signer must be did:key Ed25519");
|
|
3783
|
+
const publicKey = import_ed255192.ed25519.getPublicKey(input.privateKey);
|
|
3784
|
+
if (!equalBytes(publicKey, didMaterial.slice(2)))
|
|
3785
|
+
throw new Error("policy invocation private key does not bind recipient DID");
|
|
3786
|
+
const now = input.now ?? Math.floor(Date.now() / 1e3);
|
|
3787
|
+
const exp = Math.min(now + 60, session.exp);
|
|
3788
|
+
if (exp <= now) throw new Error("policy session has expired");
|
|
3789
|
+
const header = { alg: "EdDSA", jwk: { alg: "EdDSA", crv: "Ed25519", kty: "OKP", x: encodeBase64Url(publicKey) }, typ: "JWT", ucv: "0.10.0" };
|
|
3790
|
+
const payload = {
|
|
3791
|
+
att: { [input.resource]: { [input.action]: [input.caveat ?? {}] } },
|
|
3792
|
+
aud: input.audienceDid,
|
|
3793
|
+
exp,
|
|
3794
|
+
fct: [input.facts ?? { type: "tinycloud.policy.invocation/v1", policyCid: session.fact.policyCid, sessionCid: session.cid }],
|
|
3795
|
+
iss: input.recipientDid.includes("#") ? input.recipientDid : `${principal}#${principal.slice("did:key:".length)}`,
|
|
3796
|
+
nbf: now,
|
|
3797
|
+
nnc: input.nonce ?? encodeBase64Url(crypto.getRandomValues(new Uint8Array(16))),
|
|
3798
|
+
prf: [session.cid]
|
|
3799
|
+
};
|
|
3800
|
+
const protectedSegment = encodeBase64Url(new TextEncoder().encode(jcsCanonicalize(header)));
|
|
3801
|
+
const payloadSegment = encodeBase64Url(new TextEncoder().encode(jcsCanonicalize(payload)));
|
|
3802
|
+
const signingInput = new TextEncoder().encode(`${protectedSegment}.${payloadSegment}`);
|
|
3803
|
+
const signature = import_ed255192.ed25519.sign(signingInput, input.privateKey);
|
|
3804
|
+
return parseCompactUcanAuthorization(`${protectedSegment}.${payloadSegment}.${encodeBase64Url(signature)}`);
|
|
3805
|
+
}
|
|
3806
|
+
function createCompactPolicyDescendant(input) {
|
|
3807
|
+
const parent = parseCompactUcanAuthorization(input.parentAuthorization, input.parentCid);
|
|
3808
|
+
if (parent.payload.aud !== input.issuerDid) throw new Error("policy descendant issuer is not the parent audience");
|
|
3809
|
+
const parentFact = parent.payload.fct[0];
|
|
3810
|
+
const depth = parentFact.remainingRedelegationDepth;
|
|
3811
|
+
if (!Number.isInteger(depth) || depth <= 0) throw new Error("policy descendant depth is exhausted");
|
|
3812
|
+
if (!compactAttenuationContains(parent.payload.att, input.attenuation))
|
|
3813
|
+
throw new Error("policy descendant exceeds the parent attenuation");
|
|
3814
|
+
const principal = input.issuerDid.split("#", 1)[0];
|
|
3815
|
+
const didMaterial = base58btc.decode(principal.slice("did:key:".length));
|
|
3816
|
+
const publicKey = import_ed255192.ed25519.getPublicKey(input.privateKey);
|
|
3817
|
+
if (didMaterial.length !== 34 || !equalBytes(publicKey, didMaterial.slice(2))) throw new Error("policy descendant signer does not bind issuer DID");
|
|
3818
|
+
const now = Math.max(input.now ?? Math.floor(Date.now() / 1e3), parent.payload.nbf + 1);
|
|
3819
|
+
const exp = Math.min(input.expiresAt ?? now + 60, now + 60, parent.payload.exp - 1);
|
|
3820
|
+
if (exp <= now) throw new Error("policy parent has no strictly narrower validity window");
|
|
3821
|
+
const header = { alg: "EdDSA", jwk: { alg: "EdDSA", crv: "Ed25519", kty: "OKP", x: encodeBase64Url(publicKey) }, typ: "JWT", ucv: "0.10.0" };
|
|
3822
|
+
const payload = {
|
|
3823
|
+
att: input.attenuation,
|
|
3824
|
+
aud: input.audienceDid,
|
|
3825
|
+
exp,
|
|
3826
|
+
fct: [{ ...parentFact, remainingRedelegationDepth: depth - 1 }],
|
|
3827
|
+
iss: input.issuerDid.includes("#") ? input.issuerDid : `${principal}#${principal.slice("did:key:".length)}`,
|
|
3828
|
+
nbf: now,
|
|
3829
|
+
nnc: input.nonce ?? encodeBase64Url(crypto.getRandomValues(new Uint8Array(16))),
|
|
3830
|
+
prf: [parent.cid]
|
|
3831
|
+
};
|
|
3832
|
+
const protectedSegment = encodeBase64Url(new TextEncoder().encode(jcsCanonicalize(header)));
|
|
3833
|
+
const payloadSegment = encodeBase64Url(new TextEncoder().encode(jcsCanonicalize(payload)));
|
|
3834
|
+
const signature = import_ed255192.ed25519.sign(new TextEncoder().encode(`${protectedSegment}.${payloadSegment}`), input.privateKey);
|
|
3835
|
+
return parseCompactUcanAuthorization(`${protectedSegment}.${payloadSegment}.${encodeBase64Url(signature)}`);
|
|
3836
|
+
}
|
|
3837
|
+
function compactAttenuationContains(parent, child) {
|
|
3838
|
+
const selector = (value) => {
|
|
3839
|
+
if (value.length !== 1 || !isRecordValue(value[0])) return void 0;
|
|
3840
|
+
const caveat = value[0];
|
|
3841
|
+
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;
|
|
3842
|
+
return { kind: caveat.kind, value: caveat.value };
|
|
3843
|
+
};
|
|
3844
|
+
const equal = (left, right) => jcsCanonicalize(left) === jcsCanonicalize(right);
|
|
3845
|
+
return Object.entries(child).every(
|
|
3846
|
+
([childResource, childActions]) => Object.entries(childActions).every(
|
|
3847
|
+
([action, childCaveats]) => Object.entries(parent).some(([parentResource, parentActions]) => {
|
|
3848
|
+
const parentCaveats = parentActions[action];
|
|
3849
|
+
if (parentCaveats === void 0) return false;
|
|
3850
|
+
if (parentResource === childResource && equal(parentCaveats, childCaveats)) return true;
|
|
3851
|
+
const parentSelector = selector(parentCaveats);
|
|
3852
|
+
const childSelector = selector(childCaveats);
|
|
3853
|
+
return parentSelector?.kind === "prefix" && childSelector !== void 0 && parentSelector.value === parentResource && childSelector.value === childResource && (childResource === parentResource || childResource.startsWith(`${parentResource}/`));
|
|
3854
|
+
})
|
|
3855
|
+
)
|
|
3856
|
+
);
|
|
3857
|
+
}
|
|
3858
|
+
function isRecordValue(value) {
|
|
3859
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3860
|
+
}
|
|
3861
|
+
function parseCompactUcanAuthorization(input, expectedCid) {
|
|
3862
|
+
if (typeof input !== "string" || /\s/.test(input))
|
|
3863
|
+
throw new Error("Authorization must be compact UCAN bytes");
|
|
3864
|
+
const segments = input.split(".");
|
|
3865
|
+
if (segments.length !== 3 || segments.some((segment) => segment.length === 0))
|
|
3866
|
+
throw new Error("Authorization must have three compact segments");
|
|
3867
|
+
const [headerSegment, payloadSegment, signatureSegment] = segments;
|
|
3868
|
+
const headerBytes = decodeBase64Url(headerSegment);
|
|
3869
|
+
const payloadBytes = decodeBase64Url(payloadSegment);
|
|
3870
|
+
const signature = decodeBase64Url(signatureSegment);
|
|
3871
|
+
const headerValue = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(headerBytes));
|
|
3872
|
+
const payloadValue = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(payloadBytes));
|
|
3873
|
+
if (jcsCanonicalize(headerValue) !== new TextDecoder().decode(headerBytes) || jcsCanonicalize(payloadValue) !== new TextDecoder().decode(payloadBytes))
|
|
3874
|
+
throw new Error("compact UCAN segments are not canonical JCS");
|
|
3875
|
+
const header = CompactHeaderSchema.parse(headerValue);
|
|
3876
|
+
const payload = CompactPayloadSchema.parse(payloadValue);
|
|
3877
|
+
if (payload.nbf >= payload.exp) throw new Error("compact UCAN validity is empty");
|
|
3878
|
+
const principal = payload.iss.split("#", 1)[0];
|
|
3879
|
+
const didMaterial = principal.startsWith("did:key:") ? base58btc.decode(principal.slice("did:key:".length)) : new Uint8Array();
|
|
3880
|
+
if (didMaterial.length !== 34 || didMaterial[0] !== 237 || didMaterial[1] !== 1)
|
|
3881
|
+
throw new Error("compact UCAN issuer must be did:key Ed25519");
|
|
3882
|
+
const publicKey = didMaterial.slice(2);
|
|
3883
|
+
if (!equalBytes(publicKey, decodeBase64Url(header.jwk.x)))
|
|
3884
|
+
throw new Error("compact UCAN JWK does not bind issuer");
|
|
3885
|
+
if (!import_ed255192.ed25519.verify(signature, new TextEncoder().encode(`${headerSegment}.${payloadSegment}`), publicKey))
|
|
3886
|
+
throw new Error("compact UCAN signature is invalid");
|
|
3887
|
+
const cid = CID.createV1(85, create(30, (0, import_blake3.blake3)(new TextEncoder().encode(input)))).toString();
|
|
3888
|
+
if (expectedCid !== void 0 && cid !== expectedCid)
|
|
3889
|
+
throw new Error("compact UCAN CID does not match exact Authorization bytes");
|
|
3890
|
+
return { authorization: input, cid, header, payload };
|
|
3891
|
+
}
|
|
3892
|
+
function parsePolicySessionUcan(authorization, expectedProofs) {
|
|
3893
|
+
const parsed = parseCompactUcanAuthorization(authorization);
|
|
3894
|
+
const fact = parsed.payload.fct[0];
|
|
3895
|
+
if (parsed.payload.prf.length !== 2 || parsed.payload.prf[0] === parsed.payload.prf[1])
|
|
3896
|
+
throw new Error("policy session UCAN requires two distinct ordered proofs");
|
|
3897
|
+
if (expectedProofs !== void 0 && (parsed.payload.prf[0] !== expectedProofs[0] || parsed.payload.prf[1] !== expectedProofs[1]))
|
|
3898
|
+
throw new Error("policy session UCAN ordered proofs do not match");
|
|
3899
|
+
const factKeys = Object.keys(fact);
|
|
3900
|
+
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)))
|
|
3901
|
+
throw new Error("policy session UCAN fact is incomplete");
|
|
3902
|
+
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)
|
|
3903
|
+
throw new Error("policy session UCAN fact is invalid");
|
|
3904
|
+
return {
|
|
3905
|
+
authorization,
|
|
3906
|
+
cid: parsed.cid,
|
|
3907
|
+
iss: parsed.payload.iss,
|
|
3908
|
+
aud: parsed.payload.aud,
|
|
3909
|
+
prf: parsed.payload.prf,
|
|
3910
|
+
att: parsed.payload.att,
|
|
3911
|
+
nbf: parsed.payload.nbf,
|
|
3912
|
+
exp: parsed.payload.exp,
|
|
3913
|
+
nnc: parsed.payload.nnc,
|
|
3914
|
+
fact
|
|
3915
|
+
};
|
|
3916
|
+
}
|
|
3917
|
+
function decodeBase64Url(value) {
|
|
3918
|
+
if (!/^[A-Za-z0-9_-]+$/.test(value) || value.length % 4 === 1)
|
|
3919
|
+
throw new Error("value is not canonical base64url");
|
|
3920
|
+
const normalized = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
3921
|
+
const binary = typeof Buffer !== "undefined" ? Buffer.from(normalized, "base64").toString("binary") : atob(normalized.padEnd(Math.ceil(normalized.length / 4) * 4, "="));
|
|
3922
|
+
const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));
|
|
3923
|
+
const encoded = typeof Buffer !== "undefined" ? Buffer.from(bytes).toString("base64url") : btoa(String.fromCharCode(...bytes)).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
3924
|
+
if (encoded !== value) throw new Error("value is not canonical base64url");
|
|
3925
|
+
return bytes;
|
|
3926
|
+
}
|
|
3927
|
+
function encodeBase64Url(value) {
|
|
3928
|
+
return typeof Buffer !== "undefined" ? Buffer.from(value).toString("base64url") : btoa(String.fromCharCode(...value)).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
3929
|
+
}
|
|
3930
|
+
function equalBytes(left, right) {
|
|
3931
|
+
return left.length === right.length && left.every((byte, index) => byte === right[index]);
|
|
3932
|
+
}
|
|
3933
|
+
function hex(bytes) {
|
|
3934
|
+
return [...bytes].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
3935
|
+
}
|
|
3936
|
+
function base32Lower(bytes) {
|
|
3937
|
+
const alphabet2 = "abcdefghijklmnopqrstuvwxyz234567";
|
|
3938
|
+
let output = "";
|
|
3939
|
+
let buffer = 0;
|
|
3940
|
+
let bits = 0;
|
|
3941
|
+
for (const byte of bytes) {
|
|
3942
|
+
buffer = buffer << 8 | byte;
|
|
3943
|
+
bits += 8;
|
|
3944
|
+
while (bits >= 5) {
|
|
3945
|
+
output += alphabet2[buffer >>> bits - 5 & 31];
|
|
3946
|
+
bits -= 5;
|
|
3947
|
+
}
|
|
3948
|
+
}
|
|
3949
|
+
if (bits > 0) output += alphabet2[buffer << 5 - bits & 31];
|
|
3950
|
+
return output;
|
|
3259
3951
|
}
|
|
3260
3952
|
//# sourceMappingURL=index.cjs.map
|