From c25c97fbaa9fdcebfb8f866e2b3457586d7cd9c4 Mon Sep 17 00:00:00 2001 From: Abhinav Adduri Date: Wed, 31 May 2017 11:19:59 -0700 Subject: [PATCH] separated file into upload and download files, changed single quotes to double quotes, added progress indicator --- app.js | 40 ++++++------ public/download.html | 5 +- public/download.js | 96 ++++++++++++++++++++++++++++ public/file.js | 149 ------------------------------------------- public/index.html | 11 ++-- public/upload.js | 88 +++++++++++++++++++++++++ 6 files changed, 212 insertions(+), 177 deletions(-) create mode 100644 public/download.js delete mode 100644 public/file.js create mode 100644 public/upload.js diff --git a/app.js b/app.js index 43cad4bf..6f2670b4 100644 --- a/app.js +++ b/app.js @@ -1,40 +1,40 @@ -const express = require('express') -var busboy = require('connect-busboy'); //middleware for form/file upload -var path = require('path'); //used for file path -var fs = require('fs-extra'); //File System - for file manipulation +const express = require("express") +var busboy = require("connect-busboy"); //middleware for form/file upload +var path = require("path"); //used for file path +var fs = require("fs-extra"); //File System - for file manipulation const app = express() var redis = require("redis"), client = redis.createClient(); -client.on('error', function(err) { +client.on("error", function(err) { console.log(err); }) app.use(busboy()); -app.use(express.static(path.join(__dirname, 'public'))); +app.use(express.static(path.join(__dirname, "public"))); -app.get('/', function (req, res) { - res.send('Hello World!') +app.get("/", function (req, res) { + res.send("Hello World!") }) -app.get('/download/:id', function(req, res) { - res.sendFile(path.join(__dirname + '/public/download.html')); +app.get("/download/:id", function(req, res) { + res.sendFile(path.join(__dirname + "/public/download.html")); }); -app.get('/assets/download/:id', function(req, res) { +app.get("/assets/download/:id", function(req, res) { let id = req.params.id; client.hget(id, "filename", function(err, reply) { // maybe some expiration logic too if (!reply) { res.sendStatus(404); } else { - res.setHeader('Content-Disposition', 'attachment; filename=' + reply); - res.setHeader('Content-Type', 'application/octet-stream'); + res.setHeader("Content-Disposition", "attachment; filename=" + reply); + res.setHeader("Content-Type", "application/octet-stream"); - res.download(__dirname + '/static/' + id, reply, function(err) { + res.download(__dirname + "/static/" + id, reply, function(err) { if (!err) { client.del(id); - fs.unlinkSync(__dirname + '/static/' + id); + fs.unlinkSync(__dirname + "/static/" + id); } }); } @@ -42,18 +42,18 @@ app.get('/assets/download/:id', function(req, res) { }); -app.route('/upload/:id') +app.route("/upload/:id") .post(function (req, res, next) { var fstream; req.pipe(req.busboy); - req.busboy.on('file', function (fieldname, file, filename) { + req.busboy.on("file", function (fieldname, file, filename) { console.log("Uploading: " + filename); //Path where image will be uploaded - fstream = fs.createWriteStream(__dirname + '/static/' + req.params.id); + fstream = fs.createWriteStream(__dirname + "/static/" + req.params.id); file.pipe(fstream); - fstream.on('close', function () { + fstream.on("close", function () { let id = req.params.id; client.hset(id, "filename", filename, redis.print); client.hset(id, "expiration", 0, redis.print); @@ -67,6 +67,6 @@ app.route('/upload/:id') app.listen(3000, function () { - console.log('Portal app listening on port 3000!') + console.log("Portal app listening on port 3000!") }) diff --git a/public/download.html b/public/download.html index c301659f..ed96249b 100644 --- a/public/download.html +++ b/public/download.html @@ -2,11 +2,12 @@ Download your file - + - + +

diff --git a/public/download.js b/public/download.js new file mode 100644 index 00000000..93fc5f3e --- /dev/null +++ b/public/download.js @@ -0,0 +1,96 @@ +function download() { + + var xhr = new XMLHttpRequest(); + xhr.open("get", "/assets" + location.pathname.slice(0, -1), true); + xhr.responseType = "blob"; + + xhr.addEventListener("progress", updateProgress); + + xhr.onload = function(e) { + if (this.status == 200) { + let self = this; + var blob = new Blob([this.response]); + var arrayBuffer; + var fileReader = new FileReader(); + fileReader.onload = function() { + arrayBuffer = this.result; + var array = new Uint8Array(arrayBuffer); + salt = strToIv(location.pathname.slice(10, -1)); + + window.crypto.subtle.importKey( + "jwk", + { + kty: "oct", + k: location.hash.slice(1), + alg: "A128CBC", + ext: true, + }, + { + name: "AES-CBC", + }, + true, + ["encrypt", "decrypt"]) + .then(function(key){ + window.crypto.subtle.decrypt( + { + name: "AES-CBC", + iv: salt, + }, + key, + array) + .then(function(decrypted){ + var dataView = new DataView(decrypted); + var blob = new Blob([dataView]); + var downloadUrl = URL.createObjectURL(blob); + var a = document.createElement("a"); + a.href = downloadUrl; + a.download = xhr.getResponseHeader("Content-Disposition").match(/filename="(.+)"/)[1]; + console.log(xhr.getResponseHeader("Content-Disposition")); + document.body.appendChild(a); + a.click(); + }) + .catch(function(err){ + alert("This link is either invalid or has expired."); + console.error(err); + }); + }) + .catch(function(err){ + console.error(err); + }); + }; + fileReader.readAsArrayBuffer(blob); + } else { + alert("Unable to download excel.") + } + }; + xhr.send(); +} + +function ivToStr(iv) { + let hexStr = ""; + for (var i in iv) { + if (iv[i] < 16) { + hexStr += "0" + iv[i].toString(16); + } else { + hexStr += iv[i].toString(16); + } + } + window.hexStr = hexStr; + return hexStr; +} + +function strToIv(str) { + var iv = new Uint8Array(16); + for (var i = 0; i < str.length; i += 2) { + iv[i/2] = parseInt((str.charAt(i) + str.charAt(i + 1)), 16); + } + + return iv; +} + +function updateProgress(e) { + if (e.lengthComputable) { + var percentComplete = Math.floor((e.loaded / e.total) * 100); + document.getElementById("downloadProgress").innerHTML = "Progress: " + percentComplete + "%"; + } +} \ No newline at end of file diff --git a/public/file.js b/public/file.js deleted file mode 100644 index 8ac3ac63..00000000 --- a/public/file.js +++ /dev/null @@ -1,149 +0,0 @@ -function download() { - - var xhr = new XMLHttpRequest(); - xhr.open('get', '/assets' + location.pathname.slice(0, -1), true); - xhr.responseType = 'blob'; - - xhr.onload = function(e) { - if (this.status == 200) { - let self = this; - var blob = new Blob([this.response]); - var arrayBuffer; - var fileReader = new FileReader(); - fileReader.onload = function() { - arrayBuffer = this.result; - var array = new Uint8Array(arrayBuffer); - salt = strToIv(location.pathname.slice(10, -1)); - - window.crypto.subtle.importKey( - "jwk", - { - kty: "oct", - k: location.hash.slice(1), - alg: "A128CBC", - ext: true, - }, - { - name: "AES-CBC", - }, - true, - ["encrypt", "decrypt"] - ) - .then(function(key){ - window.crypto.subtle.decrypt( - { - name: "AES-CBC", - iv: salt, - }, - key, - array - ) - .then(function(decrypted){ - var dataView = new DataView(decrypted); - var blob = new Blob([dataView]); - var downloadUrl = URL.createObjectURL(blob); - var a = document.createElement("a"); - a.href = downloadUrl; - a.download = xhr.getResponseHeader('Content-Disposition').match(/filename="(.+)"/)[1]; - console.log(xhr.getResponseHeader('Content-Disposition')); - document.body.appendChild(a); - a.click(); - }) - .catch(function(err){ - alert('This link is either invalid or has expired.'); - console.error(err); - }); - }) - .catch(function(err){ - console.error(err); - }); - }; - fileReader.readAsArrayBuffer(blob); - } else { - alert('Unable to download excel.') - } - }; - xhr.send(); -} - -function onChange(event) { - var file = event.target.files[0]; - var reader = new FileReader(); - reader.onload = function(event) { - let self = this; - window.crypto.subtle.generateKey({ - name: "AES-CBC", - length: 128 - }, - true, - ["encrypt", "decrypt"]) - .then(function(key){ - var arrayBuffer = self.result; - var array = new Uint8Array(arrayBuffer); - - var random_iv = window.crypto.getRandomValues(new Uint8Array(16)); - - window.crypto.subtle.encrypt({ - name: "AES-CBC", - iv: random_iv }, - key, - array) - .then(function(encrypted){ - console.log('Send this salt to a friend: [' + random_iv.toString() + ']'); - - var dataView = new DataView(encrypted); - var blob = new Blob([dataView], { type: file.type }); - - var fd = new FormData(); - fd.append('fname', file.name); - fd.append('data', blob, file.name); - - var xhr = new XMLHttpRequest(); - var hex = ivToStr(random_iv); - xhr.open('post', '/upload/' + hex, true); - xhr.onreadystatechange = function() { - if (xhr.readyState == XMLHttpRequest.DONE) { - window.crypto.subtle.exportKey("jwk", key).then(function(keydata){ - console.log('Go to this URL: http://localhost:3000/download/' + hex + '/#' + keydata.k); - alert('Go to this URL: http://localhost:3000/download/' + hex + '/#' + keydata.k); - - }) - } - }; - - xhr.send(fd); - }) - .catch(function(err){ - console.error(err); - }); - - }) - .catch(function(err){ - console.error(err); - }); - - }; - reader.readAsArrayBuffer(file); -} - -function ivToStr(iv) { - let hexStr = ''; - for (var i in iv) { - if (iv[i] < 16) { - hexStr += '0' + iv[i].toString(16); - } else { - hexStr += iv[i].toString(16); - } - } - window.hexStr = hexStr; - return hexStr; -} - -function strToIv(str) { - var iv = new Uint8Array(16); - for (var i = 0; i < str.length; i += 2) { - iv[i/2] = parseInt((str.charAt(i) + str.charAt(i + 1)), 16); - } - - return iv; -} \ No newline at end of file diff --git a/public/index.html b/public/index.html index 8de58241..d49ae997 100644 --- a/public/index.html +++ b/public/index.html @@ -2,17 +2,16 @@ Firefox Fileshare - + -
- -
- - +
+ +
+

diff --git a/public/upload.js b/public/upload.js new file mode 100644 index 00000000..f3f015b5 --- /dev/null +++ b/public/upload.js @@ -0,0 +1,88 @@ +function onChange(event) { + var file = event.target.files[0]; + var reader = new FileReader(); + reader.onload = function(event) { + let self = this; + window.crypto.subtle.generateKey({ + name: "AES-CBC", + length: 128 + }, + true, + ["encrypt", "decrypt"]) + .then(function(key){ + var arrayBuffer = self.result; + var array = new Uint8Array(arrayBuffer); + + var random_iv = window.crypto.getRandomValues(new Uint8Array(16)); + + window.crypto.subtle.encrypt({ + name: "AES-CBC", + iv: random_iv }, + key, + array) + .then(function(encrypted){ + var dataView = new DataView(encrypted); + var blob = new Blob([dataView], { type: file.type }); + + var fd = new FormData(); + fd.append("fname", file.name); + fd.append("data", blob, file.name); + + var xhr = new XMLHttpRequest(); + var hex = ivToStr(random_iv); + xhr.open("post", "/upload/" + hex, true); + xhr.addEventListener("progress", updateProgress); + xhr.upload.addEventListener("progress", updateProgress); + + xhr.onreadystatechange = function() { + if (xhr.readyState == XMLHttpRequest.DONE) { + window.crypto.subtle.exportKey("jwk", key).then(function(keydata) { + console.log("Share this link with a friend: http://localhost:3000/download/" + hex + "/#" + keydata.k); + alert("Share this link with a friend: http://localhost:3000/download/" + hex + "/#" + keydata.k); + }) + } + }; + + xhr.send(fd); + }) + .catch(function(err){ + console.error(err); + }); + + }) + .catch(function(err){ + console.error(err); + }); + + }; + reader.readAsArrayBuffer(file); +} + +function ivToStr(iv) { + let hexStr = ""; + for (var i in iv) { + if (iv[i] < 16) { + hexStr += "0" + iv[i].toString(16); + } else { + hexStr += iv[i].toString(16); + } + } + window.hexStr = hexStr; + return hexStr; +} + +function strToIv(str) { + var iv = new Uint8Array(16); + for (var i = 0; i < str.length; i += 2) { + iv[i/2] = parseInt((str.charAt(i) + str.charAt(i + 1)), 16); + } + + return iv; +} + +function updateProgress(e) { + if (e.lengthComputable) { + var percentComplete = Math.floor((e.loaded / e.total) * 100); + document.getElementById("downloadProgress").innerHTML = "Progress: " + percentComplete + "%"; + } +} \ No newline at end of file