commit
8baa6d0964
|
@ -1 +1,2 @@
|
||||||
public/bundle.js
|
public/bundle.js
|
||||||
|
public/webcrypto-shim.js
|
||||||
|
|
|
@ -31,7 +31,7 @@ rules:
|
||||||
eqeqeq: error
|
eqeqeq: error
|
||||||
no-console: warn
|
no-console: warn
|
||||||
no-path-concat: error
|
no-path-concat: error
|
||||||
no-unused-vars: [error, {argsIgnorePattern: "^_|next"}]
|
no-unused-vars: [error, {argsIgnorePattern: "^_|err|event|next|reject"}]
|
||||||
no-var: error
|
no-var: error
|
||||||
one-var: [error, never]
|
one-var: [error, never]
|
||||||
prefer-const: error
|
prefer-const: error
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"attr-name-style": "dash",
|
||||||
|
"id-class-style": "dash",
|
||||||
|
"indent-width": 2
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
extends: stylelint-config-standard
|
||||||
|
|
||||||
|
rules:
|
||||||
|
color-hex-case: upper
|
||||||
|
selector-list-comma-newline-after: null
|
|
@ -5,13 +5,11 @@ $(document).ready(function() {
|
||||||
$('#send-file').click(() => {
|
$('#send-file').click(() => {
|
||||||
window.location.replace(`${window.location.origin}`);
|
window.location.replace(`${window.location.origin}`);
|
||||||
});
|
});
|
||||||
let download = () => {
|
const download = () => {
|
||||||
const fileReceiver = new FileReceiver();
|
const fileReceiver = new FileReceiver();
|
||||||
|
const name = document.createElement('p');
|
||||||
let li = document.createElement('li');
|
const progress = document.createElement('p');
|
||||||
let name = document.createElement('p');
|
const btn = $('#download-btn');
|
||||||
let progress = document.createElement('p');
|
|
||||||
let btn = $('#download-btn');
|
|
||||||
|
|
||||||
fileReceiver.on('progress', percentComplete => {
|
fileReceiver.on('progress', percentComplete => {
|
||||||
progress.innerText = `Progress: ${percentComplete}%`;
|
progress.innerText = `Progress: ${percentComplete}%`;
|
||||||
|
@ -25,7 +23,7 @@ $(document).ready(function() {
|
||||||
|
|
||||||
fileReceiver
|
fileReceiver
|
||||||
.download()
|
.download()
|
||||||
.catch(err => {
|
.catch(() => {
|
||||||
$('.title').text(
|
$('.title').text(
|
||||||
'This link has expired or never existed in the first place.'
|
'This link has expired or never existed in the first place.'
|
||||||
);
|
);
|
||||||
|
@ -36,11 +34,11 @@ $(document).ready(function() {
|
||||||
})
|
})
|
||||||
.then(([decrypted, fname]) => {
|
.then(([decrypted, fname]) => {
|
||||||
name.innerText = fname;
|
name.innerText = fname;
|
||||||
let dataView = new DataView(decrypted);
|
const dataView = new DataView(decrypted);
|
||||||
let blob = new Blob([dataView]);
|
const blob = new Blob([dataView]);
|
||||||
let downloadUrl = URL.createObjectURL(blob);
|
const downloadUrl = URL.createObjectURL(blob);
|
||||||
|
|
||||||
let a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
a.href = downloadUrl;
|
a.href = downloadUrl;
|
||||||
if (window.navigator.msSaveBlob) {
|
if (window.navigator.msSaveBlob) {
|
||||||
// if we are in microsoft edge or IE
|
// if we are in microsoft edge or IE
|
||||||
|
|
|
@ -10,16 +10,18 @@ class FileReceiver extends EventEmitter {
|
||||||
download() {
|
download() {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
let xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
|
|
||||||
xhr.onprogress = e => {
|
xhr.onprogress = event => {
|
||||||
if (e.lengthComputable) {
|
if (event.lengthComputable) {
|
||||||
let percentComplete = Math.floor(e.loaded / e.total * 100);
|
const percentComplete = Math.floor(
|
||||||
|
event.loaded / event.total * 100
|
||||||
|
);
|
||||||
this.emit('progress', percentComplete);
|
this.emit('progress', percentComplete);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
xhr.onload = function(e) {
|
xhr.onload = event => {
|
||||||
if (xhr.status === 404) {
|
if (xhr.status === 404) {
|
||||||
reject(
|
reject(
|
||||||
new Error('The file has expired, or has already been deleted.')
|
new Error('The file has expired, or has already been deleted.')
|
||||||
|
@ -27,8 +29,8 @@ class FileReceiver extends EventEmitter {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let blob = new Blob([this.response]);
|
const blob = new Blob([this.response]);
|
||||||
let fileReader = new FileReader();
|
const fileReader = new FileReader();
|
||||||
fileReader.onload = function() {
|
fileReader.onload = function() {
|
||||||
resolve({
|
resolve({
|
||||||
data: this.result,
|
data: this.result,
|
||||||
|
@ -60,7 +62,7 @@ class FileReceiver extends EventEmitter {
|
||||||
['encrypt', 'decrypt']
|
['encrypt', 'decrypt']
|
||||||
)
|
)
|
||||||
]).then(([fdata, key]) => {
|
]).then(([fdata, key]) => {
|
||||||
let salt = this.salt;
|
const salt = this.salt;
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
window.crypto.subtle.decrypt(
|
window.crypto.subtle.decrypt(
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,7 +13,7 @@ class FileSender extends EventEmitter {
|
||||||
if (!fileId || !token) {
|
if (!fileId || !token) {
|
||||||
return reject();
|
return reject();
|
||||||
}
|
}
|
||||||
let xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
xhr.open('post', '/delete/' + fileId, true);
|
xhr.open('post', '/delete/' + fileId, true);
|
||||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||||
|
|
||||||
|
@ -51,55 +51,55 @@ class FileSender extends EventEmitter {
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
.then(([secretKey, plaintext]) => {
|
.then(([secretKey, plaintext]) => {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
window.crypto.subtle.encrypt(
|
window.crypto.subtle.encrypt(
|
||||||
{
|
{
|
||||||
name: 'AES-CBC',
|
name: 'AES-CBC',
|
||||||
iv: this.iv
|
iv: this.iv
|
||||||
},
|
},
|
||||||
secretKey,
|
secretKey,
|
||||||
plaintext
|
plaintext
|
||||||
),
|
),
|
||||||
window.crypto.subtle.exportKey('jwk', secretKey)
|
window.crypto.subtle.exportKey('jwk', secretKey)
|
||||||
]);
|
]);
|
||||||
})
|
})
|
||||||
.then(([encrypted, keydata]) => {
|
.then(([encrypted, keydata]) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let file = this.file;
|
const file = this.file;
|
||||||
let fileId = ivToStr(this.iv);
|
const fileId = ivToStr(this.iv);
|
||||||
let dataView = new DataView(encrypted);
|
const dataView = new DataView(encrypted);
|
||||||
let blob = new Blob([dataView], { type: file.type });
|
const blob = new Blob([dataView], { type: file.type });
|
||||||
let fd = new FormData();
|
const fd = new FormData();
|
||||||
fd.append('fname', file.name);
|
fd.append('fname', file.name);
|
||||||
fd.append('data', blob, file.name);
|
fd.append('data', blob, file.name);
|
||||||
|
|
||||||
let xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
|
|
||||||
xhr.upload.addEventListener('progress', e => {
|
xhr.upload.addEventListener('progress', e => {
|
||||||
if (e.lengthComputable) {
|
if (e.lengthComputable) {
|
||||||
let percentComplete = Math.floor(e.loaded / e.total * 100);
|
const percentComplete = Math.floor(e.loaded / e.total * 100);
|
||||||
this.emit('progress', percentComplete);
|
this.emit('progress', percentComplete);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
xhr.onreadystatechange = () => {
|
||||||
|
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||||
|
// uuid field and url field
|
||||||
|
const responseObj = JSON.parse(xhr.responseText);
|
||||||
|
resolve({
|
||||||
|
url: responseObj.url,
|
||||||
|
fileId: fileId,
|
||||||
|
secretKey: keydata.k,
|
||||||
|
deleteToken: responseObj.uuid
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.open('post', '/upload/' + fileId, true);
|
||||||
|
xhr.send(fd);
|
||||||
});
|
});
|
||||||
|
|
||||||
xhr.onreadystatechange = () => {
|
|
||||||
if (xhr.readyState == XMLHttpRequest.DONE) {
|
|
||||||
// uuid field and url field
|
|
||||||
let responseObj = JSON.parse(xhr.responseText);
|
|
||||||
resolve({
|
|
||||||
url: responseObj.url,
|
|
||||||
fileId: fileId,
|
|
||||||
secretKey: keydata.k,
|
|
||||||
deleteToken: responseObj.uuid
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
xhr.open('post', '/upload/' + fileId, true);
|
|
||||||
xhr.send(fd);
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ const $ = require('jquery');
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
// reset copy button
|
// reset copy button
|
||||||
let copyBtn = $('#copy-btn');
|
const copyBtn = $('#copy-btn');
|
||||||
copyBtn.attr('disabled', false);
|
copyBtn.attr('disabled', false);
|
||||||
copyBtn.html('Copy');
|
copyBtn.html('Copy');
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ $(document).ready(function() {
|
||||||
|
|
||||||
// copy link to clipboard
|
// copy link to clipboard
|
||||||
copyBtn.click(() => {
|
copyBtn.click(() => {
|
||||||
var aux = document.createElement('input');
|
const aux = document.createElement('input');
|
||||||
aux.setAttribute('value', $('#link').attr('value'));
|
aux.setAttribute('value', $('#link').attr('value'));
|
||||||
document.body.appendChild(aux);
|
document.body.appendChild(aux);
|
||||||
aux.select();
|
aux.select();
|
||||||
|
@ -38,22 +38,22 @@ $(document).ready(function() {
|
||||||
window.onUpload = event => {
|
window.onUpload = event => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let file = '';
|
let file = '';
|
||||||
if (event.type == 'drop') {
|
if (event.type === 'drop') {
|
||||||
file = event.dataTransfer.files[0];
|
file = event.dataTransfer.files[0];
|
||||||
} else {
|
} else {
|
||||||
file = event.target.files[0];
|
file = event.target.files[0];
|
||||||
}
|
}
|
||||||
let $fileList = $('#uploaded-files');
|
const $fileList = $('#uploaded-files');
|
||||||
let row = document.createElement('tr');
|
const row = document.createElement('tr');
|
||||||
let name = document.createElement('td');
|
const name = document.createElement('td');
|
||||||
let link = document.createElement('td');
|
const link = document.createElement('td');
|
||||||
let expiry = document.createElement('td');
|
const expiry = document.createElement('td');
|
||||||
let del = document.createElement('td');
|
const del = document.createElement('td');
|
||||||
let btn = document.createElement('button');
|
const btn = document.createElement('button');
|
||||||
let popupDiv = document.createElement('div');
|
const popupDiv = document.createElement('div');
|
||||||
let $popupText = $('<span>', { 'class': 'popuptext' });
|
const $popupText = $('<span>', { class: 'popuptext' });
|
||||||
let cellText = document.createTextNode(file.name);
|
const cellText = document.createTextNode(file.name);
|
||||||
let progress = document.createElement('p');
|
const progress = document.createElement('p');
|
||||||
|
|
||||||
name.appendChild(cellText);
|
name.appendChild(cellText);
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ $(document).ready(function() {
|
||||||
// create popup
|
// create popup
|
||||||
popupDiv.classList.add('popup');
|
popupDiv.classList.add('popup');
|
||||||
$popupText.html(
|
$popupText.html(
|
||||||
"<span class='del-file'>Delete</span><span class='nvm'> Nevermind</span>"
|
'<span class="del-file">Delete</span><span class="nvm" > Nevermind</span>'
|
||||||
);
|
);
|
||||||
|
|
||||||
// add data cells to table row
|
// add data cells to table row
|
||||||
|
@ -96,7 +96,7 @@ $(document).ready(function() {
|
||||||
FileSender.delete(
|
FileSender.delete(
|
||||||
info.fileId,
|
info.fileId,
|
||||||
localStorage.getItem(info.fileId)
|
localStorage.getItem(info.fileId)
|
||||||
).then(() => {
|
).then(() => {
|
||||||
//
|
//
|
||||||
$(e.target).parents('tr').remove();
|
$(e.target).parents('tr').remove();
|
||||||
localStorage.removeItem(info.fileId);
|
localStorage.removeItem(info.fileId);
|
||||||
|
@ -111,7 +111,7 @@ $(document).ready(function() {
|
||||||
$('#share-link').show();
|
$('#share-link').show();
|
||||||
});
|
});
|
||||||
|
|
||||||
function toggleShow(){
|
function toggleShow() {
|
||||||
$popupText.toggleClass('show');
|
$popupText.toggleClass('show');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
function ivToStr(iv) {
|
function ivToStr(iv) {
|
||||||
let hexStr = '';
|
let hexStr = '';
|
||||||
for (let i in iv) {
|
for (const i in iv) {
|
||||||
if (iv[i] < 16) {
|
if (iv[i] < 16) {
|
||||||
hexStr += '0' + iv[i].toString(16);
|
hexStr += '0' + iv[i].toString(16);
|
||||||
} else {
|
} else {
|
||||||
|
@ -12,7 +12,7 @@ function ivToStr(iv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function strToIv(str) {
|
function strToIv(str) {
|
||||||
let iv = new Uint8Array(16);
|
const iv = new Uint8Array(16);
|
||||||
for (let i = 0; i < str.length; i += 2) {
|
for (let i = 0; i < str.length; i += 2) {
|
||||||
iv[i / 2] = parseInt(str.charAt(i) + str.charAt(i + 1), 16);
|
iv[i / 2] = parseInt(str.charAt(i) + str.charAt(i + 1), 16);
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -26,7 +26,11 @@
|
||||||
"eslint": "3.19.0",
|
"eslint": "3.19.0",
|
||||||
"eslint-plugin-node": "5.0.0",
|
"eslint-plugin-node": "5.0.0",
|
||||||
"eslint-plugin-security": "1.3.0",
|
"eslint-plugin-security": "1.3.0",
|
||||||
|
"htmllint-cli": "0.0.6",
|
||||||
|
"npm-run-all": "4.0.2",
|
||||||
"prettier": "1.4.4",
|
"prettier": "1.4.4",
|
||||||
|
"stylelint": "7.11.0",
|
||||||
|
"stylelint-config-standard": "16.0.0",
|
||||||
"watchify": "^3.9.0"
|
"watchify": "^3.9.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -37,7 +41,10 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "watchify frontend/src/main.js -o public/bundle.js -d | node server/portal_server.js",
|
"dev": "watchify frontend/src/main.js -o public/bundle.js -d | node server/portal_server.js",
|
||||||
"format": "prettier 'frontend/src/*.js' 'server/*.js' 'public/*.css' --single-quote --write",
|
"format": "prettier 'frontend/src/*.js' 'server/*.js' 'public/*.css' --single-quote --write",
|
||||||
"lint": "eslint .",
|
"lint": "npm-run-all lint:*",
|
||||||
|
"lint:css": "stylelint 'public/*.css'",
|
||||||
|
"lint:html": "htmllint 'views/*.handlebars'",
|
||||||
|
"lint:js": "eslint .",
|
||||||
"start": "watchify frontend/src/main.js -o public/bundle.js -d | cross-env NODE_ENV=production node server/portal_server.js",
|
"start": "watchify frontend/src/main.js -o public/bundle.js -d | cross-env NODE_ENV=production node server/portal_server.js",
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,9 @@ html {
|
||||||
align-content: center;
|
align-content: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
input, select, textarea, button {
|
input, select, textarea, button {
|
||||||
font-family:inherit;
|
font-family: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** page-one **/
|
/** page-one **/
|
||||||
|
@ -34,7 +35,6 @@ input, select, textarea, button {
|
||||||
|
|
||||||
.upload-window {
|
.upload-window {
|
||||||
border: 1px dashed;
|
border: 1px dashed;
|
||||||
width: 50%;
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
width: 470px;
|
width: 470px;
|
||||||
height: 250px;
|
height: 250px;
|
||||||
|
@ -59,7 +59,7 @@ input, select, textarea, button {
|
||||||
padding-right: 20px;
|
padding-right: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.upload-window>div:nth-child(2) {
|
.upload-window > div:nth-child(2) {
|
||||||
font-size: 26px;
|
font-size: 26px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ td {
|
||||||
|
|
||||||
#uploaded-files {
|
#uploaded-files {
|
||||||
width: 472px;
|
width: 472px;
|
||||||
margin: 10px auto ;
|
margin: 10px auto;
|
||||||
table-layout: fixed;
|
table-layout: fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,53 +110,50 @@ td {
|
||||||
|
|
||||||
/* Popup container */
|
/* Popup container */
|
||||||
.popup {
|
.popup {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The actual popup (appears on top) */
|
/* The actual popup (appears on top) */
|
||||||
.popup .popuptext {
|
.popup .popuptext {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
width: 160px;
|
width: 160px;
|
||||||
background-color: #555;
|
background-color: #555;
|
||||||
color: #fff;
|
color: #FFF;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
padding: 8px 0;
|
padding: 8px 0;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
bottom: 125%;
|
bottom: 125%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
margin-left: -80px;
|
margin-left: -80px;
|
||||||
transition: opacity 0.5s;
|
transition: opacity 0.5s;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Popup arrow */
|
/* Popup arrow */
|
||||||
.popup .popuptext::after {
|
.popup .popuptext::after {
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 100%;
|
top: 100%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
margin-left: -5px;
|
margin-left: -5px;
|
||||||
border-width: 5px;
|
border-width: 5px;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-color: #555 transparent transparent transparent;
|
border-color: #555 transparent transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup .show {
|
.popup .show {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** upload-progress **/
|
/** upload-progress **/
|
||||||
|
|
||||||
|
|
||||||
/** share-link **/
|
/** share-link **/
|
||||||
.share-window {
|
.share-window {
|
||||||
width: 50%;
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
width: 470px;
|
width: 470px;
|
||||||
height: 250px;
|
height: 250px;
|
||||||
|
@ -174,7 +171,7 @@ td {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
#share-window-r>div {
|
#share-window-r > div {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
const convict = require('convict');
|
const convict = require('convict');
|
||||||
|
|
||||||
let conf = convict({
|
const conf = convict({
|
||||||
bitly_key: {
|
bitly_key: {
|
||||||
format: String,
|
format: String,
|
||||||
default: 'localhost',
|
default: 'localhost',
|
||||||
|
@ -32,7 +32,7 @@ let conf = convict({
|
||||||
// Perform validation
|
// Perform validation
|
||||||
conf.validate({ allowed: 'strict' });
|
conf.validate({ allowed: 'strict' });
|
||||||
|
|
||||||
let props = conf.getProperties();
|
const props = conf.getProperties();
|
||||||
module.exports = props;
|
module.exports = props;
|
||||||
|
|
||||||
module.exports.notLocalHost =
|
module.exports.notLocalHost =
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
const conf = require('./config.js');
|
const conf = require('./config.js');
|
||||||
|
|
||||||
let notLocalHost = conf.notLocalHost;
|
const notLocalHost = conf.notLocalHost;
|
||||||
|
|
||||||
const mozlog = require('mozlog') ({
|
const mozlog = require('mozlog')({
|
||||||
app: 'FirefoxFileshare',
|
app: 'FirefoxFileshare',
|
||||||
level: notLocalHost ? 'INFO' : 'verbose',
|
level: notLocalHost ? 'INFO' : 'verbose',
|
||||||
fmt: notLocalHost ? 'heka' : 'pretty',
|
fmt: notLocalHost ? 'heka' : 'pretty',
|
||||||
debug: !notLocalHost
|
debug: !notLocalHost
|
||||||
})
|
});
|
||||||
|
|
||||||
module.exports = mozlog;
|
module.exports = mozlog;
|
|
@ -2,20 +2,16 @@ const express = require('express');
|
||||||
const exphbs = require('express-handlebars');
|
const exphbs = require('express-handlebars');
|
||||||
const busboy = require('connect-busboy');
|
const busboy = require('connect-busboy');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs-extra');
|
|
||||||
const bodyParser = require('body-parser');
|
const bodyParser = require('body-parser');
|
||||||
const crypto = require('crypto');
|
|
||||||
const stream = require('stream');
|
|
||||||
const fetch = require('node-fetch');
|
|
||||||
const bytes = require('bytes');
|
const bytes = require('bytes');
|
||||||
const conf = require('./config.js');
|
const conf = require('./config.js');
|
||||||
const storage = require('./storage.js');
|
const storage = require('./storage.js');
|
||||||
|
|
||||||
let notLocalHost = conf.notLocalHost;
|
const notLocalHost = conf.notLocalHost;
|
||||||
|
|
||||||
const mozlog = require('./log.js');
|
const mozlog = require('./log.js');
|
||||||
|
|
||||||
let log = mozlog('portal.server');
|
const log = mozlog('portal.server');
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
|
@ -32,14 +28,14 @@ app.get('/', (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/exists/:id', (req, res) => {
|
app.get('/exists/:id', (req, res) => {
|
||||||
let id = req.params.id;
|
const id = req.params.id;
|
||||||
storage.exists(id).then(doesExist => {
|
storage.exists(id).then(doesExist => {
|
||||||
res.sendStatus(doesExist ? 200 : 404);
|
res.sendStatus(doesExist ? 200 : 404);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/download/:id', (req, res) => {
|
app.get('/download/:id', (req, res) => {
|
||||||
let id = req.params.id;
|
const id = req.params.id;
|
||||||
storage.filename(id).then(filename => {
|
storage.filename(id).then(filename => {
|
||||||
storage
|
storage
|
||||||
.length(id)
|
.length(id)
|
||||||
|
@ -56,7 +52,7 @@ app.get('/download/:id', (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/assets/download/:id', (req, res) => {
|
app.get('/assets/download/:id', (req, res) => {
|
||||||
let id = req.params.id;
|
const id = req.params.id;
|
||||||
if (!validateID(id)) {
|
if (!validateID(id)) {
|
||||||
res.sendStatus(404);
|
res.sendStatus(404);
|
||||||
return;
|
return;
|
||||||
|
@ -71,7 +67,7 @@ app.get('/assets/download/:id', (req, res) => {
|
||||||
'Content-Type': 'application/octet-stream',
|
'Content-Type': 'application/octet-stream',
|
||||||
'Content-Length': contentLength
|
'Content-Length': contentLength
|
||||||
});
|
});
|
||||||
let file_stream = storage.get(id);
|
const file_stream = storage.get(id);
|
||||||
|
|
||||||
file_stream.on(notLocalHost ? 'finish' : 'close', () => {
|
file_stream.on(notLocalHost ? 'finish' : 'close', () => {
|
||||||
storage.forceDelete(id).then(err => {
|
storage.forceDelete(id).then(err => {
|
||||||
|
@ -90,14 +86,14 @@ app.get('/assets/download/:id', (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/delete/:id', (req, res) => {
|
app.post('/delete/:id', (req, res) => {
|
||||||
let id = req.params.id;
|
const id = req.params.id;
|
||||||
|
|
||||||
if (!validateID(id)) {
|
if (!validateID(id)) {
|
||||||
res.send(404);
|
res.send(404);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let delete_token = req.body.delete_token;
|
const delete_token = req.body.delete_token;
|
||||||
|
|
||||||
if (!delete_token) {
|
if (!delete_token) {
|
||||||
res.sendStatus(404);
|
res.sendStatus(404);
|
||||||
|
@ -125,7 +121,7 @@ app.post('/upload/:id', (req, res, next) => {
|
||||||
log.info('Uploading:', req.params.id);
|
log.info('Uploading:', req.params.id);
|
||||||
|
|
||||||
const protocol = notLocalHost ? 'https' : req.protocol;
|
const protocol = notLocalHost ? 'https' : req.protocol;
|
||||||
let url = `${protocol}://${req.get('host')}/download/${req.params.id}/`;
|
const url = `${protocol}://${req.get('host')}/download/${req.params.id}/`;
|
||||||
|
|
||||||
storage.set(req.params.id, file, filename, url).then(linkAndID => {
|
storage.set(req.params.id, file, filename, url).then(linkAndID => {
|
||||||
res.json(linkAndID);
|
res.json(linkAndID);
|
||||||
|
@ -133,10 +129,10 @@ app.post('/upload/:id', (req, res, next) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
let server = app.listen(conf.listen_port, () => {
|
app.listen(conf.listen_port, () => {
|
||||||
log.info('startServer:', `Portal app listening on port ${conf.listen_port}!`);
|
log.info('startServer:', `Portal app listening on port ${conf.listen_port}!`);
|
||||||
});
|
});
|
||||||
|
|
||||||
let validateID = route_id => {
|
const validateID = route_id => {
|
||||||
return route_id.match(/^[0-9a-fA-F]{32}$/) !== null;
|
return route_id.match(/^[0-9a-fA-F]{32}$/) !== null;
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,11 +7,11 @@ const path = require('path');
|
||||||
const fetch = require('node-fetch');
|
const fetch = require('node-fetch');
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
|
|
||||||
let notLocalHost = conf.notLocalHost;
|
const notLocalHost = conf.notLocalHost;
|
||||||
|
|
||||||
const mozlog = require('./log.js');
|
const mozlog = require('./log.js');
|
||||||
|
|
||||||
let log = mozlog('portal.storage');
|
const log = mozlog('portal.storage');
|
||||||
|
|
||||||
const redis = require('redis');
|
const redis = require('redis');
|
||||||
const redis_client = redis.createClient({
|
const redis_client = redis.createClient({
|
||||||
|
@ -67,7 +67,7 @@ function exists(id) {
|
||||||
function localLength(id) {
|
function localLength(id) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
resolve(fs.statSync(__dirname + '/../static/' + id).size);
|
resolve(fs.statSync(path.join(__dirname, '../static', id)).size);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
reject();
|
reject();
|
||||||
}
|
}
|
||||||
|
@ -75,15 +75,15 @@ function localLength(id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function localGet(id) {
|
function localGet(id) {
|
||||||
return fs.createReadStream(__dirname + '/../static/' + id);
|
return fs.createReadStream(path.join(__dirname, '../static', id));
|
||||||
}
|
}
|
||||||
|
|
||||||
function localSet(id, file, filename, url) {
|
function localSet(id, file, filename, url) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
fstream = fs.createWriteStream(__dirname + '/../static/' + id);
|
const fstream = fs.createWriteStream(path.join(__dirname, '../static', id));
|
||||||
file.pipe(fstream);
|
file.pipe(fstream);
|
||||||
fstream.on('close', () => {
|
fstream.on('close', () => {
|
||||||
let uuid = crypto.randomBytes(10).toString('hex');
|
const uuid = crypto.randomBytes(10).toString('hex');
|
||||||
|
|
||||||
redis_client.hmset([id, 'filename', filename, 'delete', uuid]);
|
redis_client.hmset([id, 'filename', filename, 'delete', uuid]);
|
||||||
redis_client.expire(id, 86400000);
|
redis_client.expire(id, 86400000);
|
||||||
|
@ -105,7 +105,7 @@ function localDelete(id, delete_token) {
|
||||||
reject();
|
reject();
|
||||||
} else {
|
} else {
|
||||||
redis_client.del(id);
|
redis_client.del(id);
|
||||||
resolve(fs.unlinkSync(__dirname + '/../static/' + id));
|
resolve(fs.unlinkSync(path.join(__dirname, '../static', id)));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -114,12 +114,12 @@ function localDelete(id, delete_token) {
|
||||||
function localForceDelete(id) {
|
function localForceDelete(id) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
redis_client.del(id);
|
redis_client.del(id);
|
||||||
resolve(fs.unlinkSync(__dirname + '/../static/' + id));
|
resolve(fs.unlinkSync(path.join(__dirname, '../static', id)));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function awsLength(id) {
|
function awsLength(id) {
|
||||||
let params = {
|
const params = {
|
||||||
Bucket: conf.s3_bucket,
|
Bucket: conf.s3_bucket,
|
||||||
Key: id
|
Key: id
|
||||||
};
|
};
|
||||||
|
@ -135,7 +135,7 @@ function awsLength(id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function awsGet(id) {
|
function awsGet(id) {
|
||||||
let params = {
|
const params = {
|
||||||
Bucket: conf.s3_bucket,
|
Bucket: conf.s3_bucket,
|
||||||
Key: id
|
Key: id
|
||||||
};
|
};
|
||||||
|
@ -144,19 +144,19 @@ function awsGet(id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function awsSet(id, file, filename, url) {
|
function awsSet(id, file, filename, url) {
|
||||||
let params = {
|
const params = {
|
||||||
Bucket: conf.s3_bucket,
|
Bucket: conf.s3_bucket,
|
||||||
Key: id,
|
Key: id,
|
||||||
Body: file
|
Body: file
|
||||||
};
|
};
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
s3.upload(params, function(err, data) {
|
s3.upload(params, function(err, _data) {
|
||||||
if (err) {
|
if (err) {
|
||||||
log.info('awsUploadError:', err.stack); // an error occurred
|
log.info('awsUploadError:', err.stack); // an error occurred
|
||||||
reject();
|
reject();
|
||||||
} else {
|
} else {
|
||||||
let uuid = crypto.randomBytes(10).toString('hex');
|
const uuid = crypto.randomBytes(10).toString('hex');
|
||||||
|
|
||||||
redis_client.hmset([id, 'filename', filename, 'delete', uuid]);
|
redis_client.hmset([id, 'filename', filename, 'delete', uuid]);
|
||||||
|
|
||||||
|
@ -197,12 +197,12 @@ function awsDelete(id, delete_token) {
|
||||||
reject();
|
reject();
|
||||||
} else {
|
} else {
|
||||||
redis_client.del(id);
|
redis_client.del(id);
|
||||||
let params = {
|
const params = {
|
||||||
Bucket: conf.s3_bucket,
|
Bucket: conf.s3_bucket,
|
||||||
Key: id
|
Key: id
|
||||||
};
|
};
|
||||||
|
|
||||||
s3.deleteObject(params, function(err, data) {
|
s3.deleteObject(params, function(err, _data) {
|
||||||
resolve(err);
|
resolve(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -213,12 +213,12 @@ function awsDelete(id, delete_token) {
|
||||||
function awsForceDelete(id) {
|
function awsForceDelete(id) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
redis_client.del(id);
|
redis_client.del(id);
|
||||||
let params = {
|
const params = {
|
||||||
Bucket: conf.s3_bucket,
|
Bucket: conf.s3_bucket,
|
||||||
Key: id
|
Key: id
|
||||||
};
|
};
|
||||||
|
|
||||||
s3.deleteObject(params, function(err, data) {
|
s3.deleteObject(params, function(err, _data) {
|
||||||
resolve(err);
|
resolve(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,13 +13,13 @@
|
||||||
<div id="download">
|
<div id="download">
|
||||||
{{#if filename}}
|
{{#if filename}}
|
||||||
<div class="title">
|
<div class="title">
|
||||||
Your friend is sending you a file: <br>
|
Your friend is sending you a file: <br />
|
||||||
{{{filename}}} ({{{filesize}}})
|
{{{filename}}} ({{{filesize}}})
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="share-window">
|
<div class="share-window">
|
||||||
<button id="download-btn" onclick="download()">Download File</button>
|
<button id="download-btn" onclick="download()">Download File</button>
|
||||||
<img id="expired-img" src="/resources/link_expired.png"/>
|
<img id="expired-img" src="/resources/link_expired.png" alt="Link expired" />
|
||||||
</div>
|
</div>
|
||||||
<div class="send-new" id="send-file">
|
<div class="send-new" id="send-file">
|
||||||
Send your own files
|
Send your own files
|
||||||
|
@ -30,11 +30,13 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="share-window">
|
<div class="share-window">
|
||||||
<img src="/resources/link_expired.png"/>
|
<img src="/resources/link_expired.png" alt="Link expired" />
|
||||||
</div>
|
</div>
|
||||||
|
<!-- htmllint id-no-dup="false" -->
|
||||||
<div class="send-new" id="send-file">
|
<div class="send-new" id="send-file">
|
||||||
Send your own files
|
Send your own files
|
||||||
</div>
|
</div>
|
||||||
|
<!-- htmllint tag-bans="$previous" -->
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
Share your files quickly, privately and securely.
|
Share your files quickly, privately and securely.
|
||||||
</div>
|
</div>
|
||||||
<div class="upload-window" ondrop="onUpload(event)" ondragover="allowDrop(event)">
|
<div class="upload-window" ondrop="onUpload(event)" ondragover="allowDrop(event)">
|
||||||
<div id="upload-img"><img src="/resources/upload.svg"/></div>
|
<div id="upload-img"><img src="/resources/upload.svg" alt="Upload"/></div>
|
||||||
<div>
|
<div>
|
||||||
DRAG & DROP
|
DRAG & DROP
|
||||||
</div>
|
</div>
|
||||||
|
@ -36,10 +36,12 @@
|
||||||
<div id="file-list">
|
<div id="file-list">
|
||||||
<table id="uploaded-files">
|
<table id="uploaded-files">
|
||||||
<tr>
|
<tr>
|
||||||
<th width=30%>File</th>
|
<!-- htmllint attr-bans="false" -->
|
||||||
<th width=45%>Copy URL</th>
|
<th width="30%">File</th>
|
||||||
<th width=18%>Expires in</th>
|
<th width="45%">Copy URL</th>
|
||||||
<th width=7%>Delete</th>
|
<th width="18%">Expires in</th>
|
||||||
|
<th width="7%">Delete</th>
|
||||||
|
<!-- htmllint tag-bans="$previous" -->
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
@ -49,7 +51,7 @@
|
||||||
Uploading
|
Uploading
|
||||||
</div>
|
</div>
|
||||||
<div class="upload-window">
|
<div class="upload-window">
|
||||||
<div id="upload-img"><img src="/resources/upload.svg"/></div>
|
<div id="upload-img"><img src="/resources/upload.svg" alt="Upload" /></div>
|
||||||
<div class="upload">
|
<div class="upload">
|
||||||
<!-- progress bar here -->
|
<!-- progress bar here -->
|
||||||
</div>
|
</div>
|
||||||
|
@ -61,7 +63,7 @@
|
||||||
Copy the link below to share your file!
|
Copy the link below to share your file!
|
||||||
</div>
|
</div>
|
||||||
<div class="share-window">
|
<div class="share-window">
|
||||||
<img src="/resources/share.png"/>
|
<img src="/resources/share.png" alt="Share" />
|
||||||
<div id="share-window-r">
|
<div id="share-window-r">
|
||||||
<div id="copy">
|
<div id="copy">
|
||||||
<input id="link" type="url" value="" readonly/>
|
<input id="link" type="url" value="" readonly/>
|
||||||
|
@ -76,7 +78,6 @@
|
||||||
Send another file
|
Send another file
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
Loading…
Reference in New Issue