@tinycloud/sdk-core 2.11.0-beta.1 → 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/bootstrap/index.cjs +0 -4
- package/dist/delegations/index.cjs +702 -330
- package/dist/delegations/index.cjs.map +1 -1
- package/dist/delegations/index.d.cts +9 -8
- package/dist/delegations/index.d.ts +9 -8
- package/dist/delegations/index.js +722 -263
- package/dist/delegations/index.js.map +1 -1
- package/dist/index.cjs +2338 -1156
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +350 -24
- package/dist/index.d.ts +350 -24
- package/dist/index.js +2333 -810
- package/dist/index.js.map +1 -1
- package/dist/policy/index.cjs +878 -250
- package/dist/policy/index.cjs.map +1 -1
- package/dist/policy/index.d.cts +3 -2
- package/dist/policy/index.d.ts +3 -2
- package/dist/policy/index.js +877 -183
- package/dist/policy/index.js.map +1 -1
- package/dist/{recipient-types.schema-CWIt63Qp.d.cts → recipient-types.schema-CuDpskPd.d.cts} +236 -98
- package/dist/{recipient-types.schema-CWIt63Qp.d.ts → recipient-types.schema-CuDpskPd.d.ts} +236 -98
- package/dist/requester/index.cjs +10 -38
- package/dist/requester/index.cjs.map +1 -1
- package/dist/requester/index.js +10 -8
- package/dist/requester/index.js.map +1 -1
- package/dist/unified-BYPfXp5S.d.ts +429 -0
- package/dist/unified-BdfNHNrx.d.cts +429 -0
- package/package.json +6 -3
- package/dist/signed-object-C6mWbTbB.d.ts +0 -149
- package/dist/signed-object-IMAm5a32.d.cts +0 -149
|
@@ -35,10 +35,12 @@ __export(delegations_exports, {
|
|
|
35
35
|
DelegationErrorCodes: () => DelegationErrorCodes,
|
|
36
36
|
DelegationManager: () => DelegationManager,
|
|
37
37
|
EncodedShareDataSchema: () => EncodedShareDataSchema,
|
|
38
|
+
EncryptedSenderShareHistory: () => import_share_sdk.EncryptedSenderShareHistory,
|
|
38
39
|
MAX_CONTENT_BYTES: () => MAX_CONTENT_BYTES,
|
|
39
40
|
MAX_SEALED_SHARE_CONTENT_BYTES: () => MAX_SEALED_SHARE_CONTENT_BYTES,
|
|
40
41
|
MAX_SHARE_ARTIFACT_BYTES: () => MAX_SHARE_ARTIFACT_BYTES,
|
|
41
42
|
MAX_SHARE_CONTENT_BYTES: () => MAX_SHARE_CONTENT_BYTES,
|
|
43
|
+
MemoryEncryptedShareHistoryStorage: () => import_share_sdk.MemoryEncryptedShareHistoryStorage,
|
|
42
44
|
MemorySenderShareKeyStorage: () => MemorySenderShareKeyStorage,
|
|
43
45
|
MemorySenderShareRecordStorage: () => MemorySenderShareRecordStorage,
|
|
44
46
|
MemoryShareCache: () => MemoryShareCache,
|
|
@@ -53,6 +55,7 @@ __export(delegations_exports, {
|
|
|
53
55
|
ShareConflict: () => ShareConflict,
|
|
54
56
|
ShareEnvelopeError: () => ShareEnvelopeError,
|
|
55
57
|
ShareNativeResponseSchema: () => ShareNativeResponseSchema,
|
|
58
|
+
ShareReceiveError: () => import_share_sdk2.ShareReceiveError,
|
|
56
59
|
ShareRecipientClient: () => ShareRecipientClient,
|
|
57
60
|
ShareRecipientClientOptionsSchema: () => ShareRecipientClientOptionsSchema,
|
|
58
61
|
ShareRecipientPolicySchema: () => ShareRecipientPolicySchema,
|
|
@@ -60,7 +63,10 @@ __export(delegations_exports, {
|
|
|
60
63
|
ShareResourceSchema: () => ShareResourceSchema,
|
|
61
64
|
SharingService: () => SharingService,
|
|
62
65
|
SharingServiceConfigSchema: () => SharingServiceConfigSchema,
|
|
66
|
+
authorizationMethodForTarget: () => import_share_sdk.authorizationMethodForTarget,
|
|
67
|
+
authorizeShare: () => import_share_sdk.authorizeShare,
|
|
63
68
|
canonicalOwnerSharePolicy: () => canonicalOwnerSharePolicy,
|
|
69
|
+
claimShare: () => import_share_sdk.claimShare,
|
|
64
70
|
computeOwnerShareRegistrationCid: () => computeOwnerShareRegistrationCid,
|
|
65
71
|
computeShareCid: () => computeShareCid,
|
|
66
72
|
createDelegatedShareKey: () => createDelegatedShareKey,
|
|
@@ -70,28 +76,46 @@ __export(delegations_exports, {
|
|
|
70
76
|
createSharePolicy: () => createSharePolicy,
|
|
71
77
|
createSharingService: () => createSharingService,
|
|
72
78
|
decryptShareBytesAsync: () => decryptShareBytesAsync,
|
|
79
|
+
delegatePortablePolicySession: () => delegatePortablePolicySession,
|
|
73
80
|
encodeInlineShareUrl: () => encodeInlineShareUrl,
|
|
74
81
|
encodeShareArtifact: () => encodeShareArtifact,
|
|
75
82
|
encodeShareUrl: () => encodeShareUrl,
|
|
76
83
|
encryptShareBytes: () => encryptShareBytes,
|
|
77
84
|
encryptShareBytesAsync: () => encryptShareBytesAsync,
|
|
85
|
+
importPortableDelegation: () => importPortableDelegation,
|
|
86
|
+
inspectShare: () => import_share_sdk2.inspectShare,
|
|
78
87
|
intersectShareCapabilities: () => intersectShareCapabilities,
|
|
88
|
+
isLegacyShareLink: () => import_share_sdk.isLegacyShareLink,
|
|
79
89
|
isV2ShareLink: () => isV2ShareLink,
|
|
90
|
+
listShares: () => import_share_sdk.listShares,
|
|
91
|
+
migrateShare: () => import_share_sdk.migrateShare,
|
|
80
92
|
normalizeShareActions: () => normalizeShareActions,
|
|
81
93
|
normalizeShareRecipientTarget: () => normalizeShareRecipientTarget,
|
|
82
94
|
normalizeShareResource: () => normalizeShareResource,
|
|
95
|
+
notifyShare: () => import_share_sdk.notifyShare,
|
|
96
|
+
parsePortableDelegation: () => parsePortableDelegation,
|
|
83
97
|
parseShareArtifact: () => parseShareArtifact,
|
|
84
98
|
parseShareUrl: () => parseShareUrl,
|
|
99
|
+
publishPolicyShare: () => import_share_sdk.publishPolicyShare,
|
|
100
|
+
publishTargetShare: () => import_share_sdk.publishTargetShare,
|
|
101
|
+
receiveLegacyShare: () => import_share_sdk.receiveLegacyShare,
|
|
102
|
+
receiveShare: () => import_share_sdk2.receiveShare,
|
|
85
103
|
restoreDelegatedShareKey: () => restoreDelegatedShareKey,
|
|
104
|
+
resumeShareAuthorization: () => import_share_sdk.resumeShareAuthorization,
|
|
105
|
+
revokeShare: () => import_share_sdk.revokeShare,
|
|
106
|
+
serializePortableDelegation: () => serializePortableDelegation,
|
|
86
107
|
shareCapabilityAllows: () => shareCapabilityAllows,
|
|
87
108
|
shareDeliveryTrustedKid: () => shareDeliveryTrustedKid,
|
|
109
|
+
showShare: () => import_share_sdk.showShare,
|
|
88
110
|
signShareEnvelope: () => signShareEnvelope,
|
|
111
|
+
toShareErrorInfo: () => import_share_sdk2.toShareErrorInfo,
|
|
89
112
|
validateEncodedShareData: () => validateEncodedShareData,
|
|
90
113
|
validateOwnerSharePolicyRegistration: () => validateOwnerSharePolicyRegistration,
|
|
91
114
|
validateOwnerSharePolicyRegistrationBytes: () => validateOwnerSharePolicyRegistrationBytes,
|
|
92
115
|
validateReceiveOptions: () => validateReceiveOptions,
|
|
93
116
|
validateShareDeliveryAuthorizationBytes: () => validateShareDeliveryAuthorizationBytes,
|
|
94
117
|
validateSharingServiceConfig: () => validateSharingServiceConfig,
|
|
118
|
+
verifyBearerEnvelope: () => import_share_sdk2.verifyBearerEnvelope,
|
|
95
119
|
verifyShareCid: () => verifyShareCid,
|
|
96
120
|
verifyShareEnvelope: () => verifyShareEnvelope
|
|
97
121
|
});
|
|
@@ -1362,6 +1386,7 @@ function validateSharingServiceConfig(data) {
|
|
|
1362
1386
|
|
|
1363
1387
|
// src/manifest.ts
|
|
1364
1388
|
var import_ms = __toESM(require("ms"), 1);
|
|
1389
|
+
var import_bootstrap = require("@tinycloud/bootstrap");
|
|
1365
1390
|
var import_sdk_services = require("@tinycloud/sdk-services");
|
|
1366
1391
|
var SERVICE_SHORT_TO_LONG = Object.freeze({
|
|
1367
1392
|
kv: "tinycloud.kv",
|
|
@@ -2244,13 +2269,12 @@ function digest(input, options) {
|
|
|
2244
2269
|
}
|
|
2245
2270
|
var identity2 = { code: code2, name, encode: encode4, digest };
|
|
2246
2271
|
|
|
2247
|
-
// ../../node_modules/multiformats/dist/src/hashes/sha2.js
|
|
2248
|
-
var
|
|
2249
|
-
__export(
|
|
2272
|
+
// ../../node_modules/multiformats/dist/src/hashes/sha2-browser.js
|
|
2273
|
+
var sha2_browser_exports = {};
|
|
2274
|
+
__export(sha2_browser_exports, {
|
|
2250
2275
|
sha256: () => sha256,
|
|
2251
2276
|
sha512: () => sha512
|
|
2252
2277
|
});
|
|
2253
|
-
var import_crypto = __toESM(require("crypto"), 1);
|
|
2254
2278
|
|
|
2255
2279
|
// ../../node_modules/multiformats/dist/src/hashes/hasher.js
|
|
2256
2280
|
var DEFAULT_MIN_DIGEST_LENGTH = 20;
|
|
@@ -2300,16 +2324,19 @@ function createDigest(digest4, code3, truncate) {
|
|
|
2300
2324
|
return create(code3, digest4);
|
|
2301
2325
|
}
|
|
2302
2326
|
|
|
2303
|
-
// ../../node_modules/multiformats/dist/src/hashes/sha2.js
|
|
2327
|
+
// ../../node_modules/multiformats/dist/src/hashes/sha2-browser.js
|
|
2328
|
+
function sha(name2) {
|
|
2329
|
+
return async (data) => new Uint8Array(await crypto.subtle.digest(name2, data));
|
|
2330
|
+
}
|
|
2304
2331
|
var sha256 = from2({
|
|
2305
2332
|
name: "sha2-256",
|
|
2306
2333
|
code: 18,
|
|
2307
|
-
encode: (
|
|
2334
|
+
encode: sha("SHA-256")
|
|
2308
2335
|
});
|
|
2309
2336
|
var sha512 = from2({
|
|
2310
2337
|
name: "sha2-512",
|
|
2311
2338
|
code: 19,
|
|
2312
|
-
encode: (
|
|
2339
|
+
encode: sha("SHA-512")
|
|
2313
2340
|
});
|
|
2314
2341
|
|
|
2315
2342
|
// ../../node_modules/multiformats/dist/src/cid.js
|
|
@@ -2651,15 +2678,15 @@ var cidSymbol = /* @__PURE__ */ Symbol.for("@ipld/js-cid/CID");
|
|
|
2651
2678
|
|
|
2652
2679
|
// ../../node_modules/multiformats/dist/src/basics.js
|
|
2653
2680
|
var bases = { ...identity_exports, ...base2_exports, ...base8_exports, ...base10_exports, ...base16_exports, ...base32_exports, ...base36_exports, ...base58_exports, ...base64_exports, ...base256emoji_exports };
|
|
2654
|
-
var hashes = { ...
|
|
2681
|
+
var hashes = { ...sha2_browser_exports, ...identity_exports2 };
|
|
2655
2682
|
|
|
2656
2683
|
// src/delegations/SharingService.ts
|
|
2657
|
-
var
|
|
2684
|
+
var import_ed255194 = require("@noble/curves/ed25519");
|
|
2658
2685
|
|
|
2659
2686
|
// src/delegations/ShareRecipientClient.ts
|
|
2660
2687
|
var import_sdk_services2 = require("@tinycloud/sdk-services");
|
|
2661
|
-
var
|
|
2662
|
-
var
|
|
2688
|
+
var import_ed255193 = require("@noble/curves/ed25519");
|
|
2689
|
+
var import_sha2564 = require("@noble/hashes/sha256");
|
|
2663
2690
|
|
|
2664
2691
|
// src/delegations/share-envelope.ts
|
|
2665
2692
|
var import_ed25519 = require("@noble/curves/ed25519");
|
|
@@ -2820,6 +2847,10 @@ function normalizeRecipient(recipient) {
|
|
|
2820
2847
|
}
|
|
2821
2848
|
return { kind: recipient.kind, value: domain };
|
|
2822
2849
|
}
|
|
2850
|
+
if (recipient.kind === "recipientDid") {
|
|
2851
|
+
if (!isCanonicalRecipientDid(recipient.value)) throw new ShareEnvelopeError("invalid-envelope", "recipient DID is invalid");
|
|
2852
|
+
return { kind: recipient.kind, value: recipient.value };
|
|
2853
|
+
}
|
|
2823
2854
|
const exact = recipient.value.trim();
|
|
2824
2855
|
const at = exact.lastIndexOf("@");
|
|
2825
2856
|
const normalizedExact = at > 0 ? `${exact.slice(0, at)}@${exact.slice(at + 1).toLowerCase()}` : exact;
|
|
@@ -2828,6 +2859,28 @@ function normalizeRecipient(recipient) {
|
|
|
2828
2859
|
}
|
|
2829
2860
|
return { kind: recipient.kind, value: normalizedExact };
|
|
2830
2861
|
}
|
|
2862
|
+
function isCanonicalRecipientDid(value) {
|
|
2863
|
+
if (value.length === 0 || value.length > 2048 || /[\u0000-\u0020\u007f]/.test(value)) return false;
|
|
2864
|
+
const parts = value.split(":");
|
|
2865
|
+
if (parts.length < 3 || parts[0] !== "did" || !/^[a-z0-9]+$/.test(parts[1] ?? "")) return false;
|
|
2866
|
+
const identifier = parts.slice(2);
|
|
2867
|
+
if (identifier.some((part) => part.length === 0)) return false;
|
|
2868
|
+
if (parts[1] === "web") {
|
|
2869
|
+
const host = identifier[0] ?? "";
|
|
2870
|
+
if (host.length > 253 || host.split(".").some((label) => !label || label.length > 63 || !/^[A-Za-z0-9-]+$/.test(label) || label.startsWith("-") || label.endsWith("-"))) return false;
|
|
2871
|
+
return identifier.slice(1).every((part) => /^[A-Za-z0-9._%-]+$/.test(part));
|
|
2872
|
+
}
|
|
2873
|
+
if (parts[1] === "pkh") return identifier.length >= 3 && identifier.every((part) => /^[A-Za-z0-9._%-]+$/.test(part));
|
|
2874
|
+
if (parts[1] === "key") {
|
|
2875
|
+
try {
|
|
2876
|
+
const bytes2 = base58btc.decode(identifier.join(":"));
|
|
2877
|
+
return bytes2.length === 34 && bytes2[0] === 237 && bytes2[1] === 1;
|
|
2878
|
+
} catch {
|
|
2879
|
+
return false;
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
return false;
|
|
2883
|
+
}
|
|
2831
2884
|
function normalizeShareRecipientTarget(recipient) {
|
|
2832
2885
|
const normalized = normalizeRecipient(recipient);
|
|
2833
2886
|
if (normalized === void 0) throw new ShareEnvelopeError("invalid-envelope", "recipient matcher is required");
|
|
@@ -2914,9 +2967,9 @@ function verifyShareEnvelope(envelope, options = {}) {
|
|
|
2914
2967
|
const recipient = normalizeRecipient(envelope.recipient);
|
|
2915
2968
|
if (recipient !== void 0 && JSON.stringify(recipient) !== JSON.stringify(envelope.recipient)) throw new ShareEnvelopeError("invalid-envelope", "recipient is not canonical");
|
|
2916
2969
|
if (recipient?.kind === "exactEmail" || recipient?.kind === "emailDomain") throw new ShareEnvelopeError("unsafe-plaintext", "recipient matchers are not public envelope fields");
|
|
2917
|
-
if (envelope.recipientKind !== void 0 && !["exactEmail", "emailDomain", "bearer"].includes(envelope.recipientKind)) throw new ShareEnvelopeError("invalid-envelope", "recipient mode is invalid");
|
|
2970
|
+
if (envelope.recipientKind !== void 0 && !["exactEmail", "emailDomain", "recipientDid", "bearer"].includes(envelope.recipientKind)) throw new ShareEnvelopeError("invalid-envelope", "recipient mode is invalid");
|
|
2918
2971
|
if (envelope.recipientKind === "bearer" && recipient?.kind !== void 0 && recipient.kind !== "bearer") throw new ShareEnvelopeError("invalid-envelope", "recipient mode does not match recipient");
|
|
2919
|
-
if ((envelope.recipientKind === "exactEmail" || envelope.recipientKind === "emailDomain") && !envelope.encrypted) throw new ShareEnvelopeError("unsafe-plaintext", "
|
|
2972
|
+
if ((envelope.recipientKind === "exactEmail" || envelope.recipientKind === "emailDomain" || envelope.recipientKind === "recipientDid") && !envelope.encrypted) throw new ShareEnvelopeError("unsafe-plaintext", "addressed shares require encryption");
|
|
2920
2973
|
if (typeof envelope.spaceId !== "string" || envelope.spaceId.length === 0 || typeof envelope.content.mimeType !== "string" || envelope.content.mimeType.length === 0 || typeof envelope.content.digest !== "string" || !/^[A-Za-z0-9_-]+$/.test(envelope.content.digest)) throw new ShareEnvelopeError("invalid-envelope", "content metadata is invalid");
|
|
2921
2974
|
const maxContentBytes = envelope.encrypted ? options.maxSealedContentBytes ?? MAX_SEALED_SHARE_CONTENT_BYTES : options.maxContentBytes ?? MAX_SHARE_CONTENT_BYTES;
|
|
2922
2975
|
if (!Number.isInteger(envelope.content.size) || envelope.content.size < 0 || envelope.content.size > maxContentBytes) throw new ShareEnvelopeError("content-too-large", "share content exceeds the configured limit");
|
|
@@ -3055,7 +3108,7 @@ function parsePolicyMetadata(policyBytes, target, expectedExpiry) {
|
|
|
3055
3108
|
assertKeys(policy, ["type", "version", "issuerDid", "recipientMatcher", "target", "delegation", "authority", "actions", "resource", "content-source", "expiresAt"], "published canonical policy material");
|
|
3056
3109
|
if (typeof policy.issuerDid !== "string" || typeof policy.expiresAt !== "string" || policy.expiresAt !== expectedExpiry) throw new ShareEnvelopeError("invalid-envelope", "policy expiry is not bound to the envelope");
|
|
3057
3110
|
const matcherValue = policy.recipientMatcher;
|
|
3058
|
-
if (!isPlainObject(matcherValue) || matcherValue.kind !== "exactEmail" && matcherValue.kind !== "emailDomain" || typeof matcherValue.value !== "string") throw new ShareEnvelopeError("invalid-envelope", "policy matcher is invalid");
|
|
3111
|
+
if (!isPlainObject(matcherValue) || matcherValue.kind !== "exactEmail" && matcherValue.kind !== "emailDomain" && matcherValue.kind !== "recipientDid" || typeof matcherValue.value !== "string") throw new ShareEnvelopeError("invalid-envelope", "policy matcher is invalid");
|
|
3059
3112
|
const matcher2 = normalizeRecipient(matcherValue);
|
|
3060
3113
|
if (matcher2 === void 0 || matcher2.kind === "bearer") throw new ShareEnvelopeError("invalid-envelope", "policy matcher is invalid");
|
|
3061
3114
|
if (!isPlainObject(policy.target)) throw new ShareEnvelopeError("invalid-envelope", "policy target is invalid");
|
|
@@ -3142,7 +3195,7 @@ function parseCanonicalPublishedV2(value, options) {
|
|
|
3142
3195
|
if (!Number.isFinite(expiry) || expiry <= (options.now ?? /* @__PURE__ */ new Date()).getTime() || new Date(expiry).toISOString() !== value.expiry) throw new ShareEnvelopeError("expired", "published share envelope has expired");
|
|
3143
3196
|
if (typeof delegation.cid !== "string" || typeof delegation.issuerDid !== "string" || typeof delegation.audience !== "string" || typeof delegation.expiresAt !== "string" || Date.parse(delegation.expiresAt) > expiry) throw new ShareEnvelopeError("invalid-envelope", "published v2 delegation is invalid");
|
|
3144
3197
|
const matcher = value.recipientMatcher;
|
|
3145
|
-
if (!isPlainObject(matcher) || matcher.kind !== "exactEmail" && matcher.kind !== "emailDomain" || typeof matcher.value !== "string") throw new ShareEnvelopeError("invalid-envelope", "published v2 recipient matcher is invalid");
|
|
3198
|
+
if (!isPlainObject(matcher) || matcher.kind !== "exactEmail" && matcher.kind !== "emailDomain" && matcher.kind !== "recipientDid" || typeof matcher.value !== "string") throw new ShareEnvelopeError("invalid-envelope", "published v2 recipient matcher is invalid");
|
|
3146
3199
|
const normalizedMatcher = normalizeRecipient(matcher);
|
|
3147
3200
|
if (normalizedMatcher === void 0 || normalizedMatcher.kind === "bearer") throw new ShareEnvelopeError("invalid-envelope", "published v2 recipient matcher is invalid");
|
|
3148
3201
|
if (!Array.isArray(value.actions)) throw new ShareEnvelopeError("invalid-envelope", "published v2 actions are invalid");
|
|
@@ -3583,10 +3636,11 @@ var ShareConflict = class extends Error {
|
|
|
3583
3636
|
}
|
|
3584
3637
|
};
|
|
3585
3638
|
var ShareAccessError = class extends Error {
|
|
3586
|
-
constructor(code3, message) {
|
|
3639
|
+
constructor(code3, message, details) {
|
|
3587
3640
|
super(message ?? "shared access could not be completed");
|
|
3588
3641
|
this.name = "ShareAccessError";
|
|
3589
3642
|
this.code = code3;
|
|
3643
|
+
this.details = details;
|
|
3590
3644
|
}
|
|
3591
3645
|
};
|
|
3592
3646
|
|
|
@@ -3595,6 +3649,7 @@ var import_zod3 = require("zod");
|
|
|
3595
3649
|
var ShareRecipientTargetSchema = import_zod3.z.discriminatedUnion("kind", [
|
|
3596
3650
|
import_zod3.z.object({ kind: import_zod3.z.literal("exactEmail"), value: import_zod3.z.string().min(1) }).strict(),
|
|
3597
3651
|
import_zod3.z.object({ kind: import_zod3.z.literal("emailDomain"), value: import_zod3.z.string().min(1) }).strict(),
|
|
3652
|
+
import_zod3.z.object({ kind: import_zod3.z.literal("recipientDid"), value: import_zod3.z.string().regex(/^did:[a-z0-9]+:.+$/) }).strict(),
|
|
3598
3653
|
import_zod3.z.object({ kind: import_zod3.z.literal("bearer") }).strict()
|
|
3599
3654
|
]);
|
|
3600
3655
|
var ShareResourceSchema = import_zod3.z.discriminatedUnion("kind", [
|
|
@@ -3638,7 +3693,8 @@ var ShareContentSourceSchema = import_zod3.z.discriminatedUnion("kind", [
|
|
|
3638
3693
|
]);
|
|
3639
3694
|
var ShareAddressedRecipientSchema = import_zod3.z.discriminatedUnion("kind", [
|
|
3640
3695
|
import_zod3.z.object({ kind: import_zod3.z.literal("exactEmail"), value: import_zod3.z.string().min(1) }).strict(),
|
|
3641
|
-
import_zod3.z.object({ kind: import_zod3.z.literal("emailDomain"), value: import_zod3.z.string().min(1) }).strict()
|
|
3696
|
+
import_zod3.z.object({ kind: import_zod3.z.literal("emailDomain"), value: import_zod3.z.string().min(1) }).strict(),
|
|
3697
|
+
import_zod3.z.object({ kind: import_zod3.z.literal("recipientDid"), value: import_zod3.z.string().regex(/^did:[a-z0-9]+:.+$/) }).strict()
|
|
3642
3698
|
]);
|
|
3643
3699
|
var ShareAddressedDelegationRequestV2Schema = import_zod3.z.object({
|
|
3644
3700
|
version: import_zod3.z.literal(2),
|
|
@@ -3721,6 +3777,506 @@ var ShareNativeResponseSchema = import_zod3.z.discriminatedUnion("action", [
|
|
|
3721
3777
|
}).strict()
|
|
3722
3778
|
]);
|
|
3723
3779
|
|
|
3780
|
+
// src/delegations/portable.ts
|
|
3781
|
+
var import_zod5 = require("zod");
|
|
3782
|
+
|
|
3783
|
+
// src/policy/unified.ts
|
|
3784
|
+
var import_sha2563 = require("@noble/hashes/sha256");
|
|
3785
|
+
var import_blake32 = require("@noble/hashes/blake3");
|
|
3786
|
+
var import_ed255192 = require("@noble/curves/ed25519");
|
|
3787
|
+
var import_zod4 = require("zod");
|
|
3788
|
+
|
|
3789
|
+
// src/policy/errors.ts
|
|
3790
|
+
var SignedObjectProfileError = class extends Error {
|
|
3791
|
+
constructor(code3, message) {
|
|
3792
|
+
super(message);
|
|
3793
|
+
this.name = "SignedObjectProfileError";
|
|
3794
|
+
this.code = code3;
|
|
3795
|
+
}
|
|
3796
|
+
};
|
|
3797
|
+
var SignedObjectCanonicalizationError = class extends SignedObjectProfileError {
|
|
3798
|
+
constructor(message) {
|
|
3799
|
+
super("canonicalization-mismatch", message);
|
|
3800
|
+
this.name = "SignedObjectCanonicalizationError";
|
|
3801
|
+
}
|
|
3802
|
+
};
|
|
3803
|
+
|
|
3804
|
+
// src/policy/jcs.ts
|
|
3805
|
+
var objectHasOwn = Object.hasOwn ?? Object.prototype.hasOwnProperty.call.bind(
|
|
3806
|
+
Object.prototype.hasOwnProperty
|
|
3807
|
+
);
|
|
3808
|
+
function jcsCanonicalize(input) {
|
|
3809
|
+
return serialize(normalizeJson(input, "$"));
|
|
3810
|
+
}
|
|
3811
|
+
function normalizeJson(input, path = "$") {
|
|
3812
|
+
if (input === null) {
|
|
3813
|
+
return null;
|
|
3814
|
+
}
|
|
3815
|
+
switch (typeof input) {
|
|
3816
|
+
case "boolean":
|
|
3817
|
+
return input;
|
|
3818
|
+
case "number":
|
|
3819
|
+
if (!Number.isFinite(input)) {
|
|
3820
|
+
throw new SignedObjectCanonicalizationError(
|
|
3821
|
+
`${path} must be a finite JSON number`
|
|
3822
|
+
);
|
|
3823
|
+
}
|
|
3824
|
+
return input;
|
|
3825
|
+
case "string":
|
|
3826
|
+
assertUnicodeScalarString(input, path);
|
|
3827
|
+
return input;
|
|
3828
|
+
case "object":
|
|
3829
|
+
return normalizeJsonObjectOrArray(input, path);
|
|
3830
|
+
case "bigint":
|
|
3831
|
+
case "function":
|
|
3832
|
+
case "symbol":
|
|
3833
|
+
case "undefined":
|
|
3834
|
+
default:
|
|
3835
|
+
throw new SignedObjectCanonicalizationError(
|
|
3836
|
+
`${path} is not a JSON value`
|
|
3837
|
+
);
|
|
3838
|
+
}
|
|
3839
|
+
}
|
|
3840
|
+
function serialize(value) {
|
|
3841
|
+
if (value === null) {
|
|
3842
|
+
return "null";
|
|
3843
|
+
}
|
|
3844
|
+
switch (typeof value) {
|
|
3845
|
+
case "boolean":
|
|
3846
|
+
return value ? "true" : "false";
|
|
3847
|
+
case "number": {
|
|
3848
|
+
const encoded = JSON.stringify(value);
|
|
3849
|
+
if (encoded === void 0) {
|
|
3850
|
+
throw new SignedObjectCanonicalizationError(
|
|
3851
|
+
"number could not be serialized as JSON"
|
|
3852
|
+
);
|
|
3853
|
+
}
|
|
3854
|
+
return encoded;
|
|
3855
|
+
}
|
|
3856
|
+
case "string":
|
|
3857
|
+
return JSON.stringify(value);
|
|
3858
|
+
case "object":
|
|
3859
|
+
if (Array.isArray(value)) {
|
|
3860
|
+
return `[${value.map((item) => serialize(item)).join(",")}]`;
|
|
3861
|
+
}
|
|
3862
|
+
return serializeObject(value);
|
|
3863
|
+
default:
|
|
3864
|
+
throw new SignedObjectCanonicalizationError(
|
|
3865
|
+
`unsupported JSON value type ${typeof value}`
|
|
3866
|
+
);
|
|
3867
|
+
}
|
|
3868
|
+
}
|
|
3869
|
+
function normalizeJsonObjectOrArray(input, path) {
|
|
3870
|
+
assertNoSymbolKeys(input, path);
|
|
3871
|
+
if (Array.isArray(input)) {
|
|
3872
|
+
for (const key of Object.getOwnPropertyNames(input)) {
|
|
3873
|
+
if (key === "length") {
|
|
3874
|
+
continue;
|
|
3875
|
+
}
|
|
3876
|
+
if (!isArrayIndexKey(key, input.length)) {
|
|
3877
|
+
throw new SignedObjectCanonicalizationError(
|
|
3878
|
+
`${path}.${key} is not allowed on a JSON array`
|
|
3879
|
+
);
|
|
3880
|
+
}
|
|
3881
|
+
const descriptor = Object.getOwnPropertyDescriptor(input, key);
|
|
3882
|
+
if (descriptor?.enumerable !== true) {
|
|
3883
|
+
throw new SignedObjectCanonicalizationError(
|
|
3884
|
+
`${path}[${key}] must be an enumerable JSON array item`
|
|
3885
|
+
);
|
|
3886
|
+
}
|
|
3887
|
+
if (!("value" in descriptor)) {
|
|
3888
|
+
throw new SignedObjectCanonicalizationError(
|
|
3889
|
+
`${path}[${key}] must be a JSON data property`
|
|
3890
|
+
);
|
|
3891
|
+
}
|
|
3892
|
+
}
|
|
3893
|
+
const output2 = [];
|
|
3894
|
+
for (let index = 0; index < input.length; index++) {
|
|
3895
|
+
if (!objectHasOwn(input, index)) {
|
|
3896
|
+
throw new SignedObjectCanonicalizationError(
|
|
3897
|
+
`${path}[${index}] must not be a sparse array hole`
|
|
3898
|
+
);
|
|
3899
|
+
}
|
|
3900
|
+
output2.push(normalizeJson(input[index], `${path}[${index}]`));
|
|
3901
|
+
}
|
|
3902
|
+
return output2;
|
|
3903
|
+
}
|
|
3904
|
+
const proto = Object.getPrototypeOf(input);
|
|
3905
|
+
if (proto !== Object.prototype && proto !== null) {
|
|
3906
|
+
throw new SignedObjectCanonicalizationError(
|
|
3907
|
+
`${path} must be a plain JSON object`
|
|
3908
|
+
);
|
|
3909
|
+
}
|
|
3910
|
+
const output = /* @__PURE__ */ Object.create(null);
|
|
3911
|
+
for (const key of Object.getOwnPropertyNames(input)) {
|
|
3912
|
+
assertUnicodeScalarString(key, `${path} key`);
|
|
3913
|
+
if (key === "__proto__" || key === "constructor") {
|
|
3914
|
+
throw new SignedObjectCanonicalizationError(
|
|
3915
|
+
`${path}.${key} is not allowed`
|
|
3916
|
+
);
|
|
3917
|
+
}
|
|
3918
|
+
const descriptor = Object.getOwnPropertyDescriptor(input, key);
|
|
3919
|
+
if (descriptor?.enumerable !== true) {
|
|
3920
|
+
throw new SignedObjectCanonicalizationError(
|
|
3921
|
+
`${path}.${key} must be an enumerable JSON object property`
|
|
3922
|
+
);
|
|
3923
|
+
}
|
|
3924
|
+
if (!("value" in descriptor)) {
|
|
3925
|
+
throw new SignedObjectCanonicalizationError(
|
|
3926
|
+
`${path}.${key} must be a JSON data property`
|
|
3927
|
+
);
|
|
3928
|
+
}
|
|
3929
|
+
const value = descriptor.value;
|
|
3930
|
+
output[key] = normalizeJson(value, `${path}.${key}`);
|
|
3931
|
+
}
|
|
3932
|
+
return output;
|
|
3933
|
+
}
|
|
3934
|
+
function assertNoSymbolKeys(input, path) {
|
|
3935
|
+
if (Object.getOwnPropertySymbols(input).length > 0) {
|
|
3936
|
+
throw new SignedObjectCanonicalizationError(
|
|
3937
|
+
`${path} must not have symbol properties`
|
|
3938
|
+
);
|
|
3939
|
+
}
|
|
3940
|
+
}
|
|
3941
|
+
function isArrayIndexKey(key, length2) {
|
|
3942
|
+
if (!/^(0|[1-9]\d*)$/.test(key)) {
|
|
3943
|
+
return false;
|
|
3944
|
+
}
|
|
3945
|
+
const index = Number(key);
|
|
3946
|
+
return Number.isSafeInteger(index) && index >= 0 && index < length2;
|
|
3947
|
+
}
|
|
3948
|
+
function serializeObject(value) {
|
|
3949
|
+
const keys = Object.keys(value).sort(compareUtf16CodeUnits);
|
|
3950
|
+
const parts = keys.map((key) => `${JSON.stringify(key)}:${serialize(value[key])}`);
|
|
3951
|
+
return `{${parts.join(",")}}`;
|
|
3952
|
+
}
|
|
3953
|
+
function compareUtf16CodeUnits(a, b) {
|
|
3954
|
+
const max = Math.min(a.length, b.length);
|
|
3955
|
+
for (let index = 0; index < max; index++) {
|
|
3956
|
+
const leftCodeUnit = a.charCodeAt(index);
|
|
3957
|
+
const rightCodeUnit = b.charCodeAt(index);
|
|
3958
|
+
if (leftCodeUnit !== rightCodeUnit) {
|
|
3959
|
+
return leftCodeUnit - rightCodeUnit;
|
|
3960
|
+
}
|
|
3961
|
+
}
|
|
3962
|
+
return a.length - b.length;
|
|
3963
|
+
}
|
|
3964
|
+
function assertUnicodeScalarString(value, path) {
|
|
3965
|
+
for (let index = 0; index < value.length; index++) {
|
|
3966
|
+
const code3 = value.charCodeAt(index);
|
|
3967
|
+
if (code3 >= 55296 && code3 <= 56319) {
|
|
3968
|
+
const next = value.charCodeAt(index + 1);
|
|
3969
|
+
if (Number.isNaN(next) || next < 56320 || next > 57343) {
|
|
3970
|
+
throw new SignedObjectCanonicalizationError(
|
|
3971
|
+
`${path} contains a lone high surrogate`
|
|
3972
|
+
);
|
|
3973
|
+
}
|
|
3974
|
+
index++;
|
|
3975
|
+
continue;
|
|
3976
|
+
}
|
|
3977
|
+
if (code3 >= 56320 && code3 <= 57343) {
|
|
3978
|
+
throw new SignedObjectCanonicalizationError(
|
|
3979
|
+
`${path} contains a lone low surrogate`
|
|
3980
|
+
);
|
|
3981
|
+
}
|
|
3982
|
+
}
|
|
3983
|
+
}
|
|
3984
|
+
|
|
3985
|
+
// src/policy/unified.ts
|
|
3986
|
+
var POLICY_SESSION_UCAN_V1_PROFILE = "policy-session-ucan/v1";
|
|
3987
|
+
var POLICY_SESSION_FACT_KEYS = [
|
|
3988
|
+
"profile",
|
|
3989
|
+
"ownerDid",
|
|
3990
|
+
"policyId",
|
|
3991
|
+
"policyDigestHex",
|
|
3992
|
+
"policyCid",
|
|
3993
|
+
"policyDelegationCid",
|
|
3994
|
+
"enforcementDelegationCid",
|
|
3995
|
+
"contentSourceDigestHex",
|
|
3996
|
+
"capabilityCeilingHashHex",
|
|
3997
|
+
"nativeProjectionHashHex",
|
|
3998
|
+
"enforcerDid",
|
|
3999
|
+
"nodeAudience",
|
|
4000
|
+
"recipientDid",
|
|
4001
|
+
"challengeId",
|
|
4002
|
+
"claimDigestHex",
|
|
4003
|
+
"claimJti",
|
|
4004
|
+
"vpDigestHex",
|
|
4005
|
+
"credentialEvidenceDigestHex",
|
|
4006
|
+
"decisionContextDigestHex",
|
|
4007
|
+
"issuanceAuditDigestHex",
|
|
4008
|
+
"remainingRedelegationDepth"
|
|
4009
|
+
];
|
|
4010
|
+
var CompactHeaderSchema = import_zod4.z.object({
|
|
4011
|
+
alg: import_zod4.z.literal("EdDSA"),
|
|
4012
|
+
jwk: import_zod4.z.object({ alg: import_zod4.z.literal("EdDSA"), crv: import_zod4.z.literal("Ed25519"), kty: import_zod4.z.literal("OKP"), x: import_zod4.z.string().min(1) }).strict(),
|
|
4013
|
+
typ: import_zod4.z.literal("JWT"),
|
|
4014
|
+
ucv: import_zod4.z.literal("0.10.0")
|
|
4015
|
+
}).strict();
|
|
4016
|
+
var CompactPayloadSchema = import_zod4.z.object({
|
|
4017
|
+
att: import_zod4.z.record(import_zod4.z.record(import_zod4.z.array(import_zod4.z.unknown()).min(1))),
|
|
4018
|
+
aud: import_zod4.z.string().min(1),
|
|
4019
|
+
exp: import_zod4.z.number().int(),
|
|
4020
|
+
fct: import_zod4.z.array(import_zod4.z.record(import_zod4.z.unknown())).length(1),
|
|
4021
|
+
iss: import_zod4.z.string().min(1),
|
|
4022
|
+
nbf: import_zod4.z.number().int(),
|
|
4023
|
+
nnc: import_zod4.z.string().min(1),
|
|
4024
|
+
prf: import_zod4.z.array(import_zod4.z.string().min(1))
|
|
4025
|
+
}).strict();
|
|
4026
|
+
function createCompactPolicyInvocation(input) {
|
|
4027
|
+
const session = parsePolicySessionUcan(input.sessionAuthorization);
|
|
4028
|
+
if (session.cid !== input.sessionCid || session.aud !== input.recipientDid)
|
|
4029
|
+
throw new Error("policy session does not bind the recipient signer");
|
|
4030
|
+
const principal = input.recipientDid.split("#", 1)[0];
|
|
4031
|
+
const didMaterial = base58btc.decode(principal.slice("did:key:".length));
|
|
4032
|
+
if (didMaterial.length !== 34 || didMaterial[0] !== 237 || didMaterial[1] !== 1)
|
|
4033
|
+
throw new Error("policy invocation signer must be did:key Ed25519");
|
|
4034
|
+
const publicKey = import_ed255192.ed25519.getPublicKey(input.privateKey);
|
|
4035
|
+
if (!equalBytes2(publicKey, didMaterial.slice(2)))
|
|
4036
|
+
throw new Error("policy invocation private key does not bind recipient DID");
|
|
4037
|
+
const now = input.now ?? Math.floor(Date.now() / 1e3);
|
|
4038
|
+
const exp = Math.min(now + 60, session.exp);
|
|
4039
|
+
if (exp <= now) throw new Error("policy session has expired");
|
|
4040
|
+
const header = { alg: "EdDSA", jwk: { alg: "EdDSA", crv: "Ed25519", kty: "OKP", x: encodeBase64Url(publicKey) }, typ: "JWT", ucv: "0.10.0" };
|
|
4041
|
+
const payload = {
|
|
4042
|
+
att: { [input.resource]: { [input.action]: [input.caveat ?? {}] } },
|
|
4043
|
+
aud: input.audienceDid,
|
|
4044
|
+
exp,
|
|
4045
|
+
fct: [input.facts ?? { type: "tinycloud.policy.invocation/v1", policyCid: session.fact.policyCid, sessionCid: session.cid }],
|
|
4046
|
+
iss: input.recipientDid.includes("#") ? input.recipientDid : `${principal}#${principal.slice("did:key:".length)}`,
|
|
4047
|
+
nbf: now,
|
|
4048
|
+
nnc: input.nonce ?? encodeBase64Url(crypto.getRandomValues(new Uint8Array(16))),
|
|
4049
|
+
prf: [session.cid]
|
|
4050
|
+
};
|
|
4051
|
+
const protectedSegment = encodeBase64Url(new TextEncoder().encode(jcsCanonicalize(header)));
|
|
4052
|
+
const payloadSegment = encodeBase64Url(new TextEncoder().encode(jcsCanonicalize(payload)));
|
|
4053
|
+
const signingInput = new TextEncoder().encode(`${protectedSegment}.${payloadSegment}`);
|
|
4054
|
+
const signature = import_ed255192.ed25519.sign(signingInput, input.privateKey);
|
|
4055
|
+
return parseCompactUcanAuthorization(`${protectedSegment}.${payloadSegment}.${encodeBase64Url(signature)}`);
|
|
4056
|
+
}
|
|
4057
|
+
function createCompactPolicyDescendant(input) {
|
|
4058
|
+
const parent = parseCompactUcanAuthorization(input.parentAuthorization, input.parentCid);
|
|
4059
|
+
if (parent.payload.aud !== input.issuerDid) throw new Error("policy descendant issuer is not the parent audience");
|
|
4060
|
+
const parentFact = parent.payload.fct[0];
|
|
4061
|
+
const depth = parentFact.remainingRedelegationDepth;
|
|
4062
|
+
if (!Number.isInteger(depth) || depth <= 0) throw new Error("policy descendant depth is exhausted");
|
|
4063
|
+
if (!compactAttenuationContains(parent.payload.att, input.attenuation))
|
|
4064
|
+
throw new Error("policy descendant exceeds the parent attenuation");
|
|
4065
|
+
const principal = input.issuerDid.split("#", 1)[0];
|
|
4066
|
+
const didMaterial = base58btc.decode(principal.slice("did:key:".length));
|
|
4067
|
+
const publicKey = import_ed255192.ed25519.getPublicKey(input.privateKey);
|
|
4068
|
+
if (didMaterial.length !== 34 || !equalBytes2(publicKey, didMaterial.slice(2))) throw new Error("policy descendant signer does not bind issuer DID");
|
|
4069
|
+
const now = Math.max(input.now ?? Math.floor(Date.now() / 1e3), parent.payload.nbf + 1);
|
|
4070
|
+
const exp = Math.min(input.expiresAt ?? now + 60, now + 60, parent.payload.exp - 1);
|
|
4071
|
+
if (exp <= now) throw new Error("policy parent has no strictly narrower validity window");
|
|
4072
|
+
const header = { alg: "EdDSA", jwk: { alg: "EdDSA", crv: "Ed25519", kty: "OKP", x: encodeBase64Url(publicKey) }, typ: "JWT", ucv: "0.10.0" };
|
|
4073
|
+
const payload = {
|
|
4074
|
+
att: input.attenuation,
|
|
4075
|
+
aud: input.audienceDid,
|
|
4076
|
+
exp,
|
|
4077
|
+
fct: [{ ...parentFact, remainingRedelegationDepth: depth - 1 }],
|
|
4078
|
+
iss: input.issuerDid.includes("#") ? input.issuerDid : `${principal}#${principal.slice("did:key:".length)}`,
|
|
4079
|
+
nbf: now,
|
|
4080
|
+
nnc: input.nonce ?? encodeBase64Url(crypto.getRandomValues(new Uint8Array(16))),
|
|
4081
|
+
prf: [parent.cid]
|
|
4082
|
+
};
|
|
4083
|
+
const protectedSegment = encodeBase64Url(new TextEncoder().encode(jcsCanonicalize(header)));
|
|
4084
|
+
const payloadSegment = encodeBase64Url(new TextEncoder().encode(jcsCanonicalize(payload)));
|
|
4085
|
+
const signature = import_ed255192.ed25519.sign(new TextEncoder().encode(`${protectedSegment}.${payloadSegment}`), input.privateKey);
|
|
4086
|
+
return parseCompactUcanAuthorization(`${protectedSegment}.${payloadSegment}.${encodeBase64Url(signature)}`);
|
|
4087
|
+
}
|
|
4088
|
+
function compactAttenuationContains(parent, child) {
|
|
4089
|
+
const selector = (value) => {
|
|
4090
|
+
if (value.length !== 1 || !isRecordValue(value[0])) return void 0;
|
|
4091
|
+
const caveat = value[0];
|
|
4092
|
+
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;
|
|
4093
|
+
return { kind: caveat.kind, value: caveat.value };
|
|
4094
|
+
};
|
|
4095
|
+
const equal = (left, right) => jcsCanonicalize(left) === jcsCanonicalize(right);
|
|
4096
|
+
return Object.entries(child).every(
|
|
4097
|
+
([childResource, childActions]) => Object.entries(childActions).every(
|
|
4098
|
+
([action, childCaveats]) => Object.entries(parent).some(([parentResource, parentActions]) => {
|
|
4099
|
+
const parentCaveats = parentActions[action];
|
|
4100
|
+
if (parentCaveats === void 0) return false;
|
|
4101
|
+
if (parentResource === childResource && equal(parentCaveats, childCaveats)) return true;
|
|
4102
|
+
const parentSelector = selector(parentCaveats);
|
|
4103
|
+
const childSelector = selector(childCaveats);
|
|
4104
|
+
return parentSelector?.kind === "prefix" && childSelector !== void 0 && parentSelector.value === parentResource && childSelector.value === childResource && (childResource === parentResource || childResource.startsWith(`${parentResource}/`));
|
|
4105
|
+
})
|
|
4106
|
+
)
|
|
4107
|
+
);
|
|
4108
|
+
}
|
|
4109
|
+
function isRecordValue(value) {
|
|
4110
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4111
|
+
}
|
|
4112
|
+
function parseCompactUcanAuthorization(input, expectedCid) {
|
|
4113
|
+
if (typeof input !== "string" || /\s/.test(input))
|
|
4114
|
+
throw new Error("Authorization must be compact UCAN bytes");
|
|
4115
|
+
const segments = input.split(".");
|
|
4116
|
+
if (segments.length !== 3 || segments.some((segment) => segment.length === 0))
|
|
4117
|
+
throw new Error("Authorization must have three compact segments");
|
|
4118
|
+
const [headerSegment, payloadSegment, signatureSegment] = segments;
|
|
4119
|
+
const headerBytes = decodeBase64Url(headerSegment);
|
|
4120
|
+
const payloadBytes = decodeBase64Url(payloadSegment);
|
|
4121
|
+
const signature = decodeBase64Url(signatureSegment);
|
|
4122
|
+
const headerValue = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(headerBytes));
|
|
4123
|
+
const payloadValue = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(payloadBytes));
|
|
4124
|
+
if (jcsCanonicalize(headerValue) !== new TextDecoder().decode(headerBytes) || jcsCanonicalize(payloadValue) !== new TextDecoder().decode(payloadBytes))
|
|
4125
|
+
throw new Error("compact UCAN segments are not canonical JCS");
|
|
4126
|
+
const header = CompactHeaderSchema.parse(headerValue);
|
|
4127
|
+
const payload = CompactPayloadSchema.parse(payloadValue);
|
|
4128
|
+
if (payload.nbf >= payload.exp) throw new Error("compact UCAN validity is empty");
|
|
4129
|
+
const principal = payload.iss.split("#", 1)[0];
|
|
4130
|
+
const didMaterial = principal.startsWith("did:key:") ? base58btc.decode(principal.slice("did:key:".length)) : new Uint8Array();
|
|
4131
|
+
if (didMaterial.length !== 34 || didMaterial[0] !== 237 || didMaterial[1] !== 1)
|
|
4132
|
+
throw new Error("compact UCAN issuer must be did:key Ed25519");
|
|
4133
|
+
const publicKey = didMaterial.slice(2);
|
|
4134
|
+
if (!equalBytes2(publicKey, decodeBase64Url(header.jwk.x)))
|
|
4135
|
+
throw new Error("compact UCAN JWK does not bind issuer");
|
|
4136
|
+
if (!import_ed255192.ed25519.verify(signature, new TextEncoder().encode(`${headerSegment}.${payloadSegment}`), publicKey))
|
|
4137
|
+
throw new Error("compact UCAN signature is invalid");
|
|
4138
|
+
const cid2 = CID.createV1(85, create(30, (0, import_blake32.blake3)(new TextEncoder().encode(input)))).toString();
|
|
4139
|
+
if (expectedCid !== void 0 && cid2 !== expectedCid)
|
|
4140
|
+
throw new Error("compact UCAN CID does not match exact Authorization bytes");
|
|
4141
|
+
return { authorization: input, cid: cid2, header, payload };
|
|
4142
|
+
}
|
|
4143
|
+
function parsePolicySessionUcan(authorization, expectedProofs) {
|
|
4144
|
+
const parsed = parseCompactUcanAuthorization(authorization);
|
|
4145
|
+
const fact = parsed.payload.fct[0];
|
|
4146
|
+
if (parsed.payload.prf.length !== 2 || parsed.payload.prf[0] === parsed.payload.prf[1])
|
|
4147
|
+
throw new Error("policy session UCAN requires two distinct ordered proofs");
|
|
4148
|
+
if (expectedProofs !== void 0 && (parsed.payload.prf[0] !== expectedProofs[0] || parsed.payload.prf[1] !== expectedProofs[1]))
|
|
4149
|
+
throw new Error("policy session UCAN ordered proofs do not match");
|
|
4150
|
+
const factKeys = Object.keys(fact);
|
|
4151
|
+
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)))
|
|
4152
|
+
throw new Error("policy session UCAN fact is incomplete");
|
|
4153
|
+
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)
|
|
4154
|
+
throw new Error("policy session UCAN fact is invalid");
|
|
4155
|
+
return {
|
|
4156
|
+
authorization,
|
|
4157
|
+
cid: parsed.cid,
|
|
4158
|
+
iss: parsed.payload.iss,
|
|
4159
|
+
aud: parsed.payload.aud,
|
|
4160
|
+
prf: parsed.payload.prf,
|
|
4161
|
+
att: parsed.payload.att,
|
|
4162
|
+
nbf: parsed.payload.nbf,
|
|
4163
|
+
exp: parsed.payload.exp,
|
|
4164
|
+
nnc: parsed.payload.nnc,
|
|
4165
|
+
fact
|
|
4166
|
+
};
|
|
4167
|
+
}
|
|
4168
|
+
function decodeBase64Url(value) {
|
|
4169
|
+
if (!/^[A-Za-z0-9_-]+$/.test(value) || value.length % 4 === 1)
|
|
4170
|
+
throw new Error("value is not canonical base64url");
|
|
4171
|
+
const normalized = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
4172
|
+
const binary = typeof Buffer !== "undefined" ? Buffer.from(normalized, "base64").toString("binary") : atob(normalized.padEnd(Math.ceil(normalized.length / 4) * 4, "="));
|
|
4173
|
+
const bytes2 = Uint8Array.from(binary, (character) => character.charCodeAt(0));
|
|
4174
|
+
const encoded = typeof Buffer !== "undefined" ? Buffer.from(bytes2).toString("base64url") : btoa(String.fromCharCode(...bytes2)).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
4175
|
+
if (encoded !== value) throw new Error("value is not canonical base64url");
|
|
4176
|
+
return bytes2;
|
|
4177
|
+
}
|
|
4178
|
+
function encodeBase64Url(value) {
|
|
4179
|
+
return typeof Buffer !== "undefined" ? Buffer.from(value).toString("base64url") : btoa(String.fromCharCode(...value)).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
4180
|
+
}
|
|
4181
|
+
function equalBytes2(left, right) {
|
|
4182
|
+
return left.length === right.length && left.every((byte, index) => byte === right[index]);
|
|
4183
|
+
}
|
|
4184
|
+
|
|
4185
|
+
// src/delegations/portable.ts
|
|
4186
|
+
var ResourceSchema = import_zod5.z.object({
|
|
4187
|
+
service: import_zod5.z.string().min(1),
|
|
4188
|
+
space: import_zod5.z.string().min(1),
|
|
4189
|
+
path: import_zod5.z.string(),
|
|
4190
|
+
actions: import_zod5.z.array(import_zod5.z.string().min(1)).min(1),
|
|
4191
|
+
caveats: import_zod5.z.array(import_zod5.z.record(import_zod5.z.unknown())).optional()
|
|
4192
|
+
}).strict();
|
|
4193
|
+
var PortableDelegationSchema = import_zod5.z.object({
|
|
4194
|
+
cid: import_zod5.z.string().min(1),
|
|
4195
|
+
delegationHeader: import_zod5.z.object({ Authorization: import_zod5.z.string().min(1) }).strict(),
|
|
4196
|
+
ownerAddress: import_zod5.z.string().min(1),
|
|
4197
|
+
chainId: import_zod5.z.number().int().nonnegative(),
|
|
4198
|
+
host: import_zod5.z.string().url().optional(),
|
|
4199
|
+
spaceId: import_zod5.z.string().min(1),
|
|
4200
|
+
path: import_zod5.z.string(),
|
|
4201
|
+
actions: import_zod5.z.array(import_zod5.z.string().min(1)).min(1),
|
|
4202
|
+
caveats: import_zod5.z.array(import_zod5.z.record(import_zod5.z.unknown())).optional(),
|
|
4203
|
+
expiry: import_zod5.z.coerce.date(),
|
|
4204
|
+
delegateDID: import_zod5.z.string().min(1),
|
|
4205
|
+
delegatorDID: import_zod5.z.string().min(1).optional(),
|
|
4206
|
+
parentCid: import_zod5.z.string().min(1).optional(),
|
|
4207
|
+
disableSubDelegation: import_zod5.z.boolean().optional(),
|
|
4208
|
+
resources: import_zod5.z.array(ResourceSchema).min(1).optional()
|
|
4209
|
+
}).strict();
|
|
4210
|
+
function parsePortableDelegation(input) {
|
|
4211
|
+
const parsed = PortableDelegationSchema.parse(input);
|
|
4212
|
+
if (parsed.resources !== void 0 && parsed.resources.length === 0)
|
|
4213
|
+
throw new Error("portable delegation resources must not be empty");
|
|
4214
|
+
return parsed;
|
|
4215
|
+
}
|
|
4216
|
+
function serializePortableDelegation(delegation) {
|
|
4217
|
+
return JSON.stringify({
|
|
4218
|
+
...delegation,
|
|
4219
|
+
expiry: delegation.expiry.toISOString()
|
|
4220
|
+
});
|
|
4221
|
+
}
|
|
4222
|
+
async function importPortableDelegation(fetchFn, host, delegation) {
|
|
4223
|
+
const parsed = parsePortableDelegation(delegation);
|
|
4224
|
+
const response = await fetchFn(`${host.replace(/\/+$/, "")}/delegate`, {
|
|
4225
|
+
method: "POST",
|
|
4226
|
+
headers: { Authorization: parsed.delegationHeader.Authorization }
|
|
4227
|
+
});
|
|
4228
|
+
if (!response.ok)
|
|
4229
|
+
throw new Error(`node rejected delegation import (${response.status})`);
|
|
4230
|
+
const body = await response.json().catch(() => ({}));
|
|
4231
|
+
if (body === null || typeof body !== "object" || Array.isArray(body))
|
|
4232
|
+
return {};
|
|
4233
|
+
return body;
|
|
4234
|
+
}
|
|
4235
|
+
async function delegatePortablePolicySession(input) {
|
|
4236
|
+
const parent = parsePortableDelegation(input.parent);
|
|
4237
|
+
const descendant = createCompactPolicyDescendant({
|
|
4238
|
+
parentAuthorization: parent.delegationHeader.Authorization.replace(/^Bearer\s+/i, ""),
|
|
4239
|
+
parentCid: parent.cid,
|
|
4240
|
+
issuerDid: parent.delegateDID,
|
|
4241
|
+
audienceDid: input.delegateDID,
|
|
4242
|
+
attenuation: input.attenuation,
|
|
4243
|
+
privateKey: input.issuerPrivateKey,
|
|
4244
|
+
...input.now === void 0 ? {} : { now: input.now },
|
|
4245
|
+
...input.expiresAt === void 0 ? {} : { expiresAt: input.expiresAt },
|
|
4246
|
+
...input.nonce === void 0 ? {} : { nonce: input.nonce }
|
|
4247
|
+
});
|
|
4248
|
+
const resources = Object.entries(descendant.payload.att).map(([resource, abilities]) => {
|
|
4249
|
+
const actions = Object.keys(abilities);
|
|
4250
|
+
if (resource.startsWith("urn:tinycloud:encryption:")) {
|
|
4251
|
+
return { service: "encryption", space: "encryption", path: resource, actions };
|
|
4252
|
+
}
|
|
4253
|
+
const match = /^tinycloud:\/\/([^/]+)\/kv\/(.+)$/.exec(resource);
|
|
4254
|
+
if (match === null) throw new Error("policy descendant resource is invalid");
|
|
4255
|
+
const caveats = Object.values(abilities).flat().filter((value) => value !== null && typeof value === "object" && !Array.isArray(value));
|
|
4256
|
+
return { service: "kv", space: match[1], path: match[2], actions, ...caveats.length === 0 ? {} : { caveats } };
|
|
4257
|
+
});
|
|
4258
|
+
const primary = resources.find((resource) => resource.service === "kv") ?? resources[0];
|
|
4259
|
+
if (primary === void 0) throw new Error("policy descendant attenuation is empty");
|
|
4260
|
+
const portable = {
|
|
4261
|
+
cid: descendant.cid,
|
|
4262
|
+
delegationHeader: { Authorization: descendant.authorization },
|
|
4263
|
+
ownerAddress: parent.ownerAddress,
|
|
4264
|
+
chainId: parent.chainId,
|
|
4265
|
+
host: input.host,
|
|
4266
|
+
spaceId: primary.space,
|
|
4267
|
+
path: primary.path,
|
|
4268
|
+
actions: primary.actions,
|
|
4269
|
+
expiry: new Date(descendant.payload.exp * 1e3),
|
|
4270
|
+
delegateDID: input.delegateDID,
|
|
4271
|
+
delegatorDID: parent.delegateDID,
|
|
4272
|
+
parentCid: parent.cid,
|
|
4273
|
+
disableSubDelegation: descendant.payload.fct[0]?.remainingRedelegationDepth === 0,
|
|
4274
|
+
resources
|
|
4275
|
+
};
|
|
4276
|
+
await importPortableDelegation(input.fetch, input.host, portable);
|
|
4277
|
+
return portable;
|
|
4278
|
+
}
|
|
4279
|
+
|
|
3724
4280
|
// src/delegations/ShareRecipientClient.ts
|
|
3725
4281
|
var DEFAULT_MAX_ARTIFACT_BYTES2 = MAX_SHARE_ARTIFACT_BYTES;
|
|
3726
4282
|
var DEFAULT_MAX_CONTENT_BYTES = MAX_SHARE_CONTENT_BYTES;
|
|
@@ -3796,7 +4352,7 @@ function randomJti() {
|
|
|
3796
4352
|
return bytesToBase64Url2(bytes2);
|
|
3797
4353
|
}
|
|
3798
4354
|
function digestCanonical(value) {
|
|
3799
|
-
return bytesToBase64Url2((0,
|
|
4355
|
+
return bytesToBase64Url2((0, import_sha2564.sha256)(new TextEncoder().encode(canonicalJsonForProof(value))));
|
|
3800
4356
|
}
|
|
3801
4357
|
function actionWire(action) {
|
|
3802
4358
|
return action === "get" ? "tinycloud.kv/get" : action === "metadata" ? "tinycloud.kv/metadata" : action === "list" ? "tinycloud.kv/list" : "tinycloud.kv/put";
|
|
@@ -3893,15 +4449,46 @@ var ShareRecipientClient = class {
|
|
|
3893
4449
|
const { envelope } = resolved.artifact;
|
|
3894
4450
|
const { location } = resolved;
|
|
3895
4451
|
const bearer = isBearerEnvelope(envelope);
|
|
3896
|
-
const policy = envelope.recipientKind === "exactEmail" || envelope.recipientKind === "emailDomain";
|
|
4452
|
+
const policy = envelope.recipientKind === "exactEmail" || envelope.recipientKind === "emailDomain" || envelope.authorizationTargetKind === "recipientDid";
|
|
3897
4453
|
const legacyBearer = !policy && envelope.recipientKind === void 0;
|
|
3898
|
-
|
|
4454
|
+
let recipientDidSession;
|
|
4455
|
+
if (envelope.authorizationTargetKind === "recipientDid") {
|
|
4456
|
+
if (this.options.establishRecipientDidSession === void 0) throw new ShareAccessError("SHARE_DEVICE_AUTH_REQUIRED", "an OpenKey device authorization is required");
|
|
4457
|
+
const authorization = await this.options.establishRecipientDidSession({ envelope, recipientDid: envelope.recipient?.kind === "recipientDid" ? envelope.recipient.value : "" });
|
|
4458
|
+
if ("state" in authorization) {
|
|
4459
|
+
if (authorization.state === "authorization-required") throw new ShareAccessError("SHARE_DEVICE_AUTH_REQUIRED", "an OpenKey device authorization is required", authorization);
|
|
4460
|
+
throw new ShareAccessError("SHARE_DENIED", "recipient DID authorization was denied", authorization);
|
|
4461
|
+
}
|
|
4462
|
+
recipientDidSession = authorization;
|
|
4463
|
+
}
|
|
3899
4464
|
if (policy && this.options.bearerSession !== void 0) throw new ShareAccessError("SHARE_POLICY_BEARER_MISMATCH");
|
|
3900
4465
|
if (bearer && this.options.presentation !== void 0) throw new ShareAccessError("SHARE_BEARER_PRESENTATION_MISMATCH");
|
|
3901
|
-
const session = bearer || legacyBearer ? this.options.bearerSession : policy && this.options.establishPolicySession !== void 0 ? await this.options.establishPolicySession({ envelope, presentation: this.options.presentation }) : policy ? await this.establishPolicySession(envelope) : void 0;
|
|
3902
|
-
const kv = bearer || legacyBearer ? session === void 0 ? void 0 : this.createKV(envelope.origin, session) : void 0;
|
|
4466
|
+
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;
|
|
3903
4467
|
const policySession = policy ? session : void 0;
|
|
3904
4468
|
if (policySession !== void 0) this.assertProvidedPolicySession(policySession, envelope);
|
|
4469
|
+
const portableDelegation = policySession === void 0 ? void 0 : this.policySessionDelegation(policySession, envelope.origin);
|
|
4470
|
+
const portableInvoke = portableDelegation === void 0 ? void 0 : this.policyInvocationSigner(portableDelegation);
|
|
4471
|
+
if (portableDelegation !== void 0) {
|
|
4472
|
+
if (this.options.importDelegation === void 0) {
|
|
4473
|
+
await importPortableDelegation(this.fetchFn, envelope.origin, portableDelegation);
|
|
4474
|
+
} else {
|
|
4475
|
+
const imported = await this.options.importDelegation(portableDelegation);
|
|
4476
|
+
if (imported !== void 0) {
|
|
4477
|
+
const normalized = parsePortableDelegation(imported);
|
|
4478
|
+
if (normalized.delegationHeader.Authorization !== portableDelegation.delegationHeader.Authorization) {
|
|
4479
|
+
throw new ShareAccessError("SHARE_SESSION_INVALID", "delegation importer changed authorization bytes");
|
|
4480
|
+
}
|
|
4481
|
+
}
|
|
4482
|
+
}
|
|
4483
|
+
}
|
|
4484
|
+
const ordinarySession = portableDelegation === void 0 ? void 0 : {
|
|
4485
|
+
delegationHeader: portableDelegation.delegationHeader,
|
|
4486
|
+
delegationCid: portableDelegation.cid,
|
|
4487
|
+
spaceId: this.policySessionProjection(portableDelegation).spaceId,
|
|
4488
|
+
verificationMethod: portableDelegation.delegateDID,
|
|
4489
|
+
jwk: this.options.bearerSession?.jwk ?? {}
|
|
4490
|
+
};
|
|
4491
|
+
const kv = bearer || legacyBearer || ordinarySession !== void 0 ? session === void 0 && ordinarySession === void 0 ? void 0 : this.createKV(envelope.origin, ordinarySession ?? session, portableInvoke) : void 0;
|
|
3905
4492
|
const advertisedCapability = { spaceId: envelope.spaceId, resource: envelope.resource, actions: envelope.actions };
|
|
3906
4493
|
const capability = policySession?.capability === void 0 ? advertisedCapability : intersectShareCapabilities(advertisedCapability, policySession.capability);
|
|
3907
4494
|
if (capability === void 0) throw new ShareAccessError("SHARE_CAPABILITY_EMPTY");
|
|
@@ -3926,6 +4513,11 @@ var ShareRecipientClient = class {
|
|
|
3926
4513
|
const scope = normalizePath(input.path ?? envelope.resource.path);
|
|
3927
4514
|
this.assertAllowed(capability, "list", scope);
|
|
3928
4515
|
if (kv === void 0 && policySession === void 0) throw new ShareAccessError("SHARE_SESSION_REQUIRED");
|
|
4516
|
+
if (portableDelegation !== void 0 && kv !== void 0) {
|
|
4517
|
+
const result2 = await kv.list({ path: scope, limit: input.limit, cursor: input.cursor });
|
|
4518
|
+
if (!result2.ok) throw result2.error;
|
|
4519
|
+
return { keys: result2.data.keys, truncated: result2.data.truncated, nextCursor: result2.data.nextCursor };
|
|
4520
|
+
}
|
|
3929
4521
|
if (policySession !== void 0) return this.nativeList(envelope, policySession, scope, input.limit, input.cursor);
|
|
3930
4522
|
const result = await kv.list({ path: scope, limit: input.limit, cursor: input.cursor });
|
|
3931
4523
|
if (!result.ok) throw result.error;
|
|
@@ -3939,6 +4531,14 @@ var ShareRecipientClient = class {
|
|
|
3939
4531
|
const resolvedPath = normalizePath(path);
|
|
3940
4532
|
this.assertAllowed(capability, "save", resolvedPath);
|
|
3941
4533
|
if (kv === void 0 && policySession === void 0) throw new ShareAccessError("SHARE_SESSION_REQUIRED");
|
|
4534
|
+
if (portableDelegation !== void 0 && kv !== void 0) {
|
|
4535
|
+
const result2 = await kv.put(resolvedPath, bytes2, { contentType: input.contentType ?? envelope.content.mimeType, ifMatch: input.etag });
|
|
4536
|
+
if (!result2.ok) {
|
|
4537
|
+
if (result2.error.code === import_sdk_services2.ErrorCodes.KV_PRECONDITION_FAILED || result2.error.code === import_sdk_services2.ErrorCodes.KV_CONFLICT) throw new ShareConflict(resolvedPath, result2.error.meta?.etag);
|
|
4538
|
+
throw result2.error;
|
|
4539
|
+
}
|
|
4540
|
+
return { etag: result2.data.headers.etag };
|
|
4541
|
+
}
|
|
3942
4542
|
if (policySession !== void 0) return this.nativeSave(envelope, policySession, resolvedPath, bytes2, input);
|
|
3943
4543
|
const result = await kv.put(resolvedPath, bytes2, { contentType: input.contentType ?? envelope.content.mimeType, ifMatch: input.etag });
|
|
3944
4544
|
if (!result.ok) {
|
|
@@ -3954,22 +4554,79 @@ var ShareRecipientClient = class {
|
|
|
3954
4554
|
const metadata = async (path = envelope.resource.kind === "exact" ? envelope.resource.path : "") => {
|
|
3955
4555
|
const resolvedPath = normalizePath(path);
|
|
3956
4556
|
this.assertAllowed(capability, "metadata", resolvedPath);
|
|
4557
|
+
if (portableDelegation !== void 0 && kv !== void 0) {
|
|
4558
|
+
const result2 = await kv.head(resolvedPath);
|
|
4559
|
+
if (!result2.ok) throw result2.error;
|
|
4560
|
+
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 };
|
|
4561
|
+
}
|
|
3957
4562
|
if (policySession !== void 0) return this.nativeMetadata(envelope, policySession, resolvedPath);
|
|
3958
4563
|
if (kv === void 0) throw new ShareAccessError("SHARE_SESSION_REQUIRED");
|
|
3959
4564
|
const result = await kv.head(resolvedPath);
|
|
3960
4565
|
if (!result.ok) throw result.error;
|
|
3961
4566
|
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 };
|
|
3962
4567
|
};
|
|
3963
|
-
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 };
|
|
4568
|
+
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 };
|
|
3964
4569
|
} catch (error) {
|
|
3965
4570
|
throw asError(error);
|
|
3966
4571
|
}
|
|
3967
4572
|
}
|
|
3968
|
-
|
|
4573
|
+
policySessionDelegation(session, origin) {
|
|
4574
|
+
if (session.runtimeDelegation === void 0) return void 0;
|
|
4575
|
+
const delegation = parsePortableDelegation(session.runtimeDelegation);
|
|
4576
|
+
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");
|
|
4577
|
+
return delegation;
|
|
4578
|
+
}
|
|
4579
|
+
policyInvocationSigner(delegation) {
|
|
4580
|
+
const privateKey = this.options.policySessionPrivateKey;
|
|
4581
|
+
if (privateKey === void 0) throw new ShareAccessError("SHARE_SESSION_SIGNER_REQUIRED");
|
|
4582
|
+
const session = parsePolicySessionUcan(delegation.delegationHeader.Authorization);
|
|
4583
|
+
if (session.cid !== delegation.cid || session.aud !== delegation.delegateDID)
|
|
4584
|
+
throw new ShareAccessError("SHARE_SESSION_INVALID");
|
|
4585
|
+
return (_serviceSession, service, path, action, facts) => {
|
|
4586
|
+
const serviceName = service.replace(/^tinycloud\./, "");
|
|
4587
|
+
const cleanPath = path.replace(/^\//, "").replace(/\/$/, "");
|
|
4588
|
+
const authority = Object.entries(session.att).find(([parentResource, abilities]) => {
|
|
4589
|
+
if (!(action in abilities)) return false;
|
|
4590
|
+
if (serviceName === "encryption") return parentResource.startsWith("urn:tinycloud:encryption:") && parentResource === cleanPath;
|
|
4591
|
+
const match = /^tinycloud:\/\/[^/]+\/kv\/(.+)$/.exec(parentResource);
|
|
4592
|
+
if (match === null) return false;
|
|
4593
|
+
const parentPath = match[1];
|
|
4594
|
+
const caveats = abilities[action] ?? [];
|
|
4595
|
+
const prefix = caveats.some((value) => isRecord(value) && value.kind === "prefix");
|
|
4596
|
+
return cleanPath === parentPath || prefix && cleanPath.startsWith(`${parentPath}/`);
|
|
4597
|
+
});
|
|
4598
|
+
if (authority === void 0) throw new ShareAccessError("SHARE_OUT_OF_SCOPE");
|
|
4599
|
+
const resource = serviceName === "encryption" ? authority[0] : `${authority[0].slice(0, authority[0].indexOf("/kv/") + 4)}${cleanPath}`;
|
|
4600
|
+
const caveat = serviceName === "encryption" ? {} : { type: "xyz.tinycloud.resource/selector", kind: "exact", value: resource };
|
|
4601
|
+
const invocation = createCompactPolicyInvocation({
|
|
4602
|
+
sessionAuthorization: delegation.delegationHeader.Authorization,
|
|
4603
|
+
sessionCid: delegation.cid,
|
|
4604
|
+
recipientDid: delegation.delegateDID,
|
|
4605
|
+
audienceDid: String(session.fact.nodeAudience),
|
|
4606
|
+
resource,
|
|
4607
|
+
action,
|
|
4608
|
+
caveat,
|
|
4609
|
+
...facts?.length === 1 ? { facts: facts[0] } : {},
|
|
4610
|
+
privateKey,
|
|
4611
|
+
now: Math.floor(this.now().getTime() / 1e3)
|
|
4612
|
+
});
|
|
4613
|
+
return { Authorization: invocation.authorization };
|
|
4614
|
+
};
|
|
4615
|
+
}
|
|
4616
|
+
policySessionProjection(delegation) {
|
|
4617
|
+
const session = parsePolicySessionUcan(delegation.delegationHeader.Authorization);
|
|
4618
|
+
if (session.cid !== delegation.cid || session.aud !== delegation.delegateDID) throw new ShareAccessError("SHARE_SESSION_INVALID");
|
|
4619
|
+
const kvResource = Object.keys(session.att).find((resource) => /^tinycloud:\/\/[^/]+\/kv\/.+$/.test(resource));
|
|
4620
|
+
const match = kvResource === void 0 ? void 0 : /^tinycloud:\/\/([^/]+)\/kv\/(.+)$/.exec(kvResource);
|
|
4621
|
+
if (match === void 0 || match === null) throw new ShareAccessError("SHARE_SESSION_INVALID");
|
|
4622
|
+
return { spaceId: match[1] };
|
|
4623
|
+
}
|
|
4624
|
+
createKV(origin, session, invokeOverride) {
|
|
4625
|
+
const invoke = invokeOverride ?? this.options.invoke ?? nativeInvoke;
|
|
3969
4626
|
if (this.options.createKVService !== void 0) {
|
|
3970
|
-
return this.options.createKVService({ hosts: [origin], session, invoke
|
|
4627
|
+
return this.options.createKVService({ hosts: [origin], session, invoke, fetch: this.fetchFn });
|
|
3971
4628
|
}
|
|
3972
|
-
const context = new import_sdk_services2.ServiceContext({ hosts: [origin], session, invoke
|
|
4629
|
+
const context = new import_sdk_services2.ServiceContext({ hosts: [origin], session, invoke, fetch: this.fetchFn });
|
|
3973
4630
|
const service = new import_sdk_services2.KVService({ prefix: "" });
|
|
3974
4631
|
context.registerService("kv", service);
|
|
3975
4632
|
service.initialize(context);
|
|
@@ -4012,7 +4669,7 @@ var ShareRecipientClient = class {
|
|
|
4012
4669
|
if (bytes2.byteLength > (this.options.maxContentBytes ?? DEFAULT_MAX_CONTENT_BYTES)) throw new ShareAccessError("SHARE_TOO_LARGE");
|
|
4013
4670
|
const contentType = input.contentType ?? envelope.content.mimeType;
|
|
4014
4671
|
if (contentType !== envelope.content.mimeType && !/^text\/(?:plain|markdown)(?:;|$)/i.test(contentType)) throw new ShareAccessError("SHARE_CONTENT_TYPE_INVALID");
|
|
4015
|
-
const result = await this.invokeNative({ envelope, session, action: "put", resource: path, body: bytes2, bodyDigest: bytesToBase64Url2((0,
|
|
4672
|
+
const result = await this.invokeNative({ envelope, session, action: "put", resource: path, body: bytes2, bodyDigest: bytesToBase64Url2((0, import_sha2564.sha256)(bytes2)), contentType, ifMatch: input.etag, mediaType: "application/vnd.tinycloud.share+json" });
|
|
4016
4673
|
if (result.status === 412 || result.status === 409) throw new ShareConflict(path, result.headers?.etag);
|
|
4017
4674
|
if (result.status === 401 || result.status === 403) throw new ShareAccessError("SHARE_DENIED");
|
|
4018
4675
|
if (result.status < 200 || result.status >= 300) throw new ShareAccessError("SHARE_WRITE_FAILED");
|
|
@@ -4134,7 +4791,7 @@ var ShareRecipientClient = class {
|
|
|
4134
4791
|
};
|
|
4135
4792
|
const signed = this.options.signNativeInvoke === void 0 ? void 0 : await this.options.signNativeInvoke({ envelope: input.envelope, session: input.session, request: body });
|
|
4136
4793
|
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;
|
|
4137
|
-
const response = await this.fetchFn(
|
|
4794
|
+
const response = await this.fetchFn(`${base3}/invoke`, {
|
|
4138
4795
|
method: "POST",
|
|
4139
4796
|
headers: { ...headersRecord(transport), ...headersRecord(signed), "content-type": input.mediaType, accept: input.mediaType },
|
|
4140
4797
|
body: JSON.stringify(body),
|
|
@@ -4258,7 +4915,7 @@ var ShareRecipientClient = class {
|
|
|
4258
4915
|
}]);
|
|
4259
4916
|
}
|
|
4260
4917
|
digestMatches(value, bytes2) {
|
|
4261
|
-
const digest4 = bytesToBase64Url2((0,
|
|
4918
|
+
const digest4 = bytesToBase64Url2((0, import_sha2564.sha256)(bytes2));
|
|
4262
4919
|
return value === digest4 || value === `sha-256=:${digest4}:`;
|
|
4263
4920
|
}
|
|
4264
4921
|
assertNativeRequestBounds(envelope, session, operation, path, limit, cursor) {
|
|
@@ -4476,7 +5133,7 @@ var ShareRecipientClient = class {
|
|
|
4476
5133
|
nodeAudience: binding.nodeAudience,
|
|
4477
5134
|
...isV2 ? {
|
|
4478
5135
|
enforcerDid: challenge.enforcerDid,
|
|
4479
|
-
credentialDigest: typeof presentation.credentialDigest === "string" ? presentation.credentialDigest : bytesToBase64Url2((0,
|
|
5136
|
+
credentialDigest: typeof presentation.credentialDigest === "string" ? presentation.credentialDigest : bytesToBase64Url2((0, import_sha2564.sha256)(new TextEncoder().encode(credential)))
|
|
4480
5137
|
} : {},
|
|
4481
5138
|
action,
|
|
4482
5139
|
...binding.actions === void 0 ? {} : { actions: [...binding.actions] },
|
|
@@ -4542,7 +5199,7 @@ var ShareRecipientClient = class {
|
|
|
4542
5199
|
}
|
|
4543
5200
|
if (isJwsProof && detached.kid !== `${signerDid}#${encoded}` || isEd25519Proof && detached.signerDid !== signerDid || signature.length !== 64) throw new ShareAccessError("SHARE_SESSION_INVALID", "Node proof binding is invalid");
|
|
4544
5201
|
const bytes2 = new TextEncoder().encode(`${domain}${canonicalJsonForProof(message)}`);
|
|
4545
|
-
if (!
|
|
5202
|
+
if (!import_ed255193.ed25519.verify(signature, bytes2, key)) throw new ShareAccessError("SHARE_SESSION_INVALID", "Node proof signature is invalid");
|
|
4546
5203
|
}
|
|
4547
5204
|
assertChallengeRequestBinding(request, challenge) {
|
|
4548
5205
|
const source = isRecord(request.body) ? request.body : request;
|
|
@@ -5746,7 +6403,7 @@ function shareKeyMatchesDid(key, didUrl) {
|
|
|
5746
6403
|
if (!publicKey) return false;
|
|
5747
6404
|
const jwkBytes = decodeBase64UrlBytes(key.x);
|
|
5748
6405
|
const privateKey = decodeBase64UrlBytes(key.d);
|
|
5749
|
-
const derivedPublicKey =
|
|
6406
|
+
const derivedPublicKey = import_ed255194.ed25519.getPublicKey(privateKey);
|
|
5750
6407
|
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]);
|
|
5751
6408
|
} catch {
|
|
5752
6409
|
return false;
|
|
@@ -5796,240 +6453,16 @@ function verifySignedChild(result, expected, computeCid) {
|
|
|
5796
6453
|
}
|
|
5797
6454
|
|
|
5798
6455
|
// src/delegations/owner-policy.ts
|
|
5799
|
-
var
|
|
5800
|
-
var
|
|
6456
|
+
var import_ed255196 = require("@noble/curves/ed25519");
|
|
6457
|
+
var import_sha2565 = require("@noble/hashes/sha256");
|
|
5801
6458
|
|
|
5802
6459
|
// src/policy/signed-object.ts
|
|
5803
|
-
var
|
|
5804
|
-
var import_viem3 = require("viem");
|
|
5805
|
-
|
|
5806
|
-
// src/policy/capability.ts
|
|
5807
|
-
var import_bootstrap = require("@tinycloud/bootstrap");
|
|
6460
|
+
var import_ed255195 = require("@noble/curves/ed25519");
|
|
5808
6461
|
var import_viem2 = require("viem");
|
|
5809
|
-
|
|
5810
|
-
// src/policy/errors.ts
|
|
5811
|
-
var SignedObjectProfileError = class extends Error {
|
|
5812
|
-
constructor(code3, message) {
|
|
5813
|
-
super(message);
|
|
5814
|
-
this.name = "SignedObjectProfileError";
|
|
5815
|
-
this.code = code3;
|
|
5816
|
-
}
|
|
5817
|
-
};
|
|
5818
|
-
var SignedObjectCanonicalizationError = class extends SignedObjectProfileError {
|
|
5819
|
-
constructor(message) {
|
|
5820
|
-
super("canonicalization-mismatch", message);
|
|
5821
|
-
this.name = "SignedObjectCanonicalizationError";
|
|
5822
|
-
}
|
|
5823
|
-
};
|
|
5824
|
-
|
|
5825
|
-
// src/policy/jcs.ts
|
|
5826
|
-
var objectHasOwn = Object.hasOwn ?? Object.prototype.hasOwnProperty.call.bind(
|
|
5827
|
-
Object.prototype.hasOwnProperty
|
|
5828
|
-
);
|
|
5829
|
-
function jcsCanonicalize(input) {
|
|
5830
|
-
return serialize(normalizeJson(input, "$"));
|
|
5831
|
-
}
|
|
5832
|
-
function normalizeJson(input, path = "$") {
|
|
5833
|
-
if (input === null) {
|
|
5834
|
-
return null;
|
|
5835
|
-
}
|
|
5836
|
-
switch (typeof input) {
|
|
5837
|
-
case "boolean":
|
|
5838
|
-
return input;
|
|
5839
|
-
case "number":
|
|
5840
|
-
if (!Number.isFinite(input)) {
|
|
5841
|
-
throw new SignedObjectCanonicalizationError(
|
|
5842
|
-
`${path} must be a finite JSON number`
|
|
5843
|
-
);
|
|
5844
|
-
}
|
|
5845
|
-
return input;
|
|
5846
|
-
case "string":
|
|
5847
|
-
assertUnicodeScalarString(input, path);
|
|
5848
|
-
return input;
|
|
5849
|
-
case "object":
|
|
5850
|
-
return normalizeJsonObjectOrArray(input, path);
|
|
5851
|
-
case "bigint":
|
|
5852
|
-
case "function":
|
|
5853
|
-
case "symbol":
|
|
5854
|
-
case "undefined":
|
|
5855
|
-
default:
|
|
5856
|
-
throw new SignedObjectCanonicalizationError(
|
|
5857
|
-
`${path} is not a JSON value`
|
|
5858
|
-
);
|
|
5859
|
-
}
|
|
5860
|
-
}
|
|
5861
|
-
function serialize(value) {
|
|
5862
|
-
if (value === null) {
|
|
5863
|
-
return "null";
|
|
5864
|
-
}
|
|
5865
|
-
switch (typeof value) {
|
|
5866
|
-
case "boolean":
|
|
5867
|
-
return value ? "true" : "false";
|
|
5868
|
-
case "number": {
|
|
5869
|
-
const encoded = JSON.stringify(value);
|
|
5870
|
-
if (encoded === void 0) {
|
|
5871
|
-
throw new SignedObjectCanonicalizationError(
|
|
5872
|
-
"number could not be serialized as JSON"
|
|
5873
|
-
);
|
|
5874
|
-
}
|
|
5875
|
-
return encoded;
|
|
5876
|
-
}
|
|
5877
|
-
case "string":
|
|
5878
|
-
return JSON.stringify(value);
|
|
5879
|
-
case "object":
|
|
5880
|
-
if (Array.isArray(value)) {
|
|
5881
|
-
return `[${value.map((item) => serialize(item)).join(",")}]`;
|
|
5882
|
-
}
|
|
5883
|
-
return serializeObject(value);
|
|
5884
|
-
default:
|
|
5885
|
-
throw new SignedObjectCanonicalizationError(
|
|
5886
|
-
`unsupported JSON value type ${typeof value}`
|
|
5887
|
-
);
|
|
5888
|
-
}
|
|
5889
|
-
}
|
|
5890
|
-
function normalizeJsonObjectOrArray(input, path) {
|
|
5891
|
-
assertNoSymbolKeys(input, path);
|
|
5892
|
-
if (Array.isArray(input)) {
|
|
5893
|
-
for (const key of Object.getOwnPropertyNames(input)) {
|
|
5894
|
-
if (key === "length") {
|
|
5895
|
-
continue;
|
|
5896
|
-
}
|
|
5897
|
-
if (!isArrayIndexKey(key, input.length)) {
|
|
5898
|
-
throw new SignedObjectCanonicalizationError(
|
|
5899
|
-
`${path}.${key} is not allowed on a JSON array`
|
|
5900
|
-
);
|
|
5901
|
-
}
|
|
5902
|
-
const descriptor = Object.getOwnPropertyDescriptor(input, key);
|
|
5903
|
-
if (descriptor?.enumerable !== true) {
|
|
5904
|
-
throw new SignedObjectCanonicalizationError(
|
|
5905
|
-
`${path}[${key}] must be an enumerable JSON array item`
|
|
5906
|
-
);
|
|
5907
|
-
}
|
|
5908
|
-
if (!("value" in descriptor)) {
|
|
5909
|
-
throw new SignedObjectCanonicalizationError(
|
|
5910
|
-
`${path}[${key}] must be a JSON data property`
|
|
5911
|
-
);
|
|
5912
|
-
}
|
|
5913
|
-
}
|
|
5914
|
-
const output2 = [];
|
|
5915
|
-
for (let index = 0; index < input.length; index++) {
|
|
5916
|
-
if (!objectHasOwn(input, index)) {
|
|
5917
|
-
throw new SignedObjectCanonicalizationError(
|
|
5918
|
-
`${path}[${index}] must not be a sparse array hole`
|
|
5919
|
-
);
|
|
5920
|
-
}
|
|
5921
|
-
output2.push(normalizeJson(input[index], `${path}[${index}]`));
|
|
5922
|
-
}
|
|
5923
|
-
return output2;
|
|
5924
|
-
}
|
|
5925
|
-
const proto = Object.getPrototypeOf(input);
|
|
5926
|
-
if (proto !== Object.prototype && proto !== null) {
|
|
5927
|
-
throw new SignedObjectCanonicalizationError(
|
|
5928
|
-
`${path} must be a plain JSON object`
|
|
5929
|
-
);
|
|
5930
|
-
}
|
|
5931
|
-
const output = /* @__PURE__ */ Object.create(null);
|
|
5932
|
-
for (const key of Object.getOwnPropertyNames(input)) {
|
|
5933
|
-
assertUnicodeScalarString(key, `${path} key`);
|
|
5934
|
-
if (key === "__proto__" || key === "constructor") {
|
|
5935
|
-
throw new SignedObjectCanonicalizationError(
|
|
5936
|
-
`${path}.${key} is not allowed`
|
|
5937
|
-
);
|
|
5938
|
-
}
|
|
5939
|
-
const descriptor = Object.getOwnPropertyDescriptor(input, key);
|
|
5940
|
-
if (descriptor?.enumerable !== true) {
|
|
5941
|
-
throw new SignedObjectCanonicalizationError(
|
|
5942
|
-
`${path}.${key} must be an enumerable JSON object property`
|
|
5943
|
-
);
|
|
5944
|
-
}
|
|
5945
|
-
if (!("value" in descriptor)) {
|
|
5946
|
-
throw new SignedObjectCanonicalizationError(
|
|
5947
|
-
`${path}.${key} must be a JSON data property`
|
|
5948
|
-
);
|
|
5949
|
-
}
|
|
5950
|
-
const value = descriptor.value;
|
|
5951
|
-
output[key] = normalizeJson(value, `${path}.${key}`);
|
|
5952
|
-
}
|
|
5953
|
-
return output;
|
|
5954
|
-
}
|
|
5955
|
-
function assertNoSymbolKeys(input, path) {
|
|
5956
|
-
if (Object.getOwnPropertySymbols(input).length > 0) {
|
|
5957
|
-
throw new SignedObjectCanonicalizationError(
|
|
5958
|
-
`${path} must not have symbol properties`
|
|
5959
|
-
);
|
|
5960
|
-
}
|
|
5961
|
-
}
|
|
5962
|
-
function isArrayIndexKey(key, length2) {
|
|
5963
|
-
if (!/^(0|[1-9]\d*)$/.test(key)) {
|
|
5964
|
-
return false;
|
|
5965
|
-
}
|
|
5966
|
-
const index = Number(key);
|
|
5967
|
-
return Number.isSafeInteger(index) && index >= 0 && index < length2;
|
|
5968
|
-
}
|
|
5969
|
-
function serializeObject(value) {
|
|
5970
|
-
const keys = Object.keys(value).sort(compareUtf16CodeUnits);
|
|
5971
|
-
const parts = keys.map((key) => `${JSON.stringify(key)}:${serialize(value[key])}`);
|
|
5972
|
-
return `{${parts.join(",")}}`;
|
|
5973
|
-
}
|
|
5974
|
-
function compareUtf16CodeUnits(a, b) {
|
|
5975
|
-
const max = Math.min(a.length, b.length);
|
|
5976
|
-
for (let index = 0; index < max; index++) {
|
|
5977
|
-
const leftCodeUnit = a.charCodeAt(index);
|
|
5978
|
-
const rightCodeUnit = b.charCodeAt(index);
|
|
5979
|
-
if (leftCodeUnit !== rightCodeUnit) {
|
|
5980
|
-
return leftCodeUnit - rightCodeUnit;
|
|
5981
|
-
}
|
|
5982
|
-
}
|
|
5983
|
-
return a.length - b.length;
|
|
5984
|
-
}
|
|
5985
|
-
function assertUnicodeScalarString(value, path) {
|
|
5986
|
-
for (let index = 0; index < value.length; index++) {
|
|
5987
|
-
const code3 = value.charCodeAt(index);
|
|
5988
|
-
if (code3 >= 55296 && code3 <= 56319) {
|
|
5989
|
-
const next = value.charCodeAt(index + 1);
|
|
5990
|
-
if (Number.isNaN(next) || next < 56320 || next > 57343) {
|
|
5991
|
-
throw new SignedObjectCanonicalizationError(
|
|
5992
|
-
`${path} contains a lone high surrogate`
|
|
5993
|
-
);
|
|
5994
|
-
}
|
|
5995
|
-
index++;
|
|
5996
|
-
continue;
|
|
5997
|
-
}
|
|
5998
|
-
if (code3 >= 56320 && code3 <= 57343) {
|
|
5999
|
-
throw new SignedObjectCanonicalizationError(
|
|
6000
|
-
`${path} contains a lone low surrogate`
|
|
6001
|
-
);
|
|
6002
|
-
}
|
|
6003
|
-
}
|
|
6004
|
-
}
|
|
6005
|
-
|
|
6006
|
-
// src/policy/capability.ts
|
|
6007
6462
|
var textEncoder2 = new TextEncoder();
|
|
6008
6463
|
var objectHasOwn2 = Object.hasOwn ?? Object.prototype.hasOwnProperty.call.bind(
|
|
6009
6464
|
Object.prototype.hasOwnProperty
|
|
6010
6465
|
);
|
|
6011
|
-
var CEILING_SERVICES = /* @__PURE__ */ new Set(["tinycloud.kv", "tinycloud.sql", "tinycloud.vfs"]);
|
|
6012
|
-
var GRANTABLE_ACTIONS = /* @__PURE__ */ new Map();
|
|
6013
|
-
for (const entry of import_bootstrap.CAPABILITY_REGISTRY) {
|
|
6014
|
-
if (!CEILING_SERVICES.has(entry.service)) {
|
|
6015
|
-
continue;
|
|
6016
|
-
}
|
|
6017
|
-
if (entry.aliasOf !== void 0 || entry.implies !== void 0 || entry.urn.endsWith("/*")) {
|
|
6018
|
-
continue;
|
|
6019
|
-
}
|
|
6020
|
-
const existing = GRANTABLE_ACTIONS.get(entry.service);
|
|
6021
|
-
if (existing === void 0) {
|
|
6022
|
-
GRANTABLE_ACTIONS.set(entry.service, /* @__PURE__ */ new Set([entry.urn]));
|
|
6023
|
-
continue;
|
|
6024
|
-
}
|
|
6025
|
-
existing.add(entry.urn);
|
|
6026
|
-
}
|
|
6027
|
-
|
|
6028
|
-
// src/policy/signed-object.ts
|
|
6029
|
-
var textEncoder3 = new TextEncoder();
|
|
6030
|
-
var objectHasOwn3 = Object.hasOwn ?? Object.prototype.hasOwnProperty.call.bind(
|
|
6031
|
-
Object.prototype.hasOwnProperty
|
|
6032
|
-
);
|
|
6033
6466
|
function canonicalizeSignedObjectUnsigned(input) {
|
|
6034
6467
|
return jcsCanonicalize(input);
|
|
6035
6468
|
}
|
|
@@ -6061,10 +6494,10 @@ function fromB64(value) {
|
|
|
6061
6494
|
throw new Error("base64url decoding is unavailable");
|
|
6062
6495
|
}
|
|
6063
6496
|
function cid(bytesValue) {
|
|
6064
|
-
return CID.createV1(code, create(sha256.code, (0,
|
|
6497
|
+
return CID.createV1(code, create(sha256.code, (0, import_sha2565.sha256)(bytesValue))).toString(base32.encoder);
|
|
6065
6498
|
}
|
|
6066
6499
|
function digest3(bytesValue) {
|
|
6067
|
-
return b64((0,
|
|
6500
|
+
return b64((0, import_sha2565.sha256)(bytesValue));
|
|
6068
6501
|
}
|
|
6069
6502
|
function didKeyFromEd25519PublicKey(publicKey) {
|
|
6070
6503
|
if (publicKey.length !== 32) throw new Error("share key public key must be 32 bytes");
|
|
@@ -6249,7 +6682,7 @@ function validateOwnerSharePolicyRegistration(value, expected) {
|
|
|
6249
6682
|
const publicKey = encodedKid.length === 34 ? encodedKid.slice(2) : encodedKid;
|
|
6250
6683
|
const signatureBytes = fromB64(proof.signature);
|
|
6251
6684
|
const signedBytes = new TextEncoder().encode(`${OWNER_SHARE_REGISTRATION_DOMAIN}${canonicalizeSignedObjectUnsigned(registrationCore)}`);
|
|
6252
|
-
if (signatureBytes.length !== 64 || !
|
|
6685
|
+
if (signatureBytes.length !== 64 || !import_ed255196.ed25519.verify(signatureBytes, signedBytes, publicKey)) throw new Error("owner-share registration proof signature is invalid");
|
|
6253
6686
|
return { registration, proof };
|
|
6254
6687
|
}
|
|
6255
6688
|
function validateOwnerSharePolicyRegistrationBytes(bytesValue, expected) {
|
|
@@ -6263,7 +6696,7 @@ function validateOwnerSharePolicyRegistrationBytes(bytesValue, expected) {
|
|
|
6263
6696
|
}
|
|
6264
6697
|
|
|
6265
6698
|
// src/delegations/share-delivery.ts
|
|
6266
|
-
var
|
|
6699
|
+
var import_ed255197 = require("@noble/curves/ed25519");
|
|
6267
6700
|
var SHARE_DELIVERY_AUTHORIZATION_DOMAIN = "xyz.tinycloud.share/delivery-authorization/v2\0";
|
|
6268
6701
|
function isCanonicalHttpsOrigin(value) {
|
|
6269
6702
|
let url;
|
|
@@ -6336,7 +6769,7 @@ function validateShareDeliveryAuthorizationBytes(bytesValue, expected) {
|
|
|
6336
6769
|
const authorization = assertObject2(root.authorization, AUTHORIZATION_KEYS, "share delivery authorization");
|
|
6337
6770
|
const proof = assertObject2(root.proof, ["alg", "kid", "signature"], "share delivery authorization proof");
|
|
6338
6771
|
const request = expected.request;
|
|
6339
|
-
if (authorization.type !== "TinyCloudShareDeliveryAuthorization" || authorization.version !== 2 || authorization.dataAuthority !== false || authorization.jti !== request.jti || authorization.shareCid !== request.shareCid || authorization.shareId !== request.shareId || authorization.registrationCid !== request.registrationCid || authorization.delegationCid !== request.delegationCid || authorization.enforcementDelegationCid !== request.enforcementDelegationCid || authorization.envelopeCid !== request.envelopeCid || authorization.policyCid !== request.policyCid || authorization.deliveryEmail !== request.recipientEmail || authorization.shareUrl !== request.shareUrl || authorization.documentName !== request.documentName || authorization.requestBodyDigest !== request.requestBodyDigest || authorization.expiresAt !== request.expiresAt || authorization.idempotencyKey !== request.
|
|
6772
|
+
if (authorization.type !== "TinyCloudShareDeliveryAuthorization" || authorization.version !== 2 || authorization.dataAuthority !== false || authorization.jti !== request.jti || authorization.shareCid !== request.shareCid || authorization.shareId !== request.shareId || authorization.registrationCid !== request.registrationCid || authorization.delegationCid !== request.delegationCid || authorization.enforcementDelegationCid !== request.enforcementDelegationCid || authorization.envelopeCid !== request.envelopeCid || authorization.policyCid !== request.policyCid || authorization.deliveryEmail !== request.recipientEmail || authorization.shareUrl !== request.shareUrl || authorization.documentName !== request.documentName || authorization.requestBodyDigest !== request.requestBodyDigest || authorization.expiresAt !== request.expiresAt || authorization.idempotencyKey !== request.idempotencyKey || authorization.reportAbuseToken !== request.jti || authorization.authorityMaterialHandle !== request.registrationCid) {
|
|
6340
6773
|
throw new Error("share delivery authorization is not bound to the submitted request");
|
|
6341
6774
|
}
|
|
6342
6775
|
if (typeof authorization.issuedAt !== "string" || Date.parse(authorization.issuedAt) > Date.now() + 6e4) throw new Error("share delivery authorization issuedAt is invalid");
|
|
@@ -6351,7 +6784,7 @@ function validateShareDeliveryAuthorizationBytes(bytesValue, expected) {
|
|
|
6351
6784
|
if (publicKey.length !== 32) throw new Error("share delivery authorization proof key is invalid");
|
|
6352
6785
|
const signatureBytes = fromB642(proof.signature);
|
|
6353
6786
|
const signedBytes = new TextEncoder().encode(`${SHARE_DELIVERY_AUTHORIZATION_DOMAIN}${canonicalizeSignedObjectUnsigned(authorization)}`);
|
|
6354
|
-
if (signatureBytes.length !== 64 || !
|
|
6787
|
+
if (signatureBytes.length !== 64 || !import_ed255197.ed25519.verify(signatureBytes, signedBytes, publicKey)) throw new Error("share delivery authorization proof signature is invalid");
|
|
6355
6788
|
return { authorization, proof };
|
|
6356
6789
|
}
|
|
6357
6790
|
function shareDeliveryTrustedKid(publicKey) {
|
|
@@ -6470,69 +6903,8 @@ var SenderShareStore = class {
|
|
|
6470
6903
|
await this.keys.delete(shareId);
|
|
6471
6904
|
}
|
|
6472
6905
|
};
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
EncodedShareDataSchema,
|
|
6478
|
-
MAX_CONTENT_BYTES,
|
|
6479
|
-
MAX_SEALED_SHARE_CONTENT_BYTES,
|
|
6480
|
-
MAX_SHARE_ARTIFACT_BYTES,
|
|
6481
|
-
MAX_SHARE_CONTENT_BYTES,
|
|
6482
|
-
MemorySenderShareKeyStorage,
|
|
6483
|
-
MemorySenderShareRecordStorage,
|
|
6484
|
-
MemoryShareCache,
|
|
6485
|
-
ReceiveOptionsSchema,
|
|
6486
|
-
SHARE_DELIVERY_AUTHORIZATION_DOMAIN,
|
|
6487
|
-
SenderShareStore,
|
|
6488
|
-
ShareAccessError,
|
|
6489
|
-
ShareActionSchema,
|
|
6490
|
-
ShareAddressedDelegationEnvelopeV2Schema,
|
|
6491
|
-
ShareAddressedDelegationRequestV2Schema,
|
|
6492
|
-
ShareAddressedDelegationResponseV2Schema,
|
|
6493
|
-
ShareConflict,
|
|
6494
|
-
ShareEnvelopeError,
|
|
6495
|
-
ShareNativeResponseSchema,
|
|
6496
|
-
ShareRecipientClient,
|
|
6497
|
-
ShareRecipientClientOptionsSchema,
|
|
6498
|
-
ShareRecipientPolicySchema,
|
|
6499
|
-
ShareRecipientTargetSchema,
|
|
6500
|
-
ShareResourceSchema,
|
|
6501
|
-
SharingService,
|
|
6502
|
-
SharingServiceConfigSchema,
|
|
6503
|
-
canonicalOwnerSharePolicy,
|
|
6504
|
-
computeOwnerShareRegistrationCid,
|
|
6505
|
-
computeShareCid,
|
|
6506
|
-
createDelegatedShareKey,
|
|
6507
|
-
createPolicyEnforcementDelegation,
|
|
6508
|
-
createShareArtifact,
|
|
6509
|
-
createShareArtifactAsync,
|
|
6510
|
-
createSharePolicy,
|
|
6511
|
-
createSharingService,
|
|
6512
|
-
decryptShareBytesAsync,
|
|
6513
|
-
encodeInlineShareUrl,
|
|
6514
|
-
encodeShareArtifact,
|
|
6515
|
-
encodeShareUrl,
|
|
6516
|
-
encryptShareBytes,
|
|
6517
|
-
encryptShareBytesAsync,
|
|
6518
|
-
intersectShareCapabilities,
|
|
6519
|
-
isV2ShareLink,
|
|
6520
|
-
normalizeShareActions,
|
|
6521
|
-
normalizeShareRecipientTarget,
|
|
6522
|
-
normalizeShareResource,
|
|
6523
|
-
parseShareArtifact,
|
|
6524
|
-
parseShareUrl,
|
|
6525
|
-
restoreDelegatedShareKey,
|
|
6526
|
-
shareCapabilityAllows,
|
|
6527
|
-
shareDeliveryTrustedKid,
|
|
6528
|
-
signShareEnvelope,
|
|
6529
|
-
validateEncodedShareData,
|
|
6530
|
-
validateOwnerSharePolicyRegistration,
|
|
6531
|
-
validateOwnerSharePolicyRegistrationBytes,
|
|
6532
|
-
validateReceiveOptions,
|
|
6533
|
-
validateShareDeliveryAuthorizationBytes,
|
|
6534
|
-
validateSharingServiceConfig,
|
|
6535
|
-
verifyShareCid,
|
|
6536
|
-
verifyShareEnvelope
|
|
6537
|
-
});
|
|
6906
|
+
|
|
6907
|
+
// src/delegations/index.ts
|
|
6908
|
+
var import_share_sdk = require("@tinycloud/share-sdk");
|
|
6909
|
+
var import_share_sdk2 = require("@tinycloud/share-sdk");
|
|
6538
6910
|
//# sourceMappingURL=index.cjs.map
|