Compare commits

...

87 Commits

Author SHA1 Message Date
Danny Coates
dd439bcdfb v1.0.4 2017-08-03 16:05:56 -07:00
Danny Coates
d5e936b8fc Merge pull request #418 from mozilla/footer-link-blank
_blank all footer links
2017-08-03 16:04:41 -07:00
Danny Coates
376e1efa4c don't preventDefault on links 2017-08-03 15:50:56 -07:00
Danny Coates
09cc047ade _blank all footer links 2017-08-03 15:32:56 -07:00
Danny Coates
9b6507bc1b added 'id' locale to prod 2017-08-03 15:28:08 -07:00
Danny Coates
27d2927b14 added 'ca' locale to prod 2017-08-03 15:22:44 -07:00
Danny Coates
21cb8f6608 Revert "updated prod locales"
This reverts commit 41cb49c99f.
2017-08-03 15:19:55 -07:00
Danny Coates
41cb49c99f updated prod locales 2017-08-03 15:18:53 -07:00
Selim Şumlu
504d475f5d Pontoon: Update Turkish (tr) localization of Test Pilot: Firefox Send
Localization authors:
- Selim Şumlu <selim@sum.lu>
2017-08-03 21:50:57 +00:00
manxmensch
926ce972f5 Pontoon: Update Malay (ms) localization of Test Pilot: Firefox Send
Localization authors:
- manxmensch <manxmensch@gmail.com>
2017-08-03 21:50:54 +00:00
Jordi Serratosa
2bc7f270f8 Pontoon: Update Catalan (ca) localization of Test Pilot: Firefox Send
Localization authors:
- Jordi Serratosa <jordis@softcatala.cat>
2017-08-03 21:31:19 +00:00
Jordi Serratosa
b03022b924 Pontoon: Update Catalan (ca) localization of Test Pilot: Firefox Send
Localization authors:
- Jordi Serratosa <jordis@softcatala.cat>
2017-08-03 21:10:40 +00:00
Jordi Serratosa
66863ceb1a Pontoon: Update Catalan (ca) localization of Test Pilot: Firefox Send
Localization authors:
- Jordi Serratosa <jordis@softcatala.cat>
2017-08-03 20:51:09 +00:00
Rodrigo
69e91eb4ed Pontoon: Update Portuguese (pt-PT) localization of Test Pilot: Firefox Send
Localization authors:
- Rodrigo <rodrigo.mcunha@hotmail.com>
2017-08-03 20:31:18 +00:00
Maykon Chagas
167bf8a607 Pontoon: Update Portuguese (pt-BR) localization of Test Pilot: Firefox Send
Localization authors:
- Maykon Chagas <mchagas@riseup.net>
2017-08-03 20:31:16 +00:00
Théo Chevalier
5e10fd2db6 Pontoon: Update French (fr) localization of Test Pilot: Firefox Send
Localization authors:
- Théo Chevalier <theo.chevalier11@gmail.com>
2017-08-03 20:31:14 +00:00
Jordi Serratosa
a451ae435e Pontoon: Update Catalan (ca) localization of Test Pilot: Firefox Send
Localization authors:
- Jordi Serratosa <jordis@softcatala.cat>
2017-08-03 20:31:11 +00:00
Erica
125c4232ae Merge pull request #386 from ariestiyansyah/master
fix percentage view on mobile layout
2017-08-03 16:12:57 -04:00
Michael Köhler
7f5e33613d Pontoon: Update German (de) localization of Test Pilot: Firefox Send
Localization authors:
- Michael Köhler <michael.koehler1@gmx.de>
2017-08-03 20:10:23 +00:00
Rizky Ariestiyansyah
5576bc0652 fix for firefox 51 and 52 issue 2017-08-04 02:37:42 +07:00
Rok Žerdin
ebd3a45a2c Pontoon: Update Slovenian (sl) localization of Test Pilot: Firefox Send
Localization authors:
- Rok Žerdin <rok.zerdin1990@gmail.com>
2017-08-03 19:31:23 +00:00
Марко Костић (Marko Kostić)
193f54547f Pontoon: Update Serbian (sr) localization of Test Pilot: Firefox Send
Localization authors:
- Марко Костић (Marko Kostić) <marko.m.kostic@gmail.com>
2017-08-03 19:31:19 +00:00
Bjørn I
d344531bda Pontoon: Update Norwegian Nynorsk (nn-NO) localization of Test Pilot: Firefox Send
Localization authors:
- Bjørn I. <bjorn.svindseth@online.no>
2017-08-03 19:31:17 +00:00
Erica
4ac07800c4 Merge pull request #414 from pdehaan/issue-377
Add link to FAQ in unsupported view
2017-08-03 15:09:15 -04:00
Peter deHaan
e9fa6ad401 Add en-US FAQ string to /unsupported/* route as fallback 2017-08-03 12:03:31 -07:00
Danny Coates
95e3ca7a1c Merge pull request #415 from pdehaan/de-fira
Only include Fira CSS on /unsupported/* route
2017-08-03 11:50:46 -07:00
Peter deHaan
705289d34b Only include Fira CSS on /unsupported/* route 2017-08-03 11:12:13 -07:00
Peter deHaan
4282c93b2b Add link to FAQ in unsupported view 2017-08-03 10:53:51 -07:00
Danny Coates
434f8b56cc Merge pull request #412 from mozilla/i151
throw key errors before download begins
2017-08-03 10:35:50 -07:00
Danny Coates
5c793dcde8 Merge pull request #404 from weihanglo/async-await
Use async function instead of promise (#325)
2017-08-03 10:24:57 -07:00
Danny Coates
e36f685bd2 throw key errors before download begins 2017-08-03 10:04:09 -07:00
Peter deHaan
5a7d05744c Merge pull request #406 from pdehaan/issue-373
Add noscript tag
2017-08-03 09:39:23 -07:00
Marcelo Poli
81999f2fc4 Pontoon: Update Spanish (es-AR) localization of Test Pilot: Firefox Send
Localization authors:
- Marcelo Poli <enzomatrix@gmail.com>
2017-08-03 16:31:36 +00:00
Peter deHaan
c419d29c96 Updated FAQ wording 2017-08-03 09:26:04 -07:00
Marcelo Poli
8cdfb47f84 Pontoon: Update Spanish (es-AR) localization of Test Pilot: Firefox Send
Localization authors:
- Marcelo Poli <enzomatrix@gmail.com>
2017-08-03 16:11:06 +00:00
Tymur Faradzhev
5e192d0f4a Pontoon: Update Ukrainian (uk) localization of Test Pilot: Firefox Send
Localization authors:
- Tymur Faradzhev <faradzhev.timur@gmail.com>
2017-08-03 15:31:37 +00:00
Tymur Faradzhev
1460537169 Pontoon: Update Ukrainian (uk) localization of Test Pilot: Firefox Send
Localization authors:
- Tymur Faradzhev <faradzhev.timur@gmail.com>
2017-08-03 15:11:27 +00:00
Tymur Faradzhev
f888ea74b0 Pontoon: Update Ukrainian (uk) localization of Test Pilot: Firefox Send
Localization authors:
- Tymur Faradzhev <faradzhev.timur@gmail.com>
2017-08-03 14:51:07 +00:00
Peter deHaan
ea6c78f49a Add en-US default text to footer links 2017-08-02 23:43:00 -07:00
Peter deHaan
3f316fb8b0 Add noscript tag 2017-08-02 23:37:55 -07:00
Danny Coates
ee444186e9 fixed .gitattributes locale dir 2017-08-02 23:02:50 -07:00
Weihang Lo
2b7f06dda2 Code formatting 2017-08-03 14:01:13 +08:00
Danny Coates
c19b273d4f added .gitattributes 2017-08-02 22:59:47 -07:00
Weihang Lo
596ad871df Use async function instead of promise (#325) 2017-08-03 13:31:23 +08:00
eljuno
655f685883 Pontoon: Update Indonesian (id) localization of Test Pilot: Firefox Send
Localization authors:
- eljuno <eljunotrie_anggoro@yahoo.co.id>
- Kiki <kelimutu.rizki@gmail.com>
2017-08-03 03:50:50 +00:00
Weihang Lo
bbe111a95e Use async function instead of promise (#325) 2017-08-03 11:11:04 +08:00
Rodrigo
b063cf35b8 Pontoon: Update Portuguese (pt-PT) localization of Test Pilot: Firefox Send
Localization authors:
- Rodrigo <rodrigo.mcunha@hotmail.com>
2017-08-03 00:50:35 +00:00
Danny Coates
030d65d7af v1.0.3 2017-08-02 16:59:41 -07:00
Danny Coates
aa113fd903 updated production locales 2017-08-02 16:58:26 -07:00
Danny Coates
caeba94e04 format 2017-08-02 16:51:18 -07:00
Emin Mastizada
a7de951115 Pontoon: Update Azerbaijani (az) localization of Test Pilot: Firefox Send
Localization authors:
- Emin Mastizada <emin@mastizada.com>
2017-08-02 23:50:59 +00:00
Emin Mastizada
e17d1f7235 Pontoon: Update Azerbaijani (az) localization of Test Pilot: Firefox Send
Localization authors:
- Emin Mastizada <emin@mastizada.com>
2017-08-02 23:31:39 +00:00
Emin Mastizada
51ba253f95 Pontoon: Update Azerbaijani (az) localization of Test Pilot: Firefox Send
Localization authors:
- Emin Mastizada <emin@mastizada.com>
2017-08-02 23:10:44 +00:00
Danny Coates
fef26e083a removed extraneous captureException 2017-08-02 15:53:52 -07:00
Danny Coates
de826afb9b Merge pull request #402 from mozilla/filter-sentry
filter the hash from error reports
2017-08-02 15:50:09 -07:00
Danny Coates
5944b85e67 filter the hash from error reports 2017-08-02 15:04:34 -07:00
Danny Coates
d208a82089 Merge pull request #400 from mozilla/fix-dl-breaking-link
fix link that breaks download by opening in new tab
2017-08-02 14:05:55 -07:00
John Gruen
a64eced8be fix link that breaks download by opening in new tab 2017-08-02 22:38:17 +02:00
Danny Coates
ada45323e1 Merge pull request #369 from pdehaan/eslint-no-alert
Add ESLint no-alert shame rule
2017-08-02 12:34:27 -07:00
Danny Coates
ced8c24f47 Merge pull request #396 from mozilla/i395
add babel-polyfill
2017-08-02 12:31:43 -07:00
Danny Coates
5b9e9d5146 Merge pull request #394 from mozilla/i393
catch JSON.parse errors of storage metadata
2017-08-02 12:28:55 -07:00
Danny Coates
280a4f65e7 begrudgingly added babel-polyfill 2017-08-02 12:25:13 -07:00
Danny Coates
d2dd9f4b4d Merge pull request #367 from pdehaan/issue-364
Generate production locales using 'compare-locales'
2017-08-02 12:05:23 -07:00
Danny Coates
2897a39131 catch JSON.parse errors of storage metadata 2017-08-02 11:21:03 -07:00
Erica
626b9068a9 Merge pull request #392 from weihanglo/master
Adjust hover behavior on send-logo (#382)
Fixes: #382.
2017-08-02 13:59:22 -04:00
Weihang Lo
c3bb876a2c Adjust hover behavior on send-logo (#382) 2017-08-03 01:40:57 +08:00
Weihang Lo
48912dd4d4 Adjust hover behavior on send-logo (#382) 2017-08-03 00:38:56 +08:00
Марко Костић (Marko Kostić)
f1c894d14f Pontoon: Update Serbian (sr) localization of Test Pilot: Firefox Send
Localization authors:
- Марко Костић (Marko Kostić) <marko.m.kostic@gmail.com>
2017-08-02 15:31:30 +00:00
Марко Костић (Marko Kostić)
60d61fa52c Pontoon: Update Serbian (sr) localization of Test Pilot: Firefox Send
Localization authors:
- Марко Костић (Marko Kostić) <marko.m.kostic@gmail.com>
2017-08-02 15:11:02 +00:00
ariestiyansyah
fe313f1001 fix percentage view on mobile layout 2017-08-02 21:11:59 +07:00
eljuno
68705f60db Pontoon: Update Indonesian (id) localization of Test Pilot: Firefox Send
Localization authors:
- Rahmat Subekti <rahmatsubekti@live.com>
- eljuno <eljunotrie_anggoro@yahoo.co.id>
- Kiki <kelimutu.rizki@gmail.com>
2017-08-02 12:31:54 +00:00
Fjoerfoks
92303988c0 Pontoon: Update Frisian (fy-NL) localization of Test Pilot: Firefox Send
Localization authors:
- Fjoerfoks <fryskefirefox@gmail.com>
2017-08-02 11:32:21 +00:00
Peter deHaan
49d578217c Merge pull request #380 from pdehaan/readme-pontoon
Add Pontoon URL to README
2017-08-01 22:24:48 -07:00
Peter deHaan
1abb3b7ebe Update README text w/ guidance from flod 2017-08-01 21:51:19 -07:00
Peter deHaan
4f3c2498a6 Add get-prod-locales and lint-locales scripts 2017-08-01 20:24:54 -07:00
Peter deHaan
33babe6f67 Add Pontoon URL to README 2017-08-01 17:01:11 -07:00
Tomáš Zelina
a51ee89939 Pontoon: Update Czech (cs) localization of Test Pilot: Firefox Send
Localization authors:
- Tomáš Zelina <zelitomas@gmail.com>
2017-08-01 20:31:18 +00:00
Danny Coates
bca79489c0 added 'v' to untagged version.json 2017-08-01 13:19:43 -07:00
avelper
ddfbb06e1a Pontoon: Update Spanish (es-ES) localization of Test Pilot: Firefox Send
Localization authors:
- avelper <avelper@mozilla-hispano.org>
- Jordi Cuevas <jordicuevas@gmail.com>
2017-08-01 15:31:44 +00:00
Ton
cd2c944d41 Pontoon: Update Dutch (nl) localization of Test Pilot: Firefox Send
Localization authors:
- Ton <tonnes.mb@gmail.com>
2017-08-01 12:11:07 +00:00
Peter deHaan
5f66496519 Add ESLint no-alert rule 2017-07-31 23:59:18 -07:00
Peter deHaan
318964251d Fix some linting errors 2017-07-31 15:25:29 -07:00
Peter deHaan
5effeb16d1 Generate production locales using 'compare-locales' 2017-07-31 14:34:28 -07:00
Danny Coates
c9c7c3182c v1.0.2 2017-07-31 11:58:03 -07:00
Danny Coates
18b95c497f Merge pull request #365 from mozilla/fix-chrome-footer
revert the IE fix to fix footer on chrome
2017-07-31 11:55:35 -07:00
Roberto Alvarado
80d0f73b06 Pontoon: Update Spanish (es-MX) localization of Test Pilot: Firefox Send
Localization authors:
- Roberto Alvarado <ralv888@gmail.com>
2017-07-31 18:35:08 +00:00
Danny Coates
522290dbef revert the IE fix to fix footer on chrome 2017-07-31 11:34:48 -07:00
50 changed files with 1415 additions and 587 deletions

View File

@@ -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
View File

@@ -0,0 +1,2 @@
public/locales/* linguist-documentation
docs/* linguist-documentation

1
.gitignore vendored
View File

@@ -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

View File

@@ -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 Mozillas [l10n-drivers](https://wiki.mozilla.org/L10n:Mozilla_Team#Mozilla_Corporation) for guidance.
## Contributing

View File

@@ -31,6 +31,7 @@ deployment:
test:
override:
- npm run build:version
- npm run lint
- npm test
- nsp check

View File

@@ -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

View File

@@ -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');

View File

@@ -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();

View File

@@ -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([

View File

@@ -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);
});
}
}

View File

@@ -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) => {

View File

@@ -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;
});
});

View File

@@ -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
View File

@@ -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"

View File

@@ -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"
}
}

View 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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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. Youll 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. Youll need to update your browser.
updateFirefox = Update Firefox
downloadFirefoxButtonSub = Free Download

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -67,6 +67,7 @@ expiredPageHeader = Ce lien a expiré ou na jamais existé.
notSupportedHeader = Votre navigateur nest 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 nest-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

View File

@@ -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.

View 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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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 = Колачићи

View File

@@ -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 = Firefoxu güncelle
downloadFirefoxButtonSub = Ücretsiz indirin

View 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 = Куки

View File

@@ -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
View 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
View 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
View 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`';
}

View File

@@ -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');

View File

@@ -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) => {

View File

@@ -9,7 +9,7 @@ window.Raven = {
captureException: function(err) {
console.error(err, err.stack);
}
}
};
window.FakeFile = FakeFile;
window.FileSender = require('../../frontend/src/fileSender');

View File

@@ -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);
});
});
});

View File

@@ -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));
});
});

View File

@@ -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));
});

View File

@@ -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>

View File

@@ -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">

View File

@@ -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}}};

View File

@@ -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>

View File

@@ -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. Youll 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>