From 3138f111e15698af09e690bf3abc7a1cf28f0217 Mon Sep 17 00:00:00 2001 From: Abhinav Adduri Date: Wed, 12 Jul 2017 09:01:31 -0700 Subject: [PATCH 1/3] fixes delete button error --- frontend/src/fileSender.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/fileSender.js b/frontend/src/fileSender.js index 47b63e94..1fdf149c 100644 --- a/frontend/src/fileSender.js +++ b/frontend/src/fileSender.js @@ -117,7 +117,7 @@ class FileSender extends EventEmitter { url: responseObj.url, fileId: responseObj.id, secretKey: keydata.k, - deleteToken: responseObj.uuid + deleteToken: responseObj.delete }); } }; From b32e63c3053d8486ce9ae88fb653ee28bd151f00 Mon Sep 17 00:00:00 2001 From: Danny Coates Date: Wed, 12 Jul 2017 10:53:29 -0700 Subject: [PATCH 2/3] reformat --- frontend/src/download.js | 12 ++--- frontend/src/fileReceiver.js | 86 ++++++++++++++++++++---------------- frontend/src/fileSender.js | 13 +++--- frontend/src/upload.js | 16 +++---- frontend/src/utils.js | 48 +++++++++++--------- server/server.js | 66 ++++++++++++++------------- server/storage.js | 4 +- 7 files changed, 133 insertions(+), 112 deletions(-) diff --git a/frontend/src/download.js b/frontend/src/download.js index 00208085..0bc34a04 100644 --- a/frontend/src/download.js +++ b/frontend/src/download.js @@ -37,20 +37,20 @@ $(document).ready(function() { fileReceiver.on('decrypting', isStillDecrypting => { // The file is being decrypted if (isStillDecrypting) { - console.log('Decrypting') + console.log('Decrypting'); } else { - console.log('Done decrypting') + console.log('Done decrypting'); } - }) + }); fileReceiver.on('hashing', isStillHashing => { // The file is being hashed to make sure a malicious user hasn't tampered with it if (isStillHashing) { - console.log('Checking file integrity') + console.log('Checking file integrity'); } else { - console.log('Integrity check done') + console.log('Integrity check done'); } - }) + }); fileReceiver .download() diff --git a/frontend/src/fileReceiver.js b/frontend/src/fileReceiver.js index 0404bda8..17b5393f 100644 --- a/frontend/src/fileReceiver.js +++ b/frontend/src/fileReceiver.js @@ -61,52 +61,60 @@ class FileReceiver extends EventEmitter { true, ['encrypt', 'decrypt'] ) - ]).then(([fdata, key]) => { - this.emit('decrypting', true); - return Promise.all([ - window.crypto.subtle.decrypt( - { - name: 'AES-GCM', - iv: hexToArray(fdata.iv), - additionalData: hexToArray(fdata.aad) - }, - key, - fdata.data - ).then(decrypted => { - this.emit('decrypting', false); - return new Promise((resolve, reject) => { - resolve(decrypted); - }) - }), - new Promise((resolve, reject) => { - resolve(fdata.filename); - }), - new Promise((resolve, reject) => { - resolve(hexToArray(fdata.aad)); - }) - ]); - }).then(([decrypted, fname, proposedHash]) => { - this.emit('hashing', true); - return window.crypto.subtle.digest('SHA-256', decrypted).then(calculatedHash => { - this.emit('hashing', false); - const integrity = new Uint8Array(calculatedHash).toString() === proposedHash.toString(); - if (!integrity) { - return new Promise((resolve, reject) => { - console.log('This file has been tampered with.') - reject(); - }) - } - + ]) + .then(([fdata, key]) => { + this.emit('decrypting', true); return Promise.all([ + window.crypto.subtle + .decrypt( + { + name: 'AES-GCM', + iv: hexToArray(fdata.iv), + additionalData: hexToArray(fdata.aad) + }, + key, + fdata.data + ) + .then(decrypted => { + this.emit('decrypting', false); + return new Promise((resolve, reject) => { + resolve(decrypted); + }); + }), new Promise((resolve, reject) => { - resolve(decrypted); + resolve(fdata.filename); }), new Promise((resolve, reject) => { - resolve(fname); + resolve(hexToArray(fdata.aad)); }) ]); }) - }) + .then(([decrypted, fname, proposedHash]) => { + this.emit('hashing', true); + return window.crypto.subtle + .digest('SHA-256', decrypted) + .then(calculatedHash => { + this.emit('hashing', false); + const integrity = + new Uint8Array(calculatedHash).toString() === + proposedHash.toString(); + if (!integrity) { + return new Promise((resolve, reject) => { + console.log('This file has been tampered with.'); + reject(); + }); + } + + return Promise.all([ + new Promise((resolve, reject) => { + resolve(decrypted); + }), + new Promise((resolve, reject) => { + resolve(fname); + }) + ]); + }); + }); } } diff --git a/frontend/src/fileSender.js b/frontend/src/fileSender.js index 1fdf149c..888e1de4 100644 --- a/frontend/src/fileSender.js +++ b/frontend/src/fileSender.js @@ -61,8 +61,8 @@ class FileSender extends EventEmitter { window.crypto.subtle.digest('SHA-256', plaintext).then(hash => { self.emit('hashing', false); self.emit('encrypting', true); - resolve({plaintext: plaintext, hash: new Uint8Array(hash)}); - }) + resolve({ plaintext: plaintext, hash: new Uint8Array(hash) }); + }); }; reader.onerror = function(err) { reject(err); @@ -81,14 +81,17 @@ class FileSender extends EventEmitter { }, secretKey, file.plaintext - ).then(encrypted => { + ) + .then(encrypted => { self.emit('encrypting', false); return new Promise((resolve, reject) => { resolve(encrypted); - }) + }); }), window.crypto.subtle.exportKey('jwk', secretKey), - new Promise((resolve, reject) => { resolve(file.hash) }) + new Promise((resolve, reject) => { + resolve(file.hash); + }) ]); }) .then(([encrypted, keydata, hash]) => { diff --git a/frontend/src/upload.js b/frontend/src/upload.js index f91c09b6..08adb6e0 100644 --- a/frontend/src/upload.js +++ b/frontend/src/upload.js @@ -8,7 +8,7 @@ $(document).ready(function() { gcmCompliant().catch(err => { $('#page-one').hide(); $('#compliance-error').show(); - }) + }); // reset copy button const $copyBtn = $('#copy-btn'); @@ -88,29 +88,29 @@ $(document).ready(function() { fileSender.on('loading', isStillLoading => { // The file is loading into Firefox at this stage if (isStillLoading) { - console.log('Processing') + console.log('Processing'); } else { - console.log('Finished processing') + console.log('Finished processing'); } - }) + }); fileSender.on('hashing', isStillHashing => { // The file is being hashed if (isStillHashing) { console.log('Hashing'); } else { - console.log('Finished hashing') + console.log('Finished hashing'); } - }) + }); fileSender.on('encrypting', isStillEncrypting => { // The file is being encrypted if (isStillEncrypting) { console.log('Encrypting'); } else { - console.log('Finished encrypting') + console.log('Finished encrypting'); } - }) + }); fileSender .upload() diff --git a/frontend/src/utils.js b/frontend/src/utils.js index af0c9c99..e1e7531d 100644 --- a/frontend/src/utils.js +++ b/frontend/src/utils.js @@ -34,34 +34,38 @@ function notify(str) { function gcmCompliant() { try { - return window.crypto.subtle.generateKey( - { - name: 'AES-GCM', - length: 128 - }, - true, - ['encrypt', 'decrypt'] - ).then(key => { - return window.crypto.subtle.encrypt( + return window.crypto.subtle + .generateKey( { name: 'AES-GCM', - iv: window.crypto.getRandomValues(new Uint8Array(12)), - additionalData: window.crypto.getRandomValues(new Uint8Array(6)), - tagLength: 128 + length: 128 }, - key, - new ArrayBuffer(8) + true, + ['encrypt', 'decrypt'] ) - .then(() => { - return Promise.resolve() + .then(key => { + return window.crypto.subtle + .encrypt( + { + name: 'AES-GCM', + iv: window.crypto.getRandomValues(new Uint8Array(12)), + additionalData: window.crypto.getRandomValues(new Uint8Array(6)), + tagLength: 128 + }, + key, + new ArrayBuffer(8) + ) + .then(() => { + return Promise.resolve(); + }) + .catch(err => { + return Promise.reject(); + }); }) .catch(err => { - return Promise.reject() - }) - }).catch(err => { - return Promise.reject(); - }) - } catch(err) { + return Promise.reject(); + }); + } catch (err) { return Promise.reject(); } } diff --git a/server/server.js b/server/server.js index 50696275..4f80c4ee 100644 --- a/server/server.js +++ b/server/server.js @@ -92,33 +92,35 @@ app.get('/assets/download/:id', (req, res) => { storage .metadata(id) .then(meta => { - storage.length(id).then(contentLength => { - res.writeHead(200, { - 'Content-Disposition': 'attachment; filename=' + meta.filename, - 'Content-Type': 'application/octet-stream', - 'Content-Length': contentLength, - 'X-File-Metadata': JSON.stringify(meta) - }); - const file_stream = storage.get(id); + storage + .length(id) + .then(contentLength => { + res.writeHead(200, { + 'Content-Disposition': 'attachment; filename=' + meta.filename, + 'Content-Type': 'application/octet-stream', + 'Content-Length': contentLength, + 'X-File-Metadata': JSON.stringify(meta) + }); + const file_stream = storage.get(id); - file_stream.on('end', () => { - storage - .forceDelete(id) - .then(err => { - if (!err) { - log.info('Deleted:', id); - } - }) - .catch(err => { - log.info('DeleteError:', id); - }); - }); + file_stream.on('end', () => { + storage + .forceDelete(id) + .then(err => { + if (!err) { + log.info('Deleted:', id); + } + }) + .catch(err => { + log.info('DeleteError:', id); + }); + }); - file_stream.pipe(res); - }) - .catch(err => { - res.sendStatus(404); - }); + file_stream.pipe(res); + }) + .catch(err => { + res.sendStatus(404); + }); }) .catch(err => { res.sendStatus(404); @@ -157,15 +159,17 @@ app.post('/upload', (req, res, next) => { try { meta = JSON.parse(req.header('X-File-Metadata')); - } catch(err) { + } catch (err) { res.sendStatus(400); return; } - if (!validateIV(meta.id) || - !meta.hasOwnProperty('aad') || - !meta.hasOwnProperty('id') || - !meta.hasOwnProperty('filename')) { + if ( + !validateIV(meta.id) || + !meta.hasOwnProperty('aad') || + !meta.hasOwnProperty('id') || + !meta.hasOwnProperty('filename') + ) { res.sendStatus(404); return; } @@ -216,4 +220,4 @@ const validateIV = route_id => { module.exports = { server: server, storage: storage -} +}; diff --git a/server/storage.js b/server/storage.js index b03cbbaf..5d48b490 100644 --- a/server/storage.js +++ b/server/storage.js @@ -129,7 +129,9 @@ function localGet(id) { function localSet(newId, file, filename, meta) { return new Promise((resolve, reject) => { - const fstream = fs.createWriteStream(path.join(__dirname, '../static', newId)); + const fstream = fs.createWriteStream( + path.join(__dirname, '../static', newId) + ); file.pipe(fstream); fstream.on('close', () => { redis_client.hmset(newId, meta); From 9234bce75de6fac604ac6a5d90dba560ef0d5ac4 Mon Sep 17 00:00:00 2001 From: Danny Coates Date: Wed, 12 Jul 2017 10:56:04 -0700 Subject: [PATCH 3/3] added csp directives --- frontend/src/download.js | 7 +++---- frontend/src/upload.js | 12 +++++++----- server/server.js | 24 ++++++++++++++++++++++++ views/download.handlebars | 2 +- views/index.handlebars | 4 ++-- 5 files changed, 37 insertions(+), 12 deletions(-) diff --git a/frontend/src/download.js b/frontend/src/download.js index 0bc34a04..f16adf40 100644 --- a/frontend/src/download.js +++ b/frontend/src/download.js @@ -9,7 +9,8 @@ $(document).ready(function() { $('#send-file').click(() => { window.location.replace(`${window.location.origin}`); }); - const download = () => { + $('#download-btn').click(download); + function download() { const fileReceiver = new FileReceiver(); const name = document.createElement('p'); const $btn = $('#download-btn'); @@ -84,7 +85,5 @@ $(document).ready(function() { Raven.captureException(err); return Promise.reject(err); }); - }; - - window.download = download; + } }); diff --git a/frontend/src/upload.js b/frontend/src/upload.js index 08adb6e0..69935376 100644 --- a/frontend/src/upload.js +++ b/frontend/src/upload.js @@ -10,6 +10,8 @@ $(document).ready(function() { $('#compliance-error').show(); }); + $('#file-upload').change(onUpload); + $('#page-one').on('dragover', allowDrop).on('drop', onUpload); // reset copy button const $copyBtn = $('#copy-btn'); $copyBtn.attr('disabled', false); @@ -61,11 +63,11 @@ $(document).ready(function() { }); // on file upload by browse or drag & drop - window.onUpload = event => { + function onUpload(event) { event.preventDefault(); let file = ''; if (event.type === 'drop') { - file = event.dataTransfer.files[0]; + file = event.originalEvent.dataTransfer.files[0]; } else { file = event.target.files[0]; } @@ -143,11 +145,11 @@ $(document).ready(function() { $('#page-one').hide(); $('#upload-error').show(); }); - }; + } - window.allowDrop = function(ev) { + function allowDrop(ev) { ev.preventDefault(); - }; + } function checkExistence(id, populate) { const xhr = new XMLHttpRequest(); diff --git a/server/server.js b/server/server.js index 4f80c4ee..e3c838a0 100644 --- a/server/server.js +++ b/server/server.js @@ -32,6 +32,30 @@ app.engine( app.set('view engine', 'handlebars'); app.use(helmet()); +app.use( + helmet.contentSecurityPolicy({ + directives: { + defaultSrc: ['\'self\''], + connectSrc: [ + '\'self\'', + 'https://sentry.prod.mozaws.net', + 'https://www.google-analytics.com', + 'https://ssl.google-analytics.com' + ], + imgSrc: [ + '\'self\'', + 'https://www.google-analytics.com', + 'https://ssl.google-analytics.com' + ], + scriptSrc: ['\'self\'', 'https://ssl.google-analytics.com'], + styleSrc: ['\'self\'', 'https://code.cdn.mozilla.net'], + fontSrc: ['\'self\'', 'https://code.cdn.mozilla.net'], + formAction: ['\'none\''], + frameAncestors: ['\'none\''], + objectSrc: ['\'none\''] + } + }) +); app.use(busboy()); app.use(bodyParser.json()); app.use(express.static(STATIC_PATH)); diff --git a/views/download.handlebars b/views/download.handlebars index ba6cf5c5..50cc365a 100644 --- a/views/download.handlebars +++ b/views/download.handlebars @@ -23,7 +23,7 @@
- +
diff --git a/views/index.handlebars b/views/index.handlebars index 8be8f2d5..b34a9e80 100644 --- a/views/index.handlebars +++ b/views/index.handlebars @@ -19,7 +19,7 @@
Share your files quickly, privately and securely.
-
+
Upload
DRAG & DROP @@ -31,7 +31,7 @@
- +