squidcloudctl 3.0.5 → 3.0.6
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/lib/transfer.js +40 -8
- package/package.json +1 -1
package/dist/lib/transfer.js
CHANGED
|
@@ -310,20 +310,37 @@ export async function downloadFile(target, destPath, onProgress) {
|
|
|
310
310
|
const { detectChunkVersion, decryptAny, decryptV3, deriveRawKey } = await import('./crypto/res54.js');
|
|
311
311
|
const master = deriveRawKey(defaultKey || '');
|
|
312
312
|
const fileKeyRaw = noble.hkdf(sha2.sha256, master, new Uint8Array(0), enc.encode('v3-file-master' + target.id), 32);
|
|
313
|
+
let activeMaster = master;
|
|
313
314
|
for (let i = 0; i < chunks.length; i++) {
|
|
314
315
|
const blob = await clusterDownloadChunk(chunks[i], target.userId || '');
|
|
315
316
|
const version = detectChunkVersion(blob);
|
|
316
317
|
let plain;
|
|
317
|
-
if (version ===
|
|
318
|
-
plain = decryptV3(blob, master, target.userId || '', target.id, i, chunks.length);
|
|
319
|
-
}
|
|
320
|
-
else if (version === 1 && !encrypted) {
|
|
318
|
+
if (version === 1 && !encrypted && !defaultKey) {
|
|
321
319
|
plain = blob;
|
|
322
320
|
}
|
|
323
321
|
else {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
}
|
|
322
|
+
if (!defaultKey && byokCache === undefined) {
|
|
323
|
+
byokCache = (await askByokKey(target.name)) ?? '';
|
|
324
|
+
}
|
|
325
|
+
const attemptKey = defaultKey || byokCache || '';
|
|
326
|
+
try {
|
|
327
|
+
if (version === 3) {
|
|
328
|
+
const m2 = attemptKey ? deriveRawKey(attemptKey) : master;
|
|
329
|
+
plain = decryptV3(blob, m2, target.userId || '', target.id, i, chunks.length);
|
|
330
|
+
activeMaster = m2;
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
plain = decryptAny(blob, attemptKey, {
|
|
334
|
+
userId: target.userId, fileId: target.id, chunkIndex: i, totalChunks: chunks.length,
|
|
335
|
+
}).plain;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
catch (err) {
|
|
339
|
+
if (!attemptKey)
|
|
340
|
+
throw new Error('BYOK_KEY_REQUIRED: pass --key or run interactively');
|
|
341
|
+
throw err;
|
|
342
|
+
}
|
|
343
|
+
void activeMaster;
|
|
327
344
|
}
|
|
328
345
|
void fileKeyRaw;
|
|
329
346
|
progress.update(i + 1, `chunk ${i + 1}/${chunks.length}`);
|
|
@@ -338,11 +355,26 @@ export async function downloadFile(target, destPath, onProgress) {
|
|
|
338
355
|
return finalPath2;
|
|
339
356
|
}
|
|
340
357
|
catch (e) {
|
|
341
|
-
|
|
358
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
359
|
+
if (msg.startsWith('VAULT_KEY_DRIFT'))
|
|
360
|
+
throw e;
|
|
361
|
+
errors.push(`cluster: ${msg}`);
|
|
342
362
|
}
|
|
343
363
|
}
|
|
344
364
|
throw new Error(errors.join(' · ') || 'No downloadable strategy succeeded');
|
|
345
365
|
}
|
|
366
|
+
let byokCache;
|
|
367
|
+
async function askByokKey(fileName) {
|
|
368
|
+
if (byokCache !== undefined)
|
|
369
|
+
return byokCache;
|
|
370
|
+
if (!process.stdin.isTTY || process.env.SQUIDCLOUD_NONINTERACTIVE === '1')
|
|
371
|
+
return null;
|
|
372
|
+
const readline = await import('node:readline');
|
|
373
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
374
|
+
const answer = await new Promise((res) => rl.question(`\u25cf decryption key for ${fileName}: `, (v) => { rl.close(); res(v); }));
|
|
375
|
+
byokCache = answer.trim() || null;
|
|
376
|
+
return byokCache;
|
|
377
|
+
}
|
|
346
378
|
async function resolveKey(fileId, tagsKey) {
|
|
347
379
|
if (tagsKey && !/^(managed_key|sha256:\S+|byok_encrypted|byok_protected)$/.test(tagsKey))
|
|
348
380
|
return tagsKey;
|