Compare commits
200 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2807b1cad5 | ||
|
|
157e832c95 | ||
|
|
d78fcd3721 | ||
|
|
ac7ab79aef | ||
|
|
00fb353465 | ||
|
|
f0ec5a9496 | ||
|
|
7a31082da1 | ||
|
|
b54f4575ee | ||
|
|
490a1e88eb | ||
|
|
2f8a3c9904 | ||
|
|
e7fdf76120 | ||
|
|
d0d41b743a | ||
|
|
a2995411d6 | ||
|
|
3246c4a621 | ||
|
|
48faf929a4 | ||
|
|
b7f922a999 | ||
|
|
bfcdf9340d | ||
|
|
4ed515f5a3 | ||
|
|
84b2737ffb | ||
|
|
deabca5a94 | ||
|
|
e9a49e23e8 | ||
|
|
cfdef23365 | ||
|
|
7c4b6a9de4 | ||
|
|
bb8866f73f | ||
|
|
33c42648ef | ||
|
|
7feddd2eee | ||
|
|
1344b84cf5 | ||
|
|
ef03b750c5 | ||
|
|
0c07d78a37 | ||
|
|
b5885e446c | ||
|
|
0fa3d4481a | ||
|
|
49e7c2e05b | ||
|
|
2dc7d046ef | ||
|
|
3e0bd41efd | ||
|
|
929eaca2d8 | ||
|
|
60517c5ab6 | ||
|
|
97a8a2b305 | ||
|
|
8fc54bdbe2 | ||
|
|
6ff251b24a | ||
|
|
7237800a91 | ||
|
|
b4cc8e92c7 | ||
|
|
2e233da16d | ||
|
|
b703f78db9 | ||
|
|
13e792cf4d | ||
|
|
552c2d74f3 | ||
|
|
593f23b021 | ||
|
|
1baf83bac3 | ||
|
|
d43ca3190e | ||
|
|
c4c7860876 | ||
|
|
0decdeb37c | ||
|
|
47505dcc31 | ||
|
|
e71d6e792b | ||
|
|
29796cfec8 | ||
|
|
4bdf255c3a | ||
|
|
11efe8b8d1 | ||
|
|
3dd2d09584 | ||
|
|
ed4e8e8f25 | ||
|
|
181a74df88 | ||
|
|
166b2f3a52 | ||
|
|
bd5cdc52f9 | ||
|
|
5d0318c102 | ||
|
|
17adc644fb | ||
|
|
f48159dc0b | ||
|
|
360697c034 | ||
|
|
45dd833b27 | ||
|
|
98491eed01 | ||
|
|
fdafc1c59e | ||
|
|
a32638ed4c | ||
|
|
39080a6046 | ||
|
|
a124d36714 | ||
|
|
7f9e619643 | ||
|
|
db12f2f5c8 | ||
|
|
415e0b70f3 | ||
|
|
0e4b1e5ec7 | ||
|
|
054a97371c | ||
|
|
2b25b6a6ea | ||
|
|
780ed3120e | ||
|
|
bdd3cbd4c7 | ||
|
|
0c8013038f | ||
|
|
c020d59c56 | ||
|
|
a5c336494b | ||
|
|
aaa4655f45 | ||
|
|
ed18ec0bc5 | ||
|
|
1de43f31b6 | ||
|
|
1a04c86edd | ||
|
|
2bbdcae82e | ||
|
|
9b0aa5d601 | ||
|
|
cdc261e30a | ||
|
|
09133a66b0 | ||
|
|
64f1a31533 | ||
|
|
9a92a50a5f | ||
|
|
2afd93e82f | ||
|
|
cb62cc1e9d | ||
|
|
2cd3fc5af9 | ||
|
|
bac710a17f | ||
|
|
fb8b0f78ca | ||
|
|
e18ce15753 | ||
|
|
ed8ce9e3ca | ||
|
|
af5ef04115 | ||
|
|
9530a3df52 | ||
|
|
2794ac653f | ||
|
|
43eb758d73 | ||
|
|
d0364cd101 | ||
|
|
6a008bf312 | ||
|
|
dfb271410c | ||
|
|
789d67209c | ||
|
|
a31f6b75d9 | ||
|
|
f814427a7d | ||
|
|
b0307e92d4 | ||
|
|
7fa3d69aa1 | ||
|
|
58555a6b85 | ||
|
|
52113395db | ||
|
|
8dd1309c21 | ||
|
|
202e428412 | ||
|
|
6e7ed3cea3 | ||
|
|
41cb49141b | ||
|
|
82a8283b6e | ||
|
|
a5d28adc44 | ||
|
|
82e206bccf | ||
|
|
1e4d6646c6 | ||
|
|
acbf9fc32f | ||
|
|
046f227003 | ||
|
|
50ac9e32be | ||
|
|
3459dcaa15 | ||
|
|
9410defab6 | ||
|
|
b5a26e11f8 | ||
|
|
c51481628d | ||
|
|
24fa51a12c | ||
|
|
7328520d05 | ||
|
|
409d206f1e | ||
|
|
b0b393f3d9 | ||
|
|
c4499088c8 | ||
|
|
4cccd6ac5c | ||
|
|
188b28fce3 | ||
|
|
24adda6c7d | ||
|
|
4b49302fbe | ||
|
|
402ab350de | ||
|
|
47b68770af | ||
|
|
60aa16a327 | ||
|
|
5702a4806b | ||
|
|
74c4bdb660 | ||
|
|
203a2cf7fb | ||
|
|
1faa2733b3 | ||
|
|
ffa432a876 | ||
|
|
009fd29265 | ||
|
|
8f05c2324e | ||
|
|
e1ab515883 | ||
|
|
a68a7a60a7 | ||
|
|
b4dc274646 | ||
|
|
b31892bdc6 | ||
|
|
f388a1348d | ||
|
|
52dacbddf9 | ||
|
|
cc52f60aa1 | ||
|
|
1af818b691 | ||
|
|
d76f7758e7 | ||
|
|
48ab2f2400 | ||
|
|
0aa844eebc | ||
|
|
481b02ccf2 | ||
|
|
67e6ef6fda | ||
|
|
7d19f86d7a | ||
|
|
2d27d8a47c | ||
|
|
10fac130ef | ||
|
|
c6b632543d | ||
|
|
32eb8157eb | ||
|
|
3628f22114 | ||
|
|
177fa37041 | ||
|
|
717f6576ea | ||
|
|
f1b2ffa0fa | ||
|
|
ac73c23c73 | ||
|
|
ac40308b1c | ||
|
|
6fb81aa78c | ||
|
|
92430c78c2 | ||
|
|
cb7ddaa295 | ||
|
|
786d079632 | ||
|
|
4af25a505a | ||
|
|
3218803aae | ||
|
|
2311d5bcef | ||
|
|
e56d92334f | ||
|
|
bc24a069da | ||
|
|
837747f8f7 | ||
|
|
a8c32ae49c | ||
|
|
32c5b414de | ||
|
|
12c81a22e8 | ||
|
|
0c5d0d4bb2 | ||
|
|
234f9c624d | ||
|
|
da669b44ff | ||
|
|
3c39f5f085 | ||
|
|
6de91b5872 | ||
|
|
ff9a0979f6 | ||
|
|
e1e8af2489 | ||
|
|
1eb000f615 | ||
|
|
e20fd97e59 | ||
|
|
d10ceacd67 | ||
|
|
208c28ee01 | ||
|
|
cdd1bb3c29 | ||
|
|
3d9c4fa320 | ||
|
|
9c4d18ef3b | ||
|
|
ce9ff3959f | ||
|
|
51aef4e1e5 | ||
|
|
90247059d0 |
3
.nsprc
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"exceptions": ["https://nodesecurity.io/advisories/534"]
|
||||
}
|
||||
14
README.md
@@ -7,6 +7,20 @@
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
* [What it does](#what-it-does)
|
||||
* [Requirements](#requirements)
|
||||
* [Development](#development)
|
||||
* [Commands](#commands)
|
||||
* [Configuration](#configuration)
|
||||
* [Localization](#localization)
|
||||
* [Contributing](#contributing)
|
||||
* [Testing](#testing)
|
||||
* [License](#license)
|
||||
|
||||
---
|
||||
|
||||
## What it does
|
||||
|
||||
A file sharing experiment which allows you to send encrypted files to other users.
|
||||
|
||||
@@ -1,28 +1,20 @@
|
||||
import hash from 'string-hash';
|
||||
|
||||
const experiments = {
|
||||
'5YHCzn2CQTmBwWwTmZupBA': {
|
||||
id: '5YHCzn2CQTmBwWwTmZupBA',
|
||||
'SyI-hI7gT9agiH-f3f0BYg': {
|
||||
id: 'SyI-hI7gT9agiH-f3f0BYg',
|
||||
run: function(variant, state, emitter) {
|
||||
state.experiment = {
|
||||
xid: this.id,
|
||||
xvar: variant
|
||||
};
|
||||
// Beefy UI
|
||||
if (variant === 1) {
|
||||
state.config.uploadWindowStyle = 'upload-window upload-window-b';
|
||||
state.config.uploadButtonStyle = 'btn browse browse-b';
|
||||
} else {
|
||||
state.config.uploadWindowStyle = 'upload-window';
|
||||
state.config.uploadButtonStyle = 'btn browse';
|
||||
}
|
||||
state.promo = variant === 1 ? 'body' : 'header';
|
||||
emitter.emit('render');
|
||||
},
|
||||
eligible: function(state) {
|
||||
return this.luckyNumber(state) >= 0.5;
|
||||
eligible: function() {
|
||||
return (
|
||||
!/firefox/i.test(navigator.userAgent) &&
|
||||
document.querySelector('html').lang === 'en-US'
|
||||
);
|
||||
},
|
||||
variant: function(state) {
|
||||
return this.luckyNumber(state) < 0.75 ? 0 : 1;
|
||||
return this.luckyNumber(state) > 0.5 ? 1 : 0;
|
||||
},
|
||||
luckyNumber: function(state) {
|
||||
return luckyNumber(
|
||||
@@ -33,6 +25,7 @@ const experiments = {
|
||||
};
|
||||
|
||||
//Returns a number between 0 and 1
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function luckyNumber(str) {
|
||||
return hash(str) / 0xffffffff;
|
||||
}
|
||||
@@ -61,12 +54,12 @@ export default function initialize(state, emitter) {
|
||||
checkExperiments(state, emitter);
|
||||
});
|
||||
} else {
|
||||
const enrolled = state.storage.enrolled;
|
||||
enrolled.forEach(([id, variant]) => {
|
||||
const enrolled = state.storage.enrolled.filter(([id, variant]) => {
|
||||
const xp = experiments[id];
|
||||
if (xp) {
|
||||
xp.run(variant, state, emitter);
|
||||
}
|
||||
return !!xp;
|
||||
});
|
||||
// single experiment per session for now
|
||||
if (enrolled.length === 0) {
|
||||
|
||||
@@ -135,6 +135,7 @@ export default function(state, emitter) {
|
||||
const time = Date.now() - start;
|
||||
const speed = size / (time / 1000);
|
||||
metrics.completedUpload({ size, time, speed, type });
|
||||
document.getElementById('cancel-upload').hidden = 'hidden';
|
||||
await delay(1000);
|
||||
await fadeOut('upload-progress');
|
||||
info.name = file.name;
|
||||
@@ -152,6 +153,7 @@ export default function(state, emitter) {
|
||||
state.storage.totalUploads += 1;
|
||||
emitter.emit('pushState', `/share/${info.id}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
state.transfer = null;
|
||||
if (err.message === '0') {
|
||||
//cancelled. do nothing
|
||||
@@ -160,39 +162,69 @@ export default function(state, emitter) {
|
||||
}
|
||||
state.raven.captureException(err);
|
||||
metrics.stoppedUpload({ size, type, err });
|
||||
emitter.emit('replaceState', '/error');
|
||||
emitter.emit('pushState', '/error');
|
||||
}
|
||||
});
|
||||
|
||||
emitter.on('download', async file => {
|
||||
const size = file.size;
|
||||
emitter.on('password', async ({ password, file }) => {
|
||||
try {
|
||||
await FileSender.setPassword(password, file);
|
||||
metrics.addedPassword({ size: file.size });
|
||||
file.password = password;
|
||||
state.storage.writeFiles();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
render();
|
||||
});
|
||||
|
||||
emitter.on('preview', async () => {
|
||||
const file = state.fileInfo;
|
||||
const url = `/api/download/${file.id}`;
|
||||
const receiver = new FileReceiver(url, file.key);
|
||||
const receiver = new FileReceiver(url, file);
|
||||
receiver.on('progress', updateProgress);
|
||||
receiver.on('decrypting', render);
|
||||
state.transfer = receiver;
|
||||
const links = openLinksInNewTab();
|
||||
try {
|
||||
await receiver.getMetadata(file.nonce);
|
||||
} catch (e) {
|
||||
if (e.message === '401') {
|
||||
file.password = null;
|
||||
if (!file.pwd) {
|
||||
return emitter.emit('pushState', '/404');
|
||||
}
|
||||
}
|
||||
}
|
||||
render();
|
||||
});
|
||||
|
||||
emitter.on('download', async file => {
|
||||
state.transfer.on('progress', render);
|
||||
state.transfer.on('decrypting', render);
|
||||
const links = openLinksInNewTab();
|
||||
const size = file.size;
|
||||
try {
|
||||
const start = Date.now();
|
||||
metrics.startedDownload({ size: file.size, ttl: file.ttl });
|
||||
const f = await receiver.download();
|
||||
const f = await state.transfer.download(file.nonce);
|
||||
const time = Date.now() - start;
|
||||
const speed = size / (time / 1000);
|
||||
await delay(1000);
|
||||
await fadeOut('download-progress');
|
||||
saveFile(f);
|
||||
state.storage.totalDownloads += 1;
|
||||
state.transfer = null;
|
||||
metrics.completedDownload({ size, time, speed });
|
||||
emitter.emit('pushState', '/completed');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
// TODO cancelled download
|
||||
const location = err.message === 'notfound' ? '/404' : '/error';
|
||||
if (location === '/error') {
|
||||
state.raven.captureException(err);
|
||||
metrics.stoppedDownload({ size, err });
|
||||
}
|
||||
emitter.emit('replaceState', location);
|
||||
emitter.emit('pushState', location);
|
||||
} finally {
|
||||
state.transfer = null;
|
||||
openLinksInNewTab(links, false);
|
||||
|
||||
@@ -1,25 +1,103 @@
|
||||
import Nanobus from 'nanobus';
|
||||
import { hexToArray, bytes } from './utils';
|
||||
import { arrayToB64, b64ToArray, bytes } from './utils';
|
||||
|
||||
export default class FileReceiver extends Nanobus {
|
||||
constructor(url, k) {
|
||||
constructor(url, file) {
|
||||
super('FileReceiver');
|
||||
this.key = window.crypto.subtle.importKey(
|
||||
'jwk',
|
||||
{
|
||||
k,
|
||||
kty: 'oct',
|
||||
alg: 'A128GCM',
|
||||
ext: true
|
||||
},
|
||||
{
|
||||
name: 'AES-GCM'
|
||||
},
|
||||
this.secretKeyPromise = window.crypto.subtle.importKey(
|
||||
'raw',
|
||||
b64ToArray(file.key),
|
||||
'HKDF',
|
||||
false,
|
||||
['decrypt']
|
||||
['deriveKey']
|
||||
);
|
||||
this.encryptKeyPromise = this.secretKeyPromise.then(sk => {
|
||||
const encoder = new TextEncoder();
|
||||
return window.crypto.subtle.deriveKey(
|
||||
{
|
||||
name: 'HKDF',
|
||||
salt: new Uint8Array(),
|
||||
info: encoder.encode('encryption'),
|
||||
hash: 'SHA-256'
|
||||
},
|
||||
sk,
|
||||
{
|
||||
name: 'AES-GCM',
|
||||
length: 128
|
||||
},
|
||||
false,
|
||||
['decrypt']
|
||||
);
|
||||
});
|
||||
if (file.pwd) {
|
||||
const encoder = new TextEncoder();
|
||||
this.authKeyPromise = window.crypto.subtle
|
||||
.importKey(
|
||||
'raw',
|
||||
encoder.encode(file.password),
|
||||
{ name: 'PBKDF2' },
|
||||
false,
|
||||
['deriveKey']
|
||||
)
|
||||
.then(pwdKey =>
|
||||
window.crypto.subtle.deriveKey(
|
||||
{
|
||||
name: 'PBKDF2',
|
||||
salt: encoder.encode(file.url),
|
||||
iterations: 100,
|
||||
hash: 'SHA-256'
|
||||
},
|
||||
pwdKey,
|
||||
{
|
||||
name: 'HMAC',
|
||||
hash: 'SHA-256'
|
||||
},
|
||||
true,
|
||||
['sign']
|
||||
)
|
||||
);
|
||||
} else {
|
||||
this.authKeyPromise = this.secretKeyPromise.then(sk => {
|
||||
const encoder = new TextEncoder();
|
||||
return window.crypto.subtle.deriveKey(
|
||||
{
|
||||
name: 'HKDF',
|
||||
salt: new Uint8Array(),
|
||||
info: encoder.encode('authentication'),
|
||||
hash: 'SHA-256'
|
||||
},
|
||||
sk,
|
||||
{
|
||||
name: 'HMAC',
|
||||
hash: { name: 'SHA-256' }
|
||||
},
|
||||
false,
|
||||
['sign']
|
||||
);
|
||||
});
|
||||
}
|
||||
this.metaKeyPromise = this.secretKeyPromise.then(sk => {
|
||||
const encoder = new TextEncoder();
|
||||
return window.crypto.subtle.deriveKey(
|
||||
{
|
||||
name: 'HKDF',
|
||||
salt: new Uint8Array(),
|
||||
info: encoder.encode('metadata'),
|
||||
hash: 'SHA-256'
|
||||
},
|
||||
sk,
|
||||
{
|
||||
name: 'AES-GCM',
|
||||
length: 128
|
||||
},
|
||||
false,
|
||||
['decrypt']
|
||||
);
|
||||
});
|
||||
this.file = file;
|
||||
this.url = url;
|
||||
this.msg = 'fileSizeProgress';
|
||||
this.state = 'initialized';
|
||||
this.progress = [0, 1];
|
||||
}
|
||||
|
||||
@@ -38,7 +116,65 @@ export default class FileReceiver extends Nanobus {
|
||||
// TODO
|
||||
}
|
||||
|
||||
downloadFile() {
|
||||
fetchMetadata(sig) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
const nonce = xhr.getResponseHeader('WWW-Authenticate').split(' ')[1];
|
||||
this.file.nonce = nonce;
|
||||
if (xhr.status === 200) {
|
||||
return resolve(xhr.response);
|
||||
}
|
||||
reject(new Error(xhr.status));
|
||||
}
|
||||
};
|
||||
xhr.onerror = () => reject(new Error(0));
|
||||
xhr.ontimeout = () => reject(new Error(0));
|
||||
xhr.open('get', `/api/metadata/${this.file.id}`);
|
||||
xhr.setRequestHeader('Authorization', `send-v1 ${arrayToB64(sig)}`);
|
||||
xhr.responseType = 'json';
|
||||
xhr.timeout = 2000;
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
|
||||
async getMetadata(nonce) {
|
||||
try {
|
||||
const authKey = await this.authKeyPromise;
|
||||
const sig = await window.crypto.subtle.sign(
|
||||
{
|
||||
name: 'HMAC'
|
||||
},
|
||||
authKey,
|
||||
b64ToArray(nonce)
|
||||
);
|
||||
const data = await this.fetchMetadata(new Uint8Array(sig));
|
||||
const metaKey = await this.metaKeyPromise;
|
||||
const json = await window.crypto.subtle.decrypt(
|
||||
{
|
||||
name: 'AES-GCM',
|
||||
iv: new Uint8Array(12),
|
||||
tagLength: 128
|
||||
},
|
||||
metaKey,
|
||||
b64ToArray(data.metadata)
|
||||
);
|
||||
const decoder = new TextDecoder();
|
||||
const meta = JSON.parse(decoder.decode(json));
|
||||
this.file.name = meta.name;
|
||||
this.file.type = meta.type;
|
||||
this.file.iv = meta.iv;
|
||||
this.file.size = data.size;
|
||||
this.file.ttl = data.ttl;
|
||||
this.state = 'ready';
|
||||
} catch (e) {
|
||||
this.state = 'invalid';
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
downloadFile(sig) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
@@ -49,52 +185,67 @@ export default class FileReceiver extends Nanobus {
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onload = function(event) {
|
||||
xhr.onload = event => {
|
||||
if (xhr.status === 404) {
|
||||
reject(new Error('notfound'));
|
||||
return;
|
||||
}
|
||||
|
||||
const blob = new Blob([this.response]);
|
||||
const meta = JSON.parse(xhr.getResponseHeader('X-File-Metadata'));
|
||||
if (xhr.status !== 200) {
|
||||
return reject(new Error(xhr.status));
|
||||
}
|
||||
|
||||
const blob = new Blob([xhr.response]);
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onload = function() {
|
||||
resolve({
|
||||
data: this.result,
|
||||
name: meta.filename,
|
||||
type: meta.mimeType,
|
||||
iv: meta.id
|
||||
});
|
||||
resolve(this.result);
|
||||
};
|
||||
|
||||
fileReader.readAsArrayBuffer(blob);
|
||||
};
|
||||
|
||||
xhr.open('get', this.url);
|
||||
xhr.setRequestHeader('Authorization', `send-v1 ${arrayToB64(sig)}`);
|
||||
xhr.responseType = 'blob';
|
||||
xhr.send();
|
||||
});
|
||||
}
|
||||
|
||||
async download() {
|
||||
const key = await this.key;
|
||||
const file = await this.downloadFile();
|
||||
this.msg = 'decryptingFile';
|
||||
this.emit('decrypting');
|
||||
const plaintext = await window.crypto.subtle.decrypt(
|
||||
{
|
||||
name: 'AES-GCM',
|
||||
iv: hexToArray(file.iv),
|
||||
tagLength: 128
|
||||
},
|
||||
key,
|
||||
file.data
|
||||
);
|
||||
this.msg = 'downloadFinish';
|
||||
return {
|
||||
plaintext,
|
||||
name: decodeURIComponent(file.name),
|
||||
type: file.type
|
||||
};
|
||||
async download(nonce) {
|
||||
this.state = 'downloading';
|
||||
this.emit('progress', this.progress);
|
||||
try {
|
||||
const encryptKey = await this.encryptKeyPromise;
|
||||
const authKey = await this.authKeyPromise;
|
||||
const sig = await window.crypto.subtle.sign(
|
||||
{
|
||||
name: 'HMAC'
|
||||
},
|
||||
authKey,
|
||||
b64ToArray(nonce)
|
||||
);
|
||||
const ciphertext = await this.downloadFile(new Uint8Array(sig));
|
||||
this.msg = 'decryptingFile';
|
||||
this.emit('decrypting');
|
||||
const plaintext = await window.crypto.subtle.decrypt(
|
||||
{
|
||||
name: 'AES-GCM',
|
||||
iv: b64ToArray(this.file.iv),
|
||||
tagLength: 128
|
||||
},
|
||||
encryptKey,
|
||||
ciphertext
|
||||
);
|
||||
this.msg = 'downloadFinish';
|
||||
this.state = 'complete';
|
||||
return {
|
||||
plaintext,
|
||||
name: decodeURIComponent(this.file.name),
|
||||
type: this.file.type
|
||||
};
|
||||
} catch (e) {
|
||||
this.state = 'invalid';
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Nanobus from 'nanobus';
|
||||
import { arrayToHex, bytes } from './utils';
|
||||
import { arrayToB64, b64ToArray, bytes } from './utils';
|
||||
|
||||
export default class FileSender extends Nanobus {
|
||||
constructor(file) {
|
||||
@@ -10,13 +10,13 @@ export default class FileSender extends Nanobus {
|
||||
this.cancelled = false;
|
||||
this.iv = window.crypto.getRandomValues(new Uint8Array(12));
|
||||
this.uploadXHR = new XMLHttpRequest();
|
||||
this.key = window.crypto.subtle.generateKey(
|
||||
{
|
||||
name: 'AES-GCM',
|
||||
length: 128
|
||||
},
|
||||
true,
|
||||
['encrypt']
|
||||
this.rawSecret = window.crypto.getRandomValues(new Uint8Array(16));
|
||||
this.secretKey = window.crypto.subtle.importKey(
|
||||
'raw',
|
||||
this.rawSecret,
|
||||
'HKDF',
|
||||
false,
|
||||
['deriveKey']
|
||||
);
|
||||
}
|
||||
|
||||
@@ -71,14 +71,12 @@ export default class FileSender extends Nanobus {
|
||||
});
|
||||
}
|
||||
|
||||
uploadFile(encrypted, keydata) {
|
||||
uploadFile(encrypted, metadata, rawAuth) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const file = this.file;
|
||||
const id = arrayToHex(this.iv);
|
||||
const dataView = new DataView(encrypted);
|
||||
const blob = new Blob([dataView], { type: file.type });
|
||||
const blob = new Blob([dataView], { type: 'application/octet-stream' });
|
||||
const fd = new FormData();
|
||||
fd.append('data', blob, file.name);
|
||||
fd.append('data', blob);
|
||||
|
||||
const xhr = this.uploadXHR;
|
||||
|
||||
@@ -92,14 +90,18 @@ export default class FileSender extends Nanobus {
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
if (xhr.status === 200) {
|
||||
const nonce = xhr
|
||||
.getResponseHeader('WWW-Authenticate')
|
||||
.split(' ')[1];
|
||||
this.progress = [1, 1];
|
||||
this.msg = 'notifyUploadDone';
|
||||
const responseObj = JSON.parse(xhr.responseText);
|
||||
return resolve({
|
||||
url: responseObj.url,
|
||||
id: responseObj.id,
|
||||
secretKey: keydata.k,
|
||||
deleteToken: responseObj.delete
|
||||
secretKey: arrayToB64(this.rawSecret),
|
||||
deleteToken: responseObj.delete,
|
||||
nonce
|
||||
});
|
||||
}
|
||||
this.msg = 'errorPageHeader';
|
||||
@@ -110,18 +112,62 @@ export default class FileSender extends Nanobus {
|
||||
xhr.open('post', '/api/upload', true);
|
||||
xhr.setRequestHeader(
|
||||
'X-File-Metadata',
|
||||
JSON.stringify({
|
||||
id: id,
|
||||
filename: encodeURIComponent(file.name)
|
||||
})
|
||||
arrayToB64(new Uint8Array(metadata))
|
||||
);
|
||||
xhr.setRequestHeader('Authorization', `send-v1 ${arrayToB64(rawAuth)}`);
|
||||
xhr.send(fd);
|
||||
this.msg = 'fileSizeProgress';
|
||||
});
|
||||
}
|
||||
|
||||
async upload() {
|
||||
const key = await this.key;
|
||||
const encoder = new TextEncoder();
|
||||
const secretKey = await this.secretKey;
|
||||
const encryptKey = await window.crypto.subtle.deriveKey(
|
||||
{
|
||||
name: 'HKDF',
|
||||
salt: new Uint8Array(),
|
||||
info: encoder.encode('encryption'),
|
||||
hash: 'SHA-256'
|
||||
},
|
||||
secretKey,
|
||||
{
|
||||
name: 'AES-GCM',
|
||||
length: 128
|
||||
},
|
||||
false,
|
||||
['encrypt']
|
||||
);
|
||||
const authKey = await window.crypto.subtle.deriveKey(
|
||||
{
|
||||
name: 'HKDF',
|
||||
salt: new Uint8Array(),
|
||||
info: encoder.encode('authentication'),
|
||||
hash: 'SHA-256'
|
||||
},
|
||||
secretKey,
|
||||
{
|
||||
name: 'HMAC',
|
||||
hash: 'SHA-256'
|
||||
},
|
||||
true,
|
||||
['sign']
|
||||
);
|
||||
const metaKey = await window.crypto.subtle.deriveKey(
|
||||
{
|
||||
name: 'HKDF',
|
||||
salt: new Uint8Array(),
|
||||
info: encoder.encode('metadata'),
|
||||
hash: 'SHA-256'
|
||||
},
|
||||
secretKey,
|
||||
{
|
||||
name: 'AES-GCM',
|
||||
length: 128
|
||||
},
|
||||
false,
|
||||
['encrypt']
|
||||
);
|
||||
const plaintext = await this.readFile();
|
||||
if (this.cancelled) {
|
||||
throw new Error(0);
|
||||
@@ -134,13 +180,112 @@ export default class FileSender extends Nanobus {
|
||||
iv: this.iv,
|
||||
tagLength: 128
|
||||
},
|
||||
key,
|
||||
encryptKey,
|
||||
plaintext
|
||||
);
|
||||
const metadata = await window.crypto.subtle.encrypt(
|
||||
{
|
||||
name: 'AES-GCM',
|
||||
iv: new Uint8Array(12),
|
||||
tagLength: 128
|
||||
},
|
||||
metaKey,
|
||||
encoder.encode(
|
||||
JSON.stringify({
|
||||
iv: arrayToB64(this.iv),
|
||||
name: this.file.name,
|
||||
type: this.file.type || 'application/octet-stream'
|
||||
})
|
||||
)
|
||||
);
|
||||
const rawAuth = await window.crypto.subtle.exportKey('raw', authKey);
|
||||
if (this.cancelled) {
|
||||
throw new Error(0);
|
||||
}
|
||||
const keydata = await window.crypto.subtle.exportKey('jwk', key);
|
||||
return this.uploadFile(encrypted, keydata);
|
||||
return this.uploadFile(encrypted, metadata, new Uint8Array(rawAuth));
|
||||
}
|
||||
|
||||
static async setPassword(password, file) {
|
||||
const encoder = new TextEncoder();
|
||||
const secretKey = await window.crypto.subtle.importKey(
|
||||
'raw',
|
||||
b64ToArray(file.secretKey),
|
||||
'HKDF',
|
||||
false,
|
||||
['deriveKey']
|
||||
);
|
||||
const authKey = await window.crypto.subtle.deriveKey(
|
||||
{
|
||||
name: 'HKDF',
|
||||
salt: new Uint8Array(),
|
||||
info: encoder.encode('authentication'),
|
||||
hash: 'SHA-256'
|
||||
},
|
||||
secretKey,
|
||||
{
|
||||
name: 'HMAC',
|
||||
hash: 'SHA-256'
|
||||
},
|
||||
true,
|
||||
['sign']
|
||||
);
|
||||
const sig = await window.crypto.subtle.sign(
|
||||
{
|
||||
name: 'HMAC'
|
||||
},
|
||||
authKey,
|
||||
b64ToArray(file.nonce)
|
||||
);
|
||||
const pwdKey = await window.crypto.subtle.importKey(
|
||||
'raw',
|
||||
encoder.encode(password),
|
||||
{ name: 'PBKDF2' },
|
||||
false,
|
||||
['deriveKey']
|
||||
);
|
||||
const newAuthKey = await window.crypto.subtle.deriveKey(
|
||||
{
|
||||
name: 'PBKDF2',
|
||||
salt: encoder.encode(file.url),
|
||||
iterations: 100,
|
||||
hash: 'SHA-256'
|
||||
},
|
||||
pwdKey,
|
||||
{
|
||||
name: 'HMAC',
|
||||
hash: 'SHA-256'
|
||||
},
|
||||
true,
|
||||
['sign']
|
||||
);
|
||||
const rawAuth = await window.crypto.subtle.exportKey('raw', newAuthKey);
|
||||
return new Promise((resolve, reject) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
if (xhr.status === 200) {
|
||||
return resolve(xhr.response);
|
||||
}
|
||||
if (xhr.status === 401) {
|
||||
const nonce = xhr
|
||||
.getResponseHeader('WWW-Authenticate')
|
||||
.split(' ')[1];
|
||||
file.nonce = nonce;
|
||||
}
|
||||
reject(new Error(xhr.status));
|
||||
}
|
||||
};
|
||||
xhr.onerror = () => reject(new Error(0));
|
||||
xhr.ontimeout = () => reject(new Error(0));
|
||||
xhr.open('post', `/api/password/${file.id}`);
|
||||
xhr.setRequestHeader(
|
||||
'Authorization',
|
||||
`send-v1 ${arrayToB64(new Uint8Array(sig))}`
|
||||
);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.responseType = 'json';
|
||||
xhr.timeout = 2000;
|
||||
xhr.send(JSON.stringify({ auth: arrayToB64(new Uint8Array(rawAuth)) }));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
18
app/main.js
@@ -20,22 +20,24 @@ app.use((state, emitter) => {
|
||||
state.translate = locale.getTranslator();
|
||||
state.storage = storage;
|
||||
state.raven = Raven;
|
||||
state.config = {
|
||||
uploadWindowStyle: 'upload-window',
|
||||
uploadButtonStyle: 'browse btn'
|
||||
};
|
||||
emitter.on('DOMContentLoaded', async () => {
|
||||
let reason = null;
|
||||
if (
|
||||
/firefox/i.test(navigator.userAgent) &&
|
||||
parseInt(navigator.userAgent.match(/firefox\/*([^\n\r]*)\./i)[1], 10) <=
|
||||
49
|
||||
) {
|
||||
return emitter.emit('replaceState', '/unsupported/outdated');
|
||||
reason = 'outdated';
|
||||
}
|
||||
if (/edge\/\d+/i.test(navigator.userAgent)) {
|
||||
reason = 'edge';
|
||||
}
|
||||
const ok = await canHasSend(assets.get('cryptofill.js'));
|
||||
if (!ok) {
|
||||
const reason = /firefox/i.test(navigator.userAgent) ? 'outdated' : 'gcm';
|
||||
emitter.emit('replaceState', `/unsupported/${reason}`);
|
||||
reason = /firefox/i.test(navigator.userAgent) ? 'outdated' : 'gcm';
|
||||
}
|
||||
if (reason) {
|
||||
setTimeout(() => emitter.emit('replaceState', `/unsupported/${reason}`));
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -45,4 +47,4 @@ app.use(fileManager);
|
||||
app.use(dragManager);
|
||||
app.use(experiments);
|
||||
|
||||
app.mount('#page-one');
|
||||
app.mount('body');
|
||||
|
||||
@@ -20,7 +20,7 @@ let experiment = null;
|
||||
export default function initialize(state, emitter) {
|
||||
appState = state;
|
||||
emitter.on('DOMContentLoaded', () => {
|
||||
addExitHandlers();
|
||||
// addExitHandlers();
|
||||
experiment = storage.enrolled[0];
|
||||
sendEvent(category(), 'visit', {
|
||||
cm5: storage.totalUploads,
|
||||
@@ -29,6 +29,9 @@ export default function initialize(state, emitter) {
|
||||
});
|
||||
//TODO restart handlers... somewhere
|
||||
});
|
||||
emitter.on('exit', evt => {
|
||||
exitEvent(evt);
|
||||
});
|
||||
}
|
||||
|
||||
function category() {
|
||||
@@ -81,6 +84,8 @@ function urlToMetric(url) {
|
||||
case 'https://testpilot.firefox.com/':
|
||||
case 'https://testpilot.firefox.com/experiments/send':
|
||||
return 'testpilot';
|
||||
case 'https://www.mozilla.org/firefox/new/?utm_campaign=send-acquisition&utm_medium=referral&utm_source=send.firefox.com':
|
||||
return 'promo';
|
||||
default:
|
||||
return 'other';
|
||||
}
|
||||
@@ -147,6 +152,15 @@ function completedUpload(params) {
|
||||
});
|
||||
}
|
||||
|
||||
function addedPassword(params) {
|
||||
return sendEvent('sender', 'password-added', {
|
||||
cm1: params.size,
|
||||
cm5: storage.totalUploads,
|
||||
cm6: storage.files.length,
|
||||
cm7: storage.totalDownloads
|
||||
});
|
||||
}
|
||||
|
||||
function startedDownload(params) {
|
||||
return sendEvent('recipient', 'download-started', {
|
||||
cm1: params.size,
|
||||
@@ -235,6 +249,7 @@ function exitEvent(target) {
|
||||
});
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function addExitHandlers() {
|
||||
const links = Array.from(document.querySelectorAll('a'));
|
||||
links.forEach(l => {
|
||||
@@ -262,6 +277,7 @@ export {
|
||||
cancelledDownload,
|
||||
stoppedDownload,
|
||||
completedDownload,
|
||||
addedPassword,
|
||||
restart,
|
||||
unsupported
|
||||
};
|
||||
|
||||
@@ -3,7 +3,10 @@ const download = require('../templates/download');
|
||||
|
||||
module.exports = function(state, emit) {
|
||||
if (state.transfer) {
|
||||
return download(state, emit);
|
||||
const s = state.transfer.state;
|
||||
if (s === 'downloading' || s === 'complete') {
|
||||
return download(state, emit);
|
||||
}
|
||||
}
|
||||
return preview(state, emit);
|
||||
};
|
||||
|
||||
@@ -2,7 +2,8 @@ const welcome = require('../templates/welcome');
|
||||
const upload = require('../templates/upload');
|
||||
|
||||
module.exports = function(state, emit) {
|
||||
if (state.transfer) {
|
||||
if (state.transfer && state.transfer.iv) {
|
||||
//TODO relying on 'iv' is gross
|
||||
return upload(state, emit);
|
||||
}
|
||||
return welcome(state, emit);
|
||||
|
||||
@@ -1,17 +1,43 @@
|
||||
const choo = require('choo');
|
||||
const html = require('choo/html');
|
||||
const download = require('./download');
|
||||
const header = require('../templates/header');
|
||||
const footer = require('../templates/footer');
|
||||
const fxPromo = require('../templates/fxPromo');
|
||||
|
||||
const app = choo();
|
||||
|
||||
app.route('/', require('./home'));
|
||||
app.route('/share/:id', require('../templates/share'));
|
||||
app.route('/download/:id', download);
|
||||
app.route('/download/:id/:key', download);
|
||||
app.route('/completed', require('../templates/completed'));
|
||||
app.route('/unsupported/:reason', require('../templates/unsupported'));
|
||||
app.route('/legal', require('../templates/legal'));
|
||||
app.route('/error', require('../templates/error'));
|
||||
app.route('/blank', require('../templates/blank'));
|
||||
app.route('*', require('../templates/notFound'));
|
||||
function body(template) {
|
||||
return function(state, emit) {
|
||||
const b = html`<body>
|
||||
${state.promo === 'header' ? fxPromo(state, emit) : ''}
|
||||
${header(state)}
|
||||
<div class="all">
|
||||
<noscript>
|
||||
<h2>Firefox Send requires JavaScript</h2>
|
||||
<p><a href="https://github.com/mozilla/send/blob/master/docs/faq.md#why-does-firefox-send-require-javascript">Why does Firefox Send require JavaScript?</a></p>
|
||||
<p>Please enable JavaScript and try again.</p>
|
||||
</noscript>
|
||||
${template(state, emit)}
|
||||
</div>
|
||||
${footer(state)}
|
||||
</body>`;
|
||||
if (state.layout) {
|
||||
return state.layout(state, b);
|
||||
}
|
||||
return b;
|
||||
};
|
||||
}
|
||||
|
||||
app.route('/', body(require('./home')));
|
||||
app.route('/share/:id', body(require('../templates/share')));
|
||||
app.route('/download/:id', body(download));
|
||||
app.route('/download/:id/:key', body(download));
|
||||
app.route('/completed', body(require('../templates/completed')));
|
||||
app.route('/unsupported/:reason', body(require('../templates/unsupported')));
|
||||
app.route('/legal', body(require('../templates/legal')));
|
||||
app.route('/error', body(require('../templates/error')));
|
||||
app.route('/blank', body(require('../templates/blank')));
|
||||
app.route('*', body(require('../templates/notFound')));
|
||||
|
||||
module.exports = app;
|
||||
|
||||
@@ -92,11 +92,7 @@ class Storage {
|
||||
}
|
||||
|
||||
getFileById(id) {
|
||||
try {
|
||||
return JSON.parse(this.engine.getItem(id));
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
return this._files.find(f => f.id === id);
|
||||
}
|
||||
|
||||
get(id) {
|
||||
@@ -114,6 +110,10 @@ class Storage {
|
||||
this._files.push(file);
|
||||
this.engine.setItem(file.id, JSON.stringify(file));
|
||||
}
|
||||
|
||||
writeFiles() {
|
||||
this._files.forEach(f => this.engine.setItem(f.id, JSON.stringify(f)));
|
||||
}
|
||||
}
|
||||
|
||||
export default new Storage();
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
const html = require('choo/html');
|
||||
|
||||
module.exports = function(state) {
|
||||
module.exports = function() {
|
||||
const div = html`<div id="page-one"></div>`;
|
||||
if (state.layout) {
|
||||
return state.layout(state, div);
|
||||
}
|
||||
return div;
|
||||
};
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
const html = require('choo/html');
|
||||
const progress = require('./progress');
|
||||
const { fadeOut } = require('../utils');
|
||||
const fxPromo = require('./fxPromo');
|
||||
|
||||
module.exports = function(state, emit) {
|
||||
const div = html`
|
||||
<div id="page-one">
|
||||
<div id="download" class="fadeIn">
|
||||
<div id="download-progress">
|
||||
<div id="dl-title" class="title">${state.translate(
|
||||
@@ -15,9 +17,11 @@ module.exports = function(state, emit) {
|
||||
<div class="progress-text"></div>
|
||||
</div>
|
||||
</div>
|
||||
<a class="send-new" data-state="completed" href="/" onclick=${sendNew}>${state.translate(
|
||||
'sendYourFilesLink'
|
||||
)}</a>
|
||||
<a class="send-new" data-state="completed" href="/" onclick=${
|
||||
sendNew
|
||||
}>${state.translate('sendYourFilesLink')}</a>
|
||||
</div>
|
||||
${state.promo === 'body' ? fxPromo(state, emit) : ''}
|
||||
</div>
|
||||
`;
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
const html = require('choo/html');
|
||||
const progress = require('./progress');
|
||||
const { bytes } = require('../utils');
|
||||
const fxPromo = require('./fxPromo');
|
||||
|
||||
module.exports = function(state) {
|
||||
module.exports = function(state, emit) {
|
||||
const transfer = state.transfer;
|
||||
const div = html`
|
||||
<div id="page-one">
|
||||
<div id="download-progress" class="fadeIn">
|
||||
<div id="dl-title" class="title">${state.translate(
|
||||
'downloadingPageProgress',
|
||||
@@ -21,6 +23,8 @@ module.exports = function(state) {
|
||||
transfer.sizes
|
||||
)}</div>
|
||||
</div>
|
||||
</div>
|
||||
${state.promo === 'body' ? fxPromo(state, emit) : ''}
|
||||
</div>
|
||||
`;
|
||||
|
||||
|
||||
56
app/templates/downloadPassword.js
Normal file
@@ -0,0 +1,56 @@
|
||||
const html = require('choo/html');
|
||||
|
||||
module.exports = function(state, emit) {
|
||||
const fileInfo = state.fileInfo;
|
||||
const label =
|
||||
fileInfo.password === null
|
||||
? html`
|
||||
<label class="red"
|
||||
for="unlock-input">${state.translate('passwordTryAgain')}</label>`
|
||||
: html`
|
||||
<label for="unlock-input">
|
||||
${state.translate('unlockInputLabel')}
|
||||
</label>`;
|
||||
const div = html`
|
||||
<div class="enterPassword">
|
||||
${label}
|
||||
<form id="unlock" onsubmit=${checkPassword} data-no-csrf>
|
||||
<input id="unlock-input"
|
||||
class="unlock-input input-no-btn"
|
||||
maxlength="64"
|
||||
autocomplete="off"
|
||||
placeholder="${state.translate('unlockInputPlaceholder')}"
|
||||
oninput=${inputChanged}
|
||||
type="password"/>
|
||||
<input type="submit"
|
||||
id="unlock-btn"
|
||||
class="btn btn-hidden"
|
||||
value="${state.translate('unlockButtonLabel')}"/>
|
||||
</form>
|
||||
</div>`;
|
||||
|
||||
function inputChanged() {
|
||||
const input = document.getElementById('unlock-input');
|
||||
const btn = document.getElementById('unlock-btn');
|
||||
if (input.value.length > 0) {
|
||||
btn.classList.remove('btn-hidden');
|
||||
input.classList.remove('input-no-btn');
|
||||
} else {
|
||||
btn.classList.add('btn-hidden');
|
||||
input.classList.add('input-no-btn');
|
||||
}
|
||||
}
|
||||
|
||||
function checkPassword(event) {
|
||||
event.preventDefault();
|
||||
const password = document.getElementById('unlock-input').value;
|
||||
if (password.length > 0) {
|
||||
document.getElementById('unlock-btn').disabled = true;
|
||||
state.fileInfo.url = window.location.href;
|
||||
state.fileInfo.password = password;
|
||||
emit('preview');
|
||||
}
|
||||
}
|
||||
|
||||
return div;
|
||||
};
|
||||
31
app/templates/footer.js
Normal file
@@ -0,0 +1,31 @@
|
||||
const html = require('choo/html');
|
||||
const assets = require('../../common/assets');
|
||||
|
||||
module.exports = function(state) {
|
||||
return html`<div class="footer">
|
||||
<div class="legal-links">
|
||||
<a href="https://www.mozilla.org" role="presentation"><img class="mozilla-logo" src="${assets.get(
|
||||
'mozilla-logo.svg'
|
||||
)}" alt="mozilla"/></a>
|
||||
<a href="https://www.mozilla.org/about/legal">${state.translate(
|
||||
'footerLinkLegal'
|
||||
)}</a>
|
||||
<a href="https://testpilot.firefox.com/about">${state.translate(
|
||||
'footerLinkAbout'
|
||||
)}</a>
|
||||
<a href="/legal">${state.translate('footerLinkPrivacy')}</a>
|
||||
<a href="/legal">${state.translate('footerLinkTerms')}</a>
|
||||
<a href="https://www.mozilla.org/privacy/websites/#cookies">${state.translate(
|
||||
'footerLinkCookies'
|
||||
)}</a>
|
||||
</div>
|
||||
<div class="social-links">
|
||||
<a href="https://github.com/mozilla/send" role="presentation"><img class="github" src="${assets.get(
|
||||
'github-icon.svg'
|
||||
)}" alt="github"/></a>
|
||||
<a href="https://twitter.com/FxTestPilot" role="presentation"><img class="twitter" src="${assets.get(
|
||||
'twitter-icon.svg'
|
||||
)}" alt="twitter"/></a>
|
||||
</div>
|
||||
</div>`;
|
||||
};
|
||||
44
app/templates/fxPromo.js
Normal file
@@ -0,0 +1,44 @@
|
||||
const html = require('choo/html');
|
||||
const assets = require('../../common/assets');
|
||||
|
||||
// function replaceLinks(str, urls) {
|
||||
// let i = -1;
|
||||
// const s = str.replace(/<a>([^<]+)<\/a>/g, (m, v) => {
|
||||
// i++;
|
||||
// return `<a class="link" href="${urls[i]}">${v}</a>`;
|
||||
// });
|
||||
// return [`<span>${s}</span>`];
|
||||
// }
|
||||
|
||||
module.exports = function(state, emit) {
|
||||
// function close() {
|
||||
// document.querySelector('.banner').remove();
|
||||
// }
|
||||
|
||||
function clicked(evt) {
|
||||
emit('exit', evt);
|
||||
}
|
||||
|
||||
return html`
|
||||
<div class="banner">
|
||||
<div>
|
||||
<img
|
||||
src="${assets.get('firefox_logo-only.svg')}"
|
||||
class="firefox-logo-small"
|
||||
alt="Firefox"/>
|
||||
<span>Send is brought to you by the all-new Firefox.
|
||||
<a
|
||||
class="link"
|
||||
href="https://www.mozilla.org/firefox/new/?utm_campaign=send-acquisition&utm_medium=referral&utm_source=send.firefox.com"
|
||||
onclick=${clicked}
|
||||
>Download Firefox now ≫</a></span>
|
||||
</div>
|
||||
</div>`;
|
||||
};
|
||||
|
||||
/*
|
||||
<img
|
||||
src="${assets.get('close-16.svg')}"
|
||||
class="icon-delete"
|
||||
onclick=${close}>
|
||||
*/
|
||||
21
app/templates/header.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const html = require('choo/html');
|
||||
const assets = require('../../common/assets');
|
||||
|
||||
module.exports = function(state) {
|
||||
return html`<header class="header">
|
||||
<div class="send-logo">
|
||||
<a href="/">
|
||||
<img src="${assets.get(
|
||||
'send_logo.svg'
|
||||
)}" alt="Send"/><h1 class="site-title">Send</h1>
|
||||
</a>
|
||||
<div class="site-subtitle">
|
||||
<a href="https://testpilot.firefox.com">Firefox Test Pilot</a>
|
||||
<div>${state.translate('siteSubtitle')}</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="https://qsurvey.mozilla.com/s3/txp-firefox-send" rel="noreferrer noopener" class="feedback" target="_blank">${state.translate(
|
||||
'siteFeedback'
|
||||
)}</a>
|
||||
</header>`;
|
||||
};
|
||||
@@ -30,9 +30,5 @@ module.exports = function(state) {
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
if (state.layout) {
|
||||
return state.layout(state, div);
|
||||
}
|
||||
return div;
|
||||
};
|
||||
|
||||
@@ -17,9 +17,5 @@ module.exports = function(state) {
|
||||
)}</a>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
if (state.layout) {
|
||||
return state.layout(state, div);
|
||||
}
|
||||
return div;
|
||||
};
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
const html = require('choo/html');
|
||||
const assets = require('../../common/assets');
|
||||
const notFound = require('./notFound');
|
||||
const downloadPassword = require('./downloadPassword');
|
||||
const { bytes } = require('../utils');
|
||||
const fxPromo = require('./fxPromo');
|
||||
|
||||
function getFileFromDOM() {
|
||||
const el = document.getElementById('dl-file');
|
||||
if (!el) {
|
||||
return null;
|
||||
}
|
||||
const data = el.dataset;
|
||||
return {
|
||||
name: data.name,
|
||||
size: parseInt(data.size, 10),
|
||||
ttl: parseInt(data.ttl, 10)
|
||||
nonce: el.getAttribute('data-nonce'),
|
||||
pwd: !!+el.getAttribute('data-requires-password')
|
||||
};
|
||||
}
|
||||
|
||||
@@ -24,47 +24,51 @@ module.exports = function(state, emit) {
|
||||
state.fileInfo.id = state.params.id;
|
||||
state.fileInfo.key = state.params.key;
|
||||
const fileInfo = state.fileInfo;
|
||||
const size = bytes(fileInfo.size);
|
||||
const size = fileInfo.size
|
||||
? state.translate('downloadFileSize', { size: bytes(fileInfo.size) })
|
||||
: '';
|
||||
let action = html`
|
||||
<div>
|
||||
<img src="${assets.get('illustration_download.svg')}"
|
||||
id="download-img"
|
||||
alt="${state.translate('downloadAltText')}"/>
|
||||
<div>
|
||||
<button id="download-btn"
|
||||
class="btn"
|
||||
onclick=${download}>${state.translate('downloadButtonLabel')}
|
||||
</button>
|
||||
</div>
|
||||
</div>`;
|
||||
if (fileInfo.pwd && !fileInfo.password) {
|
||||
action = downloadPassword(state, emit);
|
||||
} else if (!state.transfer) {
|
||||
emit('preview');
|
||||
}
|
||||
const title = fileInfo.name
|
||||
? state.translate('downloadFileName', { filename: fileInfo.name })
|
||||
: state.translate('downloadFileTitle');
|
||||
const div = html`
|
||||
<div id="page-one">
|
||||
<div id="download">
|
||||
<div id="download-page-one">
|
||||
<div class="title">
|
||||
<span id="dl-file"
|
||||
data-name="${fileInfo.name}"
|
||||
data-size="${fileInfo.size}"
|
||||
data-ttl="${fileInfo.ttl}">${state.translate('downloadFileName', {
|
||||
filename: fileInfo.name
|
||||
})}</span>
|
||||
<span id="dl-filesize">${' ' +
|
||||
state.translate('downloadFileSize', { size })}</span>
|
||||
data-nonce="${fileInfo.nonce}"
|
||||
data-requires-password="${fileInfo.pwd}">${title}</span>
|
||||
<span id="dl-filesize">${' ' + size}</span>
|
||||
</div>
|
||||
<div class="description">${state.translate('downloadMessage')}</div>
|
||||
<img
|
||||
src="${assets.get('illustration_download.svg')}"
|
||||
id="download-img"
|
||||
alt="${state.translate('downloadAltText')}"/>
|
||||
<div>
|
||||
<button
|
||||
id="download-btn"
|
||||
class="btn"
|
||||
title="${state.translate('downloadButtonLabel')}"
|
||||
onclick=${download}>${state.translate(
|
||||
'downloadButtonLabel'
|
||||
)}</button>
|
||||
</div>
|
||||
${action}
|
||||
</div>
|
||||
<a class="send-new" href="/">${state.translate('sendYourFilesLink')}</a>
|
||||
</div>
|
||||
${state.promo === 'body' ? fxPromo(state, emit) : ''}
|
||||
</div>
|
||||
`;
|
||||
|
||||
function download(event) {
|
||||
event.preventDefault();
|
||||
emit('download', fileInfo);
|
||||
}
|
||||
|
||||
if (state.layout) {
|
||||
return state.layout(state, div);
|
||||
}
|
||||
return div;
|
||||
};
|
||||
|
||||
@@ -10,10 +10,18 @@ module.exports = function(progressRatio) {
|
||||
const percent = Math.floor(progressRatio * 100);
|
||||
const div = html`
|
||||
<div class="progress-bar">
|
||||
<svg id="progress" width="${oDiameter}" height="${oDiameter}" viewPort="0 0 ${oDiameter} ${oDiameter}" version="1.1">
|
||||
<svg id="progress" width="${oDiameter}" height="${
|
||||
oDiameter
|
||||
}" viewPort="0 0 ${oDiameter} ${oDiameter}" version="1.1">
|
||||
<circle r="${radius}" cx="${oRadius}" cy="${oRadius}" fill="transparent"/>
|
||||
<circle id="bar" r="${radius}" cx="${oRadius}" cy="${oRadius}" fill="transparent" transform="rotate(-90 ${oRadius} ${oRadius})" stroke-dasharray="${circumference}" stroke-dashoffset="${dashOffset}"/>
|
||||
<text class="percentage" text-anchor="middle" x="50%" y="98"><tspan class="percent-number">${percent}</tspan><tspan class="percent-sign">%</tspan></text>
|
||||
<circle id="bar" r="${radius}" cx="${oRadius}" cy="${
|
||||
oRadius
|
||||
}" fill="transparent" transform="rotate(-90 ${oRadius} ${
|
||||
oRadius
|
||||
})" stroke-dasharray="${circumference}" stroke-dashoffset="${dashOffset}"/>
|
||||
<text class="percentage" text-anchor="middle" x="50%" y="98"><tspan class="percent-number">${
|
||||
percent
|
||||
}</tspan><tspan class="percent-sign">%</tspan></text>
|
||||
</svg>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -1,32 +1,54 @@
|
||||
const html = require('choo/html');
|
||||
const assets = require('../../common/assets');
|
||||
const notFound = require('./notFound');
|
||||
const uploadPassword = require('./uploadPassword');
|
||||
const { allowedCopy, delay, fadeOut } = require('../utils');
|
||||
|
||||
function passwordComplete(state, password) {
|
||||
const el = html([
|
||||
`<div class="selectPassword">${state.translate('passwordResult', {
|
||||
password: '<pre></pre>'
|
||||
})}</div>`
|
||||
]);
|
||||
el.lastElementChild.textContent = password;
|
||||
return el;
|
||||
}
|
||||
|
||||
module.exports = function(state, emit) {
|
||||
const file = state.storage.getFileById(state.params.id);
|
||||
if (!file) {
|
||||
return notFound(state, emit);
|
||||
}
|
||||
|
||||
file.password = file.password || '';
|
||||
|
||||
const passwordSection = file.password
|
||||
? passwordComplete(state, file.password)
|
||||
: uploadPassword(state, emit);
|
||||
const div = html`
|
||||
<div id="share-link" class="fadeIn">
|
||||
<div class="title">${state.translate('uploadSuccessTimingHeader')}</div>
|
||||
<div id="share-window">
|
||||
<div id="copy-text">${state.translate('copyUrlFormLabelWithName', {
|
||||
filename: file.name
|
||||
})}</div>
|
||||
<div id="copy-text">
|
||||
${state.translate('copyUrlFormLabelWithName', {
|
||||
filename: file.name
|
||||
})}</div>
|
||||
<div id="copy">
|
||||
<input id="link" type="url" value="${file.url}" readonly="true"/>
|
||||
<button id="copy-btn" class="btn" title="${state.translate(
|
||||
'copyUrlFormButton'
|
||||
)}" onclick=${copyLink}>${state.translate('copyUrlFormButton')}</button>
|
||||
<button id="copy-btn"
|
||||
class="btn"
|
||||
title="${state.translate('copyUrlFormButton')}"
|
||||
onclick=${copyLink}>${state.translate('copyUrlFormButton')}</button>
|
||||
</div>
|
||||
<button id="delete-file" class="btn" title="${state.translate(
|
||||
'deleteFileButton'
|
||||
)}" onclick=${deleteFile}>${state.translate('deleteFileButton')}</button>
|
||||
<a class="send-new" data-state="completed" href="/" onclick=${sendNew}>${state.translate(
|
||||
'sendAnotherFileLink'
|
||||
)}</a>
|
||||
${passwordSection}
|
||||
<button id="delete-file"
|
||||
class="btn"
|
||||
title="${state.translate('deleteFileButton')}"
|
||||
onclick=${deleteFile}>${state.translate('deleteFileButton')}</button>
|
||||
<a class="send-new"
|
||||
data-state="completed"
|
||||
href="/"
|
||||
onclick=${sendNew}>${state.translate('sendAnotherFileLink')}</a>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -44,13 +66,17 @@ module.exports = function(state, emit) {
|
||||
input.disabled = true;
|
||||
const copyBtn = document.getElementById('copy-btn');
|
||||
copyBtn.disabled = true;
|
||||
copyBtn.classList.add('success');
|
||||
copyBtn.replaceChild(
|
||||
html`<img src="${assets.get('check-16.svg')}" class="icon-check">`,
|
||||
copyBtn.firstChild
|
||||
);
|
||||
await delay(2000);
|
||||
input.disabled = false;
|
||||
copyBtn.disabled = false;
|
||||
if (!copyBtn.parentNode.classList.contains('wait-password')) {
|
||||
copyBtn.disabled = false;
|
||||
}
|
||||
copyBtn.classList.remove('success');
|
||||
copyBtn.textContent = state.translate('copyUrlFormButton');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,9 +42,5 @@ module.exports = function(state) {
|
||||
)}</div>
|
||||
</div>`;
|
||||
const div = html`<div id="page-one">${msg}</div>`;
|
||||
|
||||
if (state.layout) {
|
||||
return state.layout(state, div);
|
||||
}
|
||||
return div;
|
||||
};
|
||||
|
||||
65
app/templates/uploadPassword.js
Normal file
@@ -0,0 +1,65 @@
|
||||
const html = require('choo/html');
|
||||
|
||||
module.exports = function(state, emit) {
|
||||
const file = state.storage.getFileById(state.params.id);
|
||||
const div = html`
|
||||
<div class="selectPassword">
|
||||
<div id="addPasswordWrapper">
|
||||
<input id="addPassword" type="checkbox" autocomplete="off" onchange=${
|
||||
togglePasswordInput
|
||||
}/>
|
||||
<label for="addPassword">
|
||||
${state.translate('requirePasswordCheckbox')}</label>
|
||||
</div>
|
||||
<form class="setPassword hidden" onsubmit=${setPassword} data-no-csrf>
|
||||
<input id="unlock-input"
|
||||
class="unlock-input input-no-btn"
|
||||
maxlength="64"
|
||||
autocomplete="off"
|
||||
placeholder="${state.translate('unlockInputPlaceholder')}"
|
||||
oninput=${inputChanged}/>
|
||||
<input type="submit"
|
||||
id="unlock-btn"
|
||||
class="btn btn-hidden"
|
||||
value="${state.translate('addPasswordButton')}"/>
|
||||
</form>
|
||||
</div>`;
|
||||
|
||||
function inputChanged() {
|
||||
const input = document.getElementById('unlock-input');
|
||||
const btn = document.getElementById('unlock-btn');
|
||||
if (input.value.length > 0) {
|
||||
btn.classList.remove('btn-hidden');
|
||||
input.classList.remove('input-no-btn');
|
||||
} else {
|
||||
btn.classList.add('btn-hidden');
|
||||
input.classList.add('input-no-btn');
|
||||
}
|
||||
}
|
||||
|
||||
function togglePasswordInput(e) {
|
||||
const unlockInput = document.getElementById('unlock-input');
|
||||
const boxChecked = e.target.checked;
|
||||
document
|
||||
.querySelector('.setPassword')
|
||||
.classList.toggle('hidden', !boxChecked);
|
||||
if (boxChecked) {
|
||||
unlockInput.focus();
|
||||
} else {
|
||||
unlockInput.value = '';
|
||||
}
|
||||
inputChanged();
|
||||
}
|
||||
|
||||
function setPassword(event) {
|
||||
event.preventDefault();
|
||||
const password = document.getElementById('unlock-input').value;
|
||||
if (password.length > 0) {
|
||||
document.getElementById('copy').classList.remove('wait-password');
|
||||
document.getElementById('copy-btn').disabled = false;
|
||||
emit('password', { password, file });
|
||||
}
|
||||
}
|
||||
|
||||
return div;
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
const html = require('choo/html');
|
||||
const assets = require('../../common/assets');
|
||||
const fileList = require('./fileList');
|
||||
const fxPromo = require('./fxPromo');
|
||||
const { fadeOut } = require('../utils');
|
||||
|
||||
module.exports = function(state, emit) {
|
||||
@@ -9,27 +10,33 @@ module.exports = function(state, emit) {
|
||||
<div class="title">${state.translate('uploadPageHeader')}</div>
|
||||
<div class="description">
|
||||
<div>${state.translate('uploadPageExplainer')}</div>
|
||||
<a href="https://testpilot.firefox.com/experiments/send" class="link">${state.translate(
|
||||
'uploadPageLearnMore'
|
||||
)}</a>
|
||||
<a href="https://testpilot.firefox.com/experiments/send"
|
||||
class="link">${state.translate('uploadPageLearnMore')}</a>
|
||||
</div>
|
||||
<div class="${state.config
|
||||
.uploadWindowStyle}" ondragover=${dragover} ondragleave=${dragleave}>
|
||||
<div id="upload-img"><img src="${assets.get(
|
||||
'upload.svg'
|
||||
)}" title="${state.translate('uploadSvgAlt')}"/></div>
|
||||
<div class="upload-window"
|
||||
ondragover=${dragover}
|
||||
ondragleave=${dragleave}>
|
||||
<div id="upload-img">
|
||||
<img src="${assets.get('upload.svg')}"
|
||||
title="${state.translate('uploadSvgAlt')}"/>
|
||||
</div>
|
||||
<div id="upload-text">${state.translate('uploadPageDropMessage')}</div>
|
||||
<span id="file-size-msg"><em>${state.translate(
|
||||
'uploadPageSizeMessage'
|
||||
)}</em></span>
|
||||
<form method="post" action="upload" enctype="multipart/form-data">
|
||||
<label for="file-upload" id="browse" class="${state.config
|
||||
.uploadButtonStyle}" title="${state.translate(
|
||||
'uploadPageBrowseButton1'
|
||||
)}">${state.translate('uploadPageBrowseButton1')}</label>
|
||||
<input id="file-upload" type="file" name="fileUploaded" onchange=${upload} />
|
||||
</form>
|
||||
<span id="file-size-msg">
|
||||
<em>${state.translate('uploadPageSizeMessage')}</em>
|
||||
</span>
|
||||
<input id="file-upload"
|
||||
type="file"
|
||||
name="fileUploaded"
|
||||
onfocus=${onfocus}
|
||||
onblur=${onblur}
|
||||
onchange=${upload} />
|
||||
<label for="file-upload"
|
||||
id="browse"
|
||||
class="btn browse"
|
||||
title="${state.translate('uploadPageBrowseButton1')}">
|
||||
${state.translate('uploadPageBrowseButton1')}</label>
|
||||
</div>
|
||||
${state.promo === 'body' ? fxPromo(state, emit) : ''}
|
||||
${fileList(state, emit)}
|
||||
</div>
|
||||
`;
|
||||
@@ -44,6 +51,14 @@ module.exports = function(state, emit) {
|
||||
div.classList.remove('ondrag');
|
||||
}
|
||||
|
||||
function onfocus(event) {
|
||||
event.target.classList.add('has-focus');
|
||||
}
|
||||
|
||||
function onblur(event) {
|
||||
event.target.classList.remove('has-focus');
|
||||
}
|
||||
|
||||
async function upload(event) {
|
||||
event.preventDefault();
|
||||
const target = event.target;
|
||||
@@ -54,9 +69,5 @@ module.exports = function(state, emit) {
|
||||
await fadeOut('page-one');
|
||||
emit('upload', { file, type: 'click' });
|
||||
}
|
||||
|
||||
if (state.layout) {
|
||||
return state.layout(state, div);
|
||||
}
|
||||
return div;
|
||||
};
|
||||
|
||||
64
app/utils.js
@@ -1,23 +1,18 @@
|
||||
function arrayToHex(iv) {
|
||||
let hexStr = '';
|
||||
// eslint-disable-next-line prefer-const
|
||||
for (let i in iv) {
|
||||
if (iv[i] < 16) {
|
||||
hexStr += '0' + iv[i].toString(16);
|
||||
} else {
|
||||
hexStr += iv[i].toString(16);
|
||||
}
|
||||
}
|
||||
return hexStr;
|
||||
const b64 = require('base64-js');
|
||||
|
||||
function arrayToB64(array) {
|
||||
return b64
|
||||
.fromByteArray(array)
|
||||
.replace(/\+/g, '-')
|
||||
.replace(/\//g, '_')
|
||||
.replace(/=/g, '');
|
||||
}
|
||||
|
||||
function hexToArray(str) {
|
||||
const iv = new Uint8Array(str.length / 2);
|
||||
for (let i = 0; i < str.length; i += 2) {
|
||||
iv[i / 2] = parseInt(str.charAt(i) + str.charAt(i + 1), 16);
|
||||
}
|
||||
|
||||
return iv;
|
||||
function b64ToArray(str) {
|
||||
str = (str + '==='.slice((str.length + 3) % 4))
|
||||
.replace(/-/g, '+')
|
||||
.replace(/_/g, '/');
|
||||
return b64.toByteArray(str);
|
||||
}
|
||||
|
||||
function notify(str) {
|
||||
@@ -105,21 +100,36 @@ const LOCALIZE_NUMBERS = !!(
|
||||
|
||||
const UNITS = ['B', 'kB', 'MB', 'GB'];
|
||||
function bytes(num) {
|
||||
if (num < 1) {
|
||||
return '0B';
|
||||
}
|
||||
const exponent = Math.min(Math.floor(Math.log10(num) / 3), UNITS.length - 1);
|
||||
const n = Number(num / Math.pow(1000, exponent));
|
||||
const nStr = LOCALIZE_NUMBERS
|
||||
? n.toLocaleString(navigator.languages, {
|
||||
let nStr = n.toFixed(1);
|
||||
if (LOCALIZE_NUMBERS) {
|
||||
try {
|
||||
const locale = document.querySelector('html').lang;
|
||||
nStr = n.toLocaleString(locale, {
|
||||
minimumFractionDigits: 1,
|
||||
maximumFractionDigits: 1
|
||||
})
|
||||
: n.toFixed(1);
|
||||
});
|
||||
} catch (e) {
|
||||
// fall through
|
||||
}
|
||||
}
|
||||
return `${nStr}${UNITS[exponent]}`;
|
||||
}
|
||||
|
||||
function percent(ratio) {
|
||||
return LOCALIZE_NUMBERS
|
||||
? ratio.toLocaleString(navigator.languages, { style: 'percent' })
|
||||
: `${Math.floor(ratio * 100)}%`;
|
||||
if (LOCALIZE_NUMBERS) {
|
||||
try {
|
||||
const locale = document.querySelector('html').lang;
|
||||
return ratio.toLocaleString(locale, { style: 'percent' });
|
||||
} catch (e) {
|
||||
// fall through
|
||||
}
|
||||
}
|
||||
return `${Math.floor(ratio * 100)}%`;
|
||||
}
|
||||
|
||||
function allowedCopy() {
|
||||
@@ -147,8 +157,8 @@ module.exports = {
|
||||
bytes,
|
||||
percent,
|
||||
copyToClipboard,
|
||||
arrayToHex,
|
||||
hexToArray,
|
||||
arrayToB64,
|
||||
b64ToArray,
|
||||
notify,
|
||||
canHasSend,
|
||||
isFile,
|
||||
|
||||
1
assets/check-16-blue.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path fill="#0A84FF " d="M6 14a1 1 0 0 1-.707-.293l-3-3a1 1 0 0 1 1.414-1.414l2.157 2.157 6.316-9.023a1 1 0 0 1 1.639 1.146l-7 10a1 1 0 0 1-.732.427A.863.863 0 0 1 6 14z"/></svg>
|
||||
|
After Width: | Height: | Size: 238 B |
BIN
assets/favicon-120.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
assets/favicon-128.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
assets/favicon-144.png
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
BIN
assets/favicon-152.png
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
assets/favicon-167.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
assets/favicon-180.png
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
assets/favicon-195.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
BIN
assets/favicon-196.png
Normal file
|
After Width: | Height: | Size: 9.7 KiB |
BIN
assets/favicon-228.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
assets/favicon-32.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
BIN
assets/favicon-96.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 239 KiB After Width: | Height: | Size: 16 KiB |
221
assets/main.css
@@ -8,7 +8,6 @@ html {
|
||||
background-repeat: no-repeat;
|
||||
background-position: center top;
|
||||
height: 100%;
|
||||
max-width: 1440px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
@@ -130,18 +129,25 @@ body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
max-width: 630px;
|
||||
max-width: 650px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
box-sizing: border-box;
|
||||
width: 96%;
|
||||
}
|
||||
|
||||
pre,
|
||||
input,
|
||||
select,
|
||||
textarea,
|
||||
button {
|
||||
font-family: inherit;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-weight: 600;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
a {
|
||||
@@ -205,8 +211,8 @@ a {
|
||||
}
|
||||
|
||||
.upload-window {
|
||||
border: 1px dashed rgba(0, 148, 251, 0.5);
|
||||
margin: 0 auto;
|
||||
border: 3px dashed rgba(0, 148, 251, 0.5);
|
||||
margin: 0 auto 10px;
|
||||
height: 255px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
@@ -219,8 +225,7 @@ a {
|
||||
}
|
||||
|
||||
.upload-window.ondrag {
|
||||
border: 3px dashed rgba(0, 148, 251, 0.5);
|
||||
margin: 0 auto;
|
||||
border: 5px dashed rgba(0, 148, 251, 0.5);
|
||||
height: 251px;
|
||||
transform: scale(1.04);
|
||||
border-radius: 4.2px;
|
||||
@@ -231,14 +236,6 @@ a {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.upload-window-b {
|
||||
border: 3px dashed rgba(0, 148, 251, 0.5);
|
||||
}
|
||||
|
||||
.upload-window-b.ondrag {
|
||||
border: 5px dashed rgba(0, 148, 251, 0.5);
|
||||
}
|
||||
|
||||
.link {
|
||||
color: #0094fb;
|
||||
text-decoration: none;
|
||||
@@ -258,10 +255,10 @@ a {
|
||||
.browse {
|
||||
background: #0297f8;
|
||||
border-radius: 5px;
|
||||
font-size: 15px;
|
||||
font-size: 20px;
|
||||
color: #fff;
|
||||
min-width: 240px;
|
||||
height: 44px;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
@@ -273,13 +270,18 @@ a {
|
||||
background-color: #0287e8;
|
||||
}
|
||||
|
||||
.browse-b {
|
||||
height: 60px;
|
||||
font-size: 20px;
|
||||
input[type='file'] {
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
input[type='file'] {
|
||||
display: none;
|
||||
input[type='file'].has-focus + #browse,
|
||||
input[type='file']:focus + #browse {
|
||||
background-color: #0287e8;
|
||||
outline: 1px dotted #000;
|
||||
outline: -webkit-focus-ring-color auto 5px;
|
||||
}
|
||||
|
||||
#file-size-msg {
|
||||
@@ -556,6 +558,11 @@ tbody {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#copy.wait-password #link,
|
||||
#copy.wait-password #copy-btn {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
#copy-text {
|
||||
align-self: flex-start;
|
||||
margin-top: 60px;
|
||||
@@ -593,19 +600,21 @@ tbody {
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
font-size: 15px;
|
||||
height: 60px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#copy-btn:hover {
|
||||
#copy-btn:not(:disabled):hover {
|
||||
background-color: #0287e8;
|
||||
}
|
||||
|
||||
#copy-btn:disabled {
|
||||
#copy-btn.success {
|
||||
background: #05a700;
|
||||
border: 1px solid #05a700;
|
||||
}
|
||||
|
||||
#copy-btn:disabled {
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
@@ -641,6 +650,25 @@ tbody {
|
||||
color: #0287e8;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.selectPassword {
|
||||
padding: 10px 0;
|
||||
align-self: left;
|
||||
max-width: 100%;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.setPassword {
|
||||
align-self: left;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
width: 80%;
|
||||
padding: 10px 5px;
|
||||
}
|
||||
|
||||
/* upload-error */
|
||||
#upload-error {
|
||||
display: flex;
|
||||
@@ -679,6 +707,10 @@ tbody {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.firefox-logo-small {
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
#dl-firefox,
|
||||
#update-firefox {
|
||||
margin-bottom: 181px;
|
||||
@@ -736,7 +768,7 @@ tbody {
|
||||
}
|
||||
|
||||
#download {
|
||||
margin: 0 auto;
|
||||
margin: 0 auto 30px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
@@ -769,6 +801,62 @@ tbody {
|
||||
height: 196px;
|
||||
}
|
||||
|
||||
.enterPassword {
|
||||
text-align: left;
|
||||
padding: 40px;
|
||||
}
|
||||
|
||||
.red {
|
||||
color: red;
|
||||
}
|
||||
|
||||
#unlock {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
width: 100%;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.unlock-input {
|
||||
flex: 1;
|
||||
height: 46px;
|
||||
border: 1px solid #0297f8;
|
||||
border-radius: 6px 0 0 6px;
|
||||
font-size: 20px;
|
||||
color: #737373;
|
||||
font-family: 'SF Pro Text', sans-serif;
|
||||
letter-spacing: 0;
|
||||
line-height: 23px;
|
||||
font-weight: 300;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
#unlock-btn {
|
||||
flex: 0 1 165px;
|
||||
background: #0297f8;
|
||||
border-radius: 0 6px 6px 0;
|
||||
border: 1px solid #0297f8;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
font-size: 15px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#unlock-btn:hover {
|
||||
background-color: #0287e8;
|
||||
}
|
||||
|
||||
.btn-hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.input-no-btn {
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
/* footer */
|
||||
.footer {
|
||||
right: 0;
|
||||
@@ -833,6 +921,65 @@ tbody {
|
||||
margin-bottom: -5px;
|
||||
}
|
||||
|
||||
#addPasswordWrapper {
|
||||
min-height: 24px;
|
||||
}
|
||||
|
||||
#addPassword {
|
||||
position: absolute;
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
#addPasswordWrapper label {
|
||||
line-height: 20px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
#addPassword:checked + label {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#addPasswordWrapper label::before {
|
||||
content: '';
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
margin-right: 10px;
|
||||
margin-left: 5px;
|
||||
float: left;
|
||||
border: 1px solid rgba(12, 12, 13, 0.3);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
#addPassword:checked + label::before {
|
||||
background-image: url('./check-16-blue.svg');
|
||||
background-position: 2px 1px;
|
||||
}
|
||||
|
||||
.banner {
|
||||
padding: 0 15px;
|
||||
height: 48px;
|
||||
background-color: #efeff1;
|
||||
color: #4a4a4f;
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.banner > div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.banner > div > span {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
@media (max-device-width: 992px), (max-width: 992px) {
|
||||
.popup .popuptext {
|
||||
left: auto;
|
||||
@@ -903,22 +1050,40 @@ tbody {
|
||||
padding: 5px 5px 5px 20px;
|
||||
}
|
||||
|
||||
#copy {
|
||||
#copy,
|
||||
.setPassword,
|
||||
#unlock {
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
#link {
|
||||
.selectPassword {
|
||||
align-self: center;
|
||||
min-width: 95%;
|
||||
}
|
||||
|
||||
#addPasswordWrapper label::before {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
#link,
|
||||
#unlock-input {
|
||||
font-size: 22px;
|
||||
padding: 15px 10px;
|
||||
border-radius: 6px 6px 0 0;
|
||||
}
|
||||
|
||||
#copy-btn {
|
||||
#copy-btn,
|
||||
#unlock-btn {
|
||||
border-radius: 0 0 6px 6px;
|
||||
flex: 0 1 65px;
|
||||
}
|
||||
|
||||
#copy-text {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
th {
|
||||
font-size: 14px;
|
||||
padding: 0 5px;
|
||||
|
||||
@@ -1 +1 @@
|
||||
<svg width="30" height="27" viewBox="0 0 30 27" xmlns="http://www.w3.org/2000/svg"><title>send logo</title><g stroke="#3E3D40" fill="none" fill-rule="evenodd"><path d="M22.364 19.989l-2.153-2.103a2.046 2.046 0 0 0-2.665-.151l3.402 3.323a.531.531 0 0 1 0 .766l-2.466 2.408a.563.563 0 0 1-.784 0l-3.398-3.32a1.932 1.932 0 0 0 .188 2.564l2.153 2.103c.788.77 2.066.77 2.855 0l2.868-2.802a1.94 1.94 0 0 0 0-2.788M8.77 14.745a.534.534 0 0 0 0 .766l3.399 3.32a2.05 2.05 0 0 1-2.625-.184l-2.153-2.102a1.94 1.94 0 0 1 0-2.79l2.869-2.801a2.052 2.052 0 0 1 2.854 0l2.153 2.103c.73.713.775 1.83.154 2.603l-3.401-3.323a.565.565 0 0 0-.784 0L8.77 14.745zm9.464 5.682a.777.777 0 0 1 0 1.118.822.822 0 0 1-1.144 0l-5.6-5.47a.777.777 0 0 1 0-1.118.822.822 0 0 1 1.144 0l5.6 5.47z" stroke-width=".618" fill="#3E3D40"/><path d="M6.065 20.606c-2.913-1.586-3.988-3.656-3.988-6.468 0-2.81 2.265-6.425 5.786-6.289.1.004.55-.006.649 0 .895-3.27 2.508-6.353 6.898-6.353 4.557 0 7.336 3.716 6.75 7.785.08-.005 1.232.17 1.31.186 3.096.644 4.915 3.275 4.915 5.18 0 1.905-.107 3.029-2.023 4.947" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></g></svg>
|
||||
<svg width="30" height="27" viewBox="0 0 30 27" xmlns="http://www.w3.org/2000/svg"><title>send logo</title><g stroke="#3E3D40" fill="none" fill-rule="evenodd" transform="translate(-0.231,0.11948695)"><path d="M22.364 19.989l-2.153-2.103a2.046 2.046 0 0 0-2.665-.151l3.402 3.323a.531.531 0 0 1 0 .766l-2.466 2.408a.563.563 0 0 1-.784 0l-3.398-3.32a1.932 1.932 0 0 0 .188 2.564l2.153 2.103c.788.77 2.066.77 2.855 0l2.868-2.802a1.94 1.94 0 0 0 0-2.788M8.77 14.745a.534.534 0 0 0 0 .766l3.399 3.32a2.05 2.05 0 0 1-2.625-.184l-2.153-2.102a1.94 1.94 0 0 1 0-2.79l2.869-2.801a2.052 2.052 0 0 1 2.854 0l2.153 2.103c.73.713.775 1.83.154 2.603l-3.401-3.323a.565.565 0 0 0-.784 0L8.77 14.745zm9.464 5.682a.777.777 0 0 1 0 1.118.822.822 0 0 1-1.144 0l-5.6-5.47a.777.777 0 0 1 0-1.118.822.822 0 0 1 1.144 0l5.6 5.47z" stroke-width=".618" fill="#3E3D40"/><path d="M6.065 20.606c-2.913-1.586-3.988-3.656-3.988-6.468 0-2.81 2.265-6.425 5.786-6.289.1.004.55-.006.649 0 .895-3.27 2.508-6.353 6.898-6.353 4.557 0 7.336 3.716 6.75 7.785.08-.005 1.232.17 1.31.186 3.096.644 4.915 3.275 4.915 5.18 0 1.905-.107 3.029-2.023 4.947" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.2 KiB |
10
browserconfig.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square70x70logo src=“favicon-76.png”/>
|
||||
<square150x150logo src="favicon-228.png"/>
|
||||
<TileColor>#0297F8</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
||||
@@ -67,6 +67,14 @@ Triggered whenever a user stops uploading a file. Includes:
|
||||
- `cd2`
|
||||
- `cd6`
|
||||
|
||||
#### `password-added`
|
||||
Triggered whenever a password is added to a file. Includes:
|
||||
|
||||
- `cm1`
|
||||
- `cm5`
|
||||
- `cm6`
|
||||
- `cm7`
|
||||
|
||||
#### `download-started`
|
||||
Triggered whenever a user begins downloading a file. Includes:
|
||||
|
||||
|
||||
2649
package-lock.json
generated
62
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "firefox-send",
|
||||
"description": "File Sharing Experiment",
|
||||
"version": "1.2.3",
|
||||
"version": "2.1.2",
|
||||
"author": "Mozilla (https://mozilla.org)",
|
||||
"repository": "mozilla/send",
|
||||
"homepage": "https://github.com/mozilla/send/",
|
||||
@@ -43,74 +43,76 @@
|
||||
"node": ">=8.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^7.1.4",
|
||||
"autoprefixer": "^7.1.6",
|
||||
"babel-core": "^6.26.0",
|
||||
"babel-loader": "^7.1.2",
|
||||
"babel-plugin-yo-yoify": "^0.7.0",
|
||||
"babel-plugin-yo-yoify": "^1.0.1",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"babel-preset-env": "^1.6.0",
|
||||
"babel-preset-env": "^1.6.1",
|
||||
"babel-preset-es2015": "^6.24.1",
|
||||
"babel-preset-stage-2": "^6.24.1",
|
||||
"copy-webpack-plugin": "^4.0.1",
|
||||
"cross-env": "^5.0.5",
|
||||
"base64-js": "^1.2.1",
|
||||
"copy-webpack-plugin": "^4.2.0",
|
||||
"cross-env": "^5.1.1",
|
||||
"css-loader": "^0.28.7",
|
||||
"css-mqpacker": "^6.0.1",
|
||||
"cssnano": "^3.10.0",
|
||||
"eslint": "^4.7.2",
|
||||
"eslint": "^4.10.0",
|
||||
"eslint-plugin-mocha": "^4.11.0",
|
||||
"eslint-plugin-node": "^5.1.1",
|
||||
"eslint-plugin-node": "^5.2.1",
|
||||
"eslint-plugin-security": "^1.4.0",
|
||||
"expose-loader": "^0.7.3",
|
||||
"extract-loader": "^1.0.1",
|
||||
"file-loader": "^0.11.2",
|
||||
"file-loader": "^1.1.5",
|
||||
"git-rev-sync": "^1.9.1",
|
||||
"github-changes": "^1.1.0",
|
||||
"github-changes": "^1.1.1",
|
||||
"html-loader": "^0.5.1",
|
||||
"husky": "^0.14.3",
|
||||
"lint-staged": "^4.2.3",
|
||||
"lint-staged": "^4.3.0",
|
||||
"mocha": "^3.5.3",
|
||||
"nanobus": "^4.2.0",
|
||||
"npm-run-all": "^4.1.1",
|
||||
"postcss-loader": "^2.0.6",
|
||||
"prettier": "^1.7.0",
|
||||
"nanobus": "^4.3.0",
|
||||
"npm-run-all": "^4.1.2",
|
||||
"postcss-loader": "^2.0.8",
|
||||
"prettier": "^1.8.2",
|
||||
"proxyquire": "^1.8.0",
|
||||
"raven-js": "^3.17.0",
|
||||
"raven-js": "^3.19.1",
|
||||
"redis-mock": "^0.20.0",
|
||||
"require-from-string": "^1.2.1",
|
||||
"require-from-string": "^2.0.1",
|
||||
"rimraf": "^2.6.2",
|
||||
"selenium-webdriver": "^3.5.0",
|
||||
"sinon": "^3.3.0",
|
||||
"selenium-webdriver": "^3.6.0",
|
||||
"sinon": "^4.1.2",
|
||||
"string-hash": "^1.1.3",
|
||||
"stylelint-config-standard": "^17.0.0",
|
||||
"stylelint-no-unsupported-browser-features": "^1.0.0",
|
||||
"stylelint-no-unsupported-browser-features": "^1.0.1",
|
||||
"supertest": "^3.0.0",
|
||||
"testpilot-ga": "^0.3.0",
|
||||
"val-loader": "^1.0.2",
|
||||
"webpack": "^3.6.0",
|
||||
"webpack-dev-server": "^2.8.2",
|
||||
"webpack": "^3.8.1",
|
||||
"webpack-dev-server": "2.9.1",
|
||||
"webpack-manifest-plugin": "^1.3.2",
|
||||
"webpack-unassert-loader": "^1.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"aws-sdk": "^2.122.0",
|
||||
"aws-sdk": "^2.149.0",
|
||||
"body-parser": "^1.18.2",
|
||||
"choo": "^6.1.0",
|
||||
"choo": "^6.5.1",
|
||||
"cldr-core": "^32.0.0",
|
||||
"connect-busboy": "0.0.2",
|
||||
"convict": "^4.0.0",
|
||||
"express": "^4.15.5",
|
||||
"express-request-language": "^1.1.12",
|
||||
"convict": "^4.0.1",
|
||||
"express": "^4.16.2",
|
||||
"fluent": "^0.4.1",
|
||||
"fluent-langneg": "^0.1.0",
|
||||
"helmet": "^3.8.1",
|
||||
"helmet": "^3.9.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
"mozlog": "^2.1.1",
|
||||
"raven": "^2.1.2",
|
||||
"raven": "^2.2.1",
|
||||
"redis": "^2.8.0"
|
||||
},
|
||||
"availableLanguages": [
|
||||
"en-US",
|
||||
"ast",
|
||||
"az",
|
||||
"bs",
|
||||
"ca",
|
||||
"cak",
|
||||
"cs",
|
||||
@@ -131,6 +133,7 @@
|
||||
"id",
|
||||
"it",
|
||||
"ja",
|
||||
"ka",
|
||||
"kab",
|
||||
"ko",
|
||||
"ms",
|
||||
@@ -144,6 +147,7 @@
|
||||
"sl",
|
||||
"sr",
|
||||
"sv-SE",
|
||||
"tl",
|
||||
"tr",
|
||||
"uk",
|
||||
"vi",
|
||||
|
||||
80
public/locales/ar/send.ftl
Normal file
@@ -0,0 +1,80 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = فَيَرفُكس سِنْد
|
||||
siteSubtitle = تجربة وِبّيّة
|
||||
siteFeedback = الانطباعات
|
||||
uploadPageHeader = شارِك ملفاتك بخصوصية وتعمية
|
||||
uploadPageExplainer = أرسل الملفات عبر رابط آمن خاص ومعمّى تنتهي صلاحيته تلقائيا لتضمن عدم بقاء ما ترسله إلى الأبد.
|
||||
uploadPageLearnMore = اطّلع على المزيد
|
||||
uploadPageDropMessage = أسقِط ملفّك هنا لبدء الرفع
|
||||
uploadPageSizeMessage = لتتحصل على أفضل تجربة، من المستحسن أن يكون الملف أصغر من 1 غ.بايت
|
||||
uploadPageBrowseButton = اختر ملفّا على حاسوبك
|
||||
.title = اختر ملفّا على حاسوبك
|
||||
uploadPageBrowseButton1 = اختر ملفّا لرفعه
|
||||
uploadPageMultipleFilesAlert = رفع عدة ملفات (أو رفع مجلد) ليس مدعوما حاليا.
|
||||
importingFile = يستورد…
|
||||
encryptingFile = يعمّي…
|
||||
decryptingFile = يفك التعمية…
|
||||
notifyUploadDone = انتهى الرفع.
|
||||
uploadingPageMessage = ما إن يُرفع الملف سيُتاح ضبط خيارات انتهاء صلاحيته.
|
||||
uploadingPageCancel = ألغِ الرفع
|
||||
.title = ألغِ الرفع
|
||||
uploadCancelNotification = أُلغي الرفع.
|
||||
uploadingPageLargeFileMessage = هذا الملف كبير الحجم وسيأخذ رفعه وقتا. انتظر رجاءً.
|
||||
uploadingFileNotification = أعلِمني عندما يكتمل الرفع.
|
||||
uploadSvgAlt
|
||||
.alt = ارفع
|
||||
copyUrlFormLabelWithName = انسخ الرابط وشاركه لإرسال الملف: { $filename }
|
||||
copyUrlFormButton = انسخ إلى الحافظة
|
||||
.title = انسخ إلى الحافظة
|
||||
copiedUrl = نُسخ!
|
||||
deleteFileButton = احذف الملف
|
||||
.title = احذف الملف
|
||||
sendAnotherFileLink = أرسل ملفّا آخر
|
||||
.title = أرسل ملفّا آخر
|
||||
// Alternative text used on the download link/button (indicates an action).
|
||||
downloadAltText
|
||||
.alt = نزّل
|
||||
downloadFileName = نزّل { $filename }
|
||||
unlockInputLabel = أدخل كلمة السر
|
||||
unlockInputPlaceholder = كلمة السر
|
||||
downloadFileTitle = نزِّل الملف المعمّى
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = يُرسل إليك صديقك ملفا عبر «فَيَرفُكس سِنْد»، وهي خدمة تتيح لك مشاركة الملفات عبر رابط آمن وخاص ومعمّى، حيث تنتهي صلاحياتها تلقائيا لتضمن عدم بقاء ما ترسله إلى الأبد.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = نزّل
|
||||
.title = نزّل
|
||||
downloadNotification = لقد اكتمل التنزيل.
|
||||
downloadFinish = اكتمل التنزيل
|
||||
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||
fileSizeProgress = ({ $partialSize } من أصل { $totalSize })
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
sendYourFilesLink = جرِّب «فَيَرفُكس سِنْد»
|
||||
downloadingPageMessage = رجاء أبقِ هذا اللسان مفتوحا حتى نجلب الملف ونفك تعميته.
|
||||
errorAltText
|
||||
.alt = خطأ أثناء الرفع
|
||||
errorPageHeader = حدث خطب ما.
|
||||
errorPageMessage = حدث خطب ما أثناء رفع الملف.
|
||||
errorPageLink = أرسل ملفا آخر
|
||||
fileTooBig = حجم الملف كبير للغاية لرفعه. يجب أن يكون أصغر من { $size }.
|
||||
notSupportedHeader = متصفحك غير مدعوم.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = للأسف فإن متصفحك لا يدعم تقنية الوِب التي يعتمد عليها «فَيَرفُكس سِنْد». عليك تجربة متصفح آخر، ونحن ننصحك بِفَيَرفُكس!
|
||||
notSupportedLink = لماذا متصفحي غير مدعوم؟
|
||||
notSupportedOutdatedDetail = للأسف فإن إصدارة فَيَرفُكس هذه لا تدعم تقنية الوِب التي يعتمد عليها «فَيَرفُكس سِنْد». عليك تحديث متصفحك.
|
||||
updateFirefox = حدّث فَيَرفُكس
|
||||
copyFileList = انسخ الرابط
|
||||
deleteFileList = احذف
|
||||
legalHeader = الشروط والخصوصية
|
||||
deletePopupText = أأحذف هذا الملف؟
|
||||
deletePopupYes = نعم
|
||||
deletePopupCancel = ألغِ
|
||||
deleteButtonHover
|
||||
.title = احذف
|
||||
copyUrlHover
|
||||
.title = انسخ الرابط
|
||||
footerLinkTerms = الشروط
|
||||
footerLinkCookies = الكعكات
|
||||
requirePasswordCheckbox = اطلب كلمة سر لتنزيل هذا الملف
|
||||
addPasswordButton = أضِف كلمة سر
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = كلمة السر: { $password }
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Unviar otru ficheru
|
||||
downloadAltText = Baxar
|
||||
downloadFileName = Baxar { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Introducir contraseña
|
||||
unlockInputPlaceholder = Contraseña
|
||||
unlockButtonLabel = Desbloquiar
|
||||
downloadFileTitle = Baxar ficheru cifráu
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = El to collaciu unvióte un ficheru usando Firefox Send, un serviciu que te permite compartir ficheros con un enllaz seguru, priváu y cifráu que caduca automáticamente p'asegurar que les to coses nun queden siempres na rede.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = Tocante a Test Pilot
|
||||
footerLinkPrivacy = Privacidá
|
||||
footerLinkTerms = Términos
|
||||
footerLinkCookies = Cookies
|
||||
requirePasswordCheckbox = Riquir una contraseña pa baxar esti ficheru
|
||||
addPasswordButton = Amestar contraseña
|
||||
passwordTryAgain = Contraseña incorreuta. Volvi tentalo.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Contraseña: { $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Başqa fayl göndər
|
||||
downloadAltText = Endir
|
||||
downloadFileName = { $filename } faylını endir
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Parol daxil edin
|
||||
unlockInputPlaceholder = Parol
|
||||
unlockButtonLabel = Aç
|
||||
downloadFileTitle = Şifrələnmiş Faylı Endir
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Yoldaşınız Firefox Send ilə sizə fayl göndərir, fayllarınızı təhlükəsiz, məxfi, şifrələnmiş və daima onlayn qalmaması üçün avtomatik silən fayl göndərmə xidməti.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,6 @@ footerLinkAbout = Test Pilot Haqqında
|
||||
footerLinkPrivacy = Məxfilik
|
||||
footerLinkTerms = Şərtlər
|
||||
footerLinkCookies = Çərəzlər
|
||||
requirePasswordCheckbox = Bu faylı endirmək üçün parol tələb et
|
||||
addPasswordButton = Parol əlavə et
|
||||
incorrectPassword = Xətalı parol. Təkrar yoxlayın.
|
||||
|
||||
91
public/locales/bs/send.ftl
Normal file
@@ -0,0 +1,91 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Send
|
||||
siteSubtitle = web eksperiment
|
||||
siteFeedback = Povratne informacije
|
||||
uploadPageHeader = Privatno, šifrovano dijeljenje datoteka
|
||||
uploadPageExplainer = Pošaljite datoteke putem sigurne, privatne i šifrovane veze koja automatski ističe kako bi se osiguralo da vaše stvari ne ostaju na mreži zauvijek.
|
||||
uploadPageLearnMore = Saznajte više
|
||||
uploadPageDropMessage = Prevucite vaše datoteke ovdje da biste počeli sa otpremanjem
|
||||
uploadPageSizeMessage = Za bolji rad predlažemo da datoteka ne bude veća od 1GB
|
||||
uploadPageBrowseButton = Odaberite datoteku na računaru
|
||||
uploadPageBrowseButton1 = Odaberite datoteku za otpremanje
|
||||
uploadPageMultipleFilesAlert = Otpremanje direktorija ili više datoteka trenutno nije podržano.
|
||||
uploadPageBrowseButtonTitle = Otpremi datoteku
|
||||
uploadingPageProgress = Otpremam { $filename } ({ $size })
|
||||
importingFile = Uvozim...
|
||||
verifyingFile = Potvrđujem...
|
||||
encryptingFile = Šifrujem...
|
||||
decryptingFile = Dešifrujem...
|
||||
notifyUploadDone = Vaše otpremanje je završeno.
|
||||
uploadingPageMessage = Nakon što se vaša datoteka otpremi, moći ćete da podesite opcije isteka.
|
||||
uploadingPageCancel = Otkaži otpremanje
|
||||
uploadCancelNotification = Vaše otpremanje je otkazano.
|
||||
uploadingPageLargeFileMessage = Ova datoteka je velika i otpremanje može potrajati. Budite strpljivi!
|
||||
uploadingFileNotification = Obavijesti me kada otpremanje bude gotovo.
|
||||
uploadSuccessConfirmHeader = Spremno za slanje
|
||||
uploadSvgAlt = Otpremi
|
||||
uploadSuccessTimingHeader = Veza prema vašoj datoteci će isteći nakon prvog preuzimanja ili za 24 sata.
|
||||
copyUrlFormLabelWithName = Iskopirajte i podijelite vezu da biste poslali datoteku: { $filename }
|
||||
copyUrlFormButton = Kopiraj u međuspremnik
|
||||
copiedUrl = Kopirano!
|
||||
deleteFileButton = Izbriši datoteku
|
||||
sendAnotherFileLink = Pošalji drugu datoteku
|
||||
// Alternative text used on the download link/button (indicates an action).
|
||||
downloadAltText = Preuzmi
|
||||
downloadFileName = Preuzmi { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Unesite lozinku
|
||||
unlockInputPlaceholder = Lozinka
|
||||
unlockButtonLabel = Otključaj
|
||||
downloadFileTitle = Preuzmi šifrovanu datoteku
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Vaš prijatelj vam je poslao datoteku preko usluge Firefox Send koja vam omogućava da dijelite datoteke preko sigurne, privatne i šifrovane veze koja samostalno ističe da vaše stvari ne ostanu zauvijek na internetu.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = Preuzmi
|
||||
downloadNotification = Vaše preuzimanje je završeno.
|
||||
downloadFinish = Preuzimanje završeno
|
||||
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||
fileSizeProgress = ({ $partialSize } od { $totalSize })
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
sendYourFilesLink = Probajte Firefox Send
|
||||
downloadingPageProgress = Preuzimanje { $filename } ({ $size })
|
||||
downloadingPageMessage = Ostavite ovaj tab otvorenim dok ne dobavimo vašu datoteku i dok je ne dešifrujemo.
|
||||
errorAltText = Greška pri otpremanju
|
||||
errorPageHeader = Nešto nije uredu!
|
||||
errorPageMessage = Dogodila se greška pri otpremanju datoteke.
|
||||
errorPageLink = Pošalji drugu datoteku
|
||||
fileTooBig = Ta datoteka je prevelika za otpremanje. Treba biti manja od { $size }.
|
||||
linkExpiredAlt = Veza istekla
|
||||
expiredPageHeader = Veza je istekla ili nikad nije postojala!
|
||||
notSupportedHeader = Vaš pretraživač nije podržan.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Ovaj pretraživač nažalost ne podržava web tehnologiju koja omogućava Firefox Send. Trebate probati drugi pretraživač. Preporučujemo Firefox!
|
||||
notSupportedLink = Zašto moj pretraživač nije podržan?
|
||||
notSupportedOutdatedDetail = Nažalost ova verzija Firefoxa ne podržava web tehnologiju koja omogućava Firefox Send. Morate ažurirati vaš pretraživač.
|
||||
updateFirefox = Ažuriraj Firefox
|
||||
downloadFirefoxButtonSub = Besplatno preuzimanje
|
||||
uploadedFile = Datoteka
|
||||
copyFileList = Kopiraj URL
|
||||
// expiryFileList is used as a column header
|
||||
expiryFileList = Ističe za
|
||||
deleteFileList = Izbriši
|
||||
nevermindButton = Zanemari
|
||||
legalHeader = Uslovi i privatnost
|
||||
legalNoticeTestPilot = Firefox Send je trenutno Test Pilot eksperiment i podržan je <a>uslovima korištenja</a> i <a>obavještenjem o privatnosti</a>. Možete saznati više o ovom eksperimentu i o njegovom sakupljanju podataka <a>ovdje</a>.
|
||||
legalNoticeMozilla = Korištenje Firefox Send web stranice podlaže Mozillinom <a>obavještenju o privatnosti na web stranicama</a> i <a>uslovima korištenja web stranica</a>.
|
||||
deletePopupText = Izbrisati ovu datoteku?
|
||||
deletePopupYes = Da
|
||||
deletePopupCancel = Otkaži
|
||||
deleteButtonHover = Izbriši
|
||||
copyUrlHover = Kopiraj URL
|
||||
footerLinkLegal = Pravno
|
||||
// Test Pilot is a proper name and should not be localized.
|
||||
footerLinkAbout = O Test Pilotu
|
||||
footerLinkPrivacy = Privatnost
|
||||
footerLinkTerms = Uslovi
|
||||
footerLinkCookies = Kolačići
|
||||
requirePasswordCheckbox = Zahtjevaj lozinku za preuzimanje ove datoteke
|
||||
addPasswordButton = Dodaj lozinku
|
||||
passwordTryAgain = Netačna lozinka. Pokušajte ponovo.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Lozinka: { $password }
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Titaq jun chik yakb'äl
|
||||
downloadAltText = Tiqasäx
|
||||
downloadFileName = Tiqasäx { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Titz'ib'äx Ewan Tzij
|
||||
unlockInputPlaceholder = Ewan tzij
|
||||
unlockButtonLabel = Titzij chik
|
||||
downloadFileTitle = Tiqasäx Yakb'äl Ewan Rusik'ixik
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Jun awachib'il xutäq jun yakb'äl chawe rik'in ri Firefox Send, jun samaj ri nuya' q'ij chawe ye'akomonij taq yakb'äl rik'in jun jikïl, ichinan chuqa' ewan rusik'ixik ximonel, ri nik'is ruq'ijul pa ruyonil richin chi ri taq awachinaq man junelïk ta e okel pa k'amab'ey.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = Chi rij Test Pilot
|
||||
footerLinkPrivacy = Ichinanem
|
||||
footerLinkTerms = Taq ojqanem
|
||||
footerLinkCookies = Taq kaxlanwey
|
||||
requirePasswordCheckbox = Tik'utüx jun ewan tzij richin niqasäx re yakb'äl re'
|
||||
addPasswordButton = Titz'aqatisäx Ewan Tzij
|
||||
passwordTryAgain = Itzel ri ewan tzij. Tatojtob'ej chik.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Ewan tzij: { $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Poslat další soubor
|
||||
downloadAltText = Stáhnout
|
||||
downloadFileName = Stáhnout { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Zadejte heslo
|
||||
unlockInputPlaceholder = Heslo
|
||||
unlockButtonLabel = Odemknout
|
||||
downloadFileTitle = Stáhnout šifrovaný soubor
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Někdo vám posílá soubor pomocí služby Firefox Send, které umožňuje bezpečné, soukromé a šifrované sdílení souborů, které jsou pak automaticky smazány, aby nezůstaly na internetu navěky.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = O programu Test Pilot
|
||||
footerLinkPrivacy = Soukromí
|
||||
footerLinkTerms = Podmínky
|
||||
footerLinkCookies = Cookies
|
||||
requirePasswordCheckbox = Vyžadovat heslo pro stažení tohoto souboru
|
||||
addPasswordButton = Přidat heslo
|
||||
passwordTryAgain = Špatné heslo. Zkuste to znovu.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Heslo: { $password }
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
title = Firefox Send
|
||||
siteSubtitle = arbrawf gwe
|
||||
siteFeedback = Adborth
|
||||
uploadPageHeader = Rhannu Ffeiliau wedi eu Hamgryptio Preifat
|
||||
uploadPageHeader = Rhannu Ffeiliau wedi eu Hamgryptio yn Breifat
|
||||
uploadPageExplainer = Anfon ffeiliau drwy ddolen diogel, breifat ac wedi ei amgryptio sy'n dod i ben yn awtomatig er mwyn sicrhau nad yw eich pethau'n bodoli ar lein am byth.
|
||||
uploadPageLearnMore = Dysgu rhagor
|
||||
uploadPageDropMessage = Gollyngwch eich ffeiliau yma i gychwyn llwytho i fyny
|
||||
uploadPageSizeMessage = Mae'n well cadw maint y ffeiliau o dan 1GB er mwyn iddo weithio ar ei orau.
|
||||
uploadPageBrowseButton = Dewiswch ffeil ar eich cyfrifiadur
|
||||
uploadPageBrowseButton1 = Dewiswch ffeil i'w llwytho i fyny
|
||||
uploadPageMultipleFilesAlert = Nid yw llwytho nifer lluosog o ffeilia neu ffolder yn cael ei gynnal ar hyn o bryd.
|
||||
uploadPageMultipleFilesAlert = Nid yw llwytho nifer lluosog o ffeiliau neu ffolder yn cael ei gynnal ar hyn o bryd.
|
||||
uploadPageBrowseButtonTitle = Llwytho ffeil i fyny
|
||||
uploadingPageProgress = Llwytho $filename} i fyny ({ $size })
|
||||
importingFile = Mewnforio…
|
||||
@@ -17,13 +17,13 @@ verifyingFile = Wrthi'n gwirio…
|
||||
encryptingFile = Wrthi'n amgryptio…
|
||||
decryptingFile = Wrthi'n dadgryptio…
|
||||
notifyUploadDone = Mae eich llwytho wedi gorffen.
|
||||
uploadingPageMessage = Unwaith y bydd eich ffeil wedi llwytho bydd modd gosod manylion dod i ben.
|
||||
uploadingPageMessage = Unwaith y bydd eich ffeil wedi llwytho bydd modd gosod y manylion dod i ben.
|
||||
uploadingPageCancel = Diddymu'r llwytho
|
||||
uploadCancelNotification = Cafodd eich llwytho ei ddiddymu.
|
||||
uploadingPageLargeFileMessage = Mae'r ffeil yn fawr a gall gymryd peth amser i'w llwytho. Arhoswch!
|
||||
uploadingFileNotification = Dweud wrtha i pan fydd y llwytho wedi gorffen.
|
||||
uploadingPageLargeFileMessage = Mae'r ffeil yn fawr a gall gymryd peth amser i'w llwytho. Amynedd!
|
||||
uploadingFileNotification = Dweud pan fydd y llwytho wedi gorffen.
|
||||
uploadSuccessConfirmHeader = Yn Barod i Anfon
|
||||
uploadSvgAlt = LLwytho i Fyny
|
||||
uploadSvgAlt = Llwytho i Fyny
|
||||
uploadSuccessTimingHeader = Bydd y ddolen i'ch ffeil y dod i ben ar ôl 1 llwytho neu o fewn 24 awr.
|
||||
copyUrlFormLabelWithName = Copïo a rhannu'r ddolen i anfon eich ffeil: { $filename }
|
||||
copyUrlFormButton = Copïo i'r clipfwrdd
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Anfon ffeil arall
|
||||
downloadAltText = Llwytho i lawr
|
||||
downloadFileName = Llwytho i lawr { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Rhowch Gyfrinair
|
||||
unlockInputPlaceholder = Cyfrinair
|
||||
unlockButtonLabel = Datgloi
|
||||
downloadFileTitle = Llwythwch Ffeil wedi ei Hamgryptio i Lawr
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Mae ffrind i chi yn anfon ffeil atoch drwy Firefox Send, gwasanaeth sy'n caniatáu i chi rannu ffeiliau drwy ddolen ddiogel, breifat ac wedi ei amgryptio sy'n dod i ben yn awtomatig er mwyn sicrhau nad yw eich deunydd yn aros ar-lein am byth.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -43,7 +47,7 @@ downloadFinish = Llwytho wedi Gorffen
|
||||
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||
fileSizeProgress = ({ $partialSize } o { $totalSize })
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
sendYourFilesLink = Profwch Firefox Send
|
||||
sendYourFilesLink = Rhowch gynnig ar Firefox Send
|
||||
downloadingPageProgress = Llwytho i lawr { $filename } ({ $size })
|
||||
downloadingPageMessage = Gadewch y tab yma ar agor tra fyddwn yn estyn eich ffeil a'i dad-amgryptio.
|
||||
errorAltText = Gwall llwytho
|
||||
@@ -55,9 +59,9 @@ linkExpiredAlt = Mae'r ddolen wedi dod i ben
|
||||
expiredPageHeader = Mae'r ddolen wedi dod i ben neu nad yw wedi bodoli erioed!
|
||||
notSupportedHeader = Nid yw eich porwr yn cael ei gynnal.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Yn anffodus nid yw'r porwr hwn yn cynnal y technoleg gwe sy'n cynnal Firefox Send. Bydd angen i chi ddefnyddio porwr arall. Rydym ni'n argymell Firefox!
|
||||
notSupportedDetail = Yn anffodus, nid yw'r porwr hwn yn cynnal y technoleg gwe sy'n cynnal Firefox Send. Bydd angen i chi ddefnyddio porwr arall. Rydym ni'n argymell Firefox!
|
||||
notSupportedLink = Pam nad yw fy mhorwr yn cael ei gynnal?
|
||||
notSupportedOutdatedDetail = Yn anffodus nid yw'r fersiwn yma o Firefox yn cynnal y technoleg gwe sy'n gyrru Firefox Send. Bydd angen i chi ddiweddaru eich porwr.
|
||||
notSupportedOutdatedDetail = Yn anffodus, nid yw'r fersiwn yma o Firefox yn cynnal y technoleg gwe sy'n gyrru Firefox Send. Bydd angen i chi ddiweddaru eich porwr.
|
||||
updateFirefox = Diweddaru Firefox
|
||||
downloadFirefoxButtonSub = Llwytho i Lawr am Ddim
|
||||
uploadedFile = Ffeil
|
||||
@@ -67,7 +71,7 @@ expiryFileList = Daw i ben ymhen
|
||||
deleteFileList = Dileu
|
||||
nevermindButton = Dim ots
|
||||
legalHeader = Amodau a Phreifatrwydd
|
||||
legalNoticeTestPilot = Ar hyn o mae Firefox Send yn arbrawf o fewn rhaglen Test Pilot ac yn destun <a>Amodau Gwasanaeth</a> a <a>Hysbysiad Preifatrwydd</a> Test Pilot . Gallwch ddysgu rhagor am yr arbrawf a'i gasglu data <a>yma</a>.
|
||||
legalNoticeTestPilot = Ar hyn o mae Firefox Send yn arbrawf o fewn rhaglen Test Pilot ac yn destun <a>Amodau Gwasanaeth</a> a <a>Hysbysiad Preifatrwydd</a> Test Pilot . Gallwch ddysgu rhagor am yr arbrawf a'r data mae'n ei gasglu <a>yma</a>.
|
||||
legalNoticeMozilla = Mae'r defnydd o wefan Firefox Send hefyd yn destun <a>Hysbysiad Preifatrwydd Gwefannau</a> ac <a>Amodau Defnydd Gwefannau</a> Mozilla.
|
||||
deletePopupText = Dileu'r ffeil?
|
||||
deletePopupYes = Iawn
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = Ynghylch Test Pilot
|
||||
footerLinkPrivacy = Preifatrwydd
|
||||
footerLinkTerms = Amodau
|
||||
footerLinkCookies = Cwcis
|
||||
requirePasswordCheckbox = Gosod angen cyfrinair i lwytho'r ffeil hon i lawr
|
||||
addPasswordButton = Ychwanegu Cyfrinair
|
||||
passwordTryAgain = Cyfrinair anghywir. Ceisiwch eto.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Cyfrinair: { $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Eine weitere Datei senden
|
||||
downloadAltText = Herunterladen
|
||||
downloadFileName = { $filename } herunterladen
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Passwort eingeben
|
||||
unlockInputPlaceholder = Passwort
|
||||
unlockButtonLabel = Entsperren
|
||||
downloadFileTitle = Verschlüsselte Datei herunterladen
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Ihr Freund schickt Ihnen eine Datei mit Firefox Send, einem Dienst, mit dem Sie Dateien über einen sicheren, privaten und verschlüsselten Link teilen können, der automatisch abläuft, damit Ihre Daten nicht für immer im Internet bleiben.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = Über Test Pilot
|
||||
footerLinkPrivacy = Datenschutz
|
||||
footerLinkTerms = Nutzungsbedingungen
|
||||
footerLinkCookies = Cookies
|
||||
requirePasswordCheckbox = Zum Herunterladen dieser Datei soll ein Passwort erforderlich sein
|
||||
addPasswordButton = Passwort hinzufügen
|
||||
passwordTryAgain = Falsches Passwort. Versuchen Sie es erneut.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Passwort: { $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Drugu dataju pósłaś
|
||||
downloadAltText = Ześěgnuś
|
||||
downloadFileName = { $filename } ześěgnuś
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Gronidło zapódaś
|
||||
unlockInputPlaceholder = Gronidło
|
||||
unlockButtonLabel = Wótwóriś
|
||||
downloadFileTitle = Skoděrowanu dataju ześěgnuś
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Waš pśijaśel wam dataju z Firefox Send sćelo, słužba, kótaraž wam zmóžnja, dataje pśez wěsty, priwatny a skoděrowany wótkaz źěliś, kótaryž awtomatiski spadnjo, až njeby waše daty na pśecej online wóstawali.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = Wó Test Pilot
|
||||
footerLinkPrivacy = Priwatnosć
|
||||
footerLinkTerms = Wuměnjenja
|
||||
footerLinkCookies = Cookieje
|
||||
requirePasswordCheckbox = Gronidło za ześěgnjenje toś teje dataje pominaś
|
||||
addPasswordButton = Gronidło pśidaś
|
||||
passwordTryAgain = Wopacne gronidło. Wopytajśo hyšći raz.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Gronidło: { $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Αποστολή άλλου αρχείου
|
||||
downloadAltText = Λήψη
|
||||
downloadFileName = Λήψη του { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Εισαγωγή κωδικού πρόσβασης
|
||||
unlockInputPlaceholder = Κωδικός πρόσβασης
|
||||
unlockButtonLabel = Ξεκλείδωμα
|
||||
downloadFileTitle = Λήψη κρυπτογραφημένου αρχείου
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Ο/Η φίλος/-η σας, σάς στέλνει ένα αρχείο με τη βοήθεια του Firefox Send, μιας υπηρεσίας που επιτρέπει τον διαμοιρασμό αρχείων μέσω ενός ασφαλούς, ιδιωτικού και κρυπτογραφημένου συνδέσμου που λήγει αυτόματα, ώστε να είστε σίγουροι ότι τα αρχεία σας δεν θα παραμείνουν στο διαδίκτυο για πάντα.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,6 @@ footerLinkAbout = Σχετικά με το Test Pilot
|
||||
footerLinkPrivacy = Απόρρητο
|
||||
footerLinkTerms = Όροι
|
||||
footerLinkCookies = Cookies
|
||||
requirePasswordCheckbox = Απαίτηση κωδικού πρόσβασης για λήψη του αρχείου
|
||||
addPasswordButton = Προσθήκη κωδικού πρόσβασης
|
||||
incorrectPassword = Λάθος κωδικός πρόσβασης. Προσπάθεια ξανά;
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Send another file
|
||||
downloadAltText = Download
|
||||
downloadFileName = Download { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Enter Password
|
||||
unlockInputPlaceholder = Password
|
||||
unlockButtonLabel = Unlock
|
||||
downloadFileTitle = Download Encrypted File
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Your friend is sending you a file with Firefox Send, a service that allows you to share files with a safe, private, and encrypted link that automatically expires to ensure your stuff does not remain online forever.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = About Test Pilot
|
||||
footerLinkPrivacy = Privacy
|
||||
footerLinkTerms = Terms
|
||||
footerLinkCookies = Cookies
|
||||
requirePasswordCheckbox = Require a password to download this file
|
||||
addPasswordButton = Add password
|
||||
passwordTryAgain = Incorrect password. Try again.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Password: { $password }
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Enviar otro archivo
|
||||
downloadAltText = Descargar
|
||||
downloadFileName = Descargar { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Ingresar contraseña
|
||||
unlockInputPlaceholder = Contraseña
|
||||
unlockButtonLabel = Desbloquear
|
||||
downloadFileTitle = Descargar archivo cifrado
|
||||
// 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.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = Acerca de Test Pilot
|
||||
footerLinkPrivacy = Privacidad
|
||||
footerLinkTerms = Términos
|
||||
footerLinkCookies = Cookies
|
||||
requirePasswordCheckbox = Requerir contraseña para descargar este archivo
|
||||
addPasswordButton = Agregar contraseña
|
||||
passwordTryAgain = Contraseña incorrecta. Intentá nuevamente.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Contraseña: { $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Enviar otro archivo
|
||||
downloadAltText = Descargar
|
||||
downloadFileName = Descargar { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Ingresar contraseña
|
||||
unlockInputPlaceholder = Contraseña
|
||||
unlockButtonLabel = Desbloquear
|
||||
downloadFileTitle = Bajar archivo cifrado
|
||||
// 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.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = Acerca de Test Pilot
|
||||
footerLinkPrivacy = Privacidad
|
||||
footerLinkTerms = Términos
|
||||
footerLinkCookies = Cookies
|
||||
requirePasswordCheckbox = Requerir una contraseña para descargar este archivo
|
||||
addPasswordButton = Añadir contraseña
|
||||
passwordTryAgain = Contraseña incorrecta. Vuelve a intentarlo.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Contraseña: { $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Enviar otro archivo
|
||||
downloadAltText = Descargar
|
||||
downloadFileName = Descargar { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Introducir contraseña
|
||||
unlockInputPlaceholder = Contraseña
|
||||
unlockButtonLabel = Desbloquear
|
||||
downloadFileTitle = Descargar archivo encriptado
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Tu amigo te está enviando un archivo a través de Firefox Send, un servicio que te permite compartir archivos con un enlace seguro, privado y cifrado que caduca automáticamente para que tus cosas no sean accesibles en línea de por vida.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = Sobre Test Pilot
|
||||
footerLinkPrivacy = Privacidad
|
||||
footerLinkTerms = Términos
|
||||
footerLinkCookies = Cookies
|
||||
requirePasswordCheckbox = Requerir una contraseña para descargar este archivo
|
||||
addPasswordButton = Añadir contraseña
|
||||
passwordTryAgain = Contraseña incorrecta. Inténtelo de nuevo.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Contraseña: { $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Enviar otro archivo
|
||||
downloadAltText = Descargar
|
||||
downloadFileName = Descargar ($filename)
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Ingresar contraseña
|
||||
unlockInputPlaceholder = Contraseña
|
||||
unlockButtonLabel = Desbloquear
|
||||
downloadFileTitle = Descargar archivo encriptado
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Tu amigo te está enviando un archivo a través de Firefox Send, un servicio que te permite compartir archivos con un enlace seguro, privado y encriptado que caduca automáticamente para que tus cosas no sean accesibles en línea de por vida.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = Acerca de Test Pilot
|
||||
footerLinkPrivacy = Privacidad
|
||||
footerLinkTerms = Términos
|
||||
footerLinkCookies = Cookies
|
||||
requirePasswordCheckbox = Se necesita una contraseña para descargar este archivo
|
||||
addPasswordButton = Agregar contraseña
|
||||
passwordTryAgain = Contraseña incorrecta. Intenta de nuevo.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Contraseña: { $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Saada järgmine fail
|
||||
downloadAltText = Laadi alla
|
||||
downloadFileName = Laadi fail { $filename } alla
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Sisesta parool
|
||||
unlockInputPlaceholder = Parool
|
||||
unlockButtonLabel = Ava
|
||||
downloadFileTitle = Krüptitud faili allalaadimine
|
||||
// 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.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = Test Pilotist
|
||||
footerLinkPrivacy = Privaatsusest
|
||||
footerLinkTerms = Teenusetingimused
|
||||
footerLinkCookies = Küpsistest
|
||||
requirePasswordCheckbox = Selle faili allalaadimiseks nõutakse parooli
|
||||
addPasswordButton = Lisa parool
|
||||
passwordTryAgain = Vale parool. Palun proovi uuesti.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Parool: { $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = ارسال پرونده دیگر
|
||||
downloadAltText = دریافت
|
||||
downloadFileName = بارگیری { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = گذرواژه را وارد کنید
|
||||
unlockInputPlaceholder = گذرواژه
|
||||
unlockButtonLabel = باز کردن
|
||||
downloadFileTitle = دریافت پروندهٔ رمزنگاری شده
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = دوست شما درحال ارسال پرونده ای به وسیله Firefox Send است، این سرویس این امکان را به شما میدهد تا پروندههای خود را به صورت ایمن،خصوصی و رمزنگاری شده به همراه پیوند انقضا خودکار همرسانی کنید تا اطمینان حاصل کنید چیزهای شما برای همیشه آنلاین باقی نخواهد ماند.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,6 @@ footerLinkAbout = درباره Test Pilot
|
||||
footerLinkPrivacy = حریمخصوصی
|
||||
footerLinkTerms = شرایط
|
||||
footerLinkCookies = کوکیها
|
||||
requirePasswordCheckbox = دریافت این پرونده نیاز به گذرواژه دارد
|
||||
addPasswordButton = افزودن گذرواژه
|
||||
passwordTryAgain = کلمه عبور اشتباه است. مجدد تلاش کنید.
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Envoyer un autre fichier
|
||||
downloadAltText = Télécharger
|
||||
downloadFileName = Télécharger { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Saisissez un mot de passe
|
||||
unlockInputPlaceholder = Mot de passe
|
||||
unlockButtonLabel = Déverrouiller
|
||||
downloadFileTitle = Télécharger le fichier chiffré
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Votre ami⋅e vous a envoyé un fichier avec Firefox Send, un service qui permet d’envoyer des fichiers de façon sécurisée, confidentielle et chiffrée via un lien qui expire automatiquement pour que vos informations ne restent pas en ligne indéfiniment.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = À propos de Test Pilot
|
||||
footerLinkPrivacy = Confidentialité
|
||||
footerLinkTerms = Conditions d’utilisation
|
||||
footerLinkCookies = Cookies
|
||||
requirePasswordCheckbox = Exiger un mot de passe pour télécharger ce fichier
|
||||
addPasswordButton = Ajouter un mot de passe
|
||||
passwordTryAgain = Mot de passe incorrect. Veuillez réessayer.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Mot de passe : { $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Noch in bestân ferstjoere
|
||||
downloadAltText = Downloade
|
||||
downloadFileName = { $filename } downloade
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Wachtwurd ynfiere
|
||||
unlockInputPlaceholder = Wachtwurd
|
||||
unlockButtonLabel = Deblokkearje
|
||||
downloadFileTitle = Fersifere bestân downloade
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Jo freon stjoert jo in best^n mei Firefox Send, in tsjinst dy't jo yn steat stelt bestannen te dielen mei in feilige, privee en fersifere keppeling dy't automatysk ferrint om wis te wêzen dat jo guod net foar altyd online bliuwt.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = Oer Test Pilot
|
||||
footerLinkPrivacy = Privacy
|
||||
footerLinkTerms = Betingsten
|
||||
footerLinkCookies = Cookies
|
||||
requirePasswordCheckbox = Om dit bestân te downloaden is in wachtwurd fereaske
|
||||
addPasswordButton = Wachtwurd tafoegje
|
||||
passwordTryAgain = Net krekt wachtwurd. Probearje it opnij.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Wachtwurd: { $password }
|
||||
|
||||
73
public/locales/he/send.ftl
Normal file
@@ -0,0 +1,73 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Send
|
||||
siteSubtitle = ניסוי אינטרנט
|
||||
siteFeedback = משוב
|
||||
uploadPageHeader = שיתוף קבצים פרטי, מוצפן
|
||||
uploadPageExplainer = לשלוח קבצים דרך קישור בטוח, פרטי ומוצפן שפג אוטומטית, כדי לוודא שהתכנים הפרטיים שלך לא יהיו ברשת לנצח.
|
||||
uploadPageLearnMore = מידע נוסף
|
||||
uploadPageDropMessage = יש לגרור קבצים לכאן כדי להתחיל בהעלאה
|
||||
uploadPageSizeMessage = להשגת ביצועים מיטביים, מוטב לשמור על הקובץ מתחת לגודל של 1 ג״ב
|
||||
uploadPageBrowseButton1 = נא לבחור קובץ להעלאה
|
||||
uploadPageMultipleFilesAlert = העלאה של מספר קבצים או ספריה אינה נתמכת כרגע.
|
||||
uploadPageBrowseButtonTitle = העלאת קובץ
|
||||
uploadingPageProgress = { $filename } ({ $size }) בהעלאה
|
||||
importingFile = מתבצע ייבוא...
|
||||
verifyingFile = מתבצע אימות…
|
||||
encryptingFile = מתבצעת הצפנה...
|
||||
decryptingFile = מתבצע פענוח...
|
||||
notifyUploadDone = ההעלאה שלך הסתיימה
|
||||
uploadingPageMessage = אחרי שהקובץ שלך יעלה, ניתן יהיה להגדיר אפשרויות תפוגה.
|
||||
uploadCancelNotification = ההעלאה שלך בוטלה.
|
||||
uploadingPageLargeFileMessage = קובץ זה גדול ועלול לקחת זמן להעלות אותו. סבלנות!
|
||||
uploadingFileNotification = נא להודיע לי כשתסתיים ההעלאה.
|
||||
uploadSuccessConfirmHeader = מוכן לשליחה
|
||||
uploadSvgAlt
|
||||
.alt = להעלות
|
||||
uploadSuccessTimingHeader = הקישור לקובץ שלך יפוג אחרי הורדה אחת או בעוד 24 שעות.
|
||||
copyUrlFormLabelWithName = ניתן להעתיק ולשתף את הקישור כדי לשלוח את הקובץ שלך: { $filename }
|
||||
copiedUrl = הועתק!
|
||||
deleteFileButton = מחיקת קובץ
|
||||
.title = מחיקת קובץ
|
||||
sendAnotherFileLink = שליחת קובץ נוסף
|
||||
.title = שליחת קובץ נוסף
|
||||
// Alternative text used on the download link/button (indicates an action).
|
||||
downloadAltText
|
||||
.alt = הורדה
|
||||
downloadFileName = ההורדה נכשלה
|
||||
downloadFileSize = ({ $size })
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = הורדה
|
||||
.title = הורדה
|
||||
downloadNotification = ההורדה הושלמה.
|
||||
downloadFinish = ההורדה הושלמה
|
||||
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||
fileSizeProgress = ({ $partialSize } מתוך { $totalSize })
|
||||
downloadingPageProgress = בהורדה: { $filename } ({ $size })
|
||||
errorAltText
|
||||
.alt = תקלה בהעלאה
|
||||
errorPageHeader = משהו השתבש!
|
||||
errorPageLink = שליחת קובץ נוסף
|
||||
fileTooBig = הקובץ הזה גדול מידי להעלאה. עליו להיות קטן מ־{ $size }.
|
||||
linkExpiredAlt
|
||||
.alt = קישור פג
|
||||
notSupportedHeader = הדפדפן שלך לא נתמך.
|
||||
notSupportedLink = למה אין תמיכה בדפדפן שלי?
|
||||
downloadFirefoxButtonSub = הורדה בחינם
|
||||
uploadedFile = קובץ
|
||||
copyFileList = העתקת כתובת
|
||||
// expiryFileList is used as a column header
|
||||
expiryFileList = יפוג בעוד
|
||||
deleteFileList = מחיקה
|
||||
nevermindButton = לא משנה
|
||||
legalHeader = תנאי שירות ופרטיות
|
||||
deletePopupText = למחוק דף זה?
|
||||
deletePopupYes = כן
|
||||
deletePopupCancel = ביטול
|
||||
deleteButtonHover
|
||||
.title = מחיקה
|
||||
copyUrlHover
|
||||
.title = העתקת קישור
|
||||
footerLinkLegal = מידע משפטי
|
||||
footerLinkPrivacy = פרטיות
|
||||
footerLinkTerms = תנאי שימוש
|
||||
footerLinkCookies = קובצי עוגיות
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Druhu dataju pósłać
|
||||
downloadAltText = Sćahnyć
|
||||
downloadFileName = { $filename } sćahnyć
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Hesło zapodać
|
||||
unlockInputPlaceholder = Hesło
|
||||
unlockButtonLabel = Wotewrěć
|
||||
downloadFileTitle = Zaklučowanu dataju sćahnyć
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Waš přećel wam dataju z Firefox Send sćele, słužba, kotraž wam zmóžnja, dataje přez wěsty, priwatny a zaklučowany wotkaz dźělić, kotryž awtomatisce spadnje, zo njebychu waše daty na přeco online wostawali.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = Wo Test Pilot
|
||||
footerLinkPrivacy = Priwatnosć
|
||||
footerLinkTerms = Wuměnjenja
|
||||
footerLinkCookies = Placki
|
||||
requirePasswordCheckbox = Žadajće sej hesło za sćehnjenje tuteje dataje
|
||||
addPasswordButton = Hesło přidać
|
||||
passwordTryAgain = Wopačne hesło. Prošu spytajće hišće raz.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Hesło: { $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Még egy fájl küldése
|
||||
downloadAltText = Letöltés
|
||||
downloadFileName = { $filename } letöltése
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Adja meg a jelszót
|
||||
unlockInputPlaceholder = Jelszó
|
||||
unlockButtonLabel = Feloldás
|
||||
downloadFileTitle = Titkosított fájl letöltése
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Az ismerőse egy fájlt küld a Firefox Senddel, egy olyan fájlmegosztó szolgáltatással, amely biztonságos, privát és titkosított hivatkozáson keresztül működik, amely automatikusan elévül, így biztosítva hogy a dolga ne maradjon örökre online.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = A Tesztpilóta névjegye
|
||||
footerLinkPrivacy = Adatvédelem
|
||||
footerLinkTerms = Feltételek
|
||||
footerLinkCookies = Sütik
|
||||
requirePasswordCheckbox = Jelszó megkövetelése a fájl letöltéséhez
|
||||
addPasswordButton = Jelszó hozzáadása
|
||||
passwordTryAgain = Helytelen jelszó. Próbálja meg újra.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Jelszó: { $password }
|
||||
|
||||
@@ -8,9 +8,11 @@ uploadPageLearnMore = Pelajari lebih lanjut
|
||||
uploadPageDropMessage = Lepas berkas Anda di sini untuk mulai mengunggah
|
||||
uploadPageSizeMessage = Untuk pengoperasian yang paling andal, sebaiknya jaga berkas Anda di bawah 1GB
|
||||
uploadPageBrowseButton = Pilih berkas pada komputer Anda
|
||||
uploadPageBrowseButton1 = Pilih berkas untuk diunggah
|
||||
.title = Pilih berkas untuk diunggah
|
||||
uploadPageMultipleFilesAlert = Saat ini belum mendukung pengunggahan beberapa berkas atau folder.
|
||||
uploadPageBrowseButtonTitle = Unggah berkas
|
||||
uploadingPageHeader = Mengunggah Berkas Anda
|
||||
uploadingPageProgress = Mengunggah { $filename } ({ $size })
|
||||
importingFile = Mengimpor…
|
||||
verifyingFile = Memverifikasi…
|
||||
encryptingFile = Mengenkripsi...
|
||||
@@ -33,12 +35,17 @@ sendAnotherFileLink = Kirim berkas lain
|
||||
downloadAltText = Unduh
|
||||
downloadFileName = Unduh { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Masukkan Sandi
|
||||
unlockInputPlaceholder = Sandi
|
||||
downloadFileTitle = Unduh Berkas Terenkripsi
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Teman Anda mengirimkan berkas dengan Firefox Send, layanan yang memungkinkan Anda berbagi berkas dengan tautan yang aman, pribadi, dan terenkripsi yang secara otomatis berakhir untuk memastikan berkas Anda tidak daring selamanya.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = Unduh
|
||||
downloadNotification = Unduhan Anda telah selesai.
|
||||
downloadFinish = Unduhan Selesai
|
||||
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||
fileSizeProgress = ({ $partialSize } dari { $totalSize })
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
sendYourFilesLink = Coba Firefox Send
|
||||
downloadingPageProgress = Mengunduh { $filename } ({ $size })
|
||||
@@ -77,3 +84,6 @@ footerLinkAbout = Tentang Test Pilot
|
||||
footerLinkPrivacy = Privasi
|
||||
footerLinkTerms = Ketentuan
|
||||
footerLinkCookies = Kuki
|
||||
requirePasswordCheckbox = Membutuhkan sandi untuk mengunduh berkas ini
|
||||
addPasswordButton = Tambahkan Sandi
|
||||
incorrectPassword = Sandi salah. Coba lagi?
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Invia un altro file
|
||||
downloadAltText = Scarica
|
||||
downloadFileName = Scarica { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Inserire la password
|
||||
unlockInputPlaceholder = Password
|
||||
unlockButtonLabel = Sblocca
|
||||
downloadFileTitle = Scarica il file crittato
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Qualcuno ha utilizzato Firefox Send per inviarti un file. Si tratta di un servizio che permette di condividere file in modo sicuro, riservato e crittato, utilizzando un link che smette di funzionare automaticamente dopo un certo periodo di tempo, garantendo così che i tuoi dati non rimangano online per sempre.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = Informazioni su Test Pilot
|
||||
footerLinkPrivacy = Privacy
|
||||
footerLinkTerms = Condizioni di utilizzo
|
||||
footerLinkCookies = Cookie
|
||||
requirePasswordCheckbox = Richiedi una password per poter scaricare questo file
|
||||
addPasswordButton = Aggiungi password
|
||||
passwordTryAgain = Password errata, riprovare.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Password: { $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = 他のファイルを送信
|
||||
downloadAltText = ダウンロード
|
||||
downloadFileName = { $filename } をダウンロード
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = パスワードを入力
|
||||
unlockInputPlaceholder = パスワード
|
||||
unlockButtonLabel = ロック解除
|
||||
downloadFileTitle = 暗号化されたファイルをダウンロード
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = あなたの友人が Firefox Send を通じてファイルを送ってきています。これは、安全で、プライベートで、暗号化されたリンクを通じてファイルを共有できるサービスです。あなたのものがずっとオンラインに残らないよう、リンクは自動的に期限切れとなります。
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = Test Pilot について
|
||||
footerLinkPrivacy = プライバシー
|
||||
footerLinkTerms = 利用規約
|
||||
footerLinkCookies = Cookie
|
||||
requirePasswordCheckbox = このファイルをダウンロードするにはパスワードが必要です
|
||||
addPasswordButton = パスワードを追加
|
||||
passwordTryAgain = パスワードが正しくありません。再度入力してください。
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = パスワード: { $password }
|
||||
|
||||
91
public/locales/ka/send.ftl
Normal file
@@ -0,0 +1,91 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Send
|
||||
siteSubtitle = საცდელი
|
||||
siteFeedback = გამოხმაურება
|
||||
uploadPageHeader = ფაილების უსაფრთხო, დაშიფრული გაზიარება
|
||||
uploadPageExplainer = გააგზავნეთ ფაილები უსაფრთხოდ, დაფარულად და დაშიფრულად ბმულის საშუალებით, წინასწარ განსაზღვრული ვადით, რაც საწინდარია იმის, რომ თქვენი კუთვნილი მასალა, არ დარჩება ინტერნეტში სამუდამოდ.
|
||||
uploadPageLearnMore = ვრცლად
|
||||
uploadPageDropMessage = გადმოიტანეთ ფაილი აქ, ასატვირთად
|
||||
uploadPageSizeMessage = ყველაზე საიმედო მომსახურება, შეგიძლიათ ატვირთოთ არაუმეტეს 1GB ზომის ფაილი
|
||||
uploadPageBrowseButton = ფაილის არჩევა კომპიუტერიდან
|
||||
uploadPageBrowseButton1 = ფაილის არჩევა ასატვირთად
|
||||
uploadPageMultipleFilesAlert = ერთდროულად რამდენიმე ფაილის, ან საქაღალდის ატვირთვა, ამჟამად არაა ხელმისაწვდომი.
|
||||
uploadPageBrowseButtonTitle = ფაილის ატვირთვა
|
||||
uploadingPageProgress = მიმდინარეობს ატვირთვა { $filename } ({ $size })
|
||||
importingFile = გადმოტანა...
|
||||
verifyingFile = დამოწმება...
|
||||
encryptingFile = დაშიფვრა...
|
||||
decryptingFile = გაშიფვრა...
|
||||
notifyUploadDone = ფაილის ატვირთვა დასრულებულია.
|
||||
uploadingPageMessage = ფაილის ატვირთვის შემდეგ, შეგიძლიათ მიუთითოთ შენახვის ვადა.
|
||||
uploadingPageCancel = ატვირთვის გაუქმება
|
||||
uploadCancelNotification = ფაილის ატვირთვა გაუქმებულია.
|
||||
uploadingPageLargeFileMessage = ფაილი დიდია და ატვირთვამ შესაძლოა დიდხანს გასტანოს. ასე რომ, მოკალათდით!
|
||||
uploadingFileNotification = შეტყობინება, ატვირთვის დასრულებისას.
|
||||
uploadSuccessConfirmHeader = მზადაა გასაგზავნად
|
||||
uploadSvgAlt = ატვირთვა
|
||||
uploadSuccessTimingHeader = ფაილს ვადა გაუვა 1 ჩამოტვირთვის, ან 24 საათის მერე.
|
||||
copyUrlFormLabelWithName = დააკოპირეთ და გააზიარეთ ბმული, ფაილის გასაგზავნად: { $filename }
|
||||
copyUrlFormButton = დაკოპირება
|
||||
copiedUrl = დაკოპირდა!
|
||||
deleteFileButton = ფაილის წაშლა
|
||||
sendAnotherFileLink = სხვა ფაილის გაგზავნა
|
||||
// Alternative text used on the download link/button (indicates an action).
|
||||
downloadAltText = ჩამოტვირთვა
|
||||
downloadFileName = { $filename } ჩამოტვირთვა
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = შეიყვანეთ პაროლი
|
||||
unlockInputPlaceholder = პაროლი
|
||||
unlockButtonLabel = გახსნა
|
||||
downloadFileTitle = დაშიფრული ფაილის ჩამოტვირთვა
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = თქვენი მეგობარი გიგზავნით ფაილს Firefox Send მომსახურების მეშვეობით, რომლითაც შეგიძლიათ ფაილების უსაფრთხოდ, დაფარულად და დაშიფრულად გაზიარება ბმულის საშუალებით, წინასწარ განსაზღვრული ვადით, რაც საწინდარია იმის, რომ თქვენი კუთვნილი მასალა, არ დარჩება ინტერნეტში სამუდამოდ.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = ჩამოტვირთვა
|
||||
downloadNotification = თქვენი ჩამოტვირთვა დასრულებულია.
|
||||
downloadFinish = ჩამოტვირთვა დასრულდა
|
||||
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||
fileSizeProgress = ({ $partialSize } { $totalSize }-იდან)
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
sendYourFilesLink = გამოცადეთ Firefox Send
|
||||
downloadingPageProgress = მიმდინარეობს ჩამოტვირთვა { $filename } ({ $size })
|
||||
downloadingPageMessage = გთხოვთ დატოვოთ ეს ჩანართი გახსნილი, სანამ ფაილი ჩამოიტვირთება და გაიშიფრება.
|
||||
errorAltText = შეცდომა ატვირთვისას
|
||||
errorPageHeader = რაღაც ხარვეზია!
|
||||
errorPageMessage = ფაილის ატვირთვისას წარმოიშვა შეცდომა.
|
||||
errorPageLink = სხვა ფაილის გაგზავნა
|
||||
fileTooBig = ფაილი ზედმეტად დიდია. უნდა იყოს { $size } ზომაზე ნაკლები.
|
||||
linkExpiredAlt = ბმული ვადაგასულია
|
||||
expiredPageHeader = ბმული ან ვადაგასულია, ან არ არსებობს!
|
||||
notSupportedHeader = თქვენი ბრაუზერი არაა მხარდაჭერილი.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = სამწუხაროდ, ამ ბრაუზერს არ გააჩნია ის ტექნოლოგია, რომელიც აუცილებელია Firefox Send-ის მუშაობისთვის. გესაჭიროებათ სხვა ბრაუზერი. ჩვენ შეგვიძლია გირჩიოთ Firefox!
|
||||
notSupportedLink = რატომ არაა ჩემი ბრაუზერი მხარდაჭერილი?
|
||||
notSupportedOutdatedDetail = სამწუხაროდ, Firefox-ის ამ ვერსიას არ გააჩნია ის ტექნოლოგია, რომელიც აუცილებელია Firefox Send-ის მუშაობისთვის. გესაჭიროებათ, ბრაუზერის განახლება.
|
||||
updateFirefox = Firefox-ის განახლება
|
||||
downloadFirefoxButtonSub = უფასო ჩამოტვირთვა
|
||||
uploadedFile = ფაილი
|
||||
copyFileList = URL ბმულის დაკოპირება
|
||||
// expiryFileList is used as a column header
|
||||
expiryFileList = ვადის გასვლის დრო
|
||||
deleteFileList = წაშლა
|
||||
nevermindButton = არ აქვს მნიშვნელობა
|
||||
legalHeader = პირობები და პირადულობა
|
||||
legalNoticeTestPilot = Firefox Send ამჟამად Test Pilot-ის საცდელი პროექტია და ექვემდებარება Test Pilot-ის <a>მომსახურების პირობებსა</a> და <a>პირადი მონაცემების დაცვის დებულებას</a>. ვრცლად, ამ საცდელი პროექტისა და მონაცემების აღრიცხვის შესახებ, შეგიძლიათ იხილოთ <a>აქ</a>.
|
||||
legalNoticeMozilla = Firefox Send ვებსაიტი, ასევე ექვემდებარება Mozilla-ს <a>ვებსაიტების პირადი მონაცემების შესახებ დებულებას</a> და <a>ვებსაიტების გამოყენების პირობებს</a>.
|
||||
deletePopupText = გსურთ ამ ფაილის წაშლა?
|
||||
deletePopupYes = დიახ
|
||||
deletePopupCancel = გაუქმება
|
||||
deleteButtonHover = წაშლა
|
||||
copyUrlHover = URL-ს დაკოპირება
|
||||
footerLinkLegal = იურიდიული ინფორმაცია
|
||||
// Test Pilot is a proper name and should not be localized.
|
||||
footerLinkAbout = Test Pilot-ის შესახებ
|
||||
footerLinkPrivacy = პირადულობა
|
||||
footerLinkTerms = პირობები
|
||||
footerLinkCookies = ფუნთუშები
|
||||
requirePasswordCheckbox = პაროლის მოთხოვნა, ფაილის ჩამოტვირთვისას
|
||||
addPasswordButton = პაროლის დამატება
|
||||
passwordTryAgain = პაროლი არასწორია. სცადეთ ხელახლა.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = პაროლი: { $password }
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Azen afaylu-nniḍen
|
||||
downloadAltText = Sider
|
||||
downloadFileName = Sider { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Sekcem awal uffir
|
||||
unlockInputPlaceholder = Awal uffir
|
||||
unlockButtonLabel = Serreḥ
|
||||
downloadFileTitle = Sider afaylu awgelhan
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Amdakel-ik yuzen-ak-d afaylu s Firefox Firefox Send, ameẓlu ara yeǧǧen tuzna n ifuyla s wudem aɣelsan, s tbadnit akked uwgelhen s useqdec n useqwen ara yeùten s wudem awurman akken talqut-ik ur tettɣimi ara srid i lebda.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,6 @@ footerLinkAbout = Ɣef Test Pilot
|
||||
footerLinkPrivacy = Tabaḍnit
|
||||
footerLinkTerms = Tiwtilin
|
||||
footerLinkCookies = Inagan n tuqqna
|
||||
requirePasswordCheckbox = YEsra awal uffir akken ad isider afaylu-agi
|
||||
addPasswordButton = rnu awal uffir
|
||||
passwordTryAgain = Yir awal uffir. Ɛreḍ tikelt nniḍen.
|
||||
|
||||
@@ -35,6 +35,10 @@ sendAnotherFileLink = 다른 파일 보내기
|
||||
downloadAltText = 다운로드
|
||||
downloadFileName = { $filename } 다운로드
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = 비밀번호 입력
|
||||
unlockInputPlaceholder = 비밀번호
|
||||
unlockButtonLabel = 잠금 해제
|
||||
downloadFileTitle = 암호화된 파일 다운로드
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = 당신의 친구가 Firefox Send를 통해 파일을 보내고 있습니다. 이 서비스는 안전하고, 개인적이며, 암호화된 링크를 통해 파일을 공유하는 서비스입니다. 사용자의 파일이 더 이상 온라인 상에 남지 않도록 링크는 자동적으로 만료됩니다.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -81,3 +85,8 @@ footerLinkAbout = Test Pilot 정보
|
||||
footerLinkPrivacy = 개인정보 보호
|
||||
footerLinkTerms = 이용 약관
|
||||
footerLinkCookies = 쿠키
|
||||
requirePasswordCheckbox = 이 파일을 다운로드하려면 비밀번호가 필요함
|
||||
addPasswordButton = 비밀번호 추가
|
||||
passwordTryAgain = 비밀번호가 맞지 않습니다. 다시 시도해 주세요.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = 비밀번호: { $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Hantar fail lain
|
||||
downloadAltText = Muat turun
|
||||
downloadFileName = Muat turun { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Masukkan Kata Laluan
|
||||
unlockInputPlaceholder = Kata laluan
|
||||
unlockButtonLabel = Buka
|
||||
downloadFileTitle = Muat turun Fail Enkripsi
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Rakan anda menghantar satu fail kepada anda menggunakan Firefox Send, satu perkhidmatan yang membolehkan anda berkongsi fail dengan pautan yang selamat, peribadi dan dienkrip, yang secara automatik akan luput bagi memastikan fail anda tidak terus berada dalam talian selama-lamanya.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -67,7 +71,7 @@ expiryFileList = Luput Pada
|
||||
deleteFileList = Buang
|
||||
nevermindButton = Tak apalah
|
||||
legalHeader = Terma & Privasi
|
||||
legalNoticeTestPilot = Firefox Send adalah eksperimen Ujian Perintis, dan tertakluk kepada <a>Terma Perkhidmatan</a> dan <a>Privacy Notice</a> Ujian Perintis. Anda boleh ketahui selanjutnya perihal eksperimen ini dan pengumpulan data <a>di sini</a>.
|
||||
legalNoticeTestPilot = Firefox Send adalah eksperimen Ujian Perintis, dan tertakluk kepada <a>Terma Perkhidmatan</a> dan <a>Notis Privasi</a> Ujian Perintis. Anda boleh ketahui selanjutnya perihal eksperimen ini dan pengumpulan data <a>di sini</a>.
|
||||
legalNoticeMozilla = Penggunaan laman web Firefox Send juga tertakluk kepada <a>Notis Privasi Laman web</a> dan <a>Terma Penggunaan Laman web</a> Mozilla.
|
||||
deletePopupText = Buang fail ini?
|
||||
deletePopupYes = Ya
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = Perihal Ujian Perintis
|
||||
footerLinkPrivacy = Privasi
|
||||
footerLinkTerms = Terma
|
||||
footerLinkCookies = Kuki
|
||||
requirePasswordCheckbox = Perlu kata laluan untuk memuat turun fail ini
|
||||
addPasswordButton = Tambah Kata laluan
|
||||
passwordTryAgain = Kata laluan tidak betul. Cuba lagi.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Kata laluan: { $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Send en annen fil
|
||||
downloadAltText = Last ned
|
||||
downloadFileName = Last ned { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Skriv inn passord
|
||||
unlockInputPlaceholder = Passord
|
||||
unlockButtonLabel = Lås opp
|
||||
downloadFileTitle = Last ned kryptert fil
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Din venn sender deg en fil med Firefox Send, en tjeneste som lar deg dele filer med en sikker, privat og kryptert lenke, som automatisk utløper, for å sikre at ting ikke forblir på nettet for alltid.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = Om Test Pilot
|
||||
footerLinkPrivacy = Personvern
|
||||
footerLinkTerms = Vilkår
|
||||
footerLinkCookies = Infokapsler
|
||||
requirePasswordCheckbox = Krever et passord for å laste ned denne filen
|
||||
addPasswordButton = Legg til passord
|
||||
passwordTryAgain = Feil passord. Prøv igjen.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Passord: { $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Nog een bestand verzenden
|
||||
downloadAltText = Downloaden
|
||||
downloadFileName = { $filename } downloaden
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Voer wachtwoord in
|
||||
unlockInputPlaceholder = Wachtwoord
|
||||
unlockButtonLabel = Ontgrendelen
|
||||
downloadFileTitle = Versleuteld bestand downloaden
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Uw vriend(in) stuurt u een bestand met Firefox Send, een dienst waarmee u bestanden kunt verzenden met een veilige, private en versleutelde koppeling die automatisch verloopt, zodat u zeker weet dat uw zaken niet onbeperkt online blijven.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = Over Test Pilot
|
||||
footerLinkPrivacy = Privacy
|
||||
footerLinkTerms = Voorwaarden
|
||||
footerLinkCookies = Cookies
|
||||
requirePasswordCheckbox = Een wachtwoord vereisen om dit bestand te downloaden
|
||||
addPasswordButton = Wachtwoord toevoegen
|
||||
passwordTryAgain = Onjuist wachtwoord. Probeer het opnieuw.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Wachtwoord: { $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Send ei anna fil
|
||||
downloadAltText = Last ned
|
||||
downloadFileName = Last ned { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Skriv inn passord
|
||||
unlockInputPlaceholder = Passord
|
||||
unlockButtonLabel = Lås opp
|
||||
downloadFileTitle = Last ned kryptert fil
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Vennen din sender deg eni fil med Firefox Send, ei teneste som lar deg dele filer med ei sikker, privat og kryptert lenke, som automatisk går ut, for å sikre at ting ikkje vert verande på nettet for alltid.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = Om Test Pilot
|
||||
footerLinkPrivacy = Personvern
|
||||
footerLinkTerms = Vilkår
|
||||
footerLinkCookies = Infokapslar
|
||||
requirePasswordCheckbox = Krev eit passord for å laste ned denne fila
|
||||
addPasswordButton = Legg til passord
|
||||
passwordTryAgain = Feil passord. Prøv på nytt.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Passord: { $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Enviar outro arquivo
|
||||
downloadAltText = Baixar
|
||||
downloadFileName = Baixar { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Insira a senha
|
||||
unlockInputPlaceholder = Senha
|
||||
unlockButtonLabel = Desbloquear
|
||||
downloadFileTitle = Baixar arquivo criptografado
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Seu amigo está te enviando um arquivo através do Firefox Send, um serviço que permite compartilhar arquivos com um link seguro, privado e criptografado que automaticamente expira para garantir que suas coisas não permaneçam on-line eternamente.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = Sobre o Test Pilot
|
||||
footerLinkPrivacy = Privacidade
|
||||
footerLinkTerms = Termos
|
||||
footerLinkCookies = Cookies
|
||||
requirePasswordCheckbox = Para baixar esse arquivo é necessário uma senha
|
||||
addPasswordButton = Adicionar senha
|
||||
passwordTryAgain = Senha incorreta. Tente novamente.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Senha: { $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Enviar outro ficheiro
|
||||
downloadAltText = Descarregar
|
||||
downloadFileName = Descarregar { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Digitar palavra-passe
|
||||
unlockInputPlaceholder = Palavra-passe
|
||||
unlockButtonLabel = Desbloquear
|
||||
downloadFileTitle = Descarregar ficheiro encriptado
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = O seu amigo está a enviar-lhe um ficheiro com o Firefox Send, um serviço que lhe permite partilhar ficheiro com uma ligação segura, privada e encriptada que expira automaticamente para garantir que as suas coisas não fiquem online para sempre.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = Acerca do Test Pilot
|
||||
footerLinkPrivacy = Privacidade
|
||||
footerLinkTerms = Termos
|
||||
footerLinkCookies = Cookies
|
||||
requirePasswordCheckbox = Requerer uma palavra-passe para descarregar este ficheiro
|
||||
addPasswordButton = Adicionar palavra-passe
|
||||
passwordTryAgain = Palavra-passe incorreta. Tente novamente.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Palavra-passe: { $password }
|
||||
|
||||
@@ -4,7 +4,10 @@ siteSubtitle = un experiment web
|
||||
siteFeedback = Feedback
|
||||
uploadPageHeader = Partajare de fișiere privată și criptată
|
||||
uploadPageLearnMore = Află mai multe
|
||||
uploadPageDropMessage = Aruncă fișierul aici pentru a începe încărcarea.
|
||||
uploadPageBrowseButton = Alege un fișier din calculator.
|
||||
uploadPageBrowseButton1 = Selectează un fișier pentru încărcare
|
||||
uploadPageMultipleFilesAlert = Încărcarea mai multor fișiere deodată sau a dosarelor nu este suportată.
|
||||
uploadPageBrowseButtonTitle = Încarcă fișier
|
||||
uploadingPageProgress = Se încarcă { $filename } ({ $size })
|
||||
importingFile = Se importă…
|
||||
@@ -15,6 +18,7 @@ notifyUploadDone = Încărcarea s-a finalizat.
|
||||
uploadingPageMessage =
|
||||
uploadingPageCancel = Anulează încărcarea
|
||||
uploadCancelNotification = Încărcarea a fost anulată.
|
||||
uploadingPageLargeFileMessage = Stai calm! Acest fișier este mare. S-ar putea să dureze un timp încărcarea.
|
||||
uploadingFileNotification = Notifică-mă când încărcarea este încheiată.
|
||||
uploadSuccessConfirmHeader = Pregătit pentru trimitere
|
||||
uploadSvgAlt = Încarcă
|
||||
@@ -27,6 +31,10 @@ sendAnotherFileLink = Trimite un alt fișier
|
||||
downloadAltText = Descarcă
|
||||
downloadFileName = Descarcă { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Introdu parola
|
||||
unlockInputPlaceholder = Parolă
|
||||
unlockButtonLabel = Deblochează
|
||||
downloadFileTitle = Descarcă fișierul criptat
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = Descarcă
|
||||
downloadNotification = Descărcarea s-a încheiat.
|
||||
@@ -38,7 +46,9 @@ sendYourFilesLink = Încearcă Firefox Send
|
||||
downloadingPageProgress = Se descarcă { $filename } ({ $size })
|
||||
errorAltText = Eroare la încărcare
|
||||
errorPageHeader = Ceva a mers prost!
|
||||
errorPageMessage = A apărut o eroare la încărcarea fișierului.
|
||||
errorPageLink = Trimite un alt fișier
|
||||
fileTooBig = Acest fișier este prea mare. Trebuie să fie sub { $size }.
|
||||
linkExpiredAlt = Link expirat
|
||||
expiredPageHeader = Acest link a expirat sau nu a existat de la bun început!
|
||||
notSupportedHeader = Browserul tău nu este suportat.
|
||||
@@ -50,9 +60,11 @@ copyFileList = Copiază URL-ul
|
||||
// expiryFileList is used as a column header
|
||||
expiryFileList = Expiră în
|
||||
deleteFileList = Șterge
|
||||
nevermindButton = Uită
|
||||
legalHeader = Termeni de utilizare și politica de confidențialitate
|
||||
deletePopupText = Ștergi aceast fișier?
|
||||
deletePopupYes = Da
|
||||
deletePopupCancel = Renunță
|
||||
deleteButtonHover = Șterge
|
||||
copyUrlHover = Copiază URL-ul
|
||||
footerLinkLegal = Mențiuni legale
|
||||
@@ -61,3 +73,4 @@ footerLinkAbout = Despre Test Pilot
|
||||
footerLinkPrivacy = Confidențialitate
|
||||
footerLinkTerms = Termeni
|
||||
footerLinkCookies = Cookie-uri
|
||||
addPasswordButton = Adaugă parolă
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Отправить другой файл
|
||||
downloadAltText = Загрузить
|
||||
downloadFileName = Загрузить { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Введите пароль
|
||||
unlockInputPlaceholder = Пароль
|
||||
unlockButtonLabel = Разблокировать
|
||||
downloadFileTitle = Загрузить зашифрованный файл
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Ваш друг отправил вам файл с помощью Firefox Send, сервиса, который позволяет вам делиться файлами, используя безопасные, приватные и зашифрованные ссылки, по истечении срока действия которых ваши файлы не остаются в сети навсегда.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = О программе лётчика-испытателя
|
||||
footerLinkPrivacy = Приватность
|
||||
footerLinkTerms = Условия
|
||||
footerLinkCookies = Куки
|
||||
requirePasswordCheckbox = Требовать пароль для загрузки этого файла
|
||||
addPasswordButton = Добавить пароль
|
||||
passwordTryAgain = Неверный пароль. Попробуйте снова.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Пароль: { $password }
|
||||
|
||||
@@ -34,8 +34,12 @@ sendAnotherFileLink = Odoslať ďalší súbor
|
||||
downloadAltText = Prevziať
|
||||
downloadFileName = Prevziať { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Zadajte heslo
|
||||
unlockInputPlaceholder = Heslo
|
||||
unlockButtonLabel = Odomknúť
|
||||
downloadFileTitle = Prevziať šifrovaný súbor
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Váš priateľ vám odoslal súbor pomocou služby Firefox Sync - táto vám umožňuje zdieľať súbory pomocou bezpečného, súkromného a zašifrovaného odkazu, ktorého platnosť automaticky vyprší. Vďaka tomu máte istotu, že vaše súbory neostanú na internete naveky.
|
||||
downloadMessage = Váš priateľ vám odoslal súbor pomocou služby Firefox Send - táto vám umožňuje zdieľať súbory pomocou bezpečného, súkromného a zašifrovaného odkazu, ktorého platnosť automaticky vyprší. Vďaka tomu máte istotu, že vaše súbory neostanú na internete naveky.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = Prevziať
|
||||
downloadNotification = Vaše preberanie bolo dokončené.
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = O projekte Test Pilot
|
||||
footerLinkPrivacy = Súkromie
|
||||
footerLinkTerms = Podmienky používania
|
||||
footerLinkCookies = Cookies
|
||||
requirePasswordCheckbox = Pri preberaní súboru vyžadovať heslo
|
||||
addPasswordButton = Pridať heslo
|
||||
passwordTryAgain = Nesprávne heslo. Skúste to znova.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Heslo: { $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Pošlji drugo datoteko
|
||||
downloadAltText = Prenesi
|
||||
downloadFileName = Prenesi { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Vnesite geslo
|
||||
unlockInputPlaceholder = Geslo
|
||||
unlockButtonLabel = Odkleni
|
||||
downloadFileTitle = Prenesi šifrirano datoteko
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Prijatelj vam pošilja datoteko preko storitve Firefox Send, ki vam omogoča deljenje datotek preko varne, zasebne in šifrirane povezave, ki samodejno poteče, kar vam zagotavlja, da vaše stvari ne ostanejo na spletu za vedno.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = O programu Test Pilot
|
||||
footerLinkPrivacy = Zasebnost
|
||||
footerLinkTerms = Pogoji
|
||||
footerLinkCookies = Piškotki
|
||||
requirePasswordCheckbox = Zahtevaj geslo za prenos te datoteke
|
||||
addPasswordButton = Dodaj geslo
|
||||
passwordTryAgain = Napačno geslo. Poskusite znova.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Geslo: { $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Пошаљи другу датотеку
|
||||
downloadAltText = Преузми
|
||||
downloadFileName = Преузимање датотеке { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Унесите лозинку
|
||||
unlockInputPlaceholder = Лозинка
|
||||
unlockButtonLabel = Откључај
|
||||
downloadFileTitle = Преузми шифровану датотеку
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Ваш пријатељ вам је послао датотеку преко услуге Firefox Send која вам омогућава да делите датотеке преко безбедне, приватне и шифроване везе која самостално истиче да ваше ствари не би остале на нету заувек.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = О Тест Пилоту
|
||||
footerLinkPrivacy = Приватност
|
||||
footerLinkTerms = Услови
|
||||
footerLinkCookies = Колачићи
|
||||
requirePasswordCheckbox = Захтевај лозинку да би преузео ову датотеку
|
||||
addPasswordButton = Додај лозинку
|
||||
passwordTryAgain = Нетачна лозинка. Пробајте поново.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Лозинка: { $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Skicka en annan fil
|
||||
downloadAltText = Ladda ner
|
||||
downloadFileName = Ladda ner { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Ange lösenord
|
||||
unlockInputPlaceholder = Lösenord
|
||||
unlockButtonLabel = Lås upp
|
||||
downloadFileTitle = Hämta krypterad fil
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Din vän skickar dig en fil med Firefox Send, en tjänst som låter dig dela filer med en säker, privat och krypterad länk som automatiskt upphör för att säkerställa att dina saker inte förblir på nätet för alltid.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = Om Test Pilot
|
||||
footerLinkPrivacy = Sekretess
|
||||
footerLinkTerms = Villkor
|
||||
footerLinkCookies = Kakor
|
||||
requirePasswordCheckbox = Kräver ett lösenord för att ladda ner den här filen
|
||||
addPasswordButton = Lägg till lösenord
|
||||
passwordTryAgain = Felaktigt lösenord. Försök igen.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Lösenord: { $password }
|
||||
|
||||
@@ -31,6 +31,9 @@ sendAnotherFileLink = మరో ఫైలును పంపండి
|
||||
downloadAltText = దిగుమతి
|
||||
downloadFileName = దిగుమతి { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = సంకేతపదాన్ని తెలపండి
|
||||
unlockInputPlaceholder = సంకేతపదం
|
||||
unlockButtonLabel = తాళం తీయి
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = దిగుమతి
|
||||
downloadNotification = మీ దిగుమతి పూర్తయ్యింది.
|
||||
@@ -69,3 +72,8 @@ footerLinkAbout = టెస్ట్ పైలట్ గురించి
|
||||
footerLinkPrivacy = గోప్యత
|
||||
footerLinkTerms = నియమాలు
|
||||
footerLinkCookies = కుకీలు
|
||||
requirePasswordCheckbox = ఈ ఫైల్ను దింపుకోటానికి సంకేతపదం అవసరం
|
||||
addPasswordButton = సంకేతపదం జోడించండి
|
||||
passwordTryAgain = సరికాని సంకేతపదం. మళ్ళీ ప్రయత్నించండి.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = సంకేతపదం: { $password }
|
||||
|
||||
91
public/locales/tl/send.ftl
Normal file
@@ -0,0 +1,91 @@
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
title = Firefox Ipadala
|
||||
siteSubtitle = eksperimento sa web
|
||||
siteFeedback = Feedback
|
||||
uploadPageHeader = Pribadong, Naka-encrypt na Pagbabahagi ng File
|
||||
uploadPageExplainer = Magpadala ng mga file sa pamamagitan ng isang ligtas, pribado, at naka-encrypt na link na awtomatikong mawawalan ng bisa upang matiyak na ang iyong mga bagay-bagay ay hindi mananatiling online magpakailanman.
|
||||
uploadPageLearnMore = Matuto ng higit pa
|
||||
uploadPageDropMessage = I-drop ang iyong file dito upang simulan ang pag-upload
|
||||
uploadPageSizeMessage = Para sa pinaka maaasahang operasyon, pinakamahusay na panatilihin ang iyong file sa ilalim ng 1GB
|
||||
uploadPageBrowseButton = Pumili ng isang file sa iyong computer
|
||||
uploadPageBrowseButton1 = Pumili ng isang file na mai-upload
|
||||
uploadPageMultipleFilesAlert = Kasalukuyang hindi sinusuportahan ang pag-upload ng maramihang mga file o isang folder.
|
||||
uploadPageBrowseButtonTitle = I-upload ang file
|
||||
uploadingPageProgress = Uploading { $filename } ({ $size })
|
||||
importingFile = Importing…
|
||||
verifyingFile = Pinatutunayan...
|
||||
encryptingFile = Encrypting…
|
||||
decryptingFile = Decrypting…
|
||||
notifyUploadDone = Natapos na ang iyong pag-upload.
|
||||
uploadingPageMessage = Sa sandaling mag-upload ang iyong file, makakapagtakda ka ng mga expire na pagpipilian.
|
||||
uploadingPageCancel = Kanselahin ang pag-upload
|
||||
uploadCancelNotification = Kinansela ang iyong pag-upload.
|
||||
uploadingPageLargeFileMessage = Ang file na ito ay malaki at maaaring tumagal ng ilang sandali upang mag-upload. Umupo nang masikip!
|
||||
uploadingFileNotification = Abisuhan ako kapag nakumpleto na ang pag-upload.
|
||||
uploadSuccessConfirmHeader = Handa nang Ipadala
|
||||
uploadSvgAlt = I-upload
|
||||
uploadSuccessTimingHeader = Mag-e-expire ang link sa iyong file pagkatapos ng 1 pag-download o sa loob ng 24 na oras.
|
||||
copyUrlFormLabelWithName = Kopyahin at ibahagi ang link upang ipadala ang iyong file: { $filename }
|
||||
copyUrlFormButton = Kopyahin sa clipboard
|
||||
copiedUrl = Naikopya!
|
||||
deleteFileButton = Burahin ang file
|
||||
sendAnotherFileLink = Magpadala ng isang file
|
||||
// Alternative text used on the download link/button (indicates an action).
|
||||
downloadAltText = I-download
|
||||
downloadFileName = I-download { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Ilagay ang Password
|
||||
unlockInputPlaceholder = Password
|
||||
unlockButtonLabel = I-unlock
|
||||
downloadFileTitle = I-download ang Na-encrypt na File
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Ang iyong kaibigan ay nagpapadala sa iyo ng isang file na may Firefox Send, isang serbisyo na nagbibigay-daan sa iyo upang magbahagi ng mga file sa isang ligtas, pribado, at naka-encrypt na link na awtomatikong mawawalan ng bisa upang matiyak na ang iyong mga bagay-bagay ay hindi mananatiling online magpakailanman.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
downloadButtonLabel = I-download
|
||||
downloadNotification = Nakumpleto na ang iyong pag-download.
|
||||
downloadFinish = Kumpleto ang Download
|
||||
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
|
||||
fileSizeProgress = ({ $partialSize } ng { $totalSize })
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
sendYourFilesLink = Subukan ang Firefox Ipadala
|
||||
downloadingPageProgress = Downloading { $filename } ({ $size })
|
||||
downloadingPageMessage = Paki-iwan ang tab na ito habang binuksan namin ang iyong file at i-decrypt ito.
|
||||
errorAltText = Mag-upload ng error
|
||||
errorPageHeader = May nagkamali!
|
||||
errorPageMessage = Nagkaroon ng error sa pag-upload ng file.
|
||||
errorPageLink = Magpadala ng isang file
|
||||
fileTooBig = Ang file na iyon ay masyadong malaki upang mag-upload. Dapat itong mas mababa sa { $size }.
|
||||
linkExpiredAlt = Nag-expire na ang link
|
||||
expiredPageHeader = Nag-expire na ang link na ito o hindi kailanman umiiral sa unang lugar!
|
||||
notSupportedHeader = Ang iyong browser ay hindi suportado.
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
notSupportedDetail = Sa kasamaang palad hindi sinusuportahan ng browser na ito ang teknolohiya sa web na nagpapagana ng Firefox Send. Kailangan mong subukan ang ibang browser. Inirerekomenda namin ang Firefox!
|
||||
notSupportedLink = Bakit hindi suportado ang aking browser?
|
||||
notSupportedOutdatedDetail = Sa kasamaang palad ang bersyon na ito ng Firefox ay hindi sumusuporta sa teknolohiya ng web na nagpapagana ng Firefox Send. Kailangan mong i-update ang iyong browser.
|
||||
updateFirefox = I-update ang Firefox
|
||||
downloadFirefoxButtonSub = Libreng Download
|
||||
uploadedFile = File
|
||||
copyFileList = Kopyahin ang URL
|
||||
// expiryFileList is used as a column header
|
||||
expiryFileList = Magtatapos Sa
|
||||
deleteFileList = I-delete
|
||||
nevermindButton = Hindi bale
|
||||
legalHeader = Mga Tuntunin at Pagkapribado
|
||||
legalNoticeTestPilot = Ang Firefox Ipadala ay kasalukuyang eksperimentong Test Pilot, at napapailalim sa <a>Mga Tuntunin ng Serbisyo</a> at <a> Paunawa sa Privacy</a>. Maaari kang matuto nang higit pa tungkol sa eksperimentong ito at ang koleksyon ng data nito <a>dito</a>.
|
||||
legalNoticeMozilla = Ang paggamit ng website ng Ipadala ang Firefox ay napapailalim din sa <a>Mga Patakaran sa Privacy ng Website</a> ng Mozilla at <a>Mga Tuntunin ng Paggamit ng Website</a>.
|
||||
deletePopupText = Tanggalin ang file na ito?
|
||||
deletePopupYes = Oo
|
||||
deletePopupCancel = Kanselahin
|
||||
deleteButtonHover = I-delete
|
||||
copyUrlHover = Kopyahin ang URL
|
||||
footerLinkLegal = Legal
|
||||
// Test Pilot is a proper name and should not be localized.
|
||||
footerLinkAbout = Tungkol sa Test Pilot
|
||||
footerLinkPrivacy = Privacy
|
||||
footerLinkTerms = Mga term
|
||||
footerLinkCookies = Mga cookie
|
||||
requirePasswordCheckbox = Mangailangan ng isang password upang i-download ang file na ito
|
||||
addPasswordButton = Magdagdag ng password
|
||||
passwordTryAgain = Maling password. Subukan muli.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Password: { $password }
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = Başka bir dosya daha gönder
|
||||
downloadAltText = İndir
|
||||
downloadFileName = { $filename } dosyasını indir
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = Parolayı yazın
|
||||
unlockInputPlaceholder = Parola
|
||||
unlockButtonLabel = Kilidi aç
|
||||
downloadFileTitle = Şifrelenmiş dosyayı indir
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = Arkadaşınız size Firefox Send ile bir dosya gönderdi. Firefox Send; dosyalarınızı güvenli, size özel, şifrelenmiş ve otomatik olarak silinen bir bağlantıyla paylaşmayı sağlar. Böylece özel dosyalarınız sonsuza dek internette kalmaz.
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = Test Pilotu hakkında
|
||||
footerLinkPrivacy = Gizlilik
|
||||
footerLinkTerms = Şartlar
|
||||
footerLinkCookies = Çerezler
|
||||
requirePasswordCheckbox = Bu dosyayı indirmek için parola iste
|
||||
addPasswordButton = Parola ekle
|
||||
passwordTryAgain = Yanlış parola. Yeniden deneyin.
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = Parola: { $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = 发送其他文件
|
||||
downloadAltText = 下载
|
||||
downloadFileName = 下载 { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = 请输入密码
|
||||
unlockInputPlaceholder = 密码
|
||||
unlockButtonLabel = 解锁
|
||||
downloadFileTitle = 下载加密的文件
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = 您的朋友使用 Firefox Send 向您发送一个文件。该服务允许用户以安全、私密、受加密的链接分享一个文件,链接到期后文件将从网上彻底抹除。
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = 关于 Test Pilot
|
||||
footerLinkPrivacy = 隐私
|
||||
footerLinkTerms = 条款
|
||||
footerLinkCookies = Cookie
|
||||
requirePasswordCheckbox = 持有密码才能下载此文件
|
||||
addPasswordButton = 添加密码
|
||||
passwordTryAgain = 密码不正确。请重试。
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = 密码:{ $password }
|
||||
|
||||
@@ -34,6 +34,10 @@ sendAnotherFileLink = 傳送另一個檔案
|
||||
downloadAltText = 下載
|
||||
downloadFileName = 下載 { $filename }
|
||||
downloadFileSize = ({ $size })
|
||||
unlockInputLabel = 輸入密碼
|
||||
unlockInputPlaceholder = 密碼
|
||||
unlockButtonLabel = 解鎖
|
||||
downloadFileTitle = 下載加密過的檔案
|
||||
// Firefox Send is a brand name and should not be localized.
|
||||
downloadMessage = 您的朋友正透過 Firefox Send 傳送檔案給您。這是一個可讓您透過安全、隱密、並且會將鏈結加密過,自動失效以確保檔案不會在網路上無限停留的檔案分享服務。
|
||||
// Text and title used on the download link/button (indicates an action).
|
||||
@@ -80,3 +84,8 @@ footerLinkAbout = 關於 Test Pilot
|
||||
footerLinkPrivacy = 隱私權
|
||||
footerLinkTerms = 使用條款
|
||||
footerLinkCookies = Cookie
|
||||
requirePasswordCheckbox = 需要密碼才能下載此檔案
|
||||
addPasswordButton = 新增密碼
|
||||
passwordTryAgain = 密碼不正確,請再試一次。
|
||||
// This label is followed by the password needed to download a file
|
||||
passwordResult = 密碼: { $password }
|
||||
|
||||
@@ -4,11 +4,9 @@ const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
function allLangs() {
|
||||
const langs = fs.readdirSync(
|
||||
return fs.readdirSync(
|
||||
path.join(__dirname, '..', 'dist', 'public', 'locales')
|
||||
);
|
||||
langs.unshift('en-US'); // default first, TODO change for fluent-langneg
|
||||
return langs;
|
||||
}
|
||||
|
||||
if (config.l10n_dev) {
|
||||
|
||||
@@ -8,7 +8,7 @@ module.exports = function(state, body = '') {
|
||||
: '';
|
||||
return html`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="${state.locale}">
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta charset="utf-8" />
|
||||
@@ -31,9 +31,39 @@ module.exports = function(state, body = '') {
|
||||
<title>${state.title}</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="${assets.get('main.css')}" />
|
||||
<link rel="icon" type="image/png" href="${assets.get(
|
||||
'favicon-32x32.png'
|
||||
)}" sizes="32x32" />
|
||||
|
||||
<!-- generic favicons -->
|
||||
<link rel="icon" href="${assets.get('favicon-32.png')}" sizes="32x32">
|
||||
<link rel="icon" href="${assets.get('favicon-96.png')}" sizes="96x96">
|
||||
<link rel="icon" href="${assets.get('favicon-128.png')}" sizes="128x128">
|
||||
<link rel="icon" href="${assets.get('favicon-228.png')}" sizes="228x228">
|
||||
|
||||
<!-- Android -->
|
||||
<link rel="shortcut icon" href="${assets.get(
|
||||
'favicon-196.png'
|
||||
)}" sizes="196x196">
|
||||
|
||||
<!-- iOS -->
|
||||
<link rel="apple-touch-icon" href="${assets.get(
|
||||
'favicon-120.png'
|
||||
)}" sizes="120x120">
|
||||
<link rel="apple-touch-icon" href="${assets.get(
|
||||
'favicon-152.png'
|
||||
)}" sizes="152x152">
|
||||
<link rel="apple-touch-icon" href="${assets.get(
|
||||
'favicon-180.png'
|
||||
)}" sizes="180x180">
|
||||
|
||||
<!-- Windows 8 IE 10-->
|
||||
<meta name="msapplication-TileColor" content="#FFFFFF">
|
||||
<meta name="msapplication-TileImage" content="${assets.get(
|
||||
'favicon-144.png'
|
||||
)}">
|
||||
|
||||
<!— Windows 8.1 + IE11 and above —>
|
||||
<meta name="msapplication-config" content="/browserconfig.xml"/>
|
||||
|
||||
|
||||
${firaTag}
|
||||
<script defer src="/jsconfig.js"></script>
|
||||
<script defer src="${assets.get('runtime.js')}"></script>
|
||||
@@ -41,58 +71,7 @@ module.exports = function(state, body = '') {
|
||||
<script defer src="${locales.get(state.locale)}"></script>
|
||||
<script defer src="${assets.get('app.js')}"></script>
|
||||
</head>
|
||||
<body>
|
||||
<header class="header">
|
||||
<div class="send-logo">
|
||||
<a href="/">
|
||||
<img src="${assets.get(
|
||||
'send_logo.svg'
|
||||
)}" alt="Send"/><h1 class="site-title">Send</h1>
|
||||
</a>
|
||||
<div class="site-subtitle">
|
||||
<a href="https://testpilot.firefox.com">Firefox Test Pilot</a>
|
||||
<div>${state.translate('siteSubtitle')}</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="https://qsurvey.mozilla.com/s3/txp-firefox-send" rel="noreferrer noopener" class="feedback" target="_blank">${state.translate(
|
||||
'siteFeedback'
|
||||
)}</a>
|
||||
</header>
|
||||
<div class="all">
|
||||
<noscript>
|
||||
<h2>Firefox Send requires JavaScript</h2>
|
||||
<p><a href="https://github.com/mozilla/send/blob/master/docs/faq.md#why-does-firefox-send-require-javascript">Why does Firefox Send require JavaScript?</a></p>
|
||||
<p>Please enable JavaScript and try again.</p>
|
||||
</noscript>
|
||||
${body}
|
||||
</div>
|
||||
<div class="footer">
|
||||
<div class="legal-links">
|
||||
<a href="https://www.mozilla.org" role="presentation"><img class="mozilla-logo" src="${assets.get(
|
||||
'mozilla-logo.svg'
|
||||
)}" alt="mozilla"/></a>
|
||||
<a href="https://www.mozilla.org/about/legal">${state.translate(
|
||||
'footerLinkLegal'
|
||||
)}</a>
|
||||
<a href="https://testpilot.firefox.com/about">${state.translate(
|
||||
'footerLinkAbout'
|
||||
)}</a>
|
||||
<a href="/legal">${state.translate('footerLinkPrivacy')}</a>
|
||||
<a href="/legal">${state.translate('footerLinkTerms')}</a>
|
||||
<a href="https://www.mozilla.org/privacy/websites/#cookies">${state.translate(
|
||||
'footerLinkCookies'
|
||||
)}</a>
|
||||
</div>
|
||||
<div class="social-links">
|
||||
<a href="https://github.com/mozilla/send" role="presentation"><img class="github" src="${assets.get(
|
||||
'github-icon.svg'
|
||||
)}" alt="github"/></a>
|
||||
<a href="https://twitter.com/FxTestPilot" role="presentation"><img class="twitter" src="${assets.get(
|
||||
'twitter-icon.svg'
|
||||
)}" alt="twitter"/></a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
${body}
|
||||
</html>
|
||||
`;
|
||||
};
|
||||
|
||||
@@ -11,16 +11,17 @@ if (config.sentry_dsn) {
|
||||
|
||||
const app = express();
|
||||
|
||||
routes(app);
|
||||
|
||||
app.use(
|
||||
express.static(path.resolve(__dirname, '../dist/'), {
|
||||
setHeaders: function(res) {
|
||||
res.set('Cache-Control', 'public, max-age=31536000, immutable');
|
||||
res.removeHeader('Pragma');
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
routes(app);
|
||||
|
||||
app.use(pages.notfound);
|
||||
|
||||
app.listen(config.listen_port);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const storage = require('../storage');
|
||||
const mozlog = require('../log');
|
||||
const log = mozlog('send.download');
|
||||
const crypto = require('crypto');
|
||||
|
||||
function validateID(route_id) {
|
||||
return route_id.match(/^[0-9a-fA-F]{10}$/) !== null;
|
||||
@@ -13,13 +14,24 @@ module.exports = async function(req, res) {
|
||||
}
|
||||
|
||||
try {
|
||||
const auth = req.header('Authorization').split(' ')[1];
|
||||
const meta = await storage.metadata(id);
|
||||
const hmac = crypto.createHmac('sha256', Buffer.from(meta.auth, 'base64'));
|
||||
hmac.update(Buffer.from(meta.nonce, 'base64'));
|
||||
const verifyHash = hmac.digest();
|
||||
const nonce = crypto.randomBytes(16).toString('base64');
|
||||
storage.setField(id, 'nonce', nonce);
|
||||
if (!verifyHash.equals(Buffer.from(auth, 'base64'))) {
|
||||
res.set('WWW-Authenticate', `send-v1 ${nonce}`);
|
||||
return res.sendStatus(401);
|
||||
}
|
||||
const contentLength = await storage.length(id);
|
||||
res.writeHead(200, {
|
||||
'Content-Disposition': `attachment; filename=${meta.filename}`,
|
||||
'Content-Disposition': 'attachment',
|
||||
'Content-Type': 'application/octet-stream',
|
||||
'Content-Length': contentLength,
|
||||
'X-File-Metadata': JSON.stringify(meta)
|
||||
'X-File-Metadata': meta.metadata,
|
||||
'WWW-Authenticate': `send-v1 ${nonce}`
|
||||
});
|
||||
const file_stream = storage.get(id);
|
||||
|
||||
|
||||
@@ -1,20 +1,40 @@
|
||||
const busboy = require('connect-busboy');
|
||||
const helmet = require('helmet');
|
||||
const bodyParser = require('body-parser');
|
||||
const requestLanguage = require('express-request-language');
|
||||
const languages = require('../languages');
|
||||
const storage = require('../storage');
|
||||
const config = require('../config');
|
||||
const pages = require('./pages');
|
||||
// const lang = require('fluent-langneg')
|
||||
const { negotiateLanguages } = require('fluent-langneg');
|
||||
const IS_DEV = config.env === 'development';
|
||||
const acceptLanguages = /(([a-zA-Z]+(-[a-zA-Z0-9]+){0,2})|\*)(;q=[0-1](\.[0-9]+)?)?/g;
|
||||
const langData = require('cldr-core/supplemental/likelySubtags.json');
|
||||
|
||||
module.exports = function(app) {
|
||||
app.use(
|
||||
requestLanguage({
|
||||
languages
|
||||
})
|
||||
);
|
||||
app.use(function(req, res, next) {
|
||||
const header = req.headers['accept-language'] || 'en-US';
|
||||
if (header.length > 255) {
|
||||
req.language = 'en-US';
|
||||
return next();
|
||||
}
|
||||
const langs = header.replace(/\s/g, '').match(acceptLanguages);
|
||||
const preferred = langs
|
||||
.map(l => {
|
||||
const parts = l.split(';');
|
||||
return {
|
||||
locale: parts[0],
|
||||
q: parts[1] ? parseFloat(parts[1].split('=')[1]) : 1
|
||||
};
|
||||
})
|
||||
.sort((a, b) => b.q - a.q)
|
||||
.map(x => x.locale);
|
||||
req.language = negotiateLanguages(preferred, languages, {
|
||||
strategy: 'lookup',
|
||||
likelySubtags: langData.supplemental.likelySubtags,
|
||||
defaultLocale: 'en-US'
|
||||
})[0];
|
||||
next();
|
||||
});
|
||||
app.use(helmet());
|
||||
app.use(
|
||||
helmet.hsts({
|
||||
@@ -22,28 +42,26 @@ module.exports = function(app) {
|
||||
force: !IS_DEV
|
||||
})
|
||||
);
|
||||
if (!IS_DEV) {
|
||||
app.use(
|
||||
helmet.contentSecurityPolicy({
|
||||
directives: {
|
||||
defaultSrc: ["'self'"],
|
||||
connectSrc: [
|
||||
"'self'",
|
||||
'https://sentry.prod.mozaws.net',
|
||||
'https://www.google-analytics.com'
|
||||
],
|
||||
imgSrc: ["'self'", 'https://www.google-analytics.com'],
|
||||
scriptSrc: ["'self'"],
|
||||
styleSrc: ["'self'", 'https://code.cdn.mozilla.net'],
|
||||
fontSrc: ["'self'", 'https://code.cdn.mozilla.net'],
|
||||
formAction: ["'none'"],
|
||||
frameAncestors: ["'none'"],
|
||||
objectSrc: ["'none'"],
|
||||
reportUri: '/__cspreport__'
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
app.use(
|
||||
helmet.contentSecurityPolicy({
|
||||
directives: {
|
||||
defaultSrc: ["'self'"],
|
||||
connectSrc: [
|
||||
"'self'",
|
||||
'https://sentry.prod.mozaws.net',
|
||||
'https://www.google-analytics.com'
|
||||
],
|
||||
imgSrc: ["'self'", 'https://www.google-analytics.com'],
|
||||
scriptSrc: ["'self'"],
|
||||
styleSrc: ["'self'", "'unsafe-inline'", 'https://code.cdn.mozilla.net'],
|
||||
fontSrc: ["'self'", 'https://code.cdn.mozilla.net'],
|
||||
formAction: ["'none'"],
|
||||
frameAncestors: ["'none'"],
|
||||
objectSrc: ["'none'"],
|
||||
reportUri: '/__cspreport__'
|
||||
}
|
||||
})
|
||||
);
|
||||
app.use(
|
||||
busboy({
|
||||
limits: {
|
||||
@@ -51,6 +69,11 @@ module.exports = function(app) {
|
||||
}
|
||||
})
|
||||
);
|
||||
app.use(function(req, res, next) {
|
||||
res.set('Pragma', 'no-cache');
|
||||
res.set('Cache-Control', 'no-cache');
|
||||
next();
|
||||
});
|
||||
app.use(bodyParser.json());
|
||||
app.get('/', pages.index);
|
||||
app.get('/legal', pages.legal);
|
||||
@@ -59,10 +82,12 @@ module.exports = function(app) {
|
||||
app.get('/download/:id', pages.download);
|
||||
app.get('/completed', pages.blank);
|
||||
app.get('/unsupported/:reason', pages.unsupported);
|
||||
app.post('/api/upload', require('./upload'));
|
||||
app.get('/api/download/:id', require('./download'));
|
||||
app.get('/api/exists/:id', require('./exists'));
|
||||
app.get('/api/metadata/:id', require('./metadata'));
|
||||
app.post('/api/upload', require('./upload'));
|
||||
app.post('/api/delete/:id', require('./delete'));
|
||||
app.post('/api/password/:id', require('./password'));
|
||||
|
||||
app.get('/__version__', function(req, res) {
|
||||
res.sendFile(require.resolve('../../dist/version.json'));
|
||||
|
||||
36
server/routes/metadata.js
Normal file
@@ -0,0 +1,36 @@
|
||||
const storage = require('../storage');
|
||||
const crypto = require('crypto');
|
||||
|
||||
function validateID(route_id) {
|
||||
return route_id.match(/^[0-9a-fA-F]{10}$/) !== null;
|
||||
}
|
||||
|
||||
module.exports = async function(req, res) {
|
||||
const id = req.params.id;
|
||||
if (!validateID(id)) {
|
||||
return res.sendStatus(404);
|
||||
}
|
||||
|
||||
try {
|
||||
const auth = req.header('Authorization').split(' ')[1];
|
||||
const meta = await storage.metadata(id);
|
||||
const hmac = crypto.createHmac('sha256', Buffer.from(meta.auth, 'base64'));
|
||||
hmac.update(Buffer.from(meta.nonce, 'base64'));
|
||||
const verifyHash = hmac.digest();
|
||||
const nonce = crypto.randomBytes(16).toString('base64');
|
||||
storage.setField(id, 'nonce', nonce);
|
||||
res.set('WWW-Authenticate', `send-v1 ${nonce}`);
|
||||
if (!verifyHash.equals(Buffer.from(auth, 'base64'))) {
|
||||
return res.sendStatus(401);
|
||||
}
|
||||
const size = await storage.length(id);
|
||||
const ttl = await storage.ttl(id);
|
||||
res.send({
|
||||
metadata: meta.metadata,
|
||||
size,
|
||||
ttl
|
||||
});
|
||||
} catch (e) {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
};
|
||||
@@ -28,16 +28,14 @@ module.exports = {
|
||||
}
|
||||
|
||||
try {
|
||||
const efilename = await storage.filename(id);
|
||||
const name = decodeURIComponent(efilename);
|
||||
const size = await storage.length(id);
|
||||
const ttl = await storage.ttl(id);
|
||||
const { nonce, pwd } = await storage.metadata(id);
|
||||
res.set('WWW-Authenticate', `send-v1 ${nonce}`);
|
||||
res.send(
|
||||
stripEvents(
|
||||
routes.toString(
|
||||
`/download/${req.params.id}`,
|
||||
Object.assign(state(req), {
|
||||
fileInfo: { name, size, ttl }
|
||||
fileInfo: { nonce, pwd: +pwd }
|
||||
})
|
||||
)
|
||||
)
|
||||
|
||||