import Nanobus from 'nanobus'; import Keychain from './keychain'; import { bytes } from './utils'; import { metadata, downloadFile } from './api'; export default class FileReceiver extends Nanobus { constructor(fileInfo) { super('FileReceiver'); this.keychain = new Keychain(fileInfo.secretKey, fileInfo.nonce); if (fileInfo.requiresPassword) { this.keychain.setPassword(fileInfo.password, fileInfo.url); } this.fileInfo = fileInfo; this.reset(); } get progressRatio() { return this.progress[0] / this.progress[1]; } get sizes() { return { partialSize: bytes(this.progress[0]), totalSize: bytes(this.progress[1]) }; } cancel() { this.cancelled = true; if (this.fileDownload) { this.fileDownload.cancel(); } } reset() { this.fileDownload = null; this.msg = 'fileSizeProgress'; this.state = 'initialized'; this.progress = [0, 1]; this.cancelled = false; } async getMetadata() { const meta = await metadata(this.fileInfo.id, this.keychain); if (meta) { this.keychain.setIV(meta.iv); this.fileInfo.name = meta.name; this.fileInfo.type = meta.type; this.fileInfo.iv = meta.iv; this.fileInfo.size = meta.size; this.state = 'ready'; return; } this.state = 'invalid'; return; } async download() { this.state = 'downloading'; this.emit('progress', this.progress); try { const download = await downloadFile(this.fileInfo.id, this.keychain); download.onprogress = p => { this.progress = p; this.emit('progress', p); }; this.fileDownload = download; const ciphertext = await download.result; this.fileDownload = null; this.msg = 'decryptingFile'; this.state = 'decrypting'; this.emit('decrypting'); const plaintext = await this.keychain.decryptFile(ciphertext); if (this.cancelled) { throw new Error(0); } this.msg = 'downloadFinish'; this.state = 'complete'; return { plaintext, name: decodeURIComponent(this.fileInfo.name), type: this.fileInfo.type }; } catch (e) { this.state = 'invalid'; throw e; } } }