Compare commits

..

35 Commits

Author SHA1 Message Date
Danny Coates
1edc571b36 v2.5.2 2018-03-14 09:12:26 -07:00
Danny Coates
e3556aa7e1 updated cryptofill to support Android Firefox. fixes #790 2018-03-13 21:11:27 -07:00
Jobava
aa94a75da9 Pontoon: Update Romanian (ro) localization of Test Pilot: Firefox Send
Localization authors:
- Jobava <jobaval10n@gmail.com>
2018-03-13 20:51:11 +00:00
Danny Coates
ecd61830aa v2.5.1 2018-03-12 12:26:37 -07:00
Danny Coates
da82ef814b MS Edge hacks 2018-03-12 12:24:43 -07:00
Danny Coates
b840173429 Merge pull request #789 from RCMainak/issue_775
Fixed #775 : Made text not-selectable
2018-03-12 10:43:53 -07:00
rcmainak
e1dc1687fc Fixed #775 : Made text not-selectable 2018-03-12 23:09:00 +05:30
Danny Coates
3e6a88d31d render header and footer only once. fixes #788 2018-03-12 10:15:11 -07:00
Melo46
94714ecb62 Pontoon: Update Interlingua (ia) localization of Test Pilot: Firefox Send
Localization authors:
- Melo46 <melo@carmu.com>
2018-03-09 00:50:44 +00:00
Danny Coates
07a817266c v2.5.0 2018-03-08 11:31:35 -08:00
Vitaliy Krutko
706708876c Pontoon: Update Ukrainian (uk) localization of Test Pilot: Firefox Send
Localization authors:
- Vitaliy Krutko <asmforce@ukr.net>
2018-03-08 17:52:01 +00:00
Frederick Villaluna
fc4cbe4b74 Pontoon: Update Tagalog (tl) localization of Test Pilot: Firefox Send
Localization authors:
- Frederick Villaluna <fv_comscie@yahoo.com>
2018-03-08 17:51:57 +00:00
ravmn
9e8429cff3 Pontoon: Update Spanish (Chile) (es-CL) localization of Test Pilot: Firefox Send
Localization authors:
- ravmn <ravmn@ravmn.cl>
2018-03-08 17:51:54 +00:00
Gabriela
f8db7ca923 Pontoon: Update Spanish (Argentina) (es-AR) localization of Test Pilot: Firefox Send
Localization authors:
- Gabriela <gmontagu@gmail.com>
2018-03-08 17:51:51 +00:00
Rok Žerdin
70e4d9eeb0 Pontoon: Update Slovenian (sl) localization of Test Pilot: Firefox Send
Localization authors:
- Rok Žerdin <rok.zerdin1990@gmail.com>
2018-03-08 17:51:48 +00:00
Jobava
410ec72fff Pontoon: Update Romanian (ro) localization of Test Pilot: Firefox Send
Localization authors:
- Jobava <jobaval10n@gmail.com>
2018-03-08 17:51:45 +00:00
Arash Mousavi
a42a517896 Pontoon: Update Persian (fa) localization of Test Pilot: Firefox Send
Localization authors:
- Arash Mousavi <mousavi.arash@gmail.com>
2018-03-08 17:51:42 +00:00
Håvar Henriksen
d9c9d95b89 Pontoon: Update Norwegian Bokmål (nb-NO) localization of Test Pilot: Firefox Send
Localization authors:
- Håvar Henriksen <havar@firefox.no>
2018-03-08 17:51:39 +00:00
Alfredos-Panagiotis Damkalis
0ed10649ef Pontoon: Update Greek (el) localization of Test Pilot: Firefox Send
Localization authors:
- Alfredos-Panagiotis Damkalis <fredy@fredy.gr>
2018-03-08 17:51:36 +00:00
Fjoerfoks
4edf82cc21 Pontoon: Update Frisian (fy-NL) localization of Test Pilot: Firefox Send
Localization authors:
- Fjoerfoks <fryskefirefox@gmail.com>
2018-03-08 17:51:33 +00:00
Merike Sell
775726ae6d Pontoon: Update Estonian (et) localization of Test Pilot: Firefox Send
Localization authors:
- Merike Sell <merikes@gmail.com>
2018-03-08 17:51:30 +00:00
Michal Vašíček
5aeaf2e987 Pontoon: Update Czech (cs) localization of Test Pilot: Firefox Send
Localization authors:
- Michal Vašíček <michalvasicek@icloud.com>
- Michal Stanke <mstanke@mozilla.cz>
2018-03-08 17:51:27 +00:00
Emin Mastizada
773244f320 Pontoon: Update Azerbaijani (az) localization of Test Pilot: Firefox Send
Localization authors:
- Emin Mastizada <emin@mastizada.com>
2018-03-08 17:51:23 +00:00
Danny Coates
5079d9a317 Merge pull request #782 from mozilla/docs
updated docs
2018-03-07 15:20:11 -08:00
Danny Coates
18e1609cb3 updated docs 2018-03-07 15:01:08 -08:00
Danny Coates
41796840c4 Merge pull request #781 from timvisee/master
Don't translate URL-safe chars, b64 is doing it for us
2018-03-06 08:44:53 -08:00
timvisee
171b64bc98 Don't translate URL-safe chars, b64 is doing it for us 2018-03-06 14:38:29 +01:00
Danny Coates
cfc94fd9af built assets are webpack cacheable 2018-03-02 13:58:05 -08:00
Danny Coates
914394054e encapsulate translate function creation 2018-03-02 13:40:29 -08:00
Danny Coates
7a237b9b68 reduced the size of cryptofill 2018-03-02 12:21:59 -08:00
Danny Coates
80e9f129d8 ignore some lint warnings 2018-03-01 21:36:45 -08:00
Danny Coates
fddf1c40dc fixed password input style on small screens 2018-03-01 21:33:59 -08:00
Danny Coates
557db53d39 updated browserlist 2018-03-01 14:52:00 -08:00
Danny Coates
c16e00e5af Merge pull request #779 from mozilla/edgy
implemented crypto polyfills for ms edge
2018-03-01 13:21:45 -08:00
Danny Coates
cd7da20024 implemented crypto polyfills for ms edge 2018-03-01 13:10:57 -08:00
63 changed files with 994 additions and 420 deletions

View File

@@ -1,6 +1,17 @@
## Change Log ## Change Log
### upcoming (2018/02/27 01:52 +00:00) ### upcoming (2018/03/12 19:25 +00:00)
- [#789](https://github.com/mozilla/send/pull/789) Fixed #775 : Made text not-selectable (@RCMainak)
### v2.5.0 (2018/03/08 19:31 +00:00)
- [#782](https://github.com/mozilla/send/pull/782) updated docs (@dannycoates)
- [#781](https://github.com/mozilla/send/pull/781) Don't translate URL-safe chars, b64 is doing it for us (@timvisee)
- [#779](https://github.com/mozilla/send/pull/779) implemented crypto polyfills for ms edge (@dannycoates)
### v2.4.1 (2018/02/28 17:05 +00:00)
- [#777](https://github.com/mozilla/send/pull/777) use a separate circle in the progress svg for indefinite progress (@dannycoates)
### v2.4.0 (2018/02/27 01:55 +00:00)
- [#769](https://github.com/mozilla/send/pull/769) removed unsafe-inline styles via svgo-loader (@dannycoates) - [#769](https://github.com/mozilla/send/pull/769) removed unsafe-inline styles via svgo-loader (@dannycoates)
- [#767](https://github.com/mozilla/send/pull/767) added coverage artifact to circleci (@dannycoates) - [#767](https://github.com/mozilla/send/pull/767) added coverage artifact to circleci (@dannycoates)
- [#766](https://github.com/mozilla/send/pull/766) Some frontend unit tests [WIP] (@dannycoates) - [#766](https://github.com/mozilla/send/pull/766) Some frontend unit tests [WIP] (@dannycoates)

View File

@@ -3,6 +3,7 @@ Abhinav Adduri
Adnan Kičin Adnan Kičin
Alberto Castro Alberto Castro
Alexander Slovesnik Alexander Slovesnik
Alfredos-Panagiotis Damkalis
Amin Mahmudian Amin Mahmudian
Andreas Pettersson Andreas Pettersson
Arash Mousavi Arash Mousavi
@@ -33,6 +34,7 @@ Fjoerfoks
Francesco Lodolo Francesco Lodolo
Francesco Lodolo [:flod] Francesco Lodolo [:flod]
Frederick Villaluna Frederick Villaluna
Gabriela
Gautam krishna.R Gautam krishna.R
Georgianizator Georgianizator
Hyeonseok Shin Hyeonseok Shin
@@ -111,6 +113,7 @@ Tymur Faradzhev
Uccen Marzuq Uccen Marzuq
Varghese Thomas Varghese Thomas
Victor Bychek Victor Bychek
Vitaliy Krutko
Weihang Lo Weihang Lo
Wil Clouser Wil Clouser
YFdyh000 YFdyh000
@@ -137,12 +140,14 @@ kenrick95
manxmensch manxmensch
mirzet.omerovic.1992 mirzet.omerovic.1992
ravmn ravmn
rcmainak
reza.habibi2008 reza.habibi2008
savemore99.sm savemore99.sm
shikhar-scs shikhar-scs
siparon siparon
skystar-p skystar-p
tiagomoraismorgado tiagomoraismorgado
timvisee
xcffl xcffl
ybouhamam ybouhamam
Μιχάλης Μιχάλης

View File

@@ -3,7 +3,7 @@
[![CircleCI](https://img.shields.io/circleci/project/github/mozilla/send.svg)](https://circleci.com/gh/mozilla/send) [![CircleCI](https://img.shields.io/circleci/project/github/mozilla/send.svg)](https://circleci.com/gh/mozilla/send)
[![Available on Test Pilot](https://img.shields.io/badge/available_on-Test_Pilot-0996F8.svg)](https://testpilot.firefox.com/experiments/send) [![Available on Test Pilot](https://img.shields.io/badge/available_on-Test_Pilot-0996F8.svg)](https://testpilot.firefox.com/experiments/send)
**Docs:** [Docker](docs/docker.md), [Metrics](docs/metrics.md) **Docs:** [FAQ](docs/faq.md), [Encryption](docs/encryption.md), [Build](docs/build.md), [Docker](docs/docker.md), [Metrics](docs/metrics.md), [More](docs/)
--- ---
@@ -71,6 +71,8 @@ The server is configured with environment variables. See [server/config.js](serv
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. 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.
see also [docs/localization.md](docs/localization.md)
--- ---
## Contributing ## Contributing

View File

@@ -123,6 +123,7 @@ a {
cursor: pointer; cursor: pointer;
/* Force flat button look */ /* Force flat button look */
/* stylelint-disable-next-line plugin/no-unsupported-browser-features */
appearance: none; appearance: none;
font-size: 15px; font-size: 15px;
padding-bottom: 3px; padding-bottom: 3px;

View File

@@ -19,6 +19,7 @@ export default function(state, emitter) {
return; return;
} }
if (target.files.length > 1) { if (target.files.length > 1) {
// eslint-disable-next-line no-alert
return alert(state.translate('uploadPageMultipleFilesAlert')); return alert(state.translate('uploadPageMultipleFilesAlert'));
} }
const file = target.files[0]; const file = target.files[0];
@@ -26,9 +27,8 @@ export default function(state, emitter) {
return; return;
} }
if (file.size > MAXFILESIZE) { if (file.size > MAXFILESIZE) {
window.alert( // eslint-disable-next-line no-alert
state.translate('fileTooBig', { size: bytes(MAXFILESIZE) }) alert(state.translate('fileTooBig', { size: bytes(MAXFILESIZE) }));
);
return; return;
} }
emitter.emit('upload', { file, type: 'drop' }); emitter.emit('upload', { file, type: 'drop' });

View File

@@ -104,24 +104,27 @@ export default function(state, emitter) {
metrics.completedUpload(ownedFile); metrics.completedUpload(ownedFile);
state.storage.addFile(ownedFile); state.storage.addFile(ownedFile);
const cancelBtn = document.getElementById('cancel-upload');
document.getElementById('cancel-upload').hidden = 'hidden'; if (cancelBtn) {
cancelBtn.hidden = 'hidden';
}
await delay(1000); await delay(1000);
await fadeOut('.page'); await fadeOut('.page');
openLinksInNewTab(links, false);
emitter.emit('pushState', `/share/${ownedFile.id}`); emitter.emit('pushState', `/share/${ownedFile.id}`);
} catch (err) { } catch (err) {
console.error(err);
if (err.message === '0') { if (err.message === '0') {
//cancelled. do nothing //cancelled. do nothing
metrics.cancelledUpload({ size, type }); metrics.cancelledUpload({ size, type });
return render(); render();
} } else {
// eslint-disable-next-line no-console
console.error(err);
state.raven.captureException(err); state.raven.captureException(err);
metrics.stoppedUpload({ size, type, err }); metrics.stoppedUpload({ size, type, err });
emitter.emit('pushState', '/error'); emitter.emit('pushState', '/error');
}
} finally { } finally {
openLinksInNewTab(links, false);
state.uploading = false; state.uploading = false;
state.transfer = null; state.transfer = null;
} }
@@ -136,6 +139,7 @@ export default function(state, emitter) {
metrics.addedPassword({ size: file.size }); metrics.addedPassword({ size: file.size });
await delay(1000); await delay(1000);
} catch (err) { } catch (err) {
// eslint-disable-next-line no-console
console.error(err); console.error(err);
state.passwordSetError = err; state.passwordSetError = err;
} finally { } finally {
@@ -184,8 +188,9 @@ export default function(state, emitter) {
if (err.message === '0') { if (err.message === '0') {
// download cancelled // download cancelled
state.transfer.reset(); state.transfer.reset();
return render(); render();
} } else {
// eslint-disable-next-line no-console
console.error(err); console.error(err);
state.transfer = null; state.transfer = null;
const location = err.message === '404' ? '/404' : '/error'; const location = err.message === '404' ? '/404' : '/error';
@@ -194,6 +199,7 @@ export default function(state, emitter) {
metrics.stoppedDownload({ size, err }); metrics.stoppedDownload({ size, err });
} }
emitter.emit('pushState', location); emitter.emit('pushState', location);
}
} finally { } finally {
openLinksInNewTab(links, false); openLinksInNewTab(links, false);
} }

View File

@@ -78,10 +78,11 @@ export default class FileSender extends Nanobus {
this.keychain, this.keychain,
p => { p => {
this.progress = p; this.progress = p;
this.emit('progress', p); this.emit('progress');
} }
); );
this.msg = 'fileSizeProgress'; this.msg = 'fileSizeProgress';
this.emit('progress'); // HACK to kick MS Edge
try { try {
const result = await this.uploadRequest.result; const result = await this.uploadRequest.result;
const time = Date.now() - start; const time = Date.now() - start;

View File

@@ -1,10 +1,10 @@
import 'fast-text-encoding'; // MS Edge support
import 'fluent-intl-polyfill'; import 'fluent-intl-polyfill';
import app from './routes'; import app from './routes';
import locale from '../common/locales'; import locale from '../common/locales';
import fileManager from './fileManager'; import fileManager from './fileManager';
import dragManager from './dragManager'; import dragManager from './dragManager';
import { canHasSend } from './utils'; import { canHasSend } from './utils';
import assets from '../common/assets';
import storage from './storage'; import storage from './storage';
import metrics from './metrics'; import metrics from './metrics';
import experiments from './experiments'; import experiments from './experiments';
@@ -30,10 +30,7 @@ app.use((state, emitter) => {
) { ) {
unsupportedReason = 'outdated'; unsupportedReason = 'outdated';
} }
if (/edge\/\d+/i.test(navigator.userAgent)) { const ok = await canHasSend();
unsupportedReason = 'edge';
}
const ok = await canHasSend(assets.get('cryptofill.js'));
if (!ok) { if (!ok) {
unsupportedReason = /firefox/i.test(navigator.userAgent) unsupportedReason = /firefox/i.test(navigator.userAgent)
? 'outdated' ? 'outdated'

View File

@@ -73,7 +73,8 @@ module.exports = function(state, emit) {
return; return;
} }
if (file.size > MAXFILESIZE) { if (file.size > MAXFILESIZE) {
window.alert(state.translate('fileTooBig', { size: bytes(MAXFILESIZE) })); // eslint-disable-next-line no-alert
alert(state.translate('fileTooBig', { size: bytes(MAXFILESIZE) }));
return; return;
} }

9
app/readme.md Normal file
View File

@@ -0,0 +1,9 @@
# Application Code
`app/` contains the browser code that gets bundled into `app.[hash].js`. It's got all the logic, crypto, and UI. All of it gets used in the browser, and some of it by the server for server side rendering.
The main entrypoint for the browser is [main.js](./main.js) and on the server [routes/index.js](./routes/index.js) gets imported by [/server/routes/pages.js](../server/routes/pages.js)
- `pages` contains display logic an markup for pages
- `routes` contains route definitions and logic
- `templates` contains ui elements smaller than pages

View File

@@ -2,7 +2,7 @@ const html = require('choo/html');
const assets = require('../../../common/assets'); const assets = require('../../../common/assets');
module.exports = function(state) { module.exports = function(state) {
return html`<footer class="footer"> const footer = html`<footer class="footer">
<div class="legalSection"> <div class="legalSection">
<a <a
href="https://www.mozilla.org" href="https://www.mozilla.org"
@@ -61,4 +61,11 @@ module.exports = function(state) {
</a> </a>
</div> </div>
</footer>`; </footer>`;
// HACK
// We only want to render this once because we
// toggle the targets of the links with utils/openLinksInNewTab
footer.isSameNode = function(target) {
return target && target.nodeName && target.nodeName === 'FOOTER';
};
return footer;
}; };

View File

@@ -15,7 +15,8 @@ const browser = browserName();
module.exports = function(state) { module.exports = function(state) {
const feedbackUrl = `https://qsurvey.mozilla.com/s3/txp-firefox-send?ver=${version}&browser=${browser}`; const feedbackUrl = `https://qsurvey.mozilla.com/s3/txp-firefox-send?ver=${version}&browser=${browser}`;
return html`<header class="header"> const header = html`
<header class="header">
<div class="logo"> <div class="logo">
<a class="logo__link" href="/"> <a class="logo__link" href="/">
<img <img
@@ -32,7 +33,14 @@ module.exports = function(state) {
rel="noreferrer noopener" rel="noreferrer noopener"
class="feedback" class="feedback"
target="_blank">${state.translate('siteFeedback')}</a> target="_blank">${state.translate('siteFeedback')}</a>
</header>`; </header>`;
// HACK
// We only want to render this once because we
// toggle the targets of the links with utils/openLinksInNewTab
header.isSameNode = function(target) {
return target && target.nodeName && target.nodeName === 'HEADER';
};
return header;
}; };
function browserName() { function browserName() {

View File

@@ -35,8 +35,7 @@
} }
@media (max-device-width: 520px), (max-width: 520px) { @media (max-device-width: 520px), (max-width: 520px) {
.passwordInput { .passwordInput__form {
flex-direction: column; flex-direction: column;
width: inherit;
} }
} }

View File

@@ -7,6 +7,10 @@ const oDiameter = oRadius * 2;
const circumference = 2 * Math.PI * radius; const circumference = 2 * Math.PI * radius;
module.exports = function(progressRatio, indefinite = false) { module.exports = function(progressRatio, indefinite = false) {
// HACK - never indefinite for MS Edge
if (/edge/i.test(navigator.userAgent)) {
indefinite = false;
}
const p = indefinite ? 0.2 : progressRatio; const p = indefinite ? 0.2 : progressRatio;
const dashOffset = (1 - p) * circumference; const dashOffset = (1 - p) * circumference;
const progressPercent = html` const progressPercent = html`

View File

@@ -17,6 +17,7 @@
line-height: 23px; line-height: 23px;
cursor: pointer; cursor: pointer;
color: var(--lightTextColor); color: var(--lightTextColor);
user-select: none;
} }
.checkbox__label::before { .checkbox__label::before {

View File

@@ -9,10 +9,9 @@ function arrayToB64(array) {
} }
function b64ToArray(str) { function b64ToArray(str) {
str = (str + '==='.slice((str.length + 3) % 4)) return b64.toByteArray(
.replace(/-/g, '+') str + '==='.slice((str.length + 3) % 4)
.replace(/_/g, '/'); );
return b64.toByteArray(str);
} }
function loadShim(polyfill) { function loadShim(polyfill) {
@@ -25,7 +24,7 @@ function loadShim(polyfill) {
}); });
} }
async function canHasSend(polyfill) { async function canHasSend() {
try { try {
const key = await window.crypto.subtle.generateKey( const key = await window.crypto.subtle.generateKey(
{ {
@@ -35,7 +34,6 @@ async function canHasSend(polyfill) {
true, true,
['encrypt', 'decrypt'] ['encrypt', 'decrypt']
); );
await window.crypto.subtle.encrypt( await window.crypto.subtle.encrypt(
{ {
name: 'AES-GCM', name: 'AES-GCM',
@@ -45,9 +43,23 @@ async function canHasSend(polyfill) {
key, key,
new ArrayBuffer(8) new ArrayBuffer(8)
); );
await window.crypto.subtle.importKey(
'raw',
window.crypto.getRandomValues(new Uint8Array(16)),
'PBKDF2',
false,
['deriveKey']
);
await window.crypto.subtle.importKey(
'raw',
window.crypto.getRandomValues(new Uint8Array(16)),
'HKDF',
false,
['deriveKey']
);
return true; return true;
} catch (err) { } catch (err) {
return loadShim(polyfill); return false;
} }
} }
@@ -167,6 +179,7 @@ module.exports = {
copyToClipboard, copyToClipboard,
arrayToB64, arrayToB64,
b64ToArray, b64ToArray,
loadShim,
canHasSend, canHasSend,
isFile, isFile,
openLinksInNewTab openLinksInNewTab

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,5 @@
last 2 chrome versions last 2 chrome versions
last 2 firefox versions last 2 firefox versions
last 2 safari versions
last 2 edge versions
firefox esr firefox esr
safari > 9

View File

@@ -42,20 +42,22 @@ if (typeof window === 'undefined') {
require('babel-polyfill'); require('babel-polyfill');
var fluent = require('fluent/compat'); var fluent = require('fluent/compat');
} }
var fluentContext = new fluent.MessageContext('${locale}', {useIsolating: false}); (function () {
fluentContext._messages = new Map(${toJSON(merged)}); var ctx = new fluent.MessageContext('${locale}', {useIsolating: false});
function translate(id, data) { ctx._messages = new Map(${toJSON(merged)});
var msg = fluentContext.getMessage(id); function translate(id, data) {
var msg = ctx.getMessage(id);
if (typeof(msg) !== 'string' && !msg.val && msg.attrs) { if (typeof(msg) !== 'string' && !msg.val && msg.attrs) {
msg = msg.attrs.title || msg.attrs.alt msg = msg.attrs.title || msg.attrs.alt
} }
return fluentContext.format(msg, data); return ctx.format(msg, data);
} }
if (typeof window === 'undefined') { if (typeof window === 'undefined') {
module.exports = translate; module.exports = translate;
} }
else { else {
window.translate = translate; window.translate = translate;
} }
})();
\``; \``;
}; };

View File

@@ -1,3 +1,14 @@
/*
This code is included by both the server and frontend via
common/assets.js
When included from the server the export will be the function.
When included from the frontend (via webpack) the export will
be an object mapping file names to hashed file names. Example:
"send_logo.svg": "send_logo.5fcfdf0e.svg"
*/
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
@@ -14,6 +25,6 @@ module.exports = function() {
return { return {
code, code,
dependencies: files.map(f => require.resolve('../assets/' + f)), dependencies: files.map(f => require.resolve('../assets/' + f)),
cacheable: false cacheable: true
}; };
}; };

View File

@@ -1,3 +1,14 @@
/*
This code is included by both the server and frontend via
common/locales.js
When included from the server the export will be the function.
When included from the frontend (via webpack) the export will
be an object mapping ftl files to js files. Example:
"public/locales/en-US/send.ftl":"public/locales/en-US/send.6b4f8354.js"
*/
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
@@ -17,6 +28,6 @@ module.exports = function() {
dependencies: dirs.map(d => dependencies: dirs.map(d =>
require.resolve(`../public/locales/${d}/send.ftl`) require.resolve(`../public/locales/${d}/send.ftl`)
), ),
cacheable: false cacheable: true
}; };
}; };

26
build/readme.md Normal file
View File

@@ -0,0 +1,26 @@
# Custom Loaders
## Fluent Loader
The fluent loader "compiles" `.ftl` files into `.js` files directly usable by both the frontend and server for localization.
## Generate Asset Map
This loader enumerates all the files in `assets/` so that `common/assets.js` can provide mappings from the source filename to the hashed filename used on the site.
## Generate L10N Map
This loader enumerates all the ftl files in `public/locales` so that the fluent loader can create it's js files.
## Package.json Loader
This loader creates a `version.json` file that gets exposed by the `/__version__` route from the `package.json` file and current git commit hash.
## Version Loader
This loader substitutes the string "VERSION" for the version string specified in `package.json`. This is a workaround because `package.json` already uses the `package_json_loader`. See [app/templates/header/index.js](../app/templates/header/index.js) for more info.
# See Also
- [docs/build.md](../docs/build.md)
- [webpack.config.js](../webpack.config.js)

View File

@@ -4,7 +4,7 @@ const isServer = typeof gen === 'function';
const prefix = isServer ? '/' : ''; const prefix = isServer ? '/' : '';
let manifest = {}; let manifest = {};
try { try {
//eslint-disable-next-line node/no-missing-require // eslint-disable-next-line node/no-missing-require
manifest = require('../dist/manifest.json'); manifest = require('../dist/manifest.json');
} catch (e) { } catch (e) {
// use middleware // use middleware
@@ -17,6 +17,7 @@ function getLocale(name) {
} }
function serverTranslator(name) { function serverTranslator(name) {
// eslint-disable-next-line security/detect-non-literal-require
return require(`../dist/${locales[`public/locales/${name}/send.ftl`]}`); return require(`../dist/${locales[`public/locales/${name}/send.ftl`]}`);
} }

3
common/readme.md Normal file
View File

@@ -0,0 +1,3 @@
# Common Code
This directory contains code loaded by both the frontend `app` and backend `server`. The code here can be challenging to understand at first because the contexts for the two (three counting the dev server) environments that include them are quite different, but the purpose of these modules are quite simple, to provide mappings from the source assets (`copy-16.png`) to the concrete production assets (`copy-16.db66e0bf.svg`), similarly for localizations.

22
docs/build.md Normal file
View File

@@ -0,0 +1,22 @@
Send has two build configurations, development and production. Both can be run via `npm` scripts, `npm start` for development and `npm run build` for production. Webpack is our only build tool and all configuration lives in [webpack.config.js](../webpack.config.js).
# Development
`npm start` launches a `webpack-dev-server` on port 8080 that compiles the assets and watches files for changes. It also serves the backend API and frontend unit tests via the `server/dev.js` entrypoint. The frontend tests can be run in the browser by navigating to http://localhost:8080/test and will rerun automatically as the watched files are saved with changes.
# Production
`npm run build` compiles the assets and writes the files to the `dist/` directory. `npm run prod` launches an Express server on port 1443 that serves the backend API and frontend static assets from `dist/` via the `server/prod.js` entrypoint.
# Notable differences
- Development compiles assets in memory, so no `dist/` directory is generated
- Development does not enable CSP headers
- Development frontend source is instrumented for code coverage
- Only development includes sourcemaps
- Only development exposes the `/test` route
- Production sets Cache-Control immutable headers on the hashed static assets
# Custom Loaders
The `build/` directory contains custom webpack loaders specific to Send. See [build/readme.md](../build/readme.md) for details on each loader.

46
docs/encryption.md Normal file
View File

@@ -0,0 +1,46 @@
# File Encryption
Send use 128-bit AES-GCM encryption via the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) to encrypt files in the browser before uploading them to the server. The code is in [app/keychain.js](../app/keychain.js).
## Steps
### Uploading
1. A new secret key is generated with `crypto.getRandomValues`
2. The secret key is used to derive 3 more keys via HKDF SHA-256
- an encryption key for the file (AES-GCM)
- an encryption key for the file metadata (AES-GCM)
- a signing key for request authentication (HMAC SHA-256)
3. The file and metadata are encrypted with their corresponding keys
4. The encrypted data and signing key are uploaded to the server
5. An owner token and the share url are returned by the server and stored in local storage
6. The secret key is appended to the share url as a [#fragment](https://en.wikipedia.org/wiki/Fragment_identifier) and presented to the UI
### Downloading
1. The browser loads the share url page, which includes an authentication nonce
2. The browser imports the secret key from the url fragment
3. The same 3 keys as above are derived
4. The browser signs the nonce with it's signing key and requests the metadata
5. The encrypted metadata is decrypted and presented on the page
6. The browser makes another authenticated request to download the encrypted file
7. The browser downloads and decrypts the file
8. The file prompts the save dialog or automatically saves depending on the browser settings
### Passwords
A password may optionally be set to authenticate the download request. When a password is set the following steps occur.
#### Sender
1. The original signing key derived from the secret key is discarded
2. A new signing key is generated via PBKDF2 from the user entered password and the full share url (including secret key fragment)
3. The new key is sent to the server, authenticated by the owner token
4. The server stores the new key and marks the record as needing a password
#### Downloader
1. The browser loads the share url page, which includes an authentication nonce and indicator that the file requires a password
2. The user is prompted for the password and the signing key is derived
3. The browser requests the metadata using the key to sign the nonce
4. If the password was correct the metadata is returned, otherwise a 401

84
docs/experiments.md Normal file
View File

@@ -0,0 +1,84 @@
# A/B experiment testing
We're using Google Analytics Experiments for A/B testing.
## Creating an experiment
Navigate to the Behavior > Experiments section of Google Analytics and click the "Create experiment" button.
The "Objective for this experiment" is the most complicated part. See the "Promo click (Goal ID 4 / Goal Set 1)" for an example.
In step 2 add as many variants as you plan to test. The urls are not important since we aren't using their js library to choose the variants. The name will show up in the report so choose good ones. "Original page" becomes variant 0 and each variant increments by one. We'll use the numbers in our `app/experiments.js` code.
Step 3 contains some script that we'll ignore. The important thing here is the **Experiment ID**. This is the value we need to name our experiment in `app/experiments.js`. Save the changes so far and wait until the code containing the experiment has been deployed to production **before** starting the experiment.
## Experiment code
Code for experiments live in [app/experiments.js](../app/experiments.js). There's an `experiments` object that contains the logic for deciding whether an experiment should run, which variant to use, and what to do. Each object needs to have these functions:
### `eligible` function
This function returns a boolean of whether this experiment should be active for this session. Any data available to the page can be used determine the result.
### `variant` function
This function returns which experimental group this session is placed in. The variant values need to match the values set up in Google Analytics, usually 0 thru N-1. This value is usually picked at random based on what percentage of each variant is desired.
### `run` function
This function gets the `variant` value chosen by the variant function and the `state` and `emitter` objects from the app. This function can do anything needed to change the app based on the experiment. A common pattern is to set or change a value on `state` that will be picked up by other parts of the app, like ui templates, to change how it looks or behaves.
### Example
Here's a full example of the experiment object:
```js
const experiments = {
S9wqVl2SQ4ab2yZtqDI3Dw: { // The Experiment ID from Google Analytics
id: 'S9wqVl2SQ4ab2yZtqDI3Dw',
run: function(variant, state, emitter) {
switch (variant) {
case 1:
state.promo = 'blue';
break;
case 2:
state.promo = 'pink';
break;
default:
state.promo = 'grey';
}
emitter.emit('render');
},
eligible: function() {
return (
!/firefox|fxios/i.test(navigator.userAgent) &&
document.querySelector('html').lang === 'en-US'
);
},
variant: function(state) {
const n = this.luckyNumber(state);
if (n < 0.33) {
return 0;
}
return n < 0.66 ? 1 : 2;
},
luckyNumber: function(state) {
return luckyNumber(
`${this.id}:${state.storage.get('testpilot_ga__cid')}`
);
}
}
};
```
## Reporting results
All metrics pings will include the variant and experiment id, but it's usually important to trigger a specific event to be counted as the experiment goal (the "Objective for this experiment" part from setup). Use an 'experiment' event to do this. For example:
```js
emit('experiment', { cd3: 'promo' });
```
where `emit` is the app emitter function passed to the [route handler](https://github.com/choojs/choo#approuteroutename-handlerstate-emit)
The second argument can be an object with any additional parameters. It usually includes a custom dimension that we chose to filter on while creating the experiment in Google Analytics.

29
docs/localization.md Normal file
View File

@@ -0,0 +1,29 @@
# Localization
Send is localized in over 50 languages. We use the [fluent](http://projectfluent.org/) library and store our translations in [FTL](http://projectfluent.org/fluent/guide/) files in `public/locales/`. `en-US` is our base language, and other languages are managed by [pontoon](https://pontoon.mozilla.org/projects/test-pilot-firefox-send/).
## Process
Strings are added or removed from [public/locales/en-US/send.ftl] as needed. Strings **MUST NOT** be *changed* after they've been commited and pushed to master. Changing a string requires creating a new ID with a new name (preferably descriptive instead of incremented) and deletion of the obsolete ID. It's often useful to add a comment above the string with info about how and where the string is used.
Once new strings are commited to master they are available for translators in Pontoon. All languages other than `en-US` should be edited via Pontoon. Translations get automatically commited to the github master branch.
### Activation
The development environment includes all locales in `public/locales` via the `L10N_DEV` environment variable. Production uses `package.json` as the list of locales to use. Once a locale has enough string coverage it should be added to `package.json`.
## Code
In `app/` we use the `state.translate()` function to translate strings to the best matching language base on the user's `Accept-Language` header. It's a wrapper around fluent's [MessageContext.format](http://projectfluent.org/fluent.js/fluent/MessageContext.html). It works the same for both server and client side rendering.
### Examples
```js
// simple string
const finishedString = state.translate('downloadFinish')
// with parameters
const progressString = state.translate('downloadingPageProgress', {
filename: state.fileInfo.name,
size: bytes(state.fileInfo.size)
})
```

324
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{ {
"name": "firefox-send", "name": "firefox-send",
"version": "2.4.1", "version": "2.5.2",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@@ -417,6 +417,12 @@
"integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
"dev": true "dev": true
}, },
"asmcrypto.js": {
"version": "0.22.0",
"resolved": "https://registry.npmjs.org/asmcrypto.js/-/asmcrypto.js-0.22.0.tgz",
"integrity": "sha512-usgMoyXjMbx/ZPdzTSXExhMPur2FTdz/Vo5PVx2gIaBcdAAJNOFlsdgqveM8Cff7W0v+xrf9BwjOV26JSAF9qA==",
"dev": true
},
"asn1": { "asn1": {
"version": "0.1.11", "version": "0.1.11",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz",
@@ -521,9 +527,9 @@
} }
}, },
"aws-sdk": { "aws-sdk": {
"version": "2.202.0", "version": "2.206.0",
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.202.0.tgz", "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.206.0.tgz",
"integrity": "sha1-wb2QwdwL/oNVIv6B8pz4u3G/AMw=", "integrity": "sha1-I1yhCVdsiI8kZ9HBDDOvfjQtO+E=",
"requires": { "requires": {
"buffer": "4.9.1", "buffer": "4.9.1",
"events": "1.1.1", "events": "1.1.1",
@@ -769,9 +775,9 @@
} }
}, },
"babel-loader": { "babel-loader": {
"version": "7.1.3", "version": "7.1.4",
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-7.1.3.tgz", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-7.1.4.tgz",
"integrity": "sha512-PeN29YvOynPMvNk7QCzsHqxpmfXwKAC+uxkiSNFQsmXBBVltzEkVWmv/Ip3tx7yk149dQUwk497bTXNu+DZjLA==", "integrity": "sha512-/hbyEvPzBJuGpk9o80R0ZyTej6heEOr59GoEUtn8qFKbnx4cJm9FWES6J/iv644sYgrtVw9JJQkjaLW/bqb5gw==",
"dev": true, "dev": true,
"requires": { "requires": {
"find-cache-dir": "1.0.0", "find-cache-dir": "1.0.0",
@@ -1442,9 +1448,9 @@
} }
}, },
"bel": { "bel": {
"version": "5.1.6", "version": "5.1.7",
"resolved": "https://registry.npmjs.org/bel/-/bel-5.1.6.tgz", "resolved": "https://registry.npmjs.org/bel/-/bel-5.1.7.tgz",
"integrity": "sha512-qEjYYQgbMFbBwtrt+gVBk+IzdBNqyCgWjm7jtBqptcFlwaXRG/HgyHuzUucReYy155TB9UvIeF4P6/J2GpX80A==", "integrity": "sha512-f3aAzoq2ilK3ErDsv47uo2qK9NTKHkguI7j6sJi6ynKS9vPG180QGU8BzHas6xPnIsKj+m7YXlDSm9BmaZHNrg==",
"requires": { "requires": {
"hyperx": "2.3.3", "hyperx": "2.3.3",
"is-electron": "2.1.0", "is-electron": "2.1.0",
@@ -1617,9 +1623,9 @@
} }
}, },
"browser-stdout": { "browser-stdout": {
"version": "1.3.0", "version": "1.3.1",
"resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
"integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
"dev": true "dev": true
}, },
"browserify-aes": { "browserify-aes": {
@@ -2002,11 +2008,11 @@
} }
}, },
"choo": { "choo": {
"version": "6.8.0", "version": "6.10.0",
"resolved": "https://registry.npmjs.org/choo/-/choo-6.8.0.tgz", "resolved": "https://registry.npmjs.org/choo/-/choo-6.10.0.tgz",
"integrity": "sha512-yQkUqeqNtHdSeRik4yjPYIC0JRghdvG0AXxGGkqEgLqqOTCVVK8Fnu/x5FKOQ+CEGfodxIrWLIEHpx1AotmCGg==", "integrity": "sha512-5dSzBXh1PeyzKgzTTVMiIyO+2J/THwft/O65WDBnmMwwM2AveM2iDrHMcdzMm1Pr4U+44+hqAprBJbPigPYy5Q==",
"requires": { "requires": {
"bel": "5.1.6", "bel": "5.1.7",
"document-ready": "2.0.1", "document-ready": "2.0.1",
"nanobus": "4.3.3", "nanobus": "4.3.3",
"nanohref": "3.0.1", "nanohref": "3.0.1",
@@ -2601,33 +2607,19 @@
"dev": true "dev": true
}, },
"copy-webpack-plugin": { "copy-webpack-plugin": {
"version": "4.4.2", "version": "4.5.0",
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.4.2.tgz", "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.5.0.tgz",
"integrity": "sha512-tf1XKKQ5h+BPvXJ5/zx2xKVdF0/6J8XNvhB6fdmIReMnAfQGMbzph8F7ok2QF9kqWMfIgkCxwzk1zXkYqcLIqg==", "integrity": "sha512-ROQ85fWKuhJfUkBTdHvfV+Zv6Ltm3G/vPVFdLPFwzWzd9RUY1yLw3rt6FmKK2PaeNQCNvmwgFhuarkjuV4PVDQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"cacache": "10.0.4", "cacache": "10.0.4",
"find-cache-dir": "1.0.0", "find-cache-dir": "1.0.0",
"globby": "7.1.1", "globby": "7.1.1",
"is-glob": "4.0.0", "is-glob": "4.0.0",
"loader-utils": "0.2.17", "loader-utils": "1.1.0",
"minimatch": "3.0.4", "minimatch": "3.0.4",
"p-limit": "1.2.0", "p-limit": "1.2.0",
"serialize-javascript": "1.4.0" "serialize-javascript": "1.4.0"
},
"dependencies": {
"loader-utils": {
"version": "0.2.17",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz",
"integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=",
"dev": true,
"requires": {
"big.js": "3.2.0",
"emojis-list": "2.1.0",
"json5": "0.5.1",
"object-assign": "4.1.1"
}
}
} }
}, },
"core-js": { "core-js": {
@@ -3658,21 +3650,21 @@
} }
}, },
"duplexify": { "duplexify": {
"version": "3.5.3", "version": "3.5.4",
"resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.3.tgz", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.4.tgz",
"integrity": "sha512-g8ID9OroF9hKt2POf8YLayy+9594PzmM3scI00/uBXocX3TWNgoB67hjzkFe9ITAbQOne/lLdBxHXvYUM4ZgGA==", "integrity": "sha512-JzYSLYMhoVVBe8+mbHQ4KgpvHpm0DZpJuL8PY93Vyv1fW7jYJ90LoXa1di/CVbJM+TgMs91rbDapE/RNIfnJsA==",
"dev": true, "dev": true,
"requires": { "requires": {
"end-of-stream": "1.4.1", "end-of-stream": "1.4.1",
"inherits": "2.0.3", "inherits": "2.0.3",
"readable-stream": "2.3.4", "readable-stream": "2.3.5",
"stream-shift": "1.0.0" "stream-shift": "1.0.0"
}, },
"dependencies": { "dependencies": {
"readable-stream": { "readable-stream": {
"version": "2.3.4", "version": "2.3.5",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.4.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.5.tgz",
"integrity": "sha512-vuYxeWYM+fde14+rajzqgeohAI7YoJcHE7kXDAc4Nk0EbuKnJfqtY9YtRkLo/tqkuF7MsBQRhPnPeyjYITp3ZQ==", "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==",
"dev": true, "dev": true,
"requires": { "requires": {
"core-util-is": "1.0.2", "core-util-is": "1.0.2",
@@ -3956,21 +3948,21 @@
} }
}, },
"eslint": { "eslint": {
"version": "4.18.1", "version": "4.18.2",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-4.18.1.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.18.2.tgz",
"integrity": "sha512-gPSfpSRCHre1GLxGmO68tZNxOlL2y7xBd95VcLD+Eo4S2js31YoMum3CAQIOaxY24hqYOMksMvW38xuuWKQTgw==", "integrity": "sha512-qy4i3wODqKMYfz9LUI8N2qYDkHkoieTbiHpMrYUI/WbjhXJQr7lI4VngixTgaG+yHX+NBCv7nW4hA0ShbvaNKw==",
"dev": true, "dev": true,
"requires": { "requires": {
"ajv": "5.5.2", "ajv": "5.5.2",
"babel-code-frame": "6.26.0", "babel-code-frame": "6.26.0",
"chalk": "2.3.1", "chalk": "2.3.2",
"concat-stream": "1.6.0", "concat-stream": "1.6.0",
"cross-spawn": "5.1.0", "cross-spawn": "5.1.0",
"debug": "3.1.0", "debug": "3.1.0",
"doctrine": "2.1.0", "doctrine": "2.1.0",
"eslint-scope": "3.7.1", "eslint-scope": "3.7.1",
"eslint-visitor-keys": "1.0.0", "eslint-visitor-keys": "1.0.0",
"espree": "3.5.3", "espree": "3.5.4",
"esquery": "1.0.0", "esquery": "1.0.0",
"esutils": "2.0.2", "esutils": "2.0.2",
"file-entry-cache": "2.0.0", "file-entry-cache": "2.0.0",
@@ -3981,7 +3973,7 @@
"imurmurhash": "0.1.4", "imurmurhash": "0.1.4",
"inquirer": "3.3.0", "inquirer": "3.3.0",
"is-resolvable": "1.1.0", "is-resolvable": "1.1.0",
"js-yaml": "3.10.0", "js-yaml": "3.11.0",
"json-stable-stringify-without-jsonify": "1.0.1", "json-stable-stringify-without-jsonify": "1.0.1",
"levn": "0.3.0", "levn": "0.3.0",
"lodash": "4.17.5", "lodash": "4.17.5",
@@ -3996,10 +3988,16 @@
"semver": "5.5.0", "semver": "5.5.0",
"strip-ansi": "4.0.0", "strip-ansi": "4.0.0",
"strip-json-comments": "2.0.1", "strip-json-comments": "2.0.1",
"table": "4.0.3", "table": "4.0.2",
"text-table": "0.2.0" "text-table": "0.2.0"
}, },
"dependencies": { "dependencies": {
"ajv-keywords": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz",
"integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=",
"dev": true
},
"ansi-regex": { "ansi-regex": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
@@ -4007,23 +4005,23 @@
"dev": true "dev": true
}, },
"ansi-styles": { "ansi-styles": {
"version": "3.2.0", "version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true, "dev": true,
"requires": { "requires": {
"color-convert": "1.9.1" "color-convert": "1.9.1"
} }
}, },
"chalk": { "chalk": {
"version": "2.3.1", "version": "2.3.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz",
"integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"ansi-styles": "3.2.0", "ansi-styles": "3.2.1",
"escape-string-regexp": "1.0.5", "escape-string-regexp": "1.0.5",
"supports-color": "5.2.0" "supports-color": "5.3.0"
} }
}, },
"debug": { "debug": {
@@ -4054,9 +4052,9 @@
"dev": true "dev": true
}, },
"js-yaml": { "js-yaml": {
"version": "3.10.0", "version": "3.11.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.11.0.tgz",
"integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", "integrity": "sha512-saJstZWv7oNeOyBh3+Dx1qWzhW0+e6/8eDzo7p5rDFqxntSztloLtuKu+Ejhtq82jsilwOIZYsCz+lIjthg1Hw==",
"dev": true, "dev": true,
"requires": { "requires": {
"argparse": "1.0.10", "argparse": "1.0.10",
@@ -4073,23 +4071,37 @@
} }
}, },
"supports-color": { "supports-color": {
"version": "5.2.0", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz",
"integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==", "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==",
"dev": true, "dev": true,
"requires": { "requires": {
"has-flag": "3.0.0" "has-flag": "3.0.0"
} }
},
"table": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz",
"integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==",
"dev": true,
"requires": {
"ajv": "5.5.2",
"ajv-keywords": "2.1.1",
"chalk": "2.3.2",
"lodash": "4.17.5",
"slice-ansi": "1.0.0",
"string-width": "2.1.1"
}
} }
} }
}, },
"eslint-plugin-mocha": { "eslint-plugin-mocha": {
"version": "4.11.0", "version": "4.12.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-4.11.0.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-4.12.1.tgz",
"integrity": "sha1-kRk6L1XiCl41l0BUoAidMBmO5Xg=", "integrity": "sha512-hxWtYHvLA0p/PKymRfDYh9Mxt5dYkg2Goy1vZDarTEEYfELP9ksga7kKG1NUKSQy27C8Qjc7YrSWTLUhOEOksA==",
"dev": true, "dev": true,
"requires": { "requires": {
"ramda": "0.24.1" "ramda": "0.25.0"
} }
}, },
"eslint-plugin-node": { "eslint-plugin-node": {
@@ -4130,13 +4142,21 @@
"dev": true "dev": true
}, },
"espree": { "espree": {
"version": "3.5.3", "version": "3.5.4",
"resolved": "https://registry.npmjs.org/espree/-/espree-3.5.3.tgz", "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz",
"integrity": "sha512-Zy3tAJDORxQZLl2baguiRU1syPERAIg0L+JB2MWorORgTu/CplzvxS9WWA7Xh4+Q+eOQihNs/1o1Xep8cvCxWQ==", "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==",
"dev": true, "dev": true,
"requires": { "requires": {
"acorn": "5.4.1", "acorn": "5.5.3",
"acorn-jsx": "3.0.1" "acorn-jsx": "3.0.1"
},
"dependencies": {
"acorn": {
"version": "5.5.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.5.3.tgz",
"integrity": "sha512-jd5MkIUlbbmb07nXH0DT3y7rDVtkzDi4XZOUVWAer8ajmF/DTSSbl5oNFyDOl/OXA33Bl79+ypHhl2pN20VeOQ==",
"dev": true
}
} }
}, },
"esprima": { "esprima": {
@@ -4501,6 +4521,12 @@
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
"dev": true "dev": true
}, },
"fast-text-encoding": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.0.tgz",
"integrity": "sha512-R9bHCvweUxxwkDwhjav5vxpFvdPGlVngtqmx4pIZfSUhM/Q4NiIUHB456BAf+Q1Nwu3HEZYONtu+Rya+af4jiQ==",
"dev": true
},
"fastparse": { "fastparse": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz", "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz",
@@ -4545,9 +4571,9 @@
} }
}, },
"file-loader": { "file-loader": {
"version": "1.1.9", "version": "1.1.11",
"resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.9.tgz", "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz",
"integrity": "sha512-6ql03hOSoJHBkTB+3De/f7NJse+JXkUwvAf3y4Q5rIcTD0kqJiE3btvLnDcZT+P4t1QYLb9dJ9EI4auzfo3wFA==", "integrity": "sha512-TGR4HU7HUsGg6GCOPJnFk06RhWgEWFLAGWiT6rcD+GRC2keU3s9RGJ+b3Z6/U73jwwNb2gKLJ7YCrp+jvU4ALg==",
"dev": true, "dev": true,
"requires": { "requires": {
"loader-utils": "1.1.0", "loader-utils": "1.1.0",
@@ -4555,9 +4581,9 @@
}, },
"dependencies": { "dependencies": {
"ajv": { "ajv": {
"version": "6.1.1", "version": "6.2.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.1.1.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.2.1.tgz",
"integrity": "sha1-l41Zf7wrfQ5aXD3esUmmgvKr+g4=", "integrity": "sha1-KKarxJOiq+D7TIUHrK7bQ/pVBnE=",
"dev": true, "dev": true,
"requires": { "requires": {
"fast-deep-equal": "1.0.0", "fast-deep-equal": "1.0.0",
@@ -4571,7 +4597,7 @@
"integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==", "integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==",
"dev": true, "dev": true,
"requires": { "requires": {
"ajv": "6.1.1", "ajv": "6.2.1",
"ajv-keywords": "3.1.0" "ajv-keywords": "3.1.0"
} }
} }
@@ -4705,13 +4731,13 @@
"dev": true, "dev": true,
"requires": { "requires": {
"inherits": "2.0.3", "inherits": "2.0.3",
"readable-stream": "2.3.4" "readable-stream": "2.3.5"
}, },
"dependencies": { "dependencies": {
"readable-stream": { "readable-stream": {
"version": "2.3.4", "version": "2.3.5",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.4.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.5.tgz",
"integrity": "sha512-vuYxeWYM+fde14+rajzqgeohAI7YoJcHE7kXDAc4Nk0EbuKnJfqtY9YtRkLo/tqkuF7MsBQRhPnPeyjYITp3ZQ==", "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==",
"dev": true, "dev": true,
"requires": { "requires": {
"core-util-is": "1.0.2", "core-util-is": "1.0.2",
@@ -4823,13 +4849,13 @@
"dev": true, "dev": true,
"requires": { "requires": {
"inherits": "2.0.3", "inherits": "2.0.3",
"readable-stream": "2.3.4" "readable-stream": "2.3.5"
}, },
"dependencies": { "dependencies": {
"readable-stream": { "readable-stream": {
"version": "2.3.4", "version": "2.3.5",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.4.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.5.tgz",
"integrity": "sha512-vuYxeWYM+fde14+rajzqgeohAI7YoJcHE7kXDAc4Nk0EbuKnJfqtY9YtRkLo/tqkuF7MsBQRhPnPeyjYITp3ZQ==", "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==",
"dev": true, "dev": true,
"requires": { "requires": {
"core-util-is": "1.0.2", "core-util-is": "1.0.2",
@@ -6209,9 +6235,9 @@
"dev": true "dev": true
}, },
"helmet": { "helmet": {
"version": "3.11.0", "version": "3.12.0",
"resolved": "https://registry.npmjs.org/helmet/-/helmet-3.11.0.tgz", "resolved": "https://registry.npmjs.org/helmet/-/helmet-3.12.0.tgz",
"integrity": "sha512-Xqf6VXmjpZoyH4reGyeBCO5nHH0NVeRQnx23LFj6AK9ocPRgZJfSH6zZ8SvNO2tB+fKhsqy1RSjIjWHVvH1X+w==", "integrity": "sha512-CgkctpvreQLL6X3EL2Igs/92+75ZFIsrob9/Rdwf2hQCBGH/DxLk4xFPxAAl6jYnnus/YXfFEVXHEJf8TJTwlA==",
"requires": { "requires": {
"dns-prefetch-control": "0.1.0", "dns-prefetch-control": "0.1.0",
"dont-sniff-mimetype": "1.0.0", "dont-sniff-mimetype": "1.0.0",
@@ -6224,7 +6250,7 @@
"ienoopen": "1.0.0", "ienoopen": "1.0.0",
"nocache": "2.0.0", "nocache": "2.0.0",
"referrer-policy": "1.1.0", "referrer-policy": "1.1.0",
"x-xss-protection": "1.0.0" "x-xss-protection": "1.1.0"
} }
}, },
"helmet-csp": { "helmet-csp": {
@@ -9647,7 +9673,7 @@
"dev": true, "dev": true,
"requires": { "requires": {
"concat-stream": "1.6.0", "concat-stream": "1.6.0",
"duplexify": "3.5.3", "duplexify": "3.5.4",
"end-of-stream": "1.4.1", "end-of-stream": "1.4.1",
"flush-write-stream": "1.0.2", "flush-write-stream": "1.0.2",
"from2": "2.3.0", "from2": "2.3.0",
@@ -9688,15 +9714,15 @@
} }
}, },
"mocha": { "mocha": {
"version": "5.0.1", "version": "5.0.4",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-5.0.1.tgz", "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.0.4.tgz",
"integrity": "sha512-SpwyojlnE/WRBNGtvJSNfllfm5PqEDFxcWluSIgLeSBJtXG4DmoX2NNAeEA7rP5kK+79VgtVq8nG6HskaL1ykg==", "integrity": "sha512-nMOpAPFosU1B4Ix1jdhx5e3q7XO55ic5a8cgYvW27CequcEY+BabS0kUVL1Cw1V5PuVHZWeNRWFLmEPexo79VA==",
"dev": true, "dev": true,
"requires": { "requires": {
"browser-stdout": "1.3.0", "browser-stdout": "1.3.1",
"commander": "2.11.0", "commander": "2.11.0",
"debug": "3.1.0", "debug": "3.1.0",
"diff": "3.3.1", "diff": "3.5.0",
"escape-string-regexp": "1.0.5", "escape-string-regexp": "1.0.5",
"glob": "7.1.2", "glob": "7.1.2",
"growl": "1.10.3", "growl": "1.10.3",
@@ -9720,6 +9746,12 @@
"ms": "2.0.0" "ms": "2.0.0"
} }
}, },
"diff": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
"dev": true
},
"has-flag": { "has-flag": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
@@ -12305,13 +12337,13 @@
"requires": { "requires": {
"cyclist": "0.2.2", "cyclist": "0.2.2",
"inherits": "2.0.3", "inherits": "2.0.3",
"readable-stream": "2.3.4" "readable-stream": "2.3.5"
}, },
"dependencies": { "dependencies": {
"readable-stream": { "readable-stream": {
"version": "2.3.4", "version": "2.3.5",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.4.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.5.tgz",
"integrity": "sha512-vuYxeWYM+fde14+rajzqgeohAI7YoJcHE7kXDAc4Nk0EbuKnJfqtY9YtRkLo/tqkuF7MsBQRhPnPeyjYITp3ZQ==", "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==",
"dev": true, "dev": true,
"requires": { "requires": {
"core-util-is": "1.0.2", "core-util-is": "1.0.2",
@@ -14389,21 +14421,21 @@
} }
}, },
"postcss-loader": { "postcss-loader": {
"version": "2.1.0", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-2.1.0.tgz", "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-2.1.1.tgz",
"integrity": "sha512-S/dKzpDwGFmP9g8eyCu9sUIV+/+3UooeTpYlsKf23qKDdrhHuA4pTSfytVu0rEJ0iDqUavXrgtOPq5KhNyNMOw==", "integrity": "sha512-f0J/DWE/hyO9/LH0WHpXkny/ZZ238sSaG3p1SRBtVZnFWUtD7GXIEgHoBg8cnAeRbmEvUxHQptY46zWfwNYj/w==",
"dev": true, "dev": true,
"requires": { "requires": {
"loader-utils": "1.1.0", "loader-utils": "1.1.0",
"postcss": "6.0.18", "postcss": "6.0.19",
"postcss-load-config": "1.2.0", "postcss-load-config": "1.2.0",
"schema-utils": "0.4.5" "schema-utils": "0.4.5"
}, },
"dependencies": { "dependencies": {
"ajv": { "ajv": {
"version": "6.1.1", "version": "6.2.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.1.1.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.2.1.tgz",
"integrity": "sha1-l41Zf7wrfQ5aXD3esUmmgvKr+g4=", "integrity": "sha1-KKarxJOiq+D7TIUHrK7bQ/pVBnE=",
"dev": true, "dev": true,
"requires": { "requires": {
"fast-deep-equal": "1.0.0", "fast-deep-equal": "1.0.0",
@@ -14411,30 +14443,24 @@
"json-schema-traverse": "0.3.1" "json-schema-traverse": "0.3.1"
} }
}, },
"ajv-keywords": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.1.0.tgz",
"integrity": "sha1-rCsnk5xUPpXSwG5/f1wnvkqlQ74=",
"dev": true
},
"ansi-styles": { "ansi-styles": {
"version": "3.2.0", "version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true, "dev": true,
"requires": { "requires": {
"color-convert": "1.9.1" "color-convert": "1.9.1"
} }
}, },
"chalk": { "chalk": {
"version": "2.3.1", "version": "2.3.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz",
"integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"ansi-styles": "3.2.0", "ansi-styles": "3.2.1",
"escape-string-regexp": "1.0.5", "escape-string-regexp": "1.0.5",
"supports-color": "5.2.0" "supports-color": "5.3.0"
} }
}, },
"has-flag": { "has-flag": {
@@ -14444,14 +14470,14 @@
"dev": true "dev": true
}, },
"postcss": { "postcss": {
"version": "6.0.18", "version": "6.0.19",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.18.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.19.tgz",
"integrity": "sha512-X8MyLi3OYI1o71u0SsefWLpGBo5xnGiK1Pn+nrZFplc671Ts7L8aPwEbPIO8AWpulK5wuaVzyM9Rw6R8o7hYBw==", "integrity": "sha512-f13HRz0HtVwVaEuW6J6cOUCBLFtymhgyLPV7t4QEk2UD3twRI9IluDcQNdzQdBpiixkXj2OmzejhhTbSbDxNTg==",
"dev": true, "dev": true,
"requires": { "requires": {
"chalk": "2.3.1", "chalk": "2.3.2",
"source-map": "0.6.1", "source-map": "0.6.1",
"supports-color": "5.2.0" "supports-color": "5.3.0"
} }
}, },
"schema-utils": { "schema-utils": {
@@ -14460,7 +14486,7 @@
"integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==", "integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==",
"dev": true, "dev": true,
"requires": { "requires": {
"ajv": "6.1.1", "ajv": "6.2.1",
"ajv-keywords": "3.1.0" "ajv-keywords": "3.1.0"
} }
}, },
@@ -14471,9 +14497,9 @@
"dev": true "dev": true
}, },
"supports-color": { "supports-color": {
"version": "5.2.0", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz",
"integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==", "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==",
"dev": true, "dev": true,
"requires": { "requires": {
"has-flag": "3.0.0" "has-flag": "3.0.0"
@@ -15723,9 +15749,9 @@
"dev": true "dev": true
}, },
"prettier": { "prettier": {
"version": "1.10.2", "version": "1.11.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.10.2.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.11.1.tgz",
"integrity": "sha512-TcdNoQIWFoHblurqqU6d1ysopjq7UX0oRcT/hJ8qvBAELiYWn+Ugf0AXdnzISEJ7vuhNnQ98N8jR8Sh53x4IZg==", "integrity": "sha512-T/KD65Ot0PB97xTrG8afQ46x3oiVhnfGjGESSI9NWYcG92+OUPZKkwHqGWXH2t9jK1crnQjubECW0FuOth+hxw==",
"dev": true "dev": true
}, },
"pretty-format": { "pretty-format": {
@@ -15869,7 +15895,7 @@
"integrity": "sha512-2kmNR9ry+Pf45opRVirpNuIFotsxUGLaYqxIwuR77AYrYRMuFCz9eryHBS52L360O+NcR383CL4QYlMKPq4zYA==", "integrity": "sha512-2kmNR9ry+Pf45opRVirpNuIFotsxUGLaYqxIwuR77AYrYRMuFCz9eryHBS52L360O+NcR383CL4QYlMKPq4zYA==",
"dev": true, "dev": true,
"requires": { "requires": {
"duplexify": "3.5.3", "duplexify": "3.5.4",
"inherits": "2.0.3", "inherits": "2.0.3",
"pump": "2.0.1" "pump": "2.0.1"
} }
@@ -15940,9 +15966,9 @@
"dev": true "dev": true
}, },
"ramda": { "ramda": {
"version": "0.24.1", "version": "0.25.0",
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.24.1.tgz", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.25.0.tgz",
"integrity": "sha1-w7d1UZfzW43DUCIoJixMkd22uFc=", "integrity": "sha512-GXpfrYVPwx3K7RQ6aYT8KPS8XViSXUVJT1ONhoKPE9VAleW42YE+U+8VEyGWt41EnEQW7gwecYJriTI0pKoecQ==",
"dev": true "dev": true
}, },
"randomatic": { "randomatic": {
@@ -16011,9 +16037,9 @@
"integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
}, },
"raven": { "raven": {
"version": "2.4.1", "version": "2.4.2",
"resolved": "https://registry.npmjs.org/raven/-/raven-2.4.1.tgz", "resolved": "https://registry.npmjs.org/raven/-/raven-2.4.2.tgz",
"integrity": "sha512-LLLS8bOJC1q33qszBsLaEtEg7X8G8hYLGcKO4s6EifAce2BN6cTRdBXNvwVNv4kNk82YUZYrj53yEbL4kCmjjw==", "integrity": "sha1-ASnircMHiGRv1TC2fQioziXU9tw=",
"requires": { "requires": {
"cookie": "0.3.1", "cookie": "0.3.1",
"md5": "2.2.1", "md5": "2.2.1",
@@ -16035,9 +16061,9 @@
} }
}, },
"raven-js": { "raven-js": {
"version": "3.22.3", "version": "3.23.1",
"resolved": "https://registry.npmjs.org/raven-js/-/raven-js-3.22.3.tgz", "resolved": "https://registry.npmjs.org/raven-js/-/raven-js-3.23.1.tgz",
"integrity": "sha512-pIzHpAggyTOGJE3ruAKdZNK5qhO4V21kR7lwpdUM875yHpq1cqeGzvs78/RufF3g7NaAvVmMPCbaV9uUhQzJ3A==", "integrity": "sha512-cfkGRgz1TkFmEM5ahPWkIEav2+3zr32qMaBvKizzxN7fZapLbCrxMHMLDn7LSVGN0+dyPKY18imv3i0dkLRoKg==",
"dev": true "dev": true
}, },
"raw-body": { "raw-body": {
@@ -17963,9 +17989,9 @@
"dev": true "dev": true
}, },
"stylelint-config-standard": { "stylelint-config-standard": {
"version": "18.1.0", "version": "18.2.0",
"resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-18.1.0.tgz", "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-18.2.0.tgz",
"integrity": "sha512-kjpxnt1fu56ZJk+8wETz0Hr/3vvpj5KfQoBRLVeAJcFtCZBxF5kUDXGqsn4h2ZVyvNTf+2lOfX1dfok5ZOltqg==", "integrity": "sha512-07x0TaSIzvXlbOioUU4ORkCIM07kyIuojkbSVCyFWNVgXMXYHfhnQSCkqu+oHWJf3YADAnPGWzdJ53NxkoJ7RA==",
"dev": true, "dev": true,
"requires": { "requires": {
"stylelint-config-recommended": "2.1.0" "stylelint-config-recommended": "2.1.0"
@@ -19946,9 +19972,9 @@
"dev": true "dev": true
}, },
"x-xss-protection": { "x-xss-protection": {
"version": "1.0.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/x-xss-protection/-/x-xss-protection-1.0.0.tgz", "resolved": "https://registry.npmjs.org/x-xss-protection/-/x-xss-protection-1.1.0.tgz",
"integrity": "sha1-iYr7k4abJGYc+cUvnujbjtB2Tdk=" "integrity": "sha512-rx3GzJlgEeZ08MIcDsU2vY2B1QEriUKJTSiNHHUIem6eg9pzVOr2TL3Y4Pd6TMAM5D5azGjcxqI62piITBDHVg=="
}, },
"xml-char-classes": { "xml-char-classes": {
"version": "1.0.0", "version": "1.0.0",

View File

@@ -1,7 +1,7 @@
{ {
"name": "firefox-send", "name": "firefox-send",
"description": "File Sharing Experiment", "description": "File Sharing Experiment",
"version": "2.4.1", "version": "2.5.2",
"author": "Mozilla (https://mozilla.org)", "author": "Mozilla (https://mozilla.org)",
"repository": "mozilla/send", "repository": "mozilla/send",
"homepage": "https://github.com/mozilla/send/", "homepage": "https://github.com/mozilla/send/",
@@ -26,11 +26,10 @@
"contributors": "git shortlog -s | awk -F\\t '{print $2}' > CONTRIBUTORS", "contributors": "git shortlog -s | awk -F\\t '{print $2}' > CONTRIBUTORS",
"release": "npm-run-all contributors changelog", "release": "npm-run-all contributors changelog",
"test": "npm-run-all test:*", "test": "npm-run-all test:*",
"test:backend": "nyc mocha --reporter=min test/unit", "test:backend": "nyc mocha --reporter=min test/backend",
"test:frontend": "cross-env NODE_ENV=development node test/frontend/runner.js && nyc report --reporter=html", "test:frontend": "cross-env NODE_ENV=development node test/frontend/runner.js && nyc report --reporter=html",
"start": "cross-env NODE_ENV=development webpack-dev-server", "start": "npm run clean && cross-env NODE_ENV=development webpack-dev-server",
"prod": "node server/prod.js", "prod": "node server/prod.js"
"cover": "nyc --reporter=html mocha test/unit"
}, },
"lint-staged": { "lint-staged": {
"*.js": [ "*.js": [
@@ -54,8 +53,9 @@
"node": ">=8.2.0" "node": ">=8.2.0"
}, },
"devDependencies": { "devDependencies": {
"asmcrypto.js": "^0.22.0",
"babel-core": "^6.26.0", "babel-core": "^6.26.0",
"babel-loader": "^7.1.3", "babel-loader": "^7.1.4",
"babel-plugin-istanbul": "^4.1.5", "babel-plugin-istanbul": "^4.1.5",
"babel-plugin-yo-yoify": "^1.0.2", "babel-plugin-yo-yoify": "^1.0.2",
"babel-preset-env": "^1.6.1", "babel-preset-env": "^1.6.1",
@@ -63,25 +63,26 @@
"babel-preset-stage-2": "^6.24.1", "babel-preset-stage-2": "^6.24.1",
"babel-preset-stage-3": "^6.24.1", "babel-preset-stage-3": "^6.24.1",
"base64-js": "^1.2.3", "base64-js": "^1.2.3",
"copy-webpack-plugin": "^4.4.2", "copy-webpack-plugin": "^4.5.0",
"cross-env": "^5.1.3", "cross-env": "^5.1.3",
"css-loader": "^0.28.10", "css-loader": "^0.28.10",
"css-mqpacker": "^6.0.2", "css-mqpacker": "^6.0.2",
"eslint": "^4.18.1", "eslint": "^4.18.2",
"eslint-plugin-mocha": "^4.11.0", "eslint-plugin-mocha": "^4.12.1",
"eslint-plugin-node": "^6.0.1", "eslint-plugin-node": "^6.0.1",
"eslint-plugin-security": "^1.4.0", "eslint-plugin-security": "^1.4.0",
"expose-loader": "^0.7.4", "expose-loader": "^0.7.4",
"extract-loader": "^1.0.2", "extract-loader": "^1.0.2",
"extract-text-webpack-plugin": "^3.0.2", "extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^1.1.9", "fast-text-encoding": "^1.0.0",
"file-loader": "^1.1.11",
"fluent-intl-polyfill": "^0.1.0", "fluent-intl-polyfill": "^0.1.0",
"git-rev-sync": "^1.10.0", "git-rev-sync": "^1.10.0",
"github-changes": "^1.1.2", "github-changes": "^1.1.2",
"html-loader": "^0.5.5", "html-loader": "^0.5.5",
"husky": "^0.14.3", "husky": "^0.14.3",
"lint-staged": "^7.0.0", "lint-staged": "^7.0.0",
"mocha": "^5.0.0", "mocha": "^5.0.4",
"nanobus": "^4.3.2", "nanobus": "^4.3.2",
"nanotiming": "^7.3.0", "nanotiming": "^7.3.0",
"npm-run-all": "^4.1.2", "npm-run-all": "^4.1.2",
@@ -89,18 +90,18 @@
"nyc": "^11.5.0", "nyc": "^11.5.0",
"postcss-cssnext": "^3.1.0", "postcss-cssnext": "^3.1.0",
"postcss-import": "^11.1.0", "postcss-import": "^11.1.0",
"postcss-loader": "^2.1.0", "postcss-loader": "^2.1.1",
"prettier": "^1.10.2", "prettier": "^1.11.1",
"proxyquire": "^1.8.0", "proxyquire": "^1.8.0",
"puppeteer": "^1.1.1", "puppeteer": "^1.1.1",
"raven-js": "^3.22.2", "raven-js": "^3.23.1",
"redis-mock": "^0.21.0", "redis-mock": "^0.21.0",
"require-from-string": "^2.0.1", "require-from-string": "^2.0.1",
"rimraf": "^2.6.2", "rimraf": "^2.6.2",
"sinon": "^4.4.2", "sinon": "^4.4.2",
"string-hash": "^1.1.3", "string-hash": "^1.1.3",
"stylelint": "^9.1.1", "stylelint": "^9.1.1",
"stylelint-config-standard": "^18.1.0", "stylelint-config-standard": "^18.2.0",
"stylelint-no-unsupported-browser-features": "^2.0.0", "stylelint-no-unsupported-browser-features": "^2.0.0",
"svgo": "^1.0.5", "svgo": "^1.0.5",
"svgo-loader": "^2.1.0", "svgo-loader": "^2.1.0",
@@ -113,19 +114,19 @@
"webpack-unassert-loader": "^1.2.0" "webpack-unassert-loader": "^1.2.0"
}, },
"dependencies": { "dependencies": {
"aws-sdk": "^2.202.0", "aws-sdk": "^2.206.0",
"babel-polyfill": "^6.26.0", "babel-polyfill": "^6.26.0",
"choo": "^6.7.0", "choo": "^6.10.0",
"cldr-core": "^32.0.0", "cldr-core": "^32.0.0",
"connect-busboy": "0.0.2", "connect-busboy": "0.0.2",
"convict": "^4.0.1", "convict": "^4.0.1",
"express": "^4.16.2", "express": "^4.16.2",
"fluent": "^0.6.3", "fluent": "^0.6.3",
"fluent-langneg": "^0.1.0", "fluent-langneg": "^0.1.0",
"helmet": "^3.11.0", "helmet": "^3.12.0",
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
"mozlog": "^2.2.0", "mozlog": "^2.2.0",
"raven": "^2.4.1", "raven": "^2.4.2",
"redis": "^2.8.0" "redis": "^2.8.0"
}, },
"availableLanguages": [ "availableLanguages": [

View File

@@ -1,4 +1,4 @@
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
title = Firefox Send title = Firefox Send
siteSubtitle = web eksperiment siteSubtitle = web eksperiment
siteFeedback = Geri dönüş siteFeedback = Geri dönüş
@@ -39,29 +39,29 @@ copyUrlFormButton = Buferə köçür
copiedUrl = Köçürüldü! copiedUrl = Köçürüldü!
deleteFileButton = Faylı sil deleteFileButton = Faylı sil
sendAnotherFileLink = Başqa fayl göndər sendAnotherFileLink = Başqa fayl göndər
// Alternative text used on the download link/button (indicates an action). # Alternative text used on the download link/button (indicates an action).
downloadAltText = Endir downloadAltText = Endir
downloadsFileList = Endirmələr downloadsFileList = Endirmələr
// Used as header in a column indicating the amount of time left before a # Used as header in a column indicating the amount of time left before a
// download link expires (e.g. "10h 5m") # download link expires (e.g. "10h 5m")
timeFileList = Vaxt timeFileList = Vaxt
// Used as header in a column indicating the number of times a file has been # Used as header in a column indicating the number of times a file has been
// downloaded # downloaded
downloadFileName = { $filename } faylını endir downloadFileName = { $filename } faylını endir
downloadFileSize = ({ $size }) downloadFileSize = ({ $size })
unlockInputLabel = Parol daxil edin unlockInputLabel = Parol daxil edin
unlockInputPlaceholder = Parol unlockInputPlaceholder = Parol
unlockButtonLabel = Aç unlockButtonLabel = Aç
downloadFileTitle = Şifrələnmiş Faylı Endir downloadFileTitle = Şifrələnmiş Faylı Endir
// Firefox Send is a brand name and should not be localized. # 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. 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). # Text and title used on the download link/button (indicates an action).
downloadButtonLabel = Endir downloadButtonLabel = Endir
downloadNotification = Endirməniz tamamlandı. downloadNotification = Endirməniz tamamlandı.
downloadFinish = Endirmə Tamamlandı downloadFinish = Endirmə Tamamlandı
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)". # This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
fileSizeProgress = ({ $partialSize } / { $totalSize }) fileSizeProgress = ({ $partialSize } / { $totalSize })
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
sendYourFilesLink = Firefox Send Yoxla sendYourFilesLink = Firefox Send Yoxla
downloadingPageProgress = { $filename } faylı ({ $size }) endirilir downloadingPageProgress = { $filename } faylı ({ $size }) endirilir
downloadingPageMessage = Lütfən faylı endirib şifrəsini açarkən vərəqi açıq buraxın. downloadingPageMessage = Lütfən faylı endirib şifrəsini açarkən vərəqi açıq buraxın.
@@ -73,7 +73,7 @@ fileTooBig = Fayl yükləmək üçün çox böyükdür. Fayl { $size }-dan az ol
linkExpiredAlt = Keçidin vaxtı çıxıb linkExpiredAlt = Keçidin vaxtı çıxıb
expiredPageHeader = Keçidin vaxtı çıxıb və ya heç vaxt olmayıb! expiredPageHeader = Keçidin vaxtı çıxıb və ya heç vaxt olmayıb!
notSupportedHeader = Səyyahınız dəstəklənmir. notSupportedHeader = Səyyahınız dəstəklənmir.
// Firefox Send is a brand name and should not be localized. # 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! 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!
notSupportedLink = Səyyahım niyə dəstəklənmir? notSupportedLink = Səyyahım niyə dəstəklənmir?
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. 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.
@@ -81,7 +81,7 @@ updateFirefox = Firefox-u Yenilə
downloadFirefoxButtonSub = Pulsuz Endir downloadFirefoxButtonSub = Pulsuz Endir
uploadedFile = Fayl uploadedFile = Fayl
copyFileList = Keçidi Köçürt copyFileList = Keçidi Köçürt
// expiryFileList is used as a column header # expiryFileList is used as a column header
expiryFileList = Vaxtı çıxma tarixi expiryFileList = Vaxtı çıxma tarixi
deleteFileList = Sil deleteFileList = Sil
nevermindButton = Vacib deyil nevermindButton = Vacib deyil
@@ -94,7 +94,7 @@ deletePopupCancel = Ləğv et
deleteButtonHover = Sil deleteButtonHover = Sil
copyUrlHover = Keçidi Köçürt copyUrlHover = Keçidi Köçürt
footerLinkLegal = Hüquqi footerLinkLegal = Hüquqi
// Test Pilot is a proper name and should not be localized. # Test Pilot is a proper name and should not be localized.
footerLinkAbout = Test Pilot Haqqında footerLinkAbout = Test Pilot Haqqında
footerLinkPrivacy = Məxfilik footerLinkPrivacy = Məxfilik
footerLinkTerms = Şərtlər footerLinkTerms = Şərtlər
@@ -103,13 +103,17 @@ requirePasswordCheckbox = Bu faylı endirmək üçün parol tələb et
addPasswordButton = Parol əlavə et addPasswordButton = Parol əlavə et
changePasswordButton = Dəyişdir changePasswordButton = Dəyişdir
passwordTryAgain = Səhv parol. Təkrar yoxlayın. passwordTryAgain = Səhv parol. Təkrar yoxlayın.
// This label is followed by the password needed to download a file
passwordResult = Parol: { $password }
reportIPInfringement = Əqli-mülkiyyət pozuntusu bildir reportIPInfringement = Əqli-mülkiyyət pozuntusu bildir
javascriptRequired = Firefox Send üçün JavaScript lazımdır javascriptRequired = Firefox Send üçün JavaScript lazımdır
whyJavascript = Firefox Send niyə JavaScript tələb edir? whyJavascript = Firefox Send niyə JavaScript tələb edir?
enableJavascript = Lütfən JavaScript-i aktiv edib təkrar yoxlayın. enableJavascript = Lütfən JavaScript-i aktiv edib təkrar yoxlayın.
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m" # A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
expiresHoursMinutes = { $hours } saat { $minutes } dəq expiresHoursMinutes = { $hours } saat { $minutes } dəq
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m" # A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
expiresMinutes = { $minutes } dəq expiresMinutes = { $minutes } dəq
# A short status message shown when a password is successfully set
passwordIsSet = Parol quruldu
# A short status message shown when the user enters a long password
maxPasswordLength = Maksimum parol uzunluğu: { $length }
# A short status message shown when there was an error setting the password
passwordSetError = Parol qurula bilmədi

View File

@@ -32,9 +32,9 @@ downloadCount = { $num ->
*[other] { $num } staženích *[other] { $num } staženích
} }
timespanHours = { $num -> timespanHours = { $num ->
[one] hodina [one] jedné hodině
[few] hodiny [few] { $num } hodinách
*[other] hodin *[other] { $num } hodinách
} }
copyUrlFormLabelWithName = Zkopírujte a sdílejte odkaz na váš soubor: { $filename } copyUrlFormLabelWithName = Zkopírujte a sdílejte odkaz na váš soubor: { $filename }
copyUrlFormButton = Zkopírovat do schránky copyUrlFormButton = Zkopírovat do schránky
@@ -110,9 +110,9 @@ javascriptRequired = Firefox Send vyžaduje povolený JavaScript
whyJavascript = Proč Firefox Send vyžaduje povolený JavaScript? whyJavascript = Proč Firefox Send vyžaduje povolený JavaScript?
enableJavascript = Povolte JavaScript a zkuste to znovu. enableJavascript = Povolte JavaScript a zkuste to znovu.
# A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m" # A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
expiresHoursMinutes = { $hours }h { $minutes }m expiresHoursMinutes = { $hours } h { $minutes } m
# A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m" # A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
expiresMinutes = { $minutes }m expiresMinutes = { $minutes } m
# A short status message shown when a password is successfully set # A short status message shown when a password is successfully set
passwordIsSet = Heslo nastaveno passwordIsSet = Heslo nastaveno
# A short status message shown when the user enters a long password # A short status message shown when the user enters a long password

View File

@@ -1,4 +1,4 @@
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
title = Firefox Send title = Firefox Send
siteSubtitle = πείραμα διαδικτύου siteSubtitle = πείραμα διαδικτύου
siteFeedback = Σχόλια siteFeedback = Σχόλια
@@ -39,29 +39,29 @@ copyUrlFormButton = Αντιγραφή στο πρόχειρο
copiedUrl = Αντιγράφτηκε! copiedUrl = Αντιγράφτηκε!
deleteFileButton = Διαγραφή αρχείου deleteFileButton = Διαγραφή αρχείου
sendAnotherFileLink = Αποστολή άλλου αρχείου sendAnotherFileLink = Αποστολή άλλου αρχείου
// Alternative text used on the download link/button (indicates an action). # Alternative text used on the download link/button (indicates an action).
downloadAltText = Λήψη downloadAltText = Λήψη
downloadsFileList = Λήψεις downloadsFileList = Λήψεις
// Used as header in a column indicating the amount of time left before a # Used as header in a column indicating the amount of time left before a
// download link expires (e.g. "10h 5m") # download link expires (e.g. "10h 5m")
timeFileList = Ώρα timeFileList = Ώρα
// Used as header in a column indicating the number of times a file has been # Used as header in a column indicating the number of times a file has been
// downloaded # downloaded
downloadFileName = Λήψη του { $filename } downloadFileName = Λήψη του { $filename }
downloadFileSize = ({ $size }) downloadFileSize = ({ $size })
unlockInputLabel = Εισαγωγή κωδικού πρόσβασης unlockInputLabel = Εισαγωγή κωδικού πρόσβασης
unlockInputPlaceholder = Κωδικός πρόσβασης unlockInputPlaceholder = Κωδικός πρόσβασης
unlockButtonLabel = Ξεκλείδωμα unlockButtonLabel = Ξεκλείδωμα
downloadFileTitle = Λήψη κρυπτογραφημένου αρχείου downloadFileTitle = Λήψη κρυπτογραφημένου αρχείου
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
downloadMessage = Ο/Η φίλος/-η σας, σάς στέλνει ένα αρχείο με τη βοήθεια του Firefox Send, μιας υπηρεσίας που επιτρέπει τον διαμοιρασμό αρχείων μέσω ενός ασφαλούς, ιδιωτικού και κρυπτογραφημένου συνδέσμου που λήγει αυτόματα, ώστε να είστε σίγουροι ότι τα αρχεία σας δεν θα παραμείνουν στο διαδίκτυο για πάντα. downloadMessage = Ο/Η φίλος/-η σας, σάς στέλνει ένα αρχείο με τη βοήθεια του Firefox Send, μιας υπηρεσίας που επιτρέπει τον διαμοιρασμό αρχείων μέσω ενός ασφαλούς, ιδιωτικού και κρυπτογραφημένου συνδέσμου που λήγει αυτόματα, ώστε να είστε σίγουροι ότι τα αρχεία σας δεν θα παραμείνουν στο διαδίκτυο για πάντα.
// Text and title used on the download link/button (indicates an action). # Text and title used on the download link/button (indicates an action).
downloadButtonLabel = Λήψη downloadButtonLabel = Λήψη
downloadNotification = Η λήψη σας ολοκληρώθηκε. downloadNotification = Η λήψη σας ολοκληρώθηκε.
downloadFinish = Η λήψη ολοκληρώθηκε downloadFinish = Η λήψη ολοκληρώθηκε
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)". # This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
fileSizeProgress = ({ $partialSize } από { $totalSize }) fileSizeProgress = ({ $partialSize } από { $totalSize })
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
sendYourFilesLink = Δοκιμάστε το Firefox Send sendYourFilesLink = Δοκιμάστε το Firefox Send
downloadingPageProgress = Γίνεται λήψη του { $filename } ({ $size }) downloadingPageProgress = Γίνεται λήψη του { $filename } ({ $size })
downloadingPageMessage = Παρακαλώ αφήστε ανοικτή αυτή την καρτέλα όσο λαμβάνουμε και αποκρυπτογραφούμε το αρχείο σας. downloadingPageMessage = Παρακαλώ αφήστε ανοικτή αυτή την καρτέλα όσο λαμβάνουμε και αποκρυπτογραφούμε το αρχείο σας.
@@ -73,7 +73,7 @@ fileTooBig = Αυτό το αρχείο είναι πολύ μεγάλο για
linkExpiredAlt = Ο σύνδεσμος έληξε linkExpiredAlt = Ο σύνδεσμος έληξε
expiredPageHeader = Αυτός ο σύνδεσμος έχει λήξει ή δεν υπήρξε ποτέ! expiredPageHeader = Αυτός ο σύνδεσμος έχει λήξει ή δεν υπήρξε ποτέ!
notSupportedHeader = Το πρόγραμμα περιήγησής σας δεν υποστηρίζεται. notSupportedHeader = Το πρόγραμμα περιήγησής σας δεν υποστηρίζεται.
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
notSupportedDetail = Δυστυχώς, αυτό το πρόγραμμα περιήγησης δεν υποστηρίζει την τεχνολογία ιστού στην οποία βασίζεται το Firefox Send. Θα πρέπει να δοκιμάσετε ένα άλλο πρόγραμμα περιήγησης. Προτείνουμε το Firefox! notSupportedDetail = Δυστυχώς, αυτό το πρόγραμμα περιήγησης δεν υποστηρίζει την τεχνολογία ιστού στην οποία βασίζεται το Firefox Send. Θα πρέπει να δοκιμάσετε ένα άλλο πρόγραμμα περιήγησης. Προτείνουμε το Firefox!
notSupportedLink = Γιατί δεν υποστηρίζεται το πρόγραμμα περιήγησής μου; notSupportedLink = Γιατί δεν υποστηρίζεται το πρόγραμμα περιήγησής μου;
notSupportedOutdatedDetail = Δυστυχώς, αυτή η έκδοση του Firefox δεν υποστηρίζει την τεχνολογία ιστού στην οποία βασίζεται το Firefox Send. Πρέπει να ενημερώσετε το πρόγραμμα περιήγησής σας. notSupportedOutdatedDetail = Δυστυχώς, αυτή η έκδοση του Firefox δεν υποστηρίζει την τεχνολογία ιστού στην οποία βασίζεται το Firefox Send. Πρέπει να ενημερώσετε το πρόγραμμα περιήγησής σας.
@@ -81,7 +81,7 @@ updateFirefox = Ενημέρωση Firefox
downloadFirefoxButtonSub = Δωρεάν λήψη downloadFirefoxButtonSub = Δωρεάν λήψη
uploadedFile = Αρχείο uploadedFile = Αρχείο
copyFileList = Αντιγραφή URL copyFileList = Αντιγραφή URL
// expiryFileList is used as a column header # expiryFileList is used as a column header
expiryFileList = Λήγει σε expiryFileList = Λήγει σε
deleteFileList = Διαγραφή deleteFileList = Διαγραφή
nevermindButton = Μην ανησυχείτε nevermindButton = Μην ανησυχείτε
@@ -94,7 +94,7 @@ deletePopupCancel = Ακύρωση
deleteButtonHover = Διαγραφή deleteButtonHover = Διαγραφή
copyUrlHover = Αντιγραφή URL copyUrlHover = Αντιγραφή URL
footerLinkLegal = Νομικά footerLinkLegal = Νομικά
// Test Pilot is a proper name and should not be localized. # Test Pilot is a proper name and should not be localized.
footerLinkAbout = Σχετικά με το Test Pilot footerLinkAbout = Σχετικά με το Test Pilot
footerLinkPrivacy = Απόρρητο footerLinkPrivacy = Απόρρητο
footerLinkTerms = Όροι footerLinkTerms = Όροι
@@ -103,13 +103,17 @@ requirePasswordCheckbox = Απαίτηση κωδικού πρόσβασης γ
addPasswordButton = Προσθήκη κωδικού πρόσβασης addPasswordButton = Προσθήκη κωδικού πρόσβασης
changePasswordButton = Αλλαγή changePasswordButton = Αλλαγή
passwordTryAgain = Λάθος κωδικός πρόσβασης. Δοκιμάστε ξανά. passwordTryAgain = Λάθος κωδικός πρόσβασης. Δοκιμάστε ξανά.
// This label is followed by the password needed to download a file
passwordResult = Κωδικός πρόσβασης: { $password }
reportIPInfringement = Αναφορά παραβίασης IP reportIPInfringement = Αναφορά παραβίασης IP
javascriptRequired = Το Firefox Send απαιτεί JavaScript javascriptRequired = Το Firefox Send απαιτεί JavaScript
whyJavascript = Γιατί το Firefox Send απαιτεί JavaScript; whyJavascript = Γιατί το Firefox Send απαιτεί JavaScript;
enableJavascript = Παρακαλώ ενεργοποιήστε το JavaScript και δοκιμάστε ξανά. enableJavascript = Παρακαλώ ενεργοποιήστε το JavaScript και δοκιμάστε ξανά.
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m" # A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
expiresHoursMinutes = { $hours }ώ { $minutes }λ expiresHoursMinutes = { $hours }ώ { $minutes }λ
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m" # A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
expiresMinutes = { $minutes }λ expiresMinutes = { $minutes }λ
# A short status message shown when a password is successfully set
passwordIsSet = Επιτυχής ορισμός κωδικού
# A short status message shown when the user enters a long password
maxPasswordLength = Μέγιστο μήκος κωδικού: { $length }
# A short status message shown when there was an error setting the password
passwordSetError = Δεν ήταν δυνατός ο ορισμός αυτού του κωδικού

View File

@@ -1,4 +1,4 @@
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
title = Firefox Send title = Firefox Send
siteSubtitle = experimento web siteSubtitle = experimento web
siteFeedback = Opinión siteFeedback = Opinión
@@ -39,29 +39,29 @@ copyUrlFormButton = Copiar al portapapeles
copiedUrl = ¡Copiado! copiedUrl = ¡Copiado!
deleteFileButton = Borrar archivo deleteFileButton = Borrar archivo
sendAnotherFileLink = Enviar otro archivo sendAnotherFileLink = Enviar otro archivo
// Alternative text used on the download link/button (indicates an action). # Alternative text used on the download link/button (indicates an action).
downloadAltText = Descargar downloadAltText = Descargar
downloadsFileList = Descargas downloadsFileList = Descargas
// Used as header in a column indicating the amount of time left before a # Used as header in a column indicating the amount of time left before a
// download link expires (e.g. "10h 5m") # download link expires (e.g. "10h 5m")
timeFileList = Tiempo timeFileList = Tiempo
// Used as header in a column indicating the number of times a file has been # Used as header in a column indicating the number of times a file has been
// downloaded # downloaded
downloadFileName = Descargar { $filename } downloadFileName = Descargar { $filename }
downloadFileSize = ({ $size }) downloadFileSize = ({ $size })
unlockInputLabel = Ingresar contraseña unlockInputLabel = Ingresar contraseña
unlockInputPlaceholder = Contraseña unlockInputPlaceholder = Contraseña
unlockButtonLabel = Desbloquear unlockButtonLabel = Desbloquear
downloadFileTitle = Descargar archivo cifrado downloadFileTitle = Descargar archivo cifrado
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
downloadMessage = Tu amigo te está enviando un archivo con Firefox Send, un servicio que permite compartir archivos con un enlace cifrado, seguro y privado que expira automáticamente para asegurar que tus datos no quedan en línea para siempre. downloadMessage = Tu amigo te está enviando un archivo con Firefox Send, un servicio que permite compartir archivos con un enlace cifrado, seguro y privado que expira automáticamente para asegurar que tus datos no quedan en línea para siempre.
// Text and title used on the download link/button (indicates an action). # Text and title used on the download link/button (indicates an action).
downloadButtonLabel = Descargar downloadButtonLabel = Descargar
downloadNotification = La descarga se completó. downloadNotification = La descarga se completó.
downloadFinish = Descarga completa downloadFinish = Descarga completa
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)". # This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
fileSizeProgress = ({ $partialSize } de { $totalSize }) fileSizeProgress = ({ $partialSize } de { $totalSize })
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
sendYourFilesLink = Probá Firefox Send sendYourFilesLink = Probá Firefox Send
downloadingPageProgress = Descargando { $filename } ({ $size }) downloadingPageProgress = Descargando { $filename } ({ $size })
downloadingPageMessage = Dejá esta pestaña abierta mientras descargamos el archivo y lo desciframos. downloadingPageMessage = Dejá esta pestaña abierta mientras descargamos el archivo y lo desciframos.
@@ -73,7 +73,7 @@ fileTooBig = El archivo es demasiado grande para subir. Debería tener menos de
linkExpiredAlt = Enlace explirado linkExpiredAlt = Enlace explirado
expiredPageHeader = ¡Este enlace ha expirado o nunca existió en primer lugar! expiredPageHeader = ¡Este enlace ha expirado o nunca existió en primer lugar!
notSupportedHeader = El navegador no está soportado. notSupportedHeader = El navegador no está soportado.
// Firefox Send is a brand name and should not be localized. # 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! notSupportedDetail = Desafortunadamente este navegador no soporta la tecnología web que necesita Firefox Send. Deberías probar otro navegador. ¡Te recomendamos Firefox!
notSupportedLink = ¿Por qué mi navegador no está soportado? notSupportedLink = ¿Por qué mi navegador no está soportado?
notSupportedOutdatedDetail = Desafortunadamente esta versión de Firefox no soporta la tecnología web que necesita Firefox Send. Necesitás actualizar el navegador. notSupportedOutdatedDetail = Desafortunadamente esta versión de Firefox no soporta la tecnología web que necesita Firefox Send. Necesitás actualizar el navegador.
@@ -81,7 +81,7 @@ updateFirefox = Actualizar Firefox
downloadFirefoxButtonSub = Descarga gratuita downloadFirefoxButtonSub = Descarga gratuita
uploadedFile = Archivo uploadedFile = Archivo
copyFileList = Copiar URL copyFileList = Copiar URL
// expiryFileList is used as a column header # expiryFileList is used as a column header
expiryFileList = Expira en expiryFileList = Expira en
deleteFileList = Borrar deleteFileList = Borrar
nevermindButton = No importa nevermindButton = No importa
@@ -94,7 +94,7 @@ deletePopupCancel = Cancelar
deleteButtonHover = Borrar deleteButtonHover = Borrar
copyUrlHover = Copiar URL copyUrlHover = Copiar URL
footerLinkLegal = Legales footerLinkLegal = Legales
// Test Pilot is a proper name and should not be localized. # Test Pilot is a proper name and should not be localized.
footerLinkAbout = Acerca de Test Pilot footerLinkAbout = Acerca de Test Pilot
footerLinkPrivacy = Privacidad footerLinkPrivacy = Privacidad
footerLinkTerms = Términos footerLinkTerms = Términos
@@ -103,13 +103,17 @@ requirePasswordCheckbox = Requerir contraseña para descargar este archivo
addPasswordButton = Agregar contraseña addPasswordButton = Agregar contraseña
changePasswordButton = Cambiar changePasswordButton = Cambiar
passwordTryAgain = Contraseña incorrecta. Intentá nuevamente. passwordTryAgain = Contraseña incorrecta. Intentá nuevamente.
// This label is followed by the password needed to download a file
passwordResult = Contraseña: { $password }
reportIPInfringement = Informar violación de propiedad intelectual reportIPInfringement = Informar violación de propiedad intelectual
javascriptRequired = Firefox Send requiere JavaScript javascriptRequired = Firefox Send requiere JavaScript
whyJavascript = ¿Por qué Firefox Send requiere Java Script? whyJavascript = ¿Por qué Firefox Send requiere Java Script?
enableJavascript = Por favor habilite JavaScript y pruebe de nuevo. enableJavascript = Por favor habilite JavaScript y pruebe de nuevo.
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m" # A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
expiresHoursMinutes = h { $hours } m { $minutes } expiresHoursMinutes = h { $hours } m { $minutes }
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m" # A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
expiresMinutes = m { $minutes } expiresMinutes = m { $minutes }
# A short status message shown when a password is successfully set
passwordIsSet = Contraseña establecida
# A short status message shown when the user enters a long password
maxPasswordLength = Longitud máxima de la contraseña: { $length }
# A short status message shown when there was an error setting the password
passwordSetError = No se pudo establecer la contraseña

View File

@@ -1,4 +1,4 @@
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
title = Firefox Send title = Firefox Send
siteSubtitle = experimento web siteSubtitle = experimento web
siteFeedback = Comentarios siteFeedback = Comentarios
@@ -39,29 +39,29 @@ copyUrlFormButton = Copiar al portapapeles
copiedUrl = ¡Copiado! copiedUrl = ¡Copiado!
deleteFileButton = Eliminar archivo deleteFileButton = Eliminar archivo
sendAnotherFileLink = Enviar otro archivo sendAnotherFileLink = Enviar otro archivo
// Alternative text used on the download link/button (indicates an action). # Alternative text used on the download link/button (indicates an action).
downloadAltText = Descargar downloadAltText = Descargar
downloadsFileList = Descargas downloadsFileList = Descargas
// Used as header in a column indicating the amount of time left before a # Used as header in a column indicating the amount of time left before a
// download link expires (e.g. "10h 5m") # download link expires (e.g. "10h 5m")
timeFileList = Tiempo timeFileList = Tiempo
// Used as header in a column indicating the number of times a file has been # Used as header in a column indicating the number of times a file has been
// downloaded # downloaded
downloadFileName = Descargar { $filename } downloadFileName = Descargar { $filename }
downloadFileSize = ({ $size }) downloadFileSize = ({ $size })
unlockInputLabel = Ingresar contraseña unlockInputLabel = Ingresar contraseña
unlockInputPlaceholder = Contraseña unlockInputPlaceholder = Contraseña
unlockButtonLabel = Desbloquear unlockButtonLabel = Desbloquear
downloadFileTitle = Bajar archivo cifrado downloadFileTitle = Bajar archivo cifrado
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
downloadMessage = Tu amigo te está enviando un archivo con Firefox Send, un servicio que te permite compartir archivos con un enlace seguro, privado y cifrado que expira automáticamente para asegurar que tus cosas no queden en línea de por vida. downloadMessage = Tu amigo te está enviando un archivo con Firefox Send, un servicio que te permite compartir archivos con un enlace seguro, privado y cifrado que expira automáticamente para asegurar que tus cosas no queden en línea de por vida.
// Text and title used on the download link/button (indicates an action). # Text and title used on the download link/button (indicates an action).
downloadButtonLabel = Descargar downloadButtonLabel = Descargar
downloadNotification = Tu descarga se completó. downloadNotification = Tu descarga se completó.
downloadFinish = Descarga completa downloadFinish = Descarga completa
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)". # This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
fileSizeProgress = ({ $partialSize } de { $totalSize }) fileSizeProgress = ({ $partialSize } de { $totalSize })
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
sendYourFilesLink = Probar Firefox Send sendYourFilesLink = Probar Firefox Send
downloadingPageProgress = Descargando { $filename } ({ $size }) downloadingPageProgress = Descargando { $filename } ({ $size })
downloadingPageMessage = Por favor, deja esta pestaña abierta mientras recibimos tu archivo y lo desciframos. downloadingPageMessage = Por favor, deja esta pestaña abierta mientras recibimos tu archivo y lo desciframos.
@@ -73,7 +73,7 @@ fileTooBig = Ese archivo es muy grande para ser subido. Debiera tener un tamaño
linkExpiredAlt = Enlace expirado linkExpiredAlt = Enlace expirado
expiredPageHeader = ¡Este enlace ha expirado o quizá jamás existió! expiredPageHeader = ¡Este enlace ha expirado o quizá jamás existió!
notSupportedHeader = Tu navegador no está soportado. notSupportedHeader = Tu navegador no está soportado.
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
notSupportedDetail = Lamentablemente este navegador no soporta la tecnología web que potencia a Firefox Send. Deberás probar en otro navegador. ¡Recomendamos Firefox! notSupportedDetail = Lamentablemente este navegador no soporta la tecnología web que potencia a Firefox Send. Deberás probar en otro navegador. ¡Recomendamos Firefox!
notSupportedLink = ¿Por qué mi navegador no es soportado? notSupportedLink = ¿Por qué mi navegador no es soportado?
notSupportedOutdatedDetail = Lamentablemente esta versión de Firefox no soporta la tecnología web que potencia a Firefox Send. Deberás actualizar tu navegador. notSupportedOutdatedDetail = Lamentablemente esta versión de Firefox no soporta la tecnología web que potencia a Firefox Send. Deberás actualizar tu navegador.
@@ -81,7 +81,7 @@ updateFirefox = Actualizar Firefox
downloadFirefoxButtonSub = Descarga gratuita downloadFirefoxButtonSub = Descarga gratuita
uploadedFile = Archivo uploadedFile = Archivo
copyFileList = Copiar URL copyFileList = Copiar URL
// expiryFileList is used as a column header # expiryFileList is used as a column header
expiryFileList = Expira en expiryFileList = Expira en
deleteFileList = Eliminar deleteFileList = Eliminar
nevermindButton = Da lo mismo nevermindButton = Da lo mismo
@@ -94,7 +94,7 @@ deletePopupCancel = Cancelar
deleteButtonHover = Eliminar deleteButtonHover = Eliminar
copyUrlHover = Copiar URL copyUrlHover = Copiar URL
footerLinkLegal = Legal footerLinkLegal = Legal
// Test Pilot is a proper name and should not be localized. # Test Pilot is a proper name and should not be localized.
footerLinkAbout = Acerca de Test Pilot footerLinkAbout = Acerca de Test Pilot
footerLinkPrivacy = Privacidad footerLinkPrivacy = Privacidad
footerLinkTerms = Términos footerLinkTerms = Términos
@@ -103,13 +103,17 @@ requirePasswordCheckbox = Requerir una contraseña para descargar este archivo
addPasswordButton = Añadir contraseña addPasswordButton = Añadir contraseña
changePasswordButton = Cambiar changePasswordButton = Cambiar
passwordTryAgain = Contraseña incorrecta. Vuelve a intentarlo. passwordTryAgain = Contraseña incorrecta. Vuelve a intentarlo.
// This label is followed by the password needed to download a file
passwordResult = Contraseña: { $password }
reportIPInfringement = Reportar infracción de PI reportIPInfringement = Reportar infracción de PI
javascriptRequired = Firefox Send requiere JavaScript. javascriptRequired = Firefox Send requiere JavaScript.
whyJavascript = ¿Por qué Firefox Send requiere JavaScript? whyJavascript = ¿Por qué Firefox Send requiere JavaScript?
enableJavascript = Por favor, activa JavaScript y vuelve a intentarlo. enableJavascript = Por favor, activa JavaScript y vuelve a intentarlo.
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m" # A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
expiresHoursMinutes = { $hours }h { $minutes }m expiresHoursMinutes = { $hours }h { $minutes }m
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m" # A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
expiresMinutes = { $minutes }m expiresMinutes = { $minutes }m
# A short status message shown when a password is successfully set
passwordIsSet = Contraseña establecida
# A short status message shown when the user enters a long password
maxPasswordLength = Longitud máxima de la contraseña: { $length }
# A short status message shown when there was an error setting the password
passwordSetError = Esta contraseña no pudo ser establecida

View File

@@ -1,4 +1,4 @@
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
title = Firefox Send title = Firefox Send
siteSubtitle = veebieksperiment siteSubtitle = veebieksperiment
siteFeedback = Tagasiside siteFeedback = Tagasiside
@@ -39,29 +39,29 @@ copyUrlFormButton = Kopeeri vahemällu
copiedUrl = Kopeeritud! copiedUrl = Kopeeritud!
deleteFileButton = Kustuta fail deleteFileButton = Kustuta fail
sendAnotherFileLink = Saada järgmine fail sendAnotherFileLink = Saada järgmine fail
// Alternative text used on the download link/button (indicates an action). # Alternative text used on the download link/button (indicates an action).
downloadAltText = Laadi alla downloadAltText = Laadi alla
downloadsFileList = Allalaadimised downloadsFileList = Allalaadimised
// Used as header in a column indicating the amount of time left before a # Used as header in a column indicating the amount of time left before a
// download link expires (e.g. "10h 5m") # download link expires (e.g. "10h 5m")
timeFileList = Aega jäänud timeFileList = Aega jäänud
// Used as header in a column indicating the number of times a file has been # Used as header in a column indicating the number of times a file has been
// downloaded # downloaded
downloadFileName = Laadi fail { $filename } alla downloadFileName = Laadi fail { $filename } alla
downloadFileSize = ({ $size }) downloadFileSize = ({ $size })
unlockInputLabel = Sisesta parool unlockInputLabel = Sisesta parool
unlockInputPlaceholder = Parool unlockInputPlaceholder = Parool
unlockButtonLabel = Ava unlockButtonLabel = Ava
downloadFileTitle = Krüptitud faili allalaadimine downloadFileTitle = Krüptitud faili allalaadimine
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
downloadMessage = Sulle on saadetud fail Firefox Sendiga - teenusega, mis lubab faile ohutult, privaatselt ja krüpteeritult jagada. Failid kustutatakse automaatselt, et need ei jääks internetti igaveseks. downloadMessage = Sulle on saadetud fail Firefox Sendiga - teenusega, mis lubab faile ohutult, privaatselt ja krüpteeritult jagada. Failid kustutatakse automaatselt, et need ei jääks internetti igaveseks.
// Text and title used on the download link/button (indicates an action). # Text and title used on the download link/button (indicates an action).
downloadButtonLabel = Laadi alla downloadButtonLabel = Laadi alla
downloadNotification = Allalaadimine on lõpetatud. downloadNotification = Allalaadimine on lõpetatud.
downloadFinish = Allalaadimine lõpetati downloadFinish = Allalaadimine lõpetati
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)". # This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
fileSizeProgress = ({ $partialSize }/{ $totalSize }) fileSizeProgress = ({ $partialSize }/{ $totalSize })
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
sendYourFilesLink = Proovi Firefox Sendi sendYourFilesLink = Proovi Firefox Sendi
downloadingPageProgress = Faili { $filename } ({ $size }) allalaadimine downloadingPageProgress = Faili { $filename } ({ $size }) allalaadimine
downloadingPageMessage = Palun jäta see kaart lahti, kuni fail on alla laaditud ja dekrüptitud. downloadingPageMessage = Palun jäta see kaart lahti, kuni fail on alla laaditud ja dekrüptitud.
@@ -73,7 +73,7 @@ fileTooBig = Fail on üleslaadimiseks liiga suur. See peaks olema väiksem kui {
linkExpiredAlt = Link on aegunud linkExpiredAlt = Link on aegunud
expiredPageHeader = See link on aegunud või seda pole kunagi olnudki! expiredPageHeader = See link on aegunud või seda pole kunagi olnudki!
notSupportedHeader = Sinu brauser pole toetatud. notSupportedHeader = Sinu brauser pole toetatud.
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
notSupportedDetail = Kahjuks ei toeta see brauser veebitehnoloogiaid, mis teevad Firefox Sendi toimimise võimalikuks. Sa pead proovima teise brauseriga. Me soovitame Firefoxi! notSupportedDetail = Kahjuks ei toeta see brauser veebitehnoloogiaid, mis teevad Firefox Sendi toimimise võimalikuks. Sa pead proovima teise brauseriga. Me soovitame Firefoxi!
notSupportedLink = Miks mu brauser toetatud pole? notSupportedLink = Miks mu brauser toetatud pole?
notSupportedOutdatedDetail = Kahjuks ei toeta see Firefoxi versioon veebitehnoloogiaid, mis teevad Firefox Sendi toimimise võimalikuks. Sa pead oma brauserit uuendama. notSupportedOutdatedDetail = Kahjuks ei toeta see Firefoxi versioon veebitehnoloogiaid, mis teevad Firefox Sendi toimimise võimalikuks. Sa pead oma brauserit uuendama.
@@ -81,7 +81,7 @@ updateFirefox = Uuenda Firefox
downloadFirefoxButtonSub = Laadi alla tasuta downloadFirefoxButtonSub = Laadi alla tasuta
uploadedFile = Fail uploadedFile = Fail
copyFileList = Kopeeri URL copyFileList = Kopeeri URL
// expiryFileList is used as a column header # expiryFileList is used as a column header
expiryFileList = Aegub expiryFileList = Aegub
deleteFileList = Kustuta deleteFileList = Kustuta
nevermindButton = Ära pane tähele nevermindButton = Ära pane tähele
@@ -94,7 +94,7 @@ deletePopupCancel = Loobu
deleteButtonHover = Kustuta deleteButtonHover = Kustuta
copyUrlHover = Kopeeri URL copyUrlHover = Kopeeri URL
footerLinkLegal = Õiguslik teave footerLinkLegal = Õiguslik teave
// Test Pilot is a proper name and should not be localized. # Test Pilot is a proper name and should not be localized.
footerLinkAbout = Test Pilotist footerLinkAbout = Test Pilotist
footerLinkPrivacy = Privaatsusest footerLinkPrivacy = Privaatsusest
footerLinkTerms = Teenusetingimused footerLinkTerms = Teenusetingimused
@@ -103,13 +103,17 @@ requirePasswordCheckbox = Selle faili allalaadimiseks nõutakse parooli
addPasswordButton = Lisa parool addPasswordButton = Lisa parool
changePasswordButton = Muuda changePasswordButton = Muuda
passwordTryAgain = Vale parool. Palun proovi uuesti. passwordTryAgain = Vale parool. Palun proovi uuesti.
// This label is followed by the password needed to download a file
passwordResult = Parool: { $password }
reportIPInfringement = Intellektuaalomandi keelatud kasutamise raporteerimine reportIPInfringement = Intellektuaalomandi keelatud kasutamise raporteerimine
javascriptRequired = Firefox Send'i kasutamiseks tuleb JavaScript lubada javascriptRequired = Firefox Send'i kasutamiseks tuleb JavaScript lubada
whyJavascript = Miks Firefox Send JavaScripti vajab? whyJavascript = Miks Firefox Send JavaScripti vajab?
enableJavascript = Palun luba JavaScript ja proovi uuesti. enableJavascript = Palun luba JavaScript ja proovi uuesti.
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m" # A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
expiresHoursMinutes = { $hours }t { $minutes }m expiresHoursMinutes = { $hours }t { $minutes }m
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m" # A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
expiresMinutes = { $minutes }m expiresMinutes = { $minutes }m
# A short status message shown when a password is successfully set
passwordIsSet = Parool on muudetud
# A short status message shown when the user enters a long password
maxPasswordLength = Maksimaalne parooli pikkus: { $length }
# A short status message shown when there was an error setting the password
passwordSetError = Parooli muutmine ebaõnnestus

View File

@@ -1,4 +1,4 @@
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
title = Firefox Send title = Firefox Send
siteSubtitle = آزمایش وب siteSubtitle = آزمایش وب
siteFeedback = بازخورد siteFeedback = بازخورد
@@ -37,29 +37,29 @@ copyUrlFormButton = رونوشت به کلیپ‌بورد
copiedUrl = رونوشت شد! copiedUrl = رونوشت شد!
deleteFileButton = حذف پرونده deleteFileButton = حذف پرونده
sendAnotherFileLink = ارسال پرونده دیگر sendAnotherFileLink = ارسال پرونده دیگر
// Alternative text used on the download link/button (indicates an action). # Alternative text used on the download link/button (indicates an action).
downloadAltText = دریافت downloadAltText = دریافت
downloadsFileList = دریافت‌ها downloadsFileList = دریافت‌ها
// Used as header in a column indicating the amount of time left before a # Used as header in a column indicating the amount of time left before a
// download link expires (e.g. "10h 5m") # download link expires (e.g. "10h 5m")
timeFileList = زمان timeFileList = زمان
// Used as header in a column indicating the number of times a file has been # Used as header in a column indicating the number of times a file has been
// downloaded # downloaded
downloadFileName = بارگیری { $filename } downloadFileName = بارگیری { $filename }
downloadFileSize = ({ $size }) downloadFileSize = ({ $size })
unlockInputLabel = گذرواژه را وارد کنید unlockInputLabel = گذرواژه را وارد کنید
unlockInputPlaceholder = گذرواژه unlockInputPlaceholder = گذرواژه
unlockButtonLabel = باز کردن unlockButtonLabel = باز کردن
downloadFileTitle = دریافت پروندهٔ رمزنگاری شده downloadFileTitle = دریافت پروندهٔ رمزنگاری شده
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
downloadMessage = دوست شما درحال ارسال پرونده ای به وسیله Firefox Send است،‌ این سرویس این امکان را به شما می‌دهد تا پرونده‌های خود را به صورت ایمن،‌خصوصی و رمزنگاری شده به همراه پیوند انقضا خودکار همرسانی کنید تا اطمینان حاصل کنید چیزهای شما برای همیشه آنلاین باقی نخواهد ماند. downloadMessage = دوست شما درحال ارسال پرونده ای به وسیله Firefox Send است،‌ این سرویس این امکان را به شما می‌دهد تا پرونده‌های خود را به صورت ایمن،‌خصوصی و رمزنگاری شده به همراه پیوند انقضا خودکار همرسانی کنید تا اطمینان حاصل کنید چیزهای شما برای همیشه آنلاین باقی نخواهد ماند.
// Text and title used on the download link/button (indicates an action). # Text and title used on the download link/button (indicates an action).
downloadButtonLabel = بارگیری downloadButtonLabel = بارگیری
downloadNotification = بارگیری شما کامل شد. downloadNotification = بارگیری شما کامل شد.
downloadFinish = بارگیری کامل شد downloadFinish = بارگیری کامل شد
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)". # This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
fileSizeProgress = ({ $partialSize } از { $totalSize }) fileSizeProgress = ({ $partialSize } از { $totalSize })
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
sendYourFilesLink = Firefox Send را امتحان کنید sendYourFilesLink = Firefox Send را امتحان کنید
downloadingPageProgress = دریافت { $filename } ({ $size }) downloadingPageProgress = دریافت { $filename } ({ $size })
downloadingPageMessage = لطفا این زبانه را باز بگذارید در حالی که ما فایل شما را دریافت می‌کنیم و کدگذاری می‌کنیم. downloadingPageMessage = لطفا این زبانه را باز بگذارید در حالی که ما فایل شما را دریافت می‌کنیم و کدگذاری می‌کنیم.
@@ -71,7 +71,7 @@ fileTooBig = این پرونده بسیار حجیم است. حجم آن می‌
linkExpiredAlt = پیوند منقضی شده است linkExpiredAlt = پیوند منقضی شده است
expiredPageHeader = پیوند منقضی شده است یا در از همان ابتدا وجود نداشته است! expiredPageHeader = پیوند منقضی شده است یا در از همان ابتدا وجود نداشته است!
notSupportedHeader = مرورگر شما پشتیبانی نمی‌کند. notSupportedHeader = مرورگر شما پشتیبانی نمی‌کند.
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
notSupportedDetail = متاسفانه این مرورگر این تکنولوژی وب را که به Firefox Send قدرت می‌بخشد را پشتیبانی نمی‌کند. شما بایستی مرورگری دیگری را امتحان کنید. پیشنهاد ما به شما فایرفاکس است ! notSupportedDetail = متاسفانه این مرورگر این تکنولوژی وب را که به Firefox Send قدرت می‌بخشد را پشتیبانی نمی‌کند. شما بایستی مرورگری دیگری را امتحان کنید. پیشنهاد ما به شما فایرفاکس است !
notSupportedLink = چرا مرورگر من پشتیبانی نمی‌کند؟ notSupportedLink = چرا مرورگر من پشتیبانی نمی‌کند؟
notSupportedOutdatedDetail = متاسفانه این نسخه از فایرفاکس این تکنولوژی وب که به Firefox Send قدرت می‌بخشد را پشتیبانی نمی‌کند. شما نیاز دارید تا مرورگر خود را بروز کنید. notSupportedOutdatedDetail = متاسفانه این نسخه از فایرفاکس این تکنولوژی وب که به Firefox Send قدرت می‌بخشد را پشتیبانی نمی‌کند. شما نیاز دارید تا مرورگر خود را بروز کنید.
@@ -79,7 +79,7 @@ updateFirefox = بروزرسانی فایرفاکس
downloadFirefoxButtonSub = دریافت رایگان downloadFirefoxButtonSub = دریافت رایگان
uploadedFile = پرونده‌ uploadedFile = پرونده‌
copyFileList = رونوشت از نشانی copyFileList = رونوشت از نشانی
// expiryFileList is used as a column header # expiryFileList is used as a column header
expiryFileList = زمان انقضا expiryFileList = زمان انقضا
deleteFileList = حذف deleteFileList = حذف
nevermindButton = بیخیال nevermindButton = بیخیال
@@ -92,7 +92,7 @@ deletePopupCancel = انصراف
deleteButtonHover = حذف deleteButtonHover = حذف
copyUrlHover = رونوشت از نشانی copyUrlHover = رونوشت از نشانی
footerLinkLegal = ملاحظات حقوقی footerLinkLegal = ملاحظات حقوقی
// Test Pilot is a proper name and should not be localized. # Test Pilot is a proper name and should not be localized.
footerLinkAbout = درباره Test Pilot footerLinkAbout = درباره Test Pilot
footerLinkPrivacy = حریم‌خصوصی footerLinkPrivacy = حریم‌خصوصی
footerLinkTerms = شرایط footerLinkTerms = شرایط
@@ -101,13 +101,17 @@ requirePasswordCheckbox = دریافت این پرونده نیاز به گذر
addPasswordButton = افزودن گذرواژه addPasswordButton = افزودن گذرواژه
changePasswordButton = تغییر changePasswordButton = تغییر
passwordTryAgain = کلمه عبور اشتباه است. مجدد تلاش کنید. passwordTryAgain = کلمه عبور اشتباه است. مجدد تلاش کنید.
// This label is followed by the password needed to download a file
passwordResult = گذرواژه: { $password }
reportIPInfringement = گزارش تخلف IP reportIPInfringement = گزارش تخلف IP
javascriptRequired = Firefox Send نیازمند جاوااسکریپت است javascriptRequired = Firefox Send نیازمند جاوااسکریپت است
whyJavascript = چراFirefox Send جاوااسکریپت لازم دارد؟ whyJavascript = چراFirefox Send جاوااسکریپت لازم دارد؟
enableJavascript = لطفا جاوااسکریپت را فعال کنید و مجددا تلاش کنید. enableJavascript = لطفا جاوااسکریپت را فعال کنید و مجددا تلاش کنید.
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m" # A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
expiresHoursMinutes = { $hours }ساعت { $minutes }دقیقه expiresHoursMinutes = { $hours }ساعت { $minutes }دقیقه
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m" # A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
expiresMinutes = { $minutes } دقیقه expiresMinutes = { $minutes } دقیقه
# A short status message shown when a password is successfully set
passwordIsSet = گذرواژه تنظیم شد
# A short status message shown when the user enters a long password
maxPasswordLength = حداکثر اندازهٔ گذرواژه: { $length }
# A short status message shown when there was an error setting the password
passwordSetError = امکان ثبت این گذواژه نیست

View File

@@ -103,8 +103,6 @@ requirePasswordCheckbox = Om dit bestân te downloaden is in wachtwurd fereaske
addPasswordButton = Wachtwurd tafoegje addPasswordButton = Wachtwurd tafoegje
changePasswordButton = Wizigje changePasswordButton = Wizigje
passwordTryAgain = Net krekt wachtwurd. Probearje it opnij. passwordTryAgain = Net krekt wachtwurd. Probearje it opnij.
# This label is followed by the password needed to download a file
passwordResult = Wachtwurd: { $password }
reportIPInfringement = IP-ynbrek melde reportIPInfringement = IP-ynbrek melde
javascriptRequired = Firefox Send fereasket JavaScript. javascriptRequired = Firefox Send fereasket JavaScript.
whyJavascript = Werom hat Firefox Send JavaScript nedich? whyJavascript = Werom hat Firefox Send JavaScript nedich?
@@ -115,3 +113,7 @@ expiresHoursMinutes = { $hours }o { $minutes }m
expiresMinutes = { $minutes }m expiresMinutes = { $minutes }m
# A short status message shown when a password is successfully set # A short status message shown when a password is successfully set
passwordIsSet = Wachtwurd ynsteld passwordIsSet = Wachtwurd ynsteld
# A short status message shown when the user enters a long password
maxPasswordLength = Maksimale wachtwurdlingte: { $length }
# A short status message shown when there was an error setting the password
passwordSetError = Dit wachtwurd koe net ynsteld wurde

View File

@@ -1,4 +1,4 @@
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
title = Firefox Send title = Firefox Send
siteSubtitle = un experimento web siteSubtitle = un experimento web
siteFeedback = Reaction siteFeedback = Reaction
@@ -39,29 +39,29 @@ copyUrlFormButton = Copiar al area de transferentia
copiedUrl = Copiate! copiedUrl = Copiate!
deleteFileButton = Deler le file deleteFileButton = Deler le file
sendAnotherFileLink = Inviar un altere file sendAnotherFileLink = Inviar un altere file
// Alternative text used on the download link/button (indicates an action). # Alternative text used on the download link/button (indicates an action).
downloadAltText = Discargar downloadAltText = Discargar
downloadsFileList = Discargamentos downloadsFileList = Discargamentos
// Used as header in a column indicating the amount of time left before a # Used as header in a column indicating the amount of time left before a
// download link expires (e.g. "10h 5m") # download link expires (e.g. "10h 5m")
timeFileList = Tempore timeFileList = Tempore
// Used as header in a column indicating the number of times a file has been # Used as header in a column indicating the number of times a file has been
// downloaded # downloaded
downloadFileName = Discargar { $filename } downloadFileName = Discargar { $filename }
downloadFileSize = ({ $size }) downloadFileSize = ({ $size })
unlockInputLabel = Insere le contrasigno unlockInputLabel = Insere le contrasigno
unlockInputPlaceholder = Contrasigno unlockInputPlaceholder = Contrasigno
unlockButtonLabel = Disblocar unlockButtonLabel = Disblocar
downloadFileTitle = Discargar le file cryptate downloadFileTitle = Discargar le file cryptate
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
downloadMessage = Tu amico te invia un file per Firefox Send, un servicio que te permitte de compartir files per un ligamine secur, private e cryptate, que expira automaticamente pro te assecurar que tu datos non resta online per sempre. downloadMessage = Tu amico te invia un file per Firefox Send, un servicio que te permitte de compartir files per un ligamine secur, private e cryptate, que expira automaticamente pro te assecurar que tu datos non resta online per sempre.
// Text and title used on the download link/button (indicates an action). # Text and title used on the download link/button (indicates an action).
downloadButtonLabel = Discargar downloadButtonLabel = Discargar
downloadNotification = Tu discargamento es completate. downloadNotification = Tu discargamento es completate.
downloadFinish = Discargamento completate downloadFinish = Discargamento completate
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)". # This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
fileSizeProgress = ({ $partialSize } de { $totalSize }) fileSizeProgress = ({ $partialSize } de { $totalSize })
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
sendYourFilesLink = Proba Firefox Send sendYourFilesLink = Proba Firefox Send
downloadingPageProgress = Discargamento de { $filename } ({ $size }) downloadingPageProgress = Discargamento de { $filename } ({ $size })
downloadingPageMessage = Per favor lassa iste scheda aperte durante que nos prende tu file e lo decifra. downloadingPageMessage = Per favor lassa iste scheda aperte durante que nos prende tu file e lo decifra.
@@ -73,7 +73,7 @@ fileTooBig = Iste file es troppo grande pro lo cargar. Illo debe ser inferior a
linkExpiredAlt = Ligamine expirate linkExpiredAlt = Ligamine expirate
expiredPageHeader = Iste ligamine expirava o illo non existeva jammais! expiredPageHeader = Iste ligamine expirava o illo non existeva jammais!
notSupportedHeader = Tu navigator non es supportate notSupportedHeader = Tu navigator non es supportate
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
notSupportedDetail = Infelicemente iste navigator non supporta le nove technologias web que move Firefox Send. Tu besonia de probar un altere navigator. Nos recommenda Firefox! notSupportedDetail = Infelicemente iste navigator non supporta le nove technologias web que move Firefox Send. Tu besonia de probar un altere navigator. Nos recommenda Firefox!
notSupportedLink = Perque iste navigator non es supportate? notSupportedLink = Perque iste navigator non es supportate?
notSupportedOutdatedDetail = Infelicemente iste version de Firefox non supporta le nove technologias web que move Firefox Send. Tu besonia de actualisar tu navigator. notSupportedOutdatedDetail = Infelicemente iste version de Firefox non supporta le nove technologias web que move Firefox Send. Tu besonia de actualisar tu navigator.
@@ -81,7 +81,7 @@ updateFirefox = Actualisar Firefox
downloadFirefoxButtonSub = Discargamento gratuite downloadFirefoxButtonSub = Discargamento gratuite
uploadedFile = File uploadedFile = File
copyFileList = Copiar le URL copyFileList = Copiar le URL
// expiryFileList is used as a column header # expiryFileList is used as a column header
expiryFileList = Expira in expiryFileList = Expira in
deleteFileList = Deler deleteFileList = Deler
nevermindButton = No, gratias nevermindButton = No, gratias
@@ -94,7 +94,7 @@ deletePopupCancel = Cancellar
deleteButtonHover = Deler deleteButtonHover = Deler
copyUrlHover = Copiar le URL copyUrlHover = Copiar le URL
footerLinkLegal = Legal footerLinkLegal = Legal
// Test Pilot is a proper name and should not be localized. # Test Pilot is a proper name and should not be localized.
footerLinkAbout = Re Test Pilot footerLinkAbout = Re Test Pilot
footerLinkPrivacy = Confidentialitate footerLinkPrivacy = Confidentialitate
footerLinkTerms = Terminos footerLinkTerms = Terminos
@@ -103,13 +103,17 @@ requirePasswordCheckbox = Requirer un contrasigno pro discargar iste file
addPasswordButton = Adder contrasigno addPasswordButton = Adder contrasigno
changePasswordButton = Cambiar changePasswordButton = Cambiar
passwordTryAgain = Contrasigno incorrecte. Retenta. passwordTryAgain = Contrasigno incorrecte. Retenta.
// This label is followed by the password needed to download a file
passwordResult = Contrasigno: { $password }
reportIPInfringement = Reportar un violation de proprietate intellectual reportIPInfringement = Reportar un violation de proprietate intellectual
javascriptRequired = Firefox Send require JavaScript javascriptRequired = Firefox Send require JavaScript
whyJavascript = Proque Firefox Send require JavaScript? whyJavascript = Proque Firefox Send require JavaScript?
enableJavascript = Por favor activa JavaScript e tenta novemente. enableJavascript = Por favor activa JavaScript e tenta novemente.
// A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m" # A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
expiresHoursMinutes = { $hours }h { $minutes }m expiresHoursMinutes = { $hours }h { $minutes }m
// A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m" # A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
expiresMinutes = { $minutes }m expiresMinutes = { $minutes }m
# A short status message shown when a password is successfully set
passwordIsSet = Configuration del contrasigno
# A short status message shown when the user enters a long password
maxPasswordLength = Maxime longor del contrasigno: { $length }
# A short status message shown when there was an error setting the password
passwordSetError = Iste contrasigno non pote ser definite

View File

@@ -103,8 +103,6 @@ requirePasswordCheckbox = Krever et passord for å laste ned denne filen
addPasswordButton = Legg til passord addPasswordButton = Legg til passord
changePasswordButton = Endre changePasswordButton = Endre
passwordTryAgain = Feil passord. Prøv igjen. passwordTryAgain = Feil passord. Prøv igjen.
# This label is followed by the password needed to download a file
passwordResult = Passord: { $password }
reportIPInfringement = Rapporter brudd på åndsverk reportIPInfringement = Rapporter brudd på åndsverk
javascriptRequired = Firefox Send krever JavaScript. javascriptRequired = Firefox Send krever JavaScript.
whyJavascript = Hvorfor krever Firefox Send JavaScript? whyJavascript = Hvorfor krever Firefox Send JavaScript?
@@ -115,3 +113,7 @@ expiresHoursMinutes = { $hours }t { $minutes }m
expiresMinutes = { $minutes }m expiresMinutes = { $minutes }m
# A short status message shown when a password is successfully set # A short status message shown when a password is successfully set
passwordIsSet = Passord satt passwordIsSet = Passord satt
# A short status message shown when the user enters a long password
maxPasswordLength = Maksimum passordlengde: { $length }
# A short status message shown when there was an error setting the password
passwordSetError = Dette passordet kunne ikke settes

View File

@@ -1,4 +1,4 @@
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
title = Firefox Send title = Firefox Send
siteSubtitle = un experiment web siteSubtitle = un experiment web
siteFeedback = Feedback siteFeedback = Feedback
@@ -17,6 +17,7 @@ verifyingFile = Se verifică...
encryptingFile = Se criptează… encryptingFile = Se criptează…
decryptingFile = Se decriptează… decryptingFile = Se decriptează…
notifyUploadDone = Încărcarea s-a finalizat. notifyUploadDone = Încărcarea s-a finalizat.
uploadingPageMessage = După ce fișierul tău este încărcat vei putea seta opțiuni de expirare.
uploadingPageCancel = Anulează încărcarea uploadingPageCancel = Anulează încărcarea
uploadCancelNotification = Încărcarea a fost anulată. uploadCancelNotification = Încărcarea a fost anulată.
uploadingPageLargeFileMessage = Stai calm! Acest fișier este mare. S-ar putea să dureze un timp încărcarea. uploadingPageLargeFileMessage = Stai calm! Acest fișier este mare. S-ar putea să dureze un timp încărcarea.
@@ -25,7 +26,14 @@ uploadSuccessConfirmHeader = Pregătit pentru trimitere
uploadSvgAlt = Încarcă uploadSvgAlt = Încarcă
uploadSuccessTimingHeader = Linkul către fișierul tău va expira după 1 descărcare sau în 24 de ore. uploadSuccessTimingHeader = Linkul către fișierul tău va expira după 1 descărcare sau în 24 de ore.
expireInfo = Linkul la fișier va expira după { $downloadCount } sau { $timespan }. expireInfo = Linkul la fișier va expira după { $downloadCount } sau { $timespan }.
timespanHours = { $num -> downloadCount =
{ $num ->
[one] 1 descărcare
[few] { $num } descărcări
*[other] { $num } de descărcări
}
timespanHours =
{ $num ->
[one] 1 oră [one] 1 oră
[few] ore [few] ore
*[other] de ore *[other] de ore
@@ -35,29 +43,29 @@ copyUrlFormButton = Copiază în clipboard
copiedUrl = Copiat! copiedUrl = Copiat!
deleteFileButton = Șterge fișierul deleteFileButton = Șterge fișierul
sendAnotherFileLink = Trimite un alt fișier sendAnotherFileLink = Trimite un alt fișier
// Alternative text used on the download link/button (indicates an action). # Alternative text used on the download link/button (indicates an action).
downloadAltText = Descarcă downloadAltText = Descarcă
downloadsFileList = Descărcări downloadsFileList = Descărcări
// Used as header in a column indicating the amount of time left before a # Used as header in a column indicating the amount of time left before a
// download link expires (e.g. "10h 5m") # download link expires (e.g. "10h 5m")
timeFileList = Timp timeFileList = Timp
// Used as header in a column indicating the number of times a file has been # Used as header in a column indicating the number of times a file has been
// downloaded # downloaded
downloadFileName = Descarcă { $filename } downloadFileName = Descarcă { $filename }
downloadFileSize = ({ $size }) downloadFileSize = ({ $size })
unlockInputLabel = Introdu parola unlockInputLabel = Introdu parola
unlockInputPlaceholder = Parolă unlockInputPlaceholder = Parolă
unlockButtonLabel = Deblochează unlockButtonLabel = Deblochează
downloadFileTitle = Descarcă fișierul criptat downloadFileTitle = Descarcă fișierul criptat
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
downloadMessage = Un prieten îți trimite un fișier prin Firefox Send, un serviciu care îți permite să împărtășești un fișier printr-un link sigur, privat și criptat care expiră automat pentru a păstra informațiile tale online doar temporar. downloadMessage = Un prieten îți trimite un fișier prin Firefox Send, un serviciu care îți permite să împărtășești un fișier printr-un link sigur, privat și criptat care expiră automat pentru a păstra informațiile tale online doar temporar.
// Text and title used on the download link/button (indicates an action). # Text and title used on the download link/button (indicates an action).
downloadButtonLabel = Descarcă downloadButtonLabel = Descarcă
downloadNotification = Descărcarea s-a încheiat. downloadNotification = Descărcarea s-a încheiat.
downloadFinish = Descărcare încheiată downloadFinish = Descărcare încheiată
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)". # This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
fileSizeProgress = ({ $partialSize } din { $totalSize }) fileSizeProgress = ({ $partialSize } din { $totalSize })
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
sendYourFilesLink = Încearcă Firefox Send sendYourFilesLink = Încearcă Firefox Send
downloadingPageProgress = Se descarcă { $filename } ({ $size }) downloadingPageProgress = Se descarcă { $filename } ({ $size })
downloadingPageMessage = Te rugăm să păstrezi această file deschisă în timp ce preluăm fișierul și îl decriptăm. downloadingPageMessage = Te rugăm să păstrezi această file deschisă în timp ce preluăm fișierul și îl decriptăm.
@@ -69,7 +77,7 @@ fileTooBig = Acest fișier este prea mare. Trebuie să fie sub { $size }.
linkExpiredAlt = Link expirat linkExpiredAlt = Link expirat
expiredPageHeader = Acest link a expirat sau nu a existat de la bun început! expiredPageHeader = Acest link a expirat sau nu a existat de la bun început!
notSupportedHeader = Browserul tău nu este suportat. notSupportedHeader = Browserul tău nu este suportat.
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
notSupportedDetail = Din păcate acest browser nu suportă tehnologii web precum Firefox Send. Trebuie să încerci alt browser. Îți recomandăm Firefox! notSupportedDetail = Din păcate acest browser nu suportă tehnologii web precum Firefox Send. Trebuie să încerci alt browser. Îți recomandăm Firefox!
notSupportedLink = De ce browserul meu nu este suportat? notSupportedLink = De ce browserul meu nu este suportat?
notSupportedOutdatedDetail = Din păcate această versiune de Firefox nu suportă tehnologiile web din spatele Firefox Sent. Îți recomandăm să actualizezi browserul. notSupportedOutdatedDetail = Din păcate această versiune de Firefox nu suportă tehnologiile web din spatele Firefox Sent. Îți recomandăm să actualizezi browserul.
@@ -77,7 +85,7 @@ updateFirefox = Actualizează Firefox
downloadFirefoxButtonSub = Descărcare gratuită downloadFirefoxButtonSub = Descărcare gratuită
uploadedFile = Fișier uploadedFile = Fișier
copyFileList = Copiază URL-ul copyFileList = Copiază URL-ul
// expiryFileList is used as a column header # expiryFileList is used as a column header
expiryFileList = Expiră în expiryFileList = Expiră în
deleteFileList = Șterge deleteFileList = Șterge
nevermindButton = Uită nevermindButton = Uită
@@ -90,7 +98,7 @@ deletePopupCancel = Renunță
deleteButtonHover = Șterge deleteButtonHover = Șterge
copyUrlHover = Copiază URL-ul copyUrlHover = Copiază URL-ul
footerLinkLegal = Mențiuni legale footerLinkLegal = Mențiuni legale
// Test Pilot is a proper name and should not be localized. # Test Pilot is a proper name and should not be localized.
footerLinkAbout = Despre Test Pilot footerLinkAbout = Despre Test Pilot
footerLinkPrivacy = Confidențialitate footerLinkPrivacy = Confidențialitate
footerLinkTerms = Termeni footerLinkTerms = Termeni
@@ -99,6 +107,17 @@ requirePasswordCheckbox = Este necesară o parolă pentru a descărca acest fiș
addPasswordButton = Adaugă parolă addPasswordButton = Adaugă parolă
changePasswordButton = Modifică changePasswordButton = Modifică
passwordTryAgain = Parola este incorectă. Încearcă din nou. passwordTryAgain = Parola este incorectă. Încearcă din nou.
// This label is followed by the password needed to download a file
passwordResult = Parola: { $password }
reportIPInfringement = Raportează încălcarea proprietății intelectuale reportIPInfringement = Raportează încălcarea proprietății intelectuale
javascriptRequired = Firefox Send are nevoie de JavaScript
whyJavascript = De ce are nevoie Firefox Send de JavaScript?
enableJavascript = Te rugăm să reactivezi JavaScript și să încerci din nou.
# A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
expiresHoursMinutes = { $hours }h { $minutes }m
# A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
expiresMinutes = { $minutes } m
# A short status message shown when a password is successfully set
passwordIsSet = Parola a fost setată
# A short status message shown when the user enters a long password
maxPasswordLength = Lungime minimă a parolei: { $length }
# A short status message shown when there was an error setting the password
passwordSetError = Această parola nu a putut fi setată

View File

@@ -107,8 +107,6 @@ requirePasswordCheckbox = Zahtevaj geslo za prenos te datoteke
addPasswordButton = Dodaj geslo addPasswordButton = Dodaj geslo
changePasswordButton = Spremeni changePasswordButton = Spremeni
passwordTryAgain = Napačno geslo. Poskusite znova. passwordTryAgain = Napačno geslo. Poskusite znova.
# This label is followed by the password needed to download a file
passwordResult = Geslo: { $password }
reportIPInfringement = Prijavite kršitev naslova IP reportIPInfringement = Prijavite kršitev naslova IP
javascriptRequired = Firefox Send zahteva JavaScript javascriptRequired = Firefox Send zahteva JavaScript
whyJavascript = Zakaj Firefox Send zahteva JavaScript? whyJavascript = Zakaj Firefox Send zahteva JavaScript?
@@ -119,3 +117,7 @@ expiresHoursMinutes = { $hours }h { $minutes }m
expiresMinutes = { $minutes }m expiresMinutes = { $minutes }m
# A short status message shown when a password is successfully set # A short status message shown when a password is successfully set
passwordIsSet = Geslo je nastavljeno passwordIsSet = Geslo je nastavljeno
# A short status message shown when the user enters a long password
maxPasswordLength = Največja dolžina gesla: { $length }
# A short status message shown when there was an error setting the password
passwordSetError = Gesla ni mogoče nastaviti

View File

@@ -102,8 +102,6 @@ requirePasswordCheckbox = Mangailangan ng isang password upang i-download ang fi
addPasswordButton = Magdagdag ng password addPasswordButton = Magdagdag ng password
changePasswordButton = Palitan changePasswordButton = Palitan
passwordTryAgain = Maling password. Subukan muli. passwordTryAgain = Maling password. Subukan muli.
# This label is followed by the password needed to download a file
passwordResult = Password: { $password }
reportIPInfringement = Report IP Infringement reportIPInfringement = Report IP Infringement
javascriptRequired = Nangangailangan ang JavaScript sa JavaScript javascriptRequired = Nangangailangan ang JavaScript sa JavaScript
whyJavascript = Bakit ang JavaScript ay nangangailangan ng JavaScript? whyJavascript = Bakit ang JavaScript ay nangangailangan ng JavaScript?
@@ -114,3 +112,7 @@ expiresHoursMinutes = { $hours }h { $minutes }m
expiresMinutes = { $minutes }m expiresMinutes = { $minutes }m
# A short status message shown when a password is successfully set # A short status message shown when a password is successfully set
passwordIsSet = I-set ang password passwordIsSet = I-set ang password
# A short status message shown when the user enters a long password
maxPasswordLength = Pinakamataas na haba ng password: { $length }
# A short status message shown when there was an error setting the password
passwordSetError = Hindi maitakda ang password na ito

View File

@@ -1,4 +1,4 @@
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
title = Firefox Send title = Firefox Send
siteSubtitle = веб-експеримент siteSubtitle = веб-експеримент
siteFeedback = Відгуки siteFeedback = Відгуки
@@ -41,23 +41,29 @@ copyUrlFormButton = Копіювати у буфер обміну
copiedUrl = Скопійовано! copiedUrl = Скопійовано!
deleteFileButton = Видалити файл deleteFileButton = Видалити файл
sendAnotherFileLink = Надіслати інший файл sendAnotherFileLink = Надіслати інший файл
// Alternative text used on the download link/button (indicates an action). # Alternative text used on the download link/button (indicates an action).
downloadAltText = Завантаживи downloadAltText = Завантаживи
downloadsFileList = Завантажень
# Used as header in a column indicating the amount of time left before a
# download link expires (e.g. "10h 5m")
timeFileList = Дійсний
# Used as header in a column indicating the number of times a file has been
# downloaded
downloadFileName = Завантажити { $filename } downloadFileName = Завантажити { $filename }
downloadFileSize = ({ $size }) downloadFileSize = ({ $size })
unlockInputLabel = Введіть пароль unlockInputLabel = Введіть пароль
unlockInputPlaceholder = Пароль unlockInputPlaceholder = Пароль
unlockButtonLabel = Розблокувати unlockButtonLabel = Розблокувати
downloadFileTitle = Завантажити зашифрований файл downloadFileTitle = Завантажити зашифрований файл
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
downloadMessage = Ваш друг надіслав файл за допомогою Firefox Send, який дозволяє ділитися файлами, використовуючи безпечні, приватні та зашифровані посилання, термін дії яких автоматично закінчується, щоб ваші файли не лишилися в Інтернеті назавжди. downloadMessage = Ваш друг надіслав файл за допомогою Firefox Send, який дозволяє ділитися файлами, використовуючи безпечні, приватні та зашифровані посилання, термін дії яких автоматично закінчується, щоб ваші файли не лишилися в Інтернеті назавжди.
// Text and title used on the download link/button (indicates an action). # Text and title used on the download link/button (indicates an action).
downloadButtonLabel = Завантажити downloadButtonLabel = Завантажити
downloadNotification = Ваше завантаження готово. downloadNotification = Ваше завантаження готово.
downloadFinish = Завантаження готово downloadFinish = Завантаження готово
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)". # This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
fileSizeProgress = ({ $partialSize } з { $totalSize }) fileSizeProgress = ({ $partialSize } з { $totalSize })
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
sendYourFilesLink = Спробуйте Firefox Send sendYourFilesLink = Спробуйте Firefox Send
downloadingPageProgress = Завантаження { $filename } ({ $size }) downloadingPageProgress = Завантаження { $filename } ({ $size })
downloadingPageMessage = Будь ласка, залиште цю вкладку відкритою, поки ми завантажуємо ваш файл і розшифровуємо його. downloadingPageMessage = Будь ласка, залиште цю вкладку відкритою, поки ми завантажуємо ваш файл і розшифровуємо його.
@@ -69,7 +75,7 @@ fileTooBig = Цей файл завеликий для вивантаження.
linkExpiredAlt = Час дії посилання минув linkExpiredAlt = Час дії посилання минув
expiredPageHeader = Посилання не існує, або час його дії минув! expiredPageHeader = Посилання не існує, або час його дії минув!
notSupportedHeader = Ваш браузер не підтримується. notSupportedHeader = Ваш браузер не підтримується.
// Firefox Send is a brand name and should not be localized. # Firefox Send is a brand name and should not be localized.
notSupportedDetail = На жаль, цей браузер не підтримує веб-технологію, завдяки якій працює Firefox Send. Вам треба скористатися іншим браузером. Ми рекомендуємо Firefox! notSupportedDetail = На жаль, цей браузер не підтримує веб-технологію, завдяки якій працює Firefox Send. Вам треба скористатися іншим браузером. Ми рекомендуємо Firefox!
notSupportedLink = Чому мій браузер не підтримується? notSupportedLink = Чому мій браузер не підтримується?
notSupportedOutdatedDetail = На жаль, ця версія Firefox не підтримує веб-технологію, завдяки якій працює Firefox Send. Вам потрібно оновити свій браузер. notSupportedOutdatedDetail = На жаль, ця версія Firefox не підтримує веб-технологію, завдяки якій працює Firefox Send. Вам потрібно оновити свій браузер.
@@ -77,7 +83,7 @@ updateFirefox = Оновити Firefox
downloadFirefoxButtonSub = Безкоштовне завантаження downloadFirefoxButtonSub = Безкоштовне завантаження
uploadedFile = Файл uploadedFile = Файл
copyFileList = Копіювати URL copyFileList = Копіювати URL
// expiryFileList is used as a column header # expiryFileList is used as a column header
expiryFileList = Термін дії закінчується expiryFileList = Термін дії закінчується
deleteFileList = Видалити deleteFileList = Видалити
nevermindButton = Не важливо nevermindButton = Не важливо
@@ -90,14 +96,26 @@ deletePopupCancel = Скасувати
deleteButtonHover = Видалити deleteButtonHover = Видалити
copyUrlHover = Копіювати URL copyUrlHover = Копіювати URL
footerLinkLegal = Права footerLinkLegal = Права
// Test Pilot is a proper name and should not be localized. # Test Pilot is a proper name and should not be localized.
footerLinkAbout = Про Test Pilot footerLinkAbout = Про Test Pilot
footerLinkPrivacy = Приватність footerLinkPrivacy = Приватність
footerLinkTerms = Умови footerLinkTerms = Умови
footerLinkCookies = Куки footerLinkCookies = Куки
requirePasswordCheckbox = Вимагати пароль для завантаження цього файлу requirePasswordCheckbox = Вимагати пароль для завантаження цього файлу
addPasswordButton = Додати пароль addPasswordButton = Додати пароль
changePasswordButton = Змінити
passwordTryAgain = Невірний пароль. Спробуйте знову. passwordTryAgain = Невірний пароль. Спробуйте знову.
// This label is followed by the password needed to download a file
passwordResult = Пароль: { $password }
reportIPInfringement = Повідомити про порушення прав на інтелектуальну власність reportIPInfringement = Повідомити про порушення прав на інтелектуальну власність
javascriptRequired = Firefox Send потребує JavaScript
whyJavascript = Чому для Firefox Send потрібен JavaScript?
enableJavascript = Будь ласка, увімкніть JavaScript та спробуйте знову.
# A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
expiresHoursMinutes = { $hours } год. { $minutes } хв.
# A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
expiresMinutes = { $minutes } хв.
# A short status message shown when a password is successfully set
passwordIsSet = Пароль встановлено
# A short status message shown when the user enters a long password
maxPasswordLength = Найбільша довжина паролю: { $length }
# A short status message shown when there was an error setting the password
passwordSetError = Неможливо встановити цей пароль

View File

@@ -69,6 +69,7 @@ module.exports = function(state, body = '') {
<script defer src="${assets.get('runtime.js')}"></script> <script defer src="${assets.get('runtime.js')}"></script>
<script defer src="${assets.get('vendor.js')}"></script> <script defer src="${assets.get('vendor.js')}"></script>
<script defer src="${locales.get(state.locale)}"></script> <script defer src="${locales.get(state.locale)}"></script>
<script defer src="${assets.get('cryptofill.js')}"></script>
<script defer src="${assets.get('app.js')}"></script> <script defer src="${assets.get('app.js')}"></script>
</head> </head>
${body} ${body}

View File

@@ -4,6 +4,10 @@ const fs = require('fs');
const path = require('path'); const path = require('path');
const { negotiateLanguages } = require('fluent-langneg'); const { negotiateLanguages } = require('fluent-langneg');
const langData = require('cldr-core/supplemental/likelySubtags.json'); const langData = require('cldr-core/supplemental/likelySubtags.json');
// We return early in the middleware if the lang header is long.
// If that ever changes we should re-evaluate this regex.
// eslint-disable-next-line security/detect-unsafe-regex
const acceptLanguages = /(([a-zA-Z]+(-[a-zA-Z0-9]+){0,2})|\*)(;q=[0-1](\.[0-9]+)?)?/g; const acceptLanguages = /(([a-zA-Z]+(-[a-zA-Z0-9]+){0,2})|\*)(;q=[0-1](\.[0-9]+)?)?/g;
function allLangs() { function allLangs() {

19
server/readme.md Normal file
View File

@@ -0,0 +1,19 @@
# Server Code
The server provides the API, serves static assets, and renders the pages for Send. The production entrypoint is [prod.js](./prod.js) and the development entrypoint is [dev.js](./dev.js) via `webpack-dev-server`.
## Server configuration
[config.js](./config.js) contains the schema for our configuration options. Environment variables are the preferred method for setting configuration.
## Middleware
Contains authentication and localization middleware.
## Routes
Contains all the server routes and handlers for the API and pages
## Storage
Contains implementations of possible storage engines for the files and metadata

View File

@@ -7,10 +7,10 @@ function kv(f) {
module.exports = function() { module.exports = function() {
const files = fs.readdirSync(path.join(__dirname, 'tests')); const files = fs.readdirSync(path.join(__dirname, 'tests'));
const code = files.map(kv).join(';\n'); const code = "require('fast-text-encoding');\n" + files.map(kv).join(';\n');
return { return {
code, code,
dependencies: files.map(f => require.resolve('./tests/' + f)), dependencies: files.map(f => require.resolve('./tests/' + f)),
cacheable: false cacheable: true
}; };
}; };

View File

@@ -29,6 +29,7 @@ module.exports = function(app) {
}) })
</script> </script>
<script src="/jsconfig.js"></script> <script src="/jsconfig.js"></script>
<script src="${assets.get('cryptofill.js')}"></script>
<script src="${assets.get('runtime.js')}"></script> <script src="${assets.get('runtime.js')}"></script>
<script src="${assets.get('vendor.js')}"></script> <script src="${assets.get('vendor.js')}"></script>
<script src="${assets.get('tests.js')}"></script> <script src="${assets.get('tests.js')}"></script>

View File

@@ -0,0 +1,122 @@
import assert from 'assert';
import { arrayToB64, b64ToArray } from '../../../app/utils';
describe('webcrypto', function() {
it('can do it', async function() {
const encoder = new TextEncoder();
const x = b64ToArray('SPIfAlwbnncIFw3hEHYihw');
const a = await crypto.subtle.importKey('raw', x, 'PBKDF2', false, [
'deriveKey'
]);
const ad = await crypto.subtle.deriveKey(
{
name: 'PBKDF2',
salt: encoder.encode('metadata'),
iterations: 100,
hash: 'SHA-256'
},
a,
{
name: 'AES-GCM',
length: 128
},
false,
['encrypt', 'decrypt']
);
const ae = await crypto.subtle.encrypt(
{
name: 'AES-GCM',
iv: new Uint8Array(12),
tagLength: 128
},
ad,
encoder.encode('hello world!')
);
assert.equal(
arrayToB64(new Uint8Array(ae)),
'UXQQ4yVf55TRk9AZtz5QCwFofRvh-HdWJyxSCQ'
);
const ah = await crypto.subtle.deriveKey(
{
name: 'PBKDF2',
salt: encoder.encode('authentication'),
iterations: 100,
hash: 'SHA-256'
},
a,
{
name: 'HMAC',
hash: { name: 'SHA-256' }
},
true,
['sign']
);
const ahx = await crypto.subtle.exportKey('raw', ah);
assert.equal(
arrayToB64(new Uint8Array(ahx)),
'wxXDmHgmMgrcDVD8zbDLRl2yNa8jSAQgsaeIBZ4vueygpxzaTK6ZE_6X-XHvllBly6pSuFNbSxcve0ZHhVdcEA'
);
// const jwk = await crypto.subtle.exportKey('jwk', ah)
// console.error(jwk)
const as = await crypto.subtle.sign(
{
name: 'HMAC'
},
ah,
encoder.encode('test')
);
assert.equal(
arrayToB64(new Uint8Array(as)),
'AOi4HcoCJxQ4nUYxlmHB1rlcxQBn-zVjrSHz-VW7S-I'
);
const b = await crypto.subtle.importKey('raw', x, 'HKDF', false, [
'deriveKey'
]);
const bd = await crypto.subtle.deriveKey(
{
name: 'HKDF',
salt: new Uint8Array(),
info: encoder.encode('encryption'),
hash: 'SHA-256'
},
b,
{
name: 'AES-GCM',
length: 128
},
true,
['encrypt', 'decrypt']
);
const bdx = await crypto.subtle.exportKey('raw', bd);
assert.equal(arrayToB64(new Uint8Array(bdx)), 'g7okjWWO9yueDz16-owShQ');
const bh = await crypto.subtle.deriveKey(
{
name: 'HKDF',
salt: new Uint8Array(),
info: encoder.encode('authentication'),
hash: 'SHA-256'
},
b,
{
name: 'HMAC',
hash: { name: 'SHA-256' }
},
true,
['sign']
);
const bhx = await crypto.subtle.exportKey('raw', bh);
assert.equal(
arrayToB64(new Uint8Array(bhx)),
'TQOGtmQ8-ZfnWu6Iq-U1IAVBVREFuI17xqsW1shiC8eMCa-a5qeYTvoX3-5kCoCha8R59ycnPDnTz75clLBmbQ'
);
});
});

17
test/readme.md Normal file
View File

@@ -0,0 +1,17 @@
# Tests
To run all the tests use `npm test`. This will run the tests and produce a code coverage report at [coverage/index.html](../coverage/index.html). The full test suite is run as a hook on each `git push`. [Mocha](https://mochajs.org) is our preferred test runner.
## Frontend
Unit tests reside in `test/frontend/tests`.
Frontend tests can be ran in the browser by running `npm start` and then browsing to http://localhost:8080/test. Doing it this way will watch for changes and rerun the suite automatically.
You can also run them in headless Chrome by using `npm run test:frontend`. The results will be printed to the console.
## Backend
Unit tests reside in `test/backend`
Backend test can be run with `npm run test:backend`. [Sinon](http://sinonjs.org/) and [proxyquire](https://github.com/thlorenz/proxyquire) are used for mocking.

View File

@@ -1 +0,0 @@
This is a test.

View File

@@ -8,10 +8,13 @@ const IS_DEV = process.env.NODE_ENV === 'development';
const regularJSOptions = { const regularJSOptions = {
babelrc: false, babelrc: false,
presets: [['env', { modules: false }], 'stage-2'], presets: [['env', { modules: false }], 'stage-2'],
// yo-yoify converts html template strings to direct dom api calls
plugins: ['yo-yoify'] plugins: ['yo-yoify']
}; };
const entry = { const entry = {
// babel-polyfill and fluent are directly included in vendor
// because they are not explicitly referenced by app
vendor: ['babel-polyfill', 'fluent'], vendor: ['babel-polyfill', 'fluent'],
app: ['./app/main.js'], app: ['./app/main.js'],
style: ['./app/main.css'] style: ['./app/main.css']
@@ -19,6 +22,7 @@ const entry = {
if (IS_DEV) { if (IS_DEV) {
entry.tests = ['./test/frontend/index.js']; entry.tests = ['./test/frontend/index.js'];
// istanbul instruments the source for code coverage
regularJSOptions.plugins.push('istanbul'); regularJSOptions.plugins.push('istanbul');
} }
@@ -47,6 +51,7 @@ module.exports = {
] ]
}, },
{ {
// inlines version from package.json into header/index.js
include: require.resolve('./app/templates/header'), include: require.resolve('./app/templates/header'),
use: [ use: [
{ {
@@ -57,6 +62,8 @@ module.exports = {
] ]
}, },
{ {
// fluent gets exposed as a global so that each language script
// can load independently and share it.
include: [path.dirname(require.resolve('fluent'))], include: [path.dirname(require.resolve('fluent'))],
use: [ use: [
{ {
@@ -76,6 +83,8 @@ module.exports = {
include: [ include: [
path.resolve(__dirname, 'app'), path.resolve(__dirname, 'app'),
path.resolve(__dirname, 'common'), path.resolve(__dirname, 'common'),
// some dependencies need to get re-babeled because we
// have different targets than their default configs
path.resolve(__dirname, 'node_modules/testpilot-ga/src'), path.resolve(__dirname, 'node_modules/testpilot-ga/src'),
path.resolve(__dirname, 'node_modules/fluent-intl-polyfill'), path.resolve(__dirname, 'node_modules/fluent-intl-polyfill'),
path.resolve(__dirname, 'node_modules/intl-pluralrules') path.resolve(__dirname, 'node_modules/intl-pluralrules')
@@ -83,6 +92,7 @@ module.exports = {
options: regularJSOptions options: regularJSOptions
}, },
{ {
// Strip asserts from our deps, mainly choojs family
include: [path.resolve(__dirname, 'node_modules')], include: [path.resolve(__dirname, 'node_modules')],
loader: 'webpack-unassert-loader' loader: 'webpack-unassert-loader'
} }
@@ -108,15 +118,16 @@ module.exports = {
loader: 'svgo-loader', loader: 'svgo-loader',
options: { options: {
plugins: [ plugins: [
{ removeViewBox: false }, { removeViewBox: false }, // true causes stretched images
{ convertStyleToAttrs: true }, { convertStyleToAttrs: true }, // for CSP, no unsafe-eval
{ removeTitle: true } { removeTitle: true } // for smallness
] ]
} }
} }
] ]
}, },
{ {
// creates style.css with all styles
test: /\.css$/, test: /\.css$/,
use: ExtractTextPlugin.extract({ use: ExtractTextPlugin.extract({
use: [ use: [
@@ -129,6 +140,7 @@ module.exports = {
}) })
}, },
{ {
// creates version.json for /__version__ from package.json
test: require.resolve('./package.json'), test: require.resolve('./package.json'),
use: [ use: [
{ {
@@ -142,6 +154,7 @@ module.exports = {
] ]
}, },
{ {
// creates a js script for each ftl
test: /\.ftl$/, test: /\.ftl$/,
use: [ use: [
{ {
@@ -155,14 +168,17 @@ module.exports = {
] ]
}, },
{ {
// creates test.js for /test
test: require.resolve('./test/frontend/index.js'), test: require.resolve('./test/frontend/index.js'),
use: ['babel-loader', 'val-loader'] use: ['babel-loader', 'val-loader']
}, },
{ {
// loads all assets from assets/ for use by common/assets.js
test: require.resolve('./build/generate_asset_map.js'), test: require.resolve('./build/generate_asset_map.js'),
use: ['babel-loader', 'val-loader'] use: ['babel-loader', 'val-loader']
}, },
{ {
// loads all the ftl from public/locales for use by common/locales.js
test: require.resolve('./build/generate_l10n_map.js'), test: require.resolve('./build/generate_l10n_map.js'),
use: ['babel-loader', 'val-loader'] use: ['babel-loader', 'val-loader']
} }
@@ -175,8 +191,8 @@ module.exports = {
from: '*.*' from: '*.*'
} }
]), ]),
new webpack.IgnorePlugin(/dist/), new webpack.IgnorePlugin(/dist/), // used in common/*.js
new webpack.IgnorePlugin(/require-from-string/), new webpack.IgnorePlugin(/require-from-string/), // used in common/locales.js
new webpack.HashedModuleIdsPlugin(), new webpack.HashedModuleIdsPlugin(),
new webpack.optimize.CommonsChunkPlugin({ new webpack.optimize.CommonsChunkPlugin({
name: 'vendor', name: 'vendor',
@@ -188,10 +204,11 @@ module.exports = {
new ExtractTextPlugin({ new ExtractTextPlugin({
filename: 'style.[contenthash:8].css' filename: 'style.[contenthash:8].css'
}), }),
new ManifestPlugin() new ManifestPlugin() // used by server side to resolve hashed assets
], ],
devServer: { devServer: {
compress: true, compress: true,
host: '0.0.0.0',
before: IS_DEV ? require('./server/dev') : undefined before: IS_DEV ? require('./server/dev') : undefined
} }
}; };