@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
|
@@ -1271,6 +1271,7 @@ function validateSharingServiceConfig(data) {
|
|
|
1271
1271
|
|
|
1272
1272
|
// src/manifest.ts
|
|
1273
1273
|
import ms from "ms";
|
|
1274
|
+
import { ACCOUNT_MANIFEST_PERMISSIONS } from "@tinycloud/bootstrap";
|
|
1274
1275
|
import { resolveSecretPath, SECRET_NAME_RE } from "@tinycloud/sdk-services";
|
|
1275
1276
|
var SERVICE_SHORT_TO_LONG = Object.freeze({
|
|
1276
1277
|
kv: "tinycloud.kv",
|
|
@@ -2565,7 +2566,7 @@ var bases = { ...identity_exports, ...base2_exports, ...base8_exports, ...base10
|
|
|
2565
2566
|
var hashes = { ...sha2_browser_exports, ...identity_exports2 };
|
|
2566
2567
|
|
|
2567
2568
|
// src/delegations/SharingService.ts
|
|
2568
|
-
import { ed25519 as
|
|
2569
|
+
import { ed25519 as ed255194 } from "@noble/curves/ed25519";
|
|
2569
2570
|
|
|
2570
2571
|
// src/delegations/ShareRecipientClient.ts
|
|
2571
2572
|
import {
|
|
@@ -2573,8 +2574,8 @@ import {
|
|
|
2573
2574
|
KVService,
|
|
2574
2575
|
ServiceContext
|
|
2575
2576
|
} from "@tinycloud/sdk-services";
|
|
2576
|
-
import { ed25519 as
|
|
2577
|
-
import { sha256 as
|
|
2577
|
+
import { ed25519 as ed255193 } from "@noble/curves/ed25519";
|
|
2578
|
+
import { sha256 as sha2565 } from "@noble/hashes/sha256";
|
|
2578
2579
|
|
|
2579
2580
|
// src/delegations/share-envelope.ts
|
|
2580
2581
|
import { ed25519 } from "@noble/curves/ed25519";
|
|
@@ -3665,6 +3666,506 @@ var ShareNativeResponseSchema = z3.discriminatedUnion("action", [
|
|
|
3665
3666
|
}).strict()
|
|
3666
3667
|
]);
|
|
3667
3668
|
|
|
3669
|
+
// src/delegations/portable.ts
|
|
3670
|
+
import { z as z5 } from "zod";
|
|
3671
|
+
|
|
3672
|
+
// src/policy/unified.ts
|
|
3673
|
+
import { sha256 as sha2564 } from "@noble/hashes/sha256";
|
|
3674
|
+
import { blake3 as blake32 } from "@noble/hashes/blake3";
|
|
3675
|
+
import { ed25519 as ed255192 } from "@noble/curves/ed25519";
|
|
3676
|
+
import { z as z4 } from "zod";
|
|
3677
|
+
|
|
3678
|
+
// src/policy/errors.ts
|
|
3679
|
+
var SignedObjectProfileError = class extends Error {
|
|
3680
|
+
constructor(code3, message) {
|
|
3681
|
+
super(message);
|
|
3682
|
+
this.name = "SignedObjectProfileError";
|
|
3683
|
+
this.code = code3;
|
|
3684
|
+
}
|
|
3685
|
+
};
|
|
3686
|
+
var SignedObjectCanonicalizationError = class extends SignedObjectProfileError {
|
|
3687
|
+
constructor(message) {
|
|
3688
|
+
super("canonicalization-mismatch", message);
|
|
3689
|
+
this.name = "SignedObjectCanonicalizationError";
|
|
3690
|
+
}
|
|
3691
|
+
};
|
|
3692
|
+
|
|
3693
|
+
// src/policy/jcs.ts
|
|
3694
|
+
var objectHasOwn = Object.hasOwn ?? Object.prototype.hasOwnProperty.call.bind(
|
|
3695
|
+
Object.prototype.hasOwnProperty
|
|
3696
|
+
);
|
|
3697
|
+
function jcsCanonicalize(input) {
|
|
3698
|
+
return serialize(normalizeJson(input, "$"));
|
|
3699
|
+
}
|
|
3700
|
+
function normalizeJson(input, path = "$") {
|
|
3701
|
+
if (input === null) {
|
|
3702
|
+
return null;
|
|
3703
|
+
}
|
|
3704
|
+
switch (typeof input) {
|
|
3705
|
+
case "boolean":
|
|
3706
|
+
return input;
|
|
3707
|
+
case "number":
|
|
3708
|
+
if (!Number.isFinite(input)) {
|
|
3709
|
+
throw new SignedObjectCanonicalizationError(
|
|
3710
|
+
`${path} must be a finite JSON number`
|
|
3711
|
+
);
|
|
3712
|
+
}
|
|
3713
|
+
return input;
|
|
3714
|
+
case "string":
|
|
3715
|
+
assertUnicodeScalarString(input, path);
|
|
3716
|
+
return input;
|
|
3717
|
+
case "object":
|
|
3718
|
+
return normalizeJsonObjectOrArray(input, path);
|
|
3719
|
+
case "bigint":
|
|
3720
|
+
case "function":
|
|
3721
|
+
case "symbol":
|
|
3722
|
+
case "undefined":
|
|
3723
|
+
default:
|
|
3724
|
+
throw new SignedObjectCanonicalizationError(
|
|
3725
|
+
`${path} is not a JSON value`
|
|
3726
|
+
);
|
|
3727
|
+
}
|
|
3728
|
+
}
|
|
3729
|
+
function serialize(value) {
|
|
3730
|
+
if (value === null) {
|
|
3731
|
+
return "null";
|
|
3732
|
+
}
|
|
3733
|
+
switch (typeof value) {
|
|
3734
|
+
case "boolean":
|
|
3735
|
+
return value ? "true" : "false";
|
|
3736
|
+
case "number": {
|
|
3737
|
+
const encoded = JSON.stringify(value);
|
|
3738
|
+
if (encoded === void 0) {
|
|
3739
|
+
throw new SignedObjectCanonicalizationError(
|
|
3740
|
+
"number could not be serialized as JSON"
|
|
3741
|
+
);
|
|
3742
|
+
}
|
|
3743
|
+
return encoded;
|
|
3744
|
+
}
|
|
3745
|
+
case "string":
|
|
3746
|
+
return JSON.stringify(value);
|
|
3747
|
+
case "object":
|
|
3748
|
+
if (Array.isArray(value)) {
|
|
3749
|
+
return `[${value.map((item) => serialize(item)).join(",")}]`;
|
|
3750
|
+
}
|
|
3751
|
+
return serializeObject(value);
|
|
3752
|
+
default:
|
|
3753
|
+
throw new SignedObjectCanonicalizationError(
|
|
3754
|
+
`unsupported JSON value type ${typeof value}`
|
|
3755
|
+
);
|
|
3756
|
+
}
|
|
3757
|
+
}
|
|
3758
|
+
function normalizeJsonObjectOrArray(input, path) {
|
|
3759
|
+
assertNoSymbolKeys(input, path);
|
|
3760
|
+
if (Array.isArray(input)) {
|
|
3761
|
+
for (const key of Object.getOwnPropertyNames(input)) {
|
|
3762
|
+
if (key === "length") {
|
|
3763
|
+
continue;
|
|
3764
|
+
}
|
|
3765
|
+
if (!isArrayIndexKey(key, input.length)) {
|
|
3766
|
+
throw new SignedObjectCanonicalizationError(
|
|
3767
|
+
`${path}.${key} is not allowed on a JSON array`
|
|
3768
|
+
);
|
|
3769
|
+
}
|
|
3770
|
+
const descriptor = Object.getOwnPropertyDescriptor(input, key);
|
|
3771
|
+
if (descriptor?.enumerable !== true) {
|
|
3772
|
+
throw new SignedObjectCanonicalizationError(
|
|
3773
|
+
`${path}[${key}] must be an enumerable JSON array item`
|
|
3774
|
+
);
|
|
3775
|
+
}
|
|
3776
|
+
if (!("value" in descriptor)) {
|
|
3777
|
+
throw new SignedObjectCanonicalizationError(
|
|
3778
|
+
`${path}[${key}] must be a JSON data property`
|
|
3779
|
+
);
|
|
3780
|
+
}
|
|
3781
|
+
}
|
|
3782
|
+
const output2 = [];
|
|
3783
|
+
for (let index = 0; index < input.length; index++) {
|
|
3784
|
+
if (!objectHasOwn(input, index)) {
|
|
3785
|
+
throw new SignedObjectCanonicalizationError(
|
|
3786
|
+
`${path}[${index}] must not be a sparse array hole`
|
|
3787
|
+
);
|
|
3788
|
+
}
|
|
3789
|
+
output2.push(normalizeJson(input[index], `${path}[${index}]`));
|
|
3790
|
+
}
|
|
3791
|
+
return output2;
|
|
3792
|
+
}
|
|
3793
|
+
const proto = Object.getPrototypeOf(input);
|
|
3794
|
+
if (proto !== Object.prototype && proto !== null) {
|
|
3795
|
+
throw new SignedObjectCanonicalizationError(
|
|
3796
|
+
`${path} must be a plain JSON object`
|
|
3797
|
+
);
|
|
3798
|
+
}
|
|
3799
|
+
const output = /* @__PURE__ */ Object.create(null);
|
|
3800
|
+
for (const key of Object.getOwnPropertyNames(input)) {
|
|
3801
|
+
assertUnicodeScalarString(key, `${path} key`);
|
|
3802
|
+
if (key === "__proto__" || key === "constructor") {
|
|
3803
|
+
throw new SignedObjectCanonicalizationError(
|
|
3804
|
+
`${path}.${key} is not allowed`
|
|
3805
|
+
);
|
|
3806
|
+
}
|
|
3807
|
+
const descriptor = Object.getOwnPropertyDescriptor(input, key);
|
|
3808
|
+
if (descriptor?.enumerable !== true) {
|
|
3809
|
+
throw new SignedObjectCanonicalizationError(
|
|
3810
|
+
`${path}.${key} must be an enumerable JSON object property`
|
|
3811
|
+
);
|
|
3812
|
+
}
|
|
3813
|
+
if (!("value" in descriptor)) {
|
|
3814
|
+
throw new SignedObjectCanonicalizationError(
|
|
3815
|
+
`${path}.${key} must be a JSON data property`
|
|
3816
|
+
);
|
|
3817
|
+
}
|
|
3818
|
+
const value = descriptor.value;
|
|
3819
|
+
output[key] = normalizeJson(value, `${path}.${key}`);
|
|
3820
|
+
}
|
|
3821
|
+
return output;
|
|
3822
|
+
}
|
|
3823
|
+
function assertNoSymbolKeys(input, path) {
|
|
3824
|
+
if (Object.getOwnPropertySymbols(input).length > 0) {
|
|
3825
|
+
throw new SignedObjectCanonicalizationError(
|
|
3826
|
+
`${path} must not have symbol properties`
|
|
3827
|
+
);
|
|
3828
|
+
}
|
|
3829
|
+
}
|
|
3830
|
+
function isArrayIndexKey(key, length2) {
|
|
3831
|
+
if (!/^(0|[1-9]\d*)$/.test(key)) {
|
|
3832
|
+
return false;
|
|
3833
|
+
}
|
|
3834
|
+
const index = Number(key);
|
|
3835
|
+
return Number.isSafeInteger(index) && index >= 0 && index < length2;
|
|
3836
|
+
}
|
|
3837
|
+
function serializeObject(value) {
|
|
3838
|
+
const keys = Object.keys(value).sort(compareUtf16CodeUnits);
|
|
3839
|
+
const parts = keys.map((key) => `${JSON.stringify(key)}:${serialize(value[key])}`);
|
|
3840
|
+
return `{${parts.join(",")}}`;
|
|
3841
|
+
}
|
|
3842
|
+
function compareUtf16CodeUnits(a, b) {
|
|
3843
|
+
const max = Math.min(a.length, b.length);
|
|
3844
|
+
for (let index = 0; index < max; index++) {
|
|
3845
|
+
const leftCodeUnit = a.charCodeAt(index);
|
|
3846
|
+
const rightCodeUnit = b.charCodeAt(index);
|
|
3847
|
+
if (leftCodeUnit !== rightCodeUnit) {
|
|
3848
|
+
return leftCodeUnit - rightCodeUnit;
|
|
3849
|
+
}
|
|
3850
|
+
}
|
|
3851
|
+
return a.length - b.length;
|
|
3852
|
+
}
|
|
3853
|
+
function assertUnicodeScalarString(value, path) {
|
|
3854
|
+
for (let index = 0; index < value.length; index++) {
|
|
3855
|
+
const code3 = value.charCodeAt(index);
|
|
3856
|
+
if (code3 >= 55296 && code3 <= 56319) {
|
|
3857
|
+
const next = value.charCodeAt(index + 1);
|
|
3858
|
+
if (Number.isNaN(next) || next < 56320 || next > 57343) {
|
|
3859
|
+
throw new SignedObjectCanonicalizationError(
|
|
3860
|
+
`${path} contains a lone high surrogate`
|
|
3861
|
+
);
|
|
3862
|
+
}
|
|
3863
|
+
index++;
|
|
3864
|
+
continue;
|
|
3865
|
+
}
|
|
3866
|
+
if (code3 >= 56320 && code3 <= 57343) {
|
|
3867
|
+
throw new SignedObjectCanonicalizationError(
|
|
3868
|
+
`${path} contains a lone low surrogate`
|
|
3869
|
+
);
|
|
3870
|
+
}
|
|
3871
|
+
}
|
|
3872
|
+
}
|
|
3873
|
+
|
|
3874
|
+
// src/policy/unified.ts
|
|
3875
|
+
var POLICY_SESSION_UCAN_V1_PROFILE = "policy-session-ucan/v1";
|
|
3876
|
+
var POLICY_SESSION_FACT_KEYS = [
|
|
3877
|
+
"profile",
|
|
3878
|
+
"ownerDid",
|
|
3879
|
+
"policyId",
|
|
3880
|
+
"policyDigestHex",
|
|
3881
|
+
"policyCid",
|
|
3882
|
+
"policyDelegationCid",
|
|
3883
|
+
"enforcementDelegationCid",
|
|
3884
|
+
"contentSourceDigestHex",
|
|
3885
|
+
"capabilityCeilingHashHex",
|
|
3886
|
+
"nativeProjectionHashHex",
|
|
3887
|
+
"enforcerDid",
|
|
3888
|
+
"nodeAudience",
|
|
3889
|
+
"recipientDid",
|
|
3890
|
+
"challengeId",
|
|
3891
|
+
"claimDigestHex",
|
|
3892
|
+
"claimJti",
|
|
3893
|
+
"vpDigestHex",
|
|
3894
|
+
"credentialEvidenceDigestHex",
|
|
3895
|
+
"decisionContextDigestHex",
|
|
3896
|
+
"issuanceAuditDigestHex",
|
|
3897
|
+
"remainingRedelegationDepth"
|
|
3898
|
+
];
|
|
3899
|
+
var CompactHeaderSchema = z4.object({
|
|
3900
|
+
alg: z4.literal("EdDSA"),
|
|
3901
|
+
jwk: z4.object({ alg: z4.literal("EdDSA"), crv: z4.literal("Ed25519"), kty: z4.literal("OKP"), x: z4.string().min(1) }).strict(),
|
|
3902
|
+
typ: z4.literal("JWT"),
|
|
3903
|
+
ucv: z4.literal("0.10.0")
|
|
3904
|
+
}).strict();
|
|
3905
|
+
var CompactPayloadSchema = z4.object({
|
|
3906
|
+
att: z4.record(z4.record(z4.array(z4.unknown()).min(1))),
|
|
3907
|
+
aud: z4.string().min(1),
|
|
3908
|
+
exp: z4.number().int(),
|
|
3909
|
+
fct: z4.array(z4.record(z4.unknown())).length(1),
|
|
3910
|
+
iss: z4.string().min(1),
|
|
3911
|
+
nbf: z4.number().int(),
|
|
3912
|
+
nnc: z4.string().min(1),
|
|
3913
|
+
prf: z4.array(z4.string().min(1))
|
|
3914
|
+
}).strict();
|
|
3915
|
+
function createCompactPolicyInvocation(input) {
|
|
3916
|
+
const session = parsePolicySessionUcan(input.sessionAuthorization);
|
|
3917
|
+
if (session.cid !== input.sessionCid || session.aud !== input.recipientDid)
|
|
3918
|
+
throw new Error("policy session does not bind the recipient signer");
|
|
3919
|
+
const principal = input.recipientDid.split("#", 1)[0];
|
|
3920
|
+
const didMaterial = base58btc.decode(principal.slice("did:key:".length));
|
|
3921
|
+
if (didMaterial.length !== 34 || didMaterial[0] !== 237 || didMaterial[1] !== 1)
|
|
3922
|
+
throw new Error("policy invocation signer must be did:key Ed25519");
|
|
3923
|
+
const publicKey = ed255192.getPublicKey(input.privateKey);
|
|
3924
|
+
if (!equalBytes2(publicKey, didMaterial.slice(2)))
|
|
3925
|
+
throw new Error("policy invocation private key does not bind recipient DID");
|
|
3926
|
+
const now = input.now ?? Math.floor(Date.now() / 1e3);
|
|
3927
|
+
const exp = Math.min(now + 60, session.exp);
|
|
3928
|
+
if (exp <= now) throw new Error("policy session has expired");
|
|
3929
|
+
const header = { alg: "EdDSA", jwk: { alg: "EdDSA", crv: "Ed25519", kty: "OKP", x: encodeBase64Url(publicKey) }, typ: "JWT", ucv: "0.10.0" };
|
|
3930
|
+
const payload = {
|
|
3931
|
+
att: { [input.resource]: { [input.action]: [input.caveat ?? {}] } },
|
|
3932
|
+
aud: input.audienceDid,
|
|
3933
|
+
exp,
|
|
3934
|
+
fct: [input.facts ?? { type: "tinycloud.policy.invocation/v1", policyCid: session.fact.policyCid, sessionCid: session.cid }],
|
|
3935
|
+
iss: input.recipientDid.includes("#") ? input.recipientDid : `${principal}#${principal.slice("did:key:".length)}`,
|
|
3936
|
+
nbf: now,
|
|
3937
|
+
nnc: input.nonce ?? encodeBase64Url(crypto.getRandomValues(new Uint8Array(16))),
|
|
3938
|
+
prf: [session.cid]
|
|
3939
|
+
};
|
|
3940
|
+
const protectedSegment = encodeBase64Url(new TextEncoder().encode(jcsCanonicalize(header)));
|
|
3941
|
+
const payloadSegment = encodeBase64Url(new TextEncoder().encode(jcsCanonicalize(payload)));
|
|
3942
|
+
const signingInput = new TextEncoder().encode(`${protectedSegment}.${payloadSegment}`);
|
|
3943
|
+
const signature = ed255192.sign(signingInput, input.privateKey);
|
|
3944
|
+
return parseCompactUcanAuthorization(`${protectedSegment}.${payloadSegment}.${encodeBase64Url(signature)}`);
|
|
3945
|
+
}
|
|
3946
|
+
function createCompactPolicyDescendant(input) {
|
|
3947
|
+
const parent = parseCompactUcanAuthorization(input.parentAuthorization, input.parentCid);
|
|
3948
|
+
if (parent.payload.aud !== input.issuerDid) throw new Error("policy descendant issuer is not the parent audience");
|
|
3949
|
+
const parentFact = parent.payload.fct[0];
|
|
3950
|
+
const depth = parentFact.remainingRedelegationDepth;
|
|
3951
|
+
if (!Number.isInteger(depth) || depth <= 0) throw new Error("policy descendant depth is exhausted");
|
|
3952
|
+
if (!compactAttenuationContains(parent.payload.att, input.attenuation))
|
|
3953
|
+
throw new Error("policy descendant exceeds the parent attenuation");
|
|
3954
|
+
const principal = input.issuerDid.split("#", 1)[0];
|
|
3955
|
+
const didMaterial = base58btc.decode(principal.slice("did:key:".length));
|
|
3956
|
+
const publicKey = ed255192.getPublicKey(input.privateKey);
|
|
3957
|
+
if (didMaterial.length !== 34 || !equalBytes2(publicKey, didMaterial.slice(2))) throw new Error("policy descendant signer does not bind issuer DID");
|
|
3958
|
+
const now = Math.max(input.now ?? Math.floor(Date.now() / 1e3), parent.payload.nbf + 1);
|
|
3959
|
+
const exp = Math.min(input.expiresAt ?? now + 60, now + 60, parent.payload.exp - 1);
|
|
3960
|
+
if (exp <= now) throw new Error("policy parent has no strictly narrower validity window");
|
|
3961
|
+
const header = { alg: "EdDSA", jwk: { alg: "EdDSA", crv: "Ed25519", kty: "OKP", x: encodeBase64Url(publicKey) }, typ: "JWT", ucv: "0.10.0" };
|
|
3962
|
+
const payload = {
|
|
3963
|
+
att: input.attenuation,
|
|
3964
|
+
aud: input.audienceDid,
|
|
3965
|
+
exp,
|
|
3966
|
+
fct: [{ ...parentFact, remainingRedelegationDepth: depth - 1 }],
|
|
3967
|
+
iss: input.issuerDid.includes("#") ? input.issuerDid : `${principal}#${principal.slice("did:key:".length)}`,
|
|
3968
|
+
nbf: now,
|
|
3969
|
+
nnc: input.nonce ?? encodeBase64Url(crypto.getRandomValues(new Uint8Array(16))),
|
|
3970
|
+
prf: [parent.cid]
|
|
3971
|
+
};
|
|
3972
|
+
const protectedSegment = encodeBase64Url(new TextEncoder().encode(jcsCanonicalize(header)));
|
|
3973
|
+
const payloadSegment = encodeBase64Url(new TextEncoder().encode(jcsCanonicalize(payload)));
|
|
3974
|
+
const signature = ed255192.sign(new TextEncoder().encode(`${protectedSegment}.${payloadSegment}`), input.privateKey);
|
|
3975
|
+
return parseCompactUcanAuthorization(`${protectedSegment}.${payloadSegment}.${encodeBase64Url(signature)}`);
|
|
3976
|
+
}
|
|
3977
|
+
function compactAttenuationContains(parent, child) {
|
|
3978
|
+
const selector = (value) => {
|
|
3979
|
+
if (value.length !== 1 || !isRecordValue(value[0])) return void 0;
|
|
3980
|
+
const caveat = value[0];
|
|
3981
|
+
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;
|
|
3982
|
+
return { kind: caveat.kind, value: caveat.value };
|
|
3983
|
+
};
|
|
3984
|
+
const equal = (left, right) => jcsCanonicalize(left) === jcsCanonicalize(right);
|
|
3985
|
+
return Object.entries(child).every(
|
|
3986
|
+
([childResource, childActions]) => Object.entries(childActions).every(
|
|
3987
|
+
([action, childCaveats]) => Object.entries(parent).some(([parentResource, parentActions]) => {
|
|
3988
|
+
const parentCaveats = parentActions[action];
|
|
3989
|
+
if (parentCaveats === void 0) return false;
|
|
3990
|
+
if (parentResource === childResource && equal(parentCaveats, childCaveats)) return true;
|
|
3991
|
+
const parentSelector = selector(parentCaveats);
|
|
3992
|
+
const childSelector = selector(childCaveats);
|
|
3993
|
+
return parentSelector?.kind === "prefix" && childSelector !== void 0 && parentSelector.value === parentResource && childSelector.value === childResource && (childResource === parentResource || childResource.startsWith(`${parentResource}/`));
|
|
3994
|
+
})
|
|
3995
|
+
)
|
|
3996
|
+
);
|
|
3997
|
+
}
|
|
3998
|
+
function isRecordValue(value) {
|
|
3999
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4000
|
+
}
|
|
4001
|
+
function parseCompactUcanAuthorization(input, expectedCid) {
|
|
4002
|
+
if (typeof input !== "string" || /\s/.test(input))
|
|
4003
|
+
throw new Error("Authorization must be compact UCAN bytes");
|
|
4004
|
+
const segments = input.split(".");
|
|
4005
|
+
if (segments.length !== 3 || segments.some((segment) => segment.length === 0))
|
|
4006
|
+
throw new Error("Authorization must have three compact segments");
|
|
4007
|
+
const [headerSegment, payloadSegment, signatureSegment] = segments;
|
|
4008
|
+
const headerBytes = decodeBase64Url(headerSegment);
|
|
4009
|
+
const payloadBytes = decodeBase64Url(payloadSegment);
|
|
4010
|
+
const signature = decodeBase64Url(signatureSegment);
|
|
4011
|
+
const headerValue = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(headerBytes));
|
|
4012
|
+
const payloadValue = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(payloadBytes));
|
|
4013
|
+
if (jcsCanonicalize(headerValue) !== new TextDecoder().decode(headerBytes) || jcsCanonicalize(payloadValue) !== new TextDecoder().decode(payloadBytes))
|
|
4014
|
+
throw new Error("compact UCAN segments are not canonical JCS");
|
|
4015
|
+
const header = CompactHeaderSchema.parse(headerValue);
|
|
4016
|
+
const payload = CompactPayloadSchema.parse(payloadValue);
|
|
4017
|
+
if (payload.nbf >= payload.exp) throw new Error("compact UCAN validity is empty");
|
|
4018
|
+
const principal = payload.iss.split("#", 1)[0];
|
|
4019
|
+
const didMaterial = principal.startsWith("did:key:") ? base58btc.decode(principal.slice("did:key:".length)) : new Uint8Array();
|
|
4020
|
+
if (didMaterial.length !== 34 || didMaterial[0] !== 237 || didMaterial[1] !== 1)
|
|
4021
|
+
throw new Error("compact UCAN issuer must be did:key Ed25519");
|
|
4022
|
+
const publicKey = didMaterial.slice(2);
|
|
4023
|
+
if (!equalBytes2(publicKey, decodeBase64Url(header.jwk.x)))
|
|
4024
|
+
throw new Error("compact UCAN JWK does not bind issuer");
|
|
4025
|
+
if (!ed255192.verify(signature, new TextEncoder().encode(`${headerSegment}.${payloadSegment}`), publicKey))
|
|
4026
|
+
throw new Error("compact UCAN signature is invalid");
|
|
4027
|
+
const cid2 = CID.createV1(85, create(30, blake32(new TextEncoder().encode(input)))).toString();
|
|
4028
|
+
if (expectedCid !== void 0 && cid2 !== expectedCid)
|
|
4029
|
+
throw new Error("compact UCAN CID does not match exact Authorization bytes");
|
|
4030
|
+
return { authorization: input, cid: cid2, header, payload };
|
|
4031
|
+
}
|
|
4032
|
+
function parsePolicySessionUcan(authorization, expectedProofs) {
|
|
4033
|
+
const parsed = parseCompactUcanAuthorization(authorization);
|
|
4034
|
+
const fact = parsed.payload.fct[0];
|
|
4035
|
+
if (parsed.payload.prf.length !== 2 || parsed.payload.prf[0] === parsed.payload.prf[1])
|
|
4036
|
+
throw new Error("policy session UCAN requires two distinct ordered proofs");
|
|
4037
|
+
if (expectedProofs !== void 0 && (parsed.payload.prf[0] !== expectedProofs[0] || parsed.payload.prf[1] !== expectedProofs[1]))
|
|
4038
|
+
throw new Error("policy session UCAN ordered proofs do not match");
|
|
4039
|
+
const factKeys = Object.keys(fact);
|
|
4040
|
+
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)))
|
|
4041
|
+
throw new Error("policy session UCAN fact is incomplete");
|
|
4042
|
+
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)
|
|
4043
|
+
throw new Error("policy session UCAN fact is invalid");
|
|
4044
|
+
return {
|
|
4045
|
+
authorization,
|
|
4046
|
+
cid: parsed.cid,
|
|
4047
|
+
iss: parsed.payload.iss,
|
|
4048
|
+
aud: parsed.payload.aud,
|
|
4049
|
+
prf: parsed.payload.prf,
|
|
4050
|
+
att: parsed.payload.att,
|
|
4051
|
+
nbf: parsed.payload.nbf,
|
|
4052
|
+
exp: parsed.payload.exp,
|
|
4053
|
+
nnc: parsed.payload.nnc,
|
|
4054
|
+
fact
|
|
4055
|
+
};
|
|
4056
|
+
}
|
|
4057
|
+
function decodeBase64Url(value) {
|
|
4058
|
+
if (!/^[A-Za-z0-9_-]+$/.test(value) || value.length % 4 === 1)
|
|
4059
|
+
throw new Error("value is not canonical base64url");
|
|
4060
|
+
const normalized = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
4061
|
+
const binary = typeof Buffer !== "undefined" ? Buffer.from(normalized, "base64").toString("binary") : atob(normalized.padEnd(Math.ceil(normalized.length / 4) * 4, "="));
|
|
4062
|
+
const bytes2 = Uint8Array.from(binary, (character) => character.charCodeAt(0));
|
|
4063
|
+
const encoded = typeof Buffer !== "undefined" ? Buffer.from(bytes2).toString("base64url") : btoa(String.fromCharCode(...bytes2)).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
4064
|
+
if (encoded !== value) throw new Error("value is not canonical base64url");
|
|
4065
|
+
return bytes2;
|
|
4066
|
+
}
|
|
4067
|
+
function encodeBase64Url(value) {
|
|
4068
|
+
return typeof Buffer !== "undefined" ? Buffer.from(value).toString("base64url") : btoa(String.fromCharCode(...value)).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
4069
|
+
}
|
|
4070
|
+
function equalBytes2(left, right) {
|
|
4071
|
+
return left.length === right.length && left.every((byte, index) => byte === right[index]);
|
|
4072
|
+
}
|
|
4073
|
+
|
|
4074
|
+
// src/delegations/portable.ts
|
|
4075
|
+
var ResourceSchema = z5.object({
|
|
4076
|
+
service: z5.string().min(1),
|
|
4077
|
+
space: z5.string().min(1),
|
|
4078
|
+
path: z5.string(),
|
|
4079
|
+
actions: z5.array(z5.string().min(1)).min(1),
|
|
4080
|
+
caveats: z5.array(z5.record(z5.unknown())).optional()
|
|
4081
|
+
}).strict();
|
|
4082
|
+
var PortableDelegationSchema = z5.object({
|
|
4083
|
+
cid: z5.string().min(1),
|
|
4084
|
+
delegationHeader: z5.object({ Authorization: z5.string().min(1) }).strict(),
|
|
4085
|
+
ownerAddress: z5.string().min(1),
|
|
4086
|
+
chainId: z5.number().int().nonnegative(),
|
|
4087
|
+
host: z5.string().url().optional(),
|
|
4088
|
+
spaceId: z5.string().min(1),
|
|
4089
|
+
path: z5.string(),
|
|
4090
|
+
actions: z5.array(z5.string().min(1)).min(1),
|
|
4091
|
+
caveats: z5.array(z5.record(z5.unknown())).optional(),
|
|
4092
|
+
expiry: z5.coerce.date(),
|
|
4093
|
+
delegateDID: z5.string().min(1),
|
|
4094
|
+
delegatorDID: z5.string().min(1).optional(),
|
|
4095
|
+
parentCid: z5.string().min(1).optional(),
|
|
4096
|
+
disableSubDelegation: z5.boolean().optional(),
|
|
4097
|
+
resources: z5.array(ResourceSchema).min(1).optional()
|
|
4098
|
+
}).strict();
|
|
4099
|
+
function parsePortableDelegation(input) {
|
|
4100
|
+
const parsed = PortableDelegationSchema.parse(input);
|
|
4101
|
+
if (parsed.resources !== void 0 && parsed.resources.length === 0)
|
|
4102
|
+
throw new Error("portable delegation resources must not be empty");
|
|
4103
|
+
return parsed;
|
|
4104
|
+
}
|
|
4105
|
+
function serializePortableDelegation(delegation) {
|
|
4106
|
+
return JSON.stringify({
|
|
4107
|
+
...delegation,
|
|
4108
|
+
expiry: delegation.expiry.toISOString()
|
|
4109
|
+
});
|
|
4110
|
+
}
|
|
4111
|
+
async function importPortableDelegation(fetchFn, host, delegation) {
|
|
4112
|
+
const parsed = parsePortableDelegation(delegation);
|
|
4113
|
+
const response = await fetchFn(`${host.replace(/\/+$/, "")}/delegate`, {
|
|
4114
|
+
method: "POST",
|
|
4115
|
+
headers: { Authorization: parsed.delegationHeader.Authorization }
|
|
4116
|
+
});
|
|
4117
|
+
if (!response.ok)
|
|
4118
|
+
throw new Error(`node rejected delegation import (${response.status})`);
|
|
4119
|
+
const body = await response.json().catch(() => ({}));
|
|
4120
|
+
if (body === null || typeof body !== "object" || Array.isArray(body))
|
|
4121
|
+
return {};
|
|
4122
|
+
return body;
|
|
4123
|
+
}
|
|
4124
|
+
async function delegatePortablePolicySession(input) {
|
|
4125
|
+
const parent = parsePortableDelegation(input.parent);
|
|
4126
|
+
const descendant = createCompactPolicyDescendant({
|
|
4127
|
+
parentAuthorization: parent.delegationHeader.Authorization.replace(/^Bearer\s+/i, ""),
|
|
4128
|
+
parentCid: parent.cid,
|
|
4129
|
+
issuerDid: parent.delegateDID,
|
|
4130
|
+
audienceDid: input.delegateDID,
|
|
4131
|
+
attenuation: input.attenuation,
|
|
4132
|
+
privateKey: input.issuerPrivateKey,
|
|
4133
|
+
...input.now === void 0 ? {} : { now: input.now },
|
|
4134
|
+
...input.expiresAt === void 0 ? {} : { expiresAt: input.expiresAt },
|
|
4135
|
+
...input.nonce === void 0 ? {} : { nonce: input.nonce }
|
|
4136
|
+
});
|
|
4137
|
+
const resources = Object.entries(descendant.payload.att).map(([resource, abilities]) => {
|
|
4138
|
+
const actions = Object.keys(abilities);
|
|
4139
|
+
if (resource.startsWith("urn:tinycloud:encryption:")) {
|
|
4140
|
+
return { service: "encryption", space: "encryption", path: resource, actions };
|
|
4141
|
+
}
|
|
4142
|
+
const match = /^tinycloud:\/\/([^/]+)\/kv\/(.+)$/.exec(resource);
|
|
4143
|
+
if (match === null) throw new Error("policy descendant resource is invalid");
|
|
4144
|
+
const caveats = Object.values(abilities).flat().filter((value) => value !== null && typeof value === "object" && !Array.isArray(value));
|
|
4145
|
+
return { service: "kv", space: match[1], path: match[2], actions, ...caveats.length === 0 ? {} : { caveats } };
|
|
4146
|
+
});
|
|
4147
|
+
const primary = resources.find((resource) => resource.service === "kv") ?? resources[0];
|
|
4148
|
+
if (primary === void 0) throw new Error("policy descendant attenuation is empty");
|
|
4149
|
+
const portable = {
|
|
4150
|
+
cid: descendant.cid,
|
|
4151
|
+
delegationHeader: { Authorization: descendant.authorization },
|
|
4152
|
+
ownerAddress: parent.ownerAddress,
|
|
4153
|
+
chainId: parent.chainId,
|
|
4154
|
+
host: input.host,
|
|
4155
|
+
spaceId: primary.space,
|
|
4156
|
+
path: primary.path,
|
|
4157
|
+
actions: primary.actions,
|
|
4158
|
+
expiry: new Date(descendant.payload.exp * 1e3),
|
|
4159
|
+
delegateDID: input.delegateDID,
|
|
4160
|
+
delegatorDID: parent.delegateDID,
|
|
4161
|
+
parentCid: parent.cid,
|
|
4162
|
+
disableSubDelegation: descendant.payload.fct[0]?.remainingRedelegationDepth === 0,
|
|
4163
|
+
resources
|
|
4164
|
+
};
|
|
4165
|
+
await importPortableDelegation(input.fetch, input.host, portable);
|
|
4166
|
+
return portable;
|
|
4167
|
+
}
|
|
4168
|
+
|
|
3668
4169
|
// src/delegations/ShareRecipientClient.ts
|
|
3669
4170
|
var DEFAULT_MAX_ARTIFACT_BYTES2 = MAX_SHARE_ARTIFACT_BYTES;
|
|
3670
4171
|
var DEFAULT_MAX_CONTENT_BYTES = MAX_SHARE_CONTENT_BYTES;
|
|
@@ -3740,7 +4241,7 @@ function randomJti() {
|
|
|
3740
4241
|
return bytesToBase64Url2(bytes2);
|
|
3741
4242
|
}
|
|
3742
4243
|
function digestCanonical(value) {
|
|
3743
|
-
return bytesToBase64Url2(
|
|
4244
|
+
return bytesToBase64Url2(sha2565(new TextEncoder().encode(canonicalJsonForProof(value))));
|
|
3744
4245
|
}
|
|
3745
4246
|
function actionWire(action) {
|
|
3746
4247
|
return action === "get" ? "tinycloud.kv/get" : action === "metadata" ? "tinycloud.kv/metadata" : action === "list" ? "tinycloud.kv/list" : "tinycloud.kv/put";
|
|
@@ -3852,9 +4353,31 @@ var ShareRecipientClient = class {
|
|
|
3852
4353
|
if (policy && this.options.bearerSession !== void 0) throw new ShareAccessError("SHARE_POLICY_BEARER_MISMATCH");
|
|
3853
4354
|
if (bearer && this.options.presentation !== void 0) throw new ShareAccessError("SHARE_BEARER_PRESENTATION_MISMATCH");
|
|
3854
4355
|
const session = bearer || legacyBearer ? this.options.bearerSession : recipientDidSession ? recipientDidSession : policy && this.options.establishPolicySession !== void 0 ? await this.options.establishPolicySession({ envelope, presentation: this.options.presentation }) : policy ? await this.establishPolicySession(envelope) : void 0;
|
|
3855
|
-
const kv = bearer || legacyBearer ? session === void 0 ? void 0 : this.createKV(envelope.origin, session) : void 0;
|
|
3856
4356
|
const policySession = policy ? session : void 0;
|
|
3857
4357
|
if (policySession !== void 0) this.assertProvidedPolicySession(policySession, envelope);
|
|
4358
|
+
const portableDelegation = policySession === void 0 ? void 0 : this.policySessionDelegation(policySession, envelope.origin);
|
|
4359
|
+
const portableInvoke = portableDelegation === void 0 ? void 0 : this.policyInvocationSigner(portableDelegation);
|
|
4360
|
+
if (portableDelegation !== void 0) {
|
|
4361
|
+
if (this.options.importDelegation === void 0) {
|
|
4362
|
+
await importPortableDelegation(this.fetchFn, envelope.origin, portableDelegation);
|
|
4363
|
+
} else {
|
|
4364
|
+
const imported = await this.options.importDelegation(portableDelegation);
|
|
4365
|
+
if (imported !== void 0) {
|
|
4366
|
+
const normalized = parsePortableDelegation(imported);
|
|
4367
|
+
if (normalized.delegationHeader.Authorization !== portableDelegation.delegationHeader.Authorization) {
|
|
4368
|
+
throw new ShareAccessError("SHARE_SESSION_INVALID", "delegation importer changed authorization bytes");
|
|
4369
|
+
}
|
|
4370
|
+
}
|
|
4371
|
+
}
|
|
4372
|
+
}
|
|
4373
|
+
const ordinarySession = portableDelegation === void 0 ? void 0 : {
|
|
4374
|
+
delegationHeader: portableDelegation.delegationHeader,
|
|
4375
|
+
delegationCid: portableDelegation.cid,
|
|
4376
|
+
spaceId: this.policySessionProjection(portableDelegation).spaceId,
|
|
4377
|
+
verificationMethod: portableDelegation.delegateDID,
|
|
4378
|
+
jwk: this.options.bearerSession?.jwk ?? {}
|
|
4379
|
+
};
|
|
4380
|
+
const kv = bearer || legacyBearer || ordinarySession !== void 0 ? session === void 0 && ordinarySession === void 0 ? void 0 : this.createKV(envelope.origin, ordinarySession ?? session, portableInvoke) : void 0;
|
|
3858
4381
|
const advertisedCapability = { spaceId: envelope.spaceId, resource: envelope.resource, actions: envelope.actions };
|
|
3859
4382
|
const capability = policySession?.capability === void 0 ? advertisedCapability : intersectShareCapabilities(advertisedCapability, policySession.capability);
|
|
3860
4383
|
if (capability === void 0) throw new ShareAccessError("SHARE_CAPABILITY_EMPTY");
|
|
@@ -3879,6 +4402,11 @@ var ShareRecipientClient = class {
|
|
|
3879
4402
|
const scope = normalizePath(input.path ?? envelope.resource.path);
|
|
3880
4403
|
this.assertAllowed(capability, "list", scope);
|
|
3881
4404
|
if (kv === void 0 && policySession === void 0) throw new ShareAccessError("SHARE_SESSION_REQUIRED");
|
|
4405
|
+
if (portableDelegation !== void 0 && kv !== void 0) {
|
|
4406
|
+
const result2 = await kv.list({ path: scope, limit: input.limit, cursor: input.cursor });
|
|
4407
|
+
if (!result2.ok) throw result2.error;
|
|
4408
|
+
return { keys: result2.data.keys, truncated: result2.data.truncated, nextCursor: result2.data.nextCursor };
|
|
4409
|
+
}
|
|
3882
4410
|
if (policySession !== void 0) return this.nativeList(envelope, policySession, scope, input.limit, input.cursor);
|
|
3883
4411
|
const result = await kv.list({ path: scope, limit: input.limit, cursor: input.cursor });
|
|
3884
4412
|
if (!result.ok) throw result.error;
|
|
@@ -3892,6 +4420,14 @@ var ShareRecipientClient = class {
|
|
|
3892
4420
|
const resolvedPath = normalizePath(path);
|
|
3893
4421
|
this.assertAllowed(capability, "save", resolvedPath);
|
|
3894
4422
|
if (kv === void 0 && policySession === void 0) throw new ShareAccessError("SHARE_SESSION_REQUIRED");
|
|
4423
|
+
if (portableDelegation !== void 0 && kv !== void 0) {
|
|
4424
|
+
const result2 = await kv.put(resolvedPath, bytes2, { contentType: input.contentType ?? envelope.content.mimeType, ifMatch: input.etag });
|
|
4425
|
+
if (!result2.ok) {
|
|
4426
|
+
if (result2.error.code === ErrorCodes.KV_PRECONDITION_FAILED || result2.error.code === ErrorCodes.KV_CONFLICT) throw new ShareConflict(resolvedPath, result2.error.meta?.etag);
|
|
4427
|
+
throw result2.error;
|
|
4428
|
+
}
|
|
4429
|
+
return { etag: result2.data.headers.etag };
|
|
4430
|
+
}
|
|
3895
4431
|
if (policySession !== void 0) return this.nativeSave(envelope, policySession, resolvedPath, bytes2, input);
|
|
3896
4432
|
const result = await kv.put(resolvedPath, bytes2, { contentType: input.contentType ?? envelope.content.mimeType, ifMatch: input.etag });
|
|
3897
4433
|
if (!result.ok) {
|
|
@@ -3907,22 +4443,79 @@ var ShareRecipientClient = class {
|
|
|
3907
4443
|
const metadata = async (path = envelope.resource.kind === "exact" ? envelope.resource.path : "") => {
|
|
3908
4444
|
const resolvedPath = normalizePath(path);
|
|
3909
4445
|
this.assertAllowed(capability, "metadata", resolvedPath);
|
|
4446
|
+
if (portableDelegation !== void 0 && kv !== void 0) {
|
|
4447
|
+
const result2 = await kv.head(resolvedPath);
|
|
4448
|
+
if (!result2.ok) throw result2.error;
|
|
4449
|
+
return { metadata: { "content-type": result2.data.headers.contentType ?? "application/octet-stream", "content-length": String(result2.data.headers.contentLength ?? ""), ...result2.data.headers.lastModified === void 0 ? {} : { "last-modified": result2.data.headers.lastModified } }, etag: result2.data.headers.etag, contentType: result2.data.headers.contentType, size: result2.data.headers.contentLength };
|
|
4450
|
+
}
|
|
3910
4451
|
if (policySession !== void 0) return this.nativeMetadata(envelope, policySession, resolvedPath);
|
|
3911
4452
|
if (kv === void 0) throw new ShareAccessError("SHARE_SESSION_REQUIRED");
|
|
3912
4453
|
const result = await kv.head(resolvedPath);
|
|
3913
4454
|
if (!result.ok) throw result.error;
|
|
3914
4455
|
return { metadata: { "content-type": result.data.headers.contentType ?? "application/octet-stream", "content-length": String(result.data.headers.contentLength ?? ""), ...result.data.headers.lastModified === void 0 ? {} : { "last-modified": result.data.headers.lastModified } }, etag: result.data.headers.etag, contentType: result.data.headers.contentType, size: result.data.headers.contentLength };
|
|
3915
4456
|
};
|
|
3916
|
-
return { kind: "share-v2", envelope, location: { ...location, key: void 0 }, resource: envelope.resource, actions: envelope.actions, expiresAt: new Date(envelope.expiresAt), kv, get, listChildren, save, metadata };
|
|
4457
|
+
return { kind: "share-v2", envelope, location: { ...location, key: void 0 }, resource: envelope.resource, actions: envelope.actions, expiresAt: new Date(envelope.expiresAt), kv, portableDelegation, get, listChildren, save, metadata };
|
|
3917
4458
|
} catch (error) {
|
|
3918
4459
|
throw asError(error);
|
|
3919
4460
|
}
|
|
3920
4461
|
}
|
|
3921
|
-
|
|
4462
|
+
policySessionDelegation(session, origin) {
|
|
4463
|
+
if (session.runtimeDelegation === void 0) return void 0;
|
|
4464
|
+
const delegation = parsePortableDelegation(session.runtimeDelegation);
|
|
4465
|
+
if (delegation.host !== void 0 && delegation.host.replace(/\/+$/, "") !== origin.replace(/\/+$/, "")) throw new ShareAccessError("SHARE_ORIGIN_MISMATCH", "delegation host does not match the trusted share origin");
|
|
4466
|
+
return delegation;
|
|
4467
|
+
}
|
|
4468
|
+
policyInvocationSigner(delegation) {
|
|
4469
|
+
const privateKey = this.options.policySessionPrivateKey;
|
|
4470
|
+
if (privateKey === void 0) throw new ShareAccessError("SHARE_SESSION_SIGNER_REQUIRED");
|
|
4471
|
+
const session = parsePolicySessionUcan(delegation.delegationHeader.Authorization);
|
|
4472
|
+
if (session.cid !== delegation.cid || session.aud !== delegation.delegateDID)
|
|
4473
|
+
throw new ShareAccessError("SHARE_SESSION_INVALID");
|
|
4474
|
+
return (_serviceSession, service, path, action, facts) => {
|
|
4475
|
+
const serviceName = service.replace(/^tinycloud\./, "");
|
|
4476
|
+
const cleanPath = path.replace(/^\//, "").replace(/\/$/, "");
|
|
4477
|
+
const authority = Object.entries(session.att).find(([parentResource, abilities]) => {
|
|
4478
|
+
if (!(action in abilities)) return false;
|
|
4479
|
+
if (serviceName === "encryption") return parentResource.startsWith("urn:tinycloud:encryption:") && parentResource === cleanPath;
|
|
4480
|
+
const match = /^tinycloud:\/\/[^/]+\/kv\/(.+)$/.exec(parentResource);
|
|
4481
|
+
if (match === null) return false;
|
|
4482
|
+
const parentPath = match[1];
|
|
4483
|
+
const caveats = abilities[action] ?? [];
|
|
4484
|
+
const prefix = caveats.some((value) => isRecord(value) && value.kind === "prefix");
|
|
4485
|
+
return cleanPath === parentPath || prefix && cleanPath.startsWith(`${parentPath}/`);
|
|
4486
|
+
});
|
|
4487
|
+
if (authority === void 0) throw new ShareAccessError("SHARE_OUT_OF_SCOPE");
|
|
4488
|
+
const resource = serviceName === "encryption" ? authority[0] : `${authority[0].slice(0, authority[0].indexOf("/kv/") + 4)}${cleanPath}`;
|
|
4489
|
+
const caveat = serviceName === "encryption" ? {} : { type: "xyz.tinycloud.resource/selector", kind: "exact", value: resource };
|
|
4490
|
+
const invocation = createCompactPolicyInvocation({
|
|
4491
|
+
sessionAuthorization: delegation.delegationHeader.Authorization,
|
|
4492
|
+
sessionCid: delegation.cid,
|
|
4493
|
+
recipientDid: delegation.delegateDID,
|
|
4494
|
+
audienceDid: String(session.fact.nodeAudience),
|
|
4495
|
+
resource,
|
|
4496
|
+
action,
|
|
4497
|
+
caveat,
|
|
4498
|
+
...facts?.length === 1 ? { facts: facts[0] } : {},
|
|
4499
|
+
privateKey,
|
|
4500
|
+
now: Math.floor(this.now().getTime() / 1e3)
|
|
4501
|
+
});
|
|
4502
|
+
return { Authorization: invocation.authorization };
|
|
4503
|
+
};
|
|
4504
|
+
}
|
|
4505
|
+
policySessionProjection(delegation) {
|
|
4506
|
+
const session = parsePolicySessionUcan(delegation.delegationHeader.Authorization);
|
|
4507
|
+
if (session.cid !== delegation.cid || session.aud !== delegation.delegateDID) throw new ShareAccessError("SHARE_SESSION_INVALID");
|
|
4508
|
+
const kvResource = Object.keys(session.att).find((resource) => /^tinycloud:\/\/[^/]+\/kv\/.+$/.test(resource));
|
|
4509
|
+
const match = kvResource === void 0 ? void 0 : /^tinycloud:\/\/([^/]+)\/kv\/(.+)$/.exec(kvResource);
|
|
4510
|
+
if (match === void 0 || match === null) throw new ShareAccessError("SHARE_SESSION_INVALID");
|
|
4511
|
+
return { spaceId: match[1] };
|
|
4512
|
+
}
|
|
4513
|
+
createKV(origin, session, invokeOverride) {
|
|
4514
|
+
const invoke = invokeOverride ?? this.options.invoke ?? nativeInvoke;
|
|
3922
4515
|
if (this.options.createKVService !== void 0) {
|
|
3923
|
-
return this.options.createKVService({ hosts: [origin], session, invoke
|
|
4516
|
+
return this.options.createKVService({ hosts: [origin], session, invoke, fetch: this.fetchFn });
|
|
3924
4517
|
}
|
|
3925
|
-
const context = new ServiceContext({ hosts: [origin], session, invoke
|
|
4518
|
+
const context = new ServiceContext({ hosts: [origin], session, invoke, fetch: this.fetchFn });
|
|
3926
4519
|
const service = new KVService({ prefix: "" });
|
|
3927
4520
|
context.registerService("kv", service);
|
|
3928
4521
|
service.initialize(context);
|
|
@@ -3965,7 +4558,7 @@ var ShareRecipientClient = class {
|
|
|
3965
4558
|
if (bytes2.byteLength > (this.options.maxContentBytes ?? DEFAULT_MAX_CONTENT_BYTES)) throw new ShareAccessError("SHARE_TOO_LARGE");
|
|
3966
4559
|
const contentType = input.contentType ?? envelope.content.mimeType;
|
|
3967
4560
|
if (contentType !== envelope.content.mimeType && !/^text\/(?:plain|markdown)(?:;|$)/i.test(contentType)) throw new ShareAccessError("SHARE_CONTENT_TYPE_INVALID");
|
|
3968
|
-
const result = await this.invokeNative({ envelope, session, action: "put", resource: path, body: bytes2, bodyDigest: bytesToBase64Url2(
|
|
4561
|
+
const result = await this.invokeNative({ envelope, session, action: "put", resource: path, body: bytes2, bodyDigest: bytesToBase64Url2(sha2565(bytes2)), contentType, ifMatch: input.etag, mediaType: "application/vnd.tinycloud.share+json" });
|
|
3969
4562
|
if (result.status === 412 || result.status === 409) throw new ShareConflict(path, result.headers?.etag);
|
|
3970
4563
|
if (result.status === 401 || result.status === 403) throw new ShareAccessError("SHARE_DENIED");
|
|
3971
4564
|
if (result.status < 200 || result.status >= 300) throw new ShareAccessError("SHARE_WRITE_FAILED");
|
|
@@ -4087,7 +4680,7 @@ var ShareRecipientClient = class {
|
|
|
4087
4680
|
};
|
|
4088
4681
|
const signed = this.options.signNativeInvoke === void 0 ? void 0 : await this.options.signNativeInvoke({ envelope: input.envelope, session: input.session, request: body });
|
|
4089
4682
|
const transport = this.options.invoke !== void 0 || session.authorization !== void 0 || session.delegationHeader !== void 0 ? this.defaultNativeHeaders(session, input.action, input.resource, body) : void 0;
|
|
4090
|
-
const response = await this.fetchFn(
|
|
4683
|
+
const response = await this.fetchFn(`${base3}/invoke`, {
|
|
4091
4684
|
method: "POST",
|
|
4092
4685
|
headers: { ...headersRecord(transport), ...headersRecord(signed), "content-type": input.mediaType, accept: input.mediaType },
|
|
4093
4686
|
body: JSON.stringify(body),
|
|
@@ -4211,7 +4804,7 @@ var ShareRecipientClient = class {
|
|
|
4211
4804
|
}]);
|
|
4212
4805
|
}
|
|
4213
4806
|
digestMatches(value, bytes2) {
|
|
4214
|
-
const digest4 = bytesToBase64Url2(
|
|
4807
|
+
const digest4 = bytesToBase64Url2(sha2565(bytes2));
|
|
4215
4808
|
return value === digest4 || value === `sha-256=:${digest4}:`;
|
|
4216
4809
|
}
|
|
4217
4810
|
assertNativeRequestBounds(envelope, session, operation, path, limit, cursor) {
|
|
@@ -4429,7 +5022,7 @@ var ShareRecipientClient = class {
|
|
|
4429
5022
|
nodeAudience: binding.nodeAudience,
|
|
4430
5023
|
...isV2 ? {
|
|
4431
5024
|
enforcerDid: challenge.enforcerDid,
|
|
4432
|
-
credentialDigest: typeof presentation.credentialDigest === "string" ? presentation.credentialDigest : bytesToBase64Url2(
|
|
5025
|
+
credentialDigest: typeof presentation.credentialDigest === "string" ? presentation.credentialDigest : bytesToBase64Url2(sha2565(new TextEncoder().encode(credential)))
|
|
4433
5026
|
} : {},
|
|
4434
5027
|
action,
|
|
4435
5028
|
...binding.actions === void 0 ? {} : { actions: [...binding.actions] },
|
|
@@ -4495,7 +5088,7 @@ var ShareRecipientClient = class {
|
|
|
4495
5088
|
}
|
|
4496
5089
|
if (isJwsProof && detached.kid !== `${signerDid}#${encoded}` || isEd25519Proof && detached.signerDid !== signerDid || signature.length !== 64) throw new ShareAccessError("SHARE_SESSION_INVALID", "Node proof binding is invalid");
|
|
4497
5090
|
const bytes2 = new TextEncoder().encode(`${domain}${canonicalJsonForProof(message)}`);
|
|
4498
|
-
if (!
|
|
5091
|
+
if (!ed255193.verify(signature, bytes2, key)) throw new ShareAccessError("SHARE_SESSION_INVALID", "Node proof signature is invalid");
|
|
4499
5092
|
}
|
|
4500
5093
|
assertChallengeRequestBinding(request, challenge) {
|
|
4501
5094
|
const source = isRecord(request.body) ? request.body : request;
|
|
@@ -5699,7 +6292,7 @@ function shareKeyMatchesDid(key, didUrl) {
|
|
|
5699
6292
|
if (!publicKey) return false;
|
|
5700
6293
|
const jwkBytes = decodeBase64UrlBytes(key.x);
|
|
5701
6294
|
const privateKey = decodeBase64UrlBytes(key.d);
|
|
5702
|
-
const derivedPublicKey =
|
|
6295
|
+
const derivedPublicKey = ed255194.getPublicKey(privateKey);
|
|
5703
6296
|
return privateKey.length === 32 && publicKey.length === jwkBytes.length && publicKey.every((byte, index) => byte === jwkBytes[index]) && derivedPublicKey.length === jwkBytes.length && derivedPublicKey.every((byte, index) => byte === jwkBytes[index]);
|
|
5704
6297
|
} catch {
|
|
5705
6298
|
return false;
|
|
@@ -5749,210 +6342,12 @@ function verifySignedChild(result, expected, computeCid) {
|
|
|
5749
6342
|
}
|
|
5750
6343
|
|
|
5751
6344
|
// src/delegations/owner-policy.ts
|
|
5752
|
-
import { ed25519 as
|
|
5753
|
-
import { sha256 as
|
|
5754
|
-
|
|
5755
|
-
// src/policy/signed-object.ts
|
|
5756
|
-
import { ed25519 as ed255194 } from "@noble/curves/ed25519";
|
|
5757
|
-
import { bytesToHex, sha256 as sha2565, verifyMessage } from "viem";
|
|
5758
|
-
|
|
5759
|
-
// src/policy/errors.ts
|
|
5760
|
-
var SignedObjectProfileError = class extends Error {
|
|
5761
|
-
constructor(code3, message) {
|
|
5762
|
-
super(message);
|
|
5763
|
-
this.name = "SignedObjectProfileError";
|
|
5764
|
-
this.code = code3;
|
|
5765
|
-
}
|
|
5766
|
-
};
|
|
5767
|
-
var SignedObjectCanonicalizationError = class extends SignedObjectProfileError {
|
|
5768
|
-
constructor(message) {
|
|
5769
|
-
super("canonicalization-mismatch", message);
|
|
5770
|
-
this.name = "SignedObjectCanonicalizationError";
|
|
5771
|
-
}
|
|
5772
|
-
};
|
|
5773
|
-
|
|
5774
|
-
// src/policy/jcs.ts
|
|
5775
|
-
var objectHasOwn = Object.hasOwn ?? Object.prototype.hasOwnProperty.call.bind(
|
|
5776
|
-
Object.prototype.hasOwnProperty
|
|
5777
|
-
);
|
|
5778
|
-
function jcsCanonicalize(input) {
|
|
5779
|
-
return serialize(normalizeJson(input, "$"));
|
|
5780
|
-
}
|
|
5781
|
-
function normalizeJson(input, path = "$") {
|
|
5782
|
-
if (input === null) {
|
|
5783
|
-
return null;
|
|
5784
|
-
}
|
|
5785
|
-
switch (typeof input) {
|
|
5786
|
-
case "boolean":
|
|
5787
|
-
return input;
|
|
5788
|
-
case "number":
|
|
5789
|
-
if (!Number.isFinite(input)) {
|
|
5790
|
-
throw new SignedObjectCanonicalizationError(
|
|
5791
|
-
`${path} must be a finite JSON number`
|
|
5792
|
-
);
|
|
5793
|
-
}
|
|
5794
|
-
return input;
|
|
5795
|
-
case "string":
|
|
5796
|
-
assertUnicodeScalarString(input, path);
|
|
5797
|
-
return input;
|
|
5798
|
-
case "object":
|
|
5799
|
-
return normalizeJsonObjectOrArray(input, path);
|
|
5800
|
-
case "bigint":
|
|
5801
|
-
case "function":
|
|
5802
|
-
case "symbol":
|
|
5803
|
-
case "undefined":
|
|
5804
|
-
default:
|
|
5805
|
-
throw new SignedObjectCanonicalizationError(
|
|
5806
|
-
`${path} is not a JSON value`
|
|
5807
|
-
);
|
|
5808
|
-
}
|
|
5809
|
-
}
|
|
5810
|
-
function serialize(value) {
|
|
5811
|
-
if (value === null) {
|
|
5812
|
-
return "null";
|
|
5813
|
-
}
|
|
5814
|
-
switch (typeof value) {
|
|
5815
|
-
case "boolean":
|
|
5816
|
-
return value ? "true" : "false";
|
|
5817
|
-
case "number": {
|
|
5818
|
-
const encoded = JSON.stringify(value);
|
|
5819
|
-
if (encoded === void 0) {
|
|
5820
|
-
throw new SignedObjectCanonicalizationError(
|
|
5821
|
-
"number could not be serialized as JSON"
|
|
5822
|
-
);
|
|
5823
|
-
}
|
|
5824
|
-
return encoded;
|
|
5825
|
-
}
|
|
5826
|
-
case "string":
|
|
5827
|
-
return JSON.stringify(value);
|
|
5828
|
-
case "object":
|
|
5829
|
-
if (Array.isArray(value)) {
|
|
5830
|
-
return `[${value.map((item) => serialize(item)).join(",")}]`;
|
|
5831
|
-
}
|
|
5832
|
-
return serializeObject(value);
|
|
5833
|
-
default:
|
|
5834
|
-
throw new SignedObjectCanonicalizationError(
|
|
5835
|
-
`unsupported JSON value type ${typeof value}`
|
|
5836
|
-
);
|
|
5837
|
-
}
|
|
5838
|
-
}
|
|
5839
|
-
function normalizeJsonObjectOrArray(input, path) {
|
|
5840
|
-
assertNoSymbolKeys(input, path);
|
|
5841
|
-
if (Array.isArray(input)) {
|
|
5842
|
-
for (const key of Object.getOwnPropertyNames(input)) {
|
|
5843
|
-
if (key === "length") {
|
|
5844
|
-
continue;
|
|
5845
|
-
}
|
|
5846
|
-
if (!isArrayIndexKey(key, input.length)) {
|
|
5847
|
-
throw new SignedObjectCanonicalizationError(
|
|
5848
|
-
`${path}.${key} is not allowed on a JSON array`
|
|
5849
|
-
);
|
|
5850
|
-
}
|
|
5851
|
-
const descriptor = Object.getOwnPropertyDescriptor(input, key);
|
|
5852
|
-
if (descriptor?.enumerable !== true) {
|
|
5853
|
-
throw new SignedObjectCanonicalizationError(
|
|
5854
|
-
`${path}[${key}] must be an enumerable JSON array item`
|
|
5855
|
-
);
|
|
5856
|
-
}
|
|
5857
|
-
if (!("value" in descriptor)) {
|
|
5858
|
-
throw new SignedObjectCanonicalizationError(
|
|
5859
|
-
`${path}[${key}] must be a JSON data property`
|
|
5860
|
-
);
|
|
5861
|
-
}
|
|
5862
|
-
}
|
|
5863
|
-
const output2 = [];
|
|
5864
|
-
for (let index = 0; index < input.length; index++) {
|
|
5865
|
-
if (!objectHasOwn(input, index)) {
|
|
5866
|
-
throw new SignedObjectCanonicalizationError(
|
|
5867
|
-
`${path}[${index}] must not be a sparse array hole`
|
|
5868
|
-
);
|
|
5869
|
-
}
|
|
5870
|
-
output2.push(normalizeJson(input[index], `${path}[${index}]`));
|
|
5871
|
-
}
|
|
5872
|
-
return output2;
|
|
5873
|
-
}
|
|
5874
|
-
const proto = Object.getPrototypeOf(input);
|
|
5875
|
-
if (proto !== Object.prototype && proto !== null) {
|
|
5876
|
-
throw new SignedObjectCanonicalizationError(
|
|
5877
|
-
`${path} must be a plain JSON object`
|
|
5878
|
-
);
|
|
5879
|
-
}
|
|
5880
|
-
const output = /* @__PURE__ */ Object.create(null);
|
|
5881
|
-
for (const key of Object.getOwnPropertyNames(input)) {
|
|
5882
|
-
assertUnicodeScalarString(key, `${path} key`);
|
|
5883
|
-
if (key === "__proto__" || key === "constructor") {
|
|
5884
|
-
throw new SignedObjectCanonicalizationError(
|
|
5885
|
-
`${path}.${key} is not allowed`
|
|
5886
|
-
);
|
|
5887
|
-
}
|
|
5888
|
-
const descriptor = Object.getOwnPropertyDescriptor(input, key);
|
|
5889
|
-
if (descriptor?.enumerable !== true) {
|
|
5890
|
-
throw new SignedObjectCanonicalizationError(
|
|
5891
|
-
`${path}.${key} must be an enumerable JSON object property`
|
|
5892
|
-
);
|
|
5893
|
-
}
|
|
5894
|
-
if (!("value" in descriptor)) {
|
|
5895
|
-
throw new SignedObjectCanonicalizationError(
|
|
5896
|
-
`${path}.${key} must be a JSON data property`
|
|
5897
|
-
);
|
|
5898
|
-
}
|
|
5899
|
-
const value = descriptor.value;
|
|
5900
|
-
output[key] = normalizeJson(value, `${path}.${key}`);
|
|
5901
|
-
}
|
|
5902
|
-
return output;
|
|
5903
|
-
}
|
|
5904
|
-
function assertNoSymbolKeys(input, path) {
|
|
5905
|
-
if (Object.getOwnPropertySymbols(input).length > 0) {
|
|
5906
|
-
throw new SignedObjectCanonicalizationError(
|
|
5907
|
-
`${path} must not have symbol properties`
|
|
5908
|
-
);
|
|
5909
|
-
}
|
|
5910
|
-
}
|
|
5911
|
-
function isArrayIndexKey(key, length2) {
|
|
5912
|
-
if (!/^(0|[1-9]\d*)$/.test(key)) {
|
|
5913
|
-
return false;
|
|
5914
|
-
}
|
|
5915
|
-
const index = Number(key);
|
|
5916
|
-
return Number.isSafeInteger(index) && index >= 0 && index < length2;
|
|
5917
|
-
}
|
|
5918
|
-
function serializeObject(value) {
|
|
5919
|
-
const keys = Object.keys(value).sort(compareUtf16CodeUnits);
|
|
5920
|
-
const parts = keys.map((key) => `${JSON.stringify(key)}:${serialize(value[key])}`);
|
|
5921
|
-
return `{${parts.join(",")}}`;
|
|
5922
|
-
}
|
|
5923
|
-
function compareUtf16CodeUnits(a, b) {
|
|
5924
|
-
const max = Math.min(a.length, b.length);
|
|
5925
|
-
for (let index = 0; index < max; index++) {
|
|
5926
|
-
const leftCodeUnit = a.charCodeAt(index);
|
|
5927
|
-
const rightCodeUnit = b.charCodeAt(index);
|
|
5928
|
-
if (leftCodeUnit !== rightCodeUnit) {
|
|
5929
|
-
return leftCodeUnit - rightCodeUnit;
|
|
5930
|
-
}
|
|
5931
|
-
}
|
|
5932
|
-
return a.length - b.length;
|
|
5933
|
-
}
|
|
5934
|
-
function assertUnicodeScalarString(value, path) {
|
|
5935
|
-
for (let index = 0; index < value.length; index++) {
|
|
5936
|
-
const code3 = value.charCodeAt(index);
|
|
5937
|
-
if (code3 >= 55296 && code3 <= 56319) {
|
|
5938
|
-
const next = value.charCodeAt(index + 1);
|
|
5939
|
-
if (Number.isNaN(next) || next < 56320 || next > 57343) {
|
|
5940
|
-
throw new SignedObjectCanonicalizationError(
|
|
5941
|
-
`${path} contains a lone high surrogate`
|
|
5942
|
-
);
|
|
5943
|
-
}
|
|
5944
|
-
index++;
|
|
5945
|
-
continue;
|
|
5946
|
-
}
|
|
5947
|
-
if (code3 >= 56320 && code3 <= 57343) {
|
|
5948
|
-
throw new SignedObjectCanonicalizationError(
|
|
5949
|
-
`${path} contains a lone low surrogate`
|
|
5950
|
-
);
|
|
5951
|
-
}
|
|
5952
|
-
}
|
|
5953
|
-
}
|
|
6345
|
+
import { ed25519 as ed255196 } from "@noble/curves/ed25519";
|
|
6346
|
+
import { sha256 as sha2567 } from "@noble/hashes/sha256";
|
|
5954
6347
|
|
|
5955
6348
|
// src/policy/signed-object.ts
|
|
6349
|
+
import { ed25519 as ed255195 } from "@noble/curves/ed25519";
|
|
6350
|
+
import { bytesToHex, sha256 as sha2566, verifyMessage } from "viem";
|
|
5956
6351
|
var textEncoder2 = new TextEncoder();
|
|
5957
6352
|
var objectHasOwn2 = Object.hasOwn ?? Object.prototype.hasOwnProperty.call.bind(
|
|
5958
6353
|
Object.prototype.hasOwnProperty
|
|
@@ -5988,10 +6383,10 @@ function fromB64(value) {
|
|
|
5988
6383
|
throw new Error("base64url decoding is unavailable");
|
|
5989
6384
|
}
|
|
5990
6385
|
function cid(bytesValue) {
|
|
5991
|
-
return CID.createV1(code, create(sha256.code,
|
|
6386
|
+
return CID.createV1(code, create(sha256.code, sha2567(bytesValue))).toString(base32.encoder);
|
|
5992
6387
|
}
|
|
5993
6388
|
function digest3(bytesValue) {
|
|
5994
|
-
return b64(
|
|
6389
|
+
return b64(sha2567(bytesValue));
|
|
5995
6390
|
}
|
|
5996
6391
|
function didKeyFromEd25519PublicKey(publicKey) {
|
|
5997
6392
|
if (publicKey.length !== 32) throw new Error("share key public key must be 32 bytes");
|
|
@@ -6176,7 +6571,7 @@ function validateOwnerSharePolicyRegistration(value, expected) {
|
|
|
6176
6571
|
const publicKey = encodedKid.length === 34 ? encodedKid.slice(2) : encodedKid;
|
|
6177
6572
|
const signatureBytes = fromB64(proof.signature);
|
|
6178
6573
|
const signedBytes = new TextEncoder().encode(`${OWNER_SHARE_REGISTRATION_DOMAIN}${canonicalizeSignedObjectUnsigned(registrationCore)}`);
|
|
6179
|
-
if (signatureBytes.length !== 64 || !
|
|
6574
|
+
if (signatureBytes.length !== 64 || !ed255196.verify(signatureBytes, signedBytes, publicKey)) throw new Error("owner-share registration proof signature is invalid");
|
|
6180
6575
|
return { registration, proof };
|
|
6181
6576
|
}
|
|
6182
6577
|
function validateOwnerSharePolicyRegistrationBytes(bytesValue, expected) {
|
|
@@ -6190,7 +6585,7 @@ function validateOwnerSharePolicyRegistrationBytes(bytesValue, expected) {
|
|
|
6190
6585
|
}
|
|
6191
6586
|
|
|
6192
6587
|
// src/delegations/share-delivery.ts
|
|
6193
|
-
import { ed25519 as
|
|
6588
|
+
import { ed25519 as ed255197 } from "@noble/curves/ed25519";
|
|
6194
6589
|
var SHARE_DELIVERY_AUTHORIZATION_DOMAIN = "xyz.tinycloud.share/delivery-authorization/v2\0";
|
|
6195
6590
|
function isCanonicalHttpsOrigin(value) {
|
|
6196
6591
|
let url;
|
|
@@ -6278,7 +6673,7 @@ function validateShareDeliveryAuthorizationBytes(bytesValue, expected) {
|
|
|
6278
6673
|
if (publicKey.length !== 32) throw new Error("share delivery authorization proof key is invalid");
|
|
6279
6674
|
const signatureBytes = fromB642(proof.signature);
|
|
6280
6675
|
const signedBytes = new TextEncoder().encode(`${SHARE_DELIVERY_AUTHORIZATION_DOMAIN}${canonicalizeSignedObjectUnsigned(authorization)}`);
|
|
6281
|
-
if (signatureBytes.length !== 64 || !
|
|
6676
|
+
if (signatureBytes.length !== 64 || !ed255197.verify(signatureBytes, signedBytes, publicKey)) throw new Error("share delivery authorization proof signature is invalid");
|
|
6282
6677
|
return { authorization, proof };
|
|
6283
6678
|
}
|
|
6284
6679
|
function shareDeliveryTrustedKid(publicKey) {
|
|
@@ -6468,11 +6863,13 @@ export {
|
|
|
6468
6863
|
createSharePolicy,
|
|
6469
6864
|
createSharingService,
|
|
6470
6865
|
decryptShareBytesAsync,
|
|
6866
|
+
delegatePortablePolicySession,
|
|
6471
6867
|
encodeInlineShareUrl,
|
|
6472
6868
|
encodeShareArtifact,
|
|
6473
6869
|
encodeShareUrl,
|
|
6474
6870
|
encryptShareBytes,
|
|
6475
6871
|
encryptShareBytesAsync,
|
|
6872
|
+
importPortableDelegation,
|
|
6476
6873
|
inspectShare,
|
|
6477
6874
|
intersectShareCapabilities,
|
|
6478
6875
|
isLegacyShareLink,
|
|
@@ -6483,6 +6880,7 @@ export {
|
|
|
6483
6880
|
normalizeShareRecipientTarget,
|
|
6484
6881
|
normalizeShareResource,
|
|
6485
6882
|
notifyShare,
|
|
6883
|
+
parsePortableDelegation,
|
|
6486
6884
|
parseShareArtifact,
|
|
6487
6885
|
parseShareUrl,
|
|
6488
6886
|
publishPolicyShare,
|
|
@@ -6492,6 +6890,7 @@ export {
|
|
|
6492
6890
|
restoreDelegatedShareKey,
|
|
6493
6891
|
resumeShareAuthorization,
|
|
6494
6892
|
revokeShare,
|
|
6893
|
+
serializePortableDelegation,
|
|
6495
6894
|
shareCapabilityAllows,
|
|
6496
6895
|
shareDeliveryTrustedKid,
|
|
6497
6896
|
showShare,
|