From 92fe268e6b684fa1c7a0b4022c158139eb04927d Mon Sep 17 00:00:00 2001 From: tamarafinogina Date: Thu, 25 Jun 2026 16:56:40 +0200 Subject: [PATCH 1/2] add download with bucketKey --- src/network/download.ts | 48 +++++++++++++++++++++++++++++++++++ src/network/errors/context.ts | 4 +++ src/network/types.ts | 7 +++++ 3 files changed, 59 insertions(+) diff --git a/src/network/download.ts b/src/network/download.ts index d9741156..d9bf14f3 100644 --- a/src/network/download.ts +++ b/src/network/download.ts @@ -7,6 +7,7 @@ import { DownloadFileFunction, ToBinaryDataFunction, BinaryData, + CryptoV3, } from './types'; export class FileVersionOneError extends Error { @@ -71,3 +72,50 @@ export async function downloadFile( throw err; } } + +export async function downloadFileWithBucketKey( + fileId: string, + bucketId: string, + bucketKey: Buffer, + network: Network, + crypto: CryptoV3, + toBinaryData: ToBinaryDataFunction, + downloadFile: DownloadFileFunction, + decryptFile: DecryptFileFunction, + opts?: { token: string }, +): Promise { + let iv: BinaryData; + let key: BinaryData; + + try { + const fileInfo = await network.getDownloadLinks(bucketId, fileId, opts?.token); + const { index, shards, version, size } = fileInfo; + + if (!version || version === 1) { + throw new FileVersionOneError(); + } + + iv = toBinaryData(index, BinaryDataEncoding.HEX).slice(0, 16); + key = await crypto.generateFileKeyFromBucketKey(bucketKey, toBinaryData(index, BinaryDataEncoding.HEX)); + const downloadables = shards.sort((sA, sB) => sA.index - sB.index); + + await downloadFile(downloadables, fileInfo); + await decryptFile(crypto.algorithm.type, key, iv, size); + } catch (err) { + const context = getNetworkErrorContext( + { + bucketId, + fileId, + user: network.credentials.username, + crypto: { + bucketKey, + }, + }, + err, + ); + + (err as ErrorWithContext).context = context; + + throw err; + } +} diff --git a/src/network/errors/context.ts b/src/network/errors/context.ts index 514eed58..0f5f36af 100644 --- a/src/network/errors/context.ts +++ b/src/network/errors/context.ts @@ -7,6 +7,7 @@ export type NetworkUploadContext = { user: string; crypto: { mnemonic?: string; + bucketKey?: Buffer; }; }; export type NetworkDownloadContext = { @@ -15,6 +16,7 @@ export type NetworkDownloadContext = { user: string; crypto: { mnemonic?: string; + bucketKey?: Buffer; }; }; @@ -30,9 +32,11 @@ export function getNetworkErrorContext(input: NetworkContext, err: unknown): Net const output = Object.assign({}, input); delete output.crypto.mnemonic; + delete output.crypto.bucketKey; if (err instanceof UploadInvalidMnemonicError || err instanceof DownloadInvalidMnemonicError) { output.crypto.mnemonic = input.crypto.mnemonic; + output.crypto.bucketKey = input.crypto.bucketKey; } return output; diff --git a/src/network/types.ts b/src/network/types.ts index b8fe8440..66098215 100644 --- a/src/network/types.ts +++ b/src/network/types.ts @@ -127,6 +127,13 @@ export type Crypto = { computeHmac?: (key: BinaryData, shardHashes: string[]) => Promise; }; +export type CryptoV3 = { + algorithm: Algorithm; + randomBytes: (bytesLength: number) => BinaryData; + generateFileKeyFromBucketKey: (bucketKey: Buffer, index: BinaryData) => Promise; + computeHmac?: (key: BinaryData, shardHashes: string[]) => Promise; +}; + export type EncryptFileFunction = ( algorithm: SymmetricCryptoAlgorithm, key: BinaryData, From 72f2bb2a652ff95c44de0d08f63b6b2788f19460 Mon Sep 17 00:00:00 2001 From: tamarafinogina Date: Fri, 26 Jun 2026 10:32:12 +0200 Subject: [PATCH 2/2] extend types instead of copy --- src/network/download.ts | 4 ++-- src/network/types.ts | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/network/download.ts b/src/network/download.ts index d9bf14f3..b73f4979 100644 --- a/src/network/download.ts +++ b/src/network/download.ts @@ -7,7 +7,7 @@ import { DownloadFileFunction, ToBinaryDataFunction, BinaryData, - CryptoV3, + CryptoWithBucketKey, } from './types'; export class FileVersionOneError extends Error { @@ -78,7 +78,7 @@ export async function downloadFileWithBucketKey( bucketId: string, bucketKey: Buffer, network: Network, - crypto: CryptoV3, + crypto: CryptoWithBucketKey, toBinaryData: ToBinaryDataFunction, downloadFile: DownloadFileFunction, decryptFile: DecryptFileFunction, diff --git a/src/network/types.ts b/src/network/types.ts index 66098215..17a79f6d 100644 --- a/src/network/types.ts +++ b/src/network/types.ts @@ -119,19 +119,19 @@ export const ALGORITHMS: Record = { }, }; -export type Crypto = { +type CryptoBase = { algorithm: Algorithm; - validateMnemonic: (mnemonic: string) => boolean; randomBytes: (bytesLength: number) => BinaryData; - generateFileKey: (mnemonic: string, bucketId: string, index: BinaryData | string) => Promise; computeHmac?: (key: BinaryData, shardHashes: string[]) => Promise; }; -export type CryptoV3 = { - algorithm: Algorithm; - randomBytes: (bytesLength: number) => BinaryData; +export type Crypto = CryptoBase & { + validateMnemonic: (mnemonic: string) => boolean; + generateFileKey: (mnemonic: string, bucketId: string, index: BinaryData | string) => Promise; +}; + +export type CryptoWithBucketKey = CryptoBase & { generateFileKeyFromBucketKey: (bucketKey: Buffer, index: BinaryData) => Promise; - computeHmac?: (key: BinaryData, shardHashes: string[]) => Promise; }; export type EncryptFileFunction = (