mirror of
https://gitlab.com/timvisee/send.git
synced 2025-12-06 14:10:53 +03:00
Compare commits
87 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd439bcdfb | ||
|
|
d5e936b8fc | ||
|
|
376e1efa4c | ||
|
|
09cc047ade | ||
|
|
9b6507bc1b | ||
|
|
27d2927b14 | ||
|
|
21cb8f6608 | ||
|
|
41cb49c99f | ||
|
|
504d475f5d | ||
|
|
926ce972f5 | ||
|
|
2bc7f270f8 | ||
|
|
b03022b924 | ||
|
|
66863ceb1a | ||
|
|
69e91eb4ed | ||
|
|
167bf8a607 | ||
|
|
5e10fd2db6 | ||
|
|
a451ae435e | ||
|
|
125c4232ae | ||
|
|
7f5e33613d | ||
|
|
5576bc0652 | ||
|
|
ebd3a45a2c | ||
|
|
193f54547f | ||
|
|
d344531bda | ||
|
|
4ac07800c4 | ||
|
|
e9fa6ad401 | ||
|
|
95e3ca7a1c | ||
|
|
705289d34b | ||
|
|
4282c93b2b | ||
|
|
434f8b56cc | ||
|
|
5c793dcde8 | ||
|
|
e36f685bd2 | ||
|
|
5a7d05744c | ||
|
|
81999f2fc4 | ||
|
|
c419d29c96 | ||
|
|
8cdfb47f84 | ||
|
|
5e192d0f4a | ||
|
|
1460537169 | ||
|
|
f888ea74b0 | ||
|
|
ea6c78f49a | ||
|
|
3f316fb8b0 | ||
|
|
ee444186e9 | ||
|
|
2b7f06dda2 | ||
|
|
c19b273d4f | ||
|
|
596ad871df | ||
|
|
655f685883 | ||
|
|
bbe111a95e | ||
|
|
b063cf35b8 | ||
|
|
030d65d7af | ||
|
|
aa113fd903 | ||
|
|
caeba94e04 | ||
|
|
a7de951115 | ||
|
|
e17d1f7235 | ||
|
|
51ba253f95 | ||
|
|
fef26e083a | ||
|
|
de826afb9b | ||
|
|
5944b85e67 | ||
|
|
d208a82089 | ||
|
|
a64eced8be | ||
|
|
ada45323e1 | ||
|
|
ced8c24f47 | ||
|
|
5b9e9d5146 | ||
|
|
280a4f65e7 | ||
|
|
d2dd9f4b4d | ||
|
|
2897a39131 | ||
|
|
626b9068a9 | ||
|
|
c3bb876a2c | ||
|
|
48912dd4d4 | ||
|
|
f1c894d14f | ||
|
|
60d61fa52c | ||
|
|
fe313f1001 | ||
|
|
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"}]
|
||||
|
||||
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
public/locales/* linguist-documentation
|
||||
docs/* linguist-documentation
|
||||
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
|
||||
|
||||
11
docs/faq.md
11
docs/faq.md
@@ -17,6 +17,17 @@ Many browsers support this standard and should work fine, but some have not
|
||||
implemented it yet (mobile browsers lag behind on this, in
|
||||
particular).
|
||||
|
||||
## Why does Firefox Send require JavaScript?
|
||||
|
||||
Firefox Send uses JavaScript to:
|
||||
|
||||
- Encrypt and decrypt files locally on the client instead of the server.
|
||||
- Render the user interface.
|
||||
- Manage translations on the website into [various different languages](https://github.com/mozilla/send#localization).
|
||||
- Collect data to help us improve Send in accordance with our [Terms & Privacy](https://send.firefox.com/legal).
|
||||
|
||||
Since Send is an open source project, you can see all of the cool ways we use JavaScript by [examining our code](https://github.com/mozilla/send/).
|
||||
|
||||
## How long are files available for?
|
||||
|
||||
Files are available to be downloaded for 24 hours, after which they are removed
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -14,23 +14,17 @@ $(document).ready(function() {
|
||||
//link back to homepage
|
||||
$('.send-new').attr('href', window.location.origin);
|
||||
|
||||
$('.send-new').click(function(target) {
|
||||
target.preventDefault();
|
||||
$('.send-new').click(function() {
|
||||
sendEvent('recipient', 'restarted', {
|
||||
cd2: 'completed'
|
||||
}).then(() => {
|
||||
location.href = target.currentTarget.href;
|
||||
});
|
||||
});
|
||||
|
||||
$('.legal-links a, .social-links a, #dl-firefox').click(function(target) {
|
||||
target.preventDefault();
|
||||
const metric = findMetric(target.currentTarget.href);
|
||||
// record exited event by recipient
|
||||
sendEvent('recipient', 'exited', {
|
||||
cd3: metric
|
||||
}).then(() => {
|
||||
location.href = target.currentTarget.href;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -144,7 +138,7 @@ $(document).ready(function() {
|
||||
$('#download-btn').attr('hidden', true);
|
||||
$('#expired-img').removeAttr('hidden');
|
||||
}
|
||||
return;
|
||||
throw err;
|
||||
})
|
||||
.then(([decrypted, fname]) => {
|
||||
const endTime = Date.now();
|
||||
|
||||
@@ -7,42 +7,8 @@ class FileReceiver extends EventEmitter {
|
||||
}
|
||||
|
||||
download() {
|
||||
return Promise.all([
|
||||
new Promise((resolve, reject) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.onprogress = event => {
|
||||
if (event.lengthComputable && event.target.status !== 404) {
|
||||
this.emit('progress', [event.loaded, event.total]);
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onload = function(event) {
|
||||
if (xhr.status === 404) {
|
||||
reject(new Error('notfound'));
|
||||
return;
|
||||
}
|
||||
|
||||
const blob = new Blob([this.response]);
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onload = function() {
|
||||
const meta = JSON.parse(xhr.getResponseHeader('X-File-Metadata'));
|
||||
resolve({
|
||||
data: this.result,
|
||||
aad: meta.aad,
|
||||
filename: meta.filename,
|
||||
iv: meta.id
|
||||
});
|
||||
};
|
||||
|
||||
fileReader.readAsArrayBuffer(blob);
|
||||
};
|
||||
|
||||
xhr.open('get', '/assets' + location.pathname.slice(0, -1), true);
|
||||
xhr.responseType = 'blob';
|
||||
xhr.send();
|
||||
}),
|
||||
window.crypto.subtle.importKey(
|
||||
return window.crypto.subtle
|
||||
.importKey(
|
||||
'jwk',
|
||||
{
|
||||
kty: 'oct',
|
||||
@@ -56,7 +22,45 @@ class FileReceiver extends EventEmitter {
|
||||
true,
|
||||
['encrypt', 'decrypt']
|
||||
)
|
||||
])
|
||||
.then(key => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.onprogress = event => {
|
||||
if (event.lengthComputable && event.target.status !== 404) {
|
||||
this.emit('progress', [event.loaded, event.total]);
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onload = function(event) {
|
||||
if (xhr.status === 404) {
|
||||
reject(new Error('notfound'));
|
||||
return;
|
||||
}
|
||||
|
||||
const blob = new Blob([this.response]);
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onload = function() {
|
||||
const meta = JSON.parse(xhr.getResponseHeader('X-File-Metadata'));
|
||||
resolve([
|
||||
{
|
||||
data: this.result,
|
||||
aad: meta.aad,
|
||||
filename: meta.filename,
|
||||
iv: meta.id
|
||||
},
|
||||
key
|
||||
]);
|
||||
};
|
||||
|
||||
fileReader.readAsArrayBuffer(blob);
|
||||
};
|
||||
|
||||
xhr.open('get', '/assets' + location.pathname.slice(0, -1), true);
|
||||
xhr.responseType = 'blob';
|
||||
xhr.send();
|
||||
});
|
||||
})
|
||||
.then(([fdata, key]) => {
|
||||
this.emit('decrypting', true);
|
||||
return Promise.all([
|
||||
|
||||
@@ -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);
|
||||
@@ -24,38 +19,30 @@ if (storage.has('referrer')) {
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
$('#page-one').removeAttr('hidden');
|
||||
$('#file-upload').change(onUpload);
|
||||
|
||||
$('.legal-links a, .social-links a, #dl-firefox').click(function(target) {
|
||||
target.preventDefault();
|
||||
const metric = findMetric(target.currentTarget.href);
|
||||
// record exited event by recipient
|
||||
sendEvent('sender', 'exited', {
|
||||
cd3: metric
|
||||
}).then(() => {
|
||||
location.href = target.currentTarget.href;
|
||||
});
|
||||
});
|
||||
|
||||
$('#send-new-completed').click(function(target) {
|
||||
target.preventDefault();
|
||||
$('#send-new-completed').click(function() {
|
||||
// record restarted event
|
||||
storage.referrer = 'errored-upload';
|
||||
sendEvent('sender', 'restarted', {
|
||||
cd2: 'completed'
|
||||
}).then(() => {
|
||||
storage.referrer = 'completed-upload';
|
||||
location.href = target.currentTarget.href;
|
||||
});
|
||||
});
|
||||
|
||||
$('#send-new-error').click(function(target) {
|
||||
target.preventDefault();
|
||||
$('#send-new-error').click(function() {
|
||||
// record restarted event
|
||||
storage.referrer = 'errored-upload';
|
||||
sendEvent('sender', 'restarted', {
|
||||
cd2: 'errored'
|
||||
}).then(() => {
|
||||
storage.referrer = 'errored-upload';
|
||||
location.href = target.currentTarget.href;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -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.4",
|
||||
"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"
|
||||
|
||||
38
package.json
38
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "firefox-send",
|
||||
"description": "File Sharing Experiment",
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.4",
|
||||
"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,57 @@
|
||||
"license": "MPL-2.0",
|
||||
"repository": "mozilla/send",
|
||||
"availableLanguages": [
|
||||
"en-US",
|
||||
"zh-TW",
|
||||
"zh-CN",
|
||||
"az",
|
||||
"ca",
|
||||
"cs",
|
||||
"cy",
|
||||
"de",
|
||||
"dsb",
|
||||
"en-US",
|
||||
"es-ES",
|
||||
"es-MX",
|
||||
"fr",
|
||||
"fy-NL",
|
||||
"de",
|
||||
"hsb",
|
||||
"hu",
|
||||
"id",
|
||||
"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
|
||||
95
public/locales/ca/send.ftl
Normal file
95
public/locales/ca/send.ftl
Normal file
@@ -0,0 +1,95 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Send
|
||||
siteSubtitle = experiment web
|
||||
siteFeedback = Comentaris
|
||||
uploadPageHeader = Compartició de fitxers privada i xifrada
|
||||
uploadPageExplainer = Envieu fitxers mitjançant un enllaç segur, privat i xifrat que caduca automàticament per tal que les vostres dades no es conservin a Internet per sempre.
|
||||
uploadPageLearnMore = Més informació
|
||||
uploadPageDropMessage = Arrossegueu el fitxer aquí per començar a pujar-lo
|
||||
uploadPageSizeMessage = Funciona millor quan els fitxers tenen menys d'1 GB
|
||||
uploadPageBrowseButton = Trieu un fitxer de l'ordinador
|
||||
.title = Trieu un fitxer de l'ordinador
|
||||
uploadPageMultipleFilesAlert = Actualment no es permet pujar diversos fitxers ni una carpeta.
|
||||
uploadPageBrowseButtonTitle = Puja el fitxer
|
||||
uploadingPageHeader = S'està pujant el fitxer
|
||||
importingFile = S'està important…
|
||||
verifyingFile = S'està verificant…
|
||||
encryptingFile = S'està xifrant…
|
||||
decryptingFile = S'està desxifrant…
|
||||
notifyUploadDone = La pujada ha acabat.
|
||||
uploadingPageMessage = Quan s'hagi acabat de pujat el fitxer, podreu definir les opcions de caducitat.
|
||||
uploadingPageCancel = Cancel·la la pujada
|
||||
.title = Cancel·la la pujada
|
||||
uploadCancelNotification = La pujada s'ha cancel·lat.
|
||||
uploadingPageLargeFileMessage = Aquest fitxer és gros i pot trigar una estona a pujar. Espereu assegut…
|
||||
uploadingFileNotification = Notifica'm quan s'acabi de pujar.
|
||||
uploadSuccessConfirmHeader = Llest per enviar
|
||||
uploadSvgAlt
|
||||
.alt = Puja
|
||||
uploadSuccessTimingHeader = L'enllaç al fitxer caducarà quan es baixi una vegada o d'aquí 24 hores.
|
||||
copyUrlFormLabelWithName = Copieu l'enllaç i compartiu-lo per enviar el fitxer: { $filename }
|
||||
// Note: Title text for button should be the same.
|
||||
copyUrlFormButton = Copia al porta-retalls
|
||||
.title = Copia al porta-retalls
|
||||
copiedUrl = Copiat!
|
||||
// Note: Title text for button should be the same.
|
||||
deleteFileButton = Suprimeix el fitxer
|
||||
.title = Suprimeix el fitxer
|
||||
// Note: Title text for button should be the same.
|
||||
sendAnotherFileLink = Envieu un altre fitxer
|
||||
.title = Envieu un altre fitxer
|
||||
// Alternative text used on the download link/button (indicates an action).
|
||||
downloadAltText
|
||||
.alt = Baixa
|
||||
downloadFileName = Baixeu { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Un amic us ha enviat un fitxer amb el Firefox Send, un servei que permet compartir fitxers mitjançant un enllaç segur, privat i xifrat que caduca automàticament per tal que les vostres dades no es conservin a Internet per sempre.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = Baixa
|
||||
.title = Baixa
|
||||
downloadNotification = La baixada ha acabat.
|
||||
downloadFinish = Ha acabat la baixada
|
||||
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
|
||||
sendYourFilesLink = Proveu el Firefox Send
|
||||
.title = Proveu el Firefox Send
|
||||
downloadingPageProgress = S'està baixant { $filename } ({ $size })
|
||||
downloadingPageMessage = Deixeu aquesta pestanya oberta per tal que el fitxer es pugui baixar i desxifrar.
|
||||
errorAltText
|
||||
.alt = S'ha produït un error en pujar
|
||||
errorPageHeader = Hi ha hagut un problema
|
||||
errorPageMessage = S'ha produït un error en pujar el fitxer.
|
||||
errorPageLink = Envieu un altre fitxer
|
||||
fileTooBig = Aquest fitxer és massa gros per pujar-lo. Ha de tenir menys de { $size }.
|
||||
linkExpiredAlt
|
||||
.alt = L'enllaç ha caducat
|
||||
expiredPageHeader = Aquest enllaç ha caducat o no existeix.
|
||||
notSupportedHeader = El vostre navegador no és compatible.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Aquest navegador no admet la tecnologia web amb què funciona el Firefox Send. Haureu d'utilitzar un altre navegador. Us recomanem el Firefox!
|
||||
notSupportedLink = Per què el meu navegador no és compatible?
|
||||
notSupportedOutdatedDetail = Aquesta versió del Firefox no admet la tecnologia web amb què funciona el Firefox Send. Haureu d'actualitzar el navegador.
|
||||
updateFirefox = Actualitza el Firefox
|
||||
downloadFirefoxButtonSub = Baixada gratuïta
|
||||
uploadedFile = Fitxer
|
||||
copyFileList = Copia l'URL
|
||||
// expiryFileList is used as a column header
|
||||
expiryFileList = Caduca d'aquí
|
||||
deleteFileList = Suprimeix
|
||||
nevermindButton = No, gràcies
|
||||
legalHeader = Condicions d'ús i privadesa
|
||||
legalNoticeTestPilot = Actualment el Firefox Send és un experiment del Test Pilot i està subjecte a les <a>Condicions del servei</a> i a l'<a>Avís de privadesa</a> del Test Pilot. Podeu obtenir més informació sobre aquest experiment i la recollida de dades <a>aquí</a>.
|
||||
legalNoticeMozilla = L'ús del Firefox Send també està subjecte a l'<a>Avís de privadesa de llocs web</a> i a les <a>Condicions d'ús de llocs web</a> de Mozilla.
|
||||
deletePopupText = Voleu suprimir aquest fitxer?
|
||||
deletePopupYes = Sí
|
||||
deletePopupCancel = Cancel·la
|
||||
deleteButtonHover
|
||||
.title = Suprimeix
|
||||
copyUrlHover
|
||||
.title = Copia l'URL
|
||||
footerLinkLegal = Avís legal
|
||||
// Test Pilot is a proper name and should not be localized.
|
||||
footerLinkAbout = Quant al Test Pilot
|
||||
footerLinkPrivacy = Privadesa
|
||||
footerLinkTerms = Condicions d'ús
|
||||
footerLinkCookies = Galetes
|
||||
@@ -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,7 @@ expiredPageHeader = Dieser Link ist abgelaufen oder hat nie existiert!
|
||||
notSupportedHeader = Ihr Browser wird nicht unterstützt.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Leider unterstützt dieser Browser die Web-Technologie nicht, auf der Firefox Send basiert. Sie benötigen einen anderen Browser. Wir empfehlen Firefox!
|
||||
notSupportedLink = Warum wird mein Browser nicht unterstützt?
|
||||
notSupportedOutdatedDetail = Leider unterstützt diese Firefox-Version die Web-Technologie nicht, auf der Firefox Send basiert. Sie müssen Ihren Browser aktualisieren.
|
||||
updateFirefox = Firefox aktualisieren
|
||||
downloadFirefoxButtonSub = Kostenloser Download
|
||||
|
||||
@@ -67,6 +67,7 @@ expiredPageHeader = This link has expired or never existed in the first place!
|
||||
notSupportedHeader = Your browser is not supported.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Unfortunately this browser does not support the web technology that powers Firefox Send. You’ll need to try another browser. We recommend Firefox!
|
||||
notSupportedLink = Why is my browser not supported?
|
||||
notSupportedOutdatedDetail = Unfortunately this version of Firefox does not support the web technology that powers Firefox Send. You’ll need to update your browser.
|
||||
updateFirefox = Update Firefox
|
||||
downloadFirefoxButtonSub = Free Download
|
||||
|
||||
@@ -27,6 +27,7 @@ uploadSuccessConfirmHeader = Listo para enviar
|
||||
uploadSvgAlt
|
||||
.alt = Subir
|
||||
uploadSuccessTimingHeader = El enlace al archivo expirará después de 1 descarga o en 24 horas.
|
||||
copyUrlFormLabelWithName = Copiá y compartí el enlace para enviar tu archivo: { $filename }
|
||||
// Note: Title text for button should be the same.
|
||||
copyUrlFormButton = Copiar al portapapeles
|
||||
.title = Copiar al portapapeles
|
||||
@@ -64,6 +65,9 @@ linkExpiredAlt
|
||||
.alt = Enlace explirado
|
||||
expiredPageHeader = ¡Este enlace ha expirado o nunca existió en primer lugar!
|
||||
notSupportedHeader = El navegador no está soportado.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Desafortunadamente este navegador no soporta la tecnología web que necesita Firefox Send. Deberías probar otro navegador. ¡Te recomendamos Firefox!
|
||||
notSupportedOutdatedDetail = Desafortunadamente esta versión de Firefox no soporta la tecnología web que necesita Firefox Send. Necesitás actualizar el navegador.
|
||||
updateFirefox = Actualizar Firefox
|
||||
downloadFirefoxButtonSub = Descarga gratuita
|
||||
uploadedFile = Archivo
|
||||
@@ -72,6 +76,8 @@ copyFileList = Copiar URL
|
||||
expiryFileList = Expira en
|
||||
deleteFileList = Borrar
|
||||
legalHeader = Términos y privacidad
|
||||
legalNoticeTestPilot = Firefox Send es actualmente un experimento de Test Pilot y está sujeto a los <a>términos de servicio</a> y la <a>nota de privacidad</a> de Test Pilot. Podés conocer más sobre este experimento y su recolección de datos <a>aquí</a>.
|
||||
legalNoticeMozilla = El uso del sitio web de Firefox Send también está sujeto a la <a>nota de privacidad de sitios web</a> y los <a>términos de uso de sitios web</a> de Mozilla.
|
||||
deletePopupText = ¿Borrar este archivo?
|
||||
deletePopupYes = Si
|
||||
deletePopupCancel = Cancelar
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -67,6 +67,7 @@ expiredPageHeader = Ce lien a expiré ou n’a jamais existé.
|
||||
notSupportedHeader = Votre navigateur n’est pas pris en charge.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Malheureusement, ce navigateur ne prend pas en charge les technologies web utilisées par Firefox Send. Vous devrez utiliser un autre navigateur. Nous vous recommandons Firefox !
|
||||
notSupportedLink = Pourquoi mon navigateur n’est-il pas pris en charge ?
|
||||
notSupportedOutdatedDetail = Malheureusement, cette version de Firefox ne prend pas en charge les technologies web utilisées par Firefox Send. Vous devez mettre à jour votre navigateur.
|
||||
updateFirefox = Mettre à jour Firefox
|
||||
downloadFirefoxButtonSub = Téléchargement gratuit
|
||||
|
||||
@@ -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.
|
||||
|
||||
91
public/locales/id/send.ftl
Normal file
91
public/locales/id/send.ftl
Normal file
@@ -0,0 +1,91 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Send
|
||||
siteSubtitle = eksperimen web
|
||||
siteFeedback = Saran
|
||||
uploadPageHeader = Pribadi, Berbagi Berkas Terenskripsi
|
||||
uploadPageExplainer = Kirim berkas melalui tautan yang aman, pribadi, dan terenkripsi yang secara otomatis kedaluwarsa untuk memastikan berkas Anda tidak daring selamanya.
|
||||
uploadPageLearnMore = Pelajari lebih lanjut
|
||||
uploadPageDropMessage = Lepas berkas Anda di sini untuk mulai mengunggah
|
||||
uploadPageSizeMessage = Untuk pengoperasian yang paling andal, sebaiknya jaga berkas Anda di bawah 1GB
|
||||
uploadPageBrowseButton = Pilih berkas pada komputer Anda
|
||||
.title = Pilih berkas pada komputer Anda
|
||||
uploadPageMultipleFilesAlert = Saat ini belum mendukung pengunggahan beberapa berkas atau folder.
|
||||
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 })
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Teman Anda mengirimkan berkas dengan Firefox Send, layanan yang memungkinkan Anda berbagi berkas dengan tautan yang aman, pribadi, dan terenkripsi yang secara otomatis berakhir untuk memastikan berkas Anda tidak daring selamanya.
|
||||
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.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Sayangnya peramban ini tidak mendukung teknologi web yang menggerakkan Firefox Send. Anda perlu mencoba peramban lain. Kami merekomendasikan Firefox!
|
||||
notSupportedOutdatedDetail = Sayangnya Firefox versi ini tidak mendukung teknologi web yang menggerakkan Firefox Send. Anda perlu memperbarui peramban Anda.
|
||||
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
|
||||
legalNoticeTestPilot = Saat ini Firefox Send merupakan eksperimen Test Pilot, dan merupakan subyek dari <a>Ketentuan Layanan</a> dan <a>Pemberitahuan Privasi</a> Test Pilot. Anda dapat mempelajari lebih lanjut tentang eksperimen ini dan pengumpulan datanya <a>di sini</a>.
|
||||
legalNoticeMozilla = Penggunaan situs Firefox Send juga merupakan subyek dari <a>Pemberitahuan Privasi Situs Web</a> dan <a>Persyaratan Penggunaan Situs Web</a> Mozilla.
|
||||
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
|
||||
@@ -67,6 +67,7 @@ expiredPageHeader = Pautan ini sudah luput atau pun tidak pernah wujud!
|
||||
notSupportedHeader = Pelayar anda tidak disokong.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Malangnya, pelayar ini tidak menyokong teknologi web yang melaksanakan Firefox Send. Anda perlu cuba pelayar lain. Kami syorkan Firefox!
|
||||
notSupportedLink = Kenapa pelayar saya tidak disokong?
|
||||
notSupportedOutdatedDetail = Malangnya versi Firefox ini tidak menyokong teknologi web yang menguasakan Firefox Send. Anda perlu mengemaskini pelayar anda.
|
||||
updateFirefox = Kemaskini Firefox
|
||||
downloadFirefoxButtonSub = Muat turun Percuma
|
||||
|
||||
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
|
||||
@@ -67,6 +67,7 @@ expiredPageHeader = Denne lenka har gått ut eller har aldri eksistert i utgangs
|
||||
notSupportedHeader = Nettlesaren din er ikkje støtta.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Diverre støttar denne nettlesaren ikkje webteknologien som driv Firefox Send. Du må prøve ein annan nettleser. Vi tilrår Firefox!
|
||||
notSupportedLink = Kvifor er ikkje nettlesaren min støtta?
|
||||
notSupportedOutdatedDetail = Dessverre støttar ikkje denne versjonen av Firefox nett-teknologien som driv Firefox Send. Du må å oppdatere nettlesaren din.
|
||||
updateFirefox = Oppdater Firefox
|
||||
downloadFirefoxButtonSub = Gratis nedlasting
|
||||
|
||||
@@ -67,6 +67,7 @@ expiredPageHeader = Esse link expirou, ou talvez nunca tenha existido!
|
||||
notSupportedHeader = Seu navegador não tem suporte.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Infelizmente esse navegador não suporta a tecnologia utilizada pelo Firefox Send. Tente com outro navegador. Nós recomendamos o Firefox! ;-)
|
||||
notSupportedLink = Por que meu navegador não é suportado?
|
||||
notSupportedOutdatedDetail = Infelizmente esta versão do Firefox não suporta a tecnologia web que faz o Firefox Send funcionar. Você precisa atualizar o seu navegador.
|
||||
updateFirefox = Atualizar o Firefox
|
||||
downloadFirefoxButtonSub = Download gratuito
|
||||
|
||||
@@ -3,12 +3,12 @@ title = Firefox Send
|
||||
siteSubtitle = experiência web
|
||||
siteFeedback = Feedback
|
||||
uploadPageHeader = Partilha de ficheiros privada e encriptada
|
||||
uploadPageExplainer = Envie ficheiros através de uma ligação segura, privada e encriptada que automaticamente expira para garantir que as suas coisas não fiquem online para sempre.
|
||||
uploadPageExplainer = Envie ficheiros através de uma ligação segura, privada e encriptada que expira automaticamente para garantir que as suas coisas não fiquem online para sempre.
|
||||
uploadPageLearnMore = Saber mais
|
||||
uploadPageDropMessage = Largue o seu ficheiro aqui para começar a carregar
|
||||
uploadPageSizeMessage = Para uma operação mais confiável, é melhor manter o seu ficheiro abaixo de 1GB
|
||||
uploadPageBrowseButton = Selecione um ficheiro no seu computador
|
||||
.title = Selecione um ficheiro no seu computador
|
||||
uploadPageBrowseButton = Selecionar um ficheiro no seu computador
|
||||
.title = Selecionar um ficheiro no seu computador
|
||||
uploadPageMultipleFilesAlert = Carregar múltiplos ficheiros ou uma pasta não é atualmente suportado.
|
||||
uploadPageBrowseButtonTitle = Carregar ficheiro
|
||||
uploadingPageHeader = A carregar o seu ficheiro
|
||||
@@ -44,7 +44,7 @@ downloadAltText
|
||||
downloadFileName = Descarregar { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = O seu amigo está a enviar-lhe um ficheiro com o Firefox Send, um serviço que lhe permite partilhar ficheiro com uma ligação segura, privada e encriptada que automaticamente expira para garantir que as suas coisas não fiquem online para sempre.
|
||||
downloadMessage = O seu amigo está a enviar-lhe um ficheiro com o Firefox Send, um serviço que lhe permite partilhar ficheiro com uma ligação segura, privada e encriptada que expira automaticamente para garantir que as suas coisas não fiquem online para sempre.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = Descarregar
|
||||
.title = Descarregar
|
||||
@@ -67,6 +67,7 @@ expiredPageHeader = Esta ligação expirou ou nunca existiu em primeiro lugar!
|
||||
notSupportedHeader = O seu navegador não é suportado.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Infelizmente este navegador não suporta a tecnologia web que faz o Firefox Send funcionar. Irá precisar de tentar outro navegador. Nós recomendamos o Firefox!
|
||||
notSupportedLink = Porque é que o meu navegador não é suportado?
|
||||
notSupportedOutdatedDetail = Infelizmente esta versão do Firefox não suporta a tecnologia web que faz o Firefox Send funcionar. Precisa de atualizar o seu navegador.
|
||||
updateFirefox = Atualizar o Firefox
|
||||
downloadFirefoxButtonSub = Descarga gratuita
|
||||
|
||||
@@ -67,6 +67,7 @@ expiredPageHeader = Ta povezava je potekla ali pa sploh ni obstajala!
|
||||
notSupportedHeader = Vaš brskalnik ni podprt.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Ta brskalnik na žalost ne podpira tehnologije, na kateri temelji Firefox Send. Uporabiti boste morali drug brskalnik. Priporočamo Firefox!
|
||||
notSupportedLink = Zakaj moj brskalnik ni podprt?
|
||||
notSupportedOutdatedDetail = Ta brskalnik žal ne podpira tehnologije, na kateri temelji Firefox Send. Svoj brskalnik boste morali posodobiti.
|
||||
updateFirefox = Posodobi Firefox
|
||||
downloadFirefoxButtonSub = Brezplačen prenos
|
||||
|
||||
95
public/locales/sr/send.ftl
Normal file
95
public/locales/sr/send.ftl
Normal file
@@ -0,0 +1,95 @@
|
||||
// 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!
|
||||
notSupportedLink = Зашто мој прегледач није подржан?
|
||||
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 = Колачићи
|
||||
@@ -64,6 +64,7 @@ expiredPageHeader = Bu bağlantı zaman aşımına uğramış veya böyle bir ba
|
||||
notSupportedHeader = Tarayıcınız desteklenmiyor.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Ne yazık ki tarayıcınız Firefox Send için gereken web teknolojilerini desteklemiyor. Başka bir tarayıcıyla deneyebilirsiniz. Önerimiz tabii ki Firefox!
|
||||
notSupportedLink = Tarayıcım neden desteklenmiyor?
|
||||
notSupportedOutdatedDetail = Kullandığınız Firefox sürümü Firefox Send için gereken web teknolojilerini desteklemiyor. Tarayıcınızı güncellemeniz gerekiyor.
|
||||
updateFirefox = Firefox’u güncelle
|
||||
downloadFirefoxButtonSub = Ücretsiz indirin
|
||||
|
||||
94
public/locales/uk/send.ftl
Normal file
94
public/locales/uk/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 = Для більш надійної роботи сервісу, розмір вашого файлу не має перевищувати 1ГБ.
|
||||
uploadPageBrowseButton = Виберіть файл на комп'ютері
|
||||
.title = Виберіть файл на комп'ютері
|
||||
uploadPageMultipleFilesAlert = Вивантаження кількох файлів чи тек на даний момент не підтримується.
|
||||
uploadPageBrowseButtonTitle = Вивантажити файл
|
||||
uploadingPageHeader = Вивантажуємо ваш файл
|
||||
importingFile = Імпортуємо...
|
||||
verifyingFile = Перевіряємо...
|
||||
encryptingFile = Шифруємо...
|
||||
decryptingFile = Розшифровуємо...
|
||||
notifyUploadDone = Ваше вивантаження завершено.
|
||||
uploadingPageMessage = Як тільки ваш вайл вивантажиться,ви зможете встановити термін зберігання.
|
||||
uploadingPageCancel = Скасувати вивантаження
|
||||
.title = Скасувати вивантаження
|
||||
uploadCancelNotification = Ваше вивантаження було скасовано.
|
||||
uploadingPageLargeFileMessage = Цей файл доволі великий і його вивантаження може зайняти певний час. Тримайтеся!
|
||||
uploadingFileNotification = Сповістити мене, коли вивантаження буде готово.
|
||||
uploadSuccessConfirmHeader = Готовий до надсилання
|
||||
uploadSvgAlt
|
||||
.alt = Вивантажити
|
||||
uploadSuccessTimingHeader = Час дії цього посилання закінчиться після 1 завантаження, або через 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 не підтримує веб-технологію, завдяки якій працює Firefox Send. Вам потрібно оновити свій браузер.
|
||||
updateFirefox = Оновити Firefox
|
||||
downloadFirefoxButtonSub = Безкоштовне завантаження
|
||||
uploadedFile = Файл
|
||||
copyFileList = Копіювати URL
|
||||
// expiryFileList is used as a column header
|
||||
expiryFileList = Термін дії закінчується
|
||||
deleteFileList = Видалити
|
||||
nevermindButton = Не важливо
|
||||
legalHeader = Умови та конфіденційність
|
||||
legalNoticeTestPilot = Firefox Send в даний час є експериментом Test Pilot, і тому підпадає під <a>умови служби</ a> і <a>повідомлення про приватність</a> Test Pilot. Ви можете дізнатись більше про цей експеримент і його збір даних <a>тут</a>.
|
||||
legalNoticeMozilla = Використання сайту Firefox Send також підпадає під <a>повідомлення про конфіденційність веб-сайтів</ a> та <a>правила використання веб-сайтів</a> Mozilla.
|
||||
deletePopupText = Видалити цей файл?
|
||||
deletePopupYes = Так
|
||||
deletePopupCancel = Скасувати
|
||||
deleteButtonHover
|
||||
.title = Видалити
|
||||
copyUrlHover
|
||||
.title = Копіювати URL
|
||||
footerLinkLegal = Права
|
||||
// Test Pilot is a proper name and should not be localized.
|
||||
footerLinkAbout = Про Test Pilot
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -390,8 +393,8 @@ tbody {
|
||||
letter-spacing: -0.78px;
|
||||
font-family: 'Segoe UI', 'SF Pro Text', sans-serif;
|
||||
top: 53px;
|
||||
left: 246.75px;
|
||||
width: 98.5px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
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');
|
||||
|
||||
200
server/server.js
200
server/server.js
@@ -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();
|
||||
@@ -95,7 +96,8 @@ app.get('/', (req, res) => {
|
||||
app.get('/unsupported/:reason', (req, res) => {
|
||||
const outdated = req.params.reason === 'outdated';
|
||||
res.render('unsupported', {
|
||||
outdated: outdated
|
||||
outdated,
|
||||
fira: true
|
||||
});
|
||||
});
|
||||
|
||||
@@ -106,101 +108,89 @@ 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
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/exists/:id', (req, res) => {
|
||||
app.get('/exists/:id', async (req, res) => {
|
||||
const id = req.params.id;
|
||||
if (!validateID(id)) {
|
||||
res.sendStatus(404);
|
||||
return;
|
||||
}
|
||||
|
||||
storage
|
||||
.exists(id)
|
||||
.then(() => {
|
||||
res.sendStatus(200);
|
||||
})
|
||||
.catch(err => res.sendStatus(404));
|
||||
try {
|
||||
await storage.exists(id);
|
||||
res.sendStatus(200);
|
||||
} catch (e) {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/download/:id', (req, res) => {
|
||||
app.get('/download/:id', async (req, res) => {
|
||||
const id = req.params.id;
|
||||
if (!validateID(id)) {
|
||||
res.sendStatus(404);
|
||||
return;
|
||||
}
|
||||
|
||||
storage
|
||||
.filename(id)
|
||||
.then(filename => {
|
||||
return storage.length(id).then(contentLength => {
|
||||
storage.ttl(id).then(timeToExpiry => {
|
||||
res.render('download', {
|
||||
filename: decodeURIComponent(filename),
|
||||
filesize: bytes(contentLength),
|
||||
sizeInBytes: contentLength,
|
||||
timeToExpiry: timeToExpiry
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
res.status(404).render('notfound');
|
||||
try {
|
||||
const filename = await storage.filename(id);
|
||||
const contentLength = await storage.length(id);
|
||||
const timeToExpiry = await storage.ttl(id);
|
||||
res.render('download', {
|
||||
filename: decodeURIComponent(filename),
|
||||
filesize: bytes(contentLength),
|
||||
sizeInBytes: contentLength,
|
||||
timeToExpiry: timeToExpiry
|
||||
});
|
||||
} catch (e) {
|
||||
res.status(404).render('notfound');
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/assets/download/:id', (req, res) => {
|
||||
app.get('/assets/download/:id', async (req, res) => {
|
||||
const id = req.params.id;
|
||||
if (!validateID(id)) {
|
||||
res.sendStatus(404);
|
||||
return;
|
||||
}
|
||||
|
||||
storage
|
||||
.metadata(id)
|
||||
.then(meta => {
|
||||
storage
|
||||
.length(id)
|
||||
.then(contentLength => {
|
||||
res.writeHead(200, {
|
||||
'Content-Disposition': 'attachment; filename=' + meta.filename,
|
||||
'Content-Type': 'application/octet-stream',
|
||||
'Content-Length': contentLength,
|
||||
'X-File-Metadata': JSON.stringify(meta)
|
||||
});
|
||||
const file_stream = storage.get(id);
|
||||
|
||||
file_stream.on('end', () => {
|
||||
storage
|
||||
.forceDelete(id)
|
||||
.then(err => {
|
||||
if (!err) {
|
||||
log.info('Deleted:', id);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
log.info('DeleteError:', id);
|
||||
});
|
||||
});
|
||||
|
||||
file_stream.pipe(res);
|
||||
})
|
||||
.catch(err => {
|
||||
res.sendStatus(404);
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
res.sendStatus(404);
|
||||
try {
|
||||
const meta = await storage.metadata(id);
|
||||
const contentLength = await storage.length(id);
|
||||
res.writeHead(200, {
|
||||
'Content-Disposition': `attachment; filename=${meta.filename}`,
|
||||
'Content-Type': 'application/octet-stream',
|
||||
'Content-Length': contentLength,
|
||||
'X-File-Metadata': JSON.stringify(meta)
|
||||
});
|
||||
const file_stream = storage.get(id);
|
||||
|
||||
file_stream.on('end', async () => {
|
||||
try {
|
||||
const err = await storage.forceDelete(id);
|
||||
if (!err) {
|
||||
log.info('Deleted:', id);
|
||||
}
|
||||
} catch (e) {
|
||||
log.info('DeleteError:', id);
|
||||
}
|
||||
});
|
||||
|
||||
file_stream.pipe(res);
|
||||
} catch (e) {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/delete/:id', (req, res) => {
|
||||
app.post('/delete/:id', async (req, res) => {
|
||||
const id = req.params.id;
|
||||
|
||||
if (!validateID(id)) {
|
||||
@@ -215,15 +205,15 @@ app.post('/delete/:id', (req, res) => {
|
||||
return;
|
||||
}
|
||||
|
||||
storage
|
||||
.delete(id, delete_token)
|
||||
.then(err => {
|
||||
if (!err) {
|
||||
log.info('Deleted:', id);
|
||||
res.sendStatus(200);
|
||||
}
|
||||
})
|
||||
.catch(err => res.sendStatus(404));
|
||||
try {
|
||||
const err = await storage.delete(id, delete_token);
|
||||
if (!err) {
|
||||
log.info('Deleted:', id);
|
||||
res.sendStatus(200);
|
||||
}
|
||||
} catch (e) {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/upload', (req, res, next) => {
|
||||
@@ -232,7 +222,7 @@ app.post('/upload', (req, res, next) => {
|
||||
|
||||
try {
|
||||
meta = JSON.parse(req.header('X-File-Metadata'));
|
||||
} catch (err) {
|
||||
} catch (e) {
|
||||
res.sendStatus(400);
|
||||
return;
|
||||
}
|
||||
@@ -251,39 +241,36 @@ app.post('/upload', (req, res, next) => {
|
||||
log.info('meta', meta);
|
||||
req.pipe(req.busboy);
|
||||
|
||||
req.busboy.on('file', (fieldname, file, filename) => {
|
||||
req.busboy.on('file', async (fieldname, file, filename) => {
|
||||
log.info('Uploading:', newId);
|
||||
|
||||
storage.set(newId, file, filename, meta).then(
|
||||
() => {
|
||||
const protocol = conf.env === 'production' ? 'https' : req.protocol;
|
||||
const url = `${protocol}://${req.get('host')}/download/${newId}/`;
|
||||
res.json({
|
||||
url,
|
||||
delete: meta.delete,
|
||||
id: newId
|
||||
});
|
||||
},
|
||||
err => {
|
||||
if (err.message === 'limit') {
|
||||
return res.sendStatus(413);
|
||||
}
|
||||
res.sendStatus(500);
|
||||
try {
|
||||
await storage.set(newId, file, filename, meta);
|
||||
|
||||
const protocol = conf.env === 'production' ? 'https' : req.protocol;
|
||||
const url = `${protocol}://${req.get('host')}/download/${newId}/`;
|
||||
res.json({
|
||||
url,
|
||||
delete: meta.delete,
|
||||
id: newId
|
||||
});
|
||||
} catch (e) {
|
||||
if (e.message === 'limit') {
|
||||
return res.sendStatus(413);
|
||||
}
|
||||
);
|
||||
res.sendStatus(500);
|
||||
}
|
||||
});
|
||||
|
||||
req.on('close', err => {
|
||||
storage
|
||||
.forceDelete(newId)
|
||||
.then(err => {
|
||||
if (!err) {
|
||||
log.info('Deleted:', newId);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
log.info('DeleteError:', newId);
|
||||
});
|
||||
req.on('close', async err => {
|
||||
try {
|
||||
const err = await storage.forceDelete(newId);
|
||||
if (!err) {
|
||||
log.info('Deleted:', newId);
|
||||
}
|
||||
} catch (e) {
|
||||
log.info('DeleteError:', newId);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -291,8 +278,13 @@ app.get('/__lbheartbeat__', (req, res) => {
|
||||
res.sendStatus(200);
|
||||
});
|
||||
|
||||
app.get('/__heartbeat__', (req, res) => {
|
||||
storage.ping().then(() => res.sendStatus(200), () => res.sendStatus(500));
|
||||
app.get('/__heartbeat__', async (req, res) => {
|
||||
try {
|
||||
await storage.ping();
|
||||
res.sendStatus(200);
|
||||
} catch (e) {
|
||||
res.sendStatus(500);
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/__version__', (req, res) => {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div id="page-one">
|
||||
<div id="page-one" hidden>
|
||||
<script src="/upload.js"></script>
|
||||
<div class="title" data-l10n-id="uploadPageHeader"></div>
|
||||
<div class="description">
|
||||
|
||||
@@ -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}}};
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Firefox Send</title>
|
||||
<script src="/jsconfig.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/main.css" />
|
||||
<link rel="stylesheet" href="https://code.cdn.mozilla.net/fonts/fira.css">
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<meta name="defaultLanguage" content="en-US">
|
||||
<meta name="availableLanguages" content="{{availableLanguages}}">
|
||||
|
||||
<title>Firefox Send</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/main.css" />
|
||||
{{#if fira}}
|
||||
<link rel="stylesheet" type="text/css" href="https://code.cdn.mozilla.net/fonts/fira.css" />
|
||||
{{/if}}
|
||||
|
||||
<link rel="icon" type="image/png" href="/resources/favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="localization" href="/locales/{locale}/send.ftl">
|
||||
|
||||
<script src="/jsconfig.js"></script>
|
||||
<script src="/polyfill.min.js"></script>
|
||||
<script defer src="/l20n.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
@@ -28,16 +34,21 @@
|
||||
<a href="https://qsurvey.mozilla.com/s3/txp-firefox-send" rel="noreferrer noopener" class="feedback" target="_blank" data-l10n-id="siteFeedback">Feedback</a>
|
||||
</header>
|
||||
<div class="all">
|
||||
<noscript>
|
||||
<h2>Firefox Send requires JavaScript</h2>
|
||||
<p><a href="https://github.com/mozilla/send/blob/master/docs/faq.md#why-does-firefox-send-require-javascript" target="_blank" rel="noreferrer noopener">Why does Firefox Send require JavaScript?</a></p>
|
||||
<p>Please enable JavaScript and try again.</p>
|
||||
</noscript>
|
||||
{{{body}}}
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="legal-links">
|
||||
<a href="https://www.mozilla.org"><img class="mozilla-logo" src="/resources/mozilla-logo.svg"/></a>
|
||||
<a href="https://www.mozilla.org/about/legal" data-l10n-id="footerLinkLegal"></a>
|
||||
<a href="https://testpilot.firefox.com/about" data-l10n-id="footerLinkAbout"></a>
|
||||
<a href="/legal" data-l10n-id="footerLinkPrivacy"></a>
|
||||
<a href="/legal" data-l10n-id="footerLinkTerms"></a>
|
||||
<a href="https://www.mozilla.org/privacy/websites/#cookies" data-l10n-id="footerLinkCookies"></a>
|
||||
<a href="https://www.mozilla.org" target="_blank"><img class="mozilla-logo" src="/resources/mozilla-logo.svg"/></a>
|
||||
<a href="https://www.mozilla.org/about/legal" data-l10n-id="footerLinkLegal" target="_blank">Legal</a>
|
||||
<a href="https://testpilot.firefox.com/about" data-l10n-id="footerLinkAbout" target="_blank">About Test Pilot</a>
|
||||
<a href="/legal" data-l10n-id="footerLinkPrivacy" target="_blank">Privacy</a>
|
||||
<a href="/legal" data-l10n-id="footerLinkTerms" target="_blank">Terms</a>
|
||||
<a href="https://www.mozilla.org/privacy/websites/#cookies" data-l10n-id="footerLinkCookies" target="_blank">Cookies</a>
|
||||
</div>
|
||||
<div class="social-links">
|
||||
<a href="https://github.com/mozilla/send" target="_blank" rel="noreferrer noopener"><img class="github" src="/resources/github-icon.svg"/></a>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
</a>
|
||||
{{else}}
|
||||
<div class="description" data-l10n-id="notSupportedDetail">Unfortunately this browser does not support the web technology that powers Firefox Send. You’ll need to try another browser. We recommend Firefox!</div>
|
||||
<div class="description"><a href="https://github.com/mozilla/send/blob/master/docs/faq.md#why-is-my-browser-not-supported" data-l10n-id="notSupportedLink" target="_blank" rel="noopener noreferrer">Why is my browser not supported?</a></div>
|
||||
<a id="dl-firefox" href="https://www.mozilla.org/firefox/new/?scene=2" target="_blank">
|
||||
<img src="/resources/firefox_logo-only.svg" class="firefox-logo" alt="Firefox"/>
|
||||
<div class="unsupported-button-text">Firefox<br>
|
||||
|
||||
Reference in New Issue
Block a user