UNPKG

@sentclose/sentc-nodejs

Version:

End-to-end encryption sdk

185 lines (184 loc) 7.29 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Downloader = exports.findAvailableFileName = void 0; /** * @author Jörn Heinemann <joernheinemann@gmx.de> * @since 2022/08/27 */ const Mutex_1 = require("./Mutex"); const Sentc_1 = require("../Sentc"); const sentc_node_js_1 = require("@sentclose/sentc_node_js"); const promises_1 = require("node:fs/promises"); const path = require("path"); async function findAvailableFileName(file_path) { const { name, dir, ext } = path.parse(file_path); let file_name = path.join(dir, name, ext); for (let i = 1; i < 20; i++) { try { // eslint-disable-next-line no-await-in-loop await (0, promises_1.access)(file_name, promises_1.constants.W_OK); file_name = path.join(dir, `${name}(${i})`, ext); } catch (e) { return file_name; } } } exports.findAvailableFileName = findAvailableFileName; class Downloader { static init() { if (this.is_init) { return; } this.is_init = true; this.mutex = new Mutex_1.Mutex(); } constructor(base_url, app_token, user, group_id, group_as_member) { //the base url can be different when serving the files from a different storage this.base_url = base_url; this.app_token = app_token; this.user = user; this.group_id = group_id; this.group_as_member = group_as_member; Downloader.init(); } /** * Get the file info and the first page of the file part list * * @param file_id */ async downloadFileMetaInformation(file_id) { const jwt = await this.user.getJwt(); const out = await (0, sentc_node_js_1.fileDownloadFileMeta)(this.base_url, this.app_token, jwt, file_id, this.group_id, this.group_as_member); const part_list = []; for (let i = 0; i < out.partList.length; i++) { const part = out.partList[i]; part_list.push({ part_id: part.partId, extern_storage: part.externStorage, sequence: part.sequence }); } const file_meta = { file_id: out.fileId, belongs_to: out.belongsTo, belongs_to_type: out.belongsToType, encrypted_file_name: out.encryptedFileName, encrypted_key: out.encryptedKey, encrypted_key_alg: out.encryptedKeyAlg, key_id: out.masterKeyId, master_key_id: out.masterKeyId, part_list }; if (part_list.length >= 500) { //download parts via pagination let last_item = part_list[part_list.length - 1]; let next_fetch = true; while (next_fetch) { // eslint-disable-next-line no-await-in-loop const fetched_parts = await this.downloadFilePartList(file_id, last_item); part_list.push(...fetched_parts); next_fetch = fetched_parts.length >= 500; last_item = fetched_parts[fetched_parts.length - 1]; } } return { belongs_to: file_meta.belongs_to, belongs_to_type: file_meta.belongs_to_type, file_id: file_meta.file_id, master_key_id: file_meta.master_key_id, encrypted_key: file_meta.encrypted_key, encrypted_key_alg: file_meta.encrypted_key_alg, part_list, encrypted_file_name: file_meta.encrypted_file_name }; } /** * Download the rest of the part list via pagination * * @param file_id * @param last_item */ async downloadFilePartList(file_id, last_item = null) { var _a; const last_seq = (_a = (last_item === null || last_item === void 0 ? void 0 : last_item.sequence) + "") !== null && _a !== void 0 ? _a : ""; const out = await (0, sentc_node_js_1.fileDownloadPartList)(this.base_url, this.app_token, file_id, last_seq); const part_list = []; for (let i = 0; i < out.length; i++) { const part = out[i]; part_list.push({ part_id: part.partId, extern_storage: part.externStorage, sequence: part.sequence }); } return part_list; } async downloadFileParts(fileHandle, part_list, content_key, updateProgressCb, verify_key) { var _a, _b; const unlock = await Downloader.mutex.lock(); Downloader.cancel_download = false; const url_prefix = (_b = (_a = Sentc_1.Sentc.options) === null || _a === void 0 ? void 0 : _a.file_part_url) !== null && _b !== void 0 ? _b : undefined; let next_file_key = content_key; let offset = 0; for (let i = 0; i < part_list.length; i++) { const external = part_list[i].extern_storage === true; const part_url_base = (external) ? url_prefix : undefined; let part; try { if (i === 0) { //first part // eslint-disable-next-line no-await-in-loop const res = await (0, sentc_node_js_1.fileDownloadAndDecryptFilePartStart)(this.base_url, part_url_base, this.app_token, part_list[i].part_id, content_key, verify_key); next_file_key = res.nextFileKey; part = res.file; } else { // eslint-disable-next-line no-await-in-loop const res = await (0, sentc_node_js_1.fileDownloadAndDecryptFilePart)(this.base_url, part_url_base, this.app_token, part_list[i].part_id, next_file_key, verify_key); next_file_key = res.nextFileKey; part = res.file; } } catch (e) { // eslint-disable-next-line no-await-in-loop unlock(); throw e; } if (!part) { // eslint-disable-next-line no-await-in-loop unlock(); throw Error("Part not found"); } // eslint-disable-next-line no-await-in-loop await fileHandle.write(part, 0, part.length, offset); offset += part.length; if (updateProgressCb) { updateProgressCb((i + 1) / part_list.length); } if (Downloader.cancel_download) { Downloader.cancel_download = false; // eslint-disable-next-line no-await-in-loop unlock(); return; } } unlock(); } async downloadFilePartsWithPath(path, part_list, content_key, updateProgressCb, verify_key) { const file_handle = await (0, promises_1.open)(path, "a"); try { await this.downloadFileParts(file_handle, part_list, content_key, updateProgressCb, verify_key); } catch (e) { await (0, promises_1.unlink)(path); throw e; } finally { await file_handle.close(); } } } exports.Downloader = Downloader; Downloader.is_init = false; Downloader.cancel_download = false;