diff --git a/frontend/src/fileList.js b/frontend/src/fileList.js
index 93c1f26f..74b0240a 100644
--- a/frontend/src/fileList.js
+++ b/frontend/src/fileList.js
@@ -2,17 +2,15 @@ import FileSender from './fileSender';
import Storage from './storage';
import * as metrics from './metrics';
import { allowedCopy, copyToClipboard, ONE_DAY_IN_MS } from './utils';
-import $ from 'jquery/dist/jquery.slim';
+import bel from 'bel';
+const HOUR = 1000 * 60 * 60;
const storage = new Storage();
let fileList = null;
-let $link = null;
document.addEventListener('DOMContentLoaded', function() {
- $link = $('#link');
fileList = document.getElementById('file-list');
toggleHeader();
- // eslint-disable-next-line prefer-const
Promise.all(
storage.files.map(file => {
const id = file.fileId;
@@ -33,180 +31,115 @@ function toggleHeader() {
fileList.hidden = storage.files.length === 0;
}
+function timeLeft(milliseconds) {
+ const minutes = Math.floor(milliseconds / 1000 / 60);
+ const hours = Math.floor(minutes / 60);
+ const seconds = Math.floor(milliseconds / 1000 % 60);
+ if (hours >= 1) {
+ return `${hours}h ${minutes % 60}m`;
+ } else if (hours === 0) {
+ return `${minutes}m ${seconds}s`;
+ }
+ return 'Expired';
+}
+
function addFile(file) {
if (!file) {
return;
}
- const row = document.createElement('tr');
- const name = document.createElement('td');
- const link = document.createElement('td');
- const $copyIcon = $('', {
- src: '/resources/copy-16.svg',
- class: 'icon-copy',
- 'data-l10n-id': 'copyUrlHover',
- disabled: !allowedCopy()
- });
- const expiry = document.createElement('td');
- const del = document.createElement('td');
- const $delIcon = $('', {
- src: '/resources/close-16.svg',
- class: 'icon-delete',
- 'data-l10n-id': 'deleteButtonHover'
- });
- const popupDiv = document.createElement('div');
- const $popupText = $('
', { class: 'popuptext' });
- const cellText = document.createTextNode(file.name);
-
- const url = file.url.trim() + `#${file.secretKey}`.trim();
-
- $link.attr('value', url);
- $('#copy-text')
- .attr('data-l10n-args', `{"filename": "${file.name}"}`)
- .attr('data-l10n-id', 'copyUrlFormLabelWithName');
-
- $popupText.attr('tabindex', '-1');
-
- name.appendChild(cellText);
-
- // create delete button
-
- const delSpan = document.createElement('span');
- $(delSpan)
- .addClass('icon-cancel-1')
- .attr('data-l10n-id', 'deleteButtonHover');
- del.appendChild(delSpan);
-
- const linkSpan = document.createElement('span');
- $(linkSpan).addClass('icon-docs').attr('data-l10n-id', 'copyUrlHover');
-
- link.appendChild(linkSpan);
- link.style.color = '#0A8DFF';
-
- //copy link to clipboard when icon clicked
- $copyIcon.on('click', () => {
- // record copied event from upload list
- metrics.copiedLink({ location: 'upload-list' });
- copyToClipboard(url);
- document.l10n.formatValue('copiedUrl').then(translated => {
- link.innerHTML = translated;
- });
- setTimeout(() => {
- const linkImg = document.createElement('img');
- $(linkImg)
- .addClass('icon-copy')
- .attr('data-l10n-id', 'copyUrlHover')
- .attr('src', '/resources/copy-16.svg');
-
- $(link).html(linkImg);
- }, 500);
- });
-
file.creationDate = new Date(file.creationDate);
-
+ const url = `${file.url}#${file.secretKey}`;
const future = new Date();
future.setTime(file.creationDate.getTime() + file.expiry);
+ const countdown = future.getTime() - Date.now();
- let countdown = 0;
- countdown = future.getTime() - Date.now();
- let minutes = Math.floor(countdown / 1000 / 60);
- let hours = Math.floor(minutes / 60);
- let seconds = Math.floor(countdown / 1000 % 60);
-
- const poll = () => {
- countdown = future.getTime() - Date.now();
- minutes = Math.floor(countdown / 1000 / 60);
- hours = Math.floor(minutes / 60);
- seconds = Math.floor(countdown / 1000 % 60);
- let t;
-
- if (hours >= 1) {
- expiry.innerHTML = hours + 'h ' + minutes % 60 + 'm';
- t = setTimeout(() => {
- poll();
- }, 60000);
- } else if (hours === 0) {
- expiry.innerHTML = minutes + 'm ' + seconds + 's';
- t = window.setTimeout(() => {
- poll();
- }, 1000);
- }
- //remove from list when expired
- if (countdown <= 0) {
- storage.remove(file.fileId);
- $(expiry).parents('tr').remove();
- window.clearTimeout(t);
- toggleHeader();
- }
- };
+ const row = bel`
+
+ ${file.name} |
+
+
+
+
+ |
+ ${timeLeft(countdown)} |
+
+
+
+
+ |
+
+ `;
+ const popup = row.querySelector('.popuptext');
+ const timeCol = row.querySelectorAll('td')[2];
+ if (!allowedCopy()) {
+ row.querySelector('.icon-copy').disabled = true;
+ }
+ fileList.querySelector('tbody').appendChild(row);
+ toggleHeader();
poll();
- // create popup
- popupDiv.classList.add('popup');
- const $popupMessage = $('
', { class: 'popup-message' });
- $popupMessage.attr('data-l10n-id', 'deletePopupText');
- const $popupAction = $('
', { class: 'popup-action' });
- const $popupNvmSpan = $('
', { class: 'popup-no' });
- $popupNvmSpan.attr('data-l10n-id', 'deletePopupCancel');
- const $popupDelSpan = $('', { class: 'popup-yes' });
- $popupDelSpan.attr('data-l10n-id', 'deletePopupYes');
+ function copyClick(e) {
+ metrics.copiedLink({ location: 'upload-list' });
+ copyToClipboard(url);
+ const icon = e.target;
+ const text = e.target.nextSibling;
+ icon.hidden = true;
+ text.hidden = false;
+ setTimeout(() => {
+ icon.hidden = false;
+ text.hidden = true;
+ }, 500);
+ }
- $popupText.html([$popupMessage, $popupAction]);
- $popupAction.html([$popupNvmSpan, $popupDelSpan]);
-
- // add data cells to table row
- row.appendChild(name);
- $(link).append($copyIcon);
- row.appendChild(link);
- row.appendChild(expiry);
- $(popupDiv).append($popupText);
- $(del).append($delIcon);
- del.appendChild(popupDiv);
- row.appendChild(del);
- $('tbody').append(row); //add row to table
-
- // delete file
- $popupText.find('.popup-yes').on('click', e => {
- FileSender.delete(file.fileId, file.deleteToken).then(() => {
- $(e.target).parents('tr').remove();
- const ttl = ONE_DAY_IN_MS - (Date.now() - file.creationDate.getTime());
- metrics
- .deletedUpload({
- size: file.size,
- time: file.totalTime,
- speed: file.uploadSpeed,
- type: file.typeOfUpload,
- location: 'upload-list',
- ttl
- })
- .then(() => {
- storage.remove(file.fileId);
- });
+ function poll() {
+ const countdown = future.getTime() - Date.now();
+ if (countdown <= 0) {
+ storage.remove(file.fileId);
+ row.parentNode.removeChild(row);
toggleHeader();
+ }
+ timeCol.textContent = timeLeft(countdown);
+ setTimeout(poll, countdown >= HOUR ? 60000 : 1000);
+ }
+
+ function deleteFile() {
+ FileSender.delete(file.fileId, file.deleteToken);
+ const ttl = ONE_DAY_IN_MS - (Date.now() - file.creationDate.getTime());
+ metrics.deletedUpload({
+ size: file.size,
+ time: file.totalTime,
+ speed: file.uploadSpeed,
+ type: file.typeOfUpload,
+ location: 'upload-list',
+ ttl
});
- });
+ row.parentNode.removeChild(row);
+ storage.remove(file.fileId);
+ toggleHeader();
+ }
- // show popup
- $delIcon.on('click', () => {
- $popupText.addClass('show').focus();
- });
+ function showPopup() {
+ popup.classList.add('show');
+ popup.focus();
+ }
- // hide popup
- $popupText.find('.popup-no').on('click', e => {
+ function cancel(e) {
e.stopPropagation();
- $popupText.removeClass('show');
- });
+ popup.classList.remove('show');
+ }
- $popupText.on('click', e => {
+ function stopProp(e) {
e.stopPropagation();
- });
-
- //close when popup loses focus
- $popupText.on('blur', () => {
- $popupText.removeClass('show');
- });
-
- toggleHeader();
+ }
}
async function checkExistence(id) {
diff --git a/frontend/src/fileSender.js b/frontend/src/fileSender.js
index dad2365a..2073c121 100644
--- a/frontend/src/fileSender.js
+++ b/frontend/src/fileSender.js
@@ -7,6 +7,14 @@ export default class FileSender extends EventEmitter {
this.file = file;
this.iv = window.crypto.getRandomValues(new Uint8Array(12));
this.uploadXHR = new XMLHttpRequest();
+ this.key = window.crypto.subtle.generateKey(
+ {
+ name: 'AES-GCM',
+ length: 128
+ },
+ true,
+ ['encrypt']
+ );
}
static delete(fileId, token) {
@@ -32,87 +40,79 @@ export default class FileSender extends EventEmitter {
this.uploadXHR.abort();
}
- upload() {
- const self = this;
- self.emit('loading');
- return Promise.all([
- window.crypto.subtle.generateKey(
- {
- name: 'AES-GCM',
- length: 128
- },
- true,
- ['encrypt', 'decrypt']
- ),
- new Promise((resolve, reject) => {
- const reader = new FileReader();
- reader.readAsArrayBuffer(this.file);
- reader.onload = function(event) {
- const plaintext = new Uint8Array(this.result);
- resolve(plaintext);
- };
- reader.onerror = function(err) {
- reject(err);
- };
- })
- ])
- .then(([secretKey, plaintext]) => {
- self.emit('encrypting');
- return Promise.all([
- window.crypto.subtle.encrypt(
- {
- name: 'AES-GCM',
- iv: this.iv,
- tagLength: 128
- },
- secretKey,
- plaintext
- ),
- window.crypto.subtle.exportKey('jwk', secretKey)
- ]);
- })
- .then(([encrypted, keydata]) => {
- return new Promise((resolve, reject) => {
- const file = this.file;
- const fileId = arrayToHex(this.iv);
- const dataView = new DataView(encrypted);
- const blob = new Blob([dataView], { type: file.type });
- const fd = new FormData();
- fd.append('data', blob, file.name);
+ readFile() {
+ return new Promise((resolve, reject) => {
+ const reader = new FileReader();
+ reader.readAsArrayBuffer(this.file);
+ reader.onload = function(event) {
+ const plaintext = new Uint8Array(this.result);
+ resolve(plaintext);
+ };
+ reader.onerror = function(err) {
+ reject(err);
+ };
+ });
+ }
- const xhr = self.uploadXHR;
+ uploadFile(encrypted, keydata) {
+ return new Promise((resolve, reject) => {
+ const file = this.file;
+ const fileId = arrayToHex(this.iv);
+ const dataView = new DataView(encrypted);
+ const blob = new Blob([dataView], { type: file.type });
+ const fd = new FormData();
+ fd.append('data', blob, file.name);
- xhr.upload.addEventListener('progress', e => {
- if (e.lengthComputable) {
- self.emit('progress', [e.loaded, e.total]);
- }
- });
+ const xhr = this.uploadXHR;
- xhr.onreadystatechange = () => {
- if (xhr.readyState === XMLHttpRequest.DONE) {
- if (xhr.status === 200) {
- const responseObj = JSON.parse(xhr.responseText);
- return resolve({
- url: responseObj.url,
- fileId: responseObj.id,
- secretKey: keydata.k,
- deleteToken: responseObj.delete
- });
- }
- reject(xhr.status);
- }
- };
-
- xhr.open('post', '/upload', true);
- xhr.setRequestHeader(
- 'X-File-Metadata',
- JSON.stringify({
- id: fileId,
- filename: encodeURIComponent(file.name)
- })
- );
- xhr.send(fd);
- });
+ xhr.upload.addEventListener('progress', e => {
+ if (e.lengthComputable) {
+ this.emit('progress', [e.loaded, e.total]);
+ }
});
+
+ xhr.onreadystatechange = () => {
+ if (xhr.readyState === XMLHttpRequest.DONE) {
+ if (xhr.status === 200) {
+ const responseObj = JSON.parse(xhr.responseText);
+ return resolve({
+ url: responseObj.url,
+ fileId: responseObj.id,
+ secretKey: keydata.k,
+ deleteToken: responseObj.delete
+ });
+ }
+ reject(xhr.status);
+ }
+ };
+
+ xhr.open('post', '/upload', true);
+ xhr.setRequestHeader(
+ 'X-File-Metadata',
+ JSON.stringify({
+ id: fileId,
+ filename: encodeURIComponent(file.name)
+ })
+ );
+ xhr.send(fd);
+ });
+ }
+
+ async upload() {
+ this.emit('loading');
+ const key = await this.key;
+ const plaintext = await this.readFile();
+ this.emit('encrypting');
+ const encrypted = await window.crypto.subtle.encrypt(
+ {
+ name: 'AES-GCM',
+ iv: this.iv,
+ tagLength: 128
+ },
+ key,
+ plaintext
+ );
+ const keydata = await window.crypto.subtle.exportKey('jwk', key);
+ return this.uploadFile(encrypted, keydata);
}
}
diff --git a/frontend/src/main.css b/frontend/src/main.css
index 583efd19..a8a7bc82 100644
--- a/frontend/src/main.css
+++ b/frontend/src/main.css
@@ -310,6 +310,10 @@ tbody {
opacity: 0.3;
}
+.text-copied {
+ color: #0a8dff;
+}
+
/* Popup container */
.popup {
position: absolute;
diff --git a/frontend/src/upload.js b/frontend/src/upload.js
index 2863b7e7..6ab00981 100644
--- a/frontend/src/upload.js
+++ b/frontend/src/upload.js
@@ -13,236 +13,230 @@ import Storage from './storage';
import * as metrics from './metrics';
import * as progress from './progress';
import * as fileList from './fileList';
-import $ from 'jquery/dist/jquery.slim';
const storage = new Storage();
-$(() => {
+async function upload(event) {
+ event.preventDefault();
+ const pageOne = document.getElementById('page-one');
+ const link = document.getElementById('link');
+ const uploadWindow = document.querySelector('.upload-window');
+ const uploadError = document.getElementById('upload-error');
+ const uploadProgress = document.getElementById('upload-progress');
+ const clickOrDrop = event.type === 'drop' ? 'drop' : 'click';
+
+ // don't allow upload if not on upload page
+ if (pageOne.hidden) {
+ return;
+ }
+
+ storage.totalUploads += 1;
+
+ let file = '';
+ if (clickOrDrop === 'drop') {
+ if (!event.originalEvent.dataTransfer.files[0]) {
+ uploadWindow.classList.remove('ondrag');
+ return;
+ }
+ if (
+ event.originalEvent.dataTransfer.files.length > 1 ||
+ event.originalEvent.dataTransfer.files[0].size === 0
+ ) {
+ uploadWindow.classList.remove('ondrag');
+ document.l10n.formatValue('uploadPageMultipleFilesAlert').then(str => {
+ alert(str);
+ });
+ return;
+ }
+ file = event.originalEvent.dataTransfer.files[0];
+ } else {
+ file = event.target.files[0];
+ }
+
+ if (file.size > MAXFILESIZE) {
+ return document.l10n
+ .formatValue('fileTooBig', { size: bytes(MAXFILESIZE) })
+ .then(alert);
+ }
+
+ pageOne.hidden = true;
+ uploadError.hidden = true;
+ uploadProgress.hidden = false;
+ document.l10n
+ .formatValue('uploadingPageProgress', {
+ size: bytes(file.size),
+ filename: file.name
+ })
+ .then(str => {
+ document.getElementById('upload-filename').textContent = str;
+ });
+ document.l10n.formatValue('importingFile').then(progress.setText);
+ //don't allow drag and drop when not on page-one
+ document.body.removeEventListener('drop', upload);
+
+ const fileSender = new FileSender(file);
+ document.getElementById('cancel-upload').addEventListener('click', () => {
+ fileSender.cancel();
+ metrics.cancelledUpload({
+ size: file.size,
+ type: clickOrDrop
+ });
+ location.reload();
+ });
+
+ let uploadStart;
+ fileSender.on('progress', data => {
+ uploadStart = uploadStart || Date.now();
+ progress.setProgress({
+ complete: data[0],
+ total: data[1]
+ });
+ });
+
+ fileSender.on('encrypting', () => {
+ document.l10n.formatValue('encryptingFile').then(progress.setText);
+ });
+
+ let t;
+ const startTime = Date.now();
+ metrics.startedUpload({
+ size: file.size,
+ type: clickOrDrop
+ });
+ // For large files we need to give the ui a tick to breathe and update
+ // before we kick off the FileSender
+ setTimeout(() => {
+ fileSender
+ .upload()
+ .then(info => {
+ const endTime = Date.now();
+ const time = endTime - startTime;
+ const uploadTime = endTime - uploadStart;
+ const speed = file.size / (uploadTime / 1000);
+ const expiration = EXPIRE_SECONDS * 1000;
+
+ link.setAttribute('value', `${info.url}#${info.secretKey}`);
+
+ metrics.completedUpload({
+ size: file.size,
+ time,
+ speed,
+ type: clickOrDrop
+ });
+
+ const fileData = {
+ name: file.name,
+ size: file.size,
+ fileId: info.fileId,
+ url: info.url,
+ secretKey: info.secretKey,
+ deleteToken: info.deleteToken,
+ creationDate: new Date(),
+ expiry: expiration,
+ totalTime: time,
+ typeOfUpload: clickOrDrop,
+ uploadSpeed: speed
+ };
+
+ document.getElementById('delete-file').addEventListener('click', () => {
+ FileSender.delete(fileData.fileId, fileData.deleteToken).then(() => {
+ const ttl =
+ ONE_DAY_IN_MS - (Date.now() - fileData.creationDate.getTime());
+ metrics
+ .deletedUpload({
+ size: fileData.size,
+ time: fileData.totalTime,
+ speed: fileData.uploadSpeed,
+ type: fileData.typeOfUpload,
+ location: 'success-screen',
+ ttl
+ })
+ .then(() => {
+ storage.remove(fileData.fileId);
+ location.reload();
+ });
+ });
+ });
+
+ storage.addFile(info.fileId, fileData);
+
+ pageOne.hidden = true;
+ uploadProgress.hidden = true;
+ uploadError.hidden = true;
+ document.getElementById('share-link').hidden = false;
+
+ fileList.addFile(fileData);
+ document.l10n.formatValue('notifyUploadDone').then(str => {
+ notify(str);
+ });
+ })
+ .catch(err => {
+ // err is 0 when coming from a cancel upload event
+ if (err === 0) {
+ return;
+ }
+ // only show error page when the error is anything other than user cancelling the upload
+ Raven.captureException(err);
+ pageOne.hidden = true;
+ uploadProgress.hidden = true;
+ uploadError.hidden = false;
+ window.clearTimeout(t);
+
+ metrics.stoppedUpload({
+ size: file.size,
+ type: clickOrDrop,
+ err
+ });
+ });
+ }, 10);
+}
+
+document.addEventListener('DOMContentLoaded', function() {
gcmCompliant()
.then(function() {
- const $pageOne = $('#page-one');
- const $copyBtn = $('#copy-btn');
- const $link = $('#link');
- const $uploadWindow = $('.upload-window');
- const $uploadError = $('#upload-error');
- const $uploadProgress = $('#upload-progress');
+ const pageOne = document.getElementById('page-one');
+ const copyBtn = document.getElementById('copy-btn');
+ const link = document.getElementById('link');
+ const uploadWindow = document.querySelector('.upload-window');
- $pageOne.removeAttr('hidden');
- $('#file-upload').on('change', onUpload);
+ pageOne.hidden = false;
+ document.getElementById('file-upload').addEventListener('change', upload);
- $(document.body).on('dragover', allowDrop).on('drop', onUpload);
+ document.body.addEventListener('dragover', allowDrop);
+ document.body.addEventListener('drop', upload);
// reset copy button
- $copyBtn.attr({
- disabled: !allowedCopy(),
- 'data-l10n-id': 'copyUrlFormButton'
- });
+ copyBtn.disabled = !allowedCopy();
+ copyBtn.setAttribute('data-l10n-id', 'copyUrlFormButton');
- $link.attr('disabled', false);
+ link.disabled = false;
// copy link to clipboard
- $copyBtn.on('click', () => {
- if (allowedCopy() && copyToClipboard($link.attr('value'))) {
+ copyBtn.addEventListener('click', () => {
+ if (allowedCopy() && copyToClipboard(link.getAttribute('value'))) {
metrics.copiedLink({ location: 'success-screen' });
//disable button for 3s
- $copyBtn.attr('disabled', true);
- $link.attr('disabled', true);
- $copyBtn.html(
- ''
- );
+ copyBtn.disabled = true;
+ link.disabled = true;
+ copyBtn.innerHtml =
+ '';
setTimeout(() => {
- $copyBtn.attr({
- disabled: false,
- 'data-l10n-id': 'copyUrlFormButton'
- });
- $link.attr('disabled', false);
+ copyBtn.disabled = !allowedCopy();
+ copyBtn.setAttribute('data-l10n-id', 'copyUrlFormButton');
+ link.disabled = false;
}, 3000);
}
});
- $uploadWindow
- .on('dragover', () => {
- $uploadWindow.addClass('ondrag');
- })
- .on('dragleave', () => {
- $uploadWindow.removeClass('ondrag');
- });
+ uploadWindow.addEventListener('dragover', () =>
+ uploadWindow.classList.add('ondrag')
+ );
+ uploadWindow.addEventListener('dragleave', () =>
+ uploadWindow.classList.remove('ondrag')
+ );
// on file upload by browse or drag & drop
- function onUpload(event) {
- event.preventDefault();
- const clickOrDrop = event.type === 'drop' ? 'drop' : 'click';
-
- // don't allow upload if not on upload page
- if ($pageOne.attr('hidden')) {
- return;
- }
-
- storage.totalUploads += 1;
-
- let file = '';
- if (clickOrDrop === 'drop') {
- if (!event.originalEvent.dataTransfer.files[0]) {
- $uploadWindow.removeClass('ondrag');
- return;
- }
- if (
- event.originalEvent.dataTransfer.files.length > 1 ||
- event.originalEvent.dataTransfer.files[0].size === 0
- ) {
- $uploadWindow.removeClass('ondrag');
- document.l10n
- .formatValue('uploadPageMultipleFilesAlert')
- .then(str => {
- alert(str);
- });
- return;
- }
- file = event.originalEvent.dataTransfer.files[0];
- } else {
- file = event.target.files[0];
- }
-
- if (file.size > MAXFILESIZE) {
- return document.l10n
- .formatValue('fileTooBig', { size: bytes(MAXFILESIZE) })
- .then(alert);
- }
-
- $pageOne.attr('hidden', true);
- $uploadError.attr('hidden', true);
- $uploadProgress.removeAttr('hidden');
- document.l10n
- .formatValue('uploadingPageProgress', {
- size: bytes(file.size),
- filename: file.name
- })
- .then(str => {
- $('#upload-filename').text(str);
- });
- document.l10n.formatValue('importingFile').then(progress.setText);
- //don't allow drag and drop when not on page-one
- $(document.body).off('drop', onUpload);
-
- const fileSender = new FileSender(file);
- $('#cancel-upload').on('click', () => {
- fileSender.cancel();
- metrics.cancelledUpload({
- size: file.size,
- type: clickOrDrop
- });
- location.reload();
- });
-
- let uploadStart;
- fileSender.on('progress', data => {
- uploadStart = uploadStart || Date.now();
- progress.setProgress({
- complete: data[0],
- total: data[1]
- });
- });
-
- fileSender.on('encrypting', () => {
- document.l10n.formatValue('encryptingFile').then(progress.setText);
- });
-
- let t;
- const startTime = Date.now();
- metrics.startedUpload({
- size: file.size,
- type: clickOrDrop
- });
- // For large files we need to give the ui a tick to breathe and update
- // before we kick off the FileSender
- setTimeout(() => {
- fileSender
- .upload()
- .then(info => {
- const endTime = Date.now();
- const time = endTime - startTime;
- const uploadTime = endTime - uploadStart;
- const speed = file.size / (uploadTime / 1000);
- const expiration = EXPIRE_SECONDS * 1000;
-
- metrics.completedUpload({
- size: file.size,
- time,
- speed,
- type: clickOrDrop
- });
-
- const fileData = {
- name: file.name,
- size: file.size,
- fileId: info.fileId,
- url: info.url,
- secretKey: info.secretKey,
- deleteToken: info.deleteToken,
- creationDate: new Date(),
- expiry: expiration,
- totalTime: time,
- typeOfUpload: clickOrDrop,
- uploadSpeed: speed
- };
-
- $('#delete-file').on('click', () => {
- FileSender.delete(
- fileData.fileId,
- fileData.deleteToken
- ).then(() => {
- const ttl =
- ONE_DAY_IN_MS -
- (Date.now() - fileData.creationDate.getTime());
- metrics
- .deletedUpload({
- size: fileData.size,
- time: fileData.totalTime,
- speed: fileData.uploadSpeed,
- type: fileData.typeOfUpload,
- location: 'success-screen',
- ttl
- })
- .then(() => {
- storage.remove(fileData.fileId);
- location.reload();
- });
- });
- });
-
- storage.addFile(info.fileId, fileData);
-
- $pageOne.attr('hidden', true);
- $uploadProgress.attr('hidden', true);
- $uploadError.attr('hidden', true);
- $('#share-link').removeAttr('hidden');
-
- fileList.addFile(fileData);
- document.l10n.formatValue('notifyUploadDone').then(str => {
- notify(str);
- });
- })
- .catch(err => {
- // err is 0 when coming from a cancel upload event
- if (err === 0) {
- return;
- }
- // only show error page when the error is anything other than user cancelling the upload
- Raven.captureException(err);
- $pageOne.attr('hidden', true);
- $uploadProgress.attr('hidden', true);
- $uploadError.removeAttr('hidden');
- window.clearTimeout(t);
-
- metrics.stoppedUpload({
- size: file.size,
- type: clickOrDrop,
- err
- });
- });
- }, 10);
- }
function allowDrop(ev) {
ev.preventDefault();
diff --git a/package-lock.json b/package-lock.json
index c67de524..931cd167 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -291,9 +291,9 @@
}
},
"aws-sdk": {
- "version": "2.95.0",
- "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.95.0.tgz",
- "integrity": "sha1-JuIdsUlEOx8GOUnch5hPDRdwDmo=",
+ "version": "2.98.0",
+ "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.98.0.tgz",
+ "integrity": "sha1-kK0CPXM4ndFex736+TLsq2VEVxE=",
"requires": {
"buffer": "4.9.1",
"crypto-browserify": "1.0.9",
@@ -1086,6 +1086,17 @@
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz",
"integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw=="
},
+ "bel": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/bel/-/bel-5.0.3.tgz",
+ "integrity": "sha512-bMLvUOrKBM2zWp3Ab6UugjCjFmsZtIeKH3oMNWaUr9RA94sNeicajzptZHQWU3K8KNIL8o6JwAmKG1W3mUiwXw==",
+ "dev": true,
+ "requires": {
+ "hyperx": "2.3.0",
+ "is-electron": "2.1.0",
+ "pelo": "0.0.3"
+ }
+ },
"big.js": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-3.1.3.tgz",
@@ -2330,7 +2341,7 @@
"integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
"dev": true,
"requires": {
- "es5-ext": "0.10.26"
+ "es5-ext": "0.10.27"
}
},
"dasherize": {
@@ -2640,12 +2651,6 @@
}
}
},
- "dom-walk": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz",
- "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=",
- "dev": true
- },
"domain-browser": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz",
@@ -2801,9 +2806,9 @@
}
},
"es5-ext": {
- "version": "0.10.26",
- "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.26.tgz",
- "integrity": "sha1-UbISilMbcMT2dkCTpzy+u4IYY3I=",
+ "version": "0.10.27",
+ "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.27.tgz",
+ "integrity": "sha512-3KXJRYzKXTd7xfFy5uZsJCXue55fAYQ035PRjyYk2PicllxIwcW9l3AbM/eGaw3vgVAUW4tl4xg9AXDEI6yw0w==",
"dev": true,
"requires": {
"es6-iterator": "2.0.1",
@@ -2817,7 +2822,7 @@
"dev": true,
"requires": {
"d": "1.0.0",
- "es5-ext": "0.10.26",
+ "es5-ext": "0.10.27",
"es6-symbol": "3.1.1"
}
},
@@ -2828,7 +2833,7 @@
"dev": true,
"requires": {
"d": "1.0.0",
- "es5-ext": "0.10.26",
+ "es5-ext": "0.10.27",
"es6-iterator": "2.0.1",
"es6-set": "0.1.5",
"es6-symbol": "3.1.1",
@@ -2848,7 +2853,7 @@
"dev": true,
"requires": {
"d": "1.0.0",
- "es5-ext": "0.10.26",
+ "es5-ext": "0.10.27",
"es6-iterator": "2.0.1",
"es6-symbol": "3.1.1",
"event-emitter": "0.3.5"
@@ -2861,7 +2866,7 @@
"dev": true,
"requires": {
"d": "1.0.0",
- "es5-ext": "0.10.26"
+ "es5-ext": "0.10.27"
}
},
"es6-weak-map": {
@@ -2871,7 +2876,7 @@
"dev": true,
"requires": {
"d": "1.0.0",
- "es5-ext": "0.10.26",
+ "es5-ext": "0.10.27",
"es6-iterator": "2.0.1",
"es6-symbol": "3.1.1"
}
@@ -3142,7 +3147,7 @@
"dev": true,
"requires": {
"d": "1.0.0",
- "es5-ext": "0.10.26"
+ "es5-ext": "0.10.27"
}
},
"event-stream": {
@@ -4520,24 +4525,6 @@
"is-glob": "2.0.1"
}
},
- "global": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz",
- "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=",
- "dev": true,
- "requires": {
- "min-document": "2.19.0",
- "process": "0.5.2"
- },
- "dependencies": {
- "process": {
- "version": "0.5.2",
- "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz",
- "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=",
- "dev": true
- }
- }
- },
"globals": {
"version": "9.18.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
@@ -4784,6 +4771,21 @@
}
}
},
+ "hyperscript-attribute-to-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/hyperscript-attribute-to-property/-/hyperscript-attribute-to-property-1.0.0.tgz",
+ "integrity": "sha1-glMI1Ju44pV5I/cxmBvMgRytev8=",
+ "dev": true
+ },
+ "hyperx": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/hyperx/-/hyperx-2.3.0.tgz",
+ "integrity": "sha1-cPRz1m1K1VDd0cg+S+JlEna78eI=",
+ "dev": true,
+ "requires": {
+ "hyperscript-attribute-to-property": "1.0.0"
+ }
+ },
"iconv-lite": {
"version": "0.4.15",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz",
@@ -5064,6 +5066,12 @@
"integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
"dev": true
},
+ "is-electron": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-electron/-/is-electron-2.1.0.tgz",
+ "integrity": "sha512-dkg5xT383+M6zIbbXW/z7n2nz4SFUi2OSyhntnFYkRdtV+HVEfdjEK+5AWisfYgkpe3WYjTIuh7toaKmSfFVWw==",
+ "dev": true
+ },
"is-equal-shallow": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
@@ -5260,12 +5268,6 @@
"resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz",
"integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc="
},
- "jquery": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.2.1.tgz",
- "integrity": "sha1-XE2d5lKvbNCncBVKYxu6ErAVx4c=",
- "dev": true
- },
"js-base64": {
"version": "2.1.9",
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.1.9.tgz",
@@ -6324,15 +6326,6 @@
"integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=",
"dev": true
},
- "min-document": {
- "version": "2.19.0",
- "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
- "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=",
- "dev": true,
- "requires": {
- "dom-walk": "0.1.1"
- }
- },
"minimalistic-assert": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz",
@@ -6574,7 +6567,7 @@
"stream-browserify": "2.0.1",
"stream-http": "2.7.2",
"string_decoder": "0.10.31",
- "timers-browserify": "2.0.3",
+ "timers-browserify": "2.0.4",
"tty-browserify": "0.0.0",
"url": "0.11.0",
"util": "0.10.3",
@@ -6638,12 +6631,11 @@
}
},
"timers-browserify": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.3.tgz",
- "integrity": "sha512-+JAqyNgg+M8+gXIrq2EeUr4kZqRz47Ysco7X5QKRGScRE9HIHckyHD1asozSFGeqx2nmPCgA8T5tIGVO0ML7/w==",
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.4.tgz",
+ "integrity": "sha512-uZYhyU3EX8O7HQP+J9fTVYwsq90Vr68xPEFo7yrVImIxYvHgukBEgOB/SgGoorWVTzGM/3Z+wUNnboA4M8jWrg==",
"dev": true,
"requires": {
- "global": "4.3.2",
"setimmediate": "1.0.5"
}
},
@@ -7046,6 +7038,12 @@
"sha.js": "2.4.8"
}
},
+ "pelo": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/pelo/-/pelo-0.0.3.tgz",
+ "integrity": "sha1-+2smsGEgNtsCuRj+qrPowMTLWXw=",
+ "dev": true
+ },
"pify": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
@@ -10560,9 +10558,9 @@
}
},
"webpack": {
- "version": "3.5.2",
- "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.5.2.tgz",
- "integrity": "sha1-qWAQZuI688gPO/l1j9eUypd48lE=",
+ "version": "3.5.4",
+ "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.5.4.tgz",
+ "integrity": "sha1-VYPrJj7Se3i1vRe/37DrGxzRv4E=",
"dev": true,
"requires": {
"acorn": "5.1.1",
diff --git a/package.json b/package.json
index 5eaf0461..78af54d9 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
"version": "1.1.0",
"author": "Mozilla (https://mozilla.org)",
"dependencies": {
- "aws-sdk": "^2.95.0",
+ "aws-sdk": "^2.98.0",
"body-parser": "^1.17.2",
"connect-busboy": "0.0.2",
"convict": "^3.0.0",
@@ -23,6 +23,7 @@
"babel-polyfill": "^6.23.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-2": "^6.24.1",
+ "bel": "^5.0.3",
"browserify": "^14.4.0",
"cross-env": "^5.0.5",
"css-mqpacker": "^6.0.1",
@@ -33,7 +34,6 @@
"eslint-plugin-security": "^1.4.0",
"git-rev-sync": "^1.9.1",
"husky": "^0.14.3",
- "jquery": "^3.2.1",
"l20n": "^5.0.0",
"lint-staged": "^4.0.3",
"mocha": "^3.4.2",
@@ -50,7 +50,7 @@
"supertest": "^3.0.0",
"testpilot-ga": "^0.3.0",
"webcrypto-liner": "^0.1.25",
- "webpack": "^3.5.2",
+ "webpack": "^3.5.4",
"webpack-dev-middleware": "^1.12.0"
},
"engines": {
diff --git a/webpack.config.js b/webpack.config.js
index cd576cec..c9439dd4 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -11,15 +11,15 @@ module.exports = {
publicPath: '/'
},
module: {
- loaders: [
+ rules: [
{
test: /\.js$/,
- loaders: 'babel-loader',
+ loader: 'babel-loader',
include: [
path.resolve(__dirname, 'frontend'),
path.resolve(__dirname, 'node_modules/testpilot-ga/src')
],
- query: {
+ options: {
babelrc: false,
presets: [['es2015', { modules: false }], 'stage-2']
}