mirror of
https://gitlab.com/timvisee/send.git
synced 2025-12-06 14:10:53 +03:00
Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
030d65d7af | ||
|
|
aa113fd903 | ||
|
|
caeba94e04 | ||
|
|
a7de951115 | ||
|
|
e17d1f7235 | ||
|
|
51ba253f95 | ||
|
|
fef26e083a | ||
|
|
de826afb9b | ||
|
|
5944b85e67 | ||
|
|
d208a82089 | ||
|
|
a64eced8be | ||
|
|
ada45323e1 | ||
|
|
ced8c24f47 | ||
|
|
5b9e9d5146 | ||
|
|
280a4f65e7 | ||
|
|
d2dd9f4b4d | ||
|
|
2897a39131 | ||
|
|
626b9068a9 | ||
|
|
c3bb876a2c | ||
|
|
48912dd4d4 | ||
|
|
f1c894d14f | ||
|
|
60d61fa52c | ||
|
|
68705f60db | ||
|
|
92303988c0 | ||
|
|
49d578217c | ||
|
|
1abb3b7ebe | ||
|
|
4f3c2498a6 | ||
|
|
33babe6f67 | ||
|
|
a51ee89939 | ||
|
|
bca79489c0 | ||
|
|
ddfbb06e1a | ||
|
|
cd2c944d41 | ||
|
|
5f66496519 | ||
|
|
318964251d | ||
|
|
5effeb16d1 | ||
|
|
c9c7c3182c | ||
|
|
18b95c497f | ||
|
|
80d0f73b06 | ||
|
|
522290dbef |
@@ -21,6 +21,7 @@ rules:
|
||||
|
||||
eol-last: [error, always]
|
||||
eqeqeq: error
|
||||
no-alert: warn
|
||||
no-console: warn
|
||||
no-path-concat: error
|
||||
no-unused-vars: [error, {argsIgnorePattern: "^_|err|event|next|reject"}]
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,6 +4,7 @@ public/upload.js
|
||||
public/download.js
|
||||
public/version.json
|
||||
public/l20n.min.js
|
||||
public/polyfill.min.js
|
||||
static/*
|
||||
!static/info.txt
|
||||
test/frontend/bundle.js
|
||||
|
||||
@@ -32,7 +32,7 @@ $ redis-server /usr/local/etc/redis.conf
|
||||
|
||||
## Localization
|
||||
|
||||
_Coming soon_ (see [#57](https://github.com/mozilla/send/issues/57))
|
||||
Firefox Send localization is managed via [Pontoon](https://pontoon.mozilla.org/projects/test-pilot-firefox-send/), not direct pull requests to the repository. If you want to fix a typo, add a new language, or simply know more about localization, please get in touch with the [existing localization team](https://pontoon.mozilla.org/teams/) for your language, or Mozilla’s [l10n-drivers](https://wiki.mozilla.org/L10n:Mozilla_Team#Mozilla_Corporation) for guidance.
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ deployment:
|
||||
|
||||
test:
|
||||
override:
|
||||
- npm run build:version
|
||||
- npm run lint
|
||||
- npm test
|
||||
- nsp check
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
window.Raven = require('raven-js');
|
||||
window.Raven.config(window.dsn).install();
|
||||
window.dsn = undefined;
|
||||
if (navigator.doNotTrack !== '1' && window.RAVEN_CONFIG) {
|
||||
window.Raven.config(window.SENTRY_ID, window.RAVEN_CONFIG).install();
|
||||
}
|
||||
|
||||
const testPilotGA = require('testpilot-ga');
|
||||
const { gcmCompliant, sendEvent } = require('./utils');
|
||||
window.analytics = new testPilotGA({
|
||||
an: 'Firefox Send',
|
||||
ds: 'web',
|
||||
tid: window.trackerId
|
||||
tid: window.GOOGLE_ANALYTICS_ID
|
||||
});
|
||||
|
||||
const isSender = !location.pathname.includes('/download');
|
||||
|
||||
@@ -144,7 +144,7 @@ $(document).ready(function() {
|
||||
$('#download-btn').attr('hidden', true);
|
||||
$('#expired-img').removeAttr('hidden');
|
||||
}
|
||||
return;
|
||||
throw err;
|
||||
})
|
||||
.then(([decrypted, fname]) => {
|
||||
const endTime = Date.now();
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
const EventEmitter = require('events');
|
||||
const { arrayToHex } = require('./utils');
|
||||
|
||||
const Raven = window.Raven;
|
||||
|
||||
class FileSender extends EventEmitter {
|
||||
constructor(file) {
|
||||
super();
|
||||
@@ -38,15 +36,14 @@ class FileSender extends EventEmitter {
|
||||
const self = this;
|
||||
self.emit('loading', true);
|
||||
return Promise.all([
|
||||
window.crypto.subtle
|
||||
.generateKey(
|
||||
{
|
||||
name: 'AES-GCM',
|
||||
length: 128
|
||||
},
|
||||
true,
|
||||
['encrypt', 'decrypt']
|
||||
),
|
||||
window.crypto.subtle.generateKey(
|
||||
{
|
||||
name: 'AES-GCM',
|
||||
length: 128
|
||||
},
|
||||
true,
|
||||
['encrypt', 'decrypt']
|
||||
),
|
||||
new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsArrayBuffer(this.file);
|
||||
@@ -133,10 +130,6 @@ class FileSender extends EventEmitter {
|
||||
);
|
||||
xhr.send(fd);
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
Raven.captureException(err);
|
||||
return Promise.reject(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,12 @@ class Storage {
|
||||
for (let i = 0; i < this.engine.length; i++) {
|
||||
const k = this.engine.key(i);
|
||||
if (isFile(k)) {
|
||||
fs.push(JSON.parse(this.engine.getItem(k))); // parse or whatever else
|
||||
try {
|
||||
fs.push(JSON.parse(this.engine.getItem(k)));
|
||||
} catch (err) {
|
||||
// obviously you're not a golfer
|
||||
this.engine.removeItem(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
return fs.sort((file1, file2) => {
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
/* global MAXFILESIZE EXPIRE_SECONDS */
|
||||
require('./common');
|
||||
const FileSender = require('./fileSender');
|
||||
const {
|
||||
notify,
|
||||
findMetric,
|
||||
sendEvent,
|
||||
ONE_DAY_IN_MS
|
||||
} = require('./utils');
|
||||
const { notify, findMetric, sendEvent, ONE_DAY_IN_MS } = require('./utils');
|
||||
const bytes = require('bytes');
|
||||
const Storage = require('./storage');
|
||||
const storage = new Storage(localStorage);
|
||||
|
||||
@@ -99,12 +99,7 @@ function findMetric(href) {
|
||||
}
|
||||
|
||||
function isFile(id) {
|
||||
return ![
|
||||
'referrer',
|
||||
'totalDownloads',
|
||||
'totalUploads',
|
||||
'testpilot_ga__cid'
|
||||
].includes(id);
|
||||
return /^[0-9a-fA-F]{10}$/.test(id);
|
||||
}
|
||||
|
||||
function sendEvent() {
|
||||
|
||||
147
package-lock.json
generated
147
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "firefox-send",
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.3",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -263,6 +263,43 @@
|
||||
"js-tokens": "3.0.2"
|
||||
}
|
||||
},
|
||||
"babel-polyfill": {
|
||||
"version": "6.23.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz",
|
||||
"integrity": "sha1-g2TKYt+Or7gwSZ9pkXdGbDsDSZ0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-runtime": "6.25.0",
|
||||
"core-js": "2.4.1",
|
||||
"regenerator-runtime": "0.10.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz",
|
||||
"integrity": "sha1-TekR5mew6ukSTjQlS1OupvxhjT4=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"babel-runtime": {
|
||||
"version": "6.25.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.25.0.tgz",
|
||||
"integrity": "sha1-M7mOql1IK7AajRqmtDetKwGuxBw=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"core-js": "2.4.1",
|
||||
"regenerator-runtime": "0.10.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz",
|
||||
"integrity": "sha1-TekR5mew6ukSTjQlS1OupvxhjT4=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
@@ -271,12 +308,12 @@
|
||||
"base64-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz",
|
||||
"integrity": "sha1-qRlH2h9KUW6jjltOwOw3c2deCIY="
|
||||
"integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw=="
|
||||
},
|
||||
"bn.js": {
|
||||
"version": "4.11.7",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.7.tgz",
|
||||
"integrity": "sha1-3bBI5Q2UgnkAlME+s/z8gzznq0Y=",
|
||||
"integrity": "sha512-LxFiV5mefv0ley0SzqkOPR1bC4EbpPx8LkOz5vMe/Yi15t5hzwgO/G+tc7wOtL4PZTYjwHu8JnEiSLumuSjSfA==",
|
||||
"dev": true
|
||||
},
|
||||
"body-parser": {
|
||||
@@ -451,7 +488,7 @@
|
||||
"glob": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
|
||||
"integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=",
|
||||
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "1.0.0",
|
||||
@@ -480,7 +517,7 @@
|
||||
"string_decoder": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
||||
"integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=",
|
||||
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.1"
|
||||
@@ -917,65 +954,75 @@
|
||||
"resolved": "https://registry.npmjs.org/convict/-/convict-3.0.0.tgz",
|
||||
"integrity": "sha1-JZ8wv7h+4JRIYEhiA1GdRntNUbU=",
|
||||
"requires": {
|
||||
"depd": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz",
|
||||
"json5": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
|
||||
"lodash.clonedeep": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
|
||||
"minimist": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||
"moment": "https://registry.npmjs.org/moment/-/moment-2.17.1.tgz",
|
||||
"validator": "https://registry.npmjs.org/validator/-/validator-7.0.0.tgz",
|
||||
"varify": "https://registry.npmjs.org/varify/-/varify-0.2.0.tgz"
|
||||
"depd": "1.1.0",
|
||||
"json5": "0.5.1",
|
||||
"lodash.clonedeep": "4.5.0",
|
||||
"minimist": "1.2.0",
|
||||
"moment": "2.17.1",
|
||||
"validator": "7.0.0",
|
||||
"varify": "0.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"depd": {
|
||||
"version": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz",
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz",
|
||||
"integrity": "sha1-4b2Cxqq2ztlluXuIsX7T5SjKGMM="
|
||||
},
|
||||
"json5": {
|
||||
"version": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
|
||||
"integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE="
|
||||
},
|
||||
"lodash.clonedeep": {
|
||||
"version": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
|
||||
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="
|
||||
},
|
||||
"minimist": {
|
||||
"version": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
|
||||
},
|
||||
"moment": {
|
||||
"version": "https://registry.npmjs.org/moment/-/moment-2.17.1.tgz",
|
||||
"version": "2.17.1",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.17.1.tgz",
|
||||
"integrity": "sha1-/tlQYGPzaxDwZsi1mhRNf66+HYI="
|
||||
},
|
||||
"validator": {
|
||||
"version": "https://registry.npmjs.org/validator/-/validator-7.0.0.tgz",
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/validator/-/validator-7.0.0.tgz",
|
||||
"integrity": "sha1-x03rgGNRL6w1VHk45vCxUEooL9I="
|
||||
},
|
||||
"varify": {
|
||||
"version": "https://registry.npmjs.org/varify/-/varify-0.2.0.tgz",
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/varify/-/varify-0.2.0.tgz",
|
||||
"integrity": "sha1-GR2p/p3EzWjQ0USY1OKpEP9OZRY=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"redeyed": "https://registry.npmjs.org/redeyed/-/redeyed-1.0.1.tgz",
|
||||
"through": "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
|
||||
"redeyed": "1.0.1",
|
||||
"through": "2.3.8"
|
||||
},
|
||||
"dependencies": {
|
||||
"redeyed": {
|
||||
"version": "https://registry.npmjs.org/redeyed/-/redeyed-1.0.1.tgz",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/redeyed/-/redeyed-1.0.1.tgz",
|
||||
"integrity": "sha1-6WwZO0DAgWsArshCaY5hGF5VSYo=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"esprima": "https://registry.npmjs.org/esprima/-/esprima-3.0.0.tgz"
|
||||
"esprima": "3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"esprima": {
|
||||
"version": "https://registry.npmjs.org/esprima/-/esprima-3.0.0.tgz",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-3.0.0.tgz",
|
||||
"integrity": "sha1-U88kes2ncxPlUcOqLnM0LT+099k=",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"through": {
|
||||
"version": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
|
||||
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
|
||||
"optional": true
|
||||
}
|
||||
@@ -1302,7 +1349,7 @@
|
||||
"string_decoder": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
||||
"integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=",
|
||||
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.1"
|
||||
@@ -1526,7 +1573,7 @@
|
||||
"eslint-plugin-security": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-1.4.0.tgz",
|
||||
"integrity": "sha1-1PMUSEqAsbYTuMiIboT1Lv4VJsI=",
|
||||
"integrity": "sha512-xlS7P2PLMXeqfhyf3NpqbvbnW04kN8M9NtmhpR3XGyOvt/vNKS7XPXT5EDbwKW9vCjWH4PpfQvgD/+JgN0VJKA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-regex": "1.1.0"
|
||||
@@ -1730,7 +1777,7 @@
|
||||
"iconv-lite": {
|
||||
"version": "0.4.18",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz",
|
||||
"integrity": "sha1-I9hlaxaq5nQqwpcy6o8DNqR4nPI=",
|
||||
"integrity": "sha512-sr1ZQph3UwHTR0XftSbK85OvBbxe/abLGzEnPENCQwmHf7sck8Oyu4ob3LgBxWWxRoM+QszeUyl7jbqapu2TqA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@@ -2002,7 +2049,7 @@
|
||||
"globals": {
|
||||
"version": "9.18.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
|
||||
"integrity": "sha1-qjiWs+abSH8X4x7SFD1pqOMMLYo=",
|
||||
"integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==",
|
||||
"dev": true
|
||||
},
|
||||
"globby": {
|
||||
@@ -2022,7 +2069,7 @@
|
||||
"glob": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
|
||||
"integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=",
|
||||
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "1.0.0",
|
||||
@@ -2947,7 +2994,7 @@
|
||||
"lru-cache": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz",
|
||||
"integrity": "sha1-Yi4y6CSItJJ5EUpPns9F581rulU=",
|
||||
"integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"pseudomap": "1.0.2",
|
||||
@@ -3093,7 +3140,7 @@
|
||||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"requires": {
|
||||
"brace-expansion": "1.1.8"
|
||||
}
|
||||
@@ -3226,7 +3273,7 @@
|
||||
"string_decoder": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
||||
"integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=",
|
||||
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.1"
|
||||
@@ -3787,7 +3834,7 @@
|
||||
"promise": {
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
|
||||
"integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=",
|
||||
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
|
||||
"requires": {
|
||||
"asap": "2.0.6"
|
||||
}
|
||||
@@ -3919,7 +3966,7 @@
|
||||
"randombytes": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz",
|
||||
"integrity": "sha1-3ACaJGuNCaF3tLegrne8Vw9LG3k=",
|
||||
"integrity": "sha512-8T7Zn1AhMsQ/HI1SjcCfT/t4ii3eAqco3yOcSzS4mozsOz69lHLsoMXmF9nZgnFanYscnSlUSgs8uZyKzpE6kg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.1"
|
||||
@@ -4005,7 +4052,7 @@
|
||||
"string_decoder": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
||||
"integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=",
|
||||
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.1"
|
||||
@@ -4142,6 +4189,12 @@
|
||||
"resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.1.0.tgz",
|
||||
"integrity": "sha1-NXdOtzW/UPtsB46DM0tHI1AgfXk="
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.10.5",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz",
|
||||
"integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=",
|
||||
"dev": true
|
||||
},
|
||||
"regex-cache": {
|
||||
"version": "0.4.3",
|
||||
"resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz",
|
||||
@@ -4246,7 +4299,7 @@
|
||||
"glob": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
|
||||
"integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=",
|
||||
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "1.0.0",
|
||||
@@ -4296,7 +4349,7 @@
|
||||
"safe-buffer": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
|
||||
"integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM=",
|
||||
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
|
||||
"dev": true
|
||||
},
|
||||
"safe-regex": {
|
||||
@@ -4444,7 +4497,7 @@
|
||||
"glob": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
|
||||
"integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=",
|
||||
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "1.0.0",
|
||||
@@ -4590,7 +4643,7 @@
|
||||
"string_decoder": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
||||
"integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=",
|
||||
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.1"
|
||||
@@ -4635,7 +4688,7 @@
|
||||
"string_decoder": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
||||
"integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=",
|
||||
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.1"
|
||||
@@ -4646,7 +4699,7 @@
|
||||
"stream-http": {
|
||||
"version": "2.7.2",
|
||||
"resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.7.2.tgz",
|
||||
"integrity": "sha1-QKBQ7I3DtTsz2ZCUFcAsC/Gr+60=",
|
||||
"integrity": "sha512-c0yTD2rbQzXtSsFSVhtpvY/vS6u066PcXOX9kBB3mSO76RiUQzL340uJkGBWnlBg4/HZzqiUXtaVA7wcRcJgEw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"builtin-status-codes": "3.0.0",
|
||||
@@ -4674,7 +4727,7 @@
|
||||
"string_decoder": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
||||
"integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=",
|
||||
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.1"
|
||||
@@ -4710,7 +4763,7 @@
|
||||
"string_decoder": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
||||
"integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=",
|
||||
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.1"
|
||||
@@ -5007,7 +5060,7 @@
|
||||
"readable-stream": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
|
||||
"integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=",
|
||||
"integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"core-util-is": "1.0.2",
|
||||
@@ -5022,7 +5075,7 @@
|
||||
"string_decoder": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
||||
"integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=",
|
||||
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.1"
|
||||
@@ -5152,7 +5205,7 @@
|
||||
"string_decoder": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
||||
"integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=",
|
||||
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.1"
|
||||
|
||||
36
package.json
36
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "firefox-send",
|
||||
"description": "File Sharing Experiment",
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.3",
|
||||
"author": "Mozilla (https://mozilla.org)",
|
||||
"dependencies": {
|
||||
"aws-sdk": "^2.89.0",
|
||||
@@ -17,6 +17,7 @@
|
||||
"redis": "^2.7.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-polyfill": "^6.23.0",
|
||||
"browserify": "^14.4.0",
|
||||
"eslint": "^4.3.0",
|
||||
"eslint-plugin-mocha": "^4.11.0",
|
||||
@@ -46,48 +47,55 @@
|
||||
"license": "MPL-2.0",
|
||||
"repository": "mozilla/send",
|
||||
"availableLanguages": [
|
||||
"en-US",
|
||||
"zh-TW",
|
||||
"zh-CN",
|
||||
"az",
|
||||
"cs",
|
||||
"cy",
|
||||
"de",
|
||||
"dsb",
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"fr",
|
||||
"fy-NL",
|
||||
"de",
|
||||
"hsb",
|
||||
"hu",
|
||||
"it",
|
||||
"ja",
|
||||
"kab",
|
||||
"ms",
|
||||
"nb-NO",
|
||||
"nl",
|
||||
"nn-NO",
|
||||
"pt-PT",
|
||||
"pt-BR",
|
||||
"pt-PT",
|
||||
"ru",
|
||||
"sk",
|
||||
"sl",
|
||||
"dsb",
|
||||
"hsb",
|
||||
"es-CL",
|
||||
"es-ES",
|
||||
"sr",
|
||||
"sv-SE",
|
||||
"tr",
|
||||
"cy"
|
||||
"zh-CN",
|
||||
"zh-TW"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "npm-run-all build:*",
|
||||
"build:upload": "browserify frontend/src/upload.js -g uglifyify -o public/upload.js",
|
||||
"build:download": "browserify frontend/src/download.js -g uglifyify -o public/download.js",
|
||||
"build:version": "node scripts/version",
|
||||
"build:l10n": "cp node_modules/l20n/dist/web/l20n.min.js public",
|
||||
"build:vendor": "cp node_modules/l20n/dist/web/l20n.min.js node_modules/babel-polyfill/dist/polyfill.min.js public",
|
||||
"dev": "npm run build && npm start",
|
||||
"format": "prettier '{frontend/src/,scripts/,server/,test/**/!(bundle)}*.js' 'public/*.css' --single-quote --write",
|
||||
"get-prod-locales": "node scripts/get-prod-locales",
|
||||
"get-prod-locales:write": "npm run get-prod-locales -- --write",
|
||||
"lint": "npm-run-all lint:*",
|
||||
"lint:css": "stylelint 'public/*.css'",
|
||||
"lint:js": "eslint .",
|
||||
"lint-locales": "node scripts/lint-locales",
|
||||
"lint-locales:dev": "npm run lint-locales",
|
||||
"lint-locales:prod": "npm run lint-locales -- --production",
|
||||
"start": "node server/server",
|
||||
"test": "npm-run-all test:*",
|
||||
"test:unit": "mocha test/unit",
|
||||
"test:server": "mocha test/server",
|
||||
"test:browser": "browserify test/frontend/frontend.bundle.js -o test/frontend/bundle.js -d && node test/frontend/driver.js"
|
||||
"test--browser": "browserify test/frontend/frontend.bundle.js -o test/frontend/bundle.js -d && node test/frontend/driver.js"
|
||||
}
|
||||
}
|
||||
|
||||
94
public/locales/az/send.ftl
Normal file
94
public/locales/az/send.ftl
Normal file
@@ -0,0 +1,94 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Send
|
||||
siteSubtitle = web eksperiment
|
||||
siteFeedback = Geri dönüş
|
||||
uploadPageHeader = Məxfi, Şifrələnmiş Fayl Paylaşma
|
||||
uploadPageExplainer = Fayllarınızı təhlükəsiz, məxfi, şifrələnmiş və daima onlayn qalmaması üçün avtomatik silinən keçidlə göndərin.
|
||||
uploadPageLearnMore = Ətraflı öyrən
|
||||
uploadPageDropMessage = Yükləmək üçün faylınızı buraya daşıyın
|
||||
uploadPageSizeMessage = Xidmətin daha yaxşı işləməsi üçün faylınız 1 GB-dan az olmalıdır
|
||||
uploadPageBrowseButton = Kompüterinizdən fayl seçin
|
||||
.title = Kompüterinizdən fayl seçin
|
||||
uploadPageMultipleFilesAlert = Birdən çox fayl və ya qovluq yükləmə hələlik dəstəklənmir.
|
||||
uploadPageBrowseButtonTitle = Fayl yüklə
|
||||
uploadingPageHeader = Faylınız yüklənir
|
||||
importingFile = İdxal edilir…
|
||||
verifyingFile = Təsdiqlənir…
|
||||
encryptingFile = Şifrələnir...
|
||||
decryptingFile = Şifrə açılır...
|
||||
notifyUploadDone = Yükləməniz hazırdır.
|
||||
uploadingPageMessage = Faylınız yükləndikdən sonra vaxtı çıxma seçimlərini qura biləcəksiz.
|
||||
uploadingPageCancel = Yükləməni ləğv et
|
||||
.title = Yükləməni ləğv et
|
||||
uploadCancelNotification = Yükləməniz ləğv edildi.
|
||||
uploadingPageLargeFileMessage = Fayl böyükdür və yükləmək çox vaxt ala bilər. Səbirli olun!
|
||||
uploadingFileNotification = Yükləmə bitdiyində xəbər ver.
|
||||
uploadSuccessConfirmHeader = Göndərməyə hazır
|
||||
uploadSvgAlt
|
||||
.alt = Yüklə
|
||||
uploadSuccessTimingHeader = Faylınızın keçidinin 1 endirmədən və ya 24 saatdan sonra vaxtı çıxacaq.
|
||||
copyUrlFormLabelWithName = Faylınızı göndərmək üçün keçidi köçürün: { $filename }
|
||||
// Note: Title text for button should be the same.
|
||||
copyUrlFormButton = Buferə köçür
|
||||
.title = Mübadilə buferinə köçür
|
||||
copiedUrl = Köçürüldü!
|
||||
// Note: Title text for button should be the same.
|
||||
deleteFileButton = Faylı sil
|
||||
.title = Faylı sil
|
||||
// Note: Title text for button should be the same.
|
||||
sendAnotherFileLink = Başqa fayl göndər
|
||||
.title = Başqa fayl göndər
|
||||
// Alternative text used on the download link/button (indicates an action).
|
||||
downloadAltText
|
||||
.alt = Endir
|
||||
downloadFileName = { $filename } faylını endir
|
||||
downloadFileSize = ({ $size })
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Yoldaşınız Firefox Send ilə sizə fayl göndərir, fayllarınızı təhlükəsiz, məxfi, şifrələnmiş və daima onlayn qalmaması üçün avtomatik silən fayl göndərmə xidməti.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = Endir
|
||||
.title = Endir
|
||||
downloadNotification = Endirməniz tamamlandı.
|
||||
downloadFinish = Endirmə Tamamlandı
|
||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||
sendYourFilesLink = Firefox Send Yoxla
|
||||
.title = Firefox Send Yoxla
|
||||
downloadingPageProgress = { $filename } faylı ({ $size }) endirilir
|
||||
downloadingPageMessage = Lütfən faylı endirib şifrəsini açarkən vərəqi açıq buraxın.
|
||||
errorAltText
|
||||
.alt = Yükləmə xətası
|
||||
errorPageHeader = Nəsə səhv getdi!
|
||||
errorPageMessage = Faylı yüklərkən xəta baş verdi.
|
||||
errorPageLink = Başqa fayl göndər
|
||||
fileTooBig = Fayl yükləmək üçün çox böyükdür. Fayl { $size }-dan az olmalıdır.
|
||||
linkExpiredAlt
|
||||
.alt = Keçidin vaxtı çıxıb
|
||||
expiredPageHeader = Keçidin vaxtı çıxıb və ya heç vaxt olmayıb!
|
||||
notSupportedHeader = Səyyahınız dəstəklənmir.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Heyf ki, bu səyyah Firefox Send-ə güc verən web texnologiyalarını dəstəkləmir. Fərqli bir səyyah yoxlamalısınız. Biz Firefox məsləhət görürük!
|
||||
notSupportedOutdatedDetail = Heyf ki, Firefox səyyahının bu versiyası Firefox Send-ə güc verən web texnologiyalarını dəstəkləmir. Səyyahınızı yeniləməlisiniz.
|
||||
updateFirefox = Firefox-u Yenilə
|
||||
downloadFirefoxButtonSub = Pulsuz Endir
|
||||
uploadedFile = Fayl
|
||||
copyFileList = Keçidi Köçürt
|
||||
// expiryFileList is used as a column header
|
||||
expiryFileList = Vaxtı çıxma tarixi
|
||||
deleteFileList = Sil
|
||||
nevermindButton = Vacib deyil
|
||||
legalHeader = Şərtlər və Məxfilik
|
||||
legalNoticeTestPilot = Firefox Send Test Pilot eksperimentidir, Test Pilot <a>Xidmət Şərtləri</a> və <a>Məxfilik Bildirişi</a>-nə tabedir. Bu eksperiment və məlumat yığma haqqında <a>buradan</a> öyrənə bilərsiz.
|
||||
legalNoticeMozilla = Firefox Send saytının istifadəsi həmçinin Mozilla-nın <a>Saytlar üçün Məxfilik Bildirişi</a> və <a>Sayt İstifadə Şərtləri</a>-nə tabedir.
|
||||
deletePopupText = Fayl silinsin?
|
||||
deletePopupYes = Bəli
|
||||
deletePopupCancel = Ləğv et
|
||||
deleteButtonHover
|
||||
.title = Sil
|
||||
copyUrlHover
|
||||
.title = Keçidi Köçürt
|
||||
footerLinkLegal = Hüquqi
|
||||
// Test Pilot is a proper name and should not be localized.
|
||||
footerLinkAbout = Test Pilot Haqqında
|
||||
footerLinkPrivacy = Məxfilik
|
||||
footerLinkTerms = Şərtlər
|
||||
footerLinkCookies = Çərəzlər
|
||||
@@ -26,7 +26,7 @@ uploadingFileNotification = Upozornit, až bude nahrávání dokončeno.
|
||||
uploadSuccessConfirmHeader = Připraveno k odeslání
|
||||
uploadSvgAlt
|
||||
.alt = Nahrát
|
||||
uploadSuccessTimingHeader = Platnost odkazu na váš souboru vyprší pro jeho prvním stažení, nebo po 24 hodinách.
|
||||
uploadSuccessTimingHeader = Platnost odkazu na váš souboru vyprší po jeho prvním stažení, nebo po 24 hodinách.
|
||||
copyUrlFormLabelWithName = Zkopírujte a sdílejte odkaz na váš soubor: { $filename }
|
||||
// Note: Title text for button should be the same.
|
||||
copyUrlFormButton = Zkopírovat do schránky
|
||||
|
||||
@@ -67,6 +67,8 @@ expiredPageHeader = ¡El enlace ha caducado o nunca existió!
|
||||
notSupportedHeader = Tu navegador no está admitido.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Lamentablemente, este navegador no admite la tecnología web que necesita Firefox Send. Tendrás que probar otro navegador. ¡Te recomendamos Firefox!
|
||||
notSupportedOutdatedDetail = Lamentablemente, esta versión de Firefox no admite la tecnología web que impulsa Firefox Send. Tendrás que actualizar tu navegador.
|
||||
updateFirefox = Actualizar Firefox
|
||||
downloadFirefoxButtonSub = Descarga gratuita
|
||||
uploadedFile = Archivo
|
||||
copyFileList = Copiar URL
|
||||
|
||||
@@ -63,3 +63,32 @@ errorPageLink = Enviar otro archivo
|
||||
fileTooBig = Ese archivo es muy grande. Debería ocupar menos de { $size }.
|
||||
linkExpiredAlt
|
||||
.alt = Enlace caducado
|
||||
expiredPageHeader = ¡Este enlace ha caducado o nunca existió en primer lugar!
|
||||
notSupportedHeader = Tu navegador no está soportado.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Lamentablemente, este navegador no admite la tecnología web que necesita Firefox Send. Tendrás que probar otro navegador. ¡Te recomendamos Firefox!
|
||||
notSupportedOutdatedDetail = Lamentablemente esta versión de Firefox no soporta la tecnología web que potencia a Firefox Send. Deberás actualizar tu navegador.
|
||||
updateFirefox = Actualizar Firefox
|
||||
downloadFirefoxButtonSub = Descarga gratuita
|
||||
uploadedFile = Archivo
|
||||
copyFileList = Copiar URL
|
||||
// expiryFileList is used as a column header
|
||||
expiryFileList = Caduca en
|
||||
deleteFileList = Eliminar
|
||||
nevermindButton = Da igual
|
||||
legalHeader = Términos y privacidad
|
||||
legalNoticeTestPilot = Firefox Send sigue siendo un experimento de Test Pilot y está sujeto a las <a>Condiciones del servicio</a> y al <a>Aviso de privacidad</a> de Test Pilot. Puedes saber más acerca de este experimento y si recolección de datos <a>aquí</a>.
|
||||
legalNoticeMozilla = El uso de la página de Firefox Send también está sujeto al <a>Aviso de privacidad sobre sitios web</a> y a los <a>Términos de uso sobre sitios web</a>.
|
||||
deletePopupText = ¿Eliminar este archivo?
|
||||
deletePopupYes = Sí
|
||||
deletePopupCancel = Cancelar
|
||||
deleteButtonHover
|
||||
.title = Eliminar
|
||||
copyUrlHover
|
||||
.title = Copiar URL
|
||||
footerLinkLegal = Legal
|
||||
// Test Pilot is a proper name and should not be localized.
|
||||
footerLinkAbout = Acerca de Test Pilot
|
||||
footerLinkPrivacy = Privacidad
|
||||
footerLinkTerms = Términos
|
||||
footerLinkCookies = Cookies
|
||||
|
||||
@@ -6,7 +6,7 @@ uploadPageHeader = Privee, fersifere bestânsdieling
|
||||
uploadPageExplainer = Ferstjoer bestannen troch in feilich, privee en fersifere keppeling dy't automatysk ferrint, om foar te kommen dat jo guod net foar altyd online bliuwt.
|
||||
uploadPageLearnMore = Mear ynfo
|
||||
uploadPageDropMessage = Sleep jo bestân hjir hinne om opladen te starten
|
||||
uploadPageSizeMessage = Foar de meast betrouber wurking, is it it bêste om jo bestân lytser as 1 GB te hâlden
|
||||
uploadPageSizeMessage = Foar de meast betroubere wurking, is it it bêste om jo bestân lytser as 1 GB te hâlden
|
||||
uploadPageBrowseButton = Selektearje in bestân op jo kompjûter
|
||||
.title = Selektearje in bestân op jo kompjûter
|
||||
uploadPageMultipleFilesAlert = Opladen fan mear bestannen tagelyk of in map wurdt op dit stuit net stipe.
|
||||
|
||||
78
public/locales/id/send.ftl
Normal file
78
public/locales/id/send.ftl
Normal file
@@ -0,0 +1,78 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Send
|
||||
siteSubtitle = eksperimen web
|
||||
siteFeedback = Saran
|
||||
uploadPageHeader = Pribadi, Berbagi Berkas Terenskripsi
|
||||
uploadPageLearnMore = Pelajari lebih lanjut
|
||||
uploadPageBrowseButtonTitle = Unggah berkas
|
||||
uploadingPageHeader = Mengunggah Berkas Anda
|
||||
importingFile = Mengimpor…
|
||||
verifyingFile = Memverifikasi…
|
||||
encryptingFile = Mengenkripsi...
|
||||
decryptingFile = Mendekripsi...
|
||||
notifyUploadDone = Unggahan Anda telah selesai.
|
||||
uploadingPageMessage = Setelah berkas diunggah, Anda dapat mengatur pilihan kedaluwarsa.
|
||||
uploadingPageCancel = Batal unggah
|
||||
.title = Batal unggah
|
||||
uploadCancelNotification = Unggahan Anda dibatalkan.
|
||||
uploadingPageLargeFileMessage = Berkas ini berukuran besar dan mungkin perlu beberapa saat untuk mengunggahnya. Silakan tunggu!
|
||||
uploadingFileNotification = Beri tahu saya ketika unggahan telah selesai.
|
||||
uploadSuccessConfirmHeader = Siap untuk Dikirim
|
||||
uploadSvgAlt
|
||||
.alt = Unggah
|
||||
uploadSuccessTimingHeader = Tautan ke berkas Anda akan berakhir setelah 1 unduhan atau dalam 24 jam.
|
||||
copyUrlFormLabelWithName = Salin dan bagikan tautan untuk mengirim berkas Anda: { $filename }
|
||||
// Note: Title text for button should be the same.
|
||||
copyUrlFormButton = Salin ke papan klip
|
||||
.title = Salin ke papan klip
|
||||
copiedUrl = Tersalin!
|
||||
// Note: Title text for button should be the same.
|
||||
deleteFileButton = Hapus berkas
|
||||
.title = Hapus berkas
|
||||
// Note: Title text for button should be the same.
|
||||
sendAnotherFileLink = Kirim berkas lain
|
||||
.title = Kirim berkas lain
|
||||
// Alternative text used on the download link/button (indicates an action).
|
||||
downloadAltText
|
||||
.alt = Unduh
|
||||
downloadFileName = Unduh { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
downloadNotification = Unduhan Anda telah selesai.
|
||||
downloadFinish = Unduhan Selesai
|
||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||
sendYourFilesLink = Coba Firefox Send
|
||||
.title = Coba Firefox Send
|
||||
downloadingPageProgress = Mengunduh { $filename } ({ $size })
|
||||
downloadingPageMessage = Sila biarkan tab ini terbuka sementara kami memproses berkas Anda dan mendekripsinya.
|
||||
errorAltText
|
||||
.alt = Unggahan bermasalah
|
||||
errorPageHeader = Terjadi kesalahan!
|
||||
errorPageMessage = Terjadi kesalahan saat mengunggah berkas.
|
||||
errorPageLink = Kirim berkas lain
|
||||
fileTooBig = Berkas terlalu besar untuk diunggah. Harus kurang dari { $size }.
|
||||
linkExpiredAlt
|
||||
.alt = Tautan kedaluwarsa
|
||||
expiredPageHeader = Tautan ini telah kedaluwarsa atau tidak pernah ada!
|
||||
notSupportedHeader = Peramban Anda tidak mendukung.
|
||||
updateFirefox = Perbarui Firefox
|
||||
downloadFirefoxButtonSub = Unduh Gratis
|
||||
uploadedFile = Berkas
|
||||
copyFileList = Salin URL
|
||||
// expiryFileList is used as a column header
|
||||
expiryFileList = Kedaluwarsa Pada
|
||||
deleteFileList = Hapus
|
||||
nevermindButton = Abaikan
|
||||
legalHeader = Syarat & Privasi
|
||||
deletePopupText = Hapus berkas ini?
|
||||
deletePopupYes = Ya
|
||||
deletePopupCancel = Batal
|
||||
deleteButtonHover
|
||||
.title = Hapus
|
||||
copyUrlHover
|
||||
.title = Salin URL
|
||||
footerLinkLegal = Legal
|
||||
// Test Pilot is a proper name and should not be localized.
|
||||
footerLinkAbout = Tentang Test Pilot
|
||||
footerLinkPrivacy = Privasi
|
||||
footerLinkTerms = Ketentuan
|
||||
footerLinkCookies = Kuki
|
||||
94
public/locales/nl/send.ftl
Normal file
94
public/locales/nl/send.ftl
Normal file
@@ -0,0 +1,94 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Send
|
||||
siteSubtitle = webexperiment
|
||||
siteFeedback = Feedback
|
||||
uploadPageHeader = Privé, versleuteld bestanden delen
|
||||
uploadPageExplainer = Stuur bestanden via een veilige, private en versleutelde koppeling die automatisch verloopt, zodat u zeker weet dat uw zaken niet onbeperkt online blijven.
|
||||
uploadPageLearnMore = Meer info
|
||||
uploadPageDropMessage = Sleep uw bestand hiernaartoe om het te uploaden
|
||||
uploadPageSizeMessage = Voor de meest betrouwbare werking kunt u uw bestand het beste onder de 1 GB houden
|
||||
uploadPageBrowseButton = Selecteer een bestand op uw computer
|
||||
.title = Selecteer een bestand op uw computer
|
||||
uploadPageMultipleFilesAlert = Het uploaden van meerdere bestanden of een map wordt momenteel niet ondersteund.
|
||||
uploadPageBrowseButtonTitle = bestand uploaden
|
||||
uploadingPageHeader = Uw bestand wordt geüpload
|
||||
importingFile = Importeren…
|
||||
verifyingFile = Verifiëren…
|
||||
encryptingFile = Versleutelen…
|
||||
decryptingFile = Ontcijferen…
|
||||
notifyUploadDone = Uw upload is voltooid.
|
||||
uploadingPageMessage = Zodra uw bestand wordt geüpload, kunt u vervalopties instellen.
|
||||
uploadingPageCancel = Uploaden annuleren
|
||||
.title = Uploaden annuleren
|
||||
uploadCancelNotification = Uw upload is geannuleerd.
|
||||
uploadingPageLargeFileMessage = Dit bestand is groot en het uploaden kan even duren. Even geduld…
|
||||
uploadingFileNotification = Mij waarschuwen zodra het uploaden is voltooid
|
||||
uploadSuccessConfirmHeader = Gereed voor verzending
|
||||
uploadSvgAlt
|
||||
.alt = Uploaden
|
||||
uploadSuccessTimingHeader = De koppeling naar uw bestand zal na 1 download of 24 uur verlopen.
|
||||
copyUrlFormLabelWithName = Kopieer en deel de koppeling om uw bestand te verzenden: { $filename }
|
||||
// Note: Title text for button should be the same.
|
||||
copyUrlFormButton = Kopiëren naar klembord
|
||||
.title = Kopiëren naar klembord
|
||||
copiedUrl = Gekopieerd!
|
||||
// Note: Title text for button should be the same.
|
||||
deleteFileButton = Bestand verwijderen
|
||||
.title = Bestand verwijderen
|
||||
// Note: Title text for button should be the same.
|
||||
sendAnotherFileLink = Nog een bestand verzenden
|
||||
.title = Nog een bestand verzenden
|
||||
// Alternative text used on the download link/button (indicates an action).
|
||||
downloadAltText
|
||||
.alt = Downloaden
|
||||
downloadFileName = { $filename } downloaden
|
||||
downloadFileSize = ({ $size })
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Uw vriend(in) stuurt u een bestand met Firefox Send, een dienst waarmee u bestanden kunt verzenden met een veilige, private en versleutelde koppeling die automatisch verloopt, zodat u zeker weet dat uw zaken niet onbeperkt online blijven.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = Downloaden
|
||||
.title = Downloaden
|
||||
downloadNotification = Uw download is voltooid.
|
||||
downloadFinish = Downloaden voltooid
|
||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||
sendYourFilesLink = Firefox Send proberen
|
||||
.title = Firefox Send proberen
|
||||
downloadingPageProgress = { $filename } ({ $size }) wordt gedownload
|
||||
downloadingPageMessage = Laat dit tabblad geopend terwijl uw bestand wordt opgehaald en ontcijferd.
|
||||
errorAltText
|
||||
.alt = Uploadfout
|
||||
errorPageHeader = Er is iets misgegaan!
|
||||
errorPageMessage = Er is een fout opgetreden bij het uploaden van het bestand.
|
||||
errorPageLink = Nog een bestand verzenden
|
||||
fileTooBig = Dat bestand is te groot om te worden geüpload. Het moet kleiner zijn dan { $size }.
|
||||
linkExpiredAlt
|
||||
.alt = Koppeling verlopen
|
||||
expiredPageHeader = Deze koppeling is verlopen of heeft überhaupt nooit bestaan!
|
||||
notSupportedHeader = Uw browser wordt niet ondersteund.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Helaas ondersteunt deze browser de webtechnologie die Firefox Send gebruikt niet. U dient een andere browser te proberen. Firefox wordt aanbevolen!
|
||||
notSupportedOutdatedDetail = Helaas ondersteunt deze versie van Firefox de webtechnologie die Firefox Send gebruikt niet. U dient uw browser bij te werken.
|
||||
updateFirefox = Firefox bijwerken
|
||||
downloadFirefoxButtonSub = Gratis download
|
||||
uploadedFile = Bestand
|
||||
copyFileList = URL kopiëren
|
||||
// expiryFileList is used as a column header
|
||||
expiryFileList = Verloopt over
|
||||
deleteFileList = Verwijderen
|
||||
nevermindButton = Maakt niet uit
|
||||
legalHeader = Voorwaarden en privacy
|
||||
legalNoticeTestPilot = Firefox Send is momenteel een Test Pilot-experiment en onderhevig aan de <a>Servicevoorwaarden</a> en <a>Privacyverklaring</a> van Test Pilot. <a>Hier</a> vindt u meer info over dit experiment en de gegevensverzameling ervan.
|
||||
legalNoticeMozilla = Gebruik van de Firefox Send-website is ook onderhevig aan de <a>Privacyverklaring voor websites</a> en <a>Servicevoorwaarden voor websites</a> van Mozilla.
|
||||
deletePopupText = Dit bestand verwijderen?
|
||||
deletePopupYes = Ja
|
||||
deletePopupCancel = Annuleren
|
||||
deleteButtonHover
|
||||
.title = Verwijderen
|
||||
copyUrlHover
|
||||
.title = URL kopiëren
|
||||
footerLinkLegal = Juridisch
|
||||
// Test Pilot is a proper name and should not be localized.
|
||||
footerLinkAbout = Over Test Pilot
|
||||
footerLinkPrivacy = Privacy
|
||||
footerLinkTerms = Voorwaarden
|
||||
footerLinkCookies = Cookies
|
||||
94
public/locales/sr/send.ftl
Normal file
94
public/locales/sr/send.ftl
Normal file
@@ -0,0 +1,94 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Send
|
||||
siteSubtitle = веб експеримент
|
||||
siteFeedback = Повратне информације
|
||||
uploadPageHeader = Приватно и шифровано дељење датотека
|
||||
uploadPageExplainer = Шаљите датотеке преко безбедне, приватне и шифроване везе која самостално истиче да ваше ствари не би остале на нету заувек.
|
||||
uploadPageLearnMore = Сазнајте више
|
||||
uploadPageDropMessage = Превуците ваше датотеке овде да бисте кренули са отпремањем
|
||||
uploadPageSizeMessage = За бољи рад предлажемо да датотека не буде већа од 1GB
|
||||
uploadPageBrowseButton = Изаберите датотеку на рачунару
|
||||
.title = Изаберите датотеку на рачунару
|
||||
uploadPageMultipleFilesAlert = Отпремање фасцикли или више датотека тренутно није подржано.
|
||||
uploadPageBrowseButtonTitle = Отпреми датотеку
|
||||
uploadingPageHeader = Ваша датотека се отпрема
|
||||
importingFile = Увозим…
|
||||
verifyingFile = Потврђујем…
|
||||
encryptingFile = Шифрујем…
|
||||
decryptingFile = Дешифрујем…
|
||||
notifyUploadDone = Ваше отпремање је завршено.
|
||||
uploadingPageMessage = Након што се ваша датотека отпреми, моћи ћете да подесите опције истека.
|
||||
uploadingPageCancel = Откажи отпремање
|
||||
.title = Откажи отпремање
|
||||
uploadCancelNotification = Ваше отпремање је отказано.
|
||||
uploadingPageLargeFileMessage = Ово је велика датотека и отпремање може потрајати. Будите стрпљиви!
|
||||
uploadingFileNotification = Обавести ме када се отпремање заврши.
|
||||
uploadSuccessConfirmHeader = Спреман за слање
|
||||
uploadSvgAlt
|
||||
.alt = Отпреми
|
||||
uploadSuccessTimingHeader = Веза ка вашој датотеци ће истећи након једног преузимања или након 24 сата.
|
||||
copyUrlFormLabelWithName = Ископирајте и поделите везу да бисте послали вашу датотеку: { $filename }
|
||||
// Note: Title text for button should be the same.
|
||||
copyUrlFormButton = Копирај у оставу
|
||||
.title = Копирај у оставу
|
||||
copiedUrl = Ископирано!
|
||||
// Note: Title text for button should be the same.
|
||||
deleteFileButton = Обриши датотеку
|
||||
.title = Обриши датотеку
|
||||
// Note: Title text for button should be the same.
|
||||
sendAnotherFileLink = Пошаљи другу датотеку
|
||||
.title = Пошаљи другу датотеку
|
||||
// Alternative text used on the download link/button (indicates an action).
|
||||
downloadAltText
|
||||
.alt = Преузми
|
||||
downloadFileName = Преузимање датотеке { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Ваш пријатељ вам је послао датотеку преко услуге Firefox Send која вам омогућава да делите датотеке преко безбедне, приватне и шифроване везе која самостално истиче да ваше ствари не би остале на нету заувек.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = Преузми
|
||||
.title = Преузми
|
||||
downloadNotification = Ваше преузимање је завршено.
|
||||
downloadFinish = Преузимање је завршено.
|
||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||
sendYourFilesLink = Испробајте Firefox Send
|
||||
.title = Испробајте Firefox Send
|
||||
downloadingPageProgress = Преузимам датотеку { $filename } ({ $size })
|
||||
downloadingPageMessage = Оставите овај језичак отвореним док не добавимо вашу датотеку и док је не дешифрујемо.
|
||||
errorAltText
|
||||
.alt = Грешка при отпремању
|
||||
errorPageHeader = Нешто је пошло наопако!
|
||||
errorPageMessage = Догодила се грешка приликом отпремања датотеке.
|
||||
errorPageLink = Пошаљи другу датотеку
|
||||
fileTooBig = Та датотека је превелика за отпремање. Треба да буде мања од { $size }.
|
||||
linkExpiredAlt
|
||||
.alt = Веза је истекла
|
||||
expiredPageHeader = Веза је или истекла, или никада није ни постојала!
|
||||
notSupportedHeader = Ваш прегледач није подржан.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Нажалост, овај прегледач не подржава веб технологију која омогућава Firefox Send. Мораћете да пробате са другим прегледачем. Ми предлажемо Firefox!
|
||||
notSupportedOutdatedDetail = Нажалост, ово издање Firefox-a не подржава веб технологију која омогућава Firefox Send. Мораћете да ажурирате ваш прегледач.
|
||||
updateFirefox = Ажурирај Firefox
|
||||
downloadFirefoxButtonSub = Бесплатно преузимање
|
||||
uploadedFile = Датотека
|
||||
copyFileList = URL за копирање
|
||||
// expiryFileList is used as a column header
|
||||
expiryFileList = Истиче за
|
||||
deleteFileList = Брисање
|
||||
nevermindButton = Занемари
|
||||
legalHeader = Услови и приватност
|
||||
legalNoticeTestPilot = Firefox Send је тренутно Тест Пилот експеримент и подложан је <a>условима коришћења</a> Тест Пилота и <a>обавештењем о приватности</a>. Можете сазнати више о овом експерименту и о његовом сакупљању података <a>овде</a>.
|
||||
legalNoticeMozilla = Коришћење Firefox Send веб сајта подлеже Mozilla-ином <a>обавештењу о приватности на веб сајтовима</a> и <a>условима коришћења веб сајтова</a>.
|
||||
deletePopupText = Обрисати ову датотеку?
|
||||
deletePopupYes = Да
|
||||
deletePopupCancel = Откажи
|
||||
deleteButtonHover
|
||||
.title = Обриши
|
||||
copyUrlHover
|
||||
.title = Ископирај URL
|
||||
footerLinkLegal = Правни подаци
|
||||
// Test Pilot is a proper name and should not be localized.
|
||||
footerLinkAbout = О Тест Пилоту
|
||||
footerLinkPrivacy = Приватност
|
||||
footerLinkTerms = Услови
|
||||
footerLinkCookies = Колачићи
|
||||
@@ -1,12 +1,8 @@
|
||||
/*** index.html ***/
|
||||
html {
|
||||
background: url('resources/send_bg.svg');
|
||||
font-family: -apple-system,
|
||||
BlinkMacSystemFont,
|
||||
'SF Pro Text',
|
||||
Helvetica,
|
||||
Arial,
|
||||
sans-serif;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', Helvetica,
|
||||
Arial, sans-serif;
|
||||
font-weight: 200;
|
||||
background-size: 110%;
|
||||
background-repeat: no-repeat;
|
||||
@@ -21,7 +17,6 @@ body {
|
||||
flex-direction: column;
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@@ -40,6 +35,14 @@ body {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.send-logo h1 {
|
||||
transition: color 50ms;
|
||||
}
|
||||
|
||||
.send-logo h1:hover {
|
||||
color: #0297f8;
|
||||
}
|
||||
|
||||
.send-logo > a {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@@ -68,7 +71,7 @@ body {
|
||||
transition: color 50ms;
|
||||
}
|
||||
|
||||
.send-logo:hover a {
|
||||
.site-subtitle a:hover {
|
||||
color: #0297f8;
|
||||
}
|
||||
|
||||
|
||||
6
scripts/.eslintrc.yml
Normal file
6
scripts/.eslintrc.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
rules:
|
||||
node/shebang: off
|
||||
security/detect-child-process: off
|
||||
|
||||
no-console: off
|
||||
no-process-exit: off
|
||||
49
scripts/get-prod-locales.js
Executable file
49
scripts/get-prod-locales.js
Executable file
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const cp = require('child_process');
|
||||
const { promisify } = require('util');
|
||||
const fs = require('fs');
|
||||
const pkg = require('../package.json');
|
||||
|
||||
const availableLanguages = pkg.availableLanguages.sort();
|
||||
const exec = promisify(cp.exec);
|
||||
|
||||
const arrayDiff = (current, package) =>
|
||||
current.filter(locale => !package.includes(locale));
|
||||
|
||||
const cmd = 'compare-locales l10n.toml . `ls public/locales` --data=json';
|
||||
|
||||
exec(cmd)
|
||||
.then(({ stdout }) => JSON.parse(stdout))
|
||||
.then(({ summary }) => {
|
||||
const locales = Object.keys(summary)
|
||||
.filter(locale => {
|
||||
const loc = summary[locale];
|
||||
const hasMissing = loc.hasOwnProperty('missing');
|
||||
const hasErrors = loc.hasOwnProperty('errors');
|
||||
return !hasMissing && !hasErrors;
|
||||
})
|
||||
.sort();
|
||||
|
||||
if (locales.join(',') !== availableLanguages.join(',')) {
|
||||
const missingLanguages = arrayDiff(locales, availableLanguages);
|
||||
|
||||
console.log('current 100%:', JSON.stringify(locales));
|
||||
console.log('package.json:', JSON.stringify(availableLanguages));
|
||||
console.log('missing prod:', JSON.stringify(missingLanguages));
|
||||
|
||||
if (process.argv.includes('--write')) {
|
||||
const pkgPath = require.resolve('../package.json');
|
||||
pkg.availableLanguages = locales;
|
||||
const str = JSON.stringify(pkg, null, 2) + '\n';
|
||||
console.log('Updating /package.json availableLanguages');
|
||||
fs.writeFileSync(pkgPath, str, 'utf-8');
|
||||
}
|
||||
} else {
|
||||
console.log('Production locales are up to date!');
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
51
scripts/lint-locales.js
Normal file
51
scripts/lint-locales.js
Normal file
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const cp = require('child_process');
|
||||
const { promisify } = require('util');
|
||||
const pkg = require('../package.json');
|
||||
const conf = require('../server/config');
|
||||
|
||||
const exec = promisify(cp.exec);
|
||||
const cmd = `compare-locales l10n.toml . ${getLocales()} --data=json`;
|
||||
|
||||
console.log(cmd);
|
||||
|
||||
exec(cmd)
|
||||
.then(({ stdout }) => JSON.parse(stdout))
|
||||
.then(({ details }) => filterErrors(details))
|
||||
.then(results => {
|
||||
if (results.length) {
|
||||
results.forEach(({ locale, data }) => {
|
||||
console.log(locale);
|
||||
data.forEach(msg => console.log(`- ${msg}`));
|
||||
console.log('');
|
||||
});
|
||||
process.exit(2);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
function filterErrors(details) {
|
||||
return Object.keys(details)
|
||||
.sort()
|
||||
.map(locale => {
|
||||
const data = details[locale]
|
||||
.filter(item => item.hasOwnProperty('error'))
|
||||
.map(({ error }) => error);
|
||||
return { locale, data };
|
||||
})
|
||||
.filter(({ data }) => data.length);
|
||||
}
|
||||
|
||||
function getLocales() {
|
||||
// If we're in a "production" env (or passed the `--production` flag), only
|
||||
// check the locales from the package.json file's `availableLanguages` array.
|
||||
if (conf.env === 'production' || process.argv.includes('--production')) {
|
||||
return pkg.availableLanguages.sort().join(' ');
|
||||
}
|
||||
// Lint all the locales.
|
||||
return '`ls public/locales`';
|
||||
}
|
||||
@@ -14,7 +14,7 @@ const filename = path.join(__dirname, '..', 'public', 'version.json');
|
||||
const filedata = {
|
||||
commit,
|
||||
source: pkg.homepage,
|
||||
version: process.env.CIRCLE_TAG || pkg.version
|
||||
version: process.env.CIRCLE_TAG || `v${pkg.version}`
|
||||
};
|
||||
|
||||
fs.writeFileSync(filename, JSON.stringify(filedata, null, 2) + '\n');
|
||||
|
||||
@@ -10,6 +10,7 @@ const storage = require('./storage.js');
|
||||
const Raven = require('raven');
|
||||
const crypto = require('crypto');
|
||||
const fs = require('fs');
|
||||
const version = require('../public/version.json');
|
||||
|
||||
if (conf.sentry_dsn) {
|
||||
Raven.config(conf.sentry_dsn).install();
|
||||
@@ -106,8 +107,10 @@ app.get('/legal', (req, res) => {
|
||||
app.get('/jsconfig.js', (req, res) => {
|
||||
res.set('Content-Type', 'application/javascript');
|
||||
res.render('jsconfig', {
|
||||
trackerId: conf.analytics_id,
|
||||
dsn: conf.sentry_id,
|
||||
googleAnalyticsId: conf.analytics_id,
|
||||
sentryId: conf.sentry_id,
|
||||
version: version.version,
|
||||
commit: version.commit,
|
||||
maxFileSize: conf.max_file_size,
|
||||
expireSeconds: conf.expire_seconds,
|
||||
layout: false
|
||||
|
||||
@@ -9,7 +9,7 @@ window.Raven = {
|
||||
captureException: function(err) {
|
||||
console.error(err, err.stack);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.FakeFile = FakeFile;
|
||||
window.FileSender = require('../../frontend/src/fileSender');
|
||||
|
||||
@@ -15,83 +15,84 @@ let originalBlob;
|
||||
|
||||
describe('File Sender', function() {
|
||||
before(function() {
|
||||
server.respondImmediately = true;
|
||||
server.respondWith(
|
||||
'POST',
|
||||
'/upload',
|
||||
function(request) {
|
||||
const reader = new FileReader();
|
||||
reader.readAsArrayBuffer(request.requestBody.get('data'));
|
||||
server.respondImmediately = true;
|
||||
server.respondWith('POST', '/upload', function(request) {
|
||||
const reader = new FileReader();
|
||||
reader.readAsArrayBuffer(request.requestBody.get('data'));
|
||||
|
||||
reader.onload = function(event) {
|
||||
file = this.result;
|
||||
}
|
||||
reader.onload = function(event) {
|
||||
file = this.result;
|
||||
};
|
||||
|
||||
const responseObj = JSON.parse(request.requestHeaders['X-File-Metadata']);
|
||||
request.respond(
|
||||
200,
|
||||
{'Content-Type': 'application/json'},
|
||||
JSON.stringify({url: 'some url',
|
||||
id: responseObj.id,
|
||||
delete: responseObj.delete})
|
||||
)
|
||||
}
|
||||
)
|
||||
})
|
||||
const responseObj = JSON.parse(request.requestHeaders['X-File-Metadata']);
|
||||
request.respond(
|
||||
200,
|
||||
{ 'Content-Type': 'application/json' },
|
||||
JSON.stringify({
|
||||
url: 'some url',
|
||||
id: responseObj.id,
|
||||
delete: responseObj.delete
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('Should get a loading event emission', function() {
|
||||
const file = new FakeFile('hello_world.txt', ['This is some data.'])
|
||||
const fs = new FileSender(file);
|
||||
let testLoading = true;
|
||||
const file = new FakeFile('hello_world.txt', ['This is some data.']);
|
||||
const fs = new FileSender(file);
|
||||
let testLoading = true;
|
||||
|
||||
fs.on('loading', isStillLoading => {
|
||||
assert(!(!testLoading && isStillLoading));
|
||||
testLoading = isStillLoading;
|
||||
fs.on('loading', isStillLoading => {
|
||||
assert(!(!testLoading && isStillLoading));
|
||||
testLoading = isStillLoading;
|
||||
});
|
||||
|
||||
return fs
|
||||
.upload()
|
||||
.then(info => {
|
||||
assert(info);
|
||||
assert(!testLoading);
|
||||
})
|
||||
|
||||
return fs.upload()
|
||||
.then(info => {
|
||||
assert(info);
|
||||
assert(!testLoading);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err, err.stack);
|
||||
assert.fail();
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err, err.stack);
|
||||
assert.fail();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should get a hashing event emission', function() {
|
||||
const file = new FakeFile('hello_world.txt', ['This is some data.'])
|
||||
const file = new FakeFile('hello_world.txt', ['This is some data.']);
|
||||
const fs = new FileSender(file);
|
||||
let testHashing = true;
|
||||
|
||||
fs.on('hashing', isStillHashing => {
|
||||
assert(!(!testHashing && isStillHashing));
|
||||
testHashing = isStillHashing;
|
||||
})
|
||||
assert(!(!testHashing && isStillHashing));
|
||||
testHashing = isStillHashing;
|
||||
});
|
||||
|
||||
return fs.upload()
|
||||
.then(info => {
|
||||
assert(info);
|
||||
assert(!testHashing);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err, err.stack);
|
||||
assert.fail();
|
||||
});
|
||||
})
|
||||
return fs
|
||||
.upload()
|
||||
.then(info => {
|
||||
assert(info);
|
||||
assert(!testHashing);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err, err.stack);
|
||||
assert.fail();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should get a encrypting event emission', function() {
|
||||
const file = new FakeFile('hello_world.txt', ['This is some data.'])
|
||||
const file = new FakeFile('hello_world.txt', ['This is some data.']);
|
||||
const fs = new FileSender(file);
|
||||
let testEncrypting = true;
|
||||
|
||||
fs.on('encrypting', isStillEncrypting => {
|
||||
assert(!(!testEncrypting && isStillEncrypting));
|
||||
testEncrypting = isStillEncrypting;
|
||||
})
|
||||
});
|
||||
|
||||
return fs.upload()
|
||||
return fs
|
||||
.upload()
|
||||
.then(info => {
|
||||
assert(info);
|
||||
assert(!testEncrypting);
|
||||
@@ -100,67 +101,68 @@ describe('File Sender', function() {
|
||||
console.log(err, err.stack);
|
||||
assert.fail();
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
it('Should encrypt a file properly', function(done) {
|
||||
const newFile = new FakeFile('hello_world.txt', ['This is some data.'])
|
||||
const newFile = new FakeFile('hello_world.txt', ['This is some data.']);
|
||||
const fs = new FileSender(newFile);
|
||||
fs.upload().then(info => {
|
||||
const key = info.secretKey;
|
||||
secretKey = info.secretKey;
|
||||
const IV = info.fileId;
|
||||
encryptedIV = info.fileId;
|
||||
|
||||
const readRaw = new FileReader;
|
||||
|
||||
const readRaw = new FileReader();
|
||||
readRaw.onload = function(event) {
|
||||
const rawArray = new Uint8Array(this.result);
|
||||
originalBlob = rawArray;
|
||||
|
||||
window.crypto.subtle.digest('SHA-256', rawArray).then(hash => {
|
||||
fileHash = hash;
|
||||
window.crypto.subtle.importKey(
|
||||
'jwk',
|
||||
{
|
||||
kty: 'oct',
|
||||
k: key,
|
||||
alg: 'A128GCM',
|
||||
ext: true,
|
||||
},
|
||||
{
|
||||
name: 'AES-GCM'
|
||||
},
|
||||
true,
|
||||
['encrypt', 'decrypt']
|
||||
)
|
||||
.then(cryptoKey => {
|
||||
window.crypto.subtle.encrypt(
|
||||
window.crypto.subtle
|
||||
.importKey(
|
||||
'jwk',
|
||||
{
|
||||
name: 'AES-GCM',
|
||||
iv: hexToArray(IV),
|
||||
additionalData: hash,
|
||||
tagLength: 128
|
||||
kty: 'oct',
|
||||
k: key,
|
||||
alg: 'A128GCM',
|
||||
ext: true
|
||||
},
|
||||
cryptoKey,
|
||||
rawArray
|
||||
{
|
||||
name: 'AES-GCM'
|
||||
},
|
||||
true,
|
||||
['encrypt', 'decrypt']
|
||||
)
|
||||
.then(encrypted => {
|
||||
assert(new Uint8Array(encrypted).toString() ===
|
||||
new Uint8Array(file).toString());
|
||||
done();
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
.then(cryptoKey => {
|
||||
window.crypto.subtle
|
||||
.encrypt(
|
||||
{
|
||||
name: 'AES-GCM',
|
||||
iv: hexToArray(IV),
|
||||
additionalData: hash,
|
||||
tagLength: 128
|
||||
},
|
||||
cryptoKey,
|
||||
rawArray
|
||||
)
|
||||
.then(encrypted => {
|
||||
assert(
|
||||
new Uint8Array(encrypted).toString() ===
|
||||
new Uint8Array(file).toString()
|
||||
);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
readRaw.readAsArrayBuffer(newFile);
|
||||
})
|
||||
})
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('File Receiver', function() {
|
||||
|
||||
class FakeXHR {
|
||||
constructor() {
|
||||
this.response = file;
|
||||
@@ -169,19 +171,19 @@ describe('File Receiver', function() {
|
||||
|
||||
static setup() {
|
||||
FakeXHR.prototype.open = sinon.spy();
|
||||
FakeXHR.prototype.send = function () {
|
||||
FakeXHR.prototype.send = function() {
|
||||
this.onload();
|
||||
}
|
||||
};
|
||||
|
||||
FakeXHR.prototype.originalXHR = window.XMLHttpRequest;
|
||||
|
||||
FakeXHR.prototype.getResponseHeader = function () {
|
||||
FakeXHR.prototype.getResponseHeader = function() {
|
||||
return JSON.stringify({
|
||||
aad: arrayToHex(new Uint8Array(fileHash)),
|
||||
filename: 'hello_world.txt',
|
||||
id: encryptedIV
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
window.XMLHttpRequest = FakeXHR;
|
||||
}
|
||||
|
||||
@@ -191,38 +193,47 @@ describe('File Receiver', function() {
|
||||
window.XMLHttpRequest.prototype.originalXHR.restore();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const cb = function(done) {
|
||||
if (file === undefined ||
|
||||
encryptedIV === undefined ||
|
||||
fileHash === undefined ||
|
||||
secretKey === undefined) {
|
||||
assert.fail('Please run file sending tests before trying to receive the files.');
|
||||
if (
|
||||
file === undefined ||
|
||||
encryptedIV === undefined ||
|
||||
fileHash === undefined ||
|
||||
secretKey === undefined
|
||||
) {
|
||||
assert.fail(
|
||||
'Please run file sending tests before trying to receive the files.'
|
||||
);
|
||||
done();
|
||||
}
|
||||
|
||||
FakeXHR.setup();
|
||||
done();
|
||||
}
|
||||
};
|
||||
|
||||
before(cb)
|
||||
before(cb);
|
||||
|
||||
after(function() {
|
||||
FakeXHR.restore();
|
||||
})
|
||||
});
|
||||
|
||||
it('Should decrypt properly', function() {
|
||||
const fr = new FileReceiver();
|
||||
location.hash = secretKey;
|
||||
return fr.download().then(([decrypted, name]) => {
|
||||
assert(name);
|
||||
assert(new Uint8Array(decrypted).toString() ===
|
||||
new Uint8Array(originalBlob).toString())
|
||||
}).catch(err => {
|
||||
console.log(err, err.stack);
|
||||
assert.fail();
|
||||
})
|
||||
})
|
||||
return fr
|
||||
.download()
|
||||
.then(([decrypted, name]) => {
|
||||
assert(name);
|
||||
assert(
|
||||
new Uint8Array(decrypted).toString() ===
|
||||
new Uint8Array(originalBlob).toString()
|
||||
);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err, err.stack);
|
||||
assert.fail();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should emit decrypting events', function() {
|
||||
const fr = new FileReceiver();
|
||||
@@ -237,17 +248,20 @@ describe('File Receiver', function() {
|
||||
|
||||
fr.on('safe', isSafe => {
|
||||
assert(isSafe);
|
||||
})
|
||||
});
|
||||
|
||||
return fr.download().then(([decrypted, name]) => {
|
||||
assert(decrypted);
|
||||
assert(name);
|
||||
assert(!testDecrypting);
|
||||
}).catch(err => {
|
||||
console.log(err, err.stack);
|
||||
assert.fail();
|
||||
})
|
||||
})
|
||||
return fr
|
||||
.download()
|
||||
.then(([decrypted, name]) => {
|
||||
assert(decrypted);
|
||||
assert(name);
|
||||
assert(!testDecrypting);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err, err.stack);
|
||||
assert.fail();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should emit hashing events', function() {
|
||||
const fr = new FileReceiver();
|
||||
@@ -262,99 +276,109 @@ describe('File Receiver', function() {
|
||||
|
||||
fr.on('safe', isSafe => {
|
||||
assert(isSafe);
|
||||
})
|
||||
});
|
||||
|
||||
return fr.download().then(([decrypted, name]) => {
|
||||
assert(decrypted);
|
||||
assert(name);
|
||||
assert(!testHashing);
|
||||
}).catch(err => {
|
||||
assert.fail();
|
||||
})
|
||||
})
|
||||
return fr
|
||||
.download()
|
||||
.then(([decrypted, name]) => {
|
||||
assert(decrypted);
|
||||
assert(name);
|
||||
assert(!testHashing);
|
||||
})
|
||||
.catch(err => {
|
||||
assert.fail();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should catch fraudulent checksums', function(done) {
|
||||
// Use the secret key and file hash of the previous file to encrypt,
|
||||
// which has a different hash than this one (different strings).
|
||||
const newFile = new FakeFile('hello_world.txt',
|
||||
['This is some data, with a changed hash.'])
|
||||
const newFile = new FakeFile('hello_world.txt', [
|
||||
'This is some data, with a changed hash.'
|
||||
]);
|
||||
const readRaw = new FileReader();
|
||||
|
||||
|
||||
readRaw.onload = function(event) {
|
||||
const plaintext = new Uint8Array(this.result);
|
||||
window.crypto.subtle.importKey(
|
||||
'jwk',
|
||||
{
|
||||
kty: 'oct',
|
||||
k: secretKey,
|
||||
alg: 'A128GCM',
|
||||
ext: true
|
||||
},
|
||||
{
|
||||
name: 'AES-GCM'
|
||||
},
|
||||
true,
|
||||
['encrypt', 'decrypt']
|
||||
)
|
||||
.then(key => {
|
||||
// The file hash used here is the hash of the fake
|
||||
// file from the previous test; it's a phony checksum.
|
||||
return window.crypto.subtle.encrypt(
|
||||
window.crypto.subtle
|
||||
.importKey(
|
||||
'jwk',
|
||||
{
|
||||
name: 'AES-GCM',
|
||||
iv: hexToArray(encryptedIV),
|
||||
additionalData: fileHash,
|
||||
tagLength: 128
|
||||
kty: 'oct',
|
||||
k: secretKey,
|
||||
alg: 'A128GCM',
|
||||
ext: true
|
||||
},
|
||||
key,
|
||||
plaintext
|
||||
{
|
||||
name: 'AES-GCM'
|
||||
},
|
||||
true,
|
||||
['encrypt', 'decrypt']
|
||||
)
|
||||
})
|
||||
.then(encrypted => {
|
||||
file = encrypted;
|
||||
const fr = new FileReceiver();
|
||||
location.hash = secretKey;
|
||||
|
||||
fr.on('unsafe', isUnsafe => {
|
||||
assert(isUnsafe)
|
||||
.then(key => {
|
||||
// The file hash used here is the hash of the fake
|
||||
// file from the previous test; it's a phony checksum.
|
||||
return window.crypto.subtle.encrypt(
|
||||
{
|
||||
name: 'AES-GCM',
|
||||
iv: hexToArray(encryptedIV),
|
||||
additionalData: fileHash,
|
||||
tagLength: 128
|
||||
},
|
||||
key,
|
||||
plaintext
|
||||
);
|
||||
})
|
||||
.then(encrypted => {
|
||||
file = encrypted;
|
||||
const fr = new FileReceiver();
|
||||
location.hash = secretKey;
|
||||
|
||||
fr.on('safe', () => {
|
||||
// This event should not be emitted.
|
||||
assert.fail();
|
||||
})
|
||||
fr.on('unsafe', isUnsafe => {
|
||||
assert(isUnsafe);
|
||||
});
|
||||
|
||||
fr.download().then(() => {
|
||||
assert.fail();
|
||||
done();
|
||||
}).catch(err => {
|
||||
assert(1);
|
||||
done();
|
||||
})
|
||||
})
|
||||
}
|
||||
fr.on('safe', () => {
|
||||
// This event should not be emitted.
|
||||
assert.fail();
|
||||
});
|
||||
|
||||
fr
|
||||
.download()
|
||||
.then(() => {
|
||||
assert.fail();
|
||||
done();
|
||||
})
|
||||
.catch(err => {
|
||||
assert(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
};
|
||||
readRaw.readAsArrayBuffer(newFile);
|
||||
})
|
||||
});
|
||||
|
||||
it('Should not decrypt with an incorrect checksum', function() {
|
||||
FakeXHR.prototype.getResponseHeader = function () {
|
||||
FakeXHR.prototype.getResponseHeader = function() {
|
||||
return JSON.stringify({
|
||||
aad: 'some_bad_hashz',
|
||||
filename: 'hello_world.txt',
|
||||
id: encryptedIV
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const fr = new FileReceiver();
|
||||
location.hash = secretKey;
|
||||
|
||||
return fr.download().then(([decrypted, name]) => {
|
||||
assert(decrypted);
|
||||
assert(name);
|
||||
assert.fail();
|
||||
}).catch(err => {
|
||||
assert(1);
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
return fr
|
||||
.download()
|
||||
.then(([decrypted, name]) => {
|
||||
assert(decrypted);
|
||||
assert(name);
|
||||
assert.fail();
|
||||
})
|
||||
.catch(err => {
|
||||
assert(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,7 +4,6 @@ const proxyquire = require('proxyquire');
|
||||
const request = require('supertest');
|
||||
const fs = require('fs');
|
||||
|
||||
|
||||
const logStub = {};
|
||||
logStub.info = sinon.stub();
|
||||
logStub.error = sinon.stub();
|
||||
@@ -38,17 +37,21 @@ describe('Server integration tests', function() {
|
||||
storage.flushall();
|
||||
storage.quit();
|
||||
server.close();
|
||||
})
|
||||
});
|
||||
|
||||
function upload() {
|
||||
return request(server).post('/upload')
|
||||
.field('fname', 'test_upload.txt')
|
||||
.set('X-File-Metadata', JSON.stringify({
|
||||
aad: '11111',
|
||||
id: '111111111111111111111111',
|
||||
filename: 'test_upload.txt'
|
||||
}))
|
||||
.attach('file', './test/test_upload.txt')
|
||||
return request(server)
|
||||
.post('/upload')
|
||||
.field('fname', 'test_upload.txt')
|
||||
.set(
|
||||
'X-File-Metadata',
|
||||
JSON.stringify({
|
||||
aad: '11111',
|
||||
id: '111111111111111111111111',
|
||||
filename: 'test_upload.txt'
|
||||
})
|
||||
)
|
||||
.attach('file', './test/test_upload.txt');
|
||||
}
|
||||
|
||||
it('Responds with a 200 when the service is up', function() {
|
||||
@@ -56,115 +59,123 @@ describe('Server integration tests', function() {
|
||||
});
|
||||
|
||||
it('Rejects with a 404 when a file id is not valid', function() {
|
||||
return request(server).post('/upload/123')
|
||||
.field('fname', 'test_upload.txt')
|
||||
.set('X-File-Metadata', JSON.stringify({
|
||||
'silly': 'text'
|
||||
}))
|
||||
.attach('file', './test/test_upload.txt')
|
||||
.expect(404)
|
||||
})
|
||||
return request(server)
|
||||
.post('/upload/123')
|
||||
.field('fname', 'test_upload.txt')
|
||||
.set(
|
||||
'X-File-Metadata',
|
||||
JSON.stringify({
|
||||
silly: 'text'
|
||||
})
|
||||
)
|
||||
.attach('file', './test/test_upload.txt')
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
it('Accepts a file and stores it when properly uploaded', function(done) {
|
||||
upload().then(res => {
|
||||
assert(res.body.hasOwnProperty('delete'));
|
||||
uuid = res.body.delete;
|
||||
assert(res.body.hasOwnProperty('url'));
|
||||
assert(res.body.hasOwnProperty('id'));
|
||||
fileId = res.body.id;
|
||||
fs.access('./static/' + fileId, fs.constants.F_OK, err => {
|
||||
if (err) {
|
||||
done(new Error('The file does not exist'));
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
assert(res.body.hasOwnProperty('delete'));
|
||||
uuid = res.body.delete;
|
||||
assert(res.body.hasOwnProperty('url'));
|
||||
assert(res.body.hasOwnProperty('id'));
|
||||
fileId = res.body.id;
|
||||
fs.access('./static/' + fileId, fs.constants.F_OK, err => {
|
||||
if (err) {
|
||||
done(new Error('The file does not exist'));
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Responds with a 200 if a file exists', function() {
|
||||
return request(server).get('/exists/' + fileId)
|
||||
.expect(200)
|
||||
})
|
||||
return request(server).get('/exists/' + fileId).expect(200);
|
||||
});
|
||||
|
||||
it('Exists in the redis server', function() {
|
||||
return storage.exists(fileId)
|
||||
.then(() => assert(1))
|
||||
.catch(err => assert.fail())
|
||||
})
|
||||
return storage
|
||||
.exists(fileId)
|
||||
.then(() => assert(1))
|
||||
.catch(err => assert.fail());
|
||||
});
|
||||
|
||||
it('Fails delete if the delete token does not match', function() {
|
||||
return request(server).post('/delete/' + fileId)
|
||||
.send({ delete_token: 11 })
|
||||
.expect(404);
|
||||
})
|
||||
return request(server)
|
||||
.post('/delete/' + fileId)
|
||||
.send({ delete_token: 11 })
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
it('Fails delete if the id is invalid', function() {
|
||||
return request(server).post('/delete/1')
|
||||
.expect(404);
|
||||
})
|
||||
return request(server).post('/delete/1').expect(404);
|
||||
});
|
||||
|
||||
it('Successfully deletes if the id is valid and the delete token matches', function(done) {
|
||||
request(server).post('/delete/' + fileId)
|
||||
.send({ delete_token: uuid })
|
||||
.expect(200)
|
||||
.then(() => {
|
||||
fs.access('./static/' + fileId, fs.constants.F_OK, err => {
|
||||
if (err) {
|
||||
done();
|
||||
} else {
|
||||
done(new Error('The file does not exist'));
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
it('Successfully deletes if the id is valid and the delete token matches', function(
|
||||
done
|
||||
) {
|
||||
request(server)
|
||||
.post('/delete/' + fileId)
|
||||
.send({ delete_token: uuid })
|
||||
.expect(200)
|
||||
.then(() => {
|
||||
fs.access('./static/' + fileId, fs.constants.F_OK, err => {
|
||||
if (err) {
|
||||
done();
|
||||
} else {
|
||||
done(new Error('The file does not exist'));
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Responds with a 404 if a file does not exist', function() {
|
||||
return request(server).get('/exists/notfound')
|
||||
.expect(404)
|
||||
})
|
||||
return request(server).get('/exists/notfound').expect(404);
|
||||
});
|
||||
|
||||
it('Uploads properly after a delete', function(done) {
|
||||
upload().then(res => {
|
||||
assert(res.body.hasOwnProperty('delete'));
|
||||
uuid = res.body.delete;
|
||||
assert(res.body.hasOwnProperty('url'));
|
||||
assert(res.body.hasOwnProperty('id'));
|
||||
fileId = res.body.id;
|
||||
fs.access('./static/' + fileId, fs.constants.F_OK, err => {
|
||||
if (err) {
|
||||
done(new Error('The file does not exist'));
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
assert(res.body.hasOwnProperty('delete'));
|
||||
uuid = res.body.delete;
|
||||
assert(res.body.hasOwnProperty('url'));
|
||||
assert(res.body.hasOwnProperty('id'));
|
||||
fileId = res.body.id;
|
||||
fs.access('./static/' + fileId, fs.constants.F_OK, err => {
|
||||
if (err) {
|
||||
done(new Error('The file does not exist'));
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Responds with a 200 for the download page', function() {
|
||||
return request(server).get('/download/' + fileId)
|
||||
.expect(200);
|
||||
})
|
||||
return request(server).get('/download/' + fileId).expect(200);
|
||||
});
|
||||
|
||||
it('Downloads a file properly', function() {
|
||||
return request(server).get('/assets/download/' + fileId)
|
||||
.then(res => {
|
||||
assert(res.header.hasOwnProperty('content-disposition'));
|
||||
assert(res.header.hasOwnProperty('content-type'))
|
||||
assert(res.header.hasOwnProperty('content-length'))
|
||||
assert(res.header.hasOwnProperty('x-file-metadata'))
|
||||
assert.equal(res.header['content-disposition'], 'attachment; filename=test_upload.txt')
|
||||
assert.equal(res.header['content-type'], 'application/octet-stream')
|
||||
})
|
||||
})
|
||||
return request(server).get('/assets/download/' + fileId).then(res => {
|
||||
assert(res.header.hasOwnProperty('content-disposition'));
|
||||
assert(res.header.hasOwnProperty('content-type'));
|
||||
assert(res.header.hasOwnProperty('content-length'));
|
||||
assert(res.header.hasOwnProperty('x-file-metadata'));
|
||||
assert.equal(
|
||||
res.header['content-disposition'],
|
||||
'attachment; filename=test_upload.txt'
|
||||
);
|
||||
assert.equal(res.header['content-type'], 'application/octet-stream');
|
||||
});
|
||||
});
|
||||
|
||||
it('The file is deleted after one download', function() {
|
||||
assert(!fs.existsSync('./static/' + fileId));
|
||||
})
|
||||
});
|
||||
|
||||
it('No longer exists in the redis server', function() {
|
||||
return storage.exists(fileId)
|
||||
.then(() => assert.fail())
|
||||
.catch(err => assert(1))
|
||||
})
|
||||
return storage
|
||||
.exists(fileId)
|
||||
.then(() => assert.fail())
|
||||
.catch(err => assert(1));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -110,9 +110,9 @@ describe('Testing Set using aws', function() {
|
||||
it('Should pass when the file is successfully uploaded', function() {
|
||||
const buf = Buffer.alloc(10);
|
||||
sinon.stub(crypto, 'randomBytes').returns(buf);
|
||||
s3Stub.upload.returns({promise: () => Promise.resolve()});
|
||||
s3Stub.upload.returns({ promise: () => Promise.resolve() });
|
||||
return storage
|
||||
.set('123', {on: sinon.stub()}, 'Filename.moz', {})
|
||||
.set('123', { on: sinon.stub() }, 'Filename.moz', {})
|
||||
.then(() => {
|
||||
assert(expire.calledOnce);
|
||||
assert(expire.calledWith('123', 86400));
|
||||
@@ -121,9 +121,9 @@ describe('Testing Set using aws', function() {
|
||||
});
|
||||
|
||||
it('Should fail if there was an error during uploading', function() {
|
||||
s3Stub.upload.returns({promise: () => Promise.reject()});
|
||||
s3Stub.upload.returns({ promise: () => Promise.reject() });
|
||||
return storage
|
||||
.set('123', {on: sinon.stub()}, 'Filename.moz', 'url.com')
|
||||
.set('123', { on: sinon.stub() }, 'Filename.moz', 'url.com')
|
||||
.then(_reply => assert.fail())
|
||||
.catch(err => assert(1));
|
||||
});
|
||||
|
||||
@@ -35,5 +35,5 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a class="send-new" data-l10n-id="sendYourFilesLink"></a>
|
||||
<a class="send-new" data-l10n-id="sendYourFilesLink" target="_blank"></a>
|
||||
</div>
|
||||
|
||||
@@ -5,11 +5,24 @@ if (isIE && !isUnsupportedPage) {
|
||||
window.location.replace('/unsupported/ie');
|
||||
}
|
||||
|
||||
{{#if dsn}}
|
||||
window.dsn = '{{{dsn}}}';
|
||||
{{#if sentryId}}
|
||||
var RAVEN_CONFIG = {
|
||||
release: '{{{version}}}',
|
||||
tags: {
|
||||
commit: '{{{commit}}}'
|
||||
},
|
||||
dataCallback: function (data) {
|
||||
var hash = window.location.hash;
|
||||
if (hash) {
|
||||
return JSON.parse(JSON.stringify(data).replace(new RegExp(hash.slice(1), 'g'), ''));
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
var SENTRY_ID = '{{{sentryId}}}';
|
||||
{{/if}}
|
||||
{{#if trackerId}}
|
||||
window.trackerId = '{{{trackerId}}}';
|
||||
{{#if googleAnalyticsId}}
|
||||
var GOOGLE_ANALYTICS_ID = '{{{googleAnalyticsId}}}';
|
||||
{{/if}}
|
||||
var MAXFILESIZE = {{{maxFileSize}}};
|
||||
var EXPIRE_SECONDS = {{{expireSeconds}}};
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
<link rel="icon" type="image/png" href="/resources/favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="localization" href="/locales/{locale}/send.ftl">
|
||||
<script src="/polyfill.min.js"></script>
|
||||
<script defer src="/l20n.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Reference in New Issue
Block a user