diff --git a/frontend/src/download.js b/frontend/src/download.js index 00208085..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'); @@ -37,20 +38,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() @@ -84,7 +85,5 @@ $(document).ready(function() { Raven.captureException(err); return Promise.reject(err); }); - }; - - window.download = download; + } }); 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..69935376 100644 --- a/frontend/src/upload.js +++ b/frontend/src/upload.js @@ -8,8 +8,10 @@ $(document).ready(function() { gcmCompliant().catch(err => { $('#page-one').hide(); $('#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]; } @@ -88,29 +90,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() @@ -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/frontend/src/utils.js b/frontend/src/utils.js index 7b57306b..aff37488 100644 --- a/frontend/src/utils.js +++ b/frontend/src/utils.js @@ -33,34 +33,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..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)); @@ -92,33 +116,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 +183,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 +244,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); 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 @@
- +