From 921df9e1aa7c6d0125e7c7554c8fe73364bc45f7 Mon Sep 17 00:00:00 2001 From: Emily Date: Mon, 9 Jul 2018 15:39:06 -0700 Subject: [PATCH] dupe network request bug --- app/api.js | 7 ++-- app/fileReceiver.js | 53 ++++++++++++++++++++++++--- app/serviceWorker.js | 50 ++++++++++++++++++++++--- app/templates/downloadButton/index.js | 1 + 4 files changed, 96 insertions(+), 15 deletions(-) diff --git a/app/api.js b/app/api.js index 2047c2c2..d87147d7 100644 --- a/app/api.js +++ b/app/api.js @@ -13,7 +13,7 @@ function post(obj) { }; } -function parseNonce(header) { +export function parseNonce(header) { header = header || ''; return header.split(' ')[1]; } @@ -162,8 +162,8 @@ async function upload( ws.send(buf); - onprogress([Math.min(streamInfo.fileSize, size), streamInfo.fileSize]); - size += streamInfo.recordSize; + onprogress([size, streamInfo.fileSize]); + size += buf.length; state = await reader.read(); while (ws.bufferedAmount > streamInfo.recordSize * 2) { await delay(); @@ -205,7 +205,6 @@ export function uploadWs(encrypted, info, metadata, verifierB64, onprogress) { async function downloadS(id, keychain, signal) { const auth = await keychain.authHeader(); - //this will be already funneled through serviceworker const response = await fetch(`/api/download/${id}`, { signal: signal, method: 'GET', diff --git a/app/fileReceiver.js b/app/fileReceiver.js index c610b76a..603cd34f 100644 --- a/app/fileReceiver.js +++ b/app/fileReceiver.js @@ -1,7 +1,7 @@ import Nanobus from 'nanobus'; import Keychain from './keychain'; -import { bytes } from './utils'; -import { metadata } from './api'; +import { delay, bytes } from './utils'; +import { parseNonce, metadata } from './api'; export default class FileReceiver extends Nanobus { constructor(fileInfo) { @@ -67,12 +67,34 @@ export default class FileReceiver extends Nanobus { return result.slice(0, offset).buffer; } + sendMessageToSw(msg) { + return new Promise( (resolve, reject) => { + const channel = new MessageChannel(); + + channel.port1.onmessage = function(event) { + if(event.data.error !== undefined) { + reject(event.data.error); + } else { + resolve(event.data); + } + } + navigator.serviceWorker.controller.postMessage(msg, [channel.port2]); + }); + } + async download(noSave = false) { const onprogress = p => { this.progress = p; this.emit('progress'); }; + this.downloadRequest = { + cancel: () => { + this.sendMessageToSw('cancel'); + //throw new Error(0); + } + } + try { this.state = 'downloading'; @@ -83,9 +105,9 @@ export default class FileReceiver extends Nanobus { filename: this.fileInfo.name, auth: auth }; - navigator.serviceWorker.controller.postMessage(info); + await this.sendMessageToSw(info); - onprogress([0, this.fileInfo.size]); + console.log("SENDING REQUEST FROM PAGE ONCE") if (!noSave) { const downloadUrl = `${location.protocol}//${ @@ -96,12 +118,31 @@ export default class FileReceiver extends Nanobus { document.body.appendChild(a); a.click(); URL.revokeObjectURL(downloadUrl); + + /* + const auth = await this.sendMessageToSw('authHeader'); + if (auth) { + this.keychain.nonce = parseNonce(auth); + } + */ + + let prog = 0; + while (prog < this.fileInfo.size) { + prog = await this.sendMessageToSw('progress'); + onprogress([prog, this.fileInfo.size]); + await delay(); + } } - //this.msg = 'downloadFinish'; - //this.state = 'complete'; + this.downloadRequest = null; + this.msg = 'downloadFinish'; + this.state = 'complete'; + } catch (e) { this.downloadRequest = null; + if (e === 'cancelled') { + throw new Error(0); + } throw e; } } diff --git a/app/serviceWorker.js b/app/serviceWorker.js index b16e8520..f6bef69e 100644 --- a/app/serviceWorker.js +++ b/app/serviceWorker.js @@ -5,17 +5,33 @@ self.addEventListener('install', event => { }); async function decryptStream(request) { + self.controller = new AbortController(); + console.log("SW INTERCEPTED DOWNLOAD") + console.log(request) const response = await fetch(request.url, { method: 'GET', - headers: { Authorization: self.auth } + headers: { Authorization: self.auth }, + signal: controller.signal }); if (response.status !== 200) { + console.log(response.status); return response; } + self.authHeader = response.headers.get('WWW-Authenticate'); + + const body = response.body; //stream - const decrypted = self.keychain.decryptStream(body); + + const progStream = new TransformStream({ + transform: (chunk, controller) => { + self.progress += chunk.length; + controller.enqueue(chunk); + } + }); + + const decrypted = self.keychain.decryptStream(body.pipeThrough(progStream)); const headers = { headers: { @@ -35,7 +51,31 @@ self.onfetch = event => { }; self.onmessage = event => { - self.keychain = new Keychain(event.data.key, event.data.nonce); - self.filename = event.data.filename; - self.auth = event.data.auth; + if (event.data.key) { + if (!self.keychain) { + self.keychain = new Keychain(event.data.key, event.data.nonce); + } + self.filename = event.data.filename; + self.auth = event.data.auth; + self.progress = 0; + self.cancelled = false; + event.ports[0].postMessage("file info received"); + + } else if (event.data === "progress") { + if (self.cancelled) { + event.ports[0].postMessage({error: "cancelled"}); + } else { + event.ports[0].postMessage(self.progress); + } + + } else if (event.data === "authHeader") { + event.ports[0].postMessage(self.authHeader); + + } else if (event.data === "cancel") { + self.cancelled = true; + if (self.controller) { + self.controller.abort(); + } + event.ports[0].postMessage("download cancelled"); + } }; diff --git a/app/templates/downloadButton/index.js b/app/templates/downloadButton/index.js index e1cac538..bcad365b 100644 --- a/app/templates/downloadButton/index.js +++ b/app/templates/downloadButton/index.js @@ -8,6 +8,7 @@ module.exports = function(state, emit) { function download(event) { event.preventDefault(); + console.log("DOWNLOAD FIRE") emit('download', state.fileInfo); } };