@tinycloud/share-sdk 1.3.0 → 1.4.0-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/README.md +6 -0
- package/dist/{addressed-publish-Db-6rqkA.d.cts → addressed-publish-BP6nsgRq.d.cts} +58 -2
- package/dist/{addressed-publish-CAdGCqiX.d.ts → addressed-publish-CpkwV-Au.d.ts} +58 -2
- package/dist/artifact.cjs +2 -2
- package/dist/artifact.cjs.map +1 -1
- package/dist/artifact.js +2 -2
- package/dist/artifact.js.map +1 -1
- package/dist/{history-ZJFHV-IU.d.cts → history-Bg25JIsi.d.cts} +1 -1
- package/dist/{history-q0ALXTv7.d.ts → history-kwJxrZgq.d.ts} +1 -1
- package/dist/index.cjs +304 -154
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +290 -154
- package/dist/index.js.map +1 -1
- package/dist/{owner-policy-CRFeEC98.d.cts → owner-policy-aPmXIR3e.d.cts} +1 -1
- package/dist/{owner-policy-CRFeEC98.d.ts → owner-policy-aPmXIR3e.d.ts} +1 -1
- package/dist/share-index.cjs +47 -87
- package/dist/share-index.cjs.map +1 -1
- package/dist/share-index.d.cts +28 -30
- package/dist/share-index.d.ts +28 -30
- package/dist/share-index.js +46 -86
- package/dist/share-index.js.map +1 -1
- package/dist/share-root.cjs +2 -2
- package/dist/share-root.cjs.map +1 -1
- package/dist/share-root.d.cts +2 -2
- package/dist/share-root.d.ts +2 -2
- package/dist/share-root.js +2 -2
- package/dist/share-root.js.map +1 -1
- package/dist/{web-recipient-entry-D9IJEyRA.d.cts → web-recipient-entry-CiUzdSQs.d.cts} +9 -1
- package/dist/{web-recipient-entry-CKA_vCi5.d.ts → web-recipient-entry-DVyTQBl0.d.ts} +9 -1
- package/dist/web-recipient.cjs +76 -105
- package/dist/web-recipient.cjs.map +1 -1
- package/dist/web-recipient.d.cts +1 -1
- package/dist/web-recipient.d.ts +1 -1
- package/dist/web-recipient.js +66 -105
- package/dist/web-recipient.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export { D as DEFAULT_MAX_CONTENT_BLOB_BYTES, a as DEFAULT_MAX_SEALED_BLOB_BYTES, S as SHARE_RESULT_VERSION, b as ShareErrorCode, c as ShareErrorInfo, d as ShareFetchOptions, e as ShareInspection, f as ShareMetadata, g as ShareNodeTrust, h as SharePolicyChallenge, i as SharePolicyDelegationLink, j as SharePolicySession, k as SharePresentationMaterial, l as ShareReceiveAuthorizationRequired, m as ShareReceiveError, n as ShareReceiveOutcome, o as ShareReceiveResult, p as ShareRecipientClient, q as ShareRecipientClientOptions, r as createAddressedAuthorization, s as inspectShare, t as receiveShare, u as toShareErrorInfo } from './web-recipient-entry-
|
|
2
|
-
export { C as CreateOwnerDelegationParams,
|
|
1
|
+
export { D as DEFAULT_MAX_CONTENT_BLOB_BYTES, a as DEFAULT_MAX_SEALED_BLOB_BYTES, S as SHARE_RESULT_VERSION, b as ShareErrorCode, c as ShareErrorInfo, d as ShareFetchOptions, e as ShareInspection, f as ShareMetadata, g as ShareNodeTrust, h as SharePolicyChallenge, i as SharePolicyDelegationLink, j as SharePolicySession, k as SharePresentationMaterial, l as ShareReceiveAuthorizationRequired, m as ShareReceiveError, n as ShareReceiveOutcome, o as ShareReceiveResult, p as ShareRecipientClient, q as ShareRecipientClientOptions, r as createAddressedAuthorization, s as inspectShare, t as receiveShare, u as toShareErrorInfo } from './web-recipient-entry-CiUzdSQs.cjs';
|
|
2
|
+
export { C as CreateOwnerDelegationParams, h as DEFAULT_SHARE_LIFETIME_MS, D as DelegatedShareKey, M as MAX_CONTENT_BYTES, i as OWNER_SHARE_REGISTRATION_DOMAIN, j as OwnerDelegationPermission, g as OwnerDelegationReceipt, O as OwnerShareAction, k as OwnerShareDecryption, a as OwnerShareMatcher, l as OwnerSharePolicyRegistration, b as OwnerSharePolicyRegistrationReceipt, m as OwnerSharePolicyV2, c as PublishedShare, P as PublishedShareDeliveryMaterial, n as PublishedShareMetadata, R as RegisterOwnerSharePolicyParams, o as SHARE_CONTENT_LIMIT, p as SHARE_PUBLISH_RESULT_VERSION, f as SharePublishError, q as SharePublishErrorCode, e as SharePublishOptions, d as SharePublishTarget, S as SignedDelegation, r as canonicalOwnerSharePolicy, s as computeOwnerShareRegistrationCid, t as createDelegatedShareKey, u as createPolicyEnforcementDelegation, v as redactPublishedShare, w as restoreDelegatedShareKey, x as validateOwnerSharePolicyRegistration, y as validateOwnerSharePolicyRegistrationBytes } from './owner-policy-aPmXIR3e.cjs';
|
|
3
3
|
import { ShareEnvelopeV2, ArtifactPin, UnsignedShareEnvelopeV3, ShareEnvelopeV3 } from '@tinycloud/share-envelope';
|
|
4
4
|
export { CheckBearerDelegationOptions, DelegationCheckResult, canonicalize, checkBearerDelegation, fromBase64Url, requiredResourceUri, resourceUriCovers, toBase64Url } from '@tinycloud/share-envelope';
|
|
5
|
-
import { T as TargetPublishOutcome, c as TargetPublishInput, S as ShareTarget } from './addressed-publish-
|
|
6
|
-
export { A as AddressedOwnerRootInput, a as AddressedOwnerRootReceipt,
|
|
7
|
-
import { S as SenderShareRecord, a as SenderShareRecordStorage } from './history-
|
|
8
|
-
export { E as EncryptedSenderShareHistory, b as EncryptedShareHistoryStorage, M as MemoryEncryptedShareHistoryStorage, c as MemorySenderShareKeyStorage, d as MemorySenderShareRecordStorage, e as SenderShareKeyStorage, f as SenderShareRecordProofs, g as SenderShareRevocationScope, h as SenderShareStore, i as historyRecordForPublishedShare } from './history-
|
|
5
|
+
import { T as TargetPublishOutcome, c as TargetPublishInput, S as ShareTarget } from './addressed-publish-BP6nsgRq.cjs';
|
|
6
|
+
export { d as ADDRESSED_SHARE_TOO_LARGE_MESSAGE, A as AddressedOwnerRootInput, a as AddressedOwnerRootReceipt, e as AddressedPolicyRegistrationInput, f as AddressedPolicyRegistrationReceipt, b as AddressedPublishAuthority, g as AddressedShareBoundInput, h as AddressedShareOverLimitError, i as AddressedSharePublishOptions, j as AddressedShareRequest, k as AddressedShareWrites, P as PreparedAddressedShare, l as TargetPublishAdapter, m as addressedCredentialRequirement, n as addressedShareBodyUpperBound, o as assertAddressedShareFits, p as normalizeShareTarget, q as prepareAddressedShare, r as publishAddressedShare, s as publishTargetShare, t as targetAuthorizationMethod } from './addressed-publish-BP6nsgRq.cjs';
|
|
7
|
+
import { S as SenderShareRecord, a as SenderShareRecordStorage } from './history-Bg25JIsi.cjs';
|
|
8
|
+
export { E as EncryptedSenderShareHistory, b as EncryptedShareHistoryStorage, M as MemoryEncryptedShareHistoryStorage, c as MemorySenderShareKeyStorage, d as MemorySenderShareRecordStorage, e as SenderShareKeyStorage, f as SenderShareRecordProofs, g as SenderShareRevocationScope, h as SenderShareStore, i as historyRecordForPublishedShare } from './history-Bg25JIsi.cjs';
|
|
9
9
|
import { b as ShareAuthorizationResult, c as ShareAuthorizationAdapter } from './authorization-CmP1skO8.cjs';
|
|
10
10
|
export { d as ShareAuthorizationDenied, a as ShareAuthorizationMethod, e as ShareAuthorizationReady, S as ShareAuthorizationRequired, f as ShareAuthorizedContent, g as authorizationMethodForTarget, h as authorizeShare } from './authorization-CmP1skO8.cjs';
|
|
11
11
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export { D as DEFAULT_MAX_CONTENT_BLOB_BYTES, a as DEFAULT_MAX_SEALED_BLOB_BYTES, S as SHARE_RESULT_VERSION, b as ShareErrorCode, c as ShareErrorInfo, d as ShareFetchOptions, e as ShareInspection, f as ShareMetadata, g as ShareNodeTrust, h as SharePolicyChallenge, i as SharePolicyDelegationLink, j as SharePolicySession, k as SharePresentationMaterial, l as ShareReceiveAuthorizationRequired, m as ShareReceiveError, n as ShareReceiveOutcome, o as ShareReceiveResult, p as ShareRecipientClient, q as ShareRecipientClientOptions, r as createAddressedAuthorization, s as inspectShare, t as receiveShare, u as toShareErrorInfo } from './web-recipient-entry-
|
|
2
|
-
export { C as CreateOwnerDelegationParams,
|
|
1
|
+
export { D as DEFAULT_MAX_CONTENT_BLOB_BYTES, a as DEFAULT_MAX_SEALED_BLOB_BYTES, S as SHARE_RESULT_VERSION, b as ShareErrorCode, c as ShareErrorInfo, d as ShareFetchOptions, e as ShareInspection, f as ShareMetadata, g as ShareNodeTrust, h as SharePolicyChallenge, i as SharePolicyDelegationLink, j as SharePolicySession, k as SharePresentationMaterial, l as ShareReceiveAuthorizationRequired, m as ShareReceiveError, n as ShareReceiveOutcome, o as ShareReceiveResult, p as ShareRecipientClient, q as ShareRecipientClientOptions, r as createAddressedAuthorization, s as inspectShare, t as receiveShare, u as toShareErrorInfo } from './web-recipient-entry-DVyTQBl0.js';
|
|
2
|
+
export { C as CreateOwnerDelegationParams, h as DEFAULT_SHARE_LIFETIME_MS, D as DelegatedShareKey, M as MAX_CONTENT_BYTES, i as OWNER_SHARE_REGISTRATION_DOMAIN, j as OwnerDelegationPermission, g as OwnerDelegationReceipt, O as OwnerShareAction, k as OwnerShareDecryption, a as OwnerShareMatcher, l as OwnerSharePolicyRegistration, b as OwnerSharePolicyRegistrationReceipt, m as OwnerSharePolicyV2, c as PublishedShare, P as PublishedShareDeliveryMaterial, n as PublishedShareMetadata, R as RegisterOwnerSharePolicyParams, o as SHARE_CONTENT_LIMIT, p as SHARE_PUBLISH_RESULT_VERSION, f as SharePublishError, q as SharePublishErrorCode, e as SharePublishOptions, d as SharePublishTarget, S as SignedDelegation, r as canonicalOwnerSharePolicy, s as computeOwnerShareRegistrationCid, t as createDelegatedShareKey, u as createPolicyEnforcementDelegation, v as redactPublishedShare, w as restoreDelegatedShareKey, x as validateOwnerSharePolicyRegistration, y as validateOwnerSharePolicyRegistrationBytes } from './owner-policy-aPmXIR3e.js';
|
|
3
3
|
import { ShareEnvelopeV2, ArtifactPin, UnsignedShareEnvelopeV3, ShareEnvelopeV3 } from '@tinycloud/share-envelope';
|
|
4
4
|
export { CheckBearerDelegationOptions, DelegationCheckResult, canonicalize, checkBearerDelegation, fromBase64Url, requiredResourceUri, resourceUriCovers, toBase64Url } from '@tinycloud/share-envelope';
|
|
5
|
-
import { T as TargetPublishOutcome, c as TargetPublishInput, S as ShareTarget } from './addressed-publish-
|
|
6
|
-
export { A as AddressedOwnerRootInput, a as AddressedOwnerRootReceipt,
|
|
7
|
-
import { S as SenderShareRecord, a as SenderShareRecordStorage } from './history-
|
|
8
|
-
export { E as EncryptedSenderShareHistory, b as EncryptedShareHistoryStorage, M as MemoryEncryptedShareHistoryStorage, c as MemorySenderShareKeyStorage, d as MemorySenderShareRecordStorage, e as SenderShareKeyStorage, f as SenderShareRecordProofs, g as SenderShareRevocationScope, h as SenderShareStore, i as historyRecordForPublishedShare } from './history-
|
|
5
|
+
import { T as TargetPublishOutcome, c as TargetPublishInput, S as ShareTarget } from './addressed-publish-CpkwV-Au.js';
|
|
6
|
+
export { d as ADDRESSED_SHARE_TOO_LARGE_MESSAGE, A as AddressedOwnerRootInput, a as AddressedOwnerRootReceipt, e as AddressedPolicyRegistrationInput, f as AddressedPolicyRegistrationReceipt, b as AddressedPublishAuthority, g as AddressedShareBoundInput, h as AddressedShareOverLimitError, i as AddressedSharePublishOptions, j as AddressedShareRequest, k as AddressedShareWrites, P as PreparedAddressedShare, l as TargetPublishAdapter, m as addressedCredentialRequirement, n as addressedShareBodyUpperBound, o as assertAddressedShareFits, p as normalizeShareTarget, q as prepareAddressedShare, r as publishAddressedShare, s as publishTargetShare, t as targetAuthorizationMethod } from './addressed-publish-CpkwV-Au.js';
|
|
7
|
+
import { S as SenderShareRecord, a as SenderShareRecordStorage } from './history-kwJxrZgq.js';
|
|
8
|
+
export { E as EncryptedSenderShareHistory, b as EncryptedShareHistoryStorage, M as MemoryEncryptedShareHistoryStorage, c as MemorySenderShareKeyStorage, d as MemorySenderShareRecordStorage, e as SenderShareKeyStorage, f as SenderShareRecordProofs, g as SenderShareRevocationScope, h as SenderShareStore, i as historyRecordForPublishedShare } from './history-kwJxrZgq.js';
|
|
9
9
|
import { b as ShareAuthorizationResult, c as ShareAuthorizationAdapter } from './authorization-CmP1skO8.js';
|
|
10
10
|
export { d as ShareAuthorizationDenied, a as ShareAuthorizationMethod, e as ShareAuthorizationReady, S as ShareAuthorizationRequired, f as ShareAuthorizedContent, g as authorizationMethodForTarget, h as authorizeShare } from './authorization-CmP1skO8.js';
|
|
11
11
|
|
package/dist/index.js
CHANGED
|
@@ -4934,7 +4934,8 @@ function isCanonicalRawCid(cidString) {
|
|
|
4934
4934
|
} catch {
|
|
4935
4935
|
return false;
|
|
4936
4936
|
}
|
|
4937
|
-
return cid2.version === 1 && cid2.code === code && cid2.multihash.code === SHA256_CODE &&
|
|
4937
|
+
return cid2.version === 1 && cid2.code === code && cid2.multihash.code === SHA256_CODE && // `toString` of a parsed CID gives back the string it was parsed from; a fresh CID is encoded again.
|
|
4938
|
+
CID.createV1(cid2.code, cid2.multihash).toString() === cidString;
|
|
4938
4939
|
}
|
|
4939
4940
|
var base64 = rfc4648({
|
|
4940
4941
|
prefix: "m",
|
|
@@ -5596,7 +5597,6 @@ var SEALED_BLOB_VERSION = 1;
|
|
|
5596
5597
|
var AAD = utf8Bytes(ENVELOPE_AAD_LABEL);
|
|
5597
5598
|
var KEY_LENGTH = 32;
|
|
5598
5599
|
var NONCE_LENGTH = 12;
|
|
5599
|
-
var TAG_LENGTH = 16;
|
|
5600
5600
|
var HEADER_LENGTH = 1;
|
|
5601
5601
|
function assertKey(key32) {
|
|
5602
5602
|
if (key32.length !== KEY_LENGTH) {
|
|
@@ -5624,17 +5624,6 @@ async function seal(plaintextBytes, key32) {
|
|
|
5624
5624
|
blob.set(ciphertext, HEADER_LENGTH + nonce.length);
|
|
5625
5625
|
return { blob, cid: await computeCid(blob) };
|
|
5626
5626
|
}
|
|
5627
|
-
async function open(blob, key32) {
|
|
5628
|
-
if (blob.length < HEADER_LENGTH + NONCE_LENGTH + TAG_LENGTH) {
|
|
5629
|
-
throw new TypeError(`sealed blob too short: ${blob.length} bytes`);
|
|
5630
|
-
}
|
|
5631
|
-
if (blob[0] !== SEALED_BLOB_VERSION) {
|
|
5632
|
-
throw new TypeError(`unknown sealed blob version: ${blob[0]}`);
|
|
5633
|
-
}
|
|
5634
|
-
const nonce = blob.subarray(HEADER_LENGTH, HEADER_LENGTH + NONCE_LENGTH);
|
|
5635
|
-
const ciphertext = blob.subarray(HEADER_LENGTH + NONCE_LENGTH);
|
|
5636
|
-
return decryptEnvelope(nonce, ciphertext, key32);
|
|
5637
|
-
}
|
|
5638
5627
|
async function encryptEnvelope(plaintextBytes, key32) {
|
|
5639
5628
|
const key = await importAesKey(key32, "encrypt");
|
|
5640
5629
|
const nonce = globalThis.crypto.getRandomValues(new Uint8Array(NONCE_LENGTH));
|
|
@@ -5647,19 +5636,6 @@ async function encryptEnvelope(plaintextBytes, key32) {
|
|
|
5647
5636
|
);
|
|
5648
5637
|
return { nonce, ciphertext };
|
|
5649
5638
|
}
|
|
5650
|
-
async function decryptEnvelope(nonce, ciphertext, key32) {
|
|
5651
|
-
if (nonce.length !== NONCE_LENGTH) {
|
|
5652
|
-
throw new TypeError(`nonce must be ${NONCE_LENGTH} bytes, got ${nonce.length}`);
|
|
5653
|
-
}
|
|
5654
|
-
const key = await importAesKey(key32, "decrypt");
|
|
5655
|
-
return new Uint8Array(
|
|
5656
|
-
await globalThis.crypto.subtle.decrypt(
|
|
5657
|
-
{ name: "AES-GCM", iv: nonce, additionalData: AAD },
|
|
5658
|
-
key,
|
|
5659
|
-
ciphertext
|
|
5660
|
-
)
|
|
5661
|
-
);
|
|
5662
|
-
}
|
|
5663
5639
|
function isPlainRecord(value) {
|
|
5664
5640
|
const proto = Object.getPrototypeOf(value);
|
|
5665
5641
|
return proto === Object.prototype || proto === null;
|
|
@@ -5906,71 +5882,6 @@ function base32Lower(bytes3) {
|
|
|
5906
5882
|
if (bits > 0) output += alphabet[buffer << 5 - bits & 31];
|
|
5907
5883
|
return output;
|
|
5908
5884
|
}
|
|
5909
|
-
var KEY_LENGTH2 = 32;
|
|
5910
|
-
var MAX_INLINE_BYTES = 256 * 1024;
|
|
5911
|
-
function assertCanonicalCid(cidString) {
|
|
5912
|
-
const cid2 = CID.parse(cidString);
|
|
5913
|
-
if (cid2.version !== 1 || cid2.code !== code || cid2.multihash.code !== 18 || // sha2-256 (0x12) only, at the link layer too
|
|
5914
|
-
cid2.toString() !== cidString) {
|
|
5915
|
-
throw new TypeError(`not a canonical CIDv1 raw sha2-256 base32 CID: ${cidString}`);
|
|
5916
|
-
}
|
|
5917
|
-
}
|
|
5918
|
-
async function encodeSealedInlineShareUrl(parts) {
|
|
5919
|
-
if (!isCanonicalHttpsOrigin(parts.origin)) throw new TypeError("origin must be a canonical https origin");
|
|
5920
|
-
if (parts.ciphertext.byteLength === 0 || parts.ciphertext.byteLength > MAX_INLINE_BYTES) throw new RangeError("inline ciphertext is outside the allowed size");
|
|
5921
|
-
if (parts.key32.byteLength !== KEY_LENGTH2) throw new TypeError("inline key must be 32 bytes");
|
|
5922
|
-
const ciphertextCid = await computeCid(parts.ciphertext);
|
|
5923
|
-
const payload = canonicalize({
|
|
5924
|
-
v: 2,
|
|
5925
|
-
c: toBase64Url(parts.ciphertext),
|
|
5926
|
-
cid: ciphertextCid,
|
|
5927
|
-
k: toBase64Url(parts.key32)
|
|
5928
|
-
});
|
|
5929
|
-
const payloadBytes = new TextEncoder().encode(payload);
|
|
5930
|
-
if (payloadBytes.byteLength > MAX_INLINE_BYTES * 2) throw new RangeError("inline URL is too large");
|
|
5931
|
-
return `${parts.origin}/s/inline#v=2&p=${toBase64Url(payloadBytes)}`;
|
|
5932
|
-
}
|
|
5933
|
-
async function parseSealedInlineShareUrl(url, options = {}) {
|
|
5934
|
-
const parsed = new URL(url);
|
|
5935
|
-
if (parsed.protocol !== "https:" || parsed.username !== "" || parsed.password !== "") throw new TypeError("sealed inline share URL must be canonical HTTPS without userinfo");
|
|
5936
|
-
if (!isCanonicalHttpsOrigin(parsed.origin) || options.expectedOrigin !== void 0 && parsed.origin !== options.expectedOrigin) throw new TypeError("sealed inline share URL origin is not trusted");
|
|
5937
|
-
if (parsed.pathname !== "/s/inline" || parsed.search !== "") throw new TypeError("not a Node sealed-inline share URL");
|
|
5938
|
-
if (url !== `${parsed.origin}/s/inline${parsed.hash}`) throw new TypeError("sealed inline share URL is not lexically canonical");
|
|
5939
|
-
const prefix = "#v=2&p=";
|
|
5940
|
-
if (!parsed.hash.startsWith(prefix)) throw new TypeError("sealed inline URL is missing its canonical fragment");
|
|
5941
|
-
const encoded = parsed.hash.slice(prefix.length);
|
|
5942
|
-
if (encoded.length === 0 || parsed.hash !== `${prefix}${encoded}`) throw new TypeError("sealed inline URL fragment is not canonical");
|
|
5943
|
-
let payloadBytes;
|
|
5944
|
-
try {
|
|
5945
|
-
payloadBytes = fromBase64Url(encoded);
|
|
5946
|
-
} catch {
|
|
5947
|
-
throw new TypeError("sealed inline payload is not canonical base64url");
|
|
5948
|
-
}
|
|
5949
|
-
if (payloadBytes.byteLength === 0 || payloadBytes.byteLength > MAX_INLINE_BYTES * 2) throw new TypeError("sealed inline payload is too large");
|
|
5950
|
-
const payloadText = new TextDecoder("utf-8", { fatal: true }).decode(payloadBytes);
|
|
5951
|
-
let value;
|
|
5952
|
-
try {
|
|
5953
|
-
value = JSON.parse(payloadText);
|
|
5954
|
-
} catch {
|
|
5955
|
-
throw new TypeError("sealed inline payload is not valid JSON");
|
|
5956
|
-
}
|
|
5957
|
-
if (typeof value !== "object" || value === null || Array.isArray(value) || canonicalize(value) !== payloadText) throw new TypeError("sealed inline payload is not canonical JSON");
|
|
5958
|
-
const record = value;
|
|
5959
|
-
if (Object.keys(record).length !== 4 || record.v !== 2 || typeof record.c !== "string" || typeof record.cid !== "string" || typeof record.k !== "string") throw new TypeError("sealed inline payload has invalid fields");
|
|
5960
|
-
let ciphertext;
|
|
5961
|
-
let key32;
|
|
5962
|
-
try {
|
|
5963
|
-
ciphertext = fromBase64Url(record.c);
|
|
5964
|
-
key32 = fromBase64Url(record.k);
|
|
5965
|
-
} catch {
|
|
5966
|
-
throw new TypeError("sealed inline payload has invalid base64url material");
|
|
5967
|
-
}
|
|
5968
|
-
if (ciphertext.byteLength === 0 || ciphertext.byteLength > MAX_INLINE_BYTES) throw new TypeError("sealed inline ciphertext is outside the allowed size");
|
|
5969
|
-
if (key32.byteLength !== KEY_LENGTH2) throw new TypeError("sealed inline key must be 32 bytes");
|
|
5970
|
-
assertCanonicalCid(record.cid);
|
|
5971
|
-
if (await computeCid(ciphertext) !== record.cid) throw new TypeError("sealed inline ciphertext does not match its CID");
|
|
5972
|
-
return { kind: "inline", ciphertextCid: record.cid, ciphertext, key32 };
|
|
5973
|
-
}
|
|
5974
5885
|
|
|
5975
5886
|
// src/artifact-core.ts
|
|
5976
5887
|
var ARTIFACT_ROOT = "artifacts";
|
|
@@ -6090,26 +6001,80 @@ function metadataFor(envelope, origin) {
|
|
|
6090
6001
|
...envelope.artifactPin === void 0 ? {} : { artifact: { id: envelope.artifactPin.artifactId, version: envelope.artifactPin.version } }
|
|
6091
6002
|
};
|
|
6092
6003
|
}
|
|
6004
|
+
function receiveErrorFor(error) {
|
|
6005
|
+
switch (error.code) {
|
|
6006
|
+
case "origin_not_trusted":
|
|
6007
|
+
return new ShareReceiveError("origin-mismatch", "share link origin is not trusted");
|
|
6008
|
+
case "body_over_cap":
|
|
6009
|
+
case "response_too_large":
|
|
6010
|
+
return new ShareReceiveError("max-bytes-exceeded", "sealed policy envelope exceeds the size limit");
|
|
6011
|
+
case "body_hash_mismatch":
|
|
6012
|
+
case "link_cid_mismatch":
|
|
6013
|
+
return new ShareReceiveError("cid-mismatch", "sealed envelope bytes do not match the link CID");
|
|
6014
|
+
case "body_open_failed":
|
|
6015
|
+
return new ShareReceiveError("decrypt-failed", "share envelope could not be opened");
|
|
6016
|
+
case "gone":
|
|
6017
|
+
case "expired":
|
|
6018
|
+
return new ShareReceiveError("expired", "share link has expired, was deleted, or never existed");
|
|
6019
|
+
case "bad_signature":
|
|
6020
|
+
case "issuer_binding_mismatch":
|
|
6021
|
+
return new ShareReceiveError("signature-invalid", "share link signature is invalid");
|
|
6022
|
+
case "service_refused":
|
|
6023
|
+
case "service_unavailable":
|
|
6024
|
+
case "invalid_response":
|
|
6025
|
+
return new ShareReceiveError("fetch-failed", "share link could not be fetched");
|
|
6026
|
+
case "not_a_url":
|
|
6027
|
+
case "not_https":
|
|
6028
|
+
case "userinfo":
|
|
6029
|
+
case "not_canonical":
|
|
6030
|
+
case "query_present":
|
|
6031
|
+
case "removed_version":
|
|
6032
|
+
case "path_grammar":
|
|
6033
|
+
case "fragment_grammar":
|
|
6034
|
+
case "key_noncanonical":
|
|
6035
|
+
case "cid_grammar":
|
|
6036
|
+
case "record_encoding":
|
|
6037
|
+
case "record_json":
|
|
6038
|
+
case "record_not_canonical":
|
|
6039
|
+
case "type_path_mismatch":
|
|
6040
|
+
case "full_non_share":
|
|
6041
|
+
return new ShareReceiveError("invalid-link", "share link format is invalid");
|
|
6042
|
+
default:
|
|
6043
|
+
return new ShareReceiveError("envelope-invalid", "share envelope is invalid");
|
|
6044
|
+
}
|
|
6045
|
+
}
|
|
6093
6046
|
async function resolvePolicyShare(link, options) {
|
|
6094
6047
|
options.signal?.throwIfAborted();
|
|
6095
6048
|
let url;
|
|
6096
|
-
let parsed;
|
|
6097
6049
|
try {
|
|
6098
6050
|
url = new URL(link);
|
|
6099
|
-
parsed = await parseSealedInlineShareUrl(link, { ...options.expectedOrigin === void 0 ? {} : { expectedOrigin: options.expectedOrigin } });
|
|
6100
6051
|
} catch {
|
|
6101
6052
|
throw new ShareReceiveError("invalid-link", "share link format is invalid");
|
|
6102
6053
|
}
|
|
6054
|
+
const links = await import("@tinycloud/share-envelope/links");
|
|
6055
|
+
let resolved;
|
|
6056
|
+
try {
|
|
6057
|
+
resolved = await links.resolveLink(link, {
|
|
6058
|
+
trustedOrigins: [options.expectedOrigin ?? url.origin],
|
|
6059
|
+
apiOrigin: options.apiOrigin ?? links.DEFAULT_LINKS_API_ORIGIN,
|
|
6060
|
+
...options.fetch === void 0 ? {} : { fetch: options.fetch },
|
|
6061
|
+
...options.signal === void 0 ? {} : { signal: options.signal },
|
|
6062
|
+
now: options.now?.() ?? Date.now()
|
|
6063
|
+
});
|
|
6064
|
+
} catch (error) {
|
|
6065
|
+
options.signal?.throwIfAborted();
|
|
6066
|
+
throw error instanceof links.LinkError ? receiveErrorFor(error) : error;
|
|
6067
|
+
}
|
|
6068
|
+
if (resolved.type !== "share") throw new ShareReceiveError("invalid-link", "share link is not a share");
|
|
6103
6069
|
const limit = options.maxSealedBlobBytes ?? DEFAULT_MAX_SEALED_BLOB_BYTES;
|
|
6104
|
-
if (!Number.isSafeInteger(limit) || limit <= 0 ||
|
|
6105
|
-
|
|
6070
|
+
if (!Number.isSafeInteger(limit) || limit <= 0 || resolved.body.byteLength > limit) throw new ShareReceiveError("max-bytes-exceeded", "sealed policy envelope exceeds the configured byte limit");
|
|
6071
|
+
const cid2 = resolved.header.bodyCid;
|
|
6106
6072
|
options.signal?.throwIfAborted();
|
|
6107
6073
|
let envelope;
|
|
6108
6074
|
try {
|
|
6109
|
-
const encoded = new TextDecoder("utf-8", { fatal: true }).decode(
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
envelope = shareEnvelopeV3Schema.parse(value);
|
|
6075
|
+
const encoded = new TextDecoder("utf-8", { fatal: true }).decode(resolved.plaintext);
|
|
6076
|
+
if (canonicalize(resolved.value) !== encoded) throw new Error("non-canonical envelope");
|
|
6077
|
+
envelope = shareEnvelopeV3Schema.parse(resolved.value);
|
|
6113
6078
|
} catch {
|
|
6114
6079
|
throw new ShareReceiveError("envelope-invalid", "share envelope is invalid");
|
|
6115
6080
|
}
|
|
@@ -6128,8 +6093,8 @@ async function resolvePolicyShare(link, options) {
|
|
|
6128
6093
|
const expiry = Date.parse(envelope.expiry);
|
|
6129
6094
|
if (!Number.isFinite(expiry)) throw new ShareReceiveError("envelope-invalid", "share expiry is invalid");
|
|
6130
6095
|
if (expiry <= (options.now?.() ?? Date.now())) throw new ShareReceiveError("expired", "share has expired", { expiresAt: envelope.expiry });
|
|
6131
|
-
options.onResolvedAddressedEnvelope?.(envelope,
|
|
6132
|
-
return { envelope, origin: url.origin, cid:
|
|
6096
|
+
options.onResolvedAddressedEnvelope?.(envelope, cid2);
|
|
6097
|
+
return { envelope, origin: url.origin, cid: cid2 };
|
|
6133
6098
|
}
|
|
6134
6099
|
async function inspectShare(link, options = {}) {
|
|
6135
6100
|
const resolved = await resolvePolicyShare(link, options);
|
|
@@ -6758,6 +6723,53 @@ async function createPolicy(options, capabilities) {
|
|
|
6758
6723
|
};
|
|
6759
6724
|
return { policy, policyCid: await computeCid(textEncoder.encode(canonicalize(policy))), policyDigestHex };
|
|
6760
6725
|
}
|
|
6726
|
+
function addressedPlan(options) {
|
|
6727
|
+
const capabilities = sortCanonical([
|
|
6728
|
+
{ kind: "kv", resource: options.contentSource.kvResource, selector: options.resource.kind, actions: [...options.policyActions] },
|
|
6729
|
+
{ kind: "encryption", resource: options.contentSource.encryptionNetwork, action: "tinycloud.encryption/decrypt" }
|
|
6730
|
+
]);
|
|
6731
|
+
return {
|
|
6732
|
+
expiry: rfc3339Seconds(options.expiresAt),
|
|
6733
|
+
capabilities,
|
|
6734
|
+
contentSourceDigestHex: digestHex(options.contentSource, CONTENT_SOURCE_V1_DOMAIN2),
|
|
6735
|
+
capabilityCeilingHashHex: digestHex(capabilities, POLICY_CAPABILITY_V1_DOMAIN2),
|
|
6736
|
+
nativeProjectionHashHex: digestHex(nativeProjection(capabilities), NATIVE_PROJECTION_V1_DOMAIN2)
|
|
6737
|
+
};
|
|
6738
|
+
}
|
|
6739
|
+
function unsignedAddressedEnvelope(input) {
|
|
6740
|
+
const { options } = input;
|
|
6741
|
+
return {
|
|
6742
|
+
version: 3,
|
|
6743
|
+
shareId: options.shareId,
|
|
6744
|
+
recipientMatcher: input.matcher,
|
|
6745
|
+
...options.deliveryEmail === void 0 ? {} : { deliveryEmail: options.deliveryEmail },
|
|
6746
|
+
actions: [...options.actions],
|
|
6747
|
+
resource: { ...options.resource },
|
|
6748
|
+
target: { origin: options.nodeOrigin, nodeAudience: input.attestedEnforcerBinding.enforcerDid, spaceId: options.spaceId },
|
|
6749
|
+
policy: input.policy,
|
|
6750
|
+
policyCid: input.policyCid,
|
|
6751
|
+
policyRoot: input.policyRoot,
|
|
6752
|
+
enforcementRoot: input.enforcementRoot,
|
|
6753
|
+
attestedEnforcerBinding: input.attestedEnforcerBinding,
|
|
6754
|
+
contentSource: options.contentSource,
|
|
6755
|
+
contentSourceDigestHex: input.contentSourceDigestHex,
|
|
6756
|
+
encryptionNetwork: options.contentSource.encryptionNetwork,
|
|
6757
|
+
expiry: input.expiry,
|
|
6758
|
+
display: { filename: options.filename },
|
|
6759
|
+
encrypted: true,
|
|
6760
|
+
metadata: {
|
|
6761
|
+
mediaType: options.mediaType,
|
|
6762
|
+
byteLength: options.byteLength,
|
|
6763
|
+
filename: options.filename,
|
|
6764
|
+
...options.mediaType.startsWith("text/") ? { encoding: "utf-8" } : {},
|
|
6765
|
+
...options.artifact === void 0 ? {} : { artifact: options.artifact }
|
|
6766
|
+
},
|
|
6767
|
+
...options.artifactPin === void 0 ? {} : { artifactPin: options.artifactPin }
|
|
6768
|
+
};
|
|
6769
|
+
}
|
|
6770
|
+
function signedAddressedEnvelope(unsigned, signerDid, signature) {
|
|
6771
|
+
return { ...unsigned, signature: { signerDid, algorithm: "Ed25519", value: toBase64Url(signature) } };
|
|
6772
|
+
}
|
|
6761
6773
|
function publicationResult(input) {
|
|
6762
6774
|
const result = {
|
|
6763
6775
|
protocol: "tinycloud-share",
|
|
@@ -6852,16 +6864,10 @@ async function publishAddressedShare(input) {
|
|
|
6852
6864
|
});
|
|
6853
6865
|
const options = { ...input, filename: canonicalShareFilename(input.filename) };
|
|
6854
6866
|
if (target.kind !== "recipientDid") assertMailboxCommitment(options.credentialRequirement, target);
|
|
6855
|
-
const expiry = rfc3339Seconds(options.expiresAt);
|
|
6856
6867
|
const matcher = targetMatcher(target);
|
|
6857
|
-
const capabilities =
|
|
6858
|
-
|
|
6859
|
-
{ kind: "encryption", resource: options.contentSource.encryptionNetwork, action: "tinycloud.encryption/decrypt" }
|
|
6860
|
-
]);
|
|
6868
|
+
const { expiry, capabilities, contentSourceDigestHex, capabilityCeilingHashHex, nativeProjectionHashHex } = addressedPlan(options);
|
|
6869
|
+
await assertSealedBodyFits({ ...options, matcher, ownerDid: options.authority.ownerDid });
|
|
6861
6870
|
const created = await createPolicy(options, capabilities);
|
|
6862
|
-
const contentSourceDigestHex = digestHex(options.contentSource, CONTENT_SOURCE_V1_DOMAIN2);
|
|
6863
|
-
const capabilityCeilingHashHex = digestHex(capabilities, POLICY_CAPABILITY_V1_DOMAIN2);
|
|
6864
|
-
const nativeProjectionHashHex = digestHex(nativeProjection(capabilities), NATIVE_PROJECTION_V1_DOMAIN2);
|
|
6865
6871
|
const commonRoot = {
|
|
6866
6872
|
ownerDid: options.authority.ownerDid,
|
|
6867
6873
|
policyId: created.policy.policyId,
|
|
@@ -6891,48 +6897,39 @@ async function publishAddressedShare(input) {
|
|
|
6891
6897
|
expectedNodeAudience: options.nodeAudience
|
|
6892
6898
|
});
|
|
6893
6899
|
if (registration.policyCid !== created.policyCid || registration.policyRootCid !== policyRoot.cid || registration.enforcementRootCid !== enforcementRoot.cid) throw new Error("Policy/v3 registration receipt is not bound to the published roots");
|
|
6894
|
-
const unsigned = {
|
|
6895
|
-
|
|
6896
|
-
|
|
6897
|
-
recipientMatcher: matcher,
|
|
6898
|
-
...options.deliveryEmail === void 0 ? {} : { deliveryEmail: options.deliveryEmail },
|
|
6899
|
-
actions: [...options.actions],
|
|
6900
|
-
resource: { ...options.resource },
|
|
6901
|
-
target: { origin: options.nodeOrigin, nodeAudience: registration.attestedEnforcerBinding.enforcerDid, spaceId: options.spaceId },
|
|
6900
|
+
const unsigned = unsignedAddressedEnvelope({
|
|
6901
|
+
options,
|
|
6902
|
+
matcher,
|
|
6902
6903
|
policy: created.policy,
|
|
6903
6904
|
policyCid: created.policyCid,
|
|
6904
6905
|
policyRoot,
|
|
6905
6906
|
enforcementRoot,
|
|
6906
6907
|
attestedEnforcerBinding: registration.attestedEnforcerBinding,
|
|
6907
|
-
contentSource: options.contentSource,
|
|
6908
6908
|
contentSourceDigestHex,
|
|
6909
|
-
|
|
6910
|
-
|
|
6911
|
-
display: { filename: options.filename },
|
|
6912
|
-
encrypted: true,
|
|
6913
|
-
metadata: {
|
|
6914
|
-
mediaType: options.mediaType,
|
|
6915
|
-
byteLength: options.byteLength,
|
|
6916
|
-
filename: options.filename,
|
|
6917
|
-
...options.mediaType.startsWith("text/") ? { encoding: "utf-8" } : {},
|
|
6918
|
-
...options.artifact === void 0 ? {} : { artifact: options.artifact }
|
|
6919
|
-
},
|
|
6920
|
-
...options.artifactPin === void 0 ? {} : { artifactPin: options.artifactPin }
|
|
6921
|
-
};
|
|
6909
|
+
expiry
|
|
6910
|
+
});
|
|
6922
6911
|
unsignedShareEnvelopeV3Schema.parse(unsigned);
|
|
6923
6912
|
const envelopeSignature = await options.authority.sign(sha2563(textEncoder.encode(`${ENVELOPE_V3_DOMAIN}${canonicalize(unsigned)}`)));
|
|
6924
6913
|
if (envelopeSignature.byteLength !== 64) throw new TypeError("v3 envelope signature must be Ed25519");
|
|
6925
|
-
const envelope =
|
|
6914
|
+
const envelope = signedAddressedEnvelope(unsigned, options.authority.ownerDid, envelopeSignature);
|
|
6926
6915
|
shareEnvelopeV3Schema.parse(envelope);
|
|
6927
6916
|
const envelopeBytes = textEncoder.encode(canonicalize(envelope));
|
|
6928
6917
|
const envelopeKeyBytes = generateKey();
|
|
6929
6918
|
const sealed = await seal(envelopeBytes, envelopeKeyBytes);
|
|
6930
6919
|
const envelopeKey = toBase64Url(envelopeKeyBytes);
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
|
|
6920
|
+
if (sealed.blob.length > await linkBodyLimit()) {
|
|
6921
|
+
throw new AddressedShareOverLimitError({ policyCid: created.policyCid, policyRootCid: policyRoot.cid, enforcementRootCid: enforcementRoot.cid });
|
|
6922
|
+
}
|
|
6923
|
+
const links = await import("@tinycloud/share-envelope/links");
|
|
6924
|
+
const { record } = await links.prepareLinkRecord({
|
|
6925
|
+
type: "share",
|
|
6926
|
+
sealed: { blob: sealed.blob, key: envelopeKeyBytes },
|
|
6927
|
+
issuerKey: { did: options.authority.ownerDid, sign: (digest3) => options.authority.sign(digest3) },
|
|
6928
|
+
apiOrigin: options.apiOrigin ?? links.DEFAULT_LINKS_API_ORIGIN,
|
|
6929
|
+
expiresAt: new Date(expiry),
|
|
6930
|
+
enforceServiceLife: false
|
|
6935
6931
|
});
|
|
6932
|
+
const url = links.buildFullLink({ origin: options.shareOrigin, key: envelopeKeyBytes, record });
|
|
6936
6933
|
const deliveryMaterial = {
|
|
6937
6934
|
envelope,
|
|
6938
6935
|
shareCid: sealed.cid,
|
|
@@ -6953,6 +6950,149 @@ async function publishAddressedShare(input) {
|
|
|
6953
6950
|
deliveryMaterial
|
|
6954
6951
|
});
|
|
6955
6952
|
}
|
|
6953
|
+
var ADDRESSED_SHARE_TOO_LARGE_MESSAGE = "This share is too large to send as a link, so nothing was shared. Use a shorter path or fewer folders.";
|
|
6954
|
+
var AddressedShareOverLimitError = class extends SharePublishError {
|
|
6955
|
+
constructor(written) {
|
|
6956
|
+
super("max-bytes-exceeded", ADDRESSED_SHARE_TOO_LARGE_MESSAGE);
|
|
6957
|
+
this.written = written;
|
|
6958
|
+
this.name = "AddressedShareOverLimitError";
|
|
6959
|
+
}
|
|
6960
|
+
};
|
|
6961
|
+
async function linkBodyLimit() {
|
|
6962
|
+
return (await import("@tinycloud/share-envelope/links")).MAX_LINK_BODY_BYTES;
|
|
6963
|
+
}
|
|
6964
|
+
var ROOT_CID_BOUND_CHARS = 128;
|
|
6965
|
+
var NODE_TIMESTAMP_BOUND = "2026-01-01T00:00:00.123456789+00:00";
|
|
6966
|
+
var ED25519_DID_KEY_CHARS = 56;
|
|
6967
|
+
function rootAuthorizationBound(input) {
|
|
6968
|
+
const attenuation = {};
|
|
6969
|
+
for (const capability of input.capabilities) {
|
|
6970
|
+
attenuation[capability.resource] = capability.kind === "encryption" ? { [capability.action]: [{}] } : Object.fromEntries(capability.actions.map((action) => [action, [{ type: "xyz.tinycloud.resource/selector", kind: capability.selector, value: capability.resource }]]));
|
|
6971
|
+
}
|
|
6972
|
+
const facts = {
|
|
6973
|
+
role: input.role,
|
|
6974
|
+
mode: input.role === "policy-authority" ? "policy-source" : "conditional-mint",
|
|
6975
|
+
ownerDid: input.ownerDid,
|
|
6976
|
+
policyId: input.policyId,
|
|
6977
|
+
policyDigestHex: input.policyDigestHex,
|
|
6978
|
+
policyCid: input.policyCid,
|
|
6979
|
+
contentSourceDigestHex: input.contentSourceDigestHex,
|
|
6980
|
+
capabilityCeilingHashHex: input.capabilityCeilingHashHex,
|
|
6981
|
+
nativeProjectionHashHex: input.nativeProjectionHashHex,
|
|
6982
|
+
nodeAudience: input.nodeAudience,
|
|
6983
|
+
...input.role === "policy-enforcement" ? { enforcerDid: input.audienceDid } : {}
|
|
6984
|
+
};
|
|
6985
|
+
const header = { alg: "EdDSA", jwk: { alg: "EdDSA", crv: "Ed25519", kty: "OKP", x: "A".repeat(43) }, typ: "JWT", ucv: "0.10.0" };
|
|
6986
|
+
const payload = {
|
|
6987
|
+
att: attenuation,
|
|
6988
|
+
aud: input.audienceDid,
|
|
6989
|
+
exp: Number.MAX_SAFE_INTEGER,
|
|
6990
|
+
fct: [facts],
|
|
6991
|
+
iss: `${input.ownerDid}#${input.ownerDid.slice("did:key:".length)}`,
|
|
6992
|
+
nbf: Number.MAX_SAFE_INTEGER,
|
|
6993
|
+
nnc: "A".repeat(36),
|
|
6994
|
+
prf: []
|
|
6995
|
+
};
|
|
6996
|
+
return `${toBase64Url(textEncoder.encode(canonicalize(header)))}.${toBase64Url(textEncoder.encode(canonicalize(payload)))}.${"A".repeat(86)}`;
|
|
6997
|
+
}
|
|
6998
|
+
async function sealedBodyUpperBound(options) {
|
|
6999
|
+
const plan = addressedPlan(options);
|
|
7000
|
+
const signature = new Uint8Array(64);
|
|
7001
|
+
const created = await createPolicy({ ...options, authority: { ownerDid: options.ownerDid, sign: async () => signature } }, plan.capabilities);
|
|
7002
|
+
const common = {
|
|
7003
|
+
ownerDid: options.ownerDid,
|
|
7004
|
+
policyId: created.policy.policyId,
|
|
7005
|
+
policyDigestHex: created.policyDigestHex,
|
|
7006
|
+
policyCid: created.policyCid,
|
|
7007
|
+
contentSourceDigestHex: plan.contentSourceDigestHex,
|
|
7008
|
+
capabilityCeilingHashHex: plan.capabilityCeilingHashHex,
|
|
7009
|
+
nativeProjectionHashHex: plan.nativeProjectionHashHex,
|
|
7010
|
+
nodeAudience: options.nodeAudience,
|
|
7011
|
+
capabilities: plan.capabilities
|
|
7012
|
+
};
|
|
7013
|
+
const policyRoot = {
|
|
7014
|
+
cid: "b".repeat(ROOT_CID_BOUND_CHARS),
|
|
7015
|
+
role: "policy-authority",
|
|
7016
|
+
authorization: rootAuthorizationBound({ ...common, role: "policy-authority", audienceDid: `did:tinycloud:policy:${created.policyDigestHex}` })
|
|
7017
|
+
};
|
|
7018
|
+
const enforcementRoot = {
|
|
7019
|
+
cid: "b".repeat(ROOT_CID_BOUND_CHARS),
|
|
7020
|
+
role: "policy-enforcement",
|
|
7021
|
+
authorization: rootAuthorizationBound({ ...common, role: "policy-enforcement", audienceDid: options.enforcerDid })
|
|
7022
|
+
};
|
|
7023
|
+
const nodeDid = options.enforcerDid.padEnd(ED25519_DID_KEY_CHARS, "z");
|
|
7024
|
+
const unsigned = unsignedAddressedEnvelope({
|
|
7025
|
+
options,
|
|
7026
|
+
matcher: options.matcher,
|
|
7027
|
+
policy: created.policy,
|
|
7028
|
+
policyCid: created.policyCid,
|
|
7029
|
+
policyRoot,
|
|
7030
|
+
enforcementRoot,
|
|
7031
|
+
attestedEnforcerBinding: {
|
|
7032
|
+
schema: "xyz.tinycloud.policy/attested-enforcer/v2",
|
|
7033
|
+
enforcerDid: nodeDid,
|
|
7034
|
+
nodeAudience: nodeDid,
|
|
7035
|
+
attestationBindingDigestHex: "f".repeat(64),
|
|
7036
|
+
issuedAt: NODE_TIMESTAMP_BOUND,
|
|
7037
|
+
expiresAt: NODE_TIMESTAMP_BOUND,
|
|
7038
|
+
signature: { suite: "Ed25519", signerDid: nodeDid, value: "A".repeat(86) }
|
|
7039
|
+
},
|
|
7040
|
+
contentSourceDigestHex: plan.contentSourceDigestHex,
|
|
7041
|
+
expiry: plan.expiry
|
|
7042
|
+
});
|
|
7043
|
+
const envelope = signedAddressedEnvelope(unsigned, options.ownerDid, signature);
|
|
7044
|
+
return (await seal(textEncoder.encode(canonicalize(envelope)), generateKey())).blob.length;
|
|
7045
|
+
}
|
|
7046
|
+
async function assertSealedBodyFits(options) {
|
|
7047
|
+
if (await sealedBodyUpperBound(options) > await linkBodyLimit()) throw new SharePublishError("max-bytes-exceeded", ADDRESSED_SHARE_TOO_LARGE_MESSAGE);
|
|
7048
|
+
}
|
|
7049
|
+
async function addressedShareBodyUpperBound(input) {
|
|
7050
|
+
const { target, credentialRequirement } = prepareAddressedShare(input);
|
|
7051
|
+
const deliveryEmail = input.deliveryEmail ?? (target.kind === "email" && isEnvelopeDeliveryEmail(target.address) ? target.address : void 0);
|
|
7052
|
+
const artifactStorage = "artifactId" in input.storage ? input.storage : void 0;
|
|
7053
|
+
const path = "path" in input.storage ? input.storage.path : `${ARTIFACT_ROOT}/${input.storage.artifactId}/versions/${Number.MAX_SAFE_INTEGER}/${input.storage.storageName}`;
|
|
7054
|
+
const contentSource = {
|
|
7055
|
+
shareId: input.shareId,
|
|
7056
|
+
kvResource: `${input.spaceId}/kv/${path}`,
|
|
7057
|
+
selector: input.resource.kind,
|
|
7058
|
+
encryptionNetwork: input.encryptionNetwork,
|
|
7059
|
+
encryptedSymmetricKeyDigestHex: "f".repeat(64),
|
|
7060
|
+
keyVersion: Number.MAX_SAFE_INTEGER,
|
|
7061
|
+
mode: "immutable",
|
|
7062
|
+
initialCiphertextDigestHex: "f".repeat(64)
|
|
7063
|
+
};
|
|
7064
|
+
const artifactPin = artifactStorage === void 0 ? void 0 : {
|
|
7065
|
+
v: 1,
|
|
7066
|
+
artifactId: artifactStorage.artifactId,
|
|
7067
|
+
version: Number.MAX_SAFE_INTEGER,
|
|
7068
|
+
manifestSha256: "f".repeat(64),
|
|
7069
|
+
files: [{ path: artifactStorage.storageName, sha256: "f".repeat(64), bytes: Number.MAX_SAFE_INTEGER }]
|
|
7070
|
+
};
|
|
7071
|
+
return sealedBodyUpperBound({
|
|
7072
|
+
shareId: input.shareId,
|
|
7073
|
+
nodeOrigin: input.nodeOrigin,
|
|
7074
|
+
nodeAudience: input.nodeAudience,
|
|
7075
|
+
enforcerDid: input.enforcerDid,
|
|
7076
|
+
spaceId: input.spaceId,
|
|
7077
|
+
actions: input.actions,
|
|
7078
|
+
policyActions: input.policyActions,
|
|
7079
|
+
resource: { kind: input.resource.kind, path },
|
|
7080
|
+
contentSource,
|
|
7081
|
+
...artifactPin === void 0 ? {} : { artifactPin },
|
|
7082
|
+
...credentialRequirement === void 0 ? {} : { credentialRequirement },
|
|
7083
|
+
...deliveryEmail === void 0 ? {} : { deliveryEmail },
|
|
7084
|
+
...input.artifact === void 0 ? {} : { artifact: input.artifact },
|
|
7085
|
+
filename: canonicalShareFilename(input.filename),
|
|
7086
|
+
mediaType: input.mediaType,
|
|
7087
|
+
byteLength: input.byteLength,
|
|
7088
|
+
expiresAt: input.expiresAt,
|
|
7089
|
+
matcher: targetMatcher(target),
|
|
7090
|
+
ownerDid: input.ownerDid
|
|
7091
|
+
});
|
|
7092
|
+
}
|
|
7093
|
+
async function assertAddressedShareFits(input) {
|
|
7094
|
+
if (await addressedShareBodyUpperBound(input) > await linkBodyLimit()) throw new SharePublishError("max-bytes-exceeded", ADDRESSED_SHARE_TOO_LARGE_MESSAGE);
|
|
7095
|
+
}
|
|
6956
7096
|
|
|
6957
7097
|
// src/cache.ts
|
|
6958
7098
|
import { sha256 as sha2564 } from "@noble/hashes/sha256";
|
|
@@ -8049,7 +8189,8 @@ async function notifyShare(input) {
|
|
|
8049
8189
|
reason: "delivery-window-expired"
|
|
8050
8190
|
};
|
|
8051
8191
|
}
|
|
8052
|
-
|
|
8192
|
+
const refused = error !== null && typeof error === "object" && "code" in error && error.code === "delivery-authorization-invalid";
|
|
8193
|
+
if (refused || error !== null && typeof error === "object" && "status" in error && (error.status === 401 || error.status === 403)) {
|
|
8053
8194
|
return {
|
|
8054
8195
|
protocol: "tinycloud-share",
|
|
8055
8196
|
version: 1,
|
|
@@ -8101,6 +8242,7 @@ function canonicalOrigin(value) {
|
|
|
8101
8242
|
function object2(value) {
|
|
8102
8243
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8103
8244
|
}
|
|
8245
|
+
var MAX_INVITATION_LINK_BYTES = 512;
|
|
8104
8246
|
async function validateReceipt(receipt, shareUrl) {
|
|
8105
8247
|
if (!object2(receipt) || !object2(receipt.request) || !object2(receipt.admission) || !object2(receipt.proof)) {
|
|
8106
8248
|
throw new CredentialInvitationError(
|
|
@@ -8114,27 +8256,17 @@ async function validateReceipt(receipt, shareUrl) {
|
|
|
8114
8256
|
"credential invitation is not bound to the share link"
|
|
8115
8257
|
);
|
|
8116
8258
|
}
|
|
8117
|
-
|
|
8118
|
-
try {
|
|
8119
|
-
link = new URL(shareUrl);
|
|
8120
|
-
} catch {
|
|
8121
|
-
throw new CredentialInvitationError(
|
|
8122
|
-
"invalid-receipt",
|
|
8123
|
-
"credential invitation share link is invalid"
|
|
8124
|
-
);
|
|
8125
|
-
}
|
|
8126
|
-
if (link.search !== "" || link.pathname !== "/s/inline") {
|
|
8127
|
-
throw new CredentialInvitationError(
|
|
8128
|
-
"invalid-receipt",
|
|
8129
|
-
"credential invitation share link must be sealed inline"
|
|
8130
|
-
);
|
|
8131
|
-
}
|
|
8259
|
+
const links = await import("@tinycloud/share-envelope/links");
|
|
8132
8260
|
try {
|
|
8133
|
-
|
|
8261
|
+
const origin = new URL(shareUrl).origin;
|
|
8262
|
+
const parsed = links.parseLink(shareUrl, { trustedOrigins: [origin] });
|
|
8263
|
+
if (parsed.form !== "short" || parsed.pathType !== "share" || shareUrl.length > MAX_INVITATION_LINK_BYTES || shareUrl !== links.buildShortLink({ origin, type: "share", id: parsed.id, key: parsed.key, bodyCid: parsed.c })) {
|
|
8264
|
+
throw new Error("not a short share link");
|
|
8265
|
+
}
|
|
8134
8266
|
} catch {
|
|
8135
8267
|
throw new CredentialInvitationError(
|
|
8136
8268
|
"invalid-receipt",
|
|
8137
|
-
"credential invitation share link
|
|
8269
|
+
"credential invitation share link must be a short share link"
|
|
8138
8270
|
);
|
|
8139
8271
|
}
|
|
8140
8272
|
}
|
|
@@ -8800,6 +8932,8 @@ async function openNativeShare(sharing, link) {
|
|
|
8800
8932
|
return sharing.receive(parseNativeShareUrl(link), { autoSubdelegate: false, useSessionKey: false });
|
|
8801
8933
|
}
|
|
8802
8934
|
export {
|
|
8935
|
+
ADDRESSED_SHARE_TOO_LARGE_MESSAGE,
|
|
8936
|
+
AddressedShareOverLimitError,
|
|
8803
8937
|
ArtifactPinError,
|
|
8804
8938
|
CredentialInvitationError,
|
|
8805
8939
|
DEFAULT_MAX_CONTENT_BLOB_BYTES,
|
|
@@ -8823,7 +8957,9 @@ export {
|
|
|
8823
8957
|
ShareReceiveError,
|
|
8824
8958
|
ShareRecipientClient,
|
|
8825
8959
|
addressedCredentialRequirement,
|
|
8960
|
+
addressedShareBodyUpperBound,
|
|
8826
8961
|
artifactBindingView,
|
|
8962
|
+
assertAddressedShareFits,
|
|
8827
8963
|
assertArtifactBinding,
|
|
8828
8964
|
authorizationMethodForTarget,
|
|
8829
8965
|
authorizeShare,
|