mirror of
https://gitlab.com/timvisee/send.git
synced 2025-12-07 14:40:55 +03:00
Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c2dd51c638 | ||
|
|
cdd98af86a | ||
|
|
883f2bc0f9 | ||
|
|
94f1eabbc7 | ||
|
|
902bc6628e | ||
|
|
460b741f17 | ||
|
|
d5c488196d | ||
|
|
9ad9c9feb2 | ||
|
|
6576e4a74c | ||
|
|
950872109e | ||
|
|
87051d27ed | ||
|
|
3451803b37 | ||
|
|
ac15153e8f | ||
|
|
924f5dc682 | ||
|
|
ff9be6a213 | ||
|
|
883728570e | ||
|
|
0435f17f9a | ||
|
|
1e1268fff0 | ||
|
|
252d7817e3 | ||
|
|
ce28c38ebe | ||
|
|
f0407f9beb | ||
|
|
c6f222eb57 | ||
|
|
6dd6135185 | ||
|
|
8df339b66d | ||
|
|
8702fda651 | ||
|
|
807ecff471 | ||
|
|
927c981cd7 | ||
|
|
7073cc8ce6 | ||
|
|
c925fae696 | ||
|
|
966d7a5e35 | ||
|
|
96c750c098 | ||
|
|
0729064753 | ||
|
|
259a5a5f24 | ||
|
|
27be72e0cd | ||
|
|
e4231bbc0f | ||
|
|
1d184f06bf | ||
|
|
f7b46a99ac | ||
|
|
3fadb489c7 | ||
|
|
6378676c2d | ||
|
|
014d84e4c7 | ||
|
|
a08d8435a9 | ||
|
|
40a05c9ecf | ||
|
|
527040afef | ||
|
|
a48a447808 | ||
|
|
f3569d7f98 | ||
|
|
6ca7d11efb | ||
|
|
b71ae4a0ff | ||
|
|
7ba25664b5 | ||
|
|
80fb42ad3d | ||
|
|
f036df5f47 | ||
|
|
20c063db7c |
@@ -2,5 +2,6 @@ dist
|
|||||||
assets
|
assets
|
||||||
firefox
|
firefox
|
||||||
coverage
|
coverage
|
||||||
|
android/app/build
|
||||||
app/locale.js
|
app/locale.js
|
||||||
app/capabilities.js
|
app/capabilities.js
|
||||||
@@ -4,6 +4,7 @@ env:
|
|||||||
|
|
||||||
extends:
|
extends:
|
||||||
- eslint:recommended
|
- eslint:recommended
|
||||||
|
- prettier
|
||||||
- plugin:node/recommended
|
- plugin:node/recommended
|
||||||
- plugin:security/recommended
|
- plugin:security/recommended
|
||||||
|
|
||||||
@@ -22,13 +23,5 @@ rules:
|
|||||||
security/detect-non-literal-fs-filename: off
|
security/detect-non-literal-fs-filename: off
|
||||||
security/detect-object-injection: off
|
security/detect-object-injection: off
|
||||||
|
|
||||||
eol-last: [error, always]
|
|
||||||
eqeqeq: error
|
|
||||||
no-alert: warn
|
|
||||||
no-console: warn
|
|
||||||
no-path-concat: error
|
|
||||||
no-unused-vars: [error, {argsIgnorePattern: "^_|err|event|next|reject"}]
|
no-unused-vars: [error, {argsIgnorePattern: "^_|err|event|next|reject"}]
|
||||||
no-var: error
|
require-atomic-updates: warn
|
||||||
one-var: [error, never]
|
|
||||||
prefer-const: error
|
|
||||||
quotes: [error, single, {avoidEscape: true}]
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ USER app
|
|||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --chown=app:app --from=builder /app .
|
COPY --chown=app:app --from=builder /app .
|
||||||
COPY --chown=app:app . .
|
COPY --chown=app:app . .
|
||||||
|
RUN mkdir -p /app/.config/configstore
|
||||||
RUN ln -s dist/version.json version.json
|
RUN ln -s dist/version.json version.json
|
||||||
|
|
||||||
ENV PORT=1443
|
ENV PORT=1443
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'intl-pluralrules';
|
import 'intl-pluralrules';
|
||||||
import choo from 'choo';
|
import choo from 'choo';
|
||||||
import html from 'choo/html';
|
import html from 'choo/html';
|
||||||
import Raven from 'raven-js';
|
import * as Sentry from '@sentry/browser';
|
||||||
|
|
||||||
import { setApiUrlPrefix, getConstants } from '../app/api';
|
import { setApiUrlPrefix, getConstants } from '../app/api';
|
||||||
import metrics from '../app/metrics';
|
import metrics from '../app/metrics';
|
||||||
@@ -82,7 +82,7 @@ function body(main) {
|
|||||||
state.archive = new Archive([], DEFAULTS.EXPIRE_SECONDS);
|
state.archive = new Archive([], DEFAULTS.EXPIRE_SECONDS);
|
||||||
state.storage = storage;
|
state.storage = storage;
|
||||||
state.user = new User(storage, LIMITS);
|
state.user = new User(storage, LIMITS);
|
||||||
state.raven = Raven;
|
state.sentry = Sentry;
|
||||||
});
|
});
|
||||||
app.use(metrics);
|
app.use(metrics);
|
||||||
app.route('/', body(home));
|
app.route('/', body(home));
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export default function initialState(state, emitter) {
|
|||||||
getAsset(name) {
|
getAsset(name) {
|
||||||
return `${state.prefix}/${name}`;
|
return `${state.prefix}/${name}`;
|
||||||
},
|
},
|
||||||
raven: {
|
sentry: {
|
||||||
captureException: e => {
|
captureException: e => {
|
||||||
console.error('ERROR ' + e + ' ' + e.stack);
|
console.error('ERROR ' + e + ' ' + e.stack);
|
||||||
}
|
}
|
||||||
|
|||||||
78
app/api.js
78
app/api.js
@@ -11,6 +11,15 @@ if (!fileProtocolWssUrl) {
|
|||||||
fileProtocolWssUrl = 'wss://send.firefox.com/api/ws';
|
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) {
|
export function setFileProtocolWssUrl(url) {
|
||||||
localStorage && localStorage.setItem('wssURL', url);
|
localStorage && localStorage.setItem('wssURL', url);
|
||||||
fileProtocolWssUrl = url;
|
fileProtocolWssUrl = url;
|
||||||
@@ -137,17 +146,25 @@ export async function setPassword(id, owner_token, keychain) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function asyncInitWebSocket(server) {
|
function asyncInitWebSocket(server) {
|
||||||
return new Promise(resolve => {
|
return new Promise((resolve, reject) => {
|
||||||
const ws = new WebSocket(server);
|
try {
|
||||||
ws.onopen = () => {
|
const ws = new WebSocket(server);
|
||||||
resolve(ws);
|
ws.addEventListener('open', () => resolve(ws), { once: true });
|
||||||
};
|
} catch (e) {
|
||||||
|
reject(new ConnectionError(false));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function listenForResponse(ws, canceller) {
|
function listenForResponse(ws, canceller) {
|
||||||
return new Promise((resolve, reject) => {
|
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) {
|
function handleMessage(msg) {
|
||||||
|
ws.removeEventListener('close', handleClose);
|
||||||
try {
|
try {
|
||||||
const response = JSON.parse(msg.data);
|
const response = JSON.parse(msg.data);
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
@@ -156,13 +173,11 @@ function listenForResponse(ws, canceller) {
|
|||||||
resolve(response);
|
resolve(response);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
ws.close();
|
|
||||||
canceller.cancelled = true;
|
|
||||||
canceller.error = e;
|
|
||||||
reject(e);
|
reject(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ws.addEventListener('message', handleMessage, { once: true });
|
ws.addEventListener('message', handleMessage, { once: true });
|
||||||
|
ws.addEventListener('close', handleClose, { once: true });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,6 +191,8 @@ async function upload(
|
|||||||
onprogress,
|
onprogress,
|
||||||
canceller
|
canceller
|
||||||
) {
|
) {
|
||||||
|
let size = 0;
|
||||||
|
const start = Date.now();
|
||||||
const host = window.location.hostname;
|
const host = window.location.hostname;
|
||||||
const port = window.location.port;
|
const port = window.location.port;
|
||||||
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||||
@@ -203,31 +220,41 @@ async function upload(
|
|||||||
|
|
||||||
const reader = stream.getReader();
|
const reader = stream.getReader();
|
||||||
let state = await reader.read();
|
let state = await reader.read();
|
||||||
let size = 0;
|
|
||||||
while (!state.done) {
|
while (!state.done) {
|
||||||
const buf = state.value;
|
|
||||||
if (canceller.cancelled) {
|
if (canceller.cancelled) {
|
||||||
throw canceller.error;
|
ws.close();
|
||||||
}
|
}
|
||||||
|
if (ws.readyState !== WebSocket.OPEN) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const buf = state.value;
|
||||||
ws.send(buf);
|
ws.send(buf);
|
||||||
|
|
||||||
onprogress(size);
|
onprogress(size);
|
||||||
size += buf.length;
|
size += buf.length;
|
||||||
state = await reader.read();
|
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();
|
await delay();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const footer = new Uint8Array([0]);
|
if (ws.readyState === WebSocket.OPEN) {
|
||||||
ws.send(footer);
|
ws.send(new Uint8Array([0])); //EOF
|
||||||
|
}
|
||||||
|
|
||||||
await completedResponse;
|
await completedResponse;
|
||||||
ws.close();
|
uploadInfo.duration = Date.now() - start;
|
||||||
return uploadInfo;
|
return uploadInfo;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
ws.close(4000);
|
e.size = size;
|
||||||
|
e.duration = Date.now() - start;
|
||||||
throw e;
|
throw e;
|
||||||
|
} finally {
|
||||||
|
if (![WebSocket.CLOSED, WebSocket.CLOSING].includes(ws.readyState)) {
|
||||||
|
ws.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,7 +271,6 @@ export function uploadWs(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
cancel: function() {
|
cancel: function() {
|
||||||
canceller.error = new Error(0);
|
|
||||||
canceller.cancelled = true;
|
canceller.cancelled = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -284,7 +310,7 @@ async function downloadS(id, keychain, signal) {
|
|||||||
return response.body;
|
return response.body;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function tryDownloadStream(id, keychain, signal, tries = 1) {
|
async function tryDownloadStream(id, keychain, signal, tries = 2) {
|
||||||
try {
|
try {
|
||||||
const result = await downloadS(id, keychain, signal);
|
const result = await downloadS(id, keychain, signal);
|
||||||
return result;
|
return result;
|
||||||
@@ -306,18 +332,19 @@ export function downloadStream(id, keychain) {
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
cancel,
|
cancel,
|
||||||
result: tryDownloadStream(id, keychain, controller.signal, 2)
|
result: tryDownloadStream(id, keychain, controller.signal)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////
|
//////////////////
|
||||||
|
|
||||||
function download(id, keychain, onprogress, canceller) {
|
async function download(id, keychain, onprogress, canceller) {
|
||||||
|
const auth = await keychain.authHeader();
|
||||||
const xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
canceller.oncancel = function() {
|
canceller.oncancel = function() {
|
||||||
xhr.abort();
|
xhr.abort();
|
||||||
};
|
};
|
||||||
return new Promise(async function(resolve, reject) {
|
return new Promise(function(resolve, reject) {
|
||||||
xhr.addEventListener('loadend', function() {
|
xhr.addEventListener('loadend', function() {
|
||||||
canceller.oncancel = function() {};
|
canceller.oncancel = function() {};
|
||||||
const authHeader = xhr.getResponseHeader('WWW-Authenticate');
|
const authHeader = xhr.getResponseHeader('WWW-Authenticate');
|
||||||
@@ -337,7 +364,6 @@ function download(id, keychain, onprogress, canceller) {
|
|||||||
onprogress(event.loaded);
|
onprogress(event.loaded);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const auth = await keychain.authHeader();
|
|
||||||
xhr.open('get', getApiUrl(`/api/download/blob/${id}`));
|
xhr.open('get', getApiUrl(`/api/download/blob/${id}`));
|
||||||
xhr.setRequestHeader('Authorization', auth);
|
xhr.setRequestHeader('Authorization', auth);
|
||||||
xhr.responseType = 'blob';
|
xhr.responseType = 'blob';
|
||||||
@@ -346,7 +372,7 @@ 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 {
|
try {
|
||||||
const result = await download(id, keychain, onprogress, canceller);
|
const result = await download(id, keychain, onprogress, canceller);
|
||||||
return result;
|
return result;
|
||||||
@@ -367,7 +393,7 @@ export function downloadFile(id, keychain, onprogress) {
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
cancel,
|
cancel,
|
||||||
result: tryDownload(id, keychain, onprogress, canceller, 2)
|
result: tryDownload(id, keychain, onprogress, canceller)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,8 +76,8 @@ async function polyfillStreams() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default async function getCapabilities() {
|
export default async function getCapabilities() {
|
||||||
const serviceWorker =
|
const browser = browserName();
|
||||||
'serviceWorker' in navigator && browserName() !== 'edge';
|
const serviceWorker = 'serviceWorker' in navigator && browser !== 'edge';
|
||||||
let crypto = await checkCrypto();
|
let crypto = await checkCrypto();
|
||||||
const nativeStreams = checkStreams();
|
const nativeStreams = checkStreams();
|
||||||
let polyStreams = false;
|
let polyStreams = false;
|
||||||
@@ -97,13 +97,16 @@ export default async function getCapabilities() {
|
|||||||
window.matchMedia('(display-mode: standalone)').matches ||
|
window.matchMedia('(display-mode: standalone)').matches ||
|
||||||
navigator.standalone;
|
navigator.standalone;
|
||||||
|
|
||||||
|
const mobileFirefox =
|
||||||
|
browser === 'firefox' && /mobile/i.test(navigator.userAgent);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
account,
|
account,
|
||||||
crypto,
|
crypto,
|
||||||
serviceWorker,
|
serviceWorker,
|
||||||
streamUpload: nativeStreams || polyStreams,
|
streamUpload: nativeStreams || polyStreams,
|
||||||
streamDownload:
|
streamDownload:
|
||||||
nativeStreams && serviceWorker && browserName() !== 'safari',
|
nativeStreams && serviceWorker && browser !== 'safari' && !mobileFirefox,
|
||||||
multifile: nativeStreams || polyStreams,
|
multifile: nativeStreams || polyStreams,
|
||||||
share,
|
share,
|
||||||
standalone
|
standalone
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export default function(state, emitter) {
|
|||||||
state.storage.remove(ownedFile.id);
|
state.storage.remove(ownedFile.id);
|
||||||
await ownedFile.del();
|
await ownedFile.del();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
state.raven.captureException(e);
|
state.sentry.captureException(e);
|
||||||
}
|
}
|
||||||
render();
|
render();
|
||||||
});
|
});
|
||||||
@@ -176,14 +176,17 @@ export default function(state, emitter) {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.message === '0') {
|
if (err.message === '0') {
|
||||||
//cancelled. do nothing
|
//cancelled. do nothing
|
||||||
const duration = Date.now() - start;
|
metrics.cancelledUpload(archive, err.duration);
|
||||||
metrics.cancelledUpload(archive, duration);
|
|
||||||
render();
|
render();
|
||||||
} else {
|
} else {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.error(err);
|
console.error(err);
|
||||||
state.raven.captureException(err);
|
state.sentry.withScope(scope => {
|
||||||
metrics.stoppedUpload(archive);
|
scope.setExtra('duration', err.duration);
|
||||||
|
scope.setExtra('size', err.size);
|
||||||
|
state.sentry.captureException(err);
|
||||||
|
});
|
||||||
|
metrics.stoppedUpload(archive, err.duration);
|
||||||
emitter.emit('pushState', '/error');
|
emitter.emit('pushState', '/error');
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@@ -262,7 +265,12 @@ export default function(state, emitter) {
|
|||||||
state.transfer = null;
|
state.transfer = null;
|
||||||
const location = err.message === '404' ? '/404' : '/error';
|
const location = err.message === '404' ? '/404' : '/error';
|
||||||
if (location === '/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;
|
const duration = Date.now() - start;
|
||||||
metrics.stoppedDownload({
|
metrics.stoppedDownload({
|
||||||
size,
|
size,
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ export default class FileReceiver extends Nanobus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async downloadStream(noSave = false) {
|
async downloadStream(noSave = false) {
|
||||||
|
const start = Date.now();
|
||||||
const onprogress = p => {
|
const onprogress = p => {
|
||||||
this.progress = [p, this.fileInfo.size];
|
this.progress = [p, this.fileInfo.size];
|
||||||
this.emit('progress');
|
this.emit('progress');
|
||||||
@@ -153,7 +154,7 @@ export default class FileReceiver extends Nanobus {
|
|||||||
const downloadPath = `/api/download/${this.fileInfo.id}`;
|
const downloadPath = `/api/download/${this.fileInfo.id}`;
|
||||||
let downloadUrl = getApiUrl(downloadPath);
|
let downloadUrl = getApiUrl(downloadPath);
|
||||||
if (downloadUrl === 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');
|
const a = document.createElement('a');
|
||||||
a.href = downloadUrl;
|
a.href = downloadUrl;
|
||||||
@@ -162,11 +163,29 @@ export default class FileReceiver extends Nanobus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let prog = 0;
|
let prog = 0;
|
||||||
|
let hangs = 0;
|
||||||
while (prog < this.fileInfo.size) {
|
while (prog < this.fileInfo.size) {
|
||||||
const msg = await this.sendMessageToSw({
|
const msg = await this.sendMessageToSw({
|
||||||
request: 'progress',
|
request: 'progress',
|
||||||
id: this.fileInfo.id
|
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;
|
prog = msg.progress;
|
||||||
onprogress(prog);
|
onprogress(prog);
|
||||||
await delay(1000);
|
await delay(1000);
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ export default class FileSender extends Nanobus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async upload(archive, bearerToken) {
|
async upload(archive, bearerToken) {
|
||||||
const start = Date.now();
|
|
||||||
if (this.cancelled) {
|
if (this.cancelled) {
|
||||||
throw new Error(0);
|
throw new Error(0);
|
||||||
}
|
}
|
||||||
@@ -76,7 +75,6 @@ export default class FileSender extends Nanobus {
|
|||||||
this.emit('progress'); // HACK to kick MS Edge
|
this.emit('progress'); // HACK to kick MS Edge
|
||||||
try {
|
try {
|
||||||
const result = await this.uploadRequest.result;
|
const result = await this.uploadRequest.result;
|
||||||
const time = Date.now() - start;
|
|
||||||
this.msg = 'notifyUploadEncryptDone';
|
this.msg = 'notifyUploadEncryptDone';
|
||||||
this.uploadRequest = null;
|
this.uploadRequest = null;
|
||||||
this.progress = [1, 1];
|
this.progress = [1, 1];
|
||||||
@@ -87,8 +85,8 @@ export default class FileSender extends Nanobus {
|
|||||||
name: archive.name,
|
name: archive.name,
|
||||||
size: archive.size,
|
size: archive.size,
|
||||||
manifest: archive.manifest,
|
manifest: archive.manifest,
|
||||||
time: time,
|
time: result.duration,
|
||||||
speed: archive.size / (time / 1000),
|
speed: archive.size / (result.duration / 1000),
|
||||||
createdAt: Date.now(),
|
createdAt: Date.now(),
|
||||||
expiresAt: Date.now() + archive.timeLimit * 1000,
|
expiresAt: Date.now() + archive.timeLimit * 1000,
|
||||||
secretKey: secretKey,
|
secretKey: secretKey,
|
||||||
|
|||||||
10
app/main.js
10
app/main.js
@@ -12,15 +12,15 @@ import pasteManager from './pasteManager';
|
|||||||
import storage from './storage';
|
import storage from './storage';
|
||||||
import metrics from './metrics';
|
import metrics from './metrics';
|
||||||
import experiments from './experiments';
|
import experiments from './experiments';
|
||||||
import Raven from 'raven-js';
|
import * as Sentry from '@sentry/browser';
|
||||||
import './main.css';
|
import './main.css';
|
||||||
import User from './user';
|
import User from './user';
|
||||||
import { getTranslator } from './locale';
|
import { getTranslator } from './locale';
|
||||||
import Archive from './archive';
|
import Archive from './archive';
|
||||||
import { setTranslate, locale } from './utils';
|
import { setTranslate, locale } from './utils';
|
||||||
|
|
||||||
if (navigator.doNotTrack !== '1' && window.RAVEN_CONFIG) {
|
if (navigator.doNotTrack !== '1' && window.SENTRY_CONFIG) {
|
||||||
Raven.config(window.SENTRY_ID, window.RAVEN_CONFIG).install();
|
Sentry.init(window.SENTRY_CONFIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'production') {
|
if (process.env.NODE_ENV === 'production') {
|
||||||
@@ -56,13 +56,13 @@ if (process.env.NODE_ENV === 'production') {
|
|||||||
capabilities,
|
capabilities,
|
||||||
translate,
|
translate,
|
||||||
storage,
|
storage,
|
||||||
raven: Raven,
|
sentry: Sentry,
|
||||||
user: new User(storage, LIMITS, window.AUTH_CONFIG),
|
user: new User(storage, LIMITS, window.AUTH_CONFIG),
|
||||||
transfer: null,
|
transfer: null,
|
||||||
fileInfo: null
|
fileInfo: null
|
||||||
};
|
};
|
||||||
|
|
||||||
const app = routes(choo());
|
const app = routes(choo({ hash: true }));
|
||||||
// eslint-disable-next-line require-atomic-updates
|
// eslint-disable-next-line require-atomic-updates
|
||||||
window.app = app;
|
window.app = app;
|
||||||
app.use(experiments);
|
app.use(experiments);
|
||||||
|
|||||||
@@ -107,9 +107,10 @@ function completedUpload(archive, duration) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function stoppedUpload(archive) {
|
function stoppedUpload(archive, duration = 0) {
|
||||||
return addEvent('client_upload', {
|
return addEvent('client_upload', {
|
||||||
download_limit: archive.dlimit,
|
download_limit: archive.dlimit,
|
||||||
|
duration: sizeOrder(duration),
|
||||||
file_count: archive.numFiles,
|
file_count: archive.numFiles,
|
||||||
password_protected: !!archive.password,
|
password_protected: !!archive.password,
|
||||||
size: sizeOrder(archive.size),
|
size: sizeOrder(archive.size),
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ const choo = require('choo');
|
|||||||
const download = require('./ui/download');
|
const download = require('./ui/download');
|
||||||
const body = require('./ui/body');
|
const body = require('./ui/body');
|
||||||
|
|
||||||
module.exports = function(app = choo()) {
|
module.exports = function(app = choo({ hash: true })) {
|
||||||
app.route('/', body(require('./ui/home')));
|
app.route('/', body(require('./ui/home')));
|
||||||
app.route('/download/:id', body(download));
|
app.route('/download/:id', body(download));
|
||||||
app.route('/download/:id/:key', body(download));
|
app.route('/download/:id/:key', body(download));
|
||||||
|
|||||||
@@ -11,13 +11,14 @@ const map = new Map();
|
|||||||
const IMAGES = /.*\.(png|svg|jpg)$/;
|
const IMAGES = /.*\.(png|svg|jpg)$/;
|
||||||
const VERSIONED_ASSET = /\.[A-Fa-f0-9]{8}\.(js|css|png|svg|jpg)$/;
|
const VERSIONED_ASSET = /\.[A-Fa-f0-9]{8}\.(js|css|png|svg|jpg)$/;
|
||||||
const DOWNLOAD_URL = /\/api\/download\/([A-Fa-f0-9]{4,})/;
|
const DOWNLOAD_URL = /\/api\/download\/([A-Fa-f0-9]{4,})/;
|
||||||
|
const FONT = /\.woff2?$/;
|
||||||
|
|
||||||
self.addEventListener('install', event => {
|
self.addEventListener('install', () => {
|
||||||
event.waitUntil(precache());
|
self.skipWaiting();
|
||||||
});
|
});
|
||||||
|
|
||||||
self.addEventListener('activate', event => {
|
self.addEventListener('activate', event => {
|
||||||
event.waitUntil(self.clients.claim());
|
event.waitUntil(self.clients.claim().then(precache));
|
||||||
});
|
});
|
||||||
|
|
||||||
async function decryptStream(id) {
|
async function decryptStream(id) {
|
||||||
@@ -83,16 +84,28 @@ async function decryptStream(id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function precache() {
|
async function precache() {
|
||||||
|
try {
|
||||||
|
await cleanCache();
|
||||||
|
const cache = await caches.open(version);
|
||||||
|
const images = assets.match(IMAGES);
|
||||||
|
await cache.addAll(images);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
// cache will get populated on demand
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function cleanCache() {
|
||||||
const oldCaches = await caches.keys();
|
const oldCaches = await caches.keys();
|
||||||
for (const c of oldCaches) {
|
for (const c of oldCaches) {
|
||||||
if (c !== version) {
|
if (c !== version) {
|
||||||
await caches.delete(c);
|
await caches.delete(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const cache = await caches.open(version);
|
}
|
||||||
const images = assets.match(IMAGES);
|
|
||||||
await cache.addAll(images);
|
function cacheable(url) {
|
||||||
return self.skipWaiting();
|
return VERSIONED_ASSET.test(url) || FONT.test(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function cachedOrFetched(req) {
|
async function cachedOrFetched(req) {
|
||||||
@@ -102,7 +115,7 @@ async function cachedOrFetched(req) {
|
|||||||
return cached;
|
return cached;
|
||||||
}
|
}
|
||||||
const fetched = await fetch(req);
|
const fetched = await fetch(req);
|
||||||
if (fetched.ok && VERSIONED_ASSET.test(req.url)) {
|
if (fetched.ok && cacheable(req.url)) {
|
||||||
cache.put(req, fetched.clone());
|
cache.put(req, fetched.clone());
|
||||||
}
|
}
|
||||||
return fetched;
|
return fetched;
|
||||||
@@ -115,7 +128,7 @@ self.onfetch = event => {
|
|||||||
const dlmatch = DOWNLOAD_URL.exec(url.pathname);
|
const dlmatch = DOWNLOAD_URL.exec(url.pathname);
|
||||||
if (dlmatch) {
|
if (dlmatch) {
|
||||||
event.respondWith(decryptStream(dlmatch[1]));
|
event.respondWith(decryptStream(dlmatch[1]));
|
||||||
} else if (VERSIONED_ASSET.test(url.pathname)) {
|
} else if (cacheable(url.pathname)) {
|
||||||
event.respondWith(cachedOrFetched(req));
|
event.respondWith(cachedOrFetched(req));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* global ReadableStream TransformStream */
|
/* global TransformStream */
|
||||||
|
|
||||||
export function transformStream(readable, transformer, oncancel) {
|
export function transformStream(readable, transformer, oncancel) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
1949
package-lock.json
generated
1949
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
79
package.json
79
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "firefox-send",
|
"name": "firefox-send",
|
||||||
"description": "File Sharing Experiment",
|
"description": "File Sharing Experiment",
|
||||||
"version": "3.0.13",
|
"version": "3.0.18",
|
||||||
"author": "Mozilla (https://mozilla.org)",
|
"author": "Mozilla (https://mozilla.org)",
|
||||||
"repository": "mozilla/send",
|
"repository": "mozilla/send",
|
||||||
"homepage": "https://github.com/mozilla/send/",
|
"homepage": "https://github.com/mozilla/send/",
|
||||||
@@ -35,7 +35,8 @@
|
|||||||
"hooks": {
|
"hooks": {
|
||||||
"pre-commit": "lint-staged",
|
"pre-commit": "lint-staged",
|
||||||
"pre-push": "npm test",
|
"pre-push": "npm test",
|
||||||
"post-merge": "npm install"
|
"post-merge": "npm install",
|
||||||
|
"post-checkout": "scripts/sync-npm-dependencies.sh"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
@@ -60,65 +61,66 @@
|
|||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.5.5",
|
"@babel/core": "^7.6.0",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.5.5",
|
"@babel/plugin-proposal-class-properties": "^7.5.5",
|
||||||
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
|
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
|
||||||
"@babel/preset-env": "^7.5.5",
|
"@babel/preset-env": "^7.6.0",
|
||||||
"@dannycoates/webcrypto-liner": "^0.1.37",
|
"@dannycoates/webcrypto-liner": "^0.1.37",
|
||||||
"@fullhuman/postcss-purgecss": "^1.2.0",
|
"@fullhuman/postcss-purgecss": "^1.2.0",
|
||||||
"@mattiasbuelens/web-streams-polyfill": "0.2.1",
|
"@mattiasbuelens/web-streams-polyfill": "0.2.1",
|
||||||
|
"@sentry/browser": "^5.6.3",
|
||||||
"asmcrypto.js": "^0.22.0",
|
"asmcrypto.js": "^0.22.0",
|
||||||
"babel-loader": "^8.0.6",
|
"babel-loader": "^8.0.6",
|
||||||
"babel-plugin-istanbul": "^5.2.0",
|
"babel-plugin-istanbul": "^5.2.0",
|
||||||
"base64-js": "^1.3.0",
|
"base64-js": "^1.3.1",
|
||||||
"content-disposition": "^0.5.3",
|
"content-disposition": "^0.5.3",
|
||||||
"copy-webpack-plugin": "^5.0.4",
|
"copy-webpack-plugin": "^5.0.4",
|
||||||
"core-js": "^3.1.4",
|
"core-js": "^3.2.1",
|
||||||
"crc": "^3.8.0",
|
"crc": "^3.8.0",
|
||||||
"cross-env": "^5.2.0",
|
"cross-env": "^5.2.1",
|
||||||
"css-loader": "^3.1.0",
|
"css-loader": "^3.2.0",
|
||||||
"css-mqpacker": "^7.0.0",
|
"css-mqpacker": "^7.0.0",
|
||||||
"cssnano": "^4.1.10",
|
"cssnano": "^4.1.10",
|
||||||
"eslint": "^6.1.0",
|
"eslint": "^6.3.0",
|
||||||
"eslint-plugin-mocha": "^6.0.0",
|
"eslint-config-prettier": "^6.2.0",
|
||||||
"eslint-plugin-node": "^9.1.0",
|
"eslint-plugin-mocha": "^6.1.0",
|
||||||
|
"eslint-plugin-node": "^9.2.0",
|
||||||
"eslint-plugin-security": "^1.4.0",
|
"eslint-plugin-security": "^1.4.0",
|
||||||
"expose-loader": "^0.7.5",
|
"expose-loader": "^0.7.5",
|
||||||
"extract-loader": "^3.1.0",
|
"extract-loader": "^3.1.0",
|
||||||
"extract-text-webpack-plugin": "^4.0.0-beta.0",
|
"extract-text-webpack-plugin": "^4.0.0-beta.0",
|
||||||
"fast-text-encoding": "^1.0.0",
|
"fast-text-encoding": "^1.0.0",
|
||||||
"file-loader": "^4.1.0",
|
"file-loader": "^4.2.0",
|
||||||
"git-rev-sync": "^1.12.0",
|
"git-rev-sync": "^1.12.0",
|
||||||
"html-loader": "^0.5.5",
|
"html-loader": "^0.5.5",
|
||||||
"http_ece": "^1.1.0",
|
"http_ece": "^1.1.0",
|
||||||
"husky": "^3.0.2",
|
"husky": "^3.0.5",
|
||||||
"intl-pluralrules": "^1.0.3",
|
"intl-pluralrules": "^1.0.3",
|
||||||
"lint-staged": "^9.2.1",
|
"lint-staged": "^9.2.5",
|
||||||
"mocha": "^6.2.0",
|
"mocha": "^6.2.0",
|
||||||
"morgan": "^1.9.1",
|
"morgan": "^1.9.1",
|
||||||
"nanobus": "^4.4.0",
|
"nanobus": "^4.4.0",
|
||||||
"nanohtml": "^1.6.3",
|
"nanohtml": "^1.8.1",
|
||||||
"nanotiming": "^7.3.1",
|
"nanotiming": "^7.3.1",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"nyc": "^14.1.1",
|
"nyc": "^14.1.1",
|
||||||
"postcss-loader": "^3.0.0",
|
"postcss-loader": "^3.0.0",
|
||||||
"postcss-preset-env": "^6.7.0",
|
"postcss-preset-env": "^6.7.0",
|
||||||
"prettier": "^1.18.2",
|
"prettier": "^1.18.2",
|
||||||
"proxyquire": "^2.1.1",
|
"proxyquire": "^2.1.3",
|
||||||
"puppeteer": "^1.19.0",
|
"puppeteer": "^1.19.0",
|
||||||
"raven-js": "^3.27.2",
|
|
||||||
"raw-loader": "^3.1.0",
|
"raw-loader": "^3.1.0",
|
||||||
"redis-mock": "^0.45.0",
|
"redis-mock": "^0.46.0",
|
||||||
"rimraf": "^2.6.3",
|
"rimraf": "^3.0.0",
|
||||||
"script-loader": "^0.7.2",
|
"script-loader": "^0.7.2",
|
||||||
"sinon": "^7.3.2",
|
"sinon": "^7.4.2",
|
||||||
"string-hash": "^1.1.3",
|
"string-hash": "^1.1.3",
|
||||||
"stylelint": "^10.1.0",
|
"stylelint": "^10.1.0",
|
||||||
"stylelint-config-standard": "^18.3.0",
|
"stylelint-config-standard": "^18.3.0",
|
||||||
"stylelint-no-unsupported-browser-features": "^3.0.2",
|
"stylelint-no-unsupported-browser-features": "^3.0.2",
|
||||||
"svgo": "^1.3.0",
|
"svgo": "^1.3.0",
|
||||||
"svgo-loader": "^2.2.1",
|
"svgo-loader": "^2.2.1",
|
||||||
"tailwindcss": "^1.0.5",
|
"tailwindcss": "^1.1.2",
|
||||||
"val-loader": "^1.1.1",
|
"val-loader": "^1.1.1",
|
||||||
"wdio-docker-service": "^1.4.2",
|
"wdio-docker-service": "^1.4.2",
|
||||||
"wdio-dot-reporter": "0.0.10",
|
"wdio-dot-reporter": "0.0.10",
|
||||||
@@ -128,34 +130,34 @@
|
|||||||
"wdio-selenium-standalone-service": "0.0.12",
|
"wdio-selenium-standalone-service": "0.0.12",
|
||||||
"wdio-spec-reporter": "^0.1.5",
|
"wdio-spec-reporter": "^0.1.5",
|
||||||
"webdriverio": "^4.14.4",
|
"webdriverio": "^4.14.4",
|
||||||
"webpack": "^4.38.0",
|
"webpack": "4.38.0",
|
||||||
"webpack-cli": "^3.3.6",
|
"webpack-cli": "^3.3.8",
|
||||||
"webpack-dev-middleware": "^3.7.0",
|
"webpack-dev-middleware": "^3.7.1",
|
||||||
"webpack-dev-server": "^3.7.2",
|
"webpack-dev-server": "^3.8.0",
|
||||||
"webpack-manifest-plugin": "^2.0.4",
|
"webpack-manifest-plugin": "^2.0.4",
|
||||||
"webpack-unassert-loader": "^1.2.0"
|
"webpack-unassert-loader": "^1.2.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@google-cloud/storage": "^3.0.3",
|
"@dannycoates/express-ws": "^5.0.3",
|
||||||
"aws-sdk": "^2.502.0",
|
|
||||||
"body-parser": "^1.19.0",
|
|
||||||
"choo": "^6.13.3",
|
|
||||||
"cldr-core": "^35.1.0",
|
|
||||||
"convict": "^5.1.0",
|
|
||||||
"express": "^4.17.1",
|
|
||||||
"express-ws": "github:dannycoates/express-ws",
|
|
||||||
"@fluent/bundle": "^0.13.0",
|
"@fluent/bundle": "^0.13.0",
|
||||||
"@fluent/langneg": "^0.3.0",
|
"@fluent/langneg": "^0.3.0",
|
||||||
|
"@google-cloud/storage": "^3.2.1",
|
||||||
|
"@sentry/node": "^5.6.2",
|
||||||
|
"aws-sdk": "^2.524.0",
|
||||||
|
"body-parser": "^1.19.0",
|
||||||
|
"choo": "^7.0.0",
|
||||||
|
"cldr-core": "^35.1.0",
|
||||||
|
"configstore": "github:dannycoates/configstore#master",
|
||||||
|
"convict": "^5.1.0",
|
||||||
|
"express": "^4.17.1",
|
||||||
"fxa-geodb": "^1.0.4",
|
"fxa-geodb": "^1.0.4",
|
||||||
"helmet": "^3.20.0",
|
"helmet": "^3.21.0",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"mozlog": "^2.2.0",
|
"mozlog": "^2.2.0",
|
||||||
"node-fetch": "^2.6.0",
|
"node-fetch": "^2.6.0",
|
||||||
"raven": "^2.6.4",
|
|
||||||
"redis": "^2.8.0",
|
"redis": "^2.8.0",
|
||||||
"selenium-standalone": "^6.15.6",
|
"selenium-standalone": "^6.15.6",
|
||||||
"ua-parser-js": "^0.7.20",
|
"ua-parser-js": "^0.7.20"
|
||||||
"websocket-stream": "^5.5.0"
|
|
||||||
},
|
},
|
||||||
"availableLanguages": [
|
"availableLanguages": [
|
||||||
"en-US",
|
"en-US",
|
||||||
@@ -178,6 +180,7 @@
|
|||||||
"es-ES",
|
"es-ES",
|
||||||
"es-MX",
|
"es-MX",
|
||||||
"et",
|
"et",
|
||||||
|
"eu",
|
||||||
"fi",
|
"fi",
|
||||||
"fr",
|
"fr",
|
||||||
"fy-NL",
|
"fy-NL",
|
||||||
@@ -194,8 +197,10 @@
|
|||||||
"ko",
|
"ko",
|
||||||
"lt",
|
"lt",
|
||||||
"ml",
|
"ml",
|
||||||
|
"nb-NO",
|
||||||
"nl",
|
"nl",
|
||||||
"nn-NO",
|
"nn-NO",
|
||||||
|
"oc",
|
||||||
"pa-IN",
|
"pa-IN",
|
||||||
"pl",
|
"pl",
|
||||||
"pt-BR",
|
"pt-BR",
|
||||||
|
|||||||
@@ -182,3 +182,4 @@ shareLinkDescription = شارِك الرابط الذي يصل إلى الملف
|
|||||||
shareLinkButton = شارِك الرابط
|
shareLinkButton = شارِك الرابط
|
||||||
# $name is the name of the file
|
# $name is the name of the file
|
||||||
shareMessage = نزِّل ”{ $name }“ عبر { -send-brand }: خدمة لمشاركة الملفات بلا عناء وبخصوصية تامة
|
shareMessage = نزِّل ”{ $name }“ عبر { -send-brand }: خدمة لمشاركة الملفات بلا عناء وبخصوصية تامة
|
||||||
|
learnMore = اطّلع على المزيد.
|
||||||
|
|||||||
@@ -196,5 +196,5 @@ shareLinkDescription = Sdílet odkaz na soubor:
|
|||||||
shareLinkButton = Sdílet odkaz
|
shareLinkButton = Sdílet odkaz
|
||||||
# $name is the name of the file
|
# $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ů
|
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.
|
learnMore = Zjistit více.
|
||||||
|
|||||||
@@ -151,3 +151,5 @@ shareLinkDescription = Del linket til din fil:
|
|||||||
shareLinkButton = Del link
|
shareLinkButton = Del link
|
||||||
# $name is the name of the file
|
# $name is the name of the file
|
||||||
shareMessage = Hent { $name } med { -send-brand } - simpel og sikker fildeling
|
shareMessage = Hent { $name } med { -send-brand } - simpel og sikker fildeling
|
||||||
|
trailheadPromo = Beskyt dine digitale rettigheder. Slut dig til Firefox.
|
||||||
|
learnMore = Læs mere.
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ addPassword = Protegido con contraseña
|
|||||||
emailPlaceholder = Ingresa tu correo electrónico
|
emailPlaceholder = Ingresa tu correo electrónico
|
||||||
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
|
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
|
||||||
signInSizeBump = Iniciar sesión para enviar hasta { $size }
|
signInSizeBump = Iniciar sesión para enviar hasta { $size }
|
||||||
signInButton = Iniciar sesión/registrarse
|
signInOnlyButton = Iniciar sesión
|
||||||
accountBenefitTitle = Crear una cuenta de { -firefox } o iniciar sesión
|
accountBenefitTitle = Crear una cuenta de { -firefox } o iniciar sesión
|
||||||
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
|
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
|
||||||
accountBenefitLargeFiles = Compartir archivos de hasta { $size }
|
accountBenefitLargeFiles = Compartir archivos de hasta { $size }
|
||||||
@@ -145,3 +145,11 @@ noStreamsWarning = Puede que este navegador no pueda descifrar un archivo tan gr
|
|||||||
noStreamsOptionCopy = Copiar el enlace para abrir en otro navegador
|
noStreamsOptionCopy = Copiar el enlace para abrir en otro navegador
|
||||||
noStreamsOptionFirefox = Prueba nuestro navegador favorito
|
noStreamsOptionFirefox = Prueba nuestro navegador favorito
|
||||||
noStreamsOptionDownload = Continuar con este navegador
|
noStreamsOptionDownload = Continuar con este navegador
|
||||||
|
downloadFirefoxPromo = { -send-short-brand } te lo ofrece el nuevo { -firefox }.
|
||||||
|
# the next line after the colon contains a file name
|
||||||
|
shareLinkDescription = Comparte el enlace a tu archivo:
|
||||||
|
shareLinkButton = Enlace para compartir
|
||||||
|
# $name is the name of the file
|
||||||
|
shareMessage = Descarga «{ $name }» con { -send-brand }: es sencillo y seguro
|
||||||
|
trailheadPromo = Existe una forma de proteger tu privacidad. Únete a Firefox.
|
||||||
|
learnMore = Saber más.
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ fileSizeProgress = ({ $totalSize } / { $partialSize })
|
|||||||
sendYourFilesLink = Probatu Firefox Send
|
sendYourFilesLink = Probatu Firefox Send
|
||||||
errorPageHeader = Zerbait gaizki joan da!
|
errorPageHeader = Zerbait gaizki joan da!
|
||||||
fileTooBig = Fitxategia handiegia da kargatzeko. { $size } baino txikiagoa izan behar du.
|
fileTooBig = Fitxategia handiegia da kargatzeko. { $size } baino txikiagoa izan behar du.
|
||||||
linkExpiredAlt = Lotura iraungita
|
linkExpiredAlt = Lotura iraungi da
|
||||||
notSupportedHeader = Zure nabigatzailea ez da onartzen.
|
notSupportedHeader = Zure nabigatzailea ez da onartzen.
|
||||||
notSupportedLink = Zergatik ez da nire nabigatzailea 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.
|
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
|
-firefox = Firefox
|
||||||
-mozilla = Mozilla
|
-mozilla = Mozilla
|
||||||
introTitle = Partekatu fitxategiak modu sinple eta pribatuan
|
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
|
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
|
# byte abbreviation
|
||||||
bytes = B
|
bytes = B
|
||||||
# kibibyte abbreviation
|
# kibibyte abbreviation
|
||||||
@@ -65,9 +88,33 @@ mb = MB
|
|||||||
gb = GB
|
gb = GB
|
||||||
# localized number and byte abbreviation. example "2.5MB"
|
# localized number and byte abbreviation. example "2.5MB"
|
||||||
fileSize = { $num }{ $units }
|
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
|
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 }
|
downloadFirefox = Deskargatu { -firefox }
|
||||||
|
legalTitle = { -send-short-brand } pribatutasun-oharra
|
||||||
legalDateStamp = 1.0 bertsioa, 2019ko martxoaren 12koa.
|
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
|
addFilesButton = Hautatu igotzeko fitxategiak
|
||||||
uploadButton = Igo
|
uploadButton = Igo
|
||||||
# the first part of the string 'Drag and drop files or click to send up to 1GB'
|
# 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
|
orClickWithSize = edo egin klik { $size } arte igotzeko
|
||||||
addPassword = Babestu pasahitzarekin
|
addPassword = Babestu pasahitzarekin
|
||||||
emailPlaceholder = Idatzi zure helbide elektronikoa
|
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
|
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")
|
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
|
||||||
accountBenefitLargeFiles = Partekatu { $size } arteko fitxategiak
|
accountBenefitLargeFiles = Partekatu { $size } arteko fitxategiak
|
||||||
accountBenefitDownloadCount = Partekatu fitxategiak jende gehiagorekin
|
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.
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ decryptingFile = מתבצע פענוח...
|
|||||||
downloadCount =
|
downloadCount =
|
||||||
{ $num ->
|
{ $num ->
|
||||||
[one] הורדה אחת
|
[one] הורדה אחת
|
||||||
*[other] { $number } הורדות
|
*[other] { $num } הורדות
|
||||||
}
|
}
|
||||||
timespanHours =
|
timespanHours =
|
||||||
{ $num ->
|
{ $num ->
|
||||||
[one] שעה אחת
|
[one] שעה אחת
|
||||||
[two] שעתיים
|
[two] שעתיים
|
||||||
*[other] { $number } שעות
|
*[other] { $num } שעות
|
||||||
}
|
}
|
||||||
copiedUrl = הועתק!
|
copiedUrl = הועתק!
|
||||||
unlockInputPlaceholder = ססמה
|
unlockInputPlaceholder = ססמה
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ dragAndDropFiles = Traher e deponer files
|
|||||||
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
|
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
|
||||||
orClickWithSize = o cliccar pro inviar usque { $size }
|
orClickWithSize = o cliccar pro inviar usque { $size }
|
||||||
addPassword = Proteger per contrasigno
|
addPassword = Proteger per contrasigno
|
||||||
emailPlaceholder = Insere tu adresse email
|
emailPlaceholder = Insere tu adresse de e-mail
|
||||||
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
|
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
|
||||||
signInSizeBump = Accede pro inviar usque { $size }
|
signInSizeBump = Accede pro inviar usque { $size }
|
||||||
signInOnlyButton = Authentica te
|
signInOnlyButton = Authentica te
|
||||||
|
|||||||
@@ -140,4 +140,5 @@ shareLinkDescription = ファイルへのリンクを共有しましょう:
|
|||||||
shareLinkButton = リンクを共有
|
shareLinkButton = リンクを共有
|
||||||
# $name is the name of the file
|
# $name is the name of the file
|
||||||
shareMessage = { -send-brand } で "{ $name }" をダウンロード: シンプルで安全なファイル共有
|
shareMessage = { -send-brand } で "{ $name }" をダウンロード: シンプルで安全なファイル共有
|
||||||
|
trailheadPromo = プライバシーを保護する方法があります。Firefox を試してください。
|
||||||
learnMore = 詳細情報
|
learnMore = 詳細情報
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ passwordSetError = Dette passordet kunne ikke settes
|
|||||||
-firefox = Firefox
|
-firefox = Firefox
|
||||||
-mozilla = Mozilla
|
-mozilla = Mozilla
|
||||||
introTitle = Enkel, privat fildeling
|
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
|
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'
|
# 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 }
|
archiveExpiryInfo = Utløper etter { $downloadCount } eller { $timespan }
|
||||||
@@ -77,9 +78,78 @@ fileCount =
|
|||||||
[one] 1 fil
|
[one] 1 fil
|
||||||
*[other] { $num } filer
|
*[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 }
|
totalSize = Total størrelse: { $size }
|
||||||
# the next line after the colon contains a file name
|
# the next line after the colon contains a file name
|
||||||
copyLinkDescription = Kopier lenken for å dele filen din:
|
copyLinkDescription = Kopier lenken for å dele filen din:
|
||||||
copyLinkButton = Kopier lenke
|
copyLinkButton = Kopier lenke
|
||||||
downloadTitle = Last ned filer
|
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
155
public/locales/oc/send.ftl
Normal 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 l’enviar. 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 qu’expira 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 qu’expira 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 qu’enviar 1 fichièr al còp.
|
||||||
|
*[other] Òm pòt pas qu’enviar { $count } fichièrs al còp.
|
||||||
|
}
|
||||||
|
# count will always be > 10
|
||||||
|
tooManyArchives =
|
||||||
|
{ $count ->
|
||||||
|
[one] Pas qu’un 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 qu’aqueste 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.
|
||||||
@@ -151,3 +151,5 @@ shareLinkDescription = ਆਪਣੀ ਫਾਇਲ ਲਈ ਲਿੰਕ ਸਾਂ
|
|||||||
shareLinkButton = ਲਿੰਕ ਸਾਂਝਾ ਕਰੋ
|
shareLinkButton = ਲਿੰਕ ਸਾਂਝਾ ਕਰੋ
|
||||||
# $name is the name of the file
|
# $name is the name of the file
|
||||||
shareMessage = { -send-brand } ਨਾਲ "{ $name }" ਡਾਊਨਲੋਡ ਕਰੋ: ਸੌਖਾ, ਸੁਰੱਖਿਅਤ ਫਾਇਲ ਸਾਂਝਾ ਕਰਨਾ
|
shareMessage = { -send-brand } ਨਾਲ "{ $name }" ਡਾਊਨਲੋਡ ਕਰੋ: ਸੌਖਾ, ਸੁਰੱਖਿਅਤ ਫਾਇਲ ਸਾਂਝਾ ਕਰਨਾ
|
||||||
|
trailheadPromo = ਤੁਹਾਡੀ ਪਰਦੇਦਾਰੀ ਦੀ ਸੁਰੱਖਿਆ ਦਾ ਢੰਗ ਹੈ। ਫਾਇਰਫਾਕਸ ਨਾਲ ਜੁੜੋ।
|
||||||
|
learnMore = ਹੋਰ ਸਿੱਖੋ
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ passwordSetError = Essa senha não pôde ser definida
|
|||||||
-firefox = Firefox
|
-firefox = Firefox
|
||||||
-mozilla = Mozilla
|
-mozilla = Mozilla
|
||||||
introTitle = Compartilhamento de arquivos fácil e privativo
|
introTitle = Compartilhamento de arquivos fácil e privativo
|
||||||
introDescription = O { -send-brand } permite compartilhar arquivos com criptografia ponto a ponto e um link que expira automaticamente. Assim você pode manter o que compartilha privativo e ter certeza que suas coisas não ficarão online para sempre.
|
introDescription = O { -send-brand } permite compartilhar arquivos com criptografia de ponta a ponta e um link que expira automaticamente. Assim você pode manter o que compartilha privativo e ter certeza que suas coisas não ficarão online para sempre.
|
||||||
notifyUploadEncryptDone = Seu arquivo foi criptografado e está pronto para ser enviado
|
notifyUploadEncryptDone = Seu arquivo foi criptografado e está pronto para ser enviado
|
||||||
# downloadCount is from the downloadCount string and timespan is a timespanMinutes string. ex. 'Expires after 2 downloads or 25 minutes'
|
# downloadCount is from the downloadCount string and timespan is a timespanMinutes string. ex. 'Expires after 2 downloads or 25 minutes'
|
||||||
archiveExpiryInfo = Expirar após { $downloadCount } ou { $timespan }
|
archiveExpiryInfo = Expirar após { $downloadCount } ou { $timespan }
|
||||||
@@ -94,7 +94,7 @@ totalSize = Tamanho total: { $size }
|
|||||||
copyLinkDescription = Copie o link para compartilhar seu arquivo:
|
copyLinkDescription = Copie o link para compartilhar seu arquivo:
|
||||||
copyLinkButton = Copiar link
|
copyLinkButton = Copiar link
|
||||||
downloadTitle = Baixar arquivos
|
downloadTitle = Baixar arquivos
|
||||||
downloadDescription = Este arquivo foi compartilhado via { -send-brand } com criptografia ponto a ponto e um link que expira automaticamente.
|
downloadDescription = Este arquivo foi compartilhado via { -send-brand } com criptografia de ponta a ponta e um link que expira automaticamente.
|
||||||
trySendDescription = Experimente o { -send-brand } para compartilhamento de arquivos simples e seguro.
|
trySendDescription = Experimente o { -send-brand } para compartilhamento de arquivos simples e seguro.
|
||||||
# count will always be > 10
|
# count will always be > 10
|
||||||
tooManyFiles =
|
tooManyFiles =
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ totalSize = మొత్తం పరిమాణం: { $size }
|
|||||||
copyLinkDescription = మీ ఫైలును భాగస్వామ్యం చేయడానికి ఈ లంకెను నకలు చేయండి:
|
copyLinkDescription = మీ ఫైలును భాగస్వామ్యం చేయడానికి ఈ లంకెను నకలు చేయండి:
|
||||||
copyLinkButton = లంకెను నకలుతీయి
|
copyLinkButton = లంకెను నకలుతీయి
|
||||||
downloadTitle = ఫైళ్లను దింపుకోండి
|
downloadTitle = ఫైళ్లను దింపుకోండి
|
||||||
|
expiredTitle = ఈ లంకె గడువు ముగిసింది.
|
||||||
downloadFirefox = { -firefox } ను దింపుకోండి
|
downloadFirefox = { -firefox } ను దింపుకోండి
|
||||||
legalTitle = { -send-short-brand } గోప్యతా నోటీసు
|
legalTitle = { -send-short-brand } గోప్యతా నోటీసు
|
||||||
legalDateStamp = వెర్షన్ 1.0, మార్చి 12, 2019 నాటిది
|
legalDateStamp = వెర్షన్ 1.0, మార్చి 12, 2019 నాటిది
|
||||||
@@ -96,6 +97,11 @@ legalDateStamp = వెర్షన్ 1.0, మార్చి 12, 2019 నా
|
|||||||
expiresDaysHoursMinutes = { $days }d { $hours }h { $minutes }m
|
expiresDaysHoursMinutes = { $days }d { $hours }h { $minutes }m
|
||||||
addFilesButton = ఎక్కించడానికి ఫైళ్ళను ఎంచుకోండి
|
addFilesButton = ఎక్కించడానికి ఫైళ్ళను ఎంచుకోండి
|
||||||
uploadButton = ఎక్కించు
|
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 = సంకేతపదంతో రక్షించండి
|
addPassword = సంకేతపదంతో రక్షించండి
|
||||||
emailPlaceholder = ఈ ఈమెయిలును ఇవ్వండి
|
emailPlaceholder = ఈ ఈమెయిలును ఇవ్వండి
|
||||||
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
|
# $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")
|
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
|
||||||
accountBenefitLargeFiles = { $size } పరిమాణం ఫైళ్ళ వరకు పంచుకోండి
|
accountBenefitLargeFiles = { $size } పరిమాణం ఫైళ్ళ వరకు పంచుకోండి
|
||||||
accountBenefitDownloadCount = ఫైళ్లను ఎక్కువ మందితో పంచుకోండి
|
accountBenefitDownloadCount = ఫైళ్లను ఎక్కువ మందితో పంచుకోండి
|
||||||
|
accountBenefitSync = ఏదైనా పరికరం నుండి పంచుకున్న ఫైళ్ళను నిర్వహించండి
|
||||||
signOut = నిష్క్రమించు
|
signOut = నిష్క్రమించు
|
||||||
okButton = సరే
|
okButton = సరే
|
||||||
downloadingTitle = దింపుకుంటోంది
|
downloadingTitle = దింపుకుంటోంది
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ totalSize = Tổng kích thước: { $size }
|
|||||||
# the next line after the colon contains a file name
|
# the next line after the colon contains a file name
|
||||||
copyLinkDescription = Sao chép liên kết để chia sẻ tập tin của bạn:
|
copyLinkDescription = Sao chép liên kết để chia sẻ tập tin của bạn:
|
||||||
copyLinkButton = Sao chép liên kết
|
copyLinkButton = Sao chép liên kết
|
||||||
downloadTitle = Tải tập tin
|
downloadTitle = Tải xuống tập tin
|
||||||
downloadDescription = Tập tin này đã được chia sẻ qua { -send-brand } với mã hóa đầu cuối và liên kết tự động hết hạn.
|
downloadDescription = Tập tin này đã được chia sẻ qua { -send-brand } với mã hóa đầu cuối và liên kết tự động hết hạn.
|
||||||
trySendDescription = Hãy thử { -send-brand } để chia sẻ tập tin đơn giản, an toàn.
|
trySendDescription = Hãy thử { -send-brand } để chia sẻ tập tin đơn giản, an toàn.
|
||||||
# count will always be > 10
|
# count will always be > 10
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ exec(cmd)
|
|||||||
const locales = Object.keys(summary)
|
const locales = Object.keys(summary)
|
||||||
.filter(locale => {
|
.filter(locale => {
|
||||||
const loc = summary[locale];
|
const loc = summary[locale];
|
||||||
const hasMissing = loc.hasOwnProperty('missing');
|
const hasMissing = Object.prototype.hasOwnProperty.call(loc, 'missing');
|
||||||
const hasErrors = loc.hasOwnProperty('errors');
|
const hasErrors = Object.prototype.hasOwnProperty.call(loc, 'errors');
|
||||||
return !hasMissing && !hasErrors;
|
return !hasMissing && !hasErrors;
|
||||||
})
|
})
|
||||||
.sort();
|
.sort();
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ function filterErrors(details) {
|
|||||||
.sort()
|
.sort()
|
||||||
.map(locale => {
|
.map(locale => {
|
||||||
const data = details[locale]
|
const data = details[locale]
|
||||||
.filter(item => item.hasOwnProperty('error'))
|
.filter(item => Object.prototype.hasOwnProperty.call(item, 'error'))
|
||||||
.map(({ error }) => error);
|
.map(({ error }) => error);
|
||||||
return { locale, data };
|
return { locale, data };
|
||||||
})
|
})
|
||||||
|
|||||||
13
scripts/sync-npm-dependencies.sh
Executable file
13
scripts/sync-npm-dependencies.sh
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "checking package-lock.json for changes"
|
||||||
|
IFS=' '
|
||||||
|
read -ra G_PARAMS <<< "$HUSKY_GIT_PARAMS"
|
||||||
|
PREV=${G_PARAMS[0]}
|
||||||
|
NEXT=${G_PARAMS[1]}
|
||||||
|
if [ "$PREV" != "$NEXT" ]; then
|
||||||
|
DIFF=$(git diff $PREV $NEXT package-lock.json)
|
||||||
|
if [ "$DIFF" != "" ]; then
|
||||||
|
npm install
|
||||||
|
fi
|
||||||
|
fi
|
||||||
@@ -3,7 +3,7 @@ const routes = require('../routes');
|
|||||||
const pages = require('../routes/pages');
|
const pages = require('../routes/pages');
|
||||||
const tests = require('../../test/frontend/routes');
|
const tests = require('../../test/frontend/routes');
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const expressWs = require('express-ws');
|
const expressWs = require('@dannycoates/express-ws');
|
||||||
const morgan = require('morgan');
|
const morgan = require('morgan');
|
||||||
const config = require('../config');
|
const config = require('../config');
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const Raven = require('raven');
|
const Sentry = require('@sentry/node');
|
||||||
const config = require('../config');
|
const config = require('../config');
|
||||||
const routes = require('../routes');
|
const routes = require('../routes');
|
||||||
const pages = require('../routes/pages');
|
const pages = require('../routes/pages');
|
||||||
const expressWs = require('express-ws');
|
const expressWs = require('@dannycoates/express-ws');
|
||||||
|
|
||||||
if (config.sentry_dsn) {
|
if (config.sentry_dsn) {
|
||||||
Raven.config(config.sentry_dsn).install();
|
Sentry.init({ dsn: config.sentry_dsn });
|
||||||
}
|
}
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ const assets = require('../../common/assets');
|
|||||||
const routes = require('../routes');
|
const routes = require('../routes');
|
||||||
const pages = require('../routes/pages');
|
const pages = require('../routes/pages');
|
||||||
const tests = require('../../test/frontend/routes');
|
const tests = require('../../test/frontend/routes');
|
||||||
const expressWs = require('express-ws');
|
const expressWs = require('@dannycoates/express-ws');
|
||||||
|
|
||||||
module.exports = function(app, devServer) {
|
module.exports = function(app, devServer) {
|
||||||
assets.setMiddleware(devServer.middleware);
|
assets.setMiddleware(devServer.middleware);
|
||||||
|
|||||||
@@ -8,12 +8,10 @@ if (config.sentry_id) {
|
|||||||
//eslint-disable-next-line node/no-missing-require
|
//eslint-disable-next-line node/no-missing-require
|
||||||
const version = require('../dist/version.json');
|
const version = require('../dist/version.json');
|
||||||
sentry = `
|
sentry = `
|
||||||
var RAVEN_CONFIG = {
|
var SENTRY_CONFIG = {
|
||||||
|
dsn: '${config.sentry_id}',
|
||||||
release: '${version.version}',
|
release: '${version.version}',
|
||||||
tags: {
|
beforeSend: function (data) {
|
||||||
commit: '${version.commit}'
|
|
||||||
},
|
|
||||||
dataCallback: function (data) {
|
|
||||||
var hash = window.location.hash;
|
var hash = window.location.hash;
|
||||||
if (hash) {
|
if (hash) {
|
||||||
return JSON.parse(JSON.stringify(data).replace(new RegExp(hash.slice(1), 'g'), ''));
|
return JSON.parse(JSON.stringify(data).replace(new RegExp(hash.slice(1), 'g'), ''));
|
||||||
@@ -21,7 +19,6 @@ var RAVEN_CONFIG = {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var SENTRY_ID = '${config.sentry_id}';
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,10 @@ module.exports = function(app) {
|
|||||||
}
|
}
|
||||||
app.use(function(req, res, next) {
|
app.use(function(req, res, next) {
|
||||||
res.set('Pragma', 'no-cache');
|
res.set('Pragma', 'no-cache');
|
||||||
res.set('Cache-Control', 'no-cache');
|
res.set(
|
||||||
|
'Cache-Control',
|
||||||
|
'private, no-cache, no-store, must-revalidate, max-age=0'
|
||||||
|
);
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
|
|||||||
@@ -3,12 +3,11 @@ const storage = require('../storage');
|
|||||||
const config = require('../config');
|
const config = require('../config');
|
||||||
const mozlog = require('../log');
|
const mozlog = require('../log');
|
||||||
const Limiter = require('../limiter');
|
const Limiter = require('../limiter');
|
||||||
const wsStream = require('websocket-stream/stream');
|
|
||||||
const fxa = require('../fxa');
|
const fxa = require('../fxa');
|
||||||
const { statUploadEvent } = require('../amplitude');
|
const { statUploadEvent } = require('../amplitude');
|
||||||
const { encryptedSize } = require('../../app/utils');
|
const { encryptedSize } = require('../../app/utils');
|
||||||
|
|
||||||
const { Duplex } = require('stream');
|
const { Transform } = require('stream');
|
||||||
|
|
||||||
const log = mozlog('send.upload');
|
const log = mozlog('send.upload');
|
||||||
|
|
||||||
@@ -76,25 +75,19 @@ module.exports = function(ws, req) {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
const limiter = new Limiter(encryptedSize(maxFileSize));
|
const limiter = new Limiter(encryptedSize(maxFileSize));
|
||||||
const flowControl = new Duplex({
|
const eof = new Transform({
|
||||||
read() {
|
transform: function(chunk, encoding, callback) {
|
||||||
ws.resume();
|
|
||||||
},
|
|
||||||
write(chunk, encoding, callback) {
|
|
||||||
if (chunk.length === 1 && chunk[0] === 0) {
|
if (chunk.length === 1 && chunk[0] === 0) {
|
||||||
this.push(null);
|
this.push(null);
|
||||||
} else {
|
} else {
|
||||||
if (!this.push(chunk)) {
|
this.push(chunk);
|
||||||
ws.pause();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const wsStream = ws.constructor.createWebSocketStream(ws);
|
||||||
|
|
||||||
fileStream = wsStream(ws, { binary: true })
|
fileStream = wsStream.pipe(eof).pipe(limiter); // limiter needs to be the last in the chain
|
||||||
.pipe(flowControl)
|
|
||||||
.pipe(limiter); // limiter needs to be the last in the chain
|
|
||||||
|
|
||||||
await storage.set(newId, fileStream, meta, timeLimit);
|
await storage.set(newId, fileStream, meta, timeLimit);
|
||||||
|
|
||||||
@@ -126,8 +119,8 @@ module.exports = function(ws, req) {
|
|||||||
error: e === 'limit' ? 413 : 500
|
error: e === 'limit' ? 413 : 500
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
ws.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ws.close();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class GCSStorage {
|
|||||||
.pipe(
|
.pipe(
|
||||||
this.bucket.file(id).createWriteStream({
|
this.bucket.file(id).createWriteStream({
|
||||||
validation: false,
|
validation: false,
|
||||||
resumable: false
|
resumable: true
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.on('error', reject)
|
.on('error', reject)
|
||||||
|
|||||||
@@ -19,5 +19,7 @@ rules:
|
|||||||
mocha/no-pending-tests: error
|
mocha/no-pending-tests: error
|
||||||
mocha/no-return-and-callback: warn
|
mocha/no-return-and-callback: warn
|
||||||
mocha/no-skipped-tests: error
|
mocha/no-skipped-tests: error
|
||||||
|
mocha/no-setup-in-describe: off
|
||||||
|
mocha/no-hooks-for-single-case: off
|
||||||
|
|
||||||
no-console: off # ¯\_(ツ)_/¯
|
no-console: off # ¯\_(ツ)_/¯
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ module.exports = {
|
|||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const middleware = require('webpack-dev-middleware');
|
const middleware = require('webpack-dev-middleware');
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const expressWs = require('express-ws');
|
const expressWs = require('@dannycoates/express-ws');
|
||||||
const assets = require('../common/assets');
|
const assets = require('../common/assets');
|
||||||
const routes = require('../server/routes');
|
const routes = require('../server/routes');
|
||||||
const tests = require('./frontend/routes');
|
const tests = require('./frontend/routes');
|
||||||
@@ -18,8 +18,8 @@ module.exports = {
|
|||||||
app.use(wpm);
|
app.use(wpm);
|
||||||
assets.setMiddleware(wpm);
|
assets.setMiddleware(wpm);
|
||||||
expressWs(app, null, { perMessageDeflate: false });
|
expressWs(app, null, { perMessageDeflate: false });
|
||||||
app.ws('/api/ws', require('../server/routes/ws'));
|
|
||||||
routes(app);
|
routes(app);
|
||||||
|
app.ws('/api/ws', require('../server/routes/ws'));
|
||||||
tests(app);
|
tests(app);
|
||||||
wpm.waitUntilValid(() => {
|
wpm.waitUntilValid(() => {
|
||||||
server = app.listen(8000, resolve);
|
server = app.listen(8000, resolve);
|
||||||
|
|||||||
@@ -114,6 +114,7 @@ const web = {
|
|||||||
exclude: [
|
exclude: [
|
||||||
path.resolve(__dirname, 'node_modules/crc'),
|
path.resolve(__dirname, 'node_modules/crc'),
|
||||||
path.resolve(__dirname, 'node_modules/@fluent'),
|
path.resolve(__dirname, 'node_modules/@fluent'),
|
||||||
|
path.resolve(__dirname, 'node_modules/@sentry'),
|
||||||
path.resolve(__dirname, 'node_modules/tslib'),
|
path.resolve(__dirname, 'node_modules/tslib'),
|
||||||
path.resolve(__dirname, 'node_modules/webcrypto-core')
|
path.resolve(__dirname, 'node_modules/webcrypto-core')
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user