@tinycloud/sdk-core 3.0.0-beta.6 → 3.0.0-beta.8

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/index.cjs CHANGED
@@ -64,6 +64,7 @@ __export(index_exports, {
64
64
  CREDENTIAL_CONTRACT_VERSION: () => CREDENTIAL_CONTRACT_VERSION,
65
65
  CREDENTIAL_ERROR_CODES: () => CREDENTIAL_ERROR_CODES,
66
66
  CREDENTIAL_FORMAT: () => CREDENTIAL_FORMAT,
67
+ CREDENTIAL_INVITATION_REQUEST_DOMAIN: () => CREDENTIAL_INVITATION_REQUEST_DOMAIN,
67
68
  CREDENTIAL_PROTOCOL: () => CREDENTIAL_ACQUISITION_PROTOCOL,
68
69
  CREDENTIAL_STEP_REGISTRY_VERSION: () => CREDENTIAL_STEP_REGISTRY_VERSION,
69
70
  CapabilityKeyRegistry: () => CapabilityKeyRegistry,
@@ -87,6 +88,7 @@ __export(index_exports, {
87
88
  DEFAULT_SIGNED_READ_URL_EXPIRY_MS: () => DEFAULT_SIGNED_READ_URL_EXPIRY_MS,
88
89
  DEFAULT_TINYCLOUD_FALLBACK_HOST: () => DEFAULT_TINYCLOUD_FALLBACK_HOST,
89
90
  DEFAULT_TINYCLOUD_LOCATION_REGISTRY_URL: () => DEFAULT_TINYCLOUD_LOCATION_REGISTRY_URL,
91
+ DELIVERY_ADMISSION_DOMAIN: () => DELIVERY_ADMISSION_DOMAIN,
90
92
  DUCKDB: () => import_bootstrap4.DUCKDB,
91
93
  DataVaultService: () => import_sdk_services8.DataVaultService,
92
94
  DatabaseHandle: () => import_sdk_services8.DatabaseHandle,
@@ -177,7 +179,6 @@ __export(index_exports, {
177
179
  SERVICE_LONG_TO_SHORT: () => SERVICE_LONG_TO_SHORT,
178
180
  SERVICE_SHORT_TO_LONG: () => SERVICE_SHORT_TO_LONG,
179
181
  SHARE_DELIVERY_AUTHORIZATION_DOMAIN: () => SHARE_DELIVERY_AUTHORIZATION_DOMAIN,
180
- SHARE_DELIVERY_AUTHORIZATION_V3_DOMAIN: () => SHARE_DELIVERY_AUTHORIZATION_V3_DOMAIN,
181
182
  SPACE: () => import_bootstrap4.SPACE,
182
183
  SQL: () => import_bootstrap4.SQL,
183
184
  SQLAction: () => import_sdk_services8.SQLAction,
@@ -380,6 +381,7 @@ __export(index_exports, {
380
381
  parsePolicySessionUcan: () => parsePolicySessionUcan,
381
382
  parsePortableDelegation: () => parsePortableDelegation,
382
383
  parseRecapCapabilities: () => parseRecapCapabilities,
384
+ parseSecretCatalogKey: () => import_sdk_services8.parseSecretCatalogKey,
383
385
  parseShareArtifact: () => parseShareArtifact,
384
386
  parseShareUrl: () => parseShareUrl,
385
387
  parseSpaceUri: () => parseSpaceUri,
@@ -393,6 +395,7 @@ __export(index_exports, {
393
395
  projectUnifiedPolicyCapabilities: () => projectUnifiedPolicyCapabilities,
394
396
  projectUnifiedPolicyCapability: () => projectUnifiedPolicyCapability,
395
397
  recapCaveatsEqual: () => recapCaveatsEqual,
398
+ registerPolicyV3: () => registerPolicyV3,
396
399
  renewPolicyRootStatusV3: () => renewPolicyRootStatusV3,
397
400
  requestTinyCloudManageKeyScope: () => requestTinyCloudManageKeyScope,
398
401
  resolveCloudLocation: () => resolveCloudLocation,
@@ -3891,7 +3894,8 @@ var MAX_LEGACY_ENVELOPE_EXPIRES_AT = "2026-12-29T00:00:00Z";
3891
3894
  var LAST_V2_READ_AT = "2027-01-05T00:00:00Z";
3892
3895
  async function requestPolicyChallengeV3(input) {
3893
3896
  const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
3894
- const response = await fetchFn(new URL("/share/v3/policy/challenges", input.nodeOrigin), {
3897
+ const policyRuntimePath = policyRuntimeBasePath(input.policyRuntimePath);
3898
+ const response = await fetchFn(new URL(`${policyRuntimePath}/challenges`, input.nodeOrigin), {
3895
3899
  method: "POST",
3896
3900
  redirect: "error",
3897
3901
  signal: input.signal,
@@ -3904,6 +3908,13 @@ async function requestPolicyChallengeV3(input) {
3904
3908
  throw new Error("policy challenge binding is invalid");
3905
3909
  return value;
3906
3910
  }
3911
+ function policyRuntimeBasePath(value) {
3912
+ const path = value ?? "/policy/v3";
3913
+ if (!/^\/policy(?:\/[a-z0-9-]+)*$/.test(path)) {
3914
+ throw new Error("policy runtime path is invalid");
3915
+ }
3916
+ return path;
3917
+ }
3907
3918
  function compactAttenuationForPolicyCapabilities(input) {
3908
3919
  const attenuation = {};
3909
3920
  for (const raw of input) {
@@ -3949,7 +3960,7 @@ function verifyPolicyRootStatusCheckpointV3(input) {
3949
3960
  }
3950
3961
  async function getPolicyRootStatusV3(input) {
3951
3962
  const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
3952
- const response = await fetchFn(new URL(`/share/v3/policy/status/${encodeURIComponent(input.rootCid)}`, input.nodeOrigin), {
3963
+ const response = await fetchFn(new URL(`/policy/v3/status/${encodeURIComponent(input.rootCid)}`, input.nodeOrigin), {
3953
3964
  method: "GET",
3954
3965
  redirect: "error",
3955
3966
  headers: { accept: "application/json" }
@@ -4008,7 +4019,7 @@ async function renewPolicyRootStatusV3(input) {
4008
4019
  };
4009
4020
  const signature = await input.sign((0, import_sha256.sha256)(new TextEncoder().encode(ROOT_STATUS_RENEWAL_V1_DOMAIN + jcsCanonicalize(unsigned))));
4010
4021
  if (signature.length !== 64) throw new Error("policy root renewal signature must be Ed25519");
4011
- const response = await fetchFn(new URL("/share/v3/policy/status", input.nodeOrigin), {
4022
+ const response = await fetchFn(new URL("/policy/v3/status", input.nodeOrigin), {
4012
4023
  method: "POST",
4013
4024
  redirect: "error",
4014
4025
  headers: { accept: "application/json", "content-type": "application/json" },
@@ -4263,6 +4274,133 @@ function contentSourceDigestHex(input) {
4263
4274
  )
4264
4275
  );
4265
4276
  }
4277
+ function exactObject(value, keys, label) {
4278
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
4279
+ throw new Error(`${label} is invalid`);
4280
+ }
4281
+ const record2 = value;
4282
+ if (Object.keys(record2).length !== keys.length || keys.some((key) => !Object.prototype.hasOwnProperty.call(record2, key))) {
4283
+ throw new Error(`${label} is invalid`);
4284
+ }
4285
+ return record2;
4286
+ }
4287
+ function didKeyEd25519PublicKey(value) {
4288
+ const principal = value.split("#", 1)[0];
4289
+ if (!principal.startsWith("did:key:")) {
4290
+ throw new Error("policy enforcer binding signer is invalid");
4291
+ }
4292
+ const material = base58btc.decode(principal.slice("did:key:".length));
4293
+ if (material.length !== 34 || material[0] !== 237 || material[1] !== 1) {
4294
+ throw new Error("policy enforcer binding signer is invalid");
4295
+ }
4296
+ return material.slice(2);
4297
+ }
4298
+ async function registerPolicyV3(input) {
4299
+ const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
4300
+ const rootExpiresAt = new Date(input.rootExpiresAt);
4301
+ const canonicalRootExpiresAt = new Date(
4302
+ Math.floor(rootExpiresAt.getTime() / 1e3) * 1e3
4303
+ ).toISOString().replace(/\.000Z$/, "Z");
4304
+ if (!Number.isFinite(rootExpiresAt.getTime()) || canonicalRootExpiresAt !== input.rootExpiresAt || rootExpiresAt.getTime() <= Date.now()) {
4305
+ throw new Error("policy root expiry is invalid");
4306
+ }
4307
+ const bindingResponse = await fetchFn(
4308
+ new URL("/policy/v3/enforcer-bindings", input.nodeOrigin),
4309
+ {
4310
+ method: "POST",
4311
+ redirect: "error",
4312
+ signal: input.signal,
4313
+ headers: { accept: "application/json", "content-type": "application/json" },
4314
+ body: JSON.stringify({
4315
+ rootExpiresAt: input.rootExpiresAt,
4316
+ enforcerDid: input.enforcerDid
4317
+ })
4318
+ }
4319
+ );
4320
+ if (!bindingResponse.ok) {
4321
+ throw new Error(`policy enforcer binding rejected (${bindingResponse.status})`);
4322
+ }
4323
+ const binding = exactObject(
4324
+ await bindingResponse.json(),
4325
+ [
4326
+ "schema",
4327
+ "enforcerDid",
4328
+ "nodeAudience",
4329
+ "attestationBindingDigestHex",
4330
+ "issuedAt",
4331
+ "expiresAt",
4332
+ "signature"
4333
+ ],
4334
+ "policy enforcer binding"
4335
+ );
4336
+ const signature = exactObject(
4337
+ binding.signature,
4338
+ ["suite", "signerDid", "value"],
4339
+ "policy enforcer binding signature"
4340
+ );
4341
+ const expectedBindingDigestHex = hex(
4342
+ (0, import_sha256.sha256)(
4343
+ new TextEncoder().encode(
4344
+ jcsCanonicalize({
4345
+ enforcerDid: input.enforcerDid,
4346
+ nodeAudience: input.expectedNodeAudience
4347
+ })
4348
+ )
4349
+ )
4350
+ );
4351
+ if (binding.schema !== ATTESTED_ENFORCER_BINDING_V2_SCHEMA || binding.enforcerDid !== input.enforcerDid || binding.nodeAudience !== input.expectedNodeAudience || binding.attestationBindingDigestHex !== expectedBindingDigestHex || binding.expiresAt !== input.rootExpiresAt || typeof binding.issuedAt !== "string" || Date.parse(binding.issuedAt) > Date.now() || signature.suite !== "Ed25519" || signature.signerDid !== input.expectedNodeAudience || typeof signature.value !== "string") {
4352
+ throw new Error("policy enforcer binding is invalid");
4353
+ }
4354
+ const { signature: _signature, ...unsignedBinding } = binding;
4355
+ const signedBinding = (0, import_sha256.sha256)(
4356
+ new TextEncoder().encode(
4357
+ `xyz.tinycloud.policy/AttestedEnforcerBinding/v2\0${jcsCanonicalize(unsignedBinding)}`
4358
+ )
4359
+ );
4360
+ if (!import_ed255193.ed25519.verify(
4361
+ decodeBase64Url2(signature.value),
4362
+ signedBinding,
4363
+ didKeyEd25519PublicKey(input.expectedNodeAudience),
4364
+ { zip215: false }
4365
+ )) {
4366
+ throw new Error("policy enforcer binding signature is invalid");
4367
+ }
4368
+ const response = await fetchFn(
4369
+ new URL("/policy/v3/policies", input.nodeOrigin),
4370
+ {
4371
+ method: "POST",
4372
+ redirect: "error",
4373
+ signal: input.signal,
4374
+ headers: { accept: "application/json", "content-type": "application/json" },
4375
+ body: JSON.stringify({
4376
+ policyCid: input.policyCid,
4377
+ policy: input.policy,
4378
+ policyRoot: input.policyRoot.authorization.replace(/^Bearer\s+/i, ""),
4379
+ enforcementRoot: input.enforcementRoot.authorization.replace(/^Bearer\s+/i, ""),
4380
+ contentSourceDigestHex: input.contentSourceDigestHex,
4381
+ nativeProjectionHashHex: input.nativeProjectionHashHex,
4382
+ attestedEnforcerBinding: binding
4383
+ })
4384
+ }
4385
+ );
4386
+ if (!response.ok) {
4387
+ throw new Error(`policy registration rejected (${response.status})`);
4388
+ }
4389
+ const receipt = exactObject(
4390
+ await response.json(),
4391
+ ["policyCid", "policyRootCid", "enforcementRootCid"],
4392
+ "policy registration response"
4393
+ );
4394
+ if (receipt.policyCid !== input.policyCid || receipt.policyRootCid !== input.policyRoot.cid || receipt.enforcementRootCid !== input.enforcementRoot.cid) {
4395
+ throw new Error("policy registration response binding is invalid");
4396
+ }
4397
+ return {
4398
+ policyCid: input.policyCid,
4399
+ policyRootCid: input.policyRoot.cid,
4400
+ enforcementRootCid: input.enforcementRoot.cid,
4401
+ attestedEnforcerBinding: binding
4402
+ };
4403
+ }
4266
4404
  function policyDigestHex(policy) {
4267
4405
  const canonicalPolicy = {
4268
4406
  ...policy,
@@ -4879,6 +5017,7 @@ async function admitPolicyCredentialV3(input) {
4879
5017
  const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
4880
5018
  const challenge = await requestPolicyChallengeV3({
4881
5019
  nodeOrigin,
5020
+ policyRuntimePath: input.policyRuntimePath,
4882
5021
  policyCid: input.policyCid,
4883
5022
  recipientDid: input.credential.holderDid,
4884
5023
  requestedCapabilities: input.requestedCapabilities,
@@ -4891,7 +5030,7 @@ async function admitPolicyCredentialV3(input) {
4891
5030
  challenge
4892
5031
  });
4893
5032
  const response = await fetchFn(
4894
- new URL("/share/v3/policy/delegations", nodeOrigin),
5033
+ new URL(`${policyRuntimeBasePath2(input.policyRuntimePath)}/delegations`, nodeOrigin),
4895
5034
  {
4896
5035
  method: "POST",
4897
5036
  redirect: "error",
@@ -4936,6 +5075,7 @@ async function admitPolicyCredentialV4(input) {
4936
5075
  const fetchFn = input.fetch ?? globalThis.fetch.bind(globalThis);
4937
5076
  const challenge = await requestPolicyChallengeV3({
4938
5077
  nodeOrigin,
5078
+ policyRuntimePath: input.policyRuntimePath,
4939
5079
  policyCid: input.policyCid,
4940
5080
  recipientDid: input.credential.holderDid,
4941
5081
  requestedCapabilities: input.requestedCapabilities,
@@ -4947,7 +5087,7 @@ async function admitPolicyCredentialV4(input) {
4947
5087
  policy,
4948
5088
  challenge
4949
5089
  });
4950
- const response = await fetchFn(new URL("/share/v3/policy/delegations", nodeOrigin), {
5090
+ const response = await fetchFn(new URL(`${policyRuntimeBasePath2(input.policyRuntimePath)}/delegations`, nodeOrigin), {
4951
5091
  method: "POST",
4952
5092
  redirect: "error",
4953
5093
  signal: input.signal,
@@ -4974,8 +5114,22 @@ async function admitPolicyCredentialV4(input) {
4974
5114
  enforcerDid: input.expectedEnforcerDid
4975
5115
  });
4976
5116
  if (session.cid !== value.sessionCid || session.aud !== input.credential.holderDid || session.fact.policyCid !== input.policyCid || session.fact.recipientDid !== input.credential.holderDid || session.fact.policyDelegationCid !== input.policyRootCid || session.fact.enforcementDelegationCid !== input.enforcementRootCid || jcsCanonicalize(session.att) !== jcsCanonicalize(expectedAttenuation)) throw new Error("policy delegation signed binding is invalid");
5117
+ const importResponse = await fetchFn(new URL("/delegate", nodeOrigin), {
5118
+ method: "POST",
5119
+ redirect: "error",
5120
+ signal: input.signal,
5121
+ headers: { Authorization: session.authorization }
5122
+ });
5123
+ if (!importResponse.ok) throw new Error(`delegation import rejected (${importResponse.status})`);
4977
5124
  input.signal?.throwIfAborted();
4978
- return Object.freeze({ challenge, presentation, session });
5125
+ return Object.freeze({ challenge, presentation, session, delegationImported: true });
5126
+ }
5127
+ function policyRuntimeBasePath2(value) {
5128
+ const path = value ?? "/policy/v3";
5129
+ if (!/^\/policy(?:\/[a-z0-9-]+)*$/.test(path)) {
5130
+ throw new Error("policy runtime path is invalid");
5131
+ }
5132
+ return path;
4979
5133
  }
4980
5134
 
4981
5135
  // src/requester/index.ts
@@ -12161,41 +12315,12 @@ function shareDeliveryTrustedKid(publicKey) {
12161
12315
 
12162
12316
  // src/delegations/share-delivery-v3.ts
12163
12317
  var import_ed2551910 = require("@noble/curves/ed25519");
12164
- var SHARE_DELIVERY_AUTHORIZATION_V3_DOMAIN = "xyz.tinycloud.share/delivery-authorization/v3\0";
12165
- var AUTHORIZATION_KEYS2 = [
12166
- "type",
12167
- "version",
12168
- "jti",
12169
- "shareCid",
12170
- "shareId",
12171
- "policyCid",
12172
- "policyRootCid",
12173
- "enforcementRootCid",
12174
- "nodeAudience",
12175
- "enforcerDid",
12176
- "targetOrigin",
12177
- "openCredentialsAudience",
12178
- "holder",
12179
- "recipientMatcher",
12180
- "deliveryEmail",
12181
- "shareUrl",
12182
- "returnOrigin",
12183
- "documentName",
12184
- "senderDid",
12185
- "senderTrust",
12186
- "contentSource",
12187
- "contentSourceDigestHex",
12188
- "shareExpiresAt",
12189
- "issuedAt",
12190
- "reportAbuseToken",
12191
- "actions",
12192
- "resource",
12193
- "requestBodyDigest",
12194
- "idempotencyKey",
12195
- "expiresAt",
12196
- "dataAuthority"
12197
- ];
12198
- function exactObject(value, keys, label) {
12318
+ var import_sha2567 = require("@noble/hashes/sha256");
12319
+ var CREDENTIAL_INVITATION_REQUEST_DOMAIN = "xyz.tinycloud.credentials/invitation-request/v1\0";
12320
+ var DELIVERY_ADMISSION_DOMAIN = "xyz.tinycloud.policy/delivery-admission/v0\0";
12321
+ var REQUEST_KEYS = ["schema", "policyId", "recipient", "resource", "credentialType", "returnLink", "envelopeRef", "audience", "issuedAt", "expiresAt", "nonce"];
12322
+ var ADMISSION_KEYS = ["schema", "policyId", "ownerDid", "recipient", "resource", "actions", "credentialType", "returnLink", "envelopeRef", "senderKeyDid", "audience", "issuedAt", "expiresAt", "nonce", "signature"];
12323
+ function exactObject2(value, keys, label) {
12199
12324
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${label} is invalid`);
12200
12325
  const record2 = value;
12201
12326
  if (Object.keys(record2).length !== keys.length || keys.some((key) => !Object.prototype.hasOwnProperty.call(record2, key))) throw new Error(`${label} has unknown or missing fields`);
@@ -12214,6 +12339,12 @@ function object3(value, label) {
12214
12339
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${label} is invalid`);
12215
12340
  return value;
12216
12341
  }
12342
+ function didKeyBytes2(did) {
12343
+ if (!did.startsWith("did:key:z") || /[#/?]/.test(did.slice("did:key:".length))) throw new Error("v3 delivery admission signer is invalid");
12344
+ const decoded = base58btc.decode(did.slice("did:key:".length));
12345
+ if (decoded.length !== 34 || decoded[0] !== 237 || decoded[1] !== 1) throw new Error("v3 delivery admission signer is invalid");
12346
+ return decoded.slice(2);
12347
+ }
12217
12348
  function validateShareDeliveryAuthorizationV3Bytes(bytes2, expected) {
12218
12349
  let parsed;
12219
12350
  try {
@@ -12221,33 +12352,27 @@ function validateShareDeliveryAuthorizationV3Bytes(bytes2, expected) {
12221
12352
  } catch {
12222
12353
  throw new Error("v3 share delivery response is not valid UTF-8 JSON");
12223
12354
  }
12224
- const root = exactObject(parsed, ["authorization", "proof"], "v3 share delivery response");
12225
- const authorization = exactObject(root.authorization, AUTHORIZATION_KEYS2, "v3 share delivery authorization");
12226
- const proof = exactObject(root.proof, ["alg", "kid", "signature"], "v3 share delivery proof");
12355
+ const root = exactObject2(parsed, ["request", "admission"], "v3 share delivery response");
12356
+ const request = exactObject2(root.request, REQUEST_KEYS, "credential invitation request");
12357
+ const admission = exactObject2(root.admission, ADMISSION_KEYS, "delivery admission");
12358
+ const signature = exactObject2(admission.signature, ["suite", "signerDid", "value"], "delivery admission signature");
12227
12359
  const envelope = object3(expected.request.envelope, "v3 share envelope");
12228
- const policyRoot = object3(envelope.policyRoot, "v3 policy root");
12229
- const enforcementRoot = object3(envelope.enforcementRoot, "v3 enforcement root");
12230
- const target = object3(envelope.target, "v3 target");
12231
- const display = object3(envelope.display, "v3 display");
12232
- const resource = object3(envelope.resource, "v3 resource");
12360
+ const policy = object3(envelope.policy, "v3 share policy");
12361
+ const requirement = object3(policy.credentialRequirement, "v3 credential requirement");
12362
+ const credentialType = object3(requirement.credentialType, "v3 credential type");
12363
+ const contentSource = object3(envelope.contentSource, "v3 content source");
12233
12364
  const envelopeSignature = object3(envelope.signature, "v3 envelope signature");
12234
- const shareUrl = new URL(expected.request.shareUrl);
12235
- const targetOrigin = String(target.origin);
12236
- const targetUrl = new URL(targetOrigin);
12237
- const targetHost = targetUrl.hostname;
12238
- const expectedNodeAudience = `did:web:${targetHost}`;
12239
- if (authorization.type !== "TinyCloudShareDeliveryAuthorization" || authorization.version !== 3 || authorization.dataAuthority !== false || authorization.jti !== expected.request.jti || authorization.shareCid !== expected.request.shareCid || authorization.shareId !== envelope.shareId || authorization.policyCid !== envelope.policyCid || authorization.policyRootCid !== policyRoot.cid || authorization.enforcementRootCid !== enforcementRoot.cid || authorization.enforcerDid !== target.nodeAudience || authorization.targetOrigin !== target.origin || authorization.nodeAudience !== expectedNodeAudience || expected.nodeProof.kid.split("#", 1)[0] !== expectedNodeAudience || authorization.recipientMatcher === void 0 || canonicalizeSignedObjectUnsigned(authorization.recipientMatcher) !== canonicalizeSignedObjectUnsigned(envelope.recipientMatcher) || canonicalizeSignedObjectUnsigned(authorization.contentSource) !== canonicalizeSignedObjectUnsigned(envelope.contentSource) || authorization.contentSourceDigestHex !== envelope.contentSourceDigestHex || authorization.deliveryEmail !== expected.request.recipientEmail || authorization.shareUrl !== expected.request.shareUrl || authorization.documentName !== expected.request.documentName || authorization.documentName !== display.filename || authorization.senderDid !== envelopeSignature.signerDid || authorization.senderTrust !== "verified" || canonicalizeSignedObjectUnsigned(authorization.actions) !== canonicalizeSignedObjectUnsigned(envelope.actions) || authorization.resource !== resource.path || authorization.shareExpiresAt !== envelope.expiry || authorization.requestBodyDigest !== expected.request.requestBodyDigest || authorization.expiresAt !== expected.request.expiresAt || authorization.idempotencyKey !== expected.request.jti || authorization.reportAbuseToken !== expected.request.jti || authorization.returnOrigin !== shareUrl.origin || shareUrl.pathname !== `/s/${authorization.shareCid}` || shareUrl.hash !== `#k=${expected.request.envelopeKey}` || targetUrl.protocol !== "https:" || shareUrl.protocol !== "https:") throw new Error("v3 share delivery authorization is not bound to the submitted request");
12240
- if (typeof authorization.openCredentialsAudience !== "string" || authorization.openCredentialsAudience !== expected.credentialsAudience || authorization.openCredentialsAudience === authorization.nodeAudience || authorization.openCredentialsAudience === authorization.returnOrigin) throw new Error("v3 share delivery credentials audience is untrusted");
12241
- if (proof.alg !== "EdDSA" || proof.kid !== expected.nodeProof.kid || typeof proof.signature !== "string") throw new Error("v3 share delivery proof is invalid");
12242
- const issuedAt = Date.parse(String(authorization.issuedAt));
12243
- const expiresAt = Date.parse(String(authorization.expiresAt));
12244
- const shareExpiresAt = Date.parse(String(authorization.shareExpiresAt));
12245
- if (!Number.isFinite(issuedAt) || !Number.isFinite(expiresAt) || !Number.isFinite(shareExpiresAt) || expiresAt <= issuedAt || expiresAt - issuedAt > 5 * 6e4 || shareExpiresAt <= issuedAt || typeof authorization.holder !== "string" || !authorization.holder.startsWith("did:")) throw new Error("v3 share delivery authorization time or holder is invalid");
12246
- const publicKey = expected.nodeProof.publicKey.length === 34 ? expected.nodeProof.publicKey.slice(2) : expected.nodeProof.publicKey;
12247
- const signature = decodeBase64Url3(proof.signature);
12248
- const signed = new TextEncoder().encode(`${SHARE_DELIVERY_AUTHORIZATION_V3_DOMAIN}${canonicalizeSignedObjectUnsigned(authorization)}`);
12249
- if (publicKey.length !== 32 || signature.length !== 64 || !import_ed2551910.ed25519.verify(signature, signed, publicKey)) throw new Error("v3 share delivery proof signature is invalid");
12250
- return { authorization, proof };
12365
+ const target = object3(envelope.target, "v3 target");
12366
+ const fields = ["policyId", "recipient", "resource", "credentialType", "returnLink", "envelopeRef", "audience", "issuedAt", "expiresAt", "nonce"];
12367
+ 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.audience !== expected.credentialsAudience || 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" || signature.signerDid !== target.nodeAudience) throw new Error("v3 share delivery authorization is not bound to the submitted request");
12368
+ const issuedAt = Date.parse(String(request.issuedAt));
12369
+ const expiresAt = Date.parse(String(request.expiresAt));
12370
+ if (!Number.isFinite(issuedAt) || !Number.isFinite(expiresAt) || expiresAt <= issuedAt || expiresAt - issuedAt > 15 * 6e4) throw new Error("v3 share delivery authorization time is invalid");
12371
+ const admissionSignature = decodeBase64Url3(signature.value);
12372
+ const { signature: _signature, ...unsignedAdmission } = admission;
12373
+ const digest4 = (0, import_sha2567.sha256)(new TextEncoder().encode(`${DELIVERY_ADMISSION_DOMAIN}${canonicalizeSignedObjectUnsigned(unsignedAdmission)}`));
12374
+ if (admissionSignature.length !== 64 || !import_ed2551910.ed25519.verify(admissionSignature, digest4, didKeyBytes2(String(signature.signerDid)))) throw new Error("v3 share delivery admission signature is invalid");
12375
+ return { request, admission };
12251
12376
  }
12252
12377
 
12253
12378
  // src/delegations/sender-share-store.ts