Compare commits

...

29 Commits

Author SHA1 Message Date
Danny Coates
ce28c38ebe v3.0.16 2019-08-12 10:10:07 -07:00
Danny Coates
f0407f9beb use custom configstore that doesn't use the fs 2019-08-12 10:00:57 -07:00
Sahithi
c6f222eb57 Pontoon: Update Telugu (te) localization of Firefox Send
Localization authors:
- Sahithi <sahithi@swecha.net>
2019-08-11 08:54:01 +00:00
leo.toneff
6dd6135185 Pontoon: Update Norwegian Bokmål (nb-NO) localization of Firefox Send
Localization authors:
- leo.toneff <leo.toneff@gmail.com>
- Håvar Henriksen <havar@firefox.no>
2019-08-10 16:33:36 +00:00
Danny Coates
8df339b66d v3.0.15 2019-08-09 12:26:09 -07:00
Danny Coates
8702fda651 handle websocket construction exceptions 2019-08-09 11:47:44 -07:00
Danny Coates
807ecff471 updated sentry libs from raven to @sentry 2019-08-09 11:06:21 -07:00
Danny Coates
927c981cd7 added size/time info to up/download error reporting 2019-08-09 10:09:34 -07:00
Danny Coates
7073cc8ce6 added download hang detection and error reporting 2019-08-08 13:54:02 -07:00
Danny Coates
c925fae696 updated deps 2019-08-08 13:01:57 -07:00
Danny Coates
966d7a5e35 create configstore dir in docker container 2019-08-08 10:42:57 -07:00
Danny Coates
96c750c098 added size and duration to connection error reporting 2019-08-08 09:52:22 -07:00
Danny Coates
0729064753 Merge pull request #1378 from mozilla/new-ws
Use resumable uploads to GCS
2019-08-08 08:54:00 -07:00
Joergen
259a5a5f24 Pontoon: Update Danish (da) localization of Firefox Send
Localization authors:
- Joergen <joergenr@stofanet.dk>
2019-08-08 14:02:32 +00:00
Danny Coates
27be72e0cd refactored client side upload loop 2019-08-07 13:51:23 -07:00
Danny Coates
e4231bbc0f updated deps 2019-08-07 13:47:26 -07:00
Danny Coates
1d184f06bf revert webpack for broken css extraction 2019-08-07 12:14:27 -07:00
Quentí
f7b46a99ac Pontoon: Update Occitan (oc) localization of Firefox Send
Localization authors:
- Quentí <quentinantonin@free.fr>
2019-08-07 18:12:20 +00:00
Quentí
3fadb489c7 Pontoon: Update Occitan (oc) localization of Firefox Send
Localization authors:
- Quentí <quentinantonin@free.fr>
2019-08-07 17:13:10 +00:00
Danny Coates
6378676c2d use resumable uploads to GCS 2019-08-07 10:10:42 -07:00
Quentí
014d84e4c7 Pontoon: Update Occitan (oc) localization of Firefox Send
Localization authors:
- Quentí <quentinantonin@free.fr>
2019-08-07 16:54:33 +00:00
Quentí
a08d8435a9 Pontoon: Update Occitan (oc) localization of Firefox Send
Localization authors:
- Quentí <quentinantonin@free.fr>
2019-08-07 07:12:56 +00:00
Quentí
40a05c9ecf Pontoon: Update Occitan (oc) localization of Firefox Send
Localization authors:
- Quentí <quentinantonin@free.fr>
2019-08-07 06:52:27 +00:00
Danny Coates
527040afef updated ws dependency and slightly improved client side error handling, hung uploads will error instead of hang forever 2019-08-06 14:47:21 -07:00
Michal Stanke
a48a447808 Pontoon: Update Czech (cs) localization of Firefox Send
Localization authors:
- Michal Stanke <mstanke@mozilla.cz>
2019-08-06 12:14:20 +00:00
julen
f3569d7f98 Pontoon: Update Basque (eu) localization of Firefox Send
Localization authors:
- julen <julenx@gmail.com>
- Ander Elortondo <ander.elor@gmail.com>
2019-08-05 08:52:40 +00:00
صفا الفليج
6ca7d11efb Pontoon: Update Arabic (ar) localization of Firefox Send
Localization authors:
- صفا الفليج <safa1996alfulaij@gmail.com>
2019-08-05 08:52:37 +00:00
julen
b71ae4a0ff Pontoon: Update Basque (eu) localization of Firefox Send
Localization authors:
- p.sanroman.bengoetxea <p.sanroman.bengoetxea@gmail.com>
- julen <julenx@gmail.com>
- Ander Elortondo <ander.elor@gmail.com>
2019-08-05 08:34:11 +00:00
Aman Alam
7ba25664b5 Pontoon: Update Punjabi (pa-IN) localization of Firefox Send
Localization authors:
- Aman Alam <amanpreet.alam@gmail.com>
2019-08-05 00:52:41 +00:00
27 changed files with 886 additions and 601 deletions

View File

@@ -10,6 +10,7 @@ USER app
WORKDIR /app
COPY --chown=app:app --from=builder /app .
COPY --chown=app:app . .
RUN mkdir -p /app/.config/configstore
RUN ln -s dist/version.json version.json
ENV PORT=1443

View File

@@ -1,7 +1,7 @@
import 'intl-pluralrules';
import choo from 'choo';
import html from 'choo/html';
import Raven from 'raven-js';
import * as Sentry from '@sentry/browser';
import { setApiUrlPrefix, getConstants } from '../app/api';
import metrics from '../app/metrics';
@@ -82,7 +82,7 @@ function body(main) {
state.archive = new Archive([], DEFAULTS.EXPIRE_SECONDS);
state.storage = storage;
state.user = new User(storage, LIMITS);
state.raven = Raven;
state.sentry = Sentry;
});
app.use(metrics);
app.route('/', body(home));

View File

@@ -12,7 +12,7 @@ export default function initialState(state, emitter) {
getAsset(name) {
return `${state.prefix}/${name}`;
},
raven: {
sentry: {
captureException: e => {
console.error('ERROR ' + e + ' ' + e.stack);
}

View File

@@ -11,6 +11,15 @@ if (!fileProtocolWssUrl) {
fileProtocolWssUrl = 'wss://send.firefox.com/api/ws';
}
export class ConnectionError extends Error {
constructor(cancelled, duration, size) {
super(cancelled ? '0' : 'connection closed');
this.cancelled = cancelled;
this.duration = duration;
this.size = size;
}
}
export function setFileProtocolWssUrl(url) {
localStorage && localStorage.setItem('wssURL', url);
fileProtocolWssUrl = url;
@@ -137,17 +146,25 @@ export async function setPassword(id, owner_token, keychain) {
}
function asyncInitWebSocket(server) {
return new Promise(resolve => {
return new Promise((resolve, reject) => {
try {
const ws = new WebSocket(server);
ws.onopen = () => {
resolve(ws);
};
ws.addEventListener('open', () => resolve(ws), { once: true });
} catch (e) {
reject(new ConnectionError(false));
}
});
}
function listenForResponse(ws, canceller) {
return new Promise((resolve, reject) => {
function handleClose(event) {
// a 'close' event before a 'message' event means the request failed
ws.removeEventListener('message', handleMessage);
reject(new ConnectionError(canceller.cancelled));
}
function handleMessage(msg) {
ws.removeEventListener('close', handleClose);
try {
const response = JSON.parse(msg.data);
if (response.error) {
@@ -156,13 +173,11 @@ function listenForResponse(ws, canceller) {
resolve(response);
}
} catch (e) {
ws.close();
canceller.cancelled = true;
canceller.error = e;
reject(e);
}
}
ws.addEventListener('message', handleMessage, { once: true });
ws.addEventListener('close', handleClose, { once: true });
});
}
@@ -176,6 +191,8 @@ async function upload(
onprogress,
canceller
) {
let size = 0;
const start = Date.now();
const host = window.location.hostname;
const port = window.location.port;
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
@@ -203,31 +220,41 @@ async function upload(
const reader = stream.getReader();
let state = await reader.read();
let size = 0;
while (!state.done) {
const buf = state.value;
if (canceller.cancelled) {
throw canceller.error;
ws.close();
}
if (ws.readyState !== WebSocket.OPEN) {
break;
}
const buf = state.value;
ws.send(buf);
onprogress(size);
size += buf.length;
state = await reader.read();
while (ws.bufferedAmount > ECE_RECORD_SIZE * 2) {
while (
ws.bufferedAmount > ECE_RECORD_SIZE * 2 &&
ws.readyState === WebSocket.OPEN &&
!canceller.cancelled
) {
await delay();
}
}
const footer = new Uint8Array([0]);
ws.send(footer);
if (ws.readyState === WebSocket.OPEN) {
ws.send(new Uint8Array([0])); //EOF
}
await completedResponse;
ws.close();
uploadInfo.duration = Date.now() - start;
return uploadInfo;
} catch (e) {
ws.close(4000);
e.size = size;
e.duration = Date.now() - start;
throw e;
} finally {
if (![WebSocket.CLOSED, WebSocket.CLOSING].includes(ws.readyState)) {
ws.close();
}
}
}
@@ -244,7 +271,6 @@ export function uploadWs(
return {
cancel: function() {
canceller.error = new Error(0);
canceller.cancelled = true;
},
@@ -284,7 +310,7 @@ async function downloadS(id, keychain, signal) {
return response.body;
}
async function tryDownloadStream(id, keychain, signal, tries = 1) {
async function tryDownloadStream(id, keychain, signal, tries = 2) {
try {
const result = await downloadS(id, keychain, signal);
return result;
@@ -306,7 +332,7 @@ export function downloadStream(id, keychain) {
}
return {
cancel,
result: tryDownloadStream(id, keychain, controller.signal, 2)
result: tryDownloadStream(id, keychain, controller.signal)
};
}
@@ -346,7 +372,7 @@ async function download(id, keychain, onprogress, canceller) {
});
}
async function tryDownload(id, keychain, onprogress, canceller, tries = 1) {
async function tryDownload(id, keychain, onprogress, canceller, tries = 2) {
try {
const result = await download(id, keychain, onprogress, canceller);
return result;
@@ -367,7 +393,7 @@ export function downloadFile(id, keychain, onprogress) {
}
return {
cancel,
result: tryDownload(id, keychain, onprogress, canceller, 2)
result: tryDownload(id, keychain, onprogress, canceller)
};
}

View File

@@ -76,7 +76,7 @@ export default function(state, emitter) {
state.storage.remove(ownedFile.id);
await ownedFile.del();
} catch (e) {
state.raven.captureException(e);
state.sentry.captureException(e);
}
render();
});
@@ -176,14 +176,17 @@ export default function(state, emitter) {
} catch (err) {
if (err.message === '0') {
//cancelled. do nothing
const duration = Date.now() - start;
metrics.cancelledUpload(archive, duration);
metrics.cancelledUpload(archive, err.duration);
render();
} else {
// eslint-disable-next-line no-console
console.error(err);
state.raven.captureException(err);
metrics.stoppedUpload(archive);
state.sentry.withScope(scope => {
scope.setExtra('duration', err.duration);
scope.setExtra('size', err.size);
state.sentry.captureException(err);
});
metrics.stoppedUpload(archive, err.duration);
emitter.emit('pushState', '/error');
}
} finally {
@@ -262,7 +265,12 @@ export default function(state, emitter) {
state.transfer = null;
const location = err.message === '404' ? '/404' : '/error';
if (location === '/error') {
state.raven.captureException(err);
state.sentry.withScope(scope => {
scope.setExtra('duration', err.duration);
scope.setExtra('size', err.size);
scope.setExtra('progress', err.progress);
state.sentry.captureException(err);
});
const duration = Date.now() - start;
metrics.stoppedDownload({
size,

View File

@@ -112,6 +112,7 @@ export default class FileReceiver extends Nanobus {
}
async downloadStream(noSave = false) {
const start = Date.now();
const onprogress = p => {
this.progress = [p, this.fileInfo.size];
this.emit('progress');
@@ -153,7 +154,7 @@ export default class FileReceiver extends Nanobus {
const downloadPath = `/api/download/${this.fileInfo.id}`;
let downloadUrl = getApiUrl(downloadPath);
if (downloadUrl === downloadPath) {
downloadUrl = `${location.protocol}//${location.host}/api/download/${this.fileInfo.id}`;
downloadUrl = `${location.protocol}//${location.host}${downloadPath}`;
}
const a = document.createElement('a');
a.href = downloadUrl;
@@ -162,11 +163,29 @@ export default class FileReceiver extends Nanobus {
}
let prog = 0;
let hangs = 0;
while (prog < this.fileInfo.size) {
const msg = await this.sendMessageToSw({
request: 'progress',
id: this.fileInfo.id
});
if (msg.progress === prog) {
hangs++;
} else {
hangs = 0;
}
if (hangs > 30) {
// TODO: On Chrome we don't get a cancel
// signal so one is indistinguishable from
// a hang. We may be able to detect
// which end is hung in the service worker
// to improve on this.
const e = new Error('hung download');
e.duration = Date.now() - start;
e.size = this.fileInfo.size;
e.progress = prog;
throw e;
}
prog = msg.progress;
onprogress(prog);
await delay(1000);

View File

@@ -44,7 +44,6 @@ export default class FileSender extends Nanobus {
}
async upload(archive, bearerToken) {
const start = Date.now();
if (this.cancelled) {
throw new Error(0);
}
@@ -76,7 +75,6 @@ export default class FileSender extends Nanobus {
this.emit('progress'); // HACK to kick MS Edge
try {
const result = await this.uploadRequest.result;
const time = Date.now() - start;
this.msg = 'notifyUploadEncryptDone';
this.uploadRequest = null;
this.progress = [1, 1];
@@ -87,8 +85,8 @@ export default class FileSender extends Nanobus {
name: archive.name,
size: archive.size,
manifest: archive.manifest,
time: time,
speed: archive.size / (time / 1000),
time: result.duration,
speed: archive.size / (result.duration / 1000),
createdAt: Date.now(),
expiresAt: Date.now() + archive.timeLimit * 1000,
secretKey: secretKey,

View File

@@ -12,15 +12,15 @@ import pasteManager from './pasteManager';
import storage from './storage';
import metrics from './metrics';
import experiments from './experiments';
import Raven from 'raven-js';
import * as Sentry from '@sentry/browser';
import './main.css';
import User from './user';
import { getTranslator } from './locale';
import Archive from './archive';
import { setTranslate, locale } from './utils';
if (navigator.doNotTrack !== '1' && window.RAVEN_CONFIG) {
Raven.config(window.SENTRY_ID, window.RAVEN_CONFIG).install();
if (navigator.doNotTrack !== '1' && window.SENTRY_CONFIG) {
Sentry.init(window.SENTRY_CONFIG);
}
if (process.env.NODE_ENV === 'production') {
@@ -56,7 +56,7 @@ if (process.env.NODE_ENV === 'production') {
capabilities,
translate,
storage,
raven: Raven,
sentry: Sentry,
user: new User(storage, LIMITS, window.AUTH_CONFIG),
transfer: null,
fileInfo: null

View File

@@ -107,9 +107,10 @@ function completedUpload(archive, duration) {
});
}
function stoppedUpload(archive) {
function stoppedUpload(archive, duration = 0) {
return addEvent('client_upload', {
download_limit: archive.dlimit,
duration: sizeOrder(duration),
file_count: archive.numFiles,
password_protected: !!archive.password,
size: sizeOrder(archive.size),

949
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{
"name": "firefox-send",
"description": "File Sharing Experiment",
"version": "3.0.14",
"version": "3.0.16",
"author": "Mozilla (https://mozilla.org)",
"repository": "mozilla/send",
"homepage": "https://github.com/mozilla/send/",
@@ -67,16 +67,17 @@
"@dannycoates/webcrypto-liner": "^0.1.37",
"@fullhuman/postcss-purgecss": "^1.2.0",
"@mattiasbuelens/web-streams-polyfill": "0.2.1",
"@sentry/browser": "^5.6.1",
"asmcrypto.js": "^0.22.0",
"babel-loader": "^8.0.6",
"babel-plugin-istanbul": "^5.2.0",
"base64-js": "^1.3.0",
"base64-js": "^1.3.1",
"content-disposition": "^0.5.3",
"copy-webpack-plugin": "^5.0.4",
"core-js": "^3.1.4",
"core-js": "^3.2.1",
"crc": "^3.8.0",
"cross-env": "^5.2.0",
"css-loader": "^3.1.0",
"css-loader": "^3.2.0",
"css-mqpacker": "^7.0.0",
"cssnano": "^4.1.10",
"eslint": "^6.1.0",
@@ -88,38 +89,37 @@
"extract-loader": "^3.1.0",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"fast-text-encoding": "^1.0.0",
"file-loader": "^4.1.0",
"file-loader": "^4.2.0",
"git-rev-sync": "^1.12.0",
"html-loader": "^0.5.5",
"http_ece": "^1.1.0",
"husky": "^3.0.2",
"husky": "^3.0.3",
"intl-pluralrules": "^1.0.3",
"lint-staged": "^9.2.1",
"mocha": "^6.2.0",
"morgan": "^1.9.1",
"nanobus": "^4.4.0",
"nanohtml": "^1.6.3",
"nanohtml": "^1.7.0",
"nanotiming": "^7.3.1",
"npm-run-all": "^4.1.5",
"nyc": "^14.1.1",
"postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.7.0",
"prettier": "^1.18.2",
"proxyquire": "^2.1.1",
"proxyquire": "^2.1.3",
"puppeteer": "^1.19.0",
"raven-js": "^3.27.2",
"raw-loader": "^3.1.0",
"redis-mock": "^0.45.0",
"rimraf": "^2.6.3",
"script-loader": "^0.7.2",
"sinon": "^7.3.2",
"sinon": "^7.4.1",
"string-hash": "^1.1.3",
"stylelint": "^10.1.0",
"stylelint-config-standard": "^18.3.0",
"stylelint-no-unsupported-browser-features": "^3.0.2",
"svgo": "^1.3.0",
"svgo-loader": "^2.2.1",
"tailwindcss": "^1.0.6",
"tailwindcss": "^1.1.1",
"val-loader": "^1.1.1",
"wdio-docker-service": "^1.4.2",
"wdio-dot-reporter": "0.0.10",
@@ -129,34 +129,34 @@
"wdio-selenium-standalone-service": "0.0.12",
"wdio-spec-reporter": "^0.1.5",
"webdriverio": "^4.14.4",
"webpack": "^4.39.1",
"webpack": "4.38.0",
"webpack-cli": "^3.3.6",
"webpack-dev-middleware": "^3.7.0",
"webpack-dev-server": "^3.7.2",
"webpack-dev-server": "^3.8.0",
"webpack-manifest-plugin": "^2.0.4",
"webpack-unassert-loader": "^1.2.0"
},
"dependencies": {
"@dannycoates/express-ws": "^5.0.3",
"@fluent/bundle": "^0.13.0",
"@fluent/langneg": "^0.3.0",
"@google-cloud/storage": "^3.0.4",
"aws-sdk": "^2.503.0",
"@google-cloud/storage": "^3.1.0",
"@sentry/node": "^5.6.1",
"aws-sdk": "^2.507.0",
"body-parser": "^1.19.0",
"choo": "^6.13.3",
"cldr-core": "^35.1.0",
"configstore": "github:dannycoates/configstore#master",
"convict": "^5.1.0",
"express": "^4.17.1",
"express-ws": "github:dannycoates/express-ws",
"fxa-geodb": "^1.0.4",
"helmet": "^3.20.0",
"mkdirp": "^0.5.1",
"mozlog": "^2.2.0",
"node-fetch": "^2.6.0",
"raven": "^2.6.4",
"redis": "^2.8.0",
"selenium-standalone": "^6.15.6",
"ua-parser-js": "^0.7.20",
"websocket-stream": "^5.5.0"
"ua-parser-js": "^0.7.20"
},
"availableLanguages": [
"en-US",
@@ -179,6 +179,7 @@
"es-ES",
"es-MX",
"et",
"eu",
"fi",
"fr",
"fy-NL",
@@ -195,8 +196,10 @@
"ko",
"lt",
"ml",
"nb-NO",
"nl",
"nn-NO",
"oc",
"pa-IN",
"pl",
"pt-BR",

View File

@@ -182,3 +182,4 @@ shareLinkDescription = شارِك الرابط الذي يصل إلى الملف
shareLinkButton = شارِك الرابط
# $name is the name of the file
shareMessage = نزِّل ”{ $name }“ عبر { -send-brand }: خدمة لمشاركة الملفات بلا عناء وبخصوصية تامة
learnMore = اطّلع على المزيد.

View File

@@ -196,5 +196,5 @@ shareLinkDescription = Sdílet odkaz na soubor:
shareLinkButton = Sdílet odkaz
# $name is the name of the file
shareMessage = Stáhněte si soubor „{ $name }“ s { -send-brand(case: "ins") } - jednoduché a bezpečné sdílení souborů
trailheadPromo = Existuje snadný způsob pro ochranu vašeho soukromí. Používejte Firefox.
trailheadPromo = Existuje způsob, jak ochránit své soukromí. Používejte Firefox.
learnMore = Zjistit více.

View File

@@ -151,3 +151,5 @@ shareLinkDescription = Del linket til din fil:
shareLinkButton = Del link
# $name is the name of the file
shareMessage = Hent { $name } med { -send-brand } - simpel og sikker fildeling
trailheadPromo = Beskyt dine digitale rettigheder. Slut dig til Firefox.
learnMore = Læs mere.

View File

@@ -23,7 +23,7 @@ fileSizeProgress = ({ $totalSize } / { $partialSize })
sendYourFilesLink = Probatu Firefox Send
errorPageHeader = Zerbait gaizki joan da!
fileTooBig = Fitxategia handiegia da kargatzeko. { $size } baino txikiagoa izan behar du.
linkExpiredAlt = Lotura iraungita
linkExpiredAlt = Lotura iraungi da
notSupportedHeader = Zure nabigatzailea ez da onartzen.
notSupportedLink = Zergatik ez da nire nabigatzailea onartzen?
notSupportedOutdatedDetail = Zoritxarrez Firefox bertsio honek ez du Firefox Send-ek behar duen web teknologia onartzen. Zure nabigatzailea eguneratu behar duzu.
@@ -54,7 +54,30 @@ passwordSetError = Pasahitz hau ezin da ezarri
-firefox = Firefox
-mozilla = Mozilla
introTitle = Partekatu fitxategiak modu sinple eta pribatuan
introDescription = { -send-brand } tresna fitxategiak partekatzeko da, muturretik muturrera zifratuta eta automatikoki iraungitzen diren loturekin. Hortaz, partekatzen duzuna pribatua izango da eta ziur egon zaitezke zure fitxategiak ez direla online egongo betirako.
notifyUploadEncryptDone = Zure fitxategia zifratuta eta bidaltzeko prest dago
# downloadCount is from the downloadCount string and timespan is a timespanMinutes string. ex. 'Expires after 2 downloads or 25 minutes'
archiveExpiryInfo = { $downloadCount } edo { $timespan } ondoren iraungiko da
timespanMinutes =
{ $num ->
[one] minutu 1
*[other] { $num } minutu
}
timespanDays =
{ $num ->
[one] egun 1
*[other] { $num } egun
}
timespanWeeks =
{ $num ->
[one] aste 1
*[other] { $num } aste
}
fileCount =
{ $num ->
[one] fitxategi 1
*[other] { $num } fitxategi
}
# byte abbreviation
bytes = B
# kibibyte abbreviation
@@ -65,9 +88,33 @@ mb = MB
gb = GB
# localized number and byte abbreviation. example "2.5MB"
fileSize = { $num }{ $units }
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
totalSize = Tamaina guztira: { $size }
# the next line after the colon contains a file name
copyLinkDescription = Kopiatu fitxategia partekatzeko lotura:
copyLinkButton = Kopiatu lotura
downloadTitle = Deskargatu fitxategiak
downloadDescription = { -send-brand } bidez partekatu da fitxategia muturretik muturrera zifratuta eta automatikoki iraungitzen den lotura batekin.
trySendDescription = Probatu { -send-brand } fitxategiak partekatzeko modu sinple eta segururako.
# count will always be > 10
tooManyFiles =
{ $count ->
[one] Soilik fitxategi bakarra igo daiteke aldi berean.
*[other] Soilik { $count } fitxategi igo daitezke aldi berean.
}
# count will always be > 10
tooManyArchives =
{ $count ->
[one] Soilik artxibo bakarra onartzen da.
*[other] Soilik { $count } artxibo onartzen dira.
}
expiredTitle = Lotura hau iraungi da.
notSupportedDescription = { -send-brand } ez da nabigatzaile honetan ibiliko. { -send-short-brand } hobeto dabil { -firefox }(r)en azken bertsioarekin; halaber, nabigatzaile gehienen azken bertsioarekin ibiliko da.
downloadFirefox = Deskargatu { -firefox }
legalTitle = { -send-short-brand } pribatutasun-oharra
legalDateStamp = 1.0 bertsioa, 2019ko martxoaren 12koa.
# A short representation of a countdown timer containing the number of days, hours, and minutes remaining as digits, example "2d 11h 56m"
expiresDaysHoursMinutes = { $days }e { $hours }h { $minutes }m
addFilesButton = Hautatu igotzeko fitxategiak
uploadButton = Igo
# the first part of the string 'Drag and drop files or click to send up to 1GB'
@@ -77,7 +124,32 @@ dragAndDropFiles = Arrastatu eta jaregin fitxategiak
orClickWithSize = edo egin klik { $size } arte igotzeko
addPassword = Babestu pasahitzarekin
emailPlaceholder = Idatzi zure helbide elektronikoa
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
signInSizeBump = Hasi saioa { $size } arte bidaltzeko
signInOnlyButton = Hasi saioa
accountBenefitTitle = Sortu { -firefox } kontu bat edo hasi saioa
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
accountBenefitLargeFiles = Partekatu { $size } arteko fitxategiak
accountBenefitDownloadCount = Partekatu fitxategiak jende gehiagorekin
accountBenefitTimeLimit =
{ $count ->
[one] Utzi loturak erabilgarri egun batez
*[other] Utzi loturak erabilgarri { $count } egunez
}
accountBenefitSync = Kudeatu partekatutako fitxategiak edozein gailutatik
accountBenefitMoz = { -mozilla }ren beste zerbitzuei buruzko argibide gehiago
signOut = Amaitu saioa
okButton = Ados
downloadingTitle = Deskargatzen
noStreamsWarning = Baliteke nabigatzailea gai ez izatea horrelako tamaina handiko fitxategiak deszifratzeko.
noStreamsOptionCopy = Kopiatu lotura beste nabigatzaile batean irekitzeko
noStreamsOptionFirefox = Probatu gure nabigatzaile gogokoena
noStreamsOptionDownload = Jarraitu nabigatzaile honekin
downloadFirefoxPromo = Erabat berritutako { -firefox }(e)k eskaintzen dizu { -send-short-brand }
# the next line after the colon contains a file name
shareLinkDescription = Partekatu zure fitxategirako lotura:
shareLinkButton = Partekatu lotura
# $name is the name of the file
shareMessage = Deskargatu "{ $name }" { -send-brand } erabiliz: fitxategi-partekatze sinple eta segurua
trailheadPromo = Badago zure pribatutasuna babesteko modua. Egizu bat Firefoxekin.
learnMore = Argibide gehiago.

View File

@@ -54,6 +54,7 @@ passwordSetError = Dette passordet kunne ikke settes
-firefox = Firefox
-mozilla = Mozilla
introTitle = Enkel, privat fildeling
introDescription = { -send-brand } lar deg dele filer via en tidsbegrenset lenke med ende-til-ende-kryptering. På den måten kan du dele filer privat og samtidig være trygg på at filene dine ikke blir liggende på nettet for alltid.
notifyUploadEncryptDone = Filen din er kryptert og klar til å sende
# downloadCount is from the downloadCount string and timespan is a timespanMinutes string. ex. 'Expires after 2 downloads or 25 minutes'
archiveExpiryInfo = Utløper etter { $downloadCount } eller { $timespan }
@@ -77,9 +78,78 @@ fileCount =
[one] 1 fil
*[other] { $num } filer
}
# size is a localized number followed by a unit of bytes, ex. 2.5GB
# byte abbreviation
bytes = B
# kibibyte abbreviation
kb = KB
# mebibyte abbreviation
mb = MB
# gibibyte abbreviation
gb = GB
# localized number and byte abbreviation. example "2.5MB"
fileSize = { $num }{ $units }
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
totalSize = Total størrelse: { $size }
# the next line after the colon contains a file name
copyLinkDescription = Kopier lenken for å dele filen din:
copyLinkButton = Kopier lenke
downloadTitle = Last ned filer
downloadDescription = Denne filen ble delt via { -send-brand } med ende-til-ende-kryptering og en lenke som automatisk utløper.
trySendDescription = Prøv { -send-brand } for enkel, sikker fildeling.
# count will always be > 10
tooManyFiles =
{ $count ->
[one] Kun 1 fil kan lastes opp om gangen.
*[other] Kun { $count } filer kan lastes opp om gangen.
}
# count will always be > 10
tooManyArchives =
{ $count ->
[one] Kun 1 arkiv er tillatt.
*[other] Kun { $count } arkiver er tillatt.
}
expiredTitle = Denne lenken er utløpt.
notSupportedDescription = { -send-brand } virker ikke med denne nettleseren. { -send-short-brand } fungerer best med den nyeste versjonen av { -firefox }, og vil fungere med den nyeste versjonen av de fleste nettlesere.
downloadFirefox = Last ned { -firefox }
legalTitle = { -send-short-brand } Personvernerklæring
legalDateStamp = Versjon 1.0, datert den 12. mars 2019
# A short representation of a countdown timer containing the number of days, hours, and minutes remaining as digits, example "2d 11h 56m"
expiresDaysHoursMinutes = { $days }d { $hours }t { $minutes }m
addFilesButton = Velg filer du vil laste opp
uploadButton = Last opp
# the first part of the string 'Drag and drop files or click to send up to 1GB'
dragAndDropFiles = Dra og slipp filer
# the second part of the string 'Drag and drop files or click to send up to 1GB'
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
orClickWithSize = eller klikk for å sende filer på opptil { $size }
addPassword = Beskytt med passord
emailPlaceholder = Skriv inn e-postadressen din
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
signInSizeBump = Logg inn for å sende opptil { $size }
signInOnlyButton = Logg inn
accountBenefitTitle = Opprett en { -firefox }-konto eller logg inn
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
accountBenefitLargeFiles = Del filer på opptil { $size }
accountBenefitDownloadCount = Del filer med flere personer
accountBenefitTimeLimit =
{ $count ->
[one] Hold lenker aktiv opptil 1 dag
*[other] Hold lenker aktiv opptil { $count } dager
}
accountBenefitSync = Behandle delte filer fra en hvilken som helst enhet
accountBenefitMoz = Les om andre { -mozilla }-tjenester
signOut = Logg ut
okButton = OK
downloadingTitle = Laster ned
noStreamsWarning = Denne nettleseren kan kanskje ikke dekryptere en så stor fil.
noStreamsOptionCopy = Kopier lenken for å åpne den i en annen nettleser
noStreamsOptionFirefox = Prøv favorittnettleseren vår
noStreamsOptionDownload = Fortsett med denne nettleseren
downloadFirefoxPromo = { -send-short-brand } presenteres for deg av den helt nye { -firefox }.
# the next line after the colon contains a file name
shareLinkDescription = Del lenken til filen din:
shareLinkButton = Del lenke
# $name is the name of the file
shareMessage = Last ned { $name } med { -send-brand }: enkel, trygg fildeling
trailheadPromo = Det finnes en måte å ta vare på personvernet ditt. Bruk Firefox.
learnMore = Les mer.

155
public/locales/oc/send.ftl Normal file
View File

@@ -0,0 +1,155 @@
# Firefox Send is a brand name and should not be localized.
title = Firefox Send
siteFeedback = Comentaris
importingFile = Importacion…
encryptingFile = Chiframent…
decryptingFile = Deschiframent…
downloadCount =
{ $num ->
[one] 1 telecargament
*[other] { $num } telecargaments
}
timespanHours =
{ $num ->
[one] 1 ora
*[other] { $num } oras
}
copiedUrl = Copiat !
unlockInputPlaceholder = Senhal
unlockButtonLabel = Desverrolhar
downloadButtonLabel = Telecargar
downloadFinish = Telecargament acabat
fileSizeProgress = ({ $partialSize } sus { $totalSize })
sendYourFilesLink = Ensajar Firefox Send
errorPageHeader = I a quicòm que truca.
fileTooBig = Aqueste fichièr es tròp gròs per lenviar. Sa talha deu èsser inferiora a { $size }.
linkExpiredAlt = Lo ligam a expirat
notSupportedHeader = Vòstre navegador es pas compatible.
notSupportedLink = Perqué mon navegador es pas compatible ?
notSupportedOutdatedDetail = Aquesta version de Firefox es pas compatibla amb la tecnologia web amb la quala fonciona Firefox Send. Vos cal metre a jorn lo navegador.
updateFirefox = Metre a jorn Firefox
deletePopupCancel = Anullar
deleteButtonHover = Suprimir
footerLinkLegal = Mencions legalas
footerLinkPrivacy = Vida privada
footerLinkCookies = Cookies
passwordTryAgain = Senhal incorrècte. Tornatz ensajar.
javascriptRequired = Firefox Send requesís JavaScript
whyJavascript = Perque Firefox Send requesís JavaScript ?
enableJavascript = Volgatz activar lo JavaScript e ensajatz tornamai.
# A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
expiresHoursMinutes = { $hours } h { $minutes } min
# A short representation of a countdown timer containing the number of minutes remaining as digits, example "56m"
expiresMinutes = { $minutes } min
# A short status message shown when the user enters a long password
maxPasswordLength = Talha maximala del senhal : { $length }
# A short status message shown when there was an error setting the password
passwordSetError = Aqueste senhal a pas pogut èsser definit
## Send version 2 strings
# Firefox Send, Send, Firefox, Mozilla are proper names and should not be localized
-send-brand = Firefox Send
-send-short-brand = Send
-firefox = Firefox
-mozilla = Mozilla
introTitle = Partatge simple e privat de fichièrs
introDescription = { -send-brand } vos permet de partejar de fichièr amb un chiframent del cap a la fin e un ligam quexpira automaticament. Atal podètz gardar privat çò que partejatz e vos assegurar que demorarà pas en linha per totjorn.
notifyUploadEncryptDone = Vòstre fichièr es chifrat e prèst per mandadís
# downloadCount is from the downloadCount string and timespan is a timespanMinutes string. ex. 'Expires after 2 downloads or 25 minutes'
archiveExpiryInfo = Expira aprèp { $downloadCount } o { $timespan }
timespanMinutes =
{ $num ->
[one] 1 minuta
*[other] { $num } minutas
}
timespanDays =
{ $num ->
[one] 1 jorn
*[other] { $num } jorns
}
timespanWeeks =
{ $num ->
[one] 1 setmana
*[other] { $num } setmanas
}
fileCount =
{ $num ->
[one] 1 fichièr
*[other] { $num } fichièrs
}
# byte abbreviation
bytes = o
# kibibyte abbreviation
kb = Ko
# mebibyte abbreviation
mb = Mo
# gibibyte abbreviation
gb = Go
# localized number and byte abbreviation. example "2.5MB"
fileSize = { $num } { $units }
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
totalSize = Talha totala : { $size }
# the next line after the colon contains a file name
copyLinkDescription = Copiatz lo ligam per partejar vòstre fichièr :
copyLinkButton = Copiar lo ligam
downloadTitle = Telecargar los fichièrs
downloadDescription = Aqueste fichièr foguèt partejat via { -send-brand } amb chiframent del cap a la fin e un ligam quexpira automaticament.
trySendDescription = Ensajatz { -send-brand } per un partiment de fichièrs simple e segur.
# count will always be > 10
tooManyFiles =
{ $count ->
[one] Òm pòt pas quenviar 1 fichièr al còp.
*[other] Òm pòt pas quenviar { $count } fichièrs al còp.
}
# count will always be > 10
tooManyArchives =
{ $count ->
[one] Pas quun archiu es autorizat.
*[other] Pas que { $count } archius son autorizats.
}
expiredTitle = Aqueste ligam a expirat.
notSupportedDescription = { -send-brand } foncionarà pas amb aqueste navegador. { -send-short-brand } fonciona melhor amb la darrièra version de { -firefox } e foncionarà amb la version mai recenta de la màger part dels navegadors.
downloadFirefox = Telecargar { -firefox }
legalTitle = Avís de confidencialitat de { -send-short-brand }
legalDateStamp = Version 1.0 del 12 de març de 2019
# A short representation of a countdown timer containing the number of days, hours, and minutes remaining as digits, example "2d 11h 56m"
expiresDaysHoursMinutes = { $days } j { $hours } h { $minutes } min
addFilesButton = Seleccionatz los fichièrs de mandar
uploadButton = Enviar
# the first part of the string 'Drag and drop files or click to send up to 1GB'
dragAndDropFiles = Lissatz-depausatz de fichièrs
# the second part of the string 'Drag and drop files or click to send up to 1GB'
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
orClickWithSize = o clicatz per enviar fins a { $size }
addPassword = Protegir amb un senhal
emailPlaceholder = Picatz vòstra adreça electronica
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
signInSizeBump = Connectatz-vos per enviar fins a { $size }
signInOnlyButton = Connexion
accountBenefitTitle = Creatz un compte { -firefox } o connectatz-vos
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
accountBenefitLargeFiles = Partejatz de fichièrs fins a { $size }
accountBenefitDownloadCount = Partejatz de fichièrs amb mai de personas
accountBenefitTimeLimit =
{ $count ->
[one] Mantenètz los ligams actius fins a 1 jorn
*[other] Mantenètz los ligams actius fins a { $count } jorns
}
accountBenefitSync = Gerissètz los fichièrs partejats de qualque siá periferic estant
accountBenefitMoz = Aprenètz-ne mai suls autres servicis { -mozilla }
signOut = Desconnexion
okButton = D'acòrd
downloadingTitle = Telecargament
noStreamsWarning = Pòt arribar quaqueste navegador pòsca pas deschifrar un fichièr tan gròs.
noStreamsOptionCopy = Copiatz lo ligam per lo dobrir dins un autre navegador
noStreamsOptionFirefox = Ensajatz nòstre navegador preferit
noStreamsOptionDownload = Contunhar amb aqueste navegador
downloadFirefoxPromo = Lo nòu { -firefox } vos provesís { -send-short-brand }.
# the next line after the colon contains a file name
shareLinkDescription = Partejatz lo ligam cap a vòstre fichièr :
shareLinkButton = Partejar lo ligam
# $name is the name of the file
shareMessage = Telecargar « { $name } » amb { -send-brand } : un biais simple e segur de partejar de fichièrs.
trailheadPromo = Existís un biais de protegir vòstra vida privada. Rejonhètz Firefox.
learnMore = Ne saber mai.

View File

@@ -151,3 +151,5 @@ shareLinkDescription = ਆਪਣੀ ਫਾਇਲ ਲਈ ਲਿੰਕ ਸਾਂ
shareLinkButton = ਲਿੰਕ ਸਾਂਝਾ ਕਰੋ
# $name is the name of the file
shareMessage = { -send-brand } ਨਾਲ "{ $name }" ਡਾਊਨਲੋਡ ਕਰੋ: ਸੌਖਾ, ਸੁਰੱਖਿਅਤ ਫਾਇਲ ਸਾਂਝਾ ਕਰਨਾ
trailheadPromo = ਤੁਹਾਡੀ ਪਰਦੇਦਾਰੀ ਦੀ ਸੁਰੱਖਿਆ ਦਾ ਢੰਗ ਹੈ। ਫਾਇਰਫਾਕਸ ਨਾਲ ਜੁੜੋ।
learnMore = ਹੋਰ ਸਿੱਖੋ

View File

@@ -89,6 +89,7 @@ totalSize = మొత్తం పరిమాణం: { $size }
copyLinkDescription = మీ ఫైలును భాగస్వామ్యం చేయడానికి ఈ లంకెను నకలు చేయండి:
copyLinkButton = లంకెను నకలుతీయి
downloadTitle = ఫైళ్లను దింపుకోండి
expiredTitle = ఈ లంకె గడువు ముగిసింది.
downloadFirefox = { -firefox } ను దింపుకోండి
legalTitle = { -send-short-brand } గోప్యతా నోటీసు
legalDateStamp = వెర్షన్ 1.0, మార్చి 12, 2019 నాటిది
@@ -96,6 +97,11 @@ legalDateStamp = వెర్షన్ 1.0, మార్చి 12, 2019 నా
expiresDaysHoursMinutes = { $days }d { $hours }h { $minutes }m
addFilesButton = ఎక్కించడానికి ఫైళ్ళను ఎంచుకోండి
uploadButton = ఎక్కించు
# the first part of the string 'Drag and drop files or click to send up to 1GB'
dragAndDropFiles = ఫైళ్ళను లాగండి మరియు వదలండి
# the second part of the string 'Drag and drop files or click to send up to 1GB'
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
orClickWithSize = లేదా { $size } వరకు పంపడానికి నొక్కండి
addPassword = సంకేతపదంతో రక్షించండి
emailPlaceholder = ఈ ఈమెయిలును ఇవ్వండి
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
@@ -105,6 +111,7 @@ accountBenefitTitle = ఒక { -firefox } ఖాతాని సృష్టి
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
accountBenefitLargeFiles = { $size } పరిమాణం ఫైళ్ళ వరకు పంచుకోండి
accountBenefitDownloadCount = ఫైళ్లను ఎక్కువ మందితో పంచుకోండి
accountBenefitSync = ఏదైనా పరికరం నుండి పంచుకున్న ఫైళ్ళను నిర్వహించండి
signOut = నిష్క్రమించు
okButton = సరే
downloadingTitle = దింపుకుంటోంది

View File

@@ -3,7 +3,7 @@ const routes = require('../routes');
const pages = require('../routes/pages');
const tests = require('../../test/frontend/routes');
const express = require('express');
const expressWs = require('express-ws');
const expressWs = require('@dannycoates/express-ws');
const morgan = require('morgan');
const config = require('../config');

View File

@@ -1,13 +1,13 @@
const express = require('express');
const path = require('path');
const Raven = require('raven');
const Sentry = require('@sentry/node');
const config = require('../config');
const routes = require('../routes');
const pages = require('../routes/pages');
const expressWs = require('express-ws');
const expressWs = require('@dannycoates/express-ws');
if (config.sentry_dsn) {
Raven.config(config.sentry_dsn).install();
Sentry.init({ dsn: config.sentry_dsn });
}
const app = express();

View File

@@ -2,7 +2,7 @@ const assets = require('../../common/assets');
const routes = require('../routes');
const pages = require('../routes/pages');
const tests = require('../../test/frontend/routes');
const expressWs = require('express-ws');
const expressWs = require('@dannycoates/express-ws');
module.exports = function(app, devServer) {
assets.setMiddleware(devServer.middleware);

View File

@@ -8,12 +8,10 @@ if (config.sentry_id) {
//eslint-disable-next-line node/no-missing-require
const version = require('../dist/version.json');
sentry = `
var RAVEN_CONFIG = {
var SENTRY_CONFIG = {
dsn: '${config.sentry_id}',
release: '${version.version}',
tags: {
commit: '${version.commit}'
},
dataCallback: function (data) {
beforeSend: function (data) {
var hash = window.location.hash;
if (hash) {
return JSON.parse(JSON.stringify(data).replace(new RegExp(hash.slice(1), 'g'), ''));
@@ -21,7 +19,6 @@ var RAVEN_CONFIG = {
return data;
}
}
var SENTRY_ID = '${config.sentry_id}';
`;
}

View File

@@ -3,12 +3,11 @@ const storage = require('../storage');
const config = require('../config');
const mozlog = require('../log');
const Limiter = require('../limiter');
const wsStream = require('websocket-stream/stream');
const fxa = require('../fxa');
const { statUploadEvent } = require('../amplitude');
const { encryptedSize } = require('../../app/utils');
const { Duplex } = require('stream');
const { Transform } = require('stream');
const log = mozlog('send.upload');
@@ -76,25 +75,19 @@ module.exports = function(ws, req) {
})
);
const limiter = new Limiter(encryptedSize(maxFileSize));
const flowControl = new Duplex({
read() {
ws.resume();
},
write(chunk, encoding, callback) {
const eof = new Transform({
transform: function(chunk, encoding, callback) {
if (chunk.length === 1 && chunk[0] === 0) {
this.push(null);
} else {
if (!this.push(chunk)) {
ws.pause();
}
this.push(chunk);
}
callback();
}
});
const wsStream = ws.constructor.createWebSocketStream(ws);
fileStream = wsStream(ws, { binary: true })
.pipe(flowControl)
.pipe(limiter); // limiter needs to be the last in the chain
fileStream = wsStream.pipe(eof).pipe(limiter); // limiter needs to be the last in the chain
await storage.set(newId, fileStream, meta, timeLimit);
@@ -126,8 +119,8 @@ module.exports = function(ws, req) {
error: e === 'limit' ? 413 : 500
})
);
}
}
ws.close();
}
}
});
};

View File

@@ -22,7 +22,7 @@ class GCSStorage {
.pipe(
this.bucket.file(id).createWriteStream({
validation: false,
resumable: false
resumable: true
})
)
.on('error', reject)

View File

@@ -6,7 +6,7 @@ module.exports = {
const webpack = require('webpack');
const middleware = require('webpack-dev-middleware');
const express = require('express');
const expressWs = require('express-ws');
const expressWs = require('@dannycoates/express-ws');
const assets = require('../common/assets');
const routes = require('../server/routes');
const tests = require('./frontend/routes');

View File

@@ -114,6 +114,7 @@ const web = {
exclude: [
path.resolve(__dirname, 'node_modules/crc'),
path.resolve(__dirname, 'node_modules/@fluent'),
path.resolve(__dirname, 'node_modules/@sentry'),
path.resolve(__dirname, 'node_modules/tslib'),
path.resolve(__dirname, 'node_modules/webcrypto-core')
],