@tinycloud/share-sdk 1.4.1-beta.1 → 1.4.1-beta.2
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 +21 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +21 -38
- package/dist/index.js.map +1 -1
- package/dist/{web-recipient-entry-Cy1fXl_5.d.cts → web-recipient-entry-Bn3yRB7g.d.cts} +1 -1
- package/dist/{web-recipient-entry-CPntAP0H.d.ts → web-recipient-entry-CTFoIH8l.d.ts} +1 -1
- package/dist/web-recipient.cjs +21 -38
- 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 +21 -38
- package/dist/web-recipient.js.map +1 -1
- package/package.json +1 -1
package/dist/web-recipient.d.cts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { f as ShareMetadata, r as ShareRecipientClient, u as inspectShare } from './web-recipient-entry-
|
|
1
|
+
export { f as ShareMetadata, r as ShareRecipientClient, u as inspectShare } from './web-recipient-entry-Bn3yRB7g.cjs';
|
|
2
2
|
import '@tinycloud/share-envelope';
|
|
3
3
|
import './authorization-CmP1skO8.cjs';
|
package/dist/web-recipient.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { f as ShareMetadata, r as ShareRecipientClient, u as inspectShare } from './web-recipient-entry-
|
|
1
|
+
export { f as ShareMetadata, r as ShareRecipientClient, u as inspectShare } from './web-recipient-entry-CTFoIH8l.js';
|
|
2
2
|
import '@tinycloud/share-envelope';
|
|
3
3
|
import './authorization-CmP1skO8.js';
|
package/dist/web-recipient.js
CHANGED
|
@@ -6096,41 +6096,18 @@ function object2(value, label) {
|
|
|
6096
6096
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${label} is invalid`);
|
|
6097
6097
|
return value;
|
|
6098
6098
|
}
|
|
6099
|
-
var BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
6100
6099
|
function toBase64(bytes) {
|
|
6101
|
-
|
|
6102
|
-
for (let i = 0; i < bytes.length; i += 3) {
|
|
6103
|
-
const b0 = bytes[i];
|
|
6104
|
-
const b1 = i + 1 < bytes.length ? bytes[i + 1] : 0;
|
|
6105
|
-
const b2 = i + 2 < bytes.length ? bytes[i + 2] : 0;
|
|
6106
|
-
out += BASE64_ALPHABET[b0 >> 2 & 63];
|
|
6107
|
-
out += BASE64_ALPHABET[(b0 << 4 | b1 >> 4) & 63];
|
|
6108
|
-
out += i + 1 < bytes.length ? BASE64_ALPHABET[(b1 << 2 | b2 >> 6) & 63] : "=";
|
|
6109
|
-
out += i + 2 < bytes.length ? BASE64_ALPHABET[b2 & 63] : "=";
|
|
6110
|
-
}
|
|
6111
|
-
return out;
|
|
6100
|
+
return toBase64Url(bytes).replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(bytes.length / 3) * 4, "=");
|
|
6112
6101
|
}
|
|
6113
6102
|
function fromBase64(value, label) {
|
|
6114
6103
|
if (!/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value)) {
|
|
6115
6104
|
throw new Error(`${label} is invalid`);
|
|
6116
6105
|
}
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
const v1 = BASE64_ALPHABET.indexOf(value[i + 1]);
|
|
6123
|
-
const v2 = value[i + 2] === "=" ? 0 : BASE64_ALPHABET.indexOf(value[i + 2]);
|
|
6124
|
-
const v3 = value[i + 3] === "=" ? 0 : BASE64_ALPHABET.indexOf(value[i + 3]);
|
|
6125
|
-
const b0 = v0 << 2 | v1 >> 4;
|
|
6126
|
-
const b1 = (v1 & 15) << 4 | v2 >> 2;
|
|
6127
|
-
const b2 = (v2 & 3) << 6 | v3;
|
|
6128
|
-
if (outIdx < out.length) out[outIdx++] = b0;
|
|
6129
|
-
if (outIdx < out.length) out[outIdx++] = b1;
|
|
6130
|
-
if (outIdx < out.length) out[outIdx++] = b2;
|
|
6131
|
-
}
|
|
6132
|
-
if (toBase64(out) !== value) throw new Error(`${label} is invalid`);
|
|
6133
|
-
return out;
|
|
6106
|
+
try {
|
|
6107
|
+
return fromBase64Url(value.replace(/=+$/, "").replace(/\+/g, "-").replace(/\//g, "_"));
|
|
6108
|
+
} catch {
|
|
6109
|
+
throw new Error(`${label} is invalid`);
|
|
6110
|
+
}
|
|
6134
6111
|
}
|
|
6135
6112
|
async function digestBytes(value) {
|
|
6136
6113
|
return toBase64Url(new Uint8Array(await crypto.subtle.digest("SHA-256", value)));
|
|
@@ -6241,16 +6218,16 @@ function matchesInitialCiphertextDigest(bytes, expected) {
|
|
|
6241
6218
|
function canonicalHashHex(value) {
|
|
6242
6219
|
return hex2(sha2563(new TextEncoder().encode(canonicalize(value))));
|
|
6243
6220
|
}
|
|
6244
|
-
async function aesGcmDecrypt(key, blob) {
|
|
6221
|
+
async function aesGcmDecrypt(key, blob, aad) {
|
|
6245
6222
|
if (key.length !== 32 || blob.length < 28) throw new Error("encrypted content is malformed");
|
|
6246
6223
|
const cryptoKey = await crypto.subtle.importKey("raw", key, "AES-GCM", false, ["decrypt"]);
|
|
6247
|
-
return new Uint8Array(await crypto.subtle.decrypt({ name: "AES-GCM", iv: blob.slice(0, 12) }, cryptoKey, blob.slice(12)));
|
|
6224
|
+
return new Uint8Array(await crypto.subtle.decrypt({ name: "AES-GCM", iv: blob.slice(0, 12), ...aad && { additionalData: aad } }, cryptoKey, blob.slice(12)));
|
|
6248
6225
|
}
|
|
6249
|
-
async function aesGcmEncrypt(key, plaintext) {
|
|
6226
|
+
async function aesGcmEncrypt(key, plaintext, aad) {
|
|
6250
6227
|
if (key.length !== 32) throw new Error("encrypted content key is malformed");
|
|
6251
6228
|
const nonce = crypto.getRandomValues(new Uint8Array(12));
|
|
6252
6229
|
const cryptoKey = await crypto.subtle.importKey("raw", key, "AES-GCM", false, ["encrypt"]);
|
|
6253
|
-
const ciphertext = new Uint8Array(await crypto.subtle.encrypt({ name: "AES-GCM", iv: nonce }, cryptoKey, plaintext));
|
|
6230
|
+
const ciphertext = new Uint8Array(await crypto.subtle.encrypt({ name: "AES-GCM", iv: nonce, ...aad && { additionalData: aad } }, cryptoKey, plaintext));
|
|
6254
6231
|
const output = new Uint8Array(nonce.length + ciphertext.length);
|
|
6255
6232
|
output.set(nonce);
|
|
6256
6233
|
output.set(ciphertext, nonce.length);
|
|
@@ -6265,8 +6242,9 @@ function parseV3InlineEncryptedEnvelope(bytes, expected) {
|
|
|
6265
6242
|
}
|
|
6266
6243
|
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("encrypted content envelope is malformed");
|
|
6267
6244
|
const record = value;
|
|
6268
|
-
const allowed = ["v", "networkId", "keyPath", "alg", "keyVersion", "encryptedSymmetricKey", "encryptedSymmetricKeyHash", "ciphertext", "metadata"];
|
|
6269
|
-
|
|
6245
|
+
const allowed = ["v", "networkId", "keyPath", "alg", "keyVersion", "encryptedSymmetricKey", "encryptedSymmetricKeyHash", "ciphertext", "aad", "metadata"];
|
|
6246
|
+
const source = expected.contentSource;
|
|
6247
|
+
if (Object.keys(record).some((key) => !allowed.includes(key)) || record.v !== (source.encryptionKeyPath === void 0 ? 1 : 2) || record.networkId !== source.encryptionNetwork || record.networkId !== expected.encryptionNetwork || record.keyPath !== source.encryptionKeyPath || record.keyPath !== void 0 && record.keyPath !== `share/${expected.shareId}` || record.alg !== "x25519-aes256gcm/v1" || record.keyVersion !== source.keyVersion || typeof record.encryptedSymmetricKey !== "string" || typeof record.encryptedSymmetricKeyHash !== "string" || hex2(sha2563(fromBase64(record.encryptedSymmetricKey, "v3 encrypted symmetric key"))) !== source.encryptedSymmetricKeyDigestHex || record.encryptedSymmetricKeyHash !== canonicalHashHex(record.encryptedSymmetricKey) || typeof record.ciphertext !== "string" || record.aad !== void 0 && typeof record.aad !== "string" || record.metadata !== void 0 && (record.metadata === null || typeof record.metadata !== "object" || Array.isArray(record.metadata) || Object.values(record.metadata).some((entry) => typeof entry !== "string"))) {
|
|
6270
6248
|
throw new Error("encrypted content envelope binding is invalid");
|
|
6271
6249
|
}
|
|
6272
6250
|
return record;
|
|
@@ -6387,7 +6365,7 @@ var ShareRecipientClient = class {
|
|
|
6387
6365
|
this.session = { sessionId: delegation.sessionCid, expiresAt: new Date(compact.payload.exp * 1e3).toISOString(), actions: envelope.actions, resource: envelope.resource };
|
|
6388
6366
|
return this.session;
|
|
6389
6367
|
}
|
|
6390
|
-
/** Decrypt
|
|
6368
|
+
/** Decrypt unscoped v1 or path-bound v2 content, independently checking canonical and registered raw-key digests. */
|
|
6391
6369
|
async decryptV3Content(bytes) {
|
|
6392
6370
|
const envelope = this.options.envelope;
|
|
6393
6371
|
const signer = this.nativeSigner ?? this.signer;
|
|
@@ -6395,6 +6373,9 @@ var ShareRecipientClient = class {
|
|
|
6395
6373
|
assertArtifactBinding(artifactBindingView(envelope));
|
|
6396
6374
|
if (!matchesInitialCiphertextDigest(bytes, envelope.contentSource.initialCiphertextDigestHex)) throw new Error("v3 owner KV ciphertext digest mismatch");
|
|
6397
6375
|
const encrypted = parseV3InlineEncryptedEnvelope(bytes, envelope);
|
|
6376
|
+
const ciphertext = fromBase64(encrypted.ciphertext, "v3 encrypted content");
|
|
6377
|
+
if (ciphertext.length < 28) throw new Error("encrypted content is malformed");
|
|
6378
|
+
const aad = encrypted.aad === void 0 ? void 0 : fromBase64(encrypted.aad, "v3 encrypted content AAD");
|
|
6398
6379
|
const receiverPrivateKey = crypto.getRandomValues(new Uint8Array(32));
|
|
6399
6380
|
const receiverPublicKey = toBase64(x25519.getPublicKey(receiverPrivateKey));
|
|
6400
6381
|
const receiverPublicKeyHash = canonicalHashHex(receiverPublicKey);
|
|
@@ -6431,7 +6412,7 @@ var ShareRecipientClient = class {
|
|
|
6431
6412
|
const symmetricKey = await aesGcmDecrypt(shared, wrapped.slice(33));
|
|
6432
6413
|
shared.fill(0);
|
|
6433
6414
|
if (symmetricKey.length !== 32) throw new Error("v3 content key is malformed");
|
|
6434
|
-
const plaintext = await aesGcmDecrypt(symmetricKey,
|
|
6415
|
+
const plaintext = await aesGcmDecrypt(symmetricKey, ciphertext, aad);
|
|
6435
6416
|
this.v3ContentKey?.fill(0);
|
|
6436
6417
|
this.v3ContentKey = symmetricKey;
|
|
6437
6418
|
this.v3ContentEnvelope = encrypted;
|
|
@@ -6443,7 +6424,9 @@ var ShareRecipientClient = class {
|
|
|
6443
6424
|
/** Re-encrypt edited v3 content with the admitted content key. */
|
|
6444
6425
|
async encryptV3Content(bytes, mediaType) {
|
|
6445
6426
|
if (this.options.envelope.version !== 3 || this.v3ContentKey === void 0 || this.v3ContentEnvelope === void 0) throw new Error("v3 content must be decrypted before it can be saved");
|
|
6446
|
-
|
|
6427
|
+
const envelope = this.v3ContentEnvelope;
|
|
6428
|
+
const aad = envelope.aad === void 0 ? void 0 : fromBase64(envelope.aad, "v3 encrypted content AAD");
|
|
6429
|
+
return new TextEncoder().encode(canonicalize({ ...envelope, ciphertext: toBase64(await aesGcmEncrypt(this.v3ContentKey, bytes, aad)), metadata: { ...envelope.metadata ?? {}, contentType: mediaType } }));
|
|
6447
6430
|
}
|
|
6448
6431
|
async resumeWithProof(envelope, resumeToken, proof) {
|
|
6449
6432
|
void envelope;
|