2018-08-08 20:07:09 +02:00
|
|
|
/* global DEFAULT_EXPIRE_SECONDS */
|
2017-08-24 23:54:02 +02:00
|
|
|
import Nanobus from 'nanobus';
|
2018-01-24 19:23:13 +01:00
|
|
|
import OwnedFile from './ownedFile';
|
|
|
|
import Keychain from './keychain';
|
|
|
|
import { arrayToB64, bytes } from './utils';
|
2018-06-21 02:05:33 +02:00
|
|
|
import { uploadWs } from './api';
|
2018-07-26 07:26:11 +02:00
|
|
|
import { encryptedSize } from './ece';
|
2017-12-08 18:45:00 +01:00
|
|
|
|
2017-08-24 23:54:02 +02:00
|
|
|
export default class FileSender extends Nanobus {
|
2018-08-08 20:07:09 +02:00
|
|
|
constructor(file, timeLimit) {
|
2017-08-24 23:54:02 +02:00
|
|
|
super('FileSender');
|
2018-08-08 20:07:09 +02:00
|
|
|
this.timeLimit = timeLimit || DEFAULT_EXPIRE_SECONDS;
|
2017-06-02 05:59:27 +02:00
|
|
|
this.file = file;
|
2018-01-24 19:23:13 +01:00
|
|
|
this.keychain = new Keychain();
|
2018-02-24 20:24:12 +01:00
|
|
|
this.reset();
|
2017-06-02 05:59:27 +02:00
|
|
|
}
|
|
|
|
|
2017-08-24 23:54:02 +02:00
|
|
|
get progressRatio() {
|
|
|
|
return this.progress[0] / this.progress[1];
|
|
|
|
}
|
|
|
|
|
2018-02-21 22:59:06 +01:00
|
|
|
get progressIndefinite() {
|
|
|
|
return ['fileSizeProgress', 'notifyUploadDone'].indexOf(this.msg) === -1;
|
|
|
|
}
|
|
|
|
|
2017-08-24 23:54:02 +02:00
|
|
|
get sizes() {
|
|
|
|
return {
|
|
|
|
partialSize: bytes(this.progress[0]),
|
|
|
|
totalSize: bytes(this.progress[1])
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-02-24 20:24:12 +01:00
|
|
|
reset() {
|
|
|
|
this.uploadRequest = null;
|
|
|
|
this.msg = 'importingFile';
|
|
|
|
this.progress = [0, 1];
|
|
|
|
this.cancelled = false;
|
|
|
|
}
|
|
|
|
|
2017-07-18 19:52:32 +02:00
|
|
|
cancel() {
|
2017-08-24 23:54:02 +02:00
|
|
|
this.cancelled = true;
|
2018-01-24 19:23:13 +01:00
|
|
|
if (this.uploadRequest) {
|
|
|
|
this.uploadRequest.cancel();
|
2017-08-24 23:54:02 +02:00
|
|
|
}
|
2017-07-18 19:52:32 +02:00
|
|
|
}
|
|
|
|
|
2017-08-14 21:04:03 +02:00
|
|
|
readFile() {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
const reader = new FileReader();
|
|
|
|
reader.readAsArrayBuffer(this.file);
|
2018-01-24 19:23:13 +01:00
|
|
|
// TODO: progress?
|
2017-08-14 21:04:03 +02:00
|
|
|
reader.onload = function(event) {
|
|
|
|
const plaintext = new Uint8Array(this.result);
|
|
|
|
resolve(plaintext);
|
|
|
|
};
|
|
|
|
reader.onerror = function(err) {
|
|
|
|
reject(err);
|
|
|
|
};
|
|
|
|
});
|
|
|
|
}
|
2017-06-02 05:59:27 +02:00
|
|
|
|
2018-01-31 20:12:36 +01:00
|
|
|
async upload() {
|
2018-01-24 19:23:13 +01:00
|
|
|
const start = Date.now();
|
2017-08-24 23:54:02 +02:00
|
|
|
if (this.cancelled) {
|
|
|
|
throw new Error(0);
|
|
|
|
}
|
|
|
|
this.msg = 'encryptingFile';
|
2017-08-14 21:04:03 +02:00
|
|
|
this.emit('encrypting');
|
2018-07-26 07:26:11 +02:00
|
|
|
const totalSize = encryptedSize(this.file.size);
|
|
|
|
const encStream = await this.keychain.encryptStream(this.file.stream);
|
2018-01-24 19:23:13 +01:00
|
|
|
const metadata = await this.keychain.encryptMetadata(this.file);
|
|
|
|
const authKeyB64 = await this.keychain.authKeyB64();
|
2018-06-21 02:05:33 +02:00
|
|
|
|
2018-08-08 20:07:09 +02:00
|
|
|
this.uploadRequest = uploadWs(
|
|
|
|
encStream,
|
|
|
|
metadata,
|
|
|
|
authKeyB64,
|
|
|
|
p => {
|
|
|
|
this.progress = [p, totalSize];
|
|
|
|
this.emit('progress');
|
|
|
|
},
|
|
|
|
this.timeLimit
|
|
|
|
);
|
2018-06-21 02:05:33 +02:00
|
|
|
|
|
|
|
if (this.cancelled) {
|
|
|
|
throw new Error(0);
|
|
|
|
}
|
|
|
|
|
2018-01-24 19:23:13 +01:00
|
|
|
this.msg = 'fileSizeProgress';
|
2018-03-12 20:24:09 +01:00
|
|
|
this.emit('progress'); // HACK to kick MS Edge
|
2017-12-08 18:45:00 +01:00
|
|
|
try {
|
2018-01-24 19:23:13 +01:00
|
|
|
const result = await this.uploadRequest.result;
|
|
|
|
const time = Date.now() - start;
|
|
|
|
this.msg = 'notifyUploadDone';
|
|
|
|
this.uploadRequest = null;
|
|
|
|
this.progress = [1, 1];
|
|
|
|
const secretKey = arrayToB64(this.keychain.rawSecret);
|
2018-01-31 20:12:36 +01:00
|
|
|
const ownedFile = new OwnedFile({
|
|
|
|
id: result.id,
|
|
|
|
url: `${result.url}#${secretKey}`,
|
|
|
|
name: this.file.name,
|
|
|
|
size: this.file.size,
|
2018-07-31 20:09:18 +02:00
|
|
|
manifest: this.file.manifest,
|
2018-01-31 20:12:36 +01:00
|
|
|
time: time,
|
|
|
|
speed: this.file.size / (time / 1000),
|
|
|
|
createdAt: Date.now(),
|
2018-08-08 20:07:09 +02:00
|
|
|
expiresAt: Date.now() + this.timeLimit * 1000,
|
2018-01-31 20:12:36 +01:00
|
|
|
secretKey: secretKey,
|
|
|
|
nonce: this.keychain.nonce,
|
2018-08-08 20:07:09 +02:00
|
|
|
ownerToken: result.ownerToken,
|
|
|
|
timeLimit: this.timeLimit
|
2018-01-31 20:12:36 +01:00
|
|
|
});
|
2018-07-31 20:09:18 +02:00
|
|
|
|
2018-01-24 19:23:13 +01:00
|
|
|
return ownedFile;
|
2017-12-08 18:45:00 +01:00
|
|
|
} catch (e) {
|
2018-01-24 19:23:13 +01:00
|
|
|
this.msg = 'errorPageHeader';
|
|
|
|
this.uploadRequest = null;
|
|
|
|
throw e;
|
2017-12-08 18:45:00 +01:00
|
|
|
}
|
2017-06-02 05:59:27 +02:00
|
|
|
}
|
|
|
|
}
|