123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- 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 progressIndefinite() {
- return this.state !== 'downloading';
- }
- get sizes() {
- return {
- partialSize: bytes(this.progress[0]),
- totalSize: bytes(this.progress[1])
- };
- }
- cancel() {
- if (this.downloadRequest) {
- this.downloadRequest.cancel();
- }
- }
- reset() {
- this.msg = 'fileSizeProgress';
- this.state = 'initialized';
- this.progress = [0, 1];
- }
- async getMetadata() {
- const meta = await metadata(this.fileInfo.id, this.keychain);
- 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';
- }
- async download(noSave = false) {
- this.state = 'downloading';
- this.downloadRequest = await downloadFile(
- this.fileInfo.id,
- this.keychain,
- p => {
- this.progress = p;
- this.emit('progress');
- }
- );
- try {
- const ciphertext = await this.downloadRequest.result;
- this.downloadRequest = null;
- this.msg = 'decryptingFile';
- this.state = 'decrypting';
- this.emit('decrypting');
- const plaintext = await this.keychain.decryptFile(ciphertext);
- if (!noSave) {
- await saveFile({
- plaintext,
- name: decodeURIComponent(this.fileInfo.name),
- type: this.fileInfo.type
- });
- }
- this.msg = 'downloadFinish';
- this.state = 'complete';
- } catch (e) {
- this.downloadRequest = null;
- throw e;
- }
- }
- }
- async function saveFile(file) {
- return new Promise(function(resolve, reject) {
- const dataView = new DataView(file.plaintext);
- const blob = new Blob([dataView], { type: file.type });
- if (navigator.msSaveBlob) {
- navigator.msSaveBlob(blob, file.name);
- return resolve();
- } else if (/iPhone|fxios/i.test(navigator.userAgent)) {
- // This method is much slower but createObjectURL
- // is buggy on iOS
- const reader = new FileReader();
- reader.addEventListener('loadend', function() {
- if (reader.error) {
- return reject(reader.error);
- }
- if (reader.result) {
- const a = document.createElement('a');
- a.href = reader.result;
- a.download = file.name;
- document.body.appendChild(a);
- a.click();
- }
- resolve();
- });
- reader.readAsDataURL(blob);
- } else {
- const downloadUrl = URL.createObjectURL(blob);
- const a = document.createElement('a');
- a.href = downloadUrl;
- a.download = file.name;
- document.body.appendChild(a);
- a.click();
- URL.revokeObjectURL(downloadUrl);
- setTimeout(resolve, 100);
- }
- });
- }
|