@tinycloud/share-sdk 1.4.2 → 1.4.3-beta.0

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
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
33
  ADDRESSED_SHARE_TOO_LARGE_MESSAGE: () => ADDRESSED_SHARE_TOO_LARGE_MESSAGE,
34
+ AddressedContentSourceError: () => AddressedContentSourceError,
34
35
  AddressedShareOverLimitError: () => AddressedShareOverLimitError,
35
36
  ArtifactPinError: () => ArtifactPinError,
36
37
  CredentialInvitationError: () => CredentialInvitationError,
@@ -59,8 +60,10 @@ __export(src_exports, {
59
60
  artifactBindingView: () => artifactBindingView,
60
61
  assertAddressedShareFits: () => assertAddressedShareFits,
61
62
  assertArtifactBinding: () => assertArtifactBinding,
63
+ assertPathBoundContentSource: () => assertPathBoundContentSource,
62
64
  authorizationMethodForTarget: () => authorizationMethodForTarget,
63
65
  authorizeShare: () => authorizeShare,
66
+ bindPathBoundContentSource: () => bindPathBoundContentSource,
64
67
  canonicalOwnerSharePolicy: () => canonicalOwnerSharePolicy,
65
68
  canonicalShareFilename: () => canonicalShareFilename,
66
69
  canonicalize: () => canonicalize,
@@ -72,7 +75,9 @@ __export(src_exports, {
72
75
  createNativeShare: () => createNativeShare,
73
76
  createPolicyEnforcementDelegation: () => createPolicyEnforcementDelegation,
74
77
  createShareV2HolderBindingArtifact: () => createShareV2HolderBindingArtifact,
78
+ defaultEncryptionNetworkForOwner: () => defaultEncryptionNetworkForOwner,
75
79
  deliverCredentialInvitation: () => deliverCredentialInvitation,
80
+ encryptAddressedShareContent: () => encryptAddressedShareContent,
76
81
  fromBase64Url: () => fromBase64Url,
77
82
  hasUnsafeFilenameCodePoint: () => hasUnsafeFilenameCodePoint,
78
83
  historyRecordForPublishedShare: () => historyRecordForPublishedShare,
@@ -83,6 +88,10 @@ __export(src_exports, {
83
88
  openNativeShare: () => openNativeShare,
84
89
  parseAddressedEnvelope: () => parseAddressedEnvelope,
85
90
  parseNativeShareUrl: () => parseNativeShareUrl,
91
+ pathBoundKeyPath: () => pathBoundKeyPath,
92
+ pathBoundSessionPermissions: () => pathBoundSessionPermissions,
93
+ pathBoundStoredBytes: () => pathBoundStoredBytes,
94
+ planPathBoundShare: () => planPathBoundShare,
86
95
  prepareAddressedShare: () => prepareAddressedShare,
87
96
  publishAddressedShare: () => publishAddressedShare,
88
97
  publishPolicyShare: () => publishPolicyShare,
@@ -102,7 +111,8 @@ __export(src_exports, {
102
111
  toShareErrorInfo: () => toShareErrorInfo,
103
112
  validateOwnerSharePolicyRegistration: () => validateOwnerSharePolicyRegistration,
104
113
  validateOwnerSharePolicyRegistrationBytes: () => validateOwnerSharePolicyRegistrationBytes,
105
- verifyArtifactShare: () => verifyArtifactShare
114
+ verifyArtifactShare: () => verifyArtifactShare,
115
+ wrappedKeyDigestHex: () => wrappedKeyDigestHex
106
116
  });
107
117
  module.exports = __toCommonJS(src_exports);
108
118
 
@@ -6521,7 +6531,220 @@ async function parseAddressedEnvelope(value) {
6521
6531
  }
6522
6532
 
6523
6533
  // src/addressed-publish.ts
6534
+ var import_sha2563 = require("@noble/hashes/sha256");
6535
+
6536
+ // src/addressed-content.ts
6524
6537
  var import_sha2562 = require("@noble/hashes/sha256");
6538
+ var import_sha3 = require("@noble/hashes/sha3");
6539
+ var AddressedContentSourceError = class extends TypeError {
6540
+ code;
6541
+ constructor(code3, message) {
6542
+ super(message);
6543
+ this.name = "AddressedContentSourceError";
6544
+ this.code = code3;
6545
+ }
6546
+ };
6547
+ var SHARE_ID = /^[a-z0-9][a-z0-9_-]{15,63}$/;
6548
+ var NETWORK = /^urn:tinycloud:encryption:(.+):default$/;
6549
+ var OWNER_PKH = /^did:pkh:eip155:([1-9][0-9]*):(0x[0-9a-fA-F]{40})$/;
6550
+ var OWNER_KEY = /^did:key:[A-Za-z0-9]+$/;
6551
+ var ENVELOPE_FIELDS = ["v", "networkId", "keyPath", "alg", "keyVersion", "encryptedSymmetricKey", "encryptedSymmetricKeyHash", "ciphertext", "aad", "metadata"];
6552
+ var ENVELOPE_ALG = "x25519-aes256gcm/v1";
6553
+ var HEX_DIGEST = /^[0-9a-f]{64}$/;
6554
+ var BASE64 = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
6555
+ var textEncoder = new TextEncoder();
6556
+ function hex2(bytes3) {
6557
+ return [...bytes3].map((byte) => byte.toString(16).padStart(2, "0")).join("");
6558
+ }
6559
+ function checksumAddress(address) {
6560
+ const lower = address.toLowerCase().slice(2);
6561
+ const hash = (0, import_sha3.keccak_256)(textEncoder.encode(lower));
6562
+ let out = "0x";
6563
+ for (let index = 0; index < lower.length; index++) {
6564
+ const nibble = hash[index >> 1] >> (index % 2 === 0 ? 4 : 0) & 15;
6565
+ out += nibble >= 8 ? lower[index].toUpperCase() : lower[index];
6566
+ }
6567
+ return out;
6568
+ }
6569
+ function pathBoundKeyPath(shareId) {
6570
+ if (typeof shareId !== "string" || !SHARE_ID.test(shareId)) {
6571
+ throw new AddressedContentSourceError("share-id-invalid", "addressed share id is invalid: 16 to 64 characters from lowercase letters, digits, '_' and '-', starting with a letter or digit (a lowercase UUID, hyphens included, is valid)");
6572
+ }
6573
+ return `share/${shareId}`;
6574
+ }
6575
+ function defaultEncryptionNetworkForOwner(owner) {
6576
+ let did = owner;
6577
+ const address = typeof owner === "string" ? /^0x[0-9a-fA-F]{40}$/.test(owner) ? owner : void 0 : owner?.address;
6578
+ if (address !== void 0) {
6579
+ const chainId = typeof owner === "string" ? 1 : owner.chainId ?? 1;
6580
+ if (typeof address !== "string" || !/^0x[0-9a-fA-F]{40}$/.test(address) || !Number.isSafeInteger(chainId) || chainId < 1) {
6581
+ throw new AddressedContentSourceError("network-invalid", "owner address is not an Ethereum address");
6582
+ }
6583
+ did = `did:pkh:eip155:${chainId}:${address}`;
6584
+ }
6585
+ const pkh = typeof did === "string" ? OWNER_PKH.exec(did) : null;
6586
+ const normalized = pkh === null ? did : `did:pkh:eip155:${pkh[1]}:${checksumAddress(pkh[2])}`;
6587
+ const network = `urn:tinycloud:encryption:${String(normalized)}:default`;
6588
+ if (typeof normalized !== "string" || !(pkh !== null || OWNER_KEY.test(normalized))) {
6589
+ throw new AddressedContentSourceError("network-invalid", "owner does not name an encryption network");
6590
+ }
6591
+ return network;
6592
+ }
6593
+ function assertEncryptionNetwork(network) {
6594
+ const match = typeof network === "string" ? NETWORK.exec(network) : null;
6595
+ if (match === null) {
6596
+ throw new AddressedContentSourceError("network-invalid", "encryption network must be the owner's default network: urn:tinycloud:encryption:<did>:default");
6597
+ }
6598
+ const owner = match[1];
6599
+ const pkh = OWNER_PKH.exec(owner);
6600
+ if (pkh !== null) {
6601
+ if (pkh[2] !== checksumAddress(pkh[2])) {
6602
+ throw new AddressedContentSourceError("network-not-checksummed", "encryption network address must be EIP-55 checksummed; use defaultEncryptionNetworkForOwner(ownerDid)");
6603
+ }
6604
+ } else if (!OWNER_KEY.test(owner)) {
6605
+ throw new AddressedContentSourceError("network-invalid", "encryption network owner must be a did:pkh:eip155 address or a did:key");
6606
+ }
6607
+ return network;
6608
+ }
6609
+ var assertNetwork = assertEncryptionNetwork;
6610
+ function decodeWrappedKey(encryptedSymmetricKey) {
6611
+ if (typeof encryptedSymmetricKey !== "string" || !BASE64.test(encryptedSymmetricKey)) {
6612
+ throw new AddressedContentSourceError("envelope-invalid", "wrapped content key is not strict base64");
6613
+ }
6614
+ try {
6615
+ return fromBase64Url(encryptedSymmetricKey.replace(/=+$/, "").replace(/\+/g, "-").replace(/\//g, "_"));
6616
+ } catch {
6617
+ throw new AddressedContentSourceError("envelope-invalid", "wrapped content key is not strict base64");
6618
+ }
6619
+ }
6620
+ function decodeBase64(value) {
6621
+ try {
6622
+ return fromBase64Url(value.replace(/=+$/, "").replace(/\+/g, "-").replace(/\//g, "_"));
6623
+ } catch {
6624
+ throw new AddressedContentSourceError("envelope-invalid", "envelope field is not strict base64");
6625
+ }
6626
+ }
6627
+ function wrappedKeyDigestHex(encryptedSymmetricKey) {
6628
+ return hex2((0, import_sha2562.sha256)(decodeWrappedKey(encryptedSymmetricKey)));
6629
+ }
6630
+ function canonicalKeyHashHex(encryptedSymmetricKey) {
6631
+ return hex2((0, import_sha2562.sha256)(textEncoder.encode(canonicalize(encryptedSymmetricKey))));
6632
+ }
6633
+ function pathBoundSessionPermissions(input) {
6634
+ const encryptionNetwork = assertNetwork(input.encryptionNetwork);
6635
+ return [{ service: "tinycloud.encryption", path: `${encryptionNetwork}/share/`, actions: ["tinycloud.encryption/decrypt", "tinycloud.encryption/key.create"] }];
6636
+ }
6637
+ function planPathBoundShare(input) {
6638
+ const keyPath = pathBoundKeyPath(input.shareId);
6639
+ const encryptionNetwork = assertNetwork(input.encryptionNetwork);
6640
+ const keyResource = `${encryptionNetwork}/${keyPath}`;
6641
+ return {
6642
+ shareId: input.shareId,
6643
+ encryptionNetwork,
6644
+ keyPath,
6645
+ keyResource,
6646
+ requiredPermissions: [{ service: "tinycloud.encryption", path: keyResource, actions: ["tinycloud.encryption/key.create"] }],
6647
+ sessionPermissions: pathBoundSessionPermissions({ encryptionNetwork }),
6648
+ registrationPermissions: [{ service: "tinycloud.encryption", path: `${encryptionNetwork}/share/`, actions: ["tinycloud.encryption/decrypt"] }],
6649
+ encryptOptions: (extra) => ({ networkId: encryptionNetwork, ...extra?.metadata === void 0 ? {} : { metadata: { ...extra.metadata } } })
6650
+ };
6651
+ }
6652
+ function pathBoundStoredBytes(envelope) {
6653
+ return textEncoder.encode(canonicalize(envelope));
6654
+ }
6655
+ function assertEnvelope(plan, envelope) {
6656
+ if (envelope === null || typeof envelope !== "object" || envelope.v !== 2) {
6657
+ throw new AddressedContentSourceError("envelope-invalid", "path-bound content must be a v2 named-key envelope (encrypt with keys.encrypt, not encryptToNetwork)");
6658
+ }
6659
+ if (envelope.networkId !== plan.encryptionNetwork || envelope.keyPath !== plan.keyPath) {
6660
+ throw new AddressedContentSourceError("key-path-mismatch", "envelope network or key path does not match the share's plan");
6661
+ }
6662
+ if (!Number.isSafeInteger(envelope.keyVersion) || envelope.keyVersion < 1) {
6663
+ throw new AddressedContentSourceError("envelope-invalid", "envelope key version is invalid");
6664
+ }
6665
+ wrappedKeyDigestHex(envelope.encryptedSymmetricKey);
6666
+ if (envelope.encryptedSymmetricKeyHash !== canonicalKeyHashHex(envelope.encryptedSymmetricKey)) {
6667
+ throw new AddressedContentSourceError("envelope-invalid", "envelope key hash does not match its wrapped key");
6668
+ }
6669
+ const record = envelope;
6670
+ if (Object.keys(record).some((key) => !ENVELOPE_FIELDS.includes(key)) || record.alg !== ENVELOPE_ALG) {
6671
+ throw new AddressedContentSourceError("envelope-invalid", "envelope has a field or algorithm the recipient does not accept");
6672
+ }
6673
+ if (typeof record.ciphertext !== "string" || !BASE64.test(record.ciphertext) || decodeBase64(record.ciphertext).length < 28) {
6674
+ throw new AddressedContentSourceError("envelope-invalid", "envelope ciphertext is not strict base64 of at least 28 bytes");
6675
+ }
6676
+ if (record.aad !== void 0 && (typeof record.aad !== "string" || !BASE64.test(record.aad))) {
6677
+ throw new AddressedContentSourceError("envelope-invalid", "envelope aad is not strict base64");
6678
+ }
6679
+ if (record.metadata !== void 0 && (record.metadata === null || typeof record.metadata !== "object" || Array.isArray(record.metadata) || Object.values(record.metadata).some((entry) => typeof entry !== "string"))) {
6680
+ throw new AddressedContentSourceError("envelope-invalid", "envelope metadata must be an object of strings");
6681
+ }
6682
+ }
6683
+ function bindPathBoundContentSource(input) {
6684
+ const { plan, envelope } = input;
6685
+ assertEnvelope(plan, envelope);
6686
+ const expected = pathBoundStoredBytes(envelope);
6687
+ if (input.storedBytes.length !== expected.length || input.storedBytes.some((byte, index) => byte !== expected[index])) {
6688
+ throw new AddressedContentSourceError("stored-bytes-mismatch", "uploaded bytes are not the canonical v2 envelope; upload pathBoundStoredBytes(envelope)");
6689
+ }
6690
+ return {
6691
+ shareId: plan.shareId,
6692
+ kvResource: input.kvResource,
6693
+ selector: input.selector,
6694
+ encryptionNetwork: plan.encryptionNetwork,
6695
+ encryptionKeyPath: plan.keyPath,
6696
+ encryptedSymmetricKeyDigestHex: wrappedKeyDigestHex(envelope.encryptedSymmetricKey),
6697
+ keyVersion: envelope.keyVersion,
6698
+ mode: "immutable",
6699
+ initialCiphertextDigestHex: hex2((0, import_sha2562.sha256)(expected))
6700
+ };
6701
+ }
6702
+ function isUnauthorized(error) {
6703
+ const value = error;
6704
+ return value !== null && typeof value === "object" && (value.status === 401 || value.status === 403 || value.code === "PERMISSION_DENIED" || value.code === "AUTH_UNAUTHORIZED");
6705
+ }
6706
+ async function encryptAddressedShareContent(input) {
6707
+ const { plan, keys } = input;
6708
+ const byteLength = input.plaintext.byteLength;
6709
+ let receipt;
6710
+ try {
6711
+ receipt = await keys.createKey(plan.keyPath, { networkId: plan.encryptionNetwork });
6712
+ } catch (error) {
6713
+ if (isUnauthorized(error)) {
6714
+ const status = error.status;
6715
+ throw new AddressedContentSourceError(
6716
+ "key-not-authorized",
6717
+ `the owner session does not hold tinycloud.encryption/key.create on ${plan.keyResource} (the node answers "Unauthorized Action: ${plan.keyResource} / tinycloud.encryption/key.create"); hold it either at sign-in (put plan.sessionPermissions in the manifest: key.create on ${plan.encryptionNetwork}/share/) or per share (requestPermissions(plan.requiredPermissions)) before creating the key` + (status === 403 ? "; if the owner signs in through OpenKey, the request must come from a first-party TinyCloud origin" : "")
6718
+ );
6719
+ }
6720
+ throw error;
6721
+ }
6722
+ if (receipt.networkId !== plan.encryptionNetwork || receipt.keyPath !== plan.keyPath || receipt.state !== void 0 && receipt.state !== "active") {
6723
+ throw new AddressedContentSourceError("key-receipt-mismatch", "the created key does not match this share");
6724
+ }
6725
+ const envelope = await keys.encrypt(plan.keyPath, input.plaintext, plan.encryptOptions(input.metadata === void 0 ? void 0 : { metadata: input.metadata }));
6726
+ assertEnvelope(plan, envelope);
6727
+ if (receipt.keyVersion !== void 0 && envelope.keyVersion !== receipt.keyVersion) {
6728
+ throw new AddressedContentSourceError("key-receipt-mismatch", "the envelope key version does not match the created key");
6729
+ }
6730
+ const storedBytes = pathBoundStoredBytes(envelope);
6731
+ return { envelope, storedBytes, byteLength };
6732
+ }
6733
+ function assertPathBoundContentSource(source, shareId) {
6734
+ if (source === void 0 || source === null || typeof source !== "object") {
6735
+ throw new AddressedContentSourceError("key-path-required", "addressed content source is missing");
6736
+ }
6737
+ if (source.encryptionKeyPath === void 0) {
6738
+ throw new AddressedContentSourceError("key-path-required", "addressed content source must name its key (encryptionKeyPath: share/<shareId>); a network-wide source is not accepted");
6739
+ }
6740
+ if (source.encryptionKeyPath !== pathBoundKeyPath(shareId)) {
6741
+ throw new AddressedContentSourceError("key-path-mismatch", "addressed content source key path must be share/<shareId> of this share");
6742
+ }
6743
+ if (typeof source.encryptedSymmetricKeyDigestHex !== "string" || !HEX_DIGEST.test(source.encryptedSymmetricKeyDigestHex)) {
6744
+ throw new AddressedContentSourceError("digest-invalid", "addressed content source needs encryptedSymmetricKeyDigestHex: 64 lowercase hex characters");
6745
+ }
6746
+ assertEncryptionNetwork(source.encryptionNetwork);
6747
+ }
6525
6748
 
6526
6749
  // src/authorization.ts
6527
6750
  async function authorizeShare(input) {
@@ -7019,7 +7242,7 @@ var POLICY_CAPABILITY_V1_DOMAIN2 = "xyz.tinycloud.policy/PolicyCapability/v1\0";
7019
7242
  var CONTENT_SOURCE_V1_DOMAIN2 = "xyz.tinycloud.policy/ContentSource/v1\0";
7020
7243
  var NATIVE_PROJECTION_V1_DOMAIN2 = "xyz.tinycloud.policy/NativeProjection/v1\0";
7021
7244
  var ENVELOPE_V3_DOMAIN = "xyz.tinycloud.share/envelope/v3\0";
7022
- var textEncoder = new TextEncoder();
7245
+ var textEncoder2 = new TextEncoder();
7023
7246
  function targetMatcher(target) {
7024
7247
  if (target.kind === "recipientDid") return { kind: "recipientDid", value: target.did };
7025
7248
  if (target.kind === "email") return { kind: "exactEmail", value: target.address };
@@ -7030,17 +7253,18 @@ function targetKind(target) {
7030
7253
  }
7031
7254
  var OWNER_SHARE_ACTIONS = /* @__PURE__ */ new Set(["tinycloud.kv/get", "tinycloud.kv/list", "tinycloud.kv/metadata", "tinycloud.kv/put"]);
7032
7255
  function assertSafeInput(input) {
7033
- if (!/^[A-Za-z0-9_-]{16,128}$/.test(input.shareId)) throw new TypeError("addressed share id is invalid");
7256
+ pathBoundKeyPath(input.shareId);
7257
+ assertPathBoundContentSource(input.contentSource, input.shareId);
7034
7258
  if (!Number.isSafeInteger(input.byteLength) || input.byteLength < 0 || input.byteLength > SHARE_CONTENT_LIMIT) throw new TypeError("addressed content length is invalid");
7035
7259
  if (!Number.isFinite(input.expiresAt.getTime()) || input.expiresAt.getTime() <= Date.now()) throw new TypeError("addressed share expiry must be in the future");
7036
7260
  if (input.artifact === "html" && (input.resource.kind !== "prefix" || !input.actions.includes("read") || !input.actions.includes("list"))) throw new TypeError("html artifacts require a readable prefix");
7037
7261
  if (input.contentSource.shareId !== input.shareId || input.contentSource.selector !== input.resource.kind) throw new TypeError("addressed content source is not bound to the share");
7038
7262
  }
7039
- function hex2(bytes3) {
7263
+ function hex3(bytes3) {
7040
7264
  return [...bytes3].map((byte) => byte.toString(16).padStart(2, "0")).join("");
7041
7265
  }
7042
7266
  function digestHex(value, domain) {
7043
- return hex2((0, import_sha2562.sha256)(textEncoder.encode(`${domain}${canonicalize(value)}`)));
7267
+ return hex3((0, import_sha2563.sha256)(textEncoder2.encode(`${domain}${canonicalize(value)}`)));
7044
7268
  }
7045
7269
  function sortCanonical(values) {
7046
7270
  return [...values].sort((left, right) => canonicalize(left).localeCompare(canonicalize(right)));
@@ -7084,19 +7308,20 @@ async function createPolicy(options, capabilities) {
7084
7308
  const unsigned = options.credentialRequirement === void 0 ? { schema: "xyz.tinycloud.policy/policy/v1", ...fields } : { schema: "xyz.tinycloud.policy/policy/v2", ...fields, credentialRequirement: options.credentialRequirement };
7085
7309
  const domain = options.credentialRequirement === void 0 ? POLICY_V1_DOMAIN : POLICY_V2_DOMAIN;
7086
7310
  const policyDigestHex = digestHex(unsigned, domain);
7087
- const signature = await options.authority.sign((0, import_sha2562.sha256)(textEncoder.encode(`${domain}${canonicalize(unsigned)}`)));
7311
+ const signature = await options.authority.sign((0, import_sha2563.sha256)(textEncoder2.encode(`${domain}${canonicalize(unsigned)}`)));
7088
7312
  if (signature.byteLength !== 64) throw new TypeError("policy signature must be Ed25519");
7089
7313
  const policy = {
7090
7314
  ...unsigned,
7091
7315
  policyId: `pol_${base32Lower2(Uint8Array.from(policyDigestHex.match(/../g), (byte) => Number.parseInt(byte, 16)))}`,
7092
7316
  signature: { suite: "Ed25519", signerDid: options.authority.ownerDid, value: toBase64Url(signature) }
7093
7317
  };
7094
- return { policy, policyCid: await computeCid(textEncoder.encode(canonicalize(policy))), policyDigestHex };
7318
+ return { policy, policyCid: await computeCid(textEncoder2.encode(canonicalize(policy))), policyDigestHex };
7095
7319
  }
7096
7320
  function addressedPlan(options) {
7097
7321
  const capabilities = sortCanonical([
7098
7322
  { kind: "kv", resource: options.contentSource.kvResource, selector: options.resource.kind, actions: [...options.policyActions] },
7099
- { kind: "encryption", resource: options.contentSource.encryptionKeyPath === void 0 ? options.contentSource.encryptionNetwork : `${options.contentSource.encryptionNetwork}/${options.contentSource.encryptionKeyPath}`, action: "tinycloud.encryption/decrypt" }
7323
+ // Only this share's one key: there is no network-scope capability.
7324
+ { kind: "encryption", resource: `${options.contentSource.encryptionNetwork}/${options.contentSource.encryptionKeyPath}`, action: "tinycloud.encryption/decrypt" }
7100
7325
  ]);
7101
7326
  return {
7102
7327
  expiry: rfc3339Seconds(options.expiresAt),
@@ -7184,7 +7409,7 @@ function mailboxCredentialCommitment(target) {
7184
7409
  return {
7185
7410
  type: "TinyCloudPolicyCredentialRequirement",
7186
7411
  version: 1,
7187
- requirementDigest: toBase64Url((0, import_sha2562.sha256)(textEncoder.encode(canonicalize(requirement)))),
7412
+ requirementDigest: toBase64Url((0, import_sha2563.sha256)(textEncoder2.encode(canonicalize(requirement)))),
7188
7413
  descriptorDigest: target.kind === "email" ? EMAIL_DESCRIPTOR_DIGEST : EMAIL_DOMAIN_DESCRIPTOR_DIGEST,
7189
7414
  issuerDid: EMAIL_CREDENTIAL_ISSUER_DID,
7190
7415
  issuerKid: EMAIL_CREDENTIAL_ISSUER_KID,
@@ -7279,11 +7504,11 @@ async function publishAddressedShare(input) {
7279
7504
  expiry
7280
7505
  });
7281
7506
  unsignedShareEnvelopeV3Schema.parse(unsigned);
7282
- const envelopeSignature = await options.authority.sign((0, import_sha2562.sha256)(textEncoder.encode(`${ENVELOPE_V3_DOMAIN}${canonicalize(unsigned)}`)));
7507
+ const envelopeSignature = await options.authority.sign((0, import_sha2563.sha256)(textEncoder2.encode(`${ENVELOPE_V3_DOMAIN}${canonicalize(unsigned)}`)));
7283
7508
  if (envelopeSignature.byteLength !== 64) throw new TypeError("v3 envelope signature must be Ed25519");
7284
7509
  const envelope = signedAddressedEnvelope(unsigned, options.authority.ownerDid, envelopeSignature);
7285
7510
  shareEnvelopeV3Schema.parse(envelope);
7286
- const envelopeBytes = textEncoder.encode(canonicalize(envelope));
7511
+ const envelopeBytes = textEncoder2.encode(canonicalize(envelope));
7287
7512
  const envelopeKeyBytes = generateKey();
7288
7513
  const sealed = await seal(envelopeBytes, envelopeKeyBytes);
7289
7514
  const envelopeKey = toBase64Url(envelopeKeyBytes);
@@ -7363,7 +7588,7 @@ function rootAuthorizationBound(input) {
7363
7588
  nnc: "A".repeat(36),
7364
7589
  prf: []
7365
7590
  };
7366
- return `${toBase64Url(textEncoder.encode(canonicalize(header)))}.${toBase64Url(textEncoder.encode(canonicalize(payload)))}.${"A".repeat(86)}`;
7591
+ return `${toBase64Url(textEncoder2.encode(canonicalize(header)))}.${toBase64Url(textEncoder2.encode(canonicalize(payload)))}.${"A".repeat(86)}`;
7367
7592
  }
7368
7593
  async function sealedBodyUpperBound(options) {
7369
7594
  const plan = addressedPlan(options);
@@ -7411,7 +7636,7 @@ async function sealedBodyUpperBound(options) {
7411
7636
  expiry: plan.expiry
7412
7637
  });
7413
7638
  const envelope = signedAddressedEnvelope(unsigned, options.ownerDid, signature);
7414
- return (await seal(textEncoder.encode(canonicalize(envelope)), generateKey())).blob.length;
7639
+ return (await seal(textEncoder2.encode(canonicalize(envelope)), generateKey())).blob.length;
7415
7640
  }
7416
7641
  async function assertSealedBodyFits(options) {
7417
7642
  if (await sealedBodyUpperBound(options) > await linkBodyLimit()) throw new SharePublishError("max-bytes-exceeded", ADDRESSED_SHARE_TOO_LARGE_MESSAGE);
@@ -7421,12 +7646,15 @@ async function addressedShareBodyUpperBound(input) {
7421
7646
  const deliveryEmail = input.deliveryEmail ?? (target.kind === "email" && isEnvelopeDeliveryEmail(target.address) ? target.address : void 0);
7422
7647
  const artifactStorage = "artifactId" in input.storage ? input.storage : void 0;
7423
7648
  const path = "path" in input.storage ? input.storage.path : `${ARTIFACT_ROOT}/${input.storage.artifactId}/versions/${Number.MAX_SAFE_INTEGER}/${input.storage.storageName}`;
7649
+ const keyPath = pathBoundKeyPath(input.shareId);
7650
+ assertEncryptionNetwork(input.encryptionNetwork);
7651
+ if (input.encryptionKeyPath !== void 0 && input.encryptionKeyPath !== keyPath) throw new AddressedContentSourceError("key-path-mismatch", "addressed content source key path must be share/<shareId> of this share");
7424
7652
  const contentSource = {
7425
7653
  shareId: input.shareId,
7426
7654
  kvResource: `${input.spaceId}/kv/${path}`,
7427
7655
  selector: input.resource.kind,
7428
7656
  encryptionNetwork: input.encryptionNetwork,
7429
- ...input.encryptionKeyPath === void 0 ? {} : { encryptionKeyPath: input.encryptionKeyPath },
7657
+ encryptionKeyPath: keyPath,
7430
7658
  encryptedSymmetricKeyDigestHex: "f".repeat(64),
7431
7659
  keyVersion: Number.MAX_SAFE_INTEGER,
7432
7660
  mode: "immutable",
@@ -7466,13 +7694,13 @@ async function assertAddressedShareFits(input) {
7466
7694
  }
7467
7695
 
7468
7696
  // src/cache.ts
7469
- var import_sha2563 = require("@noble/hashes/sha256");
7697
+ var import_sha2564 = require("@noble/hashes/sha256");
7470
7698
  function cacheKey(key) {
7471
7699
  if (!key.cid || !key.expiresAt) throw new Error("share cache keys require CID and expiry");
7472
7700
  return `${key.cid}\0${key.expiresAt}`;
7473
7701
  }
7474
7702
  function digest(bytes3) {
7475
- return (0, import_sha2563.sha256)(bytes3);
7703
+ return (0, import_sha2564.sha256)(bytes3);
7476
7704
  }
7477
7705
  function equalBytes(left, right) {
7478
7706
  if (left.byteLength !== right.byteLength) return false;
@@ -7528,7 +7756,7 @@ var MemoryShareCache = class {
7528
7756
 
7529
7757
  // src/owner-policy.ts
7530
7758
  var import_ed255194 = require("@noble/curves/ed25519");
7531
- var import_sha2564 = require("@noble/hashes/sha256");
7759
+ var import_sha2565 = require("@noble/hashes/sha256");
7532
7760
 
7533
7761
  // ../../node_modules/multiformats/dist/src/bases/base32.js
7534
7762
  var base322 = rfc46482({
@@ -8082,10 +8310,10 @@ function fromB64(value) {
8082
8310
  throw new Error("base64url decoding is unavailable");
8083
8311
  }
8084
8312
  function cid(bytesValue) {
8085
- return CID2.createV1(code2, create2(SHA256_CODE2, (0, import_sha2564.sha256)(bytesValue))).toString(base322.encoder);
8313
+ return CID2.createV1(code2, create2(SHA256_CODE2, (0, import_sha2565.sha256)(bytesValue))).toString(base322.encoder);
8086
8314
  }
8087
8315
  function digest2(bytesValue) {
8088
- return b64((0, import_sha2564.sha256)(bytesValue));
8316
+ return b64((0, import_sha2565.sha256)(bytesValue));
8089
8317
  }
8090
8318
  function didKeyFromEd25519PublicKey2(publicKey) {
8091
8319
  if (publicKey.length !== 32) throw new Error("share key public key must be 32 bytes");
@@ -8757,7 +8985,7 @@ async function showShare(input) {
8757
8985
 
8758
8986
  // src/recipient.ts
8759
8987
  var import_ed255195 = require("@noble/curves/ed25519");
8760
- var import_sha2565 = require("@noble/hashes/sha256");
8988
+ var import_sha2566 = require("@noble/hashes/sha256");
8761
8989
 
8762
8990
  // src/protocol.ts
8763
8991
  var SHARE_V2_PROTOCOL = Object.freeze({
@@ -8925,12 +9153,12 @@ function requestedSessionExpiry(expiry) {
8925
9153
  if (!Number.isFinite(seconds) || seconds <= Math.floor(Date.now() / 1e3) + 60) return void 0;
8926
9154
  return new Date(seconds * 1e3).toISOString().replace(/\.\d{3}Z$/, "Z");
8927
9155
  }
8928
- function hex3(value) {
9156
+ function hex4(value) {
8929
9157
  return [...value].map((byte) => byte.toString(16).padStart(2, "0")).join("");
8930
9158
  }
8931
9159
  function matchesInitialCiphertextDigest(bytes3, expected) {
8932
9160
  if (typeof expected !== "string" || !LOWER_SHA256_HEX.test(expected)) return false;
8933
- const actual = (0, import_sha2565.sha256)(bytes3);
9161
+ const actual = (0, import_sha2566.sha256)(bytes3);
8934
9162
  let mismatch = 0;
8935
9163
  for (let index = 0; index < actual.length; index += 1) {
8936
9164
  mismatch |= actual[index] ^ Number.parseInt(expected.slice(index * 2, index * 2 + 2), 16);
@@ -8938,10 +9166,10 @@ function matchesInitialCiphertextDigest(bytes3, expected) {
8938
9166
  return mismatch === 0;
8939
9167
  }
8940
9168
  function canonicalHashHex(value) {
8941
- return hex3((0, import_sha2565.sha256)(new TextEncoder().encode(canonicalize(value))));
9169
+ return hex4((0, import_sha2566.sha256)(new TextEncoder().encode(canonicalize(value))));
8942
9170
  }
8943
9171
  function registeredWrappedKeyDigest(encryptedSymmetricKey, pathBound) {
8944
- const rawDigest = hex3((0, import_sha2565.sha256)(fromBase64(encryptedSymmetricKey, "v3 encrypted symmetric key")));
9172
+ const rawDigest = hex4((0, import_sha2566.sha256)(fromBase64(encryptedSymmetricKey, "v3 encrypted symmetric key")));
8945
9173
  return pathBound ? rawDigest : canonicalHashHex(encryptedSymmetricKey);
8946
9174
  }
8947
9175
  async function aesGcmDecrypt(key, blob, aad) {
@@ -9110,7 +9338,7 @@ var ShareRecipientClient = class {
9110
9338
  const receiverPublicKey = toBase64(import_ed255195.x25519.getPublicKey(receiverPrivateKey));
9111
9339
  const receiverPublicKeyHash = canonicalHashHex(receiverPublicKey);
9112
9340
  const body = { type: "tinycloud.encryption.decrypt/v1", targetNode: this.v3NodeAudience, networkId: encrypted.networkId, ...encrypted.keyPath === void 0 ? {} : { keyPath: encrypted.keyPath }, alg: encrypted.alg, keyVersion: encrypted.keyVersion, encryptedSymmetricKey: encrypted.encryptedSymmetricKey, encryptedSymmetricKeyHash: encrypted.encryptedSymmetricKeyHash, receiverPublicKey, receiverPublicKeyHash };
9113
- const bodyHash = hex3((0, import_sha2565.sha256)(new TextEncoder().encode(canonicalize(body))));
9341
+ const bodyHash = hex4((0, import_sha2566.sha256)(new TextEncoder().encode(canonicalize(body))));
9114
9342
  const session = verifyCompactUcanAuthorization(this.v3Authorization, this.session.sessionId);
9115
9343
  const now = Math.floor(Date.now() / 1e3);
9116
9344
  const decryptResource = encrypted.keyPath === void 0 ? encrypted.networkId : `${encrypted.networkId}/${encrypted.keyPath}`;
@@ -9131,7 +9359,7 @@ var ShareRecipientClient = class {
9131
9359
  if (!response.ok) throw await recipientHttpError(response, "v3 decrypt invocation rejected");
9132
9360
  const value = object3(await response.json(), "v3 decrypt response");
9133
9361
  const allowed = ["type", "targetNode", "networkId", "invocationCid", "encryptedSymmetricKeyHash", "receiverPublicKeyHash", "wrappedKey", "alg", "keyVersion", "requestHash", "nodeId", "nodeSignature"];
9134
- if (Object.keys(value).length !== allowed.length || Object.keys(value).some((key) => !allowed.includes(key)) || value.type !== "tinycloud.encryption.decrypt-result/v1" || value.targetNode !== body.targetNode || value.nodeId !== body.targetNode || value.networkId !== body.networkId || value.invocationCid !== invocation.cid || value.encryptedSymmetricKeyHash !== body.encryptedSymmetricKeyHash || value.receiverPublicKeyHash !== receiverPublicKeyHash || value.alg !== body.alg || value.keyVersion !== body.keyVersion || value.requestHash !== hex3((0, import_sha2565.sha256)(new TextEncoder().encode(`${invocation.cid}${bodyHash}`))) || typeof value.wrappedKey !== "string" || typeof value.nodeSignature !== "string") throw new Error("v3 decrypt response binding is invalid");
9362
+ if (Object.keys(value).length !== allowed.length || Object.keys(value).some((key) => !allowed.includes(key)) || value.type !== "tinycloud.encryption.decrypt-result/v1" || value.targetNode !== body.targetNode || value.nodeId !== body.targetNode || value.networkId !== body.networkId || value.invocationCid !== invocation.cid || value.encryptedSymmetricKeyHash !== body.encryptedSymmetricKeyHash || value.receiverPublicKeyHash !== receiverPublicKeyHash || value.alg !== body.alg || value.keyVersion !== body.keyVersion || value.requestHash !== hex4((0, import_sha2566.sha256)(new TextEncoder().encode(`${invocation.cid}${bodyHash}`))) || typeof value.wrappedKey !== "string" || typeof value.nodeSignature !== "string") throw new Error("v3 decrypt response binding is invalid");
9135
9363
  const unsigned = { ...value };
9136
9364
  delete unsigned.nodeSignature;
9137
9365
  const signature = fromBase64(value.nodeSignature, "v3 decrypt response signature");
@@ -9297,6 +9525,7 @@ async function openNativeShare(sharing, link) {
9297
9525
  // Annotate the CommonJS export names for ESM import in node:
9298
9526
  0 && (module.exports = {
9299
9527
  ADDRESSED_SHARE_TOO_LARGE_MESSAGE,
9528
+ AddressedContentSourceError,
9300
9529
  AddressedShareOverLimitError,
9301
9530
  ArtifactPinError,
9302
9531
  CredentialInvitationError,
@@ -9325,8 +9554,10 @@ async function openNativeShare(sharing, link) {
9325
9554
  artifactBindingView,
9326
9555
  assertAddressedShareFits,
9327
9556
  assertArtifactBinding,
9557
+ assertPathBoundContentSource,
9328
9558
  authorizationMethodForTarget,
9329
9559
  authorizeShare,
9560
+ bindPathBoundContentSource,
9330
9561
  canonicalOwnerSharePolicy,
9331
9562
  canonicalShareFilename,
9332
9563
  canonicalize,
@@ -9338,7 +9569,9 @@ async function openNativeShare(sharing, link) {
9338
9569
  createNativeShare,
9339
9570
  createPolicyEnforcementDelegation,
9340
9571
  createShareV2HolderBindingArtifact,
9572
+ defaultEncryptionNetworkForOwner,
9341
9573
  deliverCredentialInvitation,
9574
+ encryptAddressedShareContent,
9342
9575
  fromBase64Url,
9343
9576
  hasUnsafeFilenameCodePoint,
9344
9577
  historyRecordForPublishedShare,
@@ -9349,6 +9582,10 @@ async function openNativeShare(sharing, link) {
9349
9582
  openNativeShare,
9350
9583
  parseAddressedEnvelope,
9351
9584
  parseNativeShareUrl,
9585
+ pathBoundKeyPath,
9586
+ pathBoundSessionPermissions,
9587
+ pathBoundStoredBytes,
9588
+ planPathBoundShare,
9352
9589
  prepareAddressedShare,
9353
9590
  publishAddressedShare,
9354
9591
  publishPolicyShare,
@@ -9368,6 +9605,7 @@ async function openNativeShare(sharing, link) {
9368
9605
  toShareErrorInfo,
9369
9606
  validateOwnerSharePolicyRegistration,
9370
9607
  validateOwnerSharePolicyRegistrationBytes,
9371
- verifyArtifactShare
9608
+ verifyArtifactShare,
9609
+ wrappedKeyDigestHex
9372
9610
  });
9373
9611
  //# sourceMappingURL=index.cjs.map