From c25c97fbaa9fdcebfb8f866e2b3457586d7cd9c4 Mon Sep 17 00:00:00 2001 From: Abhinav Adduri Date: Wed, 31 May 2017 11:19:59 -0700 Subject: [PATCH 1/7] 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 From 895c4d364f19bd9b73f3de3b0076af7cc9c5f590 Mon Sep 17 00:00:00 2001 From: Abhinav Adduri Date: Wed, 31 May 2017 14:08:13 -0700 Subject: [PATCH 2/7] implemented deleting from server. multiple uploads by uploader handled and displayed on DOM --- app.js | 60 ++++++++++++++++++++++++++---------- package.json | 1 + public/download.js | 4 +-- public/index.html | 3 ++ public/upload.js | 77 +++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 118 insertions(+), 27 deletions(-) diff --git a/app.js b/app.js index 6f2670b4..7b3a881a 100644 --- a/app.js +++ b/app.js @@ -1,9 +1,11 @@ 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 busboy = require("connect-busboy"); +const path = require("path"); +const fs = require("fs-extra"); +const bodyParser = require('body-parser'); + const app = express() -var redis = require("redis"), +const redis = require("redis"), client = redis.createClient(); client.on("error", function(err) { @@ -11,12 +13,9 @@ client.on("error", function(err) { }) app.use(busboy()); +app.use(bodyParser.json()); app.use(express.static(path.join(__dirname, "public"))); -app.get("/", function (req, res) { - res.send("Hello World!") -}) - app.get("/download/:id", function(req, res) { res.sendFile(path.join(__dirname + "/public/download.html")); }); @@ -25,7 +24,7 @@ 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) { + if (!reply) { res.sendStatus(404); } else { res.setHeader("Content-Disposition", "attachment; filename=" + reply); @@ -42,8 +41,26 @@ app.get("/assets/download/:id", function(req, res) { }); -app.route("/upload/:id") - .post(function (req, res, next) { +app.post("/delete/:id", function(req, res) { + let id = req.params.id; + let delete_token = req.body.delete_token; + + if (!delete_token){ + res.sendStatus(404); + } + + client.hget(id, "delete", function(err, reply) { + if (!reply) { + res.sendStatus(404); + } else { + client.del(id); + fs.unlinkSync(__dirname + "/static/" + id); + res.sendStatus(200); + } + }) +}); + +app.post("/upload/:id", function (req, res, next) { var fstream; req.pipe(req.busboy); @@ -55,17 +72,26 @@ app.route("/upload/:id") file.pipe(fstream); fstream.on("close", function () { let id = req.params.id; - client.hset(id, "filename", filename, redis.print); - client.hset(id, "expiration", 0, redis.print); + let uuid = Math.floor(Math.random() * 10000000).toString() + + Math.floor(Math.random() * 10000000).toString() + + Math.floor(Math.random() * 10000000).toString(); + + client.hset(id, "filename", filename); + client.hset(id, "expiration", 0); + client.hset(id, "delete", uuid); + + // delete the file off the server in 24 hours + setTimeout(function() { + fs.unlinkSync(__dirname + "/static/" + id); + }, 86400000); + client.expire(id, 86400000); - console.log("Upload Finished of " + filename); - res.send(id); + console.log("Upload Finished of " + filename); + res.send(uuid); }); }); }); - - app.listen(3000, function () { console.log("Portal app listening on port 3000!") }) diff --git a/package.json b/package.json index ebfba011..db0b4a6a 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "author": "", "license": "ISC", "dependencies": { + "body-parser": "^1.17.2", "connect-busboy": "0.0.2", "express": "^4.15.3", "fs-extra": "^3.0.1", diff --git a/public/download.js b/public/download.js index 93fc5f3e..93a210df 100644 --- a/public/download.js +++ b/public/download.js @@ -50,7 +50,7 @@ function download() { a.click(); }) .catch(function(err){ - alert("This link is either invalid or has expired."); + alert("This link is either invalid or has expired, or the uploader has deleted the file."); console.error(err); }); }) @@ -60,7 +60,7 @@ function download() { }; fileReader.readAsArrayBuffer(blob); } else { - alert("Unable to download excel.") + alert("This link is either invalid or has expired, or the uploader has deleted the file.") } }; xhr.send(); diff --git a/public/index.html b/public/index.html index d49ae997..f8d8a43c 100644 --- a/public/index.html +++ b/public/index.html @@ -12,6 +12,9 @@

+ + diff --git a/public/upload.js b/public/upload.js index f3f015b5..32fabbcc 100644 --- a/public/upload.js +++ b/public/upload.js @@ -31,12 +31,40 @@ function onChange(event) { var xhr = new XMLHttpRequest(); var hex = ivToStr(random_iv); xhr.open("post", "/upload/" + hex, true); - xhr.addEventListener("progress", updateProgress); - xhr.upload.addEventListener("progress", updateProgress); + + var li = document.createElement("li"); + var name = document.createElement("p"); + name.innerHTML = file.name; + li.appendChild(name); + + var link = document.createElement("a"); + li.appendChild(link); + + var progress = document.createElement("p"); + li.appendChild(progress); + document.getElementById("uploaded_files").appendChild(li); + + + xhr.upload.addEventListener("progress", returnBindedLI(progress, name, link, li)); xhr.onreadystatechange = function() { if (xhr.readyState == XMLHttpRequest.DONE) { window.crypto.subtle.exportKey("jwk", key).then(function(keydata) { + var curr_name = localStorage.getItem(file.name); + + localStorage.setItem(hex, xhr.responseText); + + link.innerHTML = "http://localhost:3000/download/" + hex + "/#" + keydata.k; + link.setAttribute("href", "http://localhost:3000/download/" + hex + "/#" + keydata.k); + + // if (curr_name) { + // localStorage.setItem(file.name, curr_name + "," + hex); + // } else { + // localStorage.setItem(file.name, hex) + // } + + + 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); }) @@ -80,9 +108,42 @@ function strToIv(str) { 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 +function returnBindedLI(a_element, name, link, li) { + return function updateProgress(e) { + if (e.lengthComputable) { + var percentComplete = Math.floor((e.loaded / e.total) * 100); + a_element.innerHTML = "Progress: " + percentComplete + "%"; + + if (percentComplete === 100) { + var btn = document.createElement("button"); + btn.innerHTML = "Delete from server"; + btn.addEventListener("click", function() { + var segments = link.innerHTML.split("/"); + var key = segments[segments.length - 2]; + + var xhr = new XMLHttpRequest(); + xhr.open("post", "/delete/" + key, true); + xhr.setRequestHeader("Content-Type", "application/json"); + if (!localStorage.getItem(key)) return; + + xhr.send(JSON.stringify({delete_token: localStorage.getItem(key)})); + + xhr.onreadystatechange = function() { + if (xhr.readyState === XMLHttpRequest.DONE) { + document.getElementById("uploaded_files").removeChild(li); + } + + if (xhr.status === 200) { + console.log("The file was successfully deleted."); + } else { + console.log("The file has expired, or has already been deleted."); + } + } + + }); + li.appendChild(btn); + } + } + } +} + From 4968e501e18c105f3c5b75dbd1b56f9fd6031a55 Mon Sep 17 00:00:00 2001 From: Abhinav Adduri Date: Wed, 31 May 2017 14:12:10 -0700 Subject: [PATCH 3/7] delete localstorage after deleting file for uploader --- public/upload.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/upload.js b/public/upload.js index 32fabbcc..36629a79 100644 --- a/public/upload.js +++ b/public/upload.js @@ -131,6 +131,7 @@ function returnBindedLI(a_element, name, link, li) { xhr.onreadystatechange = function() { if (xhr.readyState === XMLHttpRequest.DONE) { document.getElementById("uploaded_files").removeChild(li); + localStorage.removeItem(key); } if (xhr.status === 200) { From bb5e05319a70fbad6f26ee372869112b8ec92e36 Mon Sep 17 00:00:00 2001 From: Abhinav Adduri Date: Thu, 1 Jun 2017 09:07:11 -0700 Subject: [PATCH 4/7] pr changes --- app.js | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/app.js b/app.js index 7b3a881a..5ac252a3 100644 --- a/app.js +++ b/app.js @@ -62,35 +62,31 @@ app.post("/delete/:id", function(req, res) { app.post("/upload/:id", function (req, res, next) { - var fstream; - req.pipe(req.busboy); - req.busboy.on("file", function (fieldname, file, filename) { - console.log("Uploading: " + filename); + var fstream; + req.pipe(req.busboy); + 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); - file.pipe(fstream); - fstream.on("close", function () { - let id = req.params.id; - let uuid = Math.floor(Math.random() * 10000000).toString() - + Math.floor(Math.random() * 10000000).toString() - + Math.floor(Math.random() * 10000000).toString(); + //Path where image will be uploaded + fstream = fs.createWriteStream(__dirname + "/static/" + req.params.id); + file.pipe(fstream); + fstream.on("close", function () { + let id = req.params.id; + let uuid = crypto.randomBytes(10).toString('hex'); - client.hset(id, "filename", filename); - client.hset(id, "expiration", 0); - client.hset(id, "delete", uuid); + client.hmset([id, "filename", filename, "delete", uuid]); - // delete the file off the server in 24 hours - setTimeout(function() { - fs.unlinkSync(__dirname + "/static/" + id); - }, 86400000); + // delete the file off the server in 24 hours + // setTimeout(function() { + // fs.unlinkSync(__dirname + "/static/" + id); + // }, 86400000); - client.expire(id, 86400000); - console.log("Upload Finished of " + filename); - res.send(uuid); - }); + client.expire(id, 86400000); + console.log("Upload Finished of " + filename); + res.send(uuid); }); }); +}); app.listen(3000, function () { console.log("Portal app listening on port 3000!") From c05b444432d237a8fa8ee064cd78a8ef4bb3a5b1 Mon Sep 17 00:00:00 2001 From: Abhinav Adduri Date: Thu, 1 Jun 2017 09:17:25 -0700 Subject: [PATCH 5/7] added require crypto line --- app.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app.js b/app.js index 5ac252a3..b5d58057 100644 --- a/app.js +++ b/app.js @@ -2,7 +2,8 @@ const express = require("express") const busboy = require("connect-busboy"); const path = require("path"); const fs = require("fs-extra"); -const bodyParser = require('body-parser'); +const bodyParser = require("body-parser"); +const crypto = require("crypto"); const app = express() const redis = require("redis"), From 065f3c201471ce9688d84c4c03092783de5c36e0 Mon Sep 17 00:00:00 2001 From: Abhinav Adduri Date: Thu, 1 Jun 2017 09:55:47 -0700 Subject: [PATCH 6/7] added route id verification, and better downloader ui --- app.js | 19 ++++++++++++++ public/download.html | 3 +++ public/download.js | 62 ++++++++++++++++++++++++++++++++------------ 3 files changed, 67 insertions(+), 17 deletions(-) diff --git a/app.js b/app.js index b5d58057..d7307896 100644 --- a/app.js +++ b/app.js @@ -23,6 +23,11 @@ app.get("/download/:id", function(req, res) { app.get("/assets/download/:id", function(req, res) { + if (!validateID(id)){ + res.send(404); + return; + } + let id = req.params.id; client.hget(id, "filename", function(err, reply) { // maybe some expiration logic too if (!reply) { @@ -44,6 +49,12 @@ app.get("/assets/download/:id", function(req, res) { app.post("/delete/:id", function(req, res) { let id = req.params.id; + + if (!validateID(id)){ + res.send(404); + return; + } + let delete_token = req.body.delete_token; if (!delete_token){ @@ -62,6 +73,11 @@ app.post("/delete/:id", function(req, res) { }); app.post("/upload/:id", function (req, res, next) { + + if (!validateID(req.params.id)){ + res.send(404); + return; + } var fstream; req.pipe(req.busboy); @@ -93,3 +109,6 @@ app.listen(3000, function () { console.log("Portal app listening on port 3000!") }) +function validateID(route_id) { + return route_id.match(/^[0-9a-fA-F]{32}$/) !== null; +} \ No newline at end of file diff --git a/public/download.html b/public/download.html index ed96249b..47ac3dbc 100644 --- a/public/download.html +++ b/public/download.html @@ -9,5 +9,8 @@

+
    +
+ diff --git a/public/download.js b/public/download.js index 93a210df..f74ab52e 100644 --- a/public/download.js +++ b/public/download.js @@ -4,7 +4,11 @@ function download() { xhr.open("get", "/assets" + location.pathname.slice(0, -1), true); xhr.responseType = "blob"; - xhr.addEventListener("progress", updateProgress); + var li = document.createElement("li"); + var progress = document.createElement("p"); + li.appendChild(progress); + + xhr.addEventListener("progress", returnBindedLI(li, progress)); xhr.onload = function(e) { if (this.status == 200) { @@ -39,19 +43,26 @@ function download() { 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(); + var filename = xhr.getResponseHeader("Content-Disposition").match(/filename="(.+)"/)[1]; + + var name = document.createElement("p"); + name.innerHTML = filename; + li.insertBefore(name, li.firstChild); + document.getElementById("downloaded_files").appendChild(li); + + 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 = filename + console.log(xhr.getResponseHeader("Content-Disposition")); + document.body.appendChild(a); + a.click(); }) .catch(function(err){ - alert("This link is either invalid or has expired, or the uploader has deleted the file."); - console.error(err); + alert("This link is either invalid or has expired, or the uploader has deleted the file."); + console.error(err); }); }) .catch(function(err){ @@ -88,9 +99,26 @@ function strToIv(str) { return iv; } -function updateProgress(e) { - if (e.lengthComputable) { - var percentComplete = Math.floor((e.loaded / e.total) * 100); - document.getElementById("downloadProgress").innerHTML = "Progress: " + percentComplete + "%"; - } +function returnBindedLI(li, progress) { + return function updateProgress(e) { + if (e.lengthComputable) { + var percentComplete = Math.floor((e.loaded / e.total) * 100); + progress.innerHTML = "Progress: " + percentComplete + "%"; + } + + if (percentComplete === 100) { + var finished = document.createElement("p"); + finished.innerHTML = "Your download has finished."; + li.appendChild(finished); + + var close = document.createElement("button"); + close.innerHTML = "Ok"; + close.addEventListener("click", function() { + document.getElementById("downloaded_files").removeChild(li); + }); + + li.appendChild(close); + } + + } } \ No newline at end of file From 76c337836dc36890eab101f6c4f76439b76d6503 Mon Sep 17 00:00:00 2001 From: Abhinav Adduri Date: Thu, 1 Jun 2017 10:05:09 -0700 Subject: [PATCH 7/7] some code cleanup, fixed bug with regex in app.js --- app.js | 3 ++- public/download.html | 1 - public/download.js | 24 ++++++++++++++---------- public/index.html | 2 -- public/upload.js | 9 --------- 5 files changed, 16 insertions(+), 23 deletions(-) diff --git a/app.js b/app.js index d7307896..afb1d0ae 100644 --- a/app.js +++ b/app.js @@ -23,12 +23,13 @@ app.get("/download/:id", function(req, res) { app.get("/assets/download/:id", function(req, res) { + let id = req.params.id; if (!validateID(id)){ res.send(404); return; } - let id = req.params.id; + client.hget(id, "filename", function(err, reply) { // maybe some expiration logic too if (!reply) { res.sendStatus(404); diff --git a/public/download.html b/public/download.html index 47ac3dbc..bf5686b0 100644 --- a/public/download.html +++ b/public/download.html @@ -7,7 +7,6 @@ -

diff --git a/public/download.js b/public/download.js index f74ab52e..66e595a1 100644 --- a/public/download.js +++ b/public/download.js @@ -7,10 +7,22 @@ function download() { var li = document.createElement("li"); var progress = document.createElement("p"); li.appendChild(progress); + document.getElementById("downloaded_files").appendChild(li); xhr.addEventListener("progress", returnBindedLI(li, progress)); - + + + xhr.onload = function(e) { + + // maybe send a separate request before this one to get the filename? + + // maybe render the html itself with the filename, since it's generated server side + // after a get request with the unique id + var name = document.createElement("p"); + name.innerHTML = xhr.getResponseHeader("Content-Disposition").match(/filename="(.+)"/)[1]; + li.insertBefore(name, li.firstChild); + if (this.status == 200) { let self = this; var blob = new Blob([this.response]); @@ -43,20 +55,12 @@ function download() { key, array) .then(function(decrypted){ - var filename = xhr.getResponseHeader("Content-Disposition").match(/filename="(.+)"/)[1]; - - var name = document.createElement("p"); - name.innerHTML = filename; - li.insertBefore(name, li.firstChild); - document.getElementById("downloaded_files").appendChild(li); - 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 = filename - console.log(xhr.getResponseHeader("Content-Disposition")); + a.download = xhr.getResponseHeader("Content-Disposition").match(/filename="(.+)"/)[1]; document.body.appendChild(a); a.click(); }) diff --git a/public/index.html b/public/index.html index f8d8a43c..c6b31826 100644 --- a/public/index.html +++ b/public/index.html @@ -11,8 +11,6 @@ -

-
diff --git a/public/upload.js b/public/upload.js index 36629a79..9e3c8789 100644 --- a/public/upload.js +++ b/public/upload.js @@ -57,16 +57,7 @@ function onChange(event) { link.innerHTML = "http://localhost:3000/download/" + hex + "/#" + keydata.k; link.setAttribute("href", "http://localhost:3000/download/" + hex + "/#" + keydata.k); - // if (curr_name) { - // localStorage.setItem(file.name, curr_name + "," + hex); - // } else { - // localStorage.setItem(file.name, hex) - // } - - - 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); }) } };