mirror of
https://gitlab.com/timvisee/send.git
synced 2025-12-10 04:05:34 +00:00
Compare commits
76 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dbe374bdc6 | ||
|
|
48ab1cdd4e | ||
|
|
54150702da | ||
|
|
981f86946b | ||
|
|
b5865f00e9 | ||
|
|
7797f485f2 | ||
|
|
db169cb9f0 | ||
|
|
f999c4c44f | ||
|
|
e9b50b7682 | ||
|
|
a3e8646ea7 | ||
|
|
a6a3cae5e9 | ||
|
|
8d80ba1f69 | ||
|
|
e5f76a7b1f | ||
|
|
acf82a4e3e | ||
|
|
0acdf3a720 | ||
|
|
305dd2f5ef | ||
|
|
e53571e219 | ||
|
|
0eda8d2082 | ||
|
|
1cd4adfc2a | ||
|
|
0460bd2e97 | ||
|
|
60146541f2 | ||
|
|
79d314146b | ||
|
|
72d12c3d80 | ||
|
|
1469464c43 | ||
|
|
7cdef4bbfc | ||
|
|
24aa1f2e17 | ||
|
|
7a4a4fc849 | ||
|
|
97be1737cb | ||
|
|
ba33e022b0 | ||
|
|
0d6b3731ef | ||
|
|
0be4a65904 | ||
|
|
54c182ab0d | ||
|
|
b2e9907551 | ||
|
|
3b4a4d82e8 | ||
|
|
5747f55876 | ||
|
|
636a239e86 | ||
|
|
f9a1583078 | ||
|
|
0dfbe3566a | ||
|
|
98b84ba05f | ||
|
|
4ad4a65924 | ||
|
|
6e07ecf643 | ||
|
|
a39cfaf3d3 | ||
|
|
97e3d78ba8 | ||
|
|
28c48f51d1 | ||
|
|
239fba452a | ||
|
|
3631bc8f39 | ||
|
|
189f4cfb9b | ||
|
|
deb2d41de8 | ||
|
|
ab53f9cf3e | ||
|
|
facb61a9b5 | ||
|
|
d8ac413064 | ||
|
|
e0f51c7fde | ||
|
|
c44c4ba41c | ||
|
|
4e9625ef36 | ||
|
|
4413fc75a3 | ||
|
|
d13fda1419 | ||
|
|
7f7ba0e33f | ||
|
|
86c5553f58 | ||
|
|
7e173ec23d | ||
|
|
3ae6f9bd5a | ||
|
|
b5ef1785ab | ||
|
|
4b1b7cb821 | ||
|
|
b0b75f5daa | ||
|
|
e2562aec17 | ||
|
|
f64e772145 | ||
|
|
bc0ccc8e5d | ||
|
|
e909a3bae8 | ||
|
|
abc58518ea | ||
|
|
4f273eca03 | ||
|
|
b15c017dcd | ||
|
|
bfaac8f66d | ||
|
|
4ffc65274b | ||
|
|
1d492cd0df | ||
|
|
b4594c5280 | ||
|
|
aa47df79f9 | ||
|
|
7533ab1930 |
@@ -4,4 +4,5 @@ firefox
|
|||||||
coverage
|
coverage
|
||||||
android/app/build
|
android/app/build
|
||||||
app/locale.js
|
app/locale.js
|
||||||
app/capabilities.js
|
app/capabilities.js
|
||||||
|
app/qrcode.js
|
||||||
@@ -16,13 +16,12 @@ RUN set -x \
|
|||||||
--home /app \
|
--home /app \
|
||||||
--uid 10001 \
|
--uid 10001 \
|
||||||
app
|
app
|
||||||
RUN npm i -g npm
|
|
||||||
COPY --chown=app:app . /app
|
COPY --chown=app:app . /app
|
||||||
USER app
|
USER app
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN set -x \
|
RUN set -x \
|
||||||
# Build
|
# Build
|
||||||
&& npm ci \
|
&& PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true npm ci \
|
||||||
&& npm run build
|
&& npm run build
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
56
README.md
56
README.md
@@ -1,7 +1,57 @@
|
|||||||
# [](https://gitlab.com/timvisee/send/) Send
|
# [](https://gitlab.com/timvisee/send/) Send
|
||||||
|
|
||||||
Based on Mozilla's [Firefox Send](https://github.com/mozilla/send),
|
[![Build status on GitLab CI][gitlab-ci-master-badge]][gitlab-ci-link]
|
||||||
with branding removed.
|
[![Latest release][release-badge]][release-link]
|
||||||
|
[![Docker image][docker-image-badge]][docker-image-link]
|
||||||
|
[![Project license][repo-license-badge]](LICENSE)
|
||||||
|
|
||||||
|
[docker-image-badge]: https://img.shields.io/badge/docker-latest-blue.svg
|
||||||
|
[docker-image-link]: https://gitlab.com/timvisee/send/container_registry/eyJuYW1lIjoidGltdmlzZWUvc2VuZCIsInRhZ3NfcGF0aCI6Ii90aW12aXNlZS9zZW5kL3JlZ2lzdHJ5L3JlcG9zaXRvcnkvMTQxODUwNC90YWdzP2Zvcm1hdD1qc29uIiwiaWQiOjE0MTg1MDQsImNsZWFudXBfcG9saWN5X3N0YXJ0ZWRfYXQiOm51bGx9
|
||||||
|
[gitlab-ci-link]: https://gitlab.com/timvisee/send/pipelines
|
||||||
|
[gitlab-ci-master-badge]: https://gitlab.com/timvisee/send/badges/master/pipeline.svg
|
||||||
|
[release-badge]: https://img.shields.io/github/v/tag/timvisee/send
|
||||||
|
[release-link]: https://gitlab.com/timvisee/send/-/
|
||||||
|
[repo-license-badge]: https://img.shields.io/github/license/timvisee/send.svg
|
||||||
|
|
||||||
|
A fork of Mozilla's [Firefox Send][mozilla-send].
|
||||||
|
Mozilla discontinued Send, this fork is a community effort to keep the project
|
||||||
|
up-to-date and alive.
|
||||||
|
|
||||||
|
- Forked [at][fork-commit] Mozilla's last publicly hosted version
|
||||||
|
- _Mozilla_ & _Firefox_ branding [is][remove-branding-pr] removed so you can legally self-host
|
||||||
|
- Kept compatible with [`ffsend`][ffsend] (CLI for Send)
|
||||||
|
- Dependencies have been updated
|
||||||
|
- Mozilla's [changes][mozilla-patches] since the fork have been selectively [merged][mozilla-patches-pr]
|
||||||
|
- Mozilla's experimental report feature, download tokens, trust warnings and FxA changes are not included
|
||||||
|
|
||||||
|
Find an up-to-date Docker image here: [docs/docker.md](docs/docker.md)
|
||||||
|
|
||||||
|
The original project by Mozilla can be found [here][mozilla-send].
|
||||||
|
The [`mozilla-master`][branch-mozilla-master] branch holds the `master` branch
|
||||||
|
as left by Mozilla.
|
||||||
|
The [`send-v3`][branch-send-v3] branch holds the commit tree of Mozilla's last
|
||||||
|
publicly hosted version, which this fork is based on.
|
||||||
|
The [`send-v4`][branch-send-v4] branch holds the commit tree of Mozilla's last
|
||||||
|
experimental version which was still a work in progress (featuring file
|
||||||
|
reporting, download tokens, trust warnings and FxA changes), this has
|
||||||
|
selectively been merged into this fork.
|
||||||
|
Please consider to [donate][donate] to allow me to keep working on this.
|
||||||
|
|
||||||
|
Thanks [Mozilla][mozilla] for building this amazing tool!
|
||||||
|
|
||||||
|
[branch-mozilla-master]: https://gitlab.com/timvisee/send/-/tree/mozilla-master
|
||||||
|
[branch-send-v3]: https://gitlab.com/timvisee/send/-/tree/send-v3
|
||||||
|
[branch-send-v4]: https://gitlab.com/timvisee/send/-/tree/send-v4
|
||||||
|
[donate]: https://timvisee.com/donate
|
||||||
|
[ffsend]: https://github.com/timvisee/ffsend
|
||||||
|
[fork-commit]: https://gitlab.com/timvisee/send/-/commit/3e9be676413a6e1baaf6a354c180e91899d10bec
|
||||||
|
[mozilla-patches-pr]: https://gitlab.com/timvisee/send/-/merge_requests/3
|
||||||
|
[mozilla-patches]: https://gitlab.com/timvisee/send/-/compare/3e9be676413a6e1baaf6a354c180e91899d10bec...mozilla-master
|
||||||
|
[mozilla-send]: https://github.com/mozilla/send
|
||||||
|
[mozilla]: https://mozilla.org/
|
||||||
|
[remove-branding-pr]: https://gitlab.com/timvisee/send/-/merge_requests/2
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
**Docs:** [FAQ](docs/faq.md), [Encryption](docs/encryption.md), [Build](docs/build.md), [Docker](docs/docker.md), [Metrics](docs/metrics.md), [More](docs/)
|
**Docs:** [FAQ](docs/faq.md), [Encryption](docs/encryption.md), [Build](docs/build.md), [Docker](docs/docker.md), [Metrics](docs/metrics.md), [More](docs/)
|
||||||
|
|
||||||
@@ -109,4 +159,6 @@ The android implementation is contained in the `android` directory, and can be v
|
|||||||
|
|
||||||
[Mozilla Public License Version 2.0](LICENSE)
|
[Mozilla Public License Version 2.0](LICENSE)
|
||||||
|
|
||||||
|
[qrcode.js](https://github.com/kazuhikoarase/qrcode-generator) licensed under MIT
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -61,7 +61,10 @@ async function fetchWithAuth(url, params, keychain) {
|
|||||||
const result = {};
|
const result = {};
|
||||||
params = params || {};
|
params = params || {};
|
||||||
const h = await keychain.authHeader();
|
const h = await keychain.authHeader();
|
||||||
params.headers = new Headers({ Authorization: h });
|
params.headers = new Headers({
|
||||||
|
Authorization: h,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
});
|
||||||
const response = await fetch(url, params);
|
const response = await fetch(url, params);
|
||||||
result.response = response;
|
result.response = response;
|
||||||
result.ok = response.ok;
|
result.ok = response.ok;
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ async function polyfillStreams() {
|
|||||||
|
|
||||||
export default async function getCapabilities() {
|
export default async function getCapabilities() {
|
||||||
const browser = browserName();
|
const browser = browserName();
|
||||||
|
const isMobile = /mobi|android/i.test(navigator.userAgent);
|
||||||
const serviceWorker = 'serviceWorker' in navigator && browser !== 'edge';
|
const serviceWorker = 'serviceWorker' in navigator && browser !== 'edge';
|
||||||
let crypto = await checkCrypto();
|
let crypto = await checkCrypto();
|
||||||
const nativeStreams = checkStreams();
|
const nativeStreams = checkStreams();
|
||||||
@@ -91,14 +92,15 @@ export default async function getCapabilities() {
|
|||||||
account = false;
|
account = false;
|
||||||
}
|
}
|
||||||
const share =
|
const share =
|
||||||
typeof navigator.share === 'function' && locale().startsWith('en'); // en until strings merge
|
isMobile &&
|
||||||
|
typeof navigator.share === 'function' &&
|
||||||
|
locale().startsWith('en'); // en until strings merge
|
||||||
|
|
||||||
const standalone =
|
const standalone =
|
||||||
window.matchMedia('(display-mode: standalone)').matches ||
|
window.matchMedia('(display-mode: standalone)').matches ||
|
||||||
navigator.standalone;
|
navigator.standalone;
|
||||||
|
|
||||||
const mobileFirefox =
|
const mobileFirefox = browser === 'firefox' && isMobile;
|
||||||
browser === 'firefox' && /mobile/i.test(navigator.userAgent);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
account,
|
account,
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import FileSender from './fileSender';
|
|
||||||
import FileReceiver from './fileReceiver';
|
|
||||||
import { copyToClipboard, delay, openLinksInNewTab, percent } from './utils';
|
|
||||||
import * as metrics from './metrics';
|
import * as metrics from './metrics';
|
||||||
import { bytes, locale } from './utils';
|
import FileReceiver from './fileReceiver';
|
||||||
import okDialog from './ui/okDialog';
|
import FileSender from './fileSender';
|
||||||
import copyDialog from './ui/copyDialog';
|
import copyDialog from './ui/copyDialog';
|
||||||
|
import faviconProgressbar from './ui/faviconProgressbar';
|
||||||
|
import okDialog from './ui/okDialog';
|
||||||
import shareDialog from './ui/shareDialog';
|
import shareDialog from './ui/shareDialog';
|
||||||
import signupDialog from './ui/signupDialog';
|
import signupDialog from './ui/signupDialog';
|
||||||
import surveyDialog from './ui/surveyDialog';
|
import surveyDialog from './ui/surveyDialog';
|
||||||
|
import { bytes, locale } from './utils';
|
||||||
|
import { copyToClipboard, delay, openLinksInNewTab, percent } from './utils';
|
||||||
|
|
||||||
export default function(state, emitter) {
|
export default function(state, emitter) {
|
||||||
let lastRender = 0;
|
let lastRender = 0;
|
||||||
@@ -29,6 +30,7 @@ export default function(state, emitter) {
|
|||||||
if (updateTitle) {
|
if (updateTitle) {
|
||||||
emitter.emit('DOMTitleChange', percent(state.transfer.progressRatio));
|
emitter.emit('DOMTitleChange', percent(state.transfer.progressRatio));
|
||||||
}
|
}
|
||||||
|
faviconProgressbar.updateFavicon(state.transfer.progressRatio);
|
||||||
render();
|
render();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,6 +39,7 @@ export default function(state, emitter) {
|
|||||||
document.addEventListener('focus', () => {
|
document.addEventListener('focus', () => {
|
||||||
updateTitle = false;
|
updateTitle = false;
|
||||||
emitter.emit('DOMTitleChange', 'Send');
|
emitter.emit('DOMTitleChange', 'Send');
|
||||||
|
faviconProgressbar.updateFavicon(0);
|
||||||
});
|
});
|
||||||
checkFiles();
|
checkFiles();
|
||||||
});
|
});
|
||||||
@@ -49,8 +52,8 @@ export default function(state, emitter) {
|
|||||||
state.user.login(email);
|
state.user.login(email);
|
||||||
});
|
});
|
||||||
|
|
||||||
emitter.on('logout', () => {
|
emitter.on('logout', async () => {
|
||||||
state.user.logout();
|
await state.user.logout();
|
||||||
metrics.loggedOut({ trigger: 'button' });
|
metrics.loggedOut({ trigger: 'button' });
|
||||||
emitter.emit('pushState', '/');
|
emitter.emit('pushState', '/');
|
||||||
});
|
});
|
||||||
@@ -83,6 +86,7 @@ export default function(state, emitter) {
|
|||||||
|
|
||||||
emitter.on('cancel', () => {
|
emitter.on('cancel', () => {
|
||||||
state.transfer.cancel();
|
state.transfer.cancel();
|
||||||
|
faviconProgressbar.updateFavicon(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
emitter.on('addFiles', async ({ files }) => {
|
emitter.on('addFiles', async ({ files }) => {
|
||||||
@@ -161,6 +165,7 @@ export default function(state, emitter) {
|
|||||||
state.storage.totalUploads += 1;
|
state.storage.totalUploads += 1;
|
||||||
const duration = Date.now() - start;
|
const duration = Date.now() - start;
|
||||||
metrics.completedUpload(archive, duration);
|
metrics.completedUpload(archive, duration);
|
||||||
|
faviconProgressbar.updateFavicon(0);
|
||||||
|
|
||||||
state.storage.addFile(ownedFile);
|
state.storage.addFile(ownedFile);
|
||||||
// TODO integrate password into /upload request
|
// TODO integrate password into /upload request
|
||||||
@@ -178,6 +183,12 @@ export default function(state, emitter) {
|
|||||||
//cancelled. do nothing
|
//cancelled. do nothing
|
||||||
metrics.cancelledUpload(archive, err.duration);
|
metrics.cancelledUpload(archive, err.duration);
|
||||||
render();
|
render();
|
||||||
|
} else if (err.message === '401') {
|
||||||
|
const refreshed = await state.user.refresh();
|
||||||
|
if (refreshed) {
|
||||||
|
return emitter.emit('upload');
|
||||||
|
}
|
||||||
|
emitter.emit('pushState', '/error');
|
||||||
} else {
|
} else {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.error(err);
|
console.error(err);
|
||||||
@@ -229,6 +240,9 @@ export default function(state, emitter) {
|
|||||||
if (!file.requiresPassword) {
|
if (!file.requiresPassword) {
|
||||||
return emitter.emit('pushState', '/404');
|
return emitter.emit('pushState', '/404');
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
console.error(e);
|
||||||
|
return emitter.emit('pushState', '/error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,6 +269,7 @@ export default function(state, emitter) {
|
|||||||
duration,
|
duration,
|
||||||
password_protected: file.requiresPassword
|
password_protected: file.requiresPassword
|
||||||
});
|
});
|
||||||
|
faviconProgressbar.updateFavicon(0);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.message === '0') {
|
if (err.message === '0') {
|
||||||
// download cancelled
|
// download cancelled
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import Nanobus from 'nanobus';
|
import Nanobus from 'nanobus';
|
||||||
import Keychain from './keychain';
|
import Keychain from './keychain';
|
||||||
import { delay, bytes, streamToArrayBuffer } from './utils';
|
import { delay, bytes, streamToArrayBuffer } from './utils';
|
||||||
import { downloadFile, metadata, getApiUrl } from './api';
|
import { downloadFile, metadata, getApiUrl, reportLink } from './api';
|
||||||
import { blobStream } from './streams';
|
import { blobStream } from './streams';
|
||||||
import Zip from './zip';
|
import Zip from './zip';
|
||||||
|
|
||||||
@@ -53,6 +53,10 @@ export default class FileReceiver extends Nanobus {
|
|||||||
this.state = 'ready';
|
this.state = 'ready';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async reportLink(reason) {
|
||||||
|
await reportLink(this.fileInfo.id, this.keychain, reason);
|
||||||
|
}
|
||||||
|
|
||||||
sendMessageToSw(msg) {
|
sendMessageToSw(msg) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const channel = new MessageChannel();
|
const channel = new MessageChannel();
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ select {
|
|||||||
@apply m-auto;
|
@apply m-auto;
|
||||||
@apply py-8;
|
@apply py-8;
|
||||||
|
|
||||||
min-height: 36rem;
|
min-height: 42rem;
|
||||||
max-height: 42rem;
|
max-height: 42rem;
|
||||||
width: calc(100% - 3rem);
|
width: calc(100% - 3rem);
|
||||||
}
|
}
|
||||||
|
|||||||
1076
app/qrcode.js
Normal file
1076
app/qrcode.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,10 @@ module.exports = function(app = choo({ hash: true })) {
|
|||||||
app.route('/oauth', function(state, emit) {
|
app.route('/oauth', function(state, emit) {
|
||||||
emit('authenticate', state.query.code, state.query.state);
|
emit('authenticate', state.query.code, state.query.state);
|
||||||
});
|
});
|
||||||
app.route('/login', body(require('./ui/home')));
|
app.route('/login', function(state, emit) {
|
||||||
|
emit('replaceState', '/');
|
||||||
|
setTimeout(() => emit('render'));
|
||||||
|
});
|
||||||
app.route('*', body(require('./ui/notFound')));
|
app.route('*', body(require('./ui/notFound')));
|
||||||
return app;
|
return app;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import contentDisposition from 'content-disposition';
|
|||||||
let noSave = false;
|
let noSave = false;
|
||||||
const map = new Map();
|
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)(#\w+)?$/;
|
||||||
const DOWNLOAD_URL = /\/api\/download\/([A-Fa-f0-9]{4,})/;
|
const DOWNLOAD_URL = /\/api\/download\/([A-Fa-f0-9]{4,})/;
|
||||||
const FONT = /\.woff2?$/;
|
const FONT = /\.woff2?$/;
|
||||||
|
|
||||||
|
|||||||
@@ -54,12 +54,17 @@ class Account extends Component {
|
|||||||
createElement() {
|
createElement() {
|
||||||
if (!this.enabled) {
|
if (!this.enabled) {
|
||||||
return html`
|
return html`
|
||||||
<div></div>
|
<send-account></send-account>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
const user = this.state.user;
|
const user = this.state.user;
|
||||||
const translate = this.state.translate;
|
const translate = this.state.translate;
|
||||||
this.setLocal();
|
this.setLocal();
|
||||||
|
if (user.loginRequired && !this.local.loggedIn) {
|
||||||
|
return html`
|
||||||
|
<send-account></send-account>
|
||||||
|
`;
|
||||||
|
}
|
||||||
if (!this.local.loggedIn) {
|
if (!this.local.loggedIn) {
|
||||||
return html`
|
return html`
|
||||||
<send-account>
|
<send-account>
|
||||||
|
|||||||
@@ -30,6 +30,12 @@ function password(state) {
|
|||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="mb-2 px-1">
|
<div class="mb-2 px-1">
|
||||||
|
<input
|
||||||
|
id="autocomplete-decoy"
|
||||||
|
class="hidden"
|
||||||
|
type="password"
|
||||||
|
value="lol"
|
||||||
|
/>
|
||||||
<div class="checkbox inline-block mr-3">
|
<div class="checkbox inline-block mr-3">
|
||||||
<input
|
<input
|
||||||
id="add-password"
|
id="add-password"
|
||||||
@@ -42,19 +48,36 @@ function password(state) {
|
|||||||
${state.translate('addPassword')}
|
${state.translate('addPassword')}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<input
|
<div class="relative inline-block my-1">
|
||||||
id="password-input"
|
<input
|
||||||
class="${state.archive.password
|
id="password-input"
|
||||||
? ''
|
class="${state.archive.password
|
||||||
: 'invisible'} border rounded focus:border-blue-60 leading-normal my-1 py-1 px-2 h-8 dark:bg-grey-80"
|
? ''
|
||||||
autocomplete="off"
|
: 'invisible'} border rounded focus:border-blue-60 leading-normal py-1 pl-2 pr-8 h-8 dark:bg-grey-80"
|
||||||
maxlength="${MAX_LENGTH}"
|
autocomplete="off"
|
||||||
type="password"
|
maxlength="${MAX_LENGTH}"
|
||||||
oninput="${inputChanged}"
|
type="password"
|
||||||
onfocus="${focused}"
|
oninput="${inputChanged}"
|
||||||
placeholder="${state.translate('unlockInputPlaceholder')}"
|
onfocus="${focused}"
|
||||||
value="${state.archive.password || ''}"
|
placeholder="${state.translate('unlockInputPlaceholder')}"
|
||||||
/>
|
value="${state.archive.password || ''}"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
id="password-preview-button"
|
||||||
|
type="button"
|
||||||
|
class="${state.archive.password
|
||||||
|
? ''
|
||||||
|
: 'invisible'} absolute top-0 right-0 w-8 h-8"
|
||||||
|
onclick="${onPasswordPreviewButtonclicked}"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src="${assets.get('eye.svg')}"
|
||||||
|
width="22"
|
||||||
|
height="22"
|
||||||
|
class="m-auto"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<label
|
<label
|
||||||
id="password-msg"
|
id="password-msg"
|
||||||
for="password-input"
|
for="password-input"
|
||||||
@@ -63,15 +86,36 @@ function password(state) {
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
function onPasswordPreviewButtonclicked(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const input = document.getElementById('password-input');
|
||||||
|
const eyeIcon = event.currentTarget.querySelector('img');
|
||||||
|
|
||||||
|
if (input.type === 'password') {
|
||||||
|
input.type = 'text';
|
||||||
|
eyeIcon.src = assets.get('eye-off.svg');
|
||||||
|
} else {
|
||||||
|
input.type = 'password';
|
||||||
|
eyeIcon.src = assets.get('eye.svg');
|
||||||
|
}
|
||||||
|
|
||||||
|
input.focus();
|
||||||
|
}
|
||||||
|
|
||||||
function togglePasswordInput(event) {
|
function togglePasswordInput(event) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
const checked = event.target.checked;
|
const checked = event.target.checked;
|
||||||
const input = document.getElementById('password-input');
|
const input = document.getElementById('password-input');
|
||||||
|
const passwordPreviewButton = document.getElementById(
|
||||||
|
'password-preview-button'
|
||||||
|
);
|
||||||
if (checked) {
|
if (checked) {
|
||||||
input.classList.remove('invisible');
|
input.classList.remove('invisible');
|
||||||
|
passwordPreviewButton.classList.remove('invisible');
|
||||||
input.focus();
|
input.focus();
|
||||||
} else {
|
} else {
|
||||||
input.classList.add('invisible');
|
input.classList.add('invisible');
|
||||||
|
passwordPreviewButton.classList.add('invisible');
|
||||||
input.value = '';
|
input.value = '';
|
||||||
document.getElementById('password-msg').textContent = '';
|
document.getElementById('password-msg').textContent = '';
|
||||||
state.archive.password = null;
|
state.archive.password = null;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
const html = require('choo/html');
|
const html = require('choo/html');
|
||||||
const { copyToClipboard } = require('../utils');
|
const { copyToClipboard } = require('../utils');
|
||||||
|
const qr = require('./qr');
|
||||||
|
|
||||||
module.exports = function(name, url) {
|
module.exports = function(name, url) {
|
||||||
const dialog = function(state, emit, close) {
|
const dialog = function(state, emit, close) {
|
||||||
@@ -16,13 +17,23 @@ module.exports = function(name, url) {
|
|||||||
${state.translate('copyLinkDescription')} <br />
|
${state.translate('copyLinkDescription')} <br />
|
||||||
${name}
|
${name}
|
||||||
</p>
|
</p>
|
||||||
<input
|
<div class="flex flex-row items-center justify-center w-full">
|
||||||
type="text"
|
<input
|
||||||
id="share-url"
|
type="text"
|
||||||
class="w-full my-4 border rounded-lg leading-loose h-12 px-2 py-1 dark:bg-grey-80"
|
id="share-url"
|
||||||
value="${url}"
|
class="block w-full my-4 border rounded-lg leading-loose h-12 px-2 py-1 dark:bg-grey-80"
|
||||||
readonly="true"
|
value="${url}"
|
||||||
/>
|
readonly="true"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
id="qr-btn"
|
||||||
|
class="w-16 m-1 p-1"
|
||||||
|
onclick="${toggleQR}"
|
||||||
|
title="QR code"
|
||||||
|
>
|
||||||
|
${qr(url)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<button
|
<button
|
||||||
class="btn rounded-lg w-full flex-shrink-0 focus:outline"
|
class="btn rounded-lg w-full flex-shrink-0 focus:outline"
|
||||||
onclick="${copy}"
|
onclick="${copy}"
|
||||||
@@ -40,6 +51,19 @@ module.exports = function(name, url) {
|
|||||||
</send-copy-dialog>
|
</send-copy-dialog>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
function toggleQR(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
const shareUrl = document.getElementById('share-url');
|
||||||
|
const qrBtn = document.getElementById('qr-btn');
|
||||||
|
if (shareUrl.classList.contains('hidden')) {
|
||||||
|
shareUrl.classList.replace('hidden', 'block');
|
||||||
|
qrBtn.classList.replace('w-48', 'w-16');
|
||||||
|
} else {
|
||||||
|
shareUrl.classList.replace('block', 'hidden');
|
||||||
|
qrBtn.classList.replace('w-16', 'w-48');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function copy(event) {
|
function copy(event) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
copyToClipboard(url);
|
copyToClipboard(url);
|
||||||
|
|||||||
@@ -55,9 +55,13 @@ module.exports = function(state, emit) {
|
|||||||
let content = '';
|
let content = '';
|
||||||
if (!state.fileInfo) {
|
if (!state.fileInfo) {
|
||||||
state.fileInfo = createFileInfo(state);
|
state.fileInfo = createFileInfo(state);
|
||||||
if (!state.fileInfo.nonce) {
|
if (downloadMetadata.status === 404) {
|
||||||
return notFound(state);
|
return notFound(state);
|
||||||
}
|
}
|
||||||
|
if (!state.fileInfo.nonce) {
|
||||||
|
// coming from something like the browser back button
|
||||||
|
return location.reload();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!state.transfer && !state.fileInfo.requiresPassword) {
|
if (!state.transfer && !state.fileInfo.requiresPassword) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ const html = require('choo/html');
|
|||||||
const assets = require('../../common/assets');
|
const assets = require('../../common/assets');
|
||||||
|
|
||||||
module.exports = function(state) {
|
module.exports = function(state) {
|
||||||
|
const btnText = state.user.loggedIn ? 'okButton' : 'sendYourFilesLink';
|
||||||
return html`
|
return html`
|
||||||
<div
|
<div
|
||||||
id="download-complete"
|
id="download-complete"
|
||||||
@@ -10,13 +11,18 @@ module.exports = function(state) {
|
|||||||
<h1 class="text-center text-3xl font-bold my-2">
|
<h1 class="text-center text-3xl font-bold my-2">
|
||||||
${state.translate('downloadFinish')}
|
${state.translate('downloadFinish')}
|
||||||
</h1>
|
</h1>
|
||||||
<img src="${assets.get('completed.svg')}" class="my-12 h-48" />
|
<img src="${assets.get('completed.svg')}" class="my-8 h-48" />
|
||||||
<p class="text-grey-80 leading-normal dark:text-grey-40">
|
<p
|
||||||
|
class="text-grey-80 leading-normal dark:text-grey-40 ${state.user
|
||||||
|
.loggedIn
|
||||||
|
? 'hidden'
|
||||||
|
: ''}"
|
||||||
|
>
|
||||||
${state.translate('trySendDescription')}
|
${state.translate('trySendDescription')}
|
||||||
</p>
|
</p>
|
||||||
<p class="my-5">
|
<p class="my-5">
|
||||||
<a href="/" class="btn rounded-lg flex items-center mt-4" role="button"
|
<a href="/" class="btn rounded-lg flex items-center mt-4" role="button"
|
||||||
>${state.translate('sendYourFilesLink')}</a
|
>${state.translate(btnText)}</a
|
||||||
>
|
>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -21,6 +21,12 @@ module.exports = function(state, emit) {
|
|||||||
onsubmit="${checkPassword}"
|
onsubmit="${checkPassword}"
|
||||||
data-no-csrf
|
data-no-csrf
|
||||||
>
|
>
|
||||||
|
<input
|
||||||
|
id="autocomplete-decoy"
|
||||||
|
class="hidden"
|
||||||
|
type="password"
|
||||||
|
value="lol"
|
||||||
|
/>
|
||||||
<input
|
<input
|
||||||
id="password-input"
|
id="password-input"
|
||||||
class="w-full border-l border-t border-b rounded-l-lg rounded-r-none ${invalid
|
class="w-full border-l border-t border-b rounded-l-lg rounded-r-none ${invalid
|
||||||
@@ -63,8 +69,13 @@ module.exports = function(state, emit) {
|
|||||||
const input = document.getElementById('password-input');
|
const input = document.getElementById('password-input');
|
||||||
const btn = document.getElementById('password-btn');
|
const btn = document.getElementById('password-btn');
|
||||||
label.classList.add('invisible');
|
label.classList.add('invisible');
|
||||||
input.classList.remove('border-red');
|
input.classList.remove('border-red', 'dark:border-red-40');
|
||||||
btn.classList.remove('bg-red', 'hover:bg-red', 'focus:bg-red');
|
btn.classList.remove(
|
||||||
|
'bg-red',
|
||||||
|
'hover:bg-red',
|
||||||
|
'focus:bg-red',
|
||||||
|
'dark:bg-red-40'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkPassword(event) {
|
function checkPassword(event) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const assets = require('../../common/assets');
|
|||||||
const modal = require('./modal');
|
const modal = require('./modal');
|
||||||
|
|
||||||
module.exports = function(state, emit) {
|
module.exports = function(state, emit) {
|
||||||
|
const btnText = state.user.loggedIn ? 'okButton' : 'sendYourFilesLink';
|
||||||
return html`
|
return html`
|
||||||
<main class="main">
|
<main class="main">
|
||||||
${state.modal && modal(state, emit)}
|
${state.modal && modal(state, emit)}
|
||||||
@@ -13,12 +14,17 @@ module.exports = function(state, emit) {
|
|||||||
${state.translate('errorPageHeader')}
|
${state.translate('errorPageHeader')}
|
||||||
</h1>
|
</h1>
|
||||||
<img class="my-12 h-48" src="${assets.get('error.svg')}" />
|
<img class="my-12 h-48" src="${assets.get('error.svg')}" />
|
||||||
<p class="max-w-md text-center text-grey-80 leading-normal">
|
<p
|
||||||
|
class="max-w-md text-center text-grey-80 leading-normal dark:text-grey-40 ${state
|
||||||
|
.user.loggedIn
|
||||||
|
? 'hidden'
|
||||||
|
: ''}"
|
||||||
|
>
|
||||||
${state.translate('trySendDescription')}
|
${state.translate('trySendDescription')}
|
||||||
</p>
|
</p>
|
||||||
<p class="my-5">
|
<p class="my-5">
|
||||||
<a href="/" class="btn rounded-lg flex items-center" role="button"
|
<a href="/" class="btn rounded-lg flex items-center" role="button"
|
||||||
>${state.translate('sendYourFilesLink')}</a
|
>${state.translate(btnText)}</a
|
||||||
>
|
>
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
41
app/ui/faviconProgressbar.js
Normal file
41
app/ui/faviconProgressbar.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
const { platform } = require('../utils');
|
||||||
|
const assets = require('../../common/assets');
|
||||||
|
|
||||||
|
const size = 32;
|
||||||
|
const loaderWidth = 5;
|
||||||
|
const loaderColor = '#0090ed';
|
||||||
|
|
||||||
|
function drawCircle(canvas, context, color, lineWidth, outerWidth, percent) {
|
||||||
|
canvas.width = canvas.height = outerWidth;
|
||||||
|
context.translate(outerWidth * 0.5, outerWidth * 0.5);
|
||||||
|
context.rotate(-Math.PI * 0.5);
|
||||||
|
const radius = (outerWidth - lineWidth) * 0.5;
|
||||||
|
context.beginPath();
|
||||||
|
context.arc(0, 0, radius, 0, Math.PI * 2 * percent, false);
|
||||||
|
context.strokeStyle = color;
|
||||||
|
context.lineCap = 'square';
|
||||||
|
context.lineWidth = lineWidth;
|
||||||
|
context.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawNewFavicon(progressRatio) {
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
const context = canvas.getContext('2d');
|
||||||
|
drawCircle(canvas, context, '#efefef', loaderWidth, size, 1);
|
||||||
|
drawCircle(canvas, context, loaderColor, loaderWidth, size, progressRatio);
|
||||||
|
return canvas.toDataURL();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.updateFavicon = function(progressRatio) {
|
||||||
|
if (platform() === 'web') {
|
||||||
|
const link = document.querySelector("link[rel='icon'][sizes='32x32']");
|
||||||
|
const progress = progressRatio * 100;
|
||||||
|
if (progress === 0 || progress === 100) {
|
||||||
|
link.type = 'image/png';
|
||||||
|
link.href = assets.get('favicon-32x32.png');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
link.href = drawNewFavicon(progressRatio);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -33,7 +33,7 @@ class Header extends Component {
|
|||||||
alt="${this.state.translate('title')}"
|
alt="${this.state.translate('title')}"
|
||||||
src="${assets.get('icon.svg')}"
|
src="${assets.get('icon.svg')}"
|
||||||
/>
|
/>
|
||||||
<svg class="w-48 md:w-64">
|
<svg viewBox="66 0 340 64" class="w-48 md:w-64">
|
||||||
<use xlink:href="${assets.get('wordmark.svg')}#logo" />
|
<use xlink:href="${assets.get('wordmark.svg')}#logo" />
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ const html = require('choo/html');
|
|||||||
const modal = require('./modal');
|
const modal = require('./modal');
|
||||||
|
|
||||||
module.exports = function(state, emit) {
|
module.exports = function(state, emit) {
|
||||||
|
state.modal = null;
|
||||||
return html`
|
return html`
|
||||||
<main class="main">
|
<main class="main">
|
||||||
${state.modal && modal(state, emit)}
|
${state.modal && modal(state, emit)}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ module.exports = function(state, emit) {
|
|||||||
class="absolute inset-0 flex items-center justify-center overflow-hidden z-40 bg-white md:rounded-xl md:my-8 dark:bg-grey-90"
|
class="absolute inset-0 flex items-center justify-center overflow-hidden z-40 bg-white md:rounded-xl md:my-8 dark:bg-grey-90"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="h-full w-full max-h-screen absolute top-0 flex items-center justify-center"
|
class="h-full w-full max-h-screen absolute top-0 flex justify-center md:items-center"
|
||||||
>
|
>
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
${state.modal(state, emit, close)}
|
${state.modal(state, emit, close)}
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ module.exports = function(state, emit) {
|
|||||||
<form class="md:w-128" onsubmit=${submit}>
|
<form class="md:w-128" onsubmit=${submit}>
|
||||||
<fieldset class="border rounded p-4 my-4" onchange=${optionChanged}>
|
<fieldset class="border rounded p-4 my-4" onchange=${optionChanged}>
|
||||||
<div class="flex items-center mb-2">
|
<div class="flex items-center mb-2">
|
||||||
<img class="mr-3 flex-shrink-0" src="${assets.get(
|
<svg class="h-8 w-6 mr-3 flex-shrink-0 text-white dark:text-grey-90">
|
||||||
'blue_file.svg'
|
<use xlink:href="${assets.get('blue_file.svg')}#icon"/>
|
||||||
)}"/>
|
</svg>
|
||||||
<p class="flex-grow">
|
<p class="flex-grow">
|
||||||
<h1 class="text-base font-medium word-break-all">${
|
<h1 class="text-base font-medium word-break-all">${
|
||||||
archive.name
|
archive.name
|
||||||
@@ -55,6 +55,11 @@ module.exports = function(state, emit) {
|
|||||||
value="${state.translate('copyLinkButton')}"
|
value="${state.translate('copyLinkButton')}"
|
||||||
title="${state.translate('copyLinkButton')}"
|
title="${state.translate('copyLinkButton')}"
|
||||||
type="submit" />
|
type="submit" />
|
||||||
|
<p
|
||||||
|
class="text-grey-80 leading-normal dark:text-grey-40 font-semibold text-center md:my-8 md:text-left"
|
||||||
|
>
|
||||||
|
${state.translate('downloadConfirmDescription')}
|
||||||
|
</p>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -64,6 +69,7 @@ module.exports = function(state, emit) {
|
|||||||
const choice = event.target.value;
|
const choice = event.target.value;
|
||||||
const button = event.currentTarget.nextElementSibling;
|
const button = event.currentTarget.nextElementSibling;
|
||||||
let title = button.title;
|
let title = button.title;
|
||||||
|
console.error(choice, title);
|
||||||
switch (choice) {
|
switch (choice) {
|
||||||
case 'copy':
|
case 'copy':
|
||||||
title = state.translate('copyLinkButton');
|
title = state.translate('copyLinkButton');
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const assets = require('../../common/assets');
|
|||||||
const modal = require('./modal');
|
const modal = require('./modal');
|
||||||
|
|
||||||
module.exports = function(state, emit) {
|
module.exports = function(state, emit) {
|
||||||
|
const btnText = state.user.loggedIn ? 'okButton' : 'sendYourFilesLink';
|
||||||
return html`
|
return html`
|
||||||
<main class="main">
|
<main class="main">
|
||||||
${state.modal && modal(state, emit)}
|
${state.modal && modal(state, emit)}
|
||||||
@@ -13,12 +14,17 @@ module.exports = function(state, emit) {
|
|||||||
${state.translate('expiredTitle')}
|
${state.translate('expiredTitle')}
|
||||||
</h1>
|
</h1>
|
||||||
<img src="${assets.get('notFound.svg')}" class="my-12" />
|
<img src="${assets.get('notFound.svg')}" class="my-12" />
|
||||||
<p class="max-w-md text-center text-grey-80 leading-normal">
|
<p
|
||||||
|
class="max-w-md text-center text-grey-80 leading-normal dark:text-grey-40 ${state
|
||||||
|
.user.loggedIn
|
||||||
|
? 'hidden'
|
||||||
|
: ''}"
|
||||||
|
>
|
||||||
${state.translate('trySendDescription')}
|
${state.translate('trySendDescription')}
|
||||||
</p>
|
</p>
|
||||||
<p class="my-5">
|
<p class="my-5">
|
||||||
<a href="/" class="btn rounded-lg flex items-center" role="button"
|
<a href="/" class="btn rounded-lg flex items-center" role="button"
|
||||||
>${state.translate('sendYourFilesLink')}</a
|
>${state.translate(btnText)}</a
|
||||||
>
|
>
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
10
app/ui/qr.js
Normal file
10
app/ui/qr.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
const raw = require('choo/html/raw');
|
||||||
|
const qrcode = require('../qrcode');
|
||||||
|
|
||||||
|
module.exports = function(url) {
|
||||||
|
const gen = qrcode(5, 'L');
|
||||||
|
gen.addData(url);
|
||||||
|
gen.make();
|
||||||
|
const qr = gen.createSvgTag({ scalable: true });
|
||||||
|
return raw(qr);
|
||||||
|
};
|
||||||
@@ -1,22 +1,19 @@
|
|||||||
const html = require('choo/html');
|
const html = require('choo/html');
|
||||||
const assets = require('../../common/assets');
|
const assets = require('../../common/assets');
|
||||||
const { bytes, platform } = require('../utils');
|
const { bytes } = require('../utils');
|
||||||
const { canceledSignup, submittedSignup } = require('../metrics');
|
const { canceledSignup, submittedSignup } = require('../metrics');
|
||||||
|
|
||||||
module.exports = function(trigger) {
|
module.exports = function(trigger) {
|
||||||
return function(state, emit, close) {
|
return function(state, emit, close) {
|
||||||
const DAYS = Math.floor(state.LIMITS.MAX_EXPIRE_SECONDS / 86400);
|
const DAYS = Math.floor(state.LIMITS.MAX_EXPIRE_SECONDS / 86400);
|
||||||
const hidden = platform() === 'android' ? 'hidden' : '';
|
|
||||||
let submitting = false;
|
let submitting = false;
|
||||||
return html`
|
return html`
|
||||||
<send-signup-dialog
|
<send-signup-dialog
|
||||||
class="flex flex-col lg:flex-row justify-center px-8 md:px-24 w-full h-full"
|
class="flex flex-col justify-center my-16 md:my-0 px-8 md:px-24 w-full h-full"
|
||||||
>
|
>
|
||||||
<img src="${assets.get('master-logo.svg')}" class="h-16 mt-1 mb-4" />
|
<img src="${assets.get('master-logo.svg')}" class="h-16 mt-1 mb-4" />
|
||||||
<section
|
<section class="flex flex-col flex-shrink-0 self-center">
|
||||||
class="flex flex-col flex-shrink-0 self-center lg:mx-6 lg:max-w-xs"
|
<h1 class="text-3xl font-bold text-center">
|
||||||
>
|
|
||||||
<h1 class="text-3xl font-bold text-center lg:text-left">
|
|
||||||
${state.translate('accountBenefitTitle')}
|
${state.translate('accountBenefitTitle')}
|
||||||
</h1>
|
</h1>
|
||||||
<ul
|
<ul
|
||||||
@@ -32,17 +29,14 @@ module.exports = function(trigger) {
|
|||||||
${state.translate('accountBenefitTimeLimit', { count: DAYS })}
|
${state.translate('accountBenefitTimeLimit', { count: DAYS })}
|
||||||
</li>
|
</li>
|
||||||
<li>${state.translate('accountBenefitSync')}</li>
|
<li>${state.translate('accountBenefitSync')}</li>
|
||||||
<li>${state.translate('accountBenefitMoz')}</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
<section
|
<section class="flex flex-col flex-grow m-4 md:self-center md:w-128">
|
||||||
class="flex flex-col flex-grow m-4 md:self-center md:w-128 lg:max-w-xs"
|
|
||||||
>
|
|
||||||
<form onsubmit=${submitEmail} data-no-csrf>
|
<form onsubmit=${submitEmail} data-no-csrf>
|
||||||
<input
|
<input
|
||||||
id="email-input"
|
id="email-input"
|
||||||
type="email"
|
type="email"
|
||||||
class="${hidden} border rounded-lg w-full px-2 py-1 h-12 mb-3 text-lg text-grey-70 leading-loose dark:bg-grey-80 dark:text-white"
|
class="hidden border rounded-lg w-full px-2 py-1 h-12 mb-3 text-lg text-grey-70 leading-loose dark:bg-grey-80 dark:text-white"
|
||||||
placeholder=${state.translate('emailPlaceholder')}
|
placeholder=${state.translate('emailPlaceholder')}
|
||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
@@ -53,13 +47,17 @@ module.exports = function(trigger) {
|
|||||||
type="submit"
|
type="submit"
|
||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
<button
|
${state.user.loginRequired
|
||||||
class="my-3 link-blue font-medium"
|
? ''
|
||||||
title="${state.translate('deletePopupCancel')}"
|
: html`
|
||||||
onclick=${cancel}
|
<button
|
||||||
>
|
class="my-3 link-blue font-medium"
|
||||||
${state.translate('deletePopupCancel')}
|
title="${state.translate('deletePopupCancel')}"
|
||||||
</button>
|
onclick=${cancel}
|
||||||
|
>
|
||||||
|
${state.translate('deletePopupCancel')}
|
||||||
|
</button>
|
||||||
|
`}
|
||||||
</section>
|
</section>
|
||||||
</send-signup-dialog>
|
</send-signup-dialog>
|
||||||
`;
|
`;
|
||||||
|
|||||||
79
app/user.js
79
app/user.js
@@ -76,6 +76,10 @@ export default class User {
|
|||||||
return this.info.access_token;
|
return this.info.access_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get refreshToken() {
|
||||||
|
return this.info.refresh_token;
|
||||||
|
}
|
||||||
|
|
||||||
get maxSize() {
|
get maxSize() {
|
||||||
return this.loggedIn
|
return this.loggedIn
|
||||||
? this.limits.MAX_FILE_SIZE
|
? this.limits.MAX_FILE_SIZE
|
||||||
@@ -135,6 +139,7 @@ export default class User {
|
|||||||
const code_challenge = await preparePkce(this.storage);
|
const code_challenge = await preparePkce(this.storage);
|
||||||
const options = {
|
const options = {
|
||||||
action: 'email',
|
action: 'email',
|
||||||
|
access_type: 'offline',
|
||||||
client_id: this.authConfig.client_id,
|
client_id: this.authConfig.client_id,
|
||||||
code_challenge,
|
code_challenge,
|
||||||
code_challenge_method: 'S256',
|
code_challenge_method: 'S256',
|
||||||
@@ -192,12 +197,69 @@ export default class User {
|
|||||||
});
|
});
|
||||||
const userInfo = await infoResponse.json();
|
const userInfo = await infoResponse.json();
|
||||||
userInfo.access_token = auth.access_token;
|
userInfo.access_token = auth.access_token;
|
||||||
|
userInfo.refresh_token = auth.refresh_token;
|
||||||
userInfo.fileListKey = await getFileListKey(this.storage, auth.keys_jwe);
|
userInfo.fileListKey = await getFileListKey(this.storage, auth.keys_jwe);
|
||||||
this.info = userInfo;
|
this.info = userInfo;
|
||||||
this.storage.remove('pkceVerifier');
|
this.storage.remove('pkceVerifier');
|
||||||
}
|
}
|
||||||
|
|
||||||
logout() {
|
async refresh() {
|
||||||
|
if (!this.refreshToken) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const tokenResponse = await fetch(this.authConfig.token_endpoint, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
client_id: this.authConfig.client_id,
|
||||||
|
grant_type: 'refresh_token',
|
||||||
|
refresh_token: this.refreshToken
|
||||||
|
})
|
||||||
|
});
|
||||||
|
if (tokenResponse.ok) {
|
||||||
|
const auth = await tokenResponse.json();
|
||||||
|
const info = { ...this.info, access_token: auth.access_token };
|
||||||
|
this.info = info;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
await this.logout();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async logout() {
|
||||||
|
try {
|
||||||
|
if (this.refreshToken) {
|
||||||
|
await fetch(this.authConfig.revocation_endpoint, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
refresh_token: this.refreshToken
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.bearerToken) {
|
||||||
|
await fetch(this.authConfig.revocation_endpoint, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
token: this.bearerToken
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
// oh well, we tried
|
||||||
|
}
|
||||||
this.storage.clearLocalFiles();
|
this.storage.clearLocalFiles();
|
||||||
this.info = {};
|
this.info = {};
|
||||||
}
|
}
|
||||||
@@ -211,6 +273,14 @@ export default class User {
|
|||||||
const key = b64ToArray(this.info.fileListKey);
|
const key = b64ToArray(this.info.fileListKey);
|
||||||
const sha = await crypto.subtle.digest('SHA-256', key);
|
const sha = await crypto.subtle.digest('SHA-256', key);
|
||||||
const kid = arrayToB64(new Uint8Array(sha)).substring(0, 16);
|
const kid = arrayToB64(new Uint8Array(sha)).substring(0, 16);
|
||||||
|
const retry = async () => {
|
||||||
|
const refreshed = await this.refresh();
|
||||||
|
if (refreshed) {
|
||||||
|
return await this.syncFileList();
|
||||||
|
} else {
|
||||||
|
return { incoming: true };
|
||||||
|
}
|
||||||
|
};
|
||||||
try {
|
try {
|
||||||
const encrypted = await getFileList(this.bearerToken, kid);
|
const encrypted = await getFileList(this.bearerToken, kid);
|
||||||
const decrypted = await streamToArrayBuffer(
|
const decrypted = await streamToArrayBuffer(
|
||||||
@@ -219,8 +289,7 @@ export default class User {
|
|||||||
list = JSON.parse(textDecoder.decode(decrypted));
|
list = JSON.parse(textDecoder.decode(decrypted));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.message === '401') {
|
if (e.message === '401') {
|
||||||
this.logout();
|
return retry(e);
|
||||||
return { incoming: true };
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
changes = await this.storage.merge(list);
|
changes = await this.storage.merge(list);
|
||||||
@@ -236,7 +305,9 @@ export default class User {
|
|||||||
);
|
);
|
||||||
await setFileList(this.bearerToken, kid, encrypted);
|
await setFileList(this.bearerToken, kid, encrypted);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
//
|
if (e.message === '401') {
|
||||||
|
return retry(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return changes;
|
return changes;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,12 +142,16 @@ function openLinksInNewTab(links, should = true) {
|
|||||||
|
|
||||||
function browserName() {
|
function browserName() {
|
||||||
try {
|
try {
|
||||||
|
// order of these matters
|
||||||
if (/firefox/i.test(navigator.userAgent)) {
|
if (/firefox/i.test(navigator.userAgent)) {
|
||||||
return 'firefox';
|
return 'firefox';
|
||||||
}
|
}
|
||||||
if (/edge/i.test(navigator.userAgent)) {
|
if (/edge/i.test(navigator.userAgent)) {
|
||||||
return 'edge';
|
return 'edge';
|
||||||
}
|
}
|
||||||
|
if (/edg/i.test(navigator.userAgent)) {
|
||||||
|
return 'edgium';
|
||||||
|
}
|
||||||
if (/trident/i.test(navigator.userAgent)) {
|
if (/trident/i.test(navigator.userAgent)) {
|
||||||
return 'ie';
|
return 'ie';
|
||||||
}
|
}
|
||||||
|
|||||||
1
assets/eye-off.svg
Normal file
1
assets/eye-off.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#8795a1" d="M256.1 144.8c56.2 0 101.9 45.3 101.9 101.1 0 13.1-2.6 25.5-7.3 37l59.5 59c30.8-25.5 55-58.4 69.9-96-35.3-88.7-122.3-151.6-224.2-151.6-28.5 0-55.8 5.1-81.1 14.1l44 43.7c11.6-4.6 24.1-7.3 37.3-7.3zM52.4 89.7l46.5 46.1 9.4 9.3c-33.9 26-60.4 60.8-76.3 100.8 35.2 88.7 122.2 151.6 224.1 151.6 31.6 0 61.7-6.1 89.2-17l8.6 8.5 59.7 59 25.9-25.7L78.2 64 52.4 89.7zM165 201.4l31.6 31.3c-1 4.2-1.6 8.7-1.6 13.1 0 33.5 27.3 60.6 61.1 60.6 4.5 0 9-.6 13.2-1.6l31.6 31.3c-13.6 6.7-28.7 10.7-44.8 10.7-56.2 0-101.9-45.3-101.9-101.1 0-15.8 4.1-30.7 10.8-44.3zm87.8-15.7l64.2 63.7.4-3.2c0-33.5-27.3-60.6-61.1-60.6l-3.5.1z"/></svg>
|
||||||
|
After Width: | Height: | Size: 701 B |
1
assets/eye.svg
Normal file
1
assets/eye.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#8795a1" d="M256 105c-101.8 0-188.4 62.4-224 151 35.6 88.6 122.2 151 224 151s188.4-62.4 224-151c-35.6-88.6-122.2-151-224-151zm0 251.7c-56 0-101.8-45.3-101.8-100.7S200 155.3 256 155.3 357.8 200.6 357.8 256 312 356.7 256 356.7zm0-161.1c-33.6 0-61.1 27.2-61.1 60.4s27.5 60.4 61.1 60.4 61.1-27.2 61.1-60.4-27.5-60.4-61.1-60.4z"/></svg>
|
||||||
|
After Width: | Height: | Size: 406 B |
@@ -1,61 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
<svg
|
<symbol id="logo">
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
<path d="m 105.17,33.27 c -1.04895,-0.638175 -2.18377,-1.123082 -3.37,-1.44 -1.25,-0.34 -2.46,-0.63 -3.63,-0.88 l -3.08,-0.7 C 94.22073,30.069182 93.37751,29.78027 92.58,29.39 91.90449,29.074134 91.31719,28.596738 90.87,28 c -0.43741,-0.644047 -0.65489,-1.412243 -0.62,-2.19 -0.0406,-1.405196 0.53693,-2.75754 1.58,-3.7 1.06,-1 2.73,-1.44 5,-1.44 1.76437,-0.07198 3.51559,0.332147 5.07,1.17 1.35935,0.80694 2.51833,1.911219 3.39,3.23 l 2.79,-2.18 c -1.26761,-1.5933 -2.84201,-2.916072 -4.63,-3.89 -2.04373,-1.017745 -4.30804,-1.512526 -6.59,-1.44 -1.40785,-0.02195 -2.80876,0.201387 -4.14,0.66 -1.16063,0.399115 -2.24085,1.001871 -3.19,1.78 -0.8713,0.712445 -1.5718,1.611145 -2.05,2.63 -0.4819,1.011666 -0.72807,2.119452 -0.72,3.24 -0.05,1.231532 0.24064,2.452997 0.84,3.53 0.55827,0.895068 1.31002,1.653654 2.2,2.22 0.94422,0.612326 1.97599,1.077636 3.06,1.38 1.13,0.32 2.29,0.6 3.47,0.84 l 3.26,0.74 c 0.96945,0.22193 1.90929,0.557589 2.8,1 0.77256,0.367753 1.45522,0.900225 2,1.56 0.51019,0.701297 0.77072,1.553301 0.74,2.42 0.0438,1.566414 -0.62122,3.069031 -1.81,4.09 -1.52512,1.147855 -3.41702,1.699065 -5.32,1.55 -4.03416,0.15747 -7.83041,-1.90763 -9.89,-5.38 l -3,2.34 c 1.3876,1.880136 3.1735,3.430427 5.23,4.54 2.3855,1.197767 5.03194,1.782045 7.7,1.7 1.49114,0.02151 2.97422,-0.222285 4.38,-0.72 1.21788,-0.44929 2.33816,-1.128248 3.3,-2 0.88604,-0.797749 1.60053,-1.767412 2.1,-2.85 0.48895,-1.06318 0.74142,-2.219779 0.74,-3.39 0.0397,-1.336553 -0.30755,-2.656119 -1,-3.8 -0.62101,-0.95962 -1.44763,-1.769154 -2.42,-2.37 z m 27.51,-4.72 c -1.0207,-1.016684 -2.23916,-1.813109 -3.58,-2.34 -1.42831,-0.567565 -2.95311,-0.852828 -4.49,-0.84 -1.58532,-0.01887 -3.15769,0.287432 -4.62,0.9 -1.3691,0.572827 -2.61257,1.408599 -3.66,2.46 -2.1451,2.217513 -3.33989,5.184759 -3.33,8.27 -0.0138,1.54162 0.26439,3.071916 0.82,4.51 0.5255,1.363982 1.32922,2.603618 2.36,3.64 1.06096,1.043663 2.31862,1.866239 3.7,2.42 1.53222,0.610739 3.17082,0.909903 4.82,0.88 2.13421,0.08534 4.25095,-0.416179 6.12,-1.45 1.69947,-1.049265 3.13073,-2.480527 4.18,-4.18 l -2.88,-1.69 c -1.41279,2.768876 -4.32635,4.443291 -7.43,4.27 -1.09666,0.02103 -2.18793,-0.158593 -3.22,-0.53 -0.93382,-0.341463 -1.79784,-0.849713 -2.55,-1.5 -0.72694,-0.645531 -1.33013,-1.418157 -1.78,-2.28 -0.47812,-0.903522 -0.77374,-1.892313 -0.87,-2.91 h 19.59 v -1.52 c 0.0166,-1.555338 -0.27566,-3.098506 -0.86,-4.54 -0.54053,-1.333176 -1.33916,-2.54641 -2.35,-3.57 z m -16.28,6.67 c 0.18109,-0.958759 0.51895,-1.881119 1,-2.73 0.47186,-0.820757 1.07675,-1.557447 1.79,-2.18 0.72195,-0.61779 1.5482,-1.102022 2.44,-1.43 0.95944,-0.356614 1.97651,-0.532906 3,-0.52 4.04346,-0.224227 7.5255,2.82256 7.84,6.86 z M 158.82,28 c -0.83726,-0.883328 -1.8626,-1.566885 -3,-2 -1.25447,-0.462049 -2.58329,-0.689169 -3.92,-0.67 -1.60057,-0.03131 -3.18086,0.362037 -4.58,1.14 -1.28188,0.720594 -2.36173,1.752297 -3.14,3 v -3.65 h -3.29 V 48 h 3.37 V 35.67 c -0.0102,-1.001391 0.16968,-1.995625 0.53,-2.93 0.3373,-0.856524 0.84023,-1.638106 1.48,-2.3 0.62704,-0.649648 1.38331,-1.160636 2.22,-1.5 0.87089,-0.363534 1.8063,-0.547214 2.75,-0.54 1.87023,-0.128793 3.70135,0.578019 5,1.93 1.22147,1.441484 1.85048,3.292756 1.76,5.18 V 48 h 3.41 V 35.34 c 0.0211,-1.424123 -0.20214,-2.84132 -0.66,-4.19 -0.40985,-1.176324 -1.06809,-2.250653 -1.93,-3.15 z m 27,-12.42 v 14.1 c -0.43264,-0.685249 -0.96517,-1.302051 -1.58,-1.83 -0.60967,-0.53196 -1.28117,-0.98858 -2,-1.36 -0.73088,-0.369676 -1.5029,-0.651634 -2.3,-0.84 -0.78611,-0.187908 -1.59174,-0.281898 -2.4,-0.28 -1.50724,-0.0078 -3.00162,0.277523 -4.4,0.84 -1.34071,0.551089 -2.56038,1.35967 -3.59,2.38 -1.03697,1.047216 -1.85907,2.287165 -2.42,3.65 -1.17023,2.996466 -1.17023,6.323534 0,9.32 0.55964,1.361695 1.37424,2.603955 2.4,3.66 1.02081,1.031107 2.2428,1.841226 3.59,2.38 1.40561,0.561607 2.90636,0.846817 4.42,0.84 0.80981,-0.0026 1.6161,-0.106786 2.4,-0.31 0.79636,-0.199929 1.56783,-0.488392 2.3,-0.86 0.72123,-0.371416 1.39312,-0.831661 2,-1.37 0.61025,-0.540083 1.14205,-1.162767 1.58,-1.85 v 4 h 3.33 V 15.59 Z m -0.37,24.58 c -1.76276,4.229524 -6.6195,6.23041 -10.85,4.47 v 0 c -0.97862,-0.401365 -1.86378,-1.000551 -2.6,-1.76 -0.7522,-0.76312 -1.34086,-1.671634 -1.73,-2.67 -0.41974,-1.066531 -0.63023,-2.203893 -0.62,-3.35 -0.0103,-1.129892 0.20027,-2.250911 0.62,-3.3 0.39328,-0.993283 0.98151,-1.897738 1.73,-2.66 0.74207,-0.76001 1.62521,-1.368023 2.6,-1.79 2.07874,-0.890012 4.43126,-0.890012 6.51,0 0.98149,0.434716 1.87338,1.048526 2.63,1.81 0.74927,0.763509 1.33458,1.672102 1.72,2.67 0.41464,1.036611 0.62516,2.14355 0.62,3.26 -1.3e-4,1.141508 -0.22084,2.272237 -0.65,3.33 z" fill="currentColor"/>
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
</symbol>
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
<use xlink:href="#logo"/>
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
version="1.1"
|
|
||||||
id="svg7"
|
|
||||||
sodipodi:docname="wordmark.svg"
|
|
||||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
|
|
||||||
<metadata
|
|
||||||
id="metadata13">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<defs
|
|
||||||
id="defs11" />
|
|
||||||
<sodipodi:namedview
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1"
|
|
||||||
objecttolerance="10"
|
|
||||||
gridtolerance="10"
|
|
||||||
guidetolerance="10"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:window-width="1874"
|
|
||||||
inkscape:window-height="1016"
|
|
||||||
id="namedview9"
|
|
||||||
showgrid="false"
|
|
||||||
inkscape:zoom="3.337544"
|
|
||||||
inkscape:cx="82.487885"
|
|
||||||
inkscape:cy="47.814478"
|
|
||||||
inkscape:window-x="1966"
|
|
||||||
inkscape:window-y="27"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:current-layer="svg7" />
|
|
||||||
<symbol
|
|
||||||
id="logo"
|
|
||||||
viewBox="66 0 340 64">
|
|
||||||
<path
|
|
||||||
d="m 105.17,33.27 c -1.04895,-0.638175 -2.18377,-1.123082 -3.37,-1.44 -1.25,-0.34 -2.46,-0.63 -3.63,-0.88 l -3.08,-0.7 C 94.22073,30.069182 93.37751,29.78027 92.58,29.39 91.90449,29.074134 91.31719,28.596738 90.87,28 c -0.43741,-0.644047 -0.65489,-1.412243 -0.62,-2.19 -0.0406,-1.405196 0.53693,-2.75754 1.58,-3.7 1.06,-1 2.73,-1.44 5,-1.44 1.76437,-0.07198 3.51559,0.332147 5.07,1.17 1.35935,0.80694 2.51833,1.911219 3.39,3.23 l 2.79,-2.18 c -1.26761,-1.5933 -2.84201,-2.916072 -4.63,-3.89 -2.04373,-1.017745 -4.30804,-1.512526 -6.59,-1.44 -1.40785,-0.02195 -2.80876,0.201387 -4.14,0.66 -1.16063,0.399115 -2.24085,1.001871 -3.19,1.78 -0.8713,0.712445 -1.5718,1.611145 -2.05,2.63 -0.4819,1.011666 -0.72807,2.119452 -0.72,3.24 -0.05,1.231532 0.24064,2.452997 0.84,3.53 0.55827,0.895068 1.31002,1.653654 2.2,2.22 0.94422,0.612326 1.97599,1.077636 3.06,1.38 1.13,0.32 2.29,0.6 3.47,0.84 l 3.26,0.74 c 0.96945,0.22193 1.90929,0.557589 2.8,1 0.77256,0.367753 1.45522,0.900225 2,1.56 0.51019,0.701297 0.77072,1.553301 0.74,2.42 0.0438,1.566414 -0.62122,3.069031 -1.81,4.09 -1.52512,1.147855 -3.41702,1.699065 -5.32,1.55 -4.03416,0.15747 -7.83041,-1.90763 -9.89,-5.38 l -3,2.34 c 1.3876,1.880136 3.1735,3.430427 5.23,4.54 2.3855,1.197767 5.03194,1.782045 7.7,1.7 1.49114,0.02151 2.97422,-0.222285 4.38,-0.72 1.21788,-0.44929 2.33816,-1.128248 3.3,-2 0.88604,-0.797749 1.60053,-1.767412 2.1,-2.85 0.48895,-1.06318 0.74142,-2.219779 0.74,-3.39 0.0397,-1.336553 -0.30755,-2.656119 -1,-3.8 -0.62101,-0.95962 -1.44763,-1.769154 -2.42,-2.37 z m 27.51,-4.72 c -1.0207,-1.016684 -2.23916,-1.813109 -3.58,-2.34 -1.42831,-0.567565 -2.95311,-0.852828 -4.49,-0.84 -1.58532,-0.01887 -3.15769,0.287432 -4.62,0.9 -1.3691,0.572827 -2.61257,1.408599 -3.66,2.46 -2.1451,2.217513 -3.33989,5.184759 -3.33,8.27 -0.0138,1.54162 0.26439,3.071916 0.82,4.51 0.5255,1.363982 1.32922,2.603618 2.36,3.64 1.06096,1.043663 2.31862,1.866239 3.7,2.42 1.53222,0.610739 3.17082,0.909903 4.82,0.88 2.13421,0.08534 4.25095,-0.416179 6.12,-1.45 1.69947,-1.049265 3.13073,-2.480527 4.18,-4.18 l -2.88,-1.69 c -1.41279,2.768876 -4.32635,4.443291 -7.43,4.27 -1.09666,0.02103 -2.18793,-0.158593 -3.22,-0.53 -0.93382,-0.341463 -1.79784,-0.849713 -2.55,-1.5 -0.72694,-0.645531 -1.33013,-1.418157 -1.78,-2.28 -0.47812,-0.903522 -0.77374,-1.892313 -0.87,-2.91 h 19.59 v -1.52 c 0.0166,-1.555338 -0.27566,-3.098506 -0.86,-4.54 -0.54053,-1.333176 -1.33916,-2.54641 -2.35,-3.57 z m -16.28,6.67 c 0.18109,-0.958759 0.51895,-1.881119 1,-2.73 0.47186,-0.820757 1.07675,-1.557447 1.79,-2.18 0.72195,-0.61779 1.5482,-1.102022 2.44,-1.43 0.95944,-0.356614 1.97651,-0.532906 3,-0.52 4.04346,-0.224227 7.5255,2.82256 7.84,6.86 z M 158.82,28 c -0.83726,-0.883328 -1.8626,-1.566885 -3,-2 -1.25447,-0.462049 -2.58329,-0.689169 -3.92,-0.67 -1.60057,-0.03131 -3.18086,0.362037 -4.58,1.14 -1.28188,0.720594 -2.36173,1.752297 -3.14,3 v -3.65 h -3.29 V 48 h 3.37 V 35.67 c -0.0102,-1.001391 0.16968,-1.995625 0.53,-2.93 0.3373,-0.856524 0.84023,-1.638106 1.48,-2.3 0.62704,-0.649648 1.38331,-1.160636 2.22,-1.5 0.87089,-0.363534 1.8063,-0.547214 2.75,-0.54 1.87023,-0.128793 3.70135,0.578019 5,1.93 1.22147,1.441484 1.85048,3.292756 1.76,5.18 V 48 h 3.41 V 35.34 c 0.0211,-1.424123 -0.20214,-2.84132 -0.66,-4.19 -0.40985,-1.176324 -1.06809,-2.250653 -1.93,-3.15 z m 27,-12.42 v 14.1 c -0.43264,-0.685249 -0.96517,-1.302051 -1.58,-1.83 -0.60967,-0.53196 -1.28117,-0.98858 -2,-1.36 -0.73088,-0.369676 -1.5029,-0.651634 -2.3,-0.84 -0.78611,-0.187908 -1.59174,-0.281898 -2.4,-0.28 -1.50724,-0.0078 -3.00162,0.277523 -4.4,0.84 -1.34071,0.551089 -2.56038,1.35967 -3.59,2.38 -1.03697,1.047216 -1.85907,2.287165 -2.42,3.65 -1.17023,2.996466 -1.17023,6.323534 0,9.32 0.55964,1.361695 1.37424,2.603955 2.4,3.66 1.02081,1.031107 2.2428,1.841226 3.59,2.38 1.40561,0.561607 2.90636,0.846817 4.42,0.84 0.80981,-0.0026 1.6161,-0.106786 2.4,-0.31 0.79636,-0.199929 1.56783,-0.488392 2.3,-0.86 0.72123,-0.371416 1.39312,-0.831661 2,-1.37 0.61025,-0.540083 1.14205,-1.162767 1.58,-1.85 v 4 h 3.33 V 15.59 Z m -0.37,24.58 c -1.76276,4.229524 -6.6195,6.23041 -10.85,4.47 v 0 c -0.97862,-0.401365 -1.86378,-1.000551 -2.6,-1.76 -0.7522,-0.76312 -1.34086,-1.671634 -1.73,-2.67 -0.41974,-1.066531 -0.63023,-2.203893 -0.62,-3.35 -0.0103,-1.129892 0.20027,-2.250911 0.62,-3.3 0.39328,-0.993283 0.98151,-1.897738 1.73,-2.66 0.74207,-0.76001 1.62521,-1.368023 2.6,-1.79 2.07874,-0.890012 4.43126,-0.890012 6.51,0 0.98149,0.434716 1.87338,1.048526 2.63,1.81 0.74927,0.763509 1.33458,1.672102 1.72,2.67 0.41464,1.036611 0.62516,2.14355 0.62,3.26 -1.3e-4,1.141508 -0.22084,2.272237 -0.65,3.33 z"
|
|
||||||
id="path2"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
style="fill:currentColor"
|
|
||||||
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" />
|
|
||||||
</symbol>
|
|
||||||
<use
|
|
||||||
xlink:href="#logo"
|
|
||||||
id="use5" />
|
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 4.7 KiB |
@@ -2,4 +2,5 @@ last 2 chrome versions
|
|||||||
last 2 firefox versions
|
last 2 firefox versions
|
||||||
last 2 safari versions
|
last 2 safari versions
|
||||||
last 2 edge versions
|
last 2 edge versions
|
||||||
|
edge 18
|
||||||
firefox esr
|
firefox esr
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# File Encryption
|
# File Encryption
|
||||||
|
|
||||||
Send use 128-bit AES-GCM encryption via the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) to encrypt files in the browser before uploading them to the server. The code is in [app/keychain.js](../app/keychain.js).
|
Send uses 128-bit AES-GCM encryption via the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) to encrypt files in the browser before uploading them to the server. The code is in [app/keychain.js](../app/keychain.js).
|
||||||
|
|
||||||
## Steps
|
## Steps
|
||||||
|
|
||||||
|
|||||||
1616
package-lock.json
generated
1616
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
17
package.json
17
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "send",
|
"name": "send",
|
||||||
"description": "File Sharing Experiment",
|
"description": "File Sharing Experiment",
|
||||||
"version": "3.1.0",
|
"version": "3.3.0",
|
||||||
"author": "Mozilla (https://mozilla.org)",
|
"author": "Mozilla (https://mozilla.org)",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
"Tim Visee <3a4fb3964f@sinenomine.email> (https://timvisee.com)"
|
"Tim Visee <3a4fb3964f@sinenomine.email> (https://timvisee.com)"
|
||||||
@@ -64,10 +64,10 @@
|
|||||||
"node": "^12.16.3"
|
"node": "^12.16.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.12.0",
|
"@babel/core": "^7.12.3",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.10.4",
|
"@babel/plugin-proposal-class-properties": "^7.12.1",
|
||||||
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
|
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
|
||||||
"@babel/preset-env": "^7.12.0",
|
"@babel/preset-env": "^7.12.1",
|
||||||
"@dannycoates/webcrypto-liner": "^0.1.37",
|
"@dannycoates/webcrypto-liner": "^0.1.37",
|
||||||
"@fullhuman/postcss-purgecss": "^1.3.0",
|
"@fullhuman/postcss-purgecss": "^1.3.0",
|
||||||
"@mattiasbuelens/web-streams-polyfill": "0.2.1",
|
"@mattiasbuelens/web-streams-polyfill": "0.2.1",
|
||||||
@@ -85,7 +85,7 @@
|
|||||||
"css-mqpacker": "^7.0.0",
|
"css-mqpacker": "^7.0.0",
|
||||||
"cssnano": "^4.1.10",
|
"cssnano": "^4.1.10",
|
||||||
"eslint": "^6.6.0",
|
"eslint": "^6.6.0",
|
||||||
"eslint-config-prettier": "^6.12.0",
|
"eslint-config-prettier": "^6.13.0",
|
||||||
"eslint-plugin-mocha": "^6.2.1",
|
"eslint-plugin-mocha": "^6.2.1",
|
||||||
"eslint-plugin-node": "^10.0.0",
|
"eslint-plugin-node": "^10.0.0",
|
||||||
"eslint-plugin-security": "^1.4.0",
|
"eslint-plugin-security": "^1.4.0",
|
||||||
@@ -123,7 +123,7 @@
|
|||||||
"stylelint-no-unsupported-browser-features": "^3.0.2",
|
"stylelint-no-unsupported-browser-features": "^3.0.2",
|
||||||
"svgo": "^1.3.2",
|
"svgo": "^1.3.2",
|
||||||
"svgo-loader": "^2.2.1",
|
"svgo-loader": "^2.2.1",
|
||||||
"tailwindcss": "^1.9.2",
|
"tailwindcss": "^1.9.4",
|
||||||
"val-loader": "^1.1.1",
|
"val-loader": "^1.1.1",
|
||||||
"webpack": "4.38.0",
|
"webpack": "4.38.0",
|
||||||
"webpack-cli": "^3.3.12",
|
"webpack-cli": "^3.3.12",
|
||||||
@@ -136,16 +136,15 @@
|
|||||||
"@dannycoates/express-ws": "^5.0.3",
|
"@dannycoates/express-ws": "^5.0.3",
|
||||||
"@fluent/bundle": "^0.13.0",
|
"@fluent/bundle": "^0.13.0",
|
||||||
"@fluent/langneg": "^0.3.0",
|
"@fluent/langneg": "^0.3.0",
|
||||||
"@google-cloud/storage": "^4.1.1",
|
"@google-cloud/storage": "^5.1.2",
|
||||||
"@sentry/node": "^5.26.0",
|
"@sentry/node": "^5.26.0",
|
||||||
"aws-sdk": "^2.771.0",
|
"aws-sdk": "^2.773.0",
|
||||||
"body-parser": "^1.19.0",
|
"body-parser": "^1.19.0",
|
||||||
"choo": "^7.0.0",
|
"choo": "^7.0.0",
|
||||||
"cldr-core": "^35.1.0",
|
"cldr-core": "^35.1.0",
|
||||||
"configstore": "github:dannycoates/configstore#master",
|
"configstore": "github:dannycoates/configstore#master",
|
||||||
"convict": "^5.2.0",
|
"convict": "^5.2.0",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"fxa-geodb": "^1.0.4",
|
|
||||||
"helmet": "^3.23.3",
|
"helmet": "^3.23.3",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"mozlog": "^2.2.0",
|
"mozlog": "^2.2.0",
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Comentarios
|
|
||||||
importingFile = Se ye importando…
|
importingFile = Se ye importando…
|
||||||
encryptingFile = Se ye cifrando…
|
encryptingFile = Se ye cifrando…
|
||||||
decryptingFile = Se ye descifrando…
|
decryptingFile = Se ye descifrando…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = فَيَرفُكس سِنْد
|
title = فَيَرفُكس سِنْد
|
||||||
siteFeedback = الانطباعات
|
|
||||||
importingFile = يستورد…
|
importingFile = يستورد…
|
||||||
encryptingFile = يعمّي…
|
encryptingFile = يعمّي…
|
||||||
decryptingFile = يفك التعمية…
|
decryptingFile = يفك التعمية…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Comentarios
|
|
||||||
importingFile = Importando...
|
importingFile = Importando...
|
||||||
encryptingFile = Cifrando...
|
encryptingFile = Cifrando...
|
||||||
decryptingFile = Descifrando...
|
decryptingFile = Descifrando...
|
||||||
@@ -107,7 +106,7 @@ tooManyArchives =
|
|||||||
*[other] Namái se permiten { $count } archivos
|
*[other] Namái se permiten { $count } archivos
|
||||||
}
|
}
|
||||||
expiredTitle = Esti enllaz caducó.
|
expiredTitle = Esti enllaz caducó.
|
||||||
notSupportedDescription = { -send-brand } nun va funcionar con esti restolador. { -send-short-brand } funciona meyor cola versión última de { -firefox } y cola versión actual de la mayoría de restoladores.
|
notSupportedDescription = { -send-brand } nun va funcionar con esti restolador. { -send-short-brand } funciona meyor cola última versión de { -firefox } y l'actual de la mayoría de restoladores.
|
||||||
downloadFirefox = Baxar { -firefox }
|
downloadFirefox = Baxar { -firefox }
|
||||||
legalTitle = Avisu de privacidá de { -send-short-brand }
|
legalTitle = Avisu de privacidá de { -send-short-brand }
|
||||||
legalDateStamp = Versión 1.0, con data del 12 de marzu de 2019
|
legalDateStamp = Versión 1.0, con data del 12 de marzu de 2019
|
||||||
@@ -131,8 +130,8 @@ accountBenefitLargeFiles = Comparti ficheros d'hasta { $size }
|
|||||||
accountBenefitDownloadCount = Comparti ficheros con más xente
|
accountBenefitDownloadCount = Comparti ficheros con más xente
|
||||||
accountBenefitTimeLimit =
|
accountBenefitTimeLimit =
|
||||||
{ $count ->
|
{ $count ->
|
||||||
[one] Caltén activos los enllaces demientres 1 día
|
[one] Caltién activos los enllaces demientres 1 día
|
||||||
*[other] Caltén activos los enllaces demientres { $count } díes
|
*[other] Caltién activos los enllaces demientres { $count } díes
|
||||||
}
|
}
|
||||||
accountBenefitSync = Xestiona los ficheros compartíos dende cualesquier preséu
|
accountBenefitSync = Xestiona los ficheros compartíos dende cualesquier preséu
|
||||||
accountBenefitMoz = Deprendi más tocante a otros servicios de { -mozilla }
|
accountBenefitMoz = Deprendi más tocante a otros servicios de { -mozilla }
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Geri dönüş
|
|
||||||
importingFile = İdxal edilir…
|
importingFile = İdxal edilir…
|
||||||
encryptingFile = Şifrələnir...
|
encryptingFile = Şifrələnir...
|
||||||
decryptingFile = Şifrə açılır...
|
decryptingFile = Şifrə açılır...
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Nikan uelis tikijkuilos tein tiknemilijtos
|
|
||||||
importingFile = Mokalakijtok…
|
importingFile = Mokalakijtok…
|
||||||
encryptingFile = Motatijtok…
|
encryptingFile = Motatijtok…
|
||||||
decryptingFile = Kichiujtok se uelis kiixtajtoltis ya…
|
decryptingFile = Kichiujtok se uelis kiixtajtoltis ya…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Водгук
|
|
||||||
importingFile = Імпартаванне...
|
importingFile = Імпартаванне...
|
||||||
encryptingFile = Зашыфроўка...
|
encryptingFile = Зашыфроўка...
|
||||||
decryptingFile = Расшыфроўка...
|
decryptingFile = Расшыфроўка...
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = প্রতিক্রিয়া
|
|
||||||
importingFile = ইম্পোর্ট হচ্ছে...
|
importingFile = ইম্পোর্ট হচ্ছে...
|
||||||
encryptingFile = ইনক্রিপট হচ্ছে...
|
encryptingFile = ইনক্রিপট হচ্ছে...
|
||||||
decryptingFile = ডিক্রিপট হচ্ছে...
|
decryptingFile = ডিক্রিপট হচ্ছে...
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Roit hoc'h ali
|
|
||||||
importingFile = Oc'h enporzhiañ …
|
importingFile = Oc'h enporzhiañ …
|
||||||
encryptingFile = Oc'h enrinegañ..
|
encryptingFile = Oc'h enrinegañ..
|
||||||
decryptingFile = Oc'h ezrinegañ...
|
decryptingFile = Oc'h ezrinegañ...
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteSubtitle = web eksperiment
|
siteSubtitle = web eksperiment
|
||||||
siteFeedback = Povratne informacije
|
|
||||||
uploadPageHeader = Privatno, šifrovano dijeljenje datoteka
|
uploadPageHeader = Privatno, šifrovano dijeljenje datoteka
|
||||||
uploadPageExplainer = Pošaljite datoteke putem sigurne, privatne i šifrovane veze koja automatski ističe kako bi se osiguralo da vaše stvari ne ostaju na mreži zauvijek.
|
uploadPageExplainer = Pošaljite datoteke putem sigurne, privatne i šifrovane veze koja automatski ističe kako bi se osiguralo da vaše stvari ne ostaju na mreži zauvijek.
|
||||||
uploadPageLearnMore = Saznajte više
|
uploadPageLearnMore = Saznajte više
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Comentaris
|
|
||||||
importingFile = S'està important…
|
importingFile = S'està important…
|
||||||
encryptingFile = S'està xifrant…
|
encryptingFile = S'està xifrant…
|
||||||
decryptingFile = S'està desxifrant…
|
decryptingFile = S'està desxifrant…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Rutzijol
|
|
||||||
importingFile = Tajin nijik…
|
importingFile = Tajin nijik…
|
||||||
encryptingFile = Tajin newäx rusik'ixik…
|
encryptingFile = Tajin newäx rusik'ixik…
|
||||||
decryptingFile = Tajin netamäx rusik'ixik...
|
decryptingFile = Tajin netamäx rusik'ixik...
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = ڕەخنەوپێشنیار
|
|
||||||
importingFile = هاوردەکردن...
|
importingFile = هاوردەکردن...
|
||||||
encryptingFile = بەهێماکردن...
|
encryptingFile = بەهێماکردن...
|
||||||
decryptingFile = هێمالابردن...
|
decryptingFile = هێمالابردن...
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Zpětná vazba
|
|
||||||
importingFile = Probíhá import…
|
importingFile = Probíhá import…
|
||||||
encryptingFile = Probíhá šifrování…
|
encryptingFile = Probíhá šifrování…
|
||||||
decryptingFile = Probíhá dešifrování…
|
decryptingFile = Probíhá dešifrování…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Adborth
|
|
||||||
importingFile = Mewnforio…
|
importingFile = Mewnforio…
|
||||||
encryptingFile = Wrthi'n amgryptio…
|
encryptingFile = Wrthi'n amgryptio…
|
||||||
decryptingFile = Wrthi'n dadgryptio…
|
decryptingFile = Wrthi'n dadgryptio…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Feedback
|
|
||||||
importingFile = Importerer…
|
importingFile = Importerer…
|
||||||
encryptingFile = Krypterer…
|
encryptingFile = Krypterer…
|
||||||
decryptingFile = Dekrypterer…
|
decryptingFile = Dekrypterer…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Feedback
|
|
||||||
importingFile = Wird importiert…
|
importingFile = Wird importiert…
|
||||||
encryptingFile = Wird verschlüsselt…
|
encryptingFile = Wird verschlüsselt…
|
||||||
decryptingFile = Wird entschlüsselt…
|
decryptingFile = Wird entschlüsselt…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Komentar
|
|
||||||
importingFile = Importěrujo se...
|
importingFile = Importěrujo se...
|
||||||
encryptingFile = Koděrujo se...
|
encryptingFile = Koděrujo se...
|
||||||
decryptingFile = Dešifrěrujo se...
|
decryptingFile = Dešifrěrujo se...
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Σχόλια
|
|
||||||
importingFile = Εισαγωγή…
|
importingFile = Εισαγωγή…
|
||||||
encryptingFile = Κρυπτογράφηση…
|
encryptingFile = Κρυπτογράφηση…
|
||||||
decryptingFile = Αποκρυπτογράφηση…
|
decryptingFile = Αποκρυπτογράφηση…
|
||||||
@@ -138,7 +137,7 @@ accountBenefitSync = Διαχειριστείτε τα διαμοιρασμέν
|
|||||||
accountBenefitMoz = Μάθετε για τις άλλες υπηρεσίες της { -mozilla }
|
accountBenefitMoz = Μάθετε για τις άλλες υπηρεσίες της { -mozilla }
|
||||||
signOut = Αποσύνδεση
|
signOut = Αποσύνδεση
|
||||||
okButton = OK
|
okButton = OK
|
||||||
downloadingTitle = Λήψη
|
downloadingTitle = Γίνεται λήψη
|
||||||
noStreamsWarning = Αυτό το πρόγραμμα περιήγησης ενδέχεται να μην μπορέσει να αποκρυπτογραφήσει αρχεία αυτού του μεγέθους.
|
noStreamsWarning = Αυτό το πρόγραμμα περιήγησης ενδέχεται να μην μπορέσει να αποκρυπτογραφήσει αρχεία αυτού του μεγέθους.
|
||||||
noStreamsOptionCopy = Αντιγράψτε το σύνδεσμο για άνοιγμα σε άλλο πρόγραμμα περιήγησης
|
noStreamsOptionCopy = Αντιγράψτε το σύνδεσμο για άνοιγμα σε άλλο πρόγραμμα περιήγησης
|
||||||
noStreamsOptionFirefox = Δοκιμάστε το αγαπημένο μας πρόγραμμα περιήγησης
|
noStreamsOptionFirefox = Δοκιμάστε το αγαπημένο μας πρόγραμμα περιήγησης
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Feedback
|
|
||||||
importingFile = Importing…
|
importingFile = Importing…
|
||||||
encryptingFile = Encrypting…
|
encryptingFile = Encrypting…
|
||||||
decryptingFile = Decrypting…
|
decryptingFile = Decrypting…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Feedback
|
|
||||||
importingFile = Importing…
|
importingFile = Importing…
|
||||||
encryptingFile = Encrypting…
|
encryptingFile = Encrypting…
|
||||||
decryptingFile = Decrypting…
|
decryptingFile = Decrypting…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Feedback
|
|
||||||
importingFile = Importing…
|
importingFile = Importing…
|
||||||
encryptingFile = Encrypting…
|
encryptingFile = Encrypting…
|
||||||
decryptingFile = Decrypting…
|
decryptingFile = Decrypting…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Opinión
|
|
||||||
importingFile = Importando…
|
importingFile = Importando…
|
||||||
encryptingFile = Cifrando…
|
encryptingFile = Cifrando…
|
||||||
decryptingFile = Descifrando…
|
decryptingFile = Descifrando…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Comentarios
|
|
||||||
importingFile = Importando…
|
importingFile = Importando…
|
||||||
encryptingFile = Cifrando…
|
encryptingFile = Cifrando…
|
||||||
decryptingFile = Descifrando…
|
decryptingFile = Descifrando…
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Comentario
|
|
||||||
importingFile = Importando...
|
importingFile = Importando...
|
||||||
encryptingFile = Encriptando...
|
encryptingFile = Cifrando...
|
||||||
decryptingFile = Desencriptando...
|
decryptingFile = Descifrando...
|
||||||
downloadCount =
|
downloadCount =
|
||||||
{ $num ->
|
{ $num ->
|
||||||
[one] 1 descarga
|
[one] 1 descarga
|
||||||
@@ -20,11 +19,11 @@ downloadButtonLabel = Descargar
|
|||||||
downloadFinish = Descarga completa
|
downloadFinish = Descarga completa
|
||||||
fileSizeProgress = ({ $partialSize } de { $totalSize })
|
fileSizeProgress = ({ $partialSize } de { $totalSize })
|
||||||
sendYourFilesLink = Prueba Send
|
sendYourFilesLink = Prueba Send
|
||||||
errorPageHeader = ¡Se produjo un error!
|
errorPageHeader = ¡Se ha producido un error!
|
||||||
fileTooBig = Ese archivo es muy grande. Debería ocupar menos de { $size }.
|
fileTooBig = Ese archivo es muy grande. Debería ocupar menos de { $size }.
|
||||||
linkExpiredAlt = Enlace caducado
|
linkExpiredAlt = Enlace caducado
|
||||||
notSupportedHeader = Tu navegador no está admitido.
|
notSupportedHeader = Tu navegador no es compatible.
|
||||||
notSupportedLink = ¿Por qué no se admite mi navegador?
|
notSupportedLink = ¿Por qué mi navegador no es compatible?
|
||||||
notSupportedOutdatedDetail = Lamentablemente, esta versión de Firefox no admite la tecnología web que impulsa Send. Tendrás que actualizar tu navegador.
|
notSupportedOutdatedDetail = Lamentablemente, esta versión de Firefox no admite la tecnología web que impulsa Send. Tendrás que actualizar tu navegador.
|
||||||
updateFirefox = Actualizar Firefox
|
updateFirefox = Actualizar Firefox
|
||||||
deletePopupCancel = Cancelar
|
deletePopupCancel = Cancelar
|
||||||
@@ -32,7 +31,7 @@ deleteButtonHover = Eliminar
|
|||||||
footerLinkLegal = Legal
|
footerLinkLegal = Legal
|
||||||
footerLinkPrivacy = Privacidad
|
footerLinkPrivacy = Privacidad
|
||||||
footerLinkCookies = Cookies
|
footerLinkCookies = Cookies
|
||||||
passwordTryAgain = Contraseña incorrecta. Inténtelo de nuevo.
|
passwordTryAgain = Contraseña incorrecta. Inténtalo de nuevo.
|
||||||
javascriptRequired = Send requiere JavaScript
|
javascriptRequired = Send requiere JavaScript
|
||||||
whyJavascript = ¿Por qué Send requiere JavaScript?
|
whyJavascript = ¿Por qué Send requiere JavaScript?
|
||||||
enableJavascript = Por favor, activa JavaScript y vuelve a intentarlo.
|
enableJavascript = Por favor, activa JavaScript y vuelve a intentarlo.
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Comentario
|
|
||||||
importingFile = Importando...
|
importingFile = Importando...
|
||||||
encryptingFile = Encriptando…
|
encryptingFile = Encriptando…
|
||||||
decryptingFile = Desencriptando…
|
decryptingFile = Desencriptando…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Tagasiside
|
|
||||||
importingFile = Importimine...
|
importingFile = Importimine...
|
||||||
encryptingFile = Krüptimine…
|
encryptingFile = Krüptimine…
|
||||||
decryptingFile = Dekrüptimine...
|
decryptingFile = Dekrüptimine...
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Iritzia
|
|
||||||
importingFile = Inportatzen…
|
importingFile = Inportatzen…
|
||||||
encryptingFile = Zifratzen...
|
encryptingFile = Zifratzen...
|
||||||
decryptingFile = Deszifratzen...
|
decryptingFile = Deszifratzen...
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = بازخورد
|
|
||||||
importingFile = در حال وارد کردن…
|
importingFile = در حال وارد کردن…
|
||||||
encryptingFile = در حال رمزنگاری…
|
encryptingFile = در حال رمزنگاری…
|
||||||
decryptingFile = در حال رمزگشایی…
|
decryptingFile = در حال رمزگشایی…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Palaute
|
|
||||||
importingFile = Tuodaan…
|
importingFile = Tuodaan…
|
||||||
encryptingFile = Salataan...
|
encryptingFile = Salataan...
|
||||||
decryptingFile = Puretaan salausta...
|
decryptingFile = Puretaan salausta...
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Votre avis
|
|
||||||
importingFile = Importation…
|
importingFile = Importation…
|
||||||
encryptingFile = Chiffrement…
|
encryptingFile = Chiffrement…
|
||||||
decryptingFile = Déchiffrement…
|
decryptingFile = Déchiffrement…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Kommentaar
|
|
||||||
importingFile = Ymportearje…
|
importingFile = Ymportearje…
|
||||||
encryptingFile = Fersiferje…
|
encryptingFile = Fersiferje…
|
||||||
decryptingFile = Untsiferje…
|
decryptingFile = Untsiferje…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Je’ejey
|
|
||||||
importingFile = Ojegueruhína…
|
importingFile = Ojegueruhína…
|
||||||
encryptingFile = Mo’ãmby…
|
encryptingFile = Mo’ãmby…
|
||||||
decryptingFile = Ñemo’ã’o…
|
decryptingFile = Ñemo’ã’o…
|
||||||
@@ -51,7 +50,7 @@ passwordSetError = Ndaikatúi oikóvo ko ñe’ẽñemi
|
|||||||
-send-short-brand = Send
|
-send-short-brand = Send
|
||||||
-firefox = Firefox
|
-firefox = Firefox
|
||||||
-mozilla = Mozilla
|
-mozilla = Mozilla
|
||||||
introTitle = Marandurenda ñemoambue hasy'ỹ ha ñemiguáva
|
introTitle = Marandurenda ñemoambue hasy’ỹ ha ñemiguáva
|
||||||
introDescription = { -send-brand } omoherakuãkuaa marandurenda papapýpe ñepyrũ guive opa peve ha juajuha opareíva ijehegui. Ikatu oreko ñemihápe emoherakuãva ha ehecháta mba’éicha ne mba’ekuéra noĩri ñandutípe opa ára.
|
introDescription = { -send-brand } omoherakuãkuaa marandurenda papapýpe ñepyrũ guive opa peve ha juajuha opareíva ijehegui. Ikatu oreko ñemihápe emoherakuãva ha ehecháta mba’éicha ne mba’ekuéra noĩri ñandutípe opa ára.
|
||||||
notifyUploadEncryptDone = Ne marandurenda oñemo’ã ha ikatúma emondo
|
notifyUploadEncryptDone = Ne marandurenda oñemo’ã ha ikatúma emondo
|
||||||
# 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'
|
||||||
@@ -135,7 +134,7 @@ accountBenefitTimeLimit =
|
|||||||
*[other] Eguereko juajuha hendyhápe { $count } ára
|
*[other] Eguereko juajuha hendyhápe { $count } ára
|
||||||
}
|
}
|
||||||
accountBenefitSync = Eñangareko marandurenda moherakuãmbyrére oimeraẽ mba’e’oka guive.
|
accountBenefitSync = Eñangareko marandurenda moherakuãmbyrére oimeraẽ mba’e’oka guive.
|
||||||
accountBenefitMoz = Eikuaa ambue { -mozilla } mba'epytyvõrã
|
accountBenefitMoz = Eikuaa ambue { -mozilla } mba’epytyvõrã
|
||||||
signOut = Emboty tembiapo
|
signOut = Emboty tembiapo
|
||||||
okButton = OK
|
okButton = OK
|
||||||
downloadingTitle = Oñemboguejyhína
|
downloadingTitle = Oñemboguejyhína
|
||||||
@@ -148,6 +147,6 @@ downloadFirefoxPromo = Ipyahúva { -firefox } ome’ẽse ndéve { -send-short-b
|
|||||||
shareLinkDescription = Emoherakuã juajuha ne mba’e’oka ndive:
|
shareLinkDescription = Emoherakuã juajuha ne mba’e’oka ndive:
|
||||||
shareLinkButton = Emoherakuã juajuha
|
shareLinkButton = Emoherakuã juajuha
|
||||||
# $name is the name of the file
|
# $name is the name of the file
|
||||||
shareMessage = Emboguejy “{ $name }” { -send-brand } ndive: emoherakuã marandurenda tasy'ỹ ha tekorosãme
|
shareMessage = Emboguejy “{ $name }” { -send-brand } ndive: emoherakuã marandurenda tasy’ỹ ha tekorosãme
|
||||||
trailheadPromo = Mba’éichapa emo’ãta ne ñemigua. Eipuru Firefox.
|
trailheadPromo = Mba’éichapa emo’ãta ne ñemigua. Eipuru Firefox.
|
||||||
learnMore = Kuaave.
|
learnMore = Kuaave.
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
title = Molawo
|
title = Molawo
|
||||||
siteSubtitle = web yimontalo
|
siteSubtitle = web yimontalo
|
||||||
siteFeedback = Potunu
|
|
||||||
uploadPageLearnMore = Pobalajariya po'olo
|
uploadPageLearnMore = Pobalajariya po'olo
|
||||||
uploadPageBrowseButton = Tulawota berkas to delomo komputermu
|
uploadPageBrowseButton = Tulawota berkas to delomo komputermu
|
||||||
uploadPageBrowseButton1 = Tulawota berkas u detohulo
|
uploadPageBrowseButton1 = Tulawota berkas u detohulo
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = משוב
|
|
||||||
importingFile = מתבצע ייבוא…
|
importingFile = מתבצע ייבוא…
|
||||||
encryptingFile = מתבצעת הצפנה...
|
encryptingFile = מתבצעת הצפנה...
|
||||||
decryptingFile = מתבצע פענוח...
|
decryptingFile = מתבצע פענוח...
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Povratne informacije
|
|
||||||
importingFile = Uvoz…
|
importingFile = Uvoz…
|
||||||
encryptingFile = Šifriranje …
|
encryptingFile = Šifriranje …
|
||||||
decryptingFile = Dešifriranje …
|
decryptingFile = Dešifriranje …
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Komentar
|
|
||||||
importingFile = Importuje so...
|
importingFile = Importuje so...
|
||||||
encryptingFile = Zaklučuje so...
|
encryptingFile = Zaklučuje so...
|
||||||
decryptingFile = Dešifruje so...
|
decryptingFile = Dešifruje so...
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Visszajelzés
|
|
||||||
importingFile = Importálás…
|
importingFile = Importálás…
|
||||||
encryptingFile = Titkosítás…
|
encryptingFile = Titkosítás…
|
||||||
decryptingFile = Visszafejtés…
|
decryptingFile = Visszafejtés…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Ka olna' max jant'oj yab u t'ojnal alwa'
|
|
||||||
importingFile = k'wajat i chiyál...
|
importingFile = k'wajat i chiyál...
|
||||||
encryptingFile = K'wajat i tsinat dheyál...
|
encryptingFile = K'wajat i tsinat dheyál...
|
||||||
decryptingFile = K'wajat i exal ki wila'...
|
decryptingFile = K'wajat i exal ki wila'...
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Արձագանք
|
|
||||||
importingFile = Ներմուծում...
|
importingFile = Ներմուծում...
|
||||||
encryptingFile = Գաղտնագրում…
|
encryptingFile = Գաղտնագրում…
|
||||||
decryptingFile = Վերծանում…
|
decryptingFile = Վերծանում…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Reaction
|
|
||||||
importingFile = Importation…
|
importingFile = Importation…
|
||||||
encryptingFile = Cryptation...
|
encryptingFile = Cryptation...
|
||||||
decryptingFile = Decryptation…
|
decryptingFile = Decryptation…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Saran
|
|
||||||
importingFile = Mengimpor…
|
importingFile = Mengimpor…
|
||||||
encryptingFile = Mengenkripsi...
|
encryptingFile = Mengenkripsi...
|
||||||
decryptingFile = Mendekripsi...
|
decryptingFile = Mendekripsi...
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
# Send is a brand name and should not be localized.
|
|
||||||
title = Zipu
|
title = Zipu
|
||||||
siteFeedback = Nzaghachi
|
|
||||||
importingFile = Mbubata…
|
importingFile = Mbubata…
|
||||||
encryptingFile = ezoro ezo...
|
encryptingFile = ezoro ezo...
|
||||||
decryptingFile = Kpebie
|
decryptingFile = Kpebie
|
||||||
@@ -30,7 +28,12 @@ notSupportedOutdatedDetail = Ọ dị nwute na ụdị Firefox a anaghị akwado
|
|||||||
updateFirefox = Melite Firefox
|
updateFirefox = Melite Firefox
|
||||||
deletePopupCancel = Kagbuo
|
deletePopupCancel = Kagbuo
|
||||||
deleteButtonHover = Hichapụ
|
deleteButtonHover = Hichapụ
|
||||||
whyJavascript = Kedu ihe kpatara Send jiri chọ JavaScript?
|
footerLinkLegal = n'Iwu
|
||||||
|
footerLinkPrivacy = nzuzo
|
||||||
|
footerLinkCookies = Kuki ga
|
||||||
|
passwordTryAgain = okwuntughe ezighi ezi.Nwaa ọzọ
|
||||||
|
javascriptRequired = Zipu chọrọ
|
||||||
|
whyJavascript = Kedu ihe kpatara Zipu jiri chọ JavaScript?
|
||||||
enableJavascript = Biko họrọ JavaScript ma nwaa ọzọ
|
enableJavascript = Biko họrọ JavaScript ma nwaa ọzọ
|
||||||
# A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
# A short representation of a countdown timer containing the number of hours and minutes remaining as digits, example "13h 47m"
|
||||||
expiresHoursMinutes = { $hours }h { $minutes }m
|
expiresHoursMinutes = { $hours }h { $minutes }m
|
||||||
@@ -43,11 +46,12 @@ passwordSetError = Enweghị ike ịtọ paswọọdụ a
|
|||||||
|
|
||||||
## Send version 2 strings
|
## Send version 2 strings
|
||||||
|
|
||||||
-send-brand = Send
|
-send-brand = Zipu
|
||||||
-send-short-brand = Zipu, Ziga
|
-send-short-brand = Zipu, Ziga
|
||||||
-firefox = Firefox
|
-firefox = Firefox
|
||||||
-mozilla = Mozilla
|
-mozilla = Mozilla
|
||||||
introTitle = Mfe, nkekọrịta faịlụ nkeonwe
|
introTitle = Mfe, nkekọrịta faịlụ nkeonwe
|
||||||
|
introDescription = na-ahapu gị ịkekọrịta faịlụ na izo ya na njedebe na njedebe na-akwụsị na akpaghị aka. Yabụ ị nwere ike idobe ihe ị na -eche ma hụ na ngwongwo gị agaghị adị n'ịntanetị ruo mgbe ebighi ebi.
|
||||||
notifyUploadEncryptDone = Failu gi zoro ezo ma di njikere iziga
|
notifyUploadEncryptDone = Failu gi zoro ezo ma di njikere iziga
|
||||||
# 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 = Ọ ga-agwu mgbe { $downloadCount } ma ọ bụ { $timespan } gasịrị
|
archiveExpiryInfo = Ọ ga-agwu mgbe { $downloadCount } ma ọ bụ { $timespan } gasịrị
|
||||||
@@ -61,4 +65,27 @@ timespanWeeks =
|
|||||||
[one] 1 izu
|
[one] 1 izu
|
||||||
*[other] izu { $num }
|
*[other] izu { $num }
|
||||||
}
|
}
|
||||||
|
# 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 = { $Number } { $nkeji }
|
||||||
|
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
|
||||||
|
totalSize = { $nha }
|
||||||
|
# the next line after the colon contains a file name
|
||||||
|
copyLinkDescription = Detuo njikọ ahụ iji kee faịlụ gị
|
||||||
|
copyLinkButton = Detuo njikọ
|
||||||
|
downloadTitle = Budata faịlụ gasi
|
||||||
|
downloadDescription = Nkekọrịta faịlụ a site na site na iji zoo njedebe na-njedebe yana otu njikọ na-akwụsị na-akpaghị aka.
|
||||||
|
trySendDescription = Gbalịa maka nyefe faịlụ dị mfe.
|
||||||
|
expiredTitle = Njikọ a emebiela.
|
||||||
|
notSupportedDescription = agaghị eji ihe nchọgharị a rụọ ọrụ. na arụ ọrụ kacha mma na ụdị nke , ọ ga-arụkwa ụdị nke ihe nchọgharị ka ugbu a.
|
||||||
|
downloadFirefox = Budata
|
||||||
|
legalTitle = Nkwupụta Nzuzo
|
||||||
|
legalDateStamp = 1.dị 1.0, akara ụbọchị Maachi 12, 2019
|
||||||
okButton = O
|
okButton = O
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Feedback
|
|
||||||
importingFile = Importazione in corso…
|
importingFile = Importazione in corso…
|
||||||
encryptingFile = Crittazione in corso…
|
encryptingFile = Crittazione in corso…
|
||||||
decryptingFile = Decrittazione in corso…
|
decryptingFile = Decrittazione in corso…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Aq'a yol sti'
|
|
||||||
importingFile = Eq'otzan
|
importingFile = Eq'otzan
|
||||||
encryptingFile = La muj isik'lele
|
encryptingFile = La muj isik'lele
|
||||||
decryptingFile = Ni jaj ve't isik'lele'
|
decryptingFile = Ni jaj ve't isik'lele'
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = フィードバック
|
|
||||||
importingFile = インポート中...
|
importingFile = インポート中...
|
||||||
encryptingFile = 暗号化中...
|
encryptingFile = 暗号化中...
|
||||||
decryptingFile = 復号化中...
|
decryptingFile = 復号化中...
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = გამოხმაურება
|
|
||||||
importingFile = გადმოტანა...
|
importingFile = გადმოტანა...
|
||||||
encryptingFile = დაშიფვრა...
|
encryptingFile = დაშიფვრა...
|
||||||
decryptingFile = გაშიფვრა...
|
decryptingFile = გაშიფვრა...
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Tikti
|
|
||||||
importingFile = Akter...
|
importingFile = Akter...
|
||||||
encryptingFile = Awgelhen...
|
encryptingFile = Awgelhen...
|
||||||
decryptingFile = Azmek...
|
decryptingFile = Azmek...
|
||||||
@@ -74,7 +73,7 @@ timespanWeeks =
|
|||||||
fileCount =
|
fileCount =
|
||||||
{ $num ->
|
{ $num ->
|
||||||
[one] 1 n ufaylu
|
[one] 1 n ufaylu
|
||||||
*[other] { $num } n ifuyla
|
*[other] { $num } n yifuyla
|
||||||
}
|
}
|
||||||
# byte abbreviation
|
# byte abbreviation
|
||||||
bytes = B
|
bytes = B
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
# Send is a brand name and should not be localized.
|
# Send is a brand name and should not be localized.
|
||||||
title = Send
|
title = Send
|
||||||
siteFeedback = 사용자 의견
|
|
||||||
importingFile = 가져오는 중…
|
importingFile = 가져오는 중…
|
||||||
encryptingFile = 암호화 중…
|
encryptingFile = 암호화 중…
|
||||||
decryptingFile = 복호화 중…
|
decryptingFile = 복호화 중…
|
||||||
@@ -96,7 +95,7 @@ tooManyArchives =
|
|||||||
expiredTitle = 이 링크는 만료되었습니다.
|
expiredTitle = 이 링크는 만료되었습니다.
|
||||||
notSupportedDescription = { -send-brand }는 이 브라우저와 작동하지 않습니다. { -send-short-brand }는 최신 { -firefox }와 가장 잘 작동하며, 대부분의 최신 웹 브라우저와도 잘 작동합니다.
|
notSupportedDescription = { -send-brand }는 이 브라우저와 작동하지 않습니다. { -send-short-brand }는 최신 { -firefox }와 가장 잘 작동하며, 대부분의 최신 웹 브라우저와도 잘 작동합니다.
|
||||||
downloadFirefox = { -firefox } 다운로드
|
downloadFirefox = { -firefox } 다운로드
|
||||||
legalTitle = { -send-short-brand } 개인정보 보호 공지
|
legalTitle = { -send-short-brand } 개인정보처리방침
|
||||||
legalDateStamp = 버전 1.0, 2019년 3월 12일자
|
legalDateStamp = 버전 1.0, 2019년 3월 12일자
|
||||||
# A short representation of a countdown timer containing the number of days, hours, and minutes remaining as digits, example "2d 11h 56m"
|
# A short representation of a countdown timer containing the number of days, hours, and minutes remaining as digits, example "2d 11h 56m"
|
||||||
expiresDaysHoursMinutes = { $days }일 { $hours }시간 { $minutes }분
|
expiresDaysHoursMinutes = { $days }일 { $hours }시간 { $minutes }분
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Pateikti atsiliepimą
|
|
||||||
importingFile = Importuojama…
|
importingFile = Importuojama…
|
||||||
encryptingFile = Šifruojama…
|
encryptingFile = Šifruojama…
|
||||||
decryptingFile = Iššifruojama…
|
decryptingFile = Iššifruojama…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Tu'un jianininu
|
|
||||||
importingFile = Nasia´a…
|
importingFile = Nasia´a…
|
||||||
encryptingFile = Encriptando...
|
encryptingFile = Encriptando...
|
||||||
decryptingFile = Desencriptando…
|
decryptingFile = Desencriptando…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Tu'un meu
|
|
||||||
importingFile = Ndakiin…
|
importingFile = Ndakiin…
|
||||||
encryptingFile = Ndasami tu'un…
|
encryptingFile = Ndasami tu'un…
|
||||||
decryptingFile = Nchiko tu'un…
|
decryptingFile = Nchiko tu'un…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = ഫയർഫോക്സ് സെൻഡ്
|
title = ഫയർഫോക്സ് സെൻഡ്
|
||||||
siteFeedback = പ്രതികരണം
|
|
||||||
importingFile = ഇറക്കുമതി ചെയ്യുന്നു...
|
importingFile = ഇറക്കുമതി ചെയ്യുന്നു...
|
||||||
encryptingFile = എൻക്രിപ്റ്റ് ചെയ്യുന്നു...
|
encryptingFile = എൻക്രിപ്റ്റ് ചെയ്യുന്നു...
|
||||||
decryptingFile = ഡീക്രിപ്റ്റ് ചെയ്യുന്നു...
|
decryptingFile = ഡീക്രിപ്റ്റ് ചെയ്യുന്നു...
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteSubtitle = experimen web
|
siteSubtitle = experimen web
|
||||||
siteFeedback = Maklum balas
|
|
||||||
uploadPageHeader = Peribadi, Perkongsian Fail Dienkrip
|
uploadPageHeader = Peribadi, Perkongsian Fail Dienkrip
|
||||||
uploadPageExplainer = Hantar fail melalui pautan yang selamat, peribadi dan dienkrip, yang akan luput secara automatik untuk memastikan fail anda itu tidak terus berada dalam talian selama-lamanya.
|
uploadPageExplainer = Hantar fail melalui pautan yang selamat, peribadi dan dienkrip, yang akan luput secara automatik untuk memastikan fail anda itu tidak terus berada dalam talian selama-lamanya.
|
||||||
uploadPageLearnMore = Ketahui selanjutnya
|
uploadPageLearnMore = Ketahui selanjutnya
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Tilbakemelding
|
|
||||||
importingFile = Importerer…
|
importingFile = Importerer…
|
||||||
encryptingFile = Krypterer...
|
encryptingFile = Krypterer...
|
||||||
decryptingFile = Dekrypterer...
|
decryptingFile = Dekrypterer...
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Feedback
|
|
||||||
importingFile = Importeren…
|
importingFile = Importeren…
|
||||||
encryptingFile = Versleutelen…
|
encryptingFile = Versleutelen…
|
||||||
decryptingFile = Ontcijferen…
|
decryptingFile = Ontsleutelen…
|
||||||
downloadCount =
|
downloadCount =
|
||||||
{ $num ->
|
{ $num ->
|
||||||
[one] 1 download
|
[one] 1 download
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Tilbakemelding
|
|
||||||
importingFile = Importerer…
|
importingFile = Importerer…
|
||||||
encryptingFile = Krypterer…
|
encryptingFile = Krypterer…
|
||||||
decryptingFile = Dekrypterer...
|
decryptingFile = Dekrypterer...
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Comentaris
|
|
||||||
importingFile = Importacion…
|
importingFile = Importacion…
|
||||||
encryptingFile = Chiframent…
|
encryptingFile = Chiframent…
|
||||||
decryptingFile = Deschiframent…
|
decryptingFile = Deschiframent…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = ਸੁਝਾਅ
|
|
||||||
importingFile = ...ਦਰਾਮਦ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ
|
importingFile = ...ਦਰਾਮਦ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ
|
||||||
encryptingFile = ...ਇੰਕ੍ਰਿਪਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ
|
encryptingFile = ...ਇੰਕ੍ਰਿਪਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ
|
||||||
decryptingFile = ...ਡਿਕ੍ਰਿਪਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ
|
decryptingFile = ...ਡਿਕ੍ਰਿਪਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
siteFeedback = Tkweek uk kabyuwuha
|
|
||||||
|
|
||||||
## Send version 2 strings
|
## Send version 2 strings
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Wyślij opinię
|
|
||||||
importingFile = Importowanie…
|
importingFile = Importowanie…
|
||||||
encryptingFile = Szyfrowanie…
|
encryptingFile = Szyfrowanie…
|
||||||
decryptingFile = Odszyfrowywanie…
|
decryptingFile = Odszyfrowywanie…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Shitechnawati
|
|
||||||
importingFile = Mukalaktia nemi…
|
importingFile = Mukalaktia nemi…
|
||||||
encryptingFile = Tikichtakawiat tinemit…
|
encryptingFile = Tikichtakawiat tinemit…
|
||||||
decryptingFile = Tikichtakapuat tinemit…
|
decryptingFile = Tikichtakapuat tinemit…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Opinião
|
|
||||||
importingFile = Importando…
|
importingFile = Importando…
|
||||||
encryptingFile = Criptografando…
|
encryptingFile = Criptografando…
|
||||||
decryptingFile = Descriptografando…
|
decryptingFile = Descriptografando…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Feedback
|
|
||||||
importingFile = A importar...
|
importingFile = A importar...
|
||||||
encryptingFile = A encriptar...
|
encryptingFile = A encriptar...
|
||||||
decryptingFile = A desencriptar...
|
decryptingFile = A desencriptar...
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Utzijoxik
|
|
||||||
importingFile = Ujek'ik…
|
importingFile = Ujek'ik…
|
||||||
encryptingFile = Uwiqik…
|
encryptingFile = Uwiqik…
|
||||||
decryptingFile = Usolik…
|
decryptingFile = Usolik…
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
title = Send
|
title = Send
|
||||||
siteFeedback = Feedback
|
|
||||||
importingFile = Se importă…
|
importingFile = Se importă…
|
||||||
encryptingFile = Se criptează…
|
encryptingFile = Se criptează…
|
||||||
decryptingFile = Se decriptează…
|
decryptingFile = Se decriptează…
|
||||||
@@ -158,5 +157,5 @@ shareLinkDescription = Partajează linkul către fișier:
|
|||||||
shareLinkButton = Partajează linkul
|
shareLinkButton = Partajează linkul
|
||||||
# $name is the name of the file
|
# $name is the name of the file
|
||||||
shareMessage = Descarcă „{ $name }” cu { -send-brand }: partajare simplă și sigură a fișierelor
|
shareMessage = Descarcă „{ $name }” cu { -send-brand }: partajare simplă și sigură a fișierelor
|
||||||
trailheadPromo = Există o modalitate de a-ți proteja viața privată. Alătură-te Firefox.
|
trailheadPromo = Există o modalitate de a-ți proteja viața privată. Folosește Firefox.
|
||||||
learnMore = Află mai multe.
|
learnMore = Află mai multe.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user