@tinycloud/sdk-core 3.0.0-beta.0 → 3.0.0-beta.10

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.
@@ -32,6 +32,8 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
32
32
  // src/delegations/index.ts
33
33
  var delegations_exports = {};
34
34
  __export(delegations_exports, {
35
+ CREDENTIAL_INVITATION_REQUEST_DOMAIN: () => CREDENTIAL_INVITATION_REQUEST_DOMAIN,
36
+ DELIVERY_ADMISSION_DOMAIN: () => DELIVERY_ADMISSION_DOMAIN,
35
37
  DelegationErrorCodes: () => DelegationErrorCodes,
36
38
  DelegationManager: () => DelegationManager,
37
39
  EncodedShareDataSchema: () => EncodedShareDataSchema,
@@ -45,7 +47,6 @@ __export(delegations_exports, {
45
47
  MemorySenderShareRecordStorage: () => MemorySenderShareRecordStorage,
46
48
  MemoryShareCache: () => MemoryShareCache,
47
49
  ReceiveOptionsSchema: () => ReceiveOptionsSchema,
48
- SHARE_DELIVERY_AUTHORIZATION_DOMAIN: () => SHARE_DELIVERY_AUTHORIZATION_DOMAIN,
49
50
  SenderShareStore: () => SenderShareStore,
50
51
  ShareAccessError: () => ShareAccessError,
51
52
  ShareActionSchema: () => ShareActionSchema,
@@ -85,10 +86,8 @@ __export(delegations_exports, {
85
86
  importPortableDelegation: () => importPortableDelegation,
86
87
  inspectShare: () => import_share_sdk2.inspectShare,
87
88
  intersectShareCapabilities: () => intersectShareCapabilities,
88
- isLegacyShareLink: () => import_share_sdk.isLegacyShareLink,
89
89
  isV2ShareLink: () => isV2ShareLink,
90
90
  listShares: () => import_share_sdk.listShares,
91
- migrateShare: () => import_share_sdk.migrateShare,
92
91
  normalizeShareActions: () => normalizeShareActions,
93
92
  normalizeShareRecipientTarget: () => normalizeShareRecipientTarget,
94
93
  normalizeShareResource: () => normalizeShareResource,
@@ -98,14 +97,12 @@ __export(delegations_exports, {
98
97
  parseShareUrl: () => parseShareUrl,
99
98
  publishPolicyShare: () => import_share_sdk.publishPolicyShare,
100
99
  publishTargetShare: () => import_share_sdk.publishTargetShare,
101
- receiveLegacyShare: () => import_share_sdk.receiveLegacyShare,
102
100
  receiveShare: () => import_share_sdk2.receiveShare,
103
101
  restoreDelegatedShareKey: () => restoreDelegatedShareKey,
104
102
  resumeShareAuthorization: () => import_share_sdk.resumeShareAuthorization,
105
103
  revokeShare: () => import_share_sdk.revokeShare,
106
104
  serializePortableDelegation: () => serializePortableDelegation,
107
105
  shareCapabilityAllows: () => shareCapabilityAllows,
108
- shareDeliveryTrustedKid: () => shareDeliveryTrustedKid,
109
106
  showShare: () => import_share_sdk.showShare,
110
107
  signShareEnvelope: () => signShareEnvelope,
111
108
  toShareErrorInfo: () => import_share_sdk2.toShareErrorInfo,
@@ -113,9 +110,8 @@ __export(delegations_exports, {
113
110
  validateOwnerSharePolicyRegistration: () => validateOwnerSharePolicyRegistration,
114
111
  validateOwnerSharePolicyRegistrationBytes: () => validateOwnerSharePolicyRegistrationBytes,
115
112
  validateReceiveOptions: () => validateReceiveOptions,
116
- validateShareDeliveryAuthorizationBytes: () => validateShareDeliveryAuthorizationBytes,
113
+ validateShareDeliveryAuthorizationV3Bytes: () => validateShareDeliveryAuthorizationV3Bytes,
117
114
  validateSharingServiceConfig: () => validateSharingServiceConfig,
118
- verifyBearerEnvelope: () => import_share_sdk2.verifyBearerEnvelope,
119
115
  verifyShareCid: () => verifyShareCid,
120
116
  verifyShareEnvelope: () => verifyShareEnvelope
121
117
  });
@@ -1493,13 +1489,13 @@ function canonicalizeRecapCaveats(caveats) {
1493
1489
  }
1494
1490
  if (Array.isArray(value)) return `[${value.map(canonicalize).join(",")}]`;
1495
1491
  if (typeof value === "object") {
1496
- const object = value;
1497
- const prototype = Object.getPrototypeOf(object);
1492
+ const object2 = value;
1493
+ const prototype = Object.getPrototypeOf(object2);
1498
1494
  if (prototype !== Object.prototype && prototype !== null) {
1499
1495
  throw new Error("ReCap caveats must contain only JSON values.");
1500
1496
  }
1501
- return `{${Object.keys(object).sort().map(
1502
- (key) => `${JSON.stringify(key)}:${canonicalize(object[key])}`
1497
+ return `{${Object.keys(object2).sort().map(
1498
+ (key) => `${JSON.stringify(key)}:${canonicalize(object2[key])}`
1503
1499
  ).join(",")}}`;
1504
1500
  }
1505
1501
  throw new Error("ReCap caveats must contain only JSON values.");
@@ -2693,7 +2689,6 @@ var import_ed25519 = require("@noble/curves/ed25519");
2693
2689
  var import_blake3 = require("@noble/hashes/blake3");
2694
2690
  var import_sha256 = require("@noble/hashes/sha256");
2695
2691
  var ENVELOPE_SCHEMA = "xyz.tinycloud.share/envelope";
2696
- var INLINE_PREFIX = "tc2:";
2697
2692
  var RAW_CID_CODEC = 85;
2698
2693
  var BLAKE3_256_CODE = 30;
2699
2694
  var DEFAULT_MAX_INLINE_BYTES = 256 * 1024;
@@ -2740,8 +2735,8 @@ function canonicalJson(value) {
2740
2735
  }
2741
2736
  if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
2742
2737
  if (typeof value === "object") {
2743
- const object = value;
2744
- return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(object[key])}`).join(",")}}`;
2738
+ const object2 = value;
2739
+ return `{${Object.keys(object2).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(object2[key])}`).join(",")}}`;
2745
2740
  }
2746
2741
  throw new ShareEnvelopeError("invalid-envelope", "unsupported JSON value");
2747
2742
  }
@@ -3398,25 +3393,8 @@ function parsePublishedShareLink(link, options = {}) {
3398
3393
  }
3399
3394
  const origin = normalizeOrigin(url.origin);
3400
3395
  if (options.trustedOrigins !== void 0 && !options.trustedOrigins.map(normalizeOrigin).includes(origin)) throw new ShareEnvelopeError("origin-mismatch", "share link origin is not trusted");
3401
- if (url.search !== "" || url.username !== "" || url.password !== "") throw new ShareEnvelopeError("invalid-link", "share link is not canonical");
3402
- if (url.pathname === "/s/inline" && url.hash.startsWith("#v=2&p=")) {
3403
- let payload;
3404
- try {
3405
- const bytes2 = base64UrlToBytes(url.hash.slice("#v=2&p=".length));
3406
- if (bytes2.length > (options.maxInlineBytes ?? DEFAULT_MAX_INLINE_BYTES) * 2) throw new Error("inline payload too large");
3407
- const value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes2));
3408
- if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("inline payload shape");
3409
- payload = value;
3410
- } catch (error) {
3411
- throw new ShareEnvelopeError("invalid-link", error instanceof Error ? error.message : "invalid inline payload");
3412
- }
3413
- if (payload.v !== 2 || typeof payload.c !== "string" || typeof payload.cid !== "string" || payload.k !== void 0 && typeof payload.k !== "string" || Object.keys(payload).some((key3) => !["v", "c", "cid", "k"].includes(key3))) throw new ShareEnvelopeError("invalid-link", "inline payload fields are invalid");
3414
- const sealed = base64UrlToBytes(payload.c);
3415
- if (!verifyPublishedShareCid(payload.cid, sealed)) throw new ShareEnvelopeError("cid-mismatch", "inline payload CID does not match");
3416
- const key2 = payload.k === void 0 ? void 0 : base64UrlToBytes(payload.k);
3417
- if (key2 !== void 0 && key2.length !== 32) throw new ShareEnvelopeError("invalid-link", "inline payload key is invalid");
3418
- return { origin, cid: payload.cid, ...key2 === void 0 ? {} : { key: key2 }, sealed };
3419
- }
3396
+ if (url.username !== "" || url.password !== "") throw new ShareEnvelopeError("invalid-link", "share link is not canonical");
3397
+ if (url.search !== "") throw new ShareEnvelopeError("invalid-link", "share link is not canonical");
3420
3398
  const match = /^\/s\/([a-z2-7]+)$/.exec(url.pathname);
3421
3399
  if (match === null || !url.hash.startsWith("#k=")) throw new ShareEnvelopeError("invalid-link", "published share link is invalid");
3422
3400
  const key = base64UrlToBytes(url.hash.slice(3));
@@ -3436,13 +3414,10 @@ function parseShareUrl(link, options = {}) {
3436
3414
  } catch {
3437
3415
  throw new ShareEnvelopeError("invalid-link", "share link must be an absolute URL");
3438
3416
  }
3439
- if (url.search !== "") throw new ShareEnvelopeError("invalid-link", "share links must not contain query parameters");
3440
3417
  const origin = normalizeOrigin(url.origin);
3441
3418
  if (options.trustedOrigins !== void 0 && !options.trustedOrigins.map(normalizeOrigin).includes(origin)) throw new ShareEnvelopeError("origin-mismatch", "share link origin is not trusted");
3442
- if (url.pathname === "/s/inline" && url.hash.startsWith("#v=2&p=")) {
3443
- const published = parsePublishedShareLink(link, options);
3444
- return { kind: "inline", origin, cid: published.cid, key: published.key, url: `${url.origin}${url.pathname}`, protocol: "share-envelope-v2" };
3445
- }
3419
+ if (url.pathname === "/viewer") throw new ShareEnvelopeError("invalid-link", "retired viewer links are not accepted");
3420
+ if (url.search !== "") throw new ShareEnvelopeError("invalid-link", "share links must not contain query parameters");
3446
3421
  const match = url.pathname.match(/^\/s\/(i\/)?([^/]+)$/);
3447
3422
  if (!match) throw new ShareEnvelopeError("invalid-link", "share link path is invalid");
3448
3423
  const fragmentParams = url.hash === "" ? void 0 : new URLSearchParams(url.hash.slice(1));
@@ -3465,9 +3440,10 @@ function parseShareUrl(link, options = {}) {
3465
3440
  }
3466
3441
  function isV2ShareLink(link) {
3467
3442
  try {
3468
- return new URL(link).pathname.startsWith("/s/");
3443
+ const url = new URL(link);
3444
+ return url.search === "" && url.pathname.startsWith("/s/");
3469
3445
  } catch {
3470
- return link.startsWith(INLINE_PREFIX);
3446
+ return false;
3471
3447
  }
3472
3448
  }
3473
3449
  async function encryptShareBytes(bytes2, key) {
@@ -4007,6 +3983,11 @@ var POLICY_SESSION_FACT_KEYS = [
4007
3983
  "issuanceAuditDigestHex",
4008
3984
  "remainingRedelegationDepth"
4009
3985
  ];
3986
+ var POLICY_SESSION_V4_AUDIT_FACT_KEYS = [
3987
+ "credentialIdAuditDigestHex",
3988
+ "presentationJtiAuditDigestHex"
3989
+ ];
3990
+ var LOWER_SHA256_HEX = /^[0-9a-f]{64}$/;
4010
3991
  var CompactHeaderSchema = import_zod4.z.object({
4011
3992
  alg: import_zod4.z.literal("EdDSA"),
4012
3993
  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(),
@@ -4148,9 +4129,13 @@ function parsePolicySessionUcan(authorization, expectedProofs) {
4148
4129
  if (expectedProofs !== void 0 && (parsed.payload.prf[0] !== expectedProofs[0] || parsed.payload.prf[1] !== expectedProofs[1]))
4149
4130
  throw new Error("policy session UCAN ordered proofs do not match");
4150
4131
  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)))
4132
+ const hasLegacyFactShape = factKeys.length === POLICY_SESSION_FACT_KEYS.length && factKeys.every((key) => POLICY_SESSION_FACT_KEYS.includes(key)) && POLICY_SESSION_FACT_KEYS.every((key) => key in fact);
4133
+ const hasV4AuditFactShape = factKeys.length === POLICY_SESSION_FACT_KEYS.length + POLICY_SESSION_V4_AUDIT_FACT_KEYS.length && factKeys.every((key) => POLICY_SESSION_FACT_KEYS.includes(key) || POLICY_SESSION_V4_AUDIT_FACT_KEYS.includes(key)) && POLICY_SESSION_FACT_KEYS.every((key) => key in fact) && POLICY_SESSION_V4_AUDIT_FACT_KEYS.every((key) => key in fact);
4134
+ if (!hasLegacyFactShape && !hasV4AuditFactShape)
4152
4135
  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)
4136
+ if (hasV4AuditFactShape && (!LOWER_SHA256_HEX.test(fact.credentialIdAuditDigestHex) || !LOWER_SHA256_HEX.test(fact.presentationJtiAuditDigestHex)))
4137
+ throw new Error("policy session UCAN v4 audit facts are invalid");
4138
+ 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.nodeAudience || parsed.payload.aud !== fact.recipientDid)
4154
4139
  throw new Error("policy session UCAN fact is invalid");
4155
4140
  return {
4156
4141
  authorization,
@@ -4327,8 +4312,8 @@ function canonicalJsonForProof(value) {
4327
4312
  }
4328
4313
  if (Array.isArray(value)) return `[${value.map(canonicalJsonForProof).join(",")}]`;
4329
4314
  if (typeof value === "object") {
4330
- const object = value;
4331
- return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${canonicalJsonForProof(object[key])}`).join(",")}}`;
4315
+ const object2 = value;
4316
+ return `{${Object.keys(object2).sort().map((key) => `${JSON.stringify(key)}:${canonicalJsonForProof(object2[key])}`).join(",")}}`;
4332
4317
  }
4333
4318
  throw new ShareAccessError("SHARE_SESSION_INVALID");
4334
4319
  }
@@ -5037,12 +5022,12 @@ var ShareRecipientClient = class {
5037
5022
  this.assertDetachedProof(request.proof);
5038
5023
  }
5039
5024
  parseSessionCapability(value) {
5040
- const object = this.requireObject(value, "session capability");
5041
- if (typeof object.spaceId !== "string") throw new ShareAccessError("SHARE_SESSION_INVALID", "session capability space is invalid");
5042
- if (!Array.isArray(object.actions) || object.actions.some((action) => !["read", "list", "edit"].includes(action))) throw new ShareAccessError("SHARE_SESSION_INVALID", "session capability actions are invalid");
5043
- const resource = this.requireObject(object.resource, "session capability resource");
5025
+ const object2 = this.requireObject(value, "session capability");
5026
+ if (typeof object2.spaceId !== "string") throw new ShareAccessError("SHARE_SESSION_INVALID", "session capability space is invalid");
5027
+ if (!Array.isArray(object2.actions) || object2.actions.some((action) => !["read", "list", "edit"].includes(action))) throw new ShareAccessError("SHARE_SESSION_INVALID", "session capability actions are invalid");
5028
+ const resource = this.requireObject(object2.resource, "session capability resource");
5044
5029
  if (resource.kind !== "exact" && resource.kind !== "prefix" || typeof resource.path !== "string") throw new ShareAccessError("SHARE_SESSION_INVALID", "session capability resource is invalid");
5045
- return { spaceId: object.spaceId, actions: [...new Set(object.actions)], resource: { kind: resource.kind, path: resource.path } };
5030
+ return { spaceId: object2.spaceId, actions: [...new Set(object2.actions)], resource: { kind: resource.kind, path: resource.path } };
5046
5031
  }
5047
5032
  assertProvidedPolicySession(session, envelope) {
5048
5033
  const sessionExpiry = dateValue(session.expiresAt);
@@ -6695,62 +6680,21 @@ function validateOwnerSharePolicyRegistrationBytes(bytesValue, expected) {
6695
6680
  return validateOwnerSharePolicyRegistration(value, expected);
6696
6681
  }
6697
6682
 
6698
- // src/delegations/share-delivery.ts
6683
+ // src/delegations/share-delivery-v3.ts
6699
6684
  var import_ed255197 = require("@noble/curves/ed25519");
6700
- var SHARE_DELIVERY_AUTHORIZATION_DOMAIN = "xyz.tinycloud.share/delivery-authorization/v2\0";
6701
- function isCanonicalHttpsOrigin(value) {
6702
- let url;
6703
- try {
6704
- url = new URL(value);
6705
- } catch {
6706
- return false;
6707
- }
6708
- return url.protocol === "https:" && url.origin === value && url.pathname === "/" && url.search === "" && url.hash === "" && url.username === "" && url.password === "";
6709
- }
6710
- var AUTHORIZATION_KEYS = [
6711
- "type",
6712
- "version",
6713
- "jti",
6714
- "shareCid",
6715
- "shareId",
6716
- "registrationCid",
6717
- "delegationCid",
6718
- "enforcementDelegationCid",
6719
- "envelopeCid",
6720
- "policyCid",
6721
- "nodeAudience",
6722
- "targetOrigin",
6723
- "openCredentialsAudience",
6724
- "holder",
6725
- "recipientMatcher",
6726
- "deliveryEmail",
6727
- "shareUrl",
6728
- "returnOrigin",
6729
- "documentName",
6730
- "senderDid",
6731
- "senderTrust",
6732
- "contentSource",
6733
- "contentSourceDigest",
6734
- "shareExpiresAt",
6735
- "issuedAt",
6736
- "reportAbuseToken",
6737
- "actions",
6738
- "resource",
6739
- "authorityMaterialHandle",
6740
- "authorityMaterialDigest",
6741
- "requestBodyDigest",
6742
- "idempotencyKey",
6743
- "expiresAt",
6744
- "dataAuthority"
6745
- ];
6746
- function assertObject2(value, keys, label) {
6685
+ var import_sha2566 = require("@noble/hashes/sha256");
6686
+ var CREDENTIAL_INVITATION_REQUEST_DOMAIN = "xyz.tinycloud.credentials/invitation-request/v1\0";
6687
+ var DELIVERY_ADMISSION_DOMAIN = "xyz.tinycloud.policy/delivery-admission/v0\0";
6688
+ var REQUEST_KEYS = ["schema", "policyId", "recipient", "resource", "credentialType", "returnLink", "envelopeRef", "label", "shareExpiresAt", "audience", "issuedAt", "expiresAt", "nonce"];
6689
+ var ADMISSION_KEYS = ["schema", "policyId", "ownerDid", "recipient", "resource", "actions", "credentialType", "returnLink", "envelopeRef", "label", "shareExpiresAt", "senderKeyDid", "audience", "issuedAt", "expiresAt", "nonce", "signature"];
6690
+ function exactObject(value, keys, label) {
6747
6691
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${label} is invalid`);
6748
6692
  const record = value;
6749
6693
  if (Object.keys(record).length !== keys.length || keys.some((key) => !Object.prototype.hasOwnProperty.call(record, key))) throw new Error(`${label} has unknown or missing fields`);
6750
6694
  return record;
6751
6695
  }
6752
- function fromB642(value) {
6753
- if (!/^[A-Za-z0-9_-]+$/.test(value)) throw new Error("share delivery value is not canonical base64url");
6696
+ function decodeBase64Url2(value) {
6697
+ if (typeof value !== "string" || !/^[A-Za-z0-9_-]+$/.test(value)) throw new Error("share delivery value is not canonical base64url");
6754
6698
  if (typeof atob === "function") {
6755
6699
  const padded = value.replace(/-/g, "+").replace(/_/g, "/") + "=".repeat((4 - value.length % 4) % 4);
6756
6700
  return Uint8Array.from(atob(padded), (character) => character.charCodeAt(0));
@@ -6758,42 +6702,45 @@ function fromB642(value) {
6758
6702
  if (typeof Buffer !== "undefined") return new Uint8Array(Buffer.from(value, "base64url"));
6759
6703
  throw new Error("base64url decoding is unavailable");
6760
6704
  }
6761
- function validateShareDeliveryAuthorizationBytes(bytesValue, expected) {
6762
- let value;
6705
+ function object(value, label) {
6706
+ if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${label} is invalid`);
6707
+ return value;
6708
+ }
6709
+ function didKeyBytes(did) {
6710
+ if (!did.startsWith("did:key:z") || /[#/?]/.test(did.slice("did:key:".length))) throw new Error("v3 delivery admission signer is invalid");
6711
+ const decoded = base58btc.decode(did.slice("did:key:".length));
6712
+ if (decoded.length !== 34 || decoded[0] !== 237 || decoded[1] !== 1) throw new Error("v3 delivery admission signer is invalid");
6713
+ return decoded.slice(2);
6714
+ }
6715
+ function validateShareDeliveryAuthorizationV3Bytes(bytes2, expected) {
6716
+ let parsed;
6763
6717
  try {
6764
- value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytesValue));
6718
+ parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes2));
6765
6719
  } catch {
6766
- throw new Error("share delivery authorization response is not valid UTF-8 JSON");
6767
- }
6768
- const root = assertObject2(value, ["authorization", "proof"], "share delivery authorization response");
6769
- const authorization = assertObject2(root.authorization, AUTHORIZATION_KEYS, "share delivery authorization");
6770
- const proof = assertObject2(root.proof, ["alg", "kid", "signature"], "share delivery authorization proof");
6771
- const request = expected.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) {
6773
- throw new Error("share delivery authorization is not bound to the submitted request");
6774
- }
6775
- if (typeof authorization.issuedAt !== "string" || Date.parse(authorization.issuedAt) > Date.now() + 6e4) throw new Error("share delivery authorization issuedAt is invalid");
6776
- if (new Date(authorization.expiresAt).toISOString() !== authorization.expiresAt) throw new Error("share delivery authorization expiresAt is non-canonical");
6777
- if (typeof authorization.openCredentialsAudience !== "string" || !isCanonicalHttpsOrigin(authorization.openCredentialsAudience) || authorization.openCredentialsAudience !== expected.credentialsAudience || authorization.openCredentialsAudience === authorization.nodeAudience || authorization.openCredentialsAudience === authorization.returnOrigin) {
6778
- throw new Error("share delivery authorization openCredentialsAudience is missing or untrusted");
6779
- }
6780
- if (proof.alg !== "EdDSA" || typeof proof.kid !== "string" || typeof proof.signature !== "string") throw new Error("share delivery authorization proof is invalid");
6781
- if (proof.kid !== expected.nodeProof.kid) throw new Error("share delivery authorization proof key is not trusted");
6782
- const encodedKid = expected.nodeProof.publicKey;
6783
- const publicKey = encodedKid.length === 34 && encodedKid[0] === 237 && encodedKid[1] === 1 ? encodedKid.slice(2) : encodedKid;
6784
- if (publicKey.length !== 32) throw new Error("share delivery authorization proof key is invalid");
6785
- const signatureBytes = fromB642(proof.signature);
6786
- const signedBytes = new TextEncoder().encode(`${SHARE_DELIVERY_AUTHORIZATION_DOMAIN}${canonicalizeSignedObjectUnsigned(authorization)}`);
6787
- if (signatureBytes.length !== 64 || !import_ed255197.ed25519.verify(signatureBytes, signedBytes, publicKey)) throw new Error("share delivery authorization proof signature is invalid");
6788
- return { authorization, proof };
6789
- }
6790
- function shareDeliveryTrustedKid(publicKey) {
6791
- if (publicKey.length !== 32) throw new Error("share delivery node key must be a raw 32-byte Ed25519 public key");
6792
- const prefixed = new Uint8Array(34);
6793
- prefixed.set([237, 1]);
6794
- prefixed.set(publicKey, 2);
6795
- const did = `did:key:${base58btc.encode(prefixed)}`;
6796
- return `${did}#${did.slice("did:key:".length)}`;
6720
+ throw new Error("v3 share delivery response is not valid UTF-8 JSON");
6721
+ }
6722
+ const root = exactObject(parsed, ["request", "admission"], "v3 share delivery response");
6723
+ const request = exactObject(root.request, REQUEST_KEYS, "credential invitation request");
6724
+ const admission = exactObject(root.admission, ADMISSION_KEYS, "delivery admission");
6725
+ const signature = exactObject(admission.signature, ["suite", "signerDid", "value"], "delivery admission signature");
6726
+ const envelope = object(expected.request.envelope, "v3 share envelope");
6727
+ const policy = object(envelope.policy, "v3 share policy");
6728
+ const requirement = object(policy.credentialRequirement, "v3 credential requirement");
6729
+ const credentialType = object(requirement.credentialType, "v3 credential type");
6730
+ const contentSource = object(envelope.contentSource, "v3 content source");
6731
+ const envelopeSignature = object(envelope.signature, "v3 envelope signature");
6732
+ const target = object(envelope.target, "v3 target");
6733
+ const binding = object(envelope.attestedEnforcerBinding, "v3 attested enforcer binding");
6734
+ const fields = ["policyId", "recipient", "resource", "credentialType", "returnLink", "envelopeRef", "label", "shareExpiresAt", "audience", "issuedAt", "expiresAt", "nonce"];
6735
+ if (request.schema !== "xyz.tinycloud.credentials/invitation-request/v1" || admission.schema !== "xyz.tinycloud.policy/delivery-admission/v0" || fields.some((field) => request[field] !== admission[field]) || request.policyId !== envelope.policyCid || request.recipient !== expected.request.recipientEmail || request.resource !== contentSource.kvResource || request.credentialType !== credentialType.id || request.credentialType !== "opencredentials.email/v1" || request.returnLink !== expected.request.shareUrl || request.envelopeRef !== expected.request.shareCid || request.label !== expected.request.documentName || request.shareExpiresAt !== envelope.expiry || request.audience !== expected.deliveryAudience || request.expiresAt !== expected.request.expiresAt || request.nonce !== expected.request.jti || admission.ownerDid !== envelopeSignature.signerDid || admission.senderKeyDid !== expected.senderKeyDid || canonicalizeSignedObjectUnsigned(admission.actions) !== canonicalizeSignedObjectUnsigned(["tinycloud.kv/get"]) || signature.suite !== "eddsa-ed25519-sha256-jcs-v1" || target.nodeAudience !== binding.nodeAudience || signature.signerDid !== binding.nodeAudience) throw new Error("v3 share delivery authorization is not bound to the submitted request");
6736
+ const issuedAt = Date.parse(String(request.issuedAt));
6737
+ const expiresAt = Date.parse(String(request.expiresAt));
6738
+ if (!Number.isFinite(issuedAt) || !Number.isFinite(expiresAt) || expiresAt <= issuedAt || expiresAt - issuedAt > 15 * 6e4) throw new Error("v3 share delivery authorization time is invalid");
6739
+ const admissionSignature = decodeBase64Url2(signature.value);
6740
+ const { signature: _signature, ...unsignedAdmission } = admission;
6741
+ const digest4 = (0, import_sha2566.sha256)(new TextEncoder().encode(`${DELIVERY_ADMISSION_DOMAIN}${canonicalizeSignedObjectUnsigned(unsignedAdmission)}`));
6742
+ if (admissionSignature.length !== 64 || !import_ed255197.ed25519.verify(admissionSignature, digest4, didKeyBytes(String(signature.signerDid)))) throw new Error("v3 share delivery admission signature is invalid");
6743
+ return { request, admission };
6797
6744
  }
6798
6745
 
6799
6746
  // src/delegations/sender-share-store.ts