@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
|
@@ -226,7 +226,7 @@ declare class ShareRecipientClient {
|
|
|
226
226
|
authorize(envelope: ShareEnvelopeV2): Promise<ShareAuthorizedContent>;
|
|
227
227
|
establishPolicySession(): Promise<SharePolicySession>;
|
|
228
228
|
private establishV3;
|
|
229
|
-
/** Decrypt
|
|
229
|
+
/** Decrypt unscoped v1 or path-bound v2 content, independently checking canonical and registered raw-key digests. */
|
|
230
230
|
decryptV3Content(bytes: Uint8Array): Promise<{
|
|
231
231
|
readonly bytes: Uint8Array;
|
|
232
232
|
readonly mediaType: string;
|
|
@@ -226,7 +226,7 @@ declare class ShareRecipientClient {
|
|
|
226
226
|
authorize(envelope: ShareEnvelopeV2): Promise<ShareAuthorizedContent>;
|
|
227
227
|
establishPolicySession(): Promise<SharePolicySession>;
|
|
228
228
|
private establishV3;
|
|
229
|
-
/** Decrypt
|
|
229
|
+
/** Decrypt unscoped v1 or path-bound v2 content, independently checking canonical and registered raw-key digests. */
|
|
230
230
|
decryptV3Content(bytes: Uint8Array): Promise<{
|
|
231
231
|
readonly bytes: Uint8Array;
|
|
232
232
|
readonly mediaType: string;
|
package/dist/web-recipient.cjs
CHANGED
|
@@ -6127,41 +6127,18 @@ function object2(value, label) {
|
|
|
6127
6127
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${label} is invalid`);
|
|
6128
6128
|
return value;
|
|
6129
6129
|
}
|
|
6130
|
-
var BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
6131
6130
|
function toBase64(bytes) {
|
|
6132
|
-
|
|
6133
|
-
for (let i = 0; i < bytes.length; i += 3) {
|
|
6134
|
-
const b0 = bytes[i];
|
|
6135
|
-
const b1 = i + 1 < bytes.length ? bytes[i + 1] : 0;
|
|
6136
|
-
const b2 = i + 2 < bytes.length ? bytes[i + 2] : 0;
|
|
6137
|
-
out += BASE64_ALPHABET[b0 >> 2 & 63];
|
|
6138
|
-
out += BASE64_ALPHABET[(b0 << 4 | b1 >> 4) & 63];
|
|
6139
|
-
out += i + 1 < bytes.length ? BASE64_ALPHABET[(b1 << 2 | b2 >> 6) & 63] : "=";
|
|
6140
|
-
out += i + 2 < bytes.length ? BASE64_ALPHABET[b2 & 63] : "=";
|
|
6141
|
-
}
|
|
6142
|
-
return out;
|
|
6131
|
+
return toBase64Url(bytes).replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(bytes.length / 3) * 4, "=");
|
|
6143
6132
|
}
|
|
6144
6133
|
function fromBase64(value, label) {
|
|
6145
6134
|
if (!/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value)) {
|
|
6146
6135
|
throw new Error(`${label} is invalid`);
|
|
6147
6136
|
}
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
6153
|
-
const v1 = BASE64_ALPHABET.indexOf(value[i + 1]);
|
|
6154
|
-
const v2 = value[i + 2] === "=" ? 0 : BASE64_ALPHABET.indexOf(value[i + 2]);
|
|
6155
|
-
const v3 = value[i + 3] === "=" ? 0 : BASE64_ALPHABET.indexOf(value[i + 3]);
|
|
6156
|
-
const b0 = v0 << 2 | v1 >> 4;
|
|
6157
|
-
const b1 = (v1 & 15) << 4 | v2 >> 2;
|
|
6158
|
-
const b2 = (v2 & 3) << 6 | v3;
|
|
6159
|
-
if (outIdx < out.length) out[outIdx++] = b0;
|
|
6160
|
-
if (outIdx < out.length) out[outIdx++] = b1;
|
|
6161
|
-
if (outIdx < out.length) out[outIdx++] = b2;
|
|
6162
|
-
}
|
|
6163
|
-
if (toBase64(out) !== value) throw new Error(`${label} is invalid`);
|
|
6164
|
-
return out;
|
|
6137
|
+
try {
|
|
6138
|
+
return fromBase64Url(value.replace(/=+$/, "").replace(/\+/g, "-").replace(/\//g, "_"));
|
|
6139
|
+
} catch {
|
|
6140
|
+
throw new Error(`${label} is invalid`);
|
|
6141
|
+
}
|
|
6165
6142
|
}
|
|
6166
6143
|
async function digestBytes(value) {
|
|
6167
6144
|
return toBase64Url(new Uint8Array(await crypto.subtle.digest("SHA-256", value)));
|
|
@@ -6272,16 +6249,16 @@ function matchesInitialCiphertextDigest(bytes, expected) {
|
|
|
6272
6249
|
function canonicalHashHex(value) {
|
|
6273
6250
|
return hex2((0, import_sha2562.sha256)(new TextEncoder().encode(canonicalize(value))));
|
|
6274
6251
|
}
|
|
6275
|
-
async function aesGcmDecrypt(key, blob) {
|
|
6252
|
+
async function aesGcmDecrypt(key, blob, aad) {
|
|
6276
6253
|
if (key.length !== 32 || blob.length < 28) throw new Error("encrypted content is malformed");
|
|
6277
6254
|
const cryptoKey = await crypto.subtle.importKey("raw", key, "AES-GCM", false, ["decrypt"]);
|
|
6278
|
-
return new Uint8Array(await crypto.subtle.decrypt({ name: "AES-GCM", iv: blob.slice(0, 12) }, cryptoKey, blob.slice(12)));
|
|
6255
|
+
return new Uint8Array(await crypto.subtle.decrypt({ name: "AES-GCM", iv: blob.slice(0, 12), ...aad && { additionalData: aad } }, cryptoKey, blob.slice(12)));
|
|
6279
6256
|
}
|
|
6280
|
-
async function aesGcmEncrypt(key, plaintext) {
|
|
6257
|
+
async function aesGcmEncrypt(key, plaintext, aad) {
|
|
6281
6258
|
if (key.length !== 32) throw new Error("encrypted content key is malformed");
|
|
6282
6259
|
const nonce = crypto.getRandomValues(new Uint8Array(12));
|
|
6283
6260
|
const cryptoKey = await crypto.subtle.importKey("raw", key, "AES-GCM", false, ["encrypt"]);
|
|
6284
|
-
const ciphertext = new Uint8Array(await crypto.subtle.encrypt({ name: "AES-GCM", iv: nonce }, cryptoKey, plaintext));
|
|
6261
|
+
const ciphertext = new Uint8Array(await crypto.subtle.encrypt({ name: "AES-GCM", iv: nonce, ...aad && { additionalData: aad } }, cryptoKey, plaintext));
|
|
6285
6262
|
const output = new Uint8Array(nonce.length + ciphertext.length);
|
|
6286
6263
|
output.set(nonce);
|
|
6287
6264
|
output.set(ciphertext, nonce.length);
|
|
@@ -6296,8 +6273,9 @@ function parseV3InlineEncryptedEnvelope(bytes, expected) {
|
|
|
6296
6273
|
}
|
|
6297
6274
|
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("encrypted content envelope is malformed");
|
|
6298
6275
|
const record = value;
|
|
6299
|
-
const allowed = ["v", "networkId", "keyPath", "alg", "keyVersion", "encryptedSymmetricKey", "encryptedSymmetricKeyHash", "ciphertext", "metadata"];
|
|
6300
|
-
|
|
6276
|
+
const allowed = ["v", "networkId", "keyPath", "alg", "keyVersion", "encryptedSymmetricKey", "encryptedSymmetricKeyHash", "ciphertext", "aad", "metadata"];
|
|
6277
|
+
const source = expected.contentSource;
|
|
6278
|
+
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((0, import_sha2562.sha256)(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"))) {
|
|
6301
6279
|
throw new Error("encrypted content envelope binding is invalid");
|
|
6302
6280
|
}
|
|
6303
6281
|
return record;
|
|
@@ -6418,7 +6396,7 @@ var ShareRecipientClient = class {
|
|
|
6418
6396
|
this.session = { sessionId: delegation.sessionCid, expiresAt: new Date(compact.payload.exp * 1e3).toISOString(), actions: envelope.actions, resource: envelope.resource };
|
|
6419
6397
|
return this.session;
|
|
6420
6398
|
}
|
|
6421
|
-
/** Decrypt
|
|
6399
|
+
/** Decrypt unscoped v1 or path-bound v2 content, independently checking canonical and registered raw-key digests. */
|
|
6422
6400
|
async decryptV3Content(bytes) {
|
|
6423
6401
|
const envelope = this.options.envelope;
|
|
6424
6402
|
const signer = this.nativeSigner ?? this.signer;
|
|
@@ -6426,6 +6404,9 @@ var ShareRecipientClient = class {
|
|
|
6426
6404
|
assertArtifactBinding(artifactBindingView(envelope));
|
|
6427
6405
|
if (!matchesInitialCiphertextDigest(bytes, envelope.contentSource.initialCiphertextDigestHex)) throw new Error("v3 owner KV ciphertext digest mismatch");
|
|
6428
6406
|
const encrypted = parseV3InlineEncryptedEnvelope(bytes, envelope);
|
|
6407
|
+
const ciphertext = fromBase64(encrypted.ciphertext, "v3 encrypted content");
|
|
6408
|
+
if (ciphertext.length < 28) throw new Error("encrypted content is malformed");
|
|
6409
|
+
const aad = encrypted.aad === void 0 ? void 0 : fromBase64(encrypted.aad, "v3 encrypted content AAD");
|
|
6429
6410
|
const receiverPrivateKey = crypto.getRandomValues(new Uint8Array(32));
|
|
6430
6411
|
const receiverPublicKey = toBase64(import_ed255194.x25519.getPublicKey(receiverPrivateKey));
|
|
6431
6412
|
const receiverPublicKeyHash = canonicalHashHex(receiverPublicKey);
|
|
@@ -6462,7 +6443,7 @@ var ShareRecipientClient = class {
|
|
|
6462
6443
|
const symmetricKey = await aesGcmDecrypt(shared, wrapped.slice(33));
|
|
6463
6444
|
shared.fill(0);
|
|
6464
6445
|
if (symmetricKey.length !== 32) throw new Error("v3 content key is malformed");
|
|
6465
|
-
const plaintext = await aesGcmDecrypt(symmetricKey,
|
|
6446
|
+
const plaintext = await aesGcmDecrypt(symmetricKey, ciphertext, aad);
|
|
6466
6447
|
this.v3ContentKey?.fill(0);
|
|
6467
6448
|
this.v3ContentKey = symmetricKey;
|
|
6468
6449
|
this.v3ContentEnvelope = encrypted;
|
|
@@ -6474,7 +6455,9 @@ var ShareRecipientClient = class {
|
|
|
6474
6455
|
/** Re-encrypt edited v3 content with the admitted content key. */
|
|
6475
6456
|
async encryptV3Content(bytes, mediaType) {
|
|
6476
6457
|
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");
|
|
6477
|
-
|
|
6458
|
+
const envelope = this.v3ContentEnvelope;
|
|
6459
|
+
const aad = envelope.aad === void 0 ? void 0 : fromBase64(envelope.aad, "v3 encrypted content AAD");
|
|
6460
|
+
return new TextEncoder().encode(canonicalize({ ...envelope, ciphertext: toBase64(await aesGcmEncrypt(this.v3ContentKey, bytes, aad)), metadata: { ...envelope.metadata ?? {}, contentType: mediaType } }));
|
|
6478
6461
|
}
|
|
6479
6462
|
async resumeWithProof(envelope, resumeToken, proof) {
|
|
6480
6463
|
void envelope;
|