Compare commits

...

196 commits

Author SHA1 Message Date
timvisee
e0a3d2bf2c
Bump version to 3.4.27 2025-07-01 08:50:51 +02:00
timvisee
b93256316b
Move icon styles into stylesheet 2025-07-01 08:50:18 +02:00
timvisee
8a82e53e82
Bump version to 3.4.26 2025-06-30 23:51:56 +02:00
Tim Visée
6215bb1555 Merge branch 'add-thunderbird-sponsor-banner' into 'master'
Add Thunderbird sponsor banner

See merge request timvisee/send!37
2025-06-30 23:50:14 +02:00
timvisee
d7e929a0d1
Merge branch 'master' of github.com:timvisee/send 2025-06-30 23:30:05 +02:00
timvisee
154a8a90c1
Add sponsored by Thunderbird label to translations 2025-06-30 23:25:51 +02:00
timvisee
0a6bf39353
Add Thunderbird sponsorship banner to home, uploads and download page 2025-06-30 23:12:54 +02:00
Raymond Hear
c0cf7bbda2 fix: use Authorization header 2025-05-23 17:30:29 +02:00
timvisee
197b0bcf59
Update contribute.json 2025-04-23 21:01:10 +02:00
timvisee
56a0e830bd
Bump version to 3.4.25 2025-04-23 10:47:15 +02:00
timvisee
b3317df707
Move main notice on top of text 2025-04-23 10:46:26 +02:00
Tim Visée
9931074905 Merge branch 'more-customizable-notices' into 'master'
More customizable notices

See merge request timvisee/send!36
2025-04-23 10:37:44 +02:00
timvisee
0088a4ccc0
Add class to underline text 2025-04-23 10:12:16 +02:00
timvisee
11aad6eac5
Rename downloads list to uploads list 2025-04-23 10:09:51 +02:00
timvisee
1fb2f45285
Rename existing warnings to notices 2025-04-23 10:08:11 +02:00
timvisee
d0f21e8078
Add customizable notice on main page and in downloads list 2025-04-23 10:07:40 +02:00
timvisee
c71100c82a
Bump version to 3.4.24 2025-04-22 22:03:29 +02:00
Tim Visée
4f2dd96708 Merge branch 'update-dependencies' into 'master'
Update dependencies

See merge request timvisee/send!35
2025-04-22 21:59:01 +02:00
Tim Visée
d8456c2c51 Merge branch 'add-custom-upload-download-warnings' into 'master'
Add customizable warnings shown on upload and download pages

See merge request timvisee/send!34
2025-04-22 21:55:25 +02:00
timvisee
b7324f3a5b
Update dependencies 2025-04-22 21:35:39 +02:00
timvisee
6890165f67
Add customizable warnings shown on upload and download pages 2025-04-22 21:31:23 +02:00
Tim Visée
5124572dba Merge branch 'fix-node-18-crypto' into 'master'
Fix build failure due to crypto when using Node 18 or higher

See merge request timvisee/send!33
2025-02-04 19:32:41 +00:00
timvisee
0c1819bb15
Fix build failure due to crypto when using Node 18 or higher 2025-02-04 20:08:03 +01:00
LOLSALT
906990991e Update send.ftl 2024-12-20 11:34:42 +01:00
LOLSALT
48bdf734c5 Update send.ftl 2024-12-20 11:34:42 +01:00
LOLSALT
cf63e0e804 Update send.ftl 2024-12-20 11:34:42 +01:00
LOLSALT
ec66c2dc4e Update send.ftl 2024-12-20 11:34:42 +01:00
LOLSALT
67dfc94ef3 Update send.ftl 2024-12-20 11:34:42 +01:00
Filip Znachor
f54f3ccaa2 Update CS send.ftl
Improved Czech translations
2024-04-19 12:12:13 +02:00
DeAlexPesh
a35e2e58a3 Update RU send.ftl 2024-03-13 17:14:17 +01:00
Tim Visée
6ad2885a16 Merge branch 'aron9861623-master-patch-24529' into 'master'
Fixed docker.md first example

See merge request timvisee/send!32
2023-06-09 13:31:51 +00:00
Aron Tecsi
70662888b1 Fixed docker.md first example 2023-06-09 11:19:42 +00:00
timvisee
9f09a79986
Merge branch 'emilstahl-patch-1' into master
See https://github.com/timvisee/send/pull/149
2023-02-27 21:45:59 +01:00
Emil Stahl
db64c0467a
Small typo 2023-02-27 21:02:53 +01:00
Tim Visée
ca52f84aa5 Merge branch 'master' into 'master'
Add build for arm64v8

See merge request timvisee/send!27
2023-02-22 11:40:25 +00:00
timvisee
6fff664947
Bump version to 3.4.23 2023-02-14 13:42:39 +01:00
timvisee
439ac0ab7c
Update dependencies 2023-02-14 13:41:10 +01:00
timvisee
dee6b3e9cc
Merge branch 'tdulcet-passphrase' into master
See https://github.com/timvisee/send/pull/147
2023-02-14 13:38:30 +01:00
Teal Dulcet
dc9d072472 Increased password length limit to support passphrases. 2023-02-14 04:36:19 -08:00
simepy
91773832c1 Updated from timvisee/send master 2023-02-03 14:29:30 +01:00
timvisee
65730db0db
Bump version to 3.4.22 2023-01-16 17:23:07 +01:00
timvisee
a86221b1cc
Update dependencies 2023-01-16 17:00:14 +01:00
dependabot[bot]
bcc53f73c6
Bump decode-uri-component from 0.2.0 to 0.2.2
Bumps [decode-uri-component](https://github.com/SamVerschueren/decode-uri-component) from 0.2.0 to 0.2.2.
- [Release notes](https://github.com/SamVerschueren/decode-uri-component/releases)
- [Commits](https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.0...v0.2.2)

---
updated-dependencies:
- dependency-name: decode-uri-component
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-11 11:27:01 +00:00
dependabot[bot]
b0444f488b
Bump convict from 6.2.3 to 6.2.4
Bumps [convict](https://github.com/mozilla/node-convict) from 6.2.3 to 6.2.4.
- [Release notes](https://github.com/mozilla/node-convict/releases)
- [Changelog](https://github.com/mozilla/node-convict/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mozilla/node-convict/commits)

---
updated-dependencies:
- dependency-name: convict
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-10 22:22:09 +00:00
Tim Visée
70a11e5300 Merge branch 'reset-dlimit-to-default' into 'master'
Reset download limit to default after uploading files

See merge request timvisee/send!30
2023-01-10 20:50:13 +00:00
Jun Omae
f62a99882d Reset download limit to default after uplaoding files 2023-01-06 17:42:45 +09:00
timvisee
309c7d63ac
Change GitLab CI test image to node 16, add missing packages for testing 2022-12-20 20:04:45 +01:00
dependabot[bot]
1d75366f66
Bump loader-utils from 1.4.1 to 1.4.2
Bumps [loader-utils](https://github.com/webpack/loader-utils) from 1.4.1 to 1.4.2.
- [Release notes](https://github.com/webpack/loader-utils/releases)
- [Changelog](https://github.com/webpack/loader-utils/blob/v1.4.2/CHANGELOG.md)
- [Commits](https://github.com/webpack/loader-utils/compare/v1.4.1...v1.4.2)

---
updated-dependencies:
- dependency-name: loader-utils
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-18 00:43:28 +00:00
timvisee
0a849fb7c6
Revert "Bump node-forge and webpack-dev-server"
This reverts commit 88725df09d.
2022-11-14 19:43:09 +01:00
dependabot[bot]
88725df09d
Bump node-forge and webpack-dev-server
Bumps [node-forge](https://github.com/digitalbazaar/forge) to 1.3.1 and updates ancestor dependency [webpack-dev-server](https://github.com/webpack/webpack-dev-server). These dependencies need to be updated together.


Updates `node-forge` from 0.10.0 to 1.3.1
- [Release notes](https://github.com/digitalbazaar/forge/releases)
- [Changelog](https://github.com/digitalbazaar/forge/blob/main/CHANGELOG.md)
- [Commits](https://github.com/digitalbazaar/forge/compare/0.10.0...v1.3.1)

Updates `webpack-dev-server` from 3.11.3 to 4.11.1
- [Release notes](https://github.com/webpack/webpack-dev-server/releases)
- [Changelog](https://github.com/webpack/webpack-dev-server/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-dev-server/compare/v3.11.3...v4.11.1)

---
updated-dependencies:
- dependency-name: node-forge
  dependency-type: indirect
- dependency-name: webpack-dev-server
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-14 18:35:44 +00:00
dependabot[bot]
5a92e7e5e7
Bump minimatch and mocha
Bumps [minimatch](https://github.com/isaacs/minimatch) to 3.1.2 and updates ancestor dependency [mocha](https://github.com/mochajs/mocha). These dependencies need to be updated together.


Updates `minimatch` from 3.0.4 to 3.1.2
- [Release notes](https://github.com/isaacs/minimatch/releases)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.0.4...v3.1.2)

Updates `mocha` from 6.2.3 to 10.1.0
- [Release notes](https://github.com/mochajs/mocha/releases)
- [Changelog](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mochajs/mocha/compare/v6.2.3...v10.1.0)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-type: indirect
- dependency-name: mocha
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-14 18:32:13 +00:00
dependabot[bot]
71541fc2b6
Bump loader-utils from 1.4.0 to 1.4.1
Bumps [loader-utils](https://github.com/webpack/loader-utils) from 1.4.0 to 1.4.1.
- [Release notes](https://github.com/webpack/loader-utils/releases)
- [Changelog](https://github.com/webpack/loader-utils/blob/v1.4.1/CHANGELOG.md)
- [Commits](https://github.com/webpack/loader-utils/compare/v1.4.0...v1.4.1)

---
updated-dependencies:
- dependency-name: loader-utils
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-09 03:16:30 +00:00
Simon PERA
c524804c63 Add build for arm64v8 2022-10-25 19:08:27 +02:00
timvisee
5b4c0d2540
Merge branch 'JoshAtticus-patch-1' into master
See https://github.com/timvisee/send/pull/115
2022-10-05 16:05:01 +02:00
Josh
e7f3c91d0b
Update config.js 2022-09-19 15:46:47 +08:00
Josh
8bb198b73e
Remove firefox link 2022-09-17 12:33:03 +08:00
Tim Visée
9e188bc76c Merge branch 'registry-credentials' into 'master'
Refactor CI

See merge request timvisee/send!26
2022-09-14 14:37:33 +00:00
Marian Hähnlein
1353a54c49
Refactor CI 2022-09-12 13:53:00 +02:00
Tim Visée
4ae007167d Merge branch 'custom-css-undefined' into 'master'
Change default value for custom css to empty string

See merge request timvisee/send!25
2022-09-09 12:34:16 +00:00
Marian Hähnlein
660f36e584
Change default value for custom css to empty string 2022-09-08 14:16:00 +02:00
timvisee
3dede083cd
Bump version to 3.4.21 2022-09-04 12:48:04 +02:00
timvisee
26e81455ff
Update dependencies 2022-09-04 12:47:40 +02:00
timvisee
4ceac20623
Revert "Remove some polyfills"
This reverts commit 64644b57e3.
2022-09-04 12:26:12 +02:00
timvisee
073accfe65
Revert "Update eslint & plugins"
This reverts commit 38746b86fd.
2022-09-04 12:26:10 +02:00
timvisee
6306a433e8
Revert "More dependency cleanups"
This reverts commit e1d6224570.
2022-09-04 12:26:09 +02:00
timvisee
1da317bcc1
Revert "Further dependency cleanup"
This reverts commit 1725ff434e.
2022-09-04 12:26:07 +02:00
timvisee
08f597405c
Revert "Remove double-ended-queue"
This reverts commit 9b8b11ffc3.
2022-09-04 12:26:05 +02:00
timvisee
c624766edc
Revert "Remove asmcrypto.js"
This reverts commit c619be58ae.
2022-09-04 12:26:03 +02:00
Tim Visée
e030c46a9c Merge branch 'fix-csp' into 'master'
Fix CSP

Closes #29

See merge request timvisee/send!24
2022-08-22 15:27:03 +00:00
Marian Hähnlein
d081affa38
Move injection of custom CSS from client to server 2022-08-19 13:17:59 +02:00
Marian Hähnlein
71372fcbc1
Replace tabs with spaces to maintain consistency 2022-08-19 13:11:30 +02:00
HrBingR
671390ca24 Added the ability for a user to define and set a custom locale
New environment variable CUSTOM_LOCALE allows a user to define a locale per the /public/locales directory (this should be listed in the docs, will create a pull request for that too).

If the environment variable is blank or invalid it reverts to previous behaviour of system + default locale. Fully tested the above as follows:

CUSTOM_LOCALE = 'nl' < This works correctly, translating to nl.
CUSTOM_LOCALE = 'HelloThere' < This reverts to previous behavior
CUSTOM_LOCALE = '' < Also reverts
#CUSTOM_LOCALE = < Also reverts
2022-08-13 02:25:19 +02:00
HrBingR
9221b86660
Merge branch 'timvisee:master' into master 2022-08-13 02:20:33 +02:00
HrBingR
fd2e954b3e Updated docs to include custom CSS and custom footer. 2022-08-12 21:57:14 +02:00
timvisee
c528ad3147
Merge branch 'HrBingR-master' into master
See https://github.com/timvisee/send/pull/103
2022-08-12 12:35:56 +02:00
HrBingR
df9c7ea734
Merge branch 'timvisee:master' into master 2022-08-11 23:06:47 +02:00
HrBingR
e32ea7d0aa Added the ability to define a custom footer via environment variables
Added the CUSTOM_FOOTER_TEXT and CUSTOM_FOOTER_URL environment variables.

If undefined, the default translated footer will display.

If only CUSTOM_FOOTER_TEXT is defined, only this defined text will display in place of the normal footer text.

If only CUSTOM_FOOTER_URL is defined then the defined URL will display.

If both variables are defined, the defined text will display as a link to the defined URL.
2022-08-11 23:04:45 +02:00
timvisee
55ad08fd96
Merge branch 'HrBingR-master' into master
See https://github.com/timvisee/send/pull/100
2022-08-11 10:07:14 +02:00
timvisee
96d53e4118
Merge branch 'master' of github.com:HrBingR/send into HrBingR-master 2022-08-11 10:06:45 +02:00
HrBingR
bce861bcaf Added if check to see if user is using custom CSS 2022-08-10 22:55:51 +02:00
timvisee
643287e235
Merge branch 'AaronDewes-chore/cleanup-dependencies' into master
See https://github.com/timvisee/send/pull/101
2022-08-10 19:04:33 +02:00
AaronDewes
c619be58ae Remove asmcrypto.js 2022-08-09 16:18:16 +00:00
AaronDewes
9b8b11ffc3 Remove double-ended-queue
Not required anymore since node-redis 3.0
2022-08-09 15:39:41 +00:00
AaronDewes
1725ff434e Further dependency cleanup 2022-08-09 15:37:16 +00:00
AaronDewes
e1d6224570 More dependency cleanups 2022-08-09 15:29:54 +00:00
AaronDewes
38746b86fd Update eslint & plugins
Also replace eslint-plugin-node with the maintained eslint-plugin-n
2022-08-09 15:26:25 +00:00
AaronDewes
64644b57e3 Remove some polyfills
This should reduce the runtime size & load times somewhat by removing polyfills for older browsers which are not used much
2022-08-09 15:17:38 +00:00
timvisee
625fdf5bca
Merge branch 'AaronDewes-update-deps' into master
See https://github.com/timvisee/send/pull/98
2022-08-09 16:20:33 +02:00
AaronDewes
951c613095 Fix stylelint errors 2022-08-09 09:12:32 +00:00
AaronDewes
16e78847a2 Fix style problems 2022-08-09 09:00:43 +00:00
HrBingR
310271c10f Added new environment variables for custom css, custom title, and custom description.
Fully tested using the Dockerfile, example can be found on https://fileshare.thenextweb.co.za
2022-08-08 00:37:17 +02:00
AaronDewes
55344f8a9d Drop mkdirp 2022-07-26 17:23:19 +00:00
AaronDewes
2b22e8cd05 Update more dependencies 2022-07-26 17:21:12 +00:00
AaronDewes
47ff32fc9f Modernize CSS 2022-07-26 16:52:29 +00:00
AaronDewes
b598a1c090 Update svgo 2022-07-26 11:56:20 +00:00
AaronDewes
3ae9e6adeb Update git-rev-sync 2022-07-26 11:18:17 +00:00
AaronDewes
33e7e0f5ba npm audit fix 2022-07-26 11:15:12 +00:00
AaronDewes
ca3b5cf7ca Update more packages 2022-07-26 11:05:53 +00:00
AaronDewes
44a25e4156 Update fluent 2022-07-26 11:03:10 +00:00
timvisee
000854104f
Merge branch 'NamPNQ-master' into master
See https://github.com/timvisee/send/pull/94
2022-07-04 18:40:45 +02:00
Nam PHAM
1a0ddf9a05 Disable check user when fxa is not enabled 2022-07-02 23:48:04 +02:00
dependabot[bot]
0ac1eeed2c
Bump got from 11.8.3 to 11.8.5
Bumps [got](https://github.com/sindresorhus/got) from 11.8.3 to 11.8.5.
- [Release notes](https://github.com/sindresorhus/got/releases)
- [Commits](https://github.com/sindresorhus/got/compare/v11.8.3...v11.8.5)

---
updated-dependencies:
- dependency-name: got
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-24 05:02:22 +00:00
dependabot[bot]
2457545502
Bump eventsource from 1.1.0 to 1.1.1
Bumps [eventsource](https://github.com/EventSource/eventsource) from 1.1.0 to 1.1.1.
- [Release notes](https://github.com/EventSource/eventsource/releases)
- [Changelog](https://github.com/EventSource/eventsource/blob/master/HISTORY.md)
- [Commits](https://github.com/EventSource/eventsource/compare/v1.1.0...v1.1.1)

---
updated-dependencies:
- dependency-name: eventsource
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-01 20:39:30 +00:00
dependabot[bot]
75637807eb
Bump convict from 6.2.2 to 6.2.3
Bumps [convict](https://github.com/mozilla/node-convict) from 6.2.2 to 6.2.3.
- [Release notes](https://github.com/mozilla/node-convict/releases)
- [Changelog](https://github.com/mozilla/node-convict/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mozilla/node-convict/compare/v6.2.2...v6.2.3)

---
updated-dependencies:
- dependency-name: convict
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-26 02:57:43 +00:00
timvisee
3b0ef1c0d6
Bump version to 3.4.20 2022-05-12 21:57:02 +02:00
timvisee
22c9560855
Update package-lock.json 2022-05-12 21:56:10 +02:00
Tim Visée
dda964ebf9 Merge branch 'feature/branding' into 'master'
Add ability to change the branding

See merge request timvisee/send!23
2022-05-12 19:52:46 +00:00
Marian Hähnlein
560747106b
Add ability to change the branding 2022-05-02 13:38:16 +02:00
timvisee
81741dcc76
Bump version to 3.4.19 2022-04-25 10:33:18 +02:00
timvisee
58a0800384
Add package for extracted ipaddress format from convic 2022-04-25 10:30:48 +02:00
timvisee
7323f584c1
Merge branch 'dependabot/npm_and_yarn/convict-6.2.2' into master
See https://github.com/timvisee/send/pull/83
2022-04-25 10:04:58 +02:00
dependabot[bot]
c616412449
Bump convict from 5.2.1 to 6.2.2
Bumps [convict](https://github.com/mozilla/node-convict) from 5.2.1 to 6.2.2.
- [Release notes](https://github.com/mozilla/node-convict/releases)
- [Changelog](https://github.com/mozilla/node-convict/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mozilla/node-convict/compare/v5.2.1...v6.2.2)

---
updated-dependencies:
- dependency-name: convict
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-20 21:04:28 +00:00
timvisee
b9faece68e
Merge branch 'dependabot/npm_and_yarn/minimist-1.2.6' into master
See https://github.com/timvisee/send/pull/80
2022-04-07 14:10:40 +02:00
dependabot[bot]
097bdf8853
Bump minimist from 1.2.5 to 1.2.6
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-07 11:27:32 +00:00
timvisee
e96e09f664
Update dependencies 2022-04-07 13:22:46 +02:00
timvisee
0ebea72b3e
Bump version to 3.4.18 2022-03-28 22:03:52 +02:00
timvisee
9cac202892
Update dependencies 2022-03-28 21:45:05 +02:00
Tim Visée
b41c8087f9 Merge branch 'improve-dockerfile' into 'master'
Docker: Set app user gid/uid to 1000

See merge request timvisee/send!22
2022-03-28 19:41:20 +00:00
Lounès Ksouri
9fcc8e36b0 set app user gid/uid to 1000 2022-03-26 15:08:24 +00:00
timvisee
905ca545c7
Update dependencies 2022-03-21 16:13:07 +01:00
timvisee
742b5de7e1
Update dependencies 2022-03-07 14:39:38 +01:00
timvisee
5d7162c4a3
Bump version to 3.4.17 2022-03-04 16:54:02 +01:00
Tim Visée
4c5d8e3bd3 Merge branch 'fix-utf8' into 'master'
Change archive bit flags to specify use of UTF-8 filenames

See merge request timvisee/send!21
2022-03-04 15:52:16 +00:00
timvisee
709997ba72
Fix garbled filenames on Windows with ZIP files due to missing UTF-8 flag
See https://gitlab.com/timvisee/send/-/issues/10
2022-03-04 16:48:58 +01:00
timvisee
b880516edf
Change archive bit flags to specify use of UTF-8 filenames
Related to https://gitlab.com/timvisee/send/-/issues/10#note_549739569

Suggested in https://github.com/mozilla/send/issues/1432#issue-545383226
2022-03-04 16:46:12 +01:00
timvisee
fa716a7da6
Merge branch 'dependabot/npm_and_yarn/url-parse-1.5.10' into master
See https://github.com/timvisee/send/pull/74
2022-02-28 12:08:53 +01:00
dependabot[bot]
40fc5c35ca
Bump url-parse from 1.5.7 to 1.5.10
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.7 to 1.5.10.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.7...1.5.10)

---
updated-dependencies:
- dependency-name: url-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-28 04:39:37 +00:00
timvisee
8d72c81150
Merge branch 'dependabot/npm_and_yarn/url-parse-1.5.7' into master
See https://github.com/timvisee/send/pull/73
2022-02-20 20:29:42 +01:00
dependabot[bot]
383b84ef1f
Bump url-parse from 1.5.3 to 1.5.7
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.3 to 1.5.7.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.3...1.5.7)

---
updated-dependencies:
- dependency-name: url-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-19 06:33:26 +00:00
timvisee
7cba51b729
Tweak FAQ to remove old FXA notice 2022-02-18 16:53:55 +01:00
timvisee
7d024a9998
Merge branch 'dependabot/npm_and_yarn/tar-4.4.19' into master
See https://github.com/timvisee/send/pull/70
2022-02-14 13:40:58 +01:00
timvisee
eabff183ec
Merge branch 'master' into dependabot/npm_and_yarn/tar-4.4.19
See https://github.com/timvisee/send/pull/70
2022-02-14 13:40:49 +01:00
timvisee
d04829cbf2
Merge branch 'dependabot/npm_and_yarn/follow-redirects-1.14.8' into master
See https://github.com/timvisee/send/pull/69
2022-02-14 12:35:42 +01:00
dependabot[bot]
af52b96ab4
Bump follow-redirects from 1.14.7 to 1.14.8
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.7 to 1.14.8.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.7...v1.14.8)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-14 11:30:46 +00:00
dependabot[bot]
ec26a8e38f
Bump tar from 4.4.13 to 4.4.19
Bumps [tar](https://github.com/npm/node-tar) from 4.4.13 to 4.4.19.
- [Release notes](https://github.com/npm/node-tar/releases)
- [Changelog](https://github.com/npm/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/npm/node-tar/compare/v4.4.13...v4.4.19)

---
updated-dependencies:
- dependency-name: tar
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-14 11:30:35 +00:00
timvisee
41f5615acc
Merge branch 'dependabot/npm_and_yarn/ajv-6.12.6' into master
See https://github.com/timvisee/send/pull/68
2022-02-14 12:27:30 +01:00
dependabot[bot]
756d1b1d14
Bump ajv from 6.12.2 to 6.12.6
Bumps [ajv](https://github.com/ajv-validator/ajv) from 6.12.2 to 6.12.6.
- [Release notes](https://github.com/ajv-validator/ajv/releases)
- [Commits](https://github.com/ajv-validator/ajv/compare/v6.12.2...v6.12.6)

---
updated-dependencies:
- dependency-name: ajv
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-13 20:05:07 +00:00
timvisee
a37a0c8678
Update dependencies 2022-01-24 17:20:29 +01:00
timvisee
8c50da564f
Update configstore 2022-01-24 17:16:14 +01:00
timvisee
214f723232
Merge branch 'dependabot/npm_and_yarn/nanoid-3.2.0' into master
See https://github.com/timvisee/send/pull/64
2022-01-24 17:14:41 +01:00
dependabot[bot]
f2a6af409e
Bump nanoid from 3.1.16 to 3.2.0
Bumps [nanoid](https://github.com/ai/nanoid) from 3.1.16 to 3.2.0.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/3.1.16...3.2.0)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-22 01:16:00 +00:00
timvisee
b346e3e3ae
Bump version to 3.4.16 2022-01-17 13:09:45 +01:00
timvisee
aea428372d
Update dependencies 2022-01-17 13:09:19 +01:00
timvisee
ea8efb9d93
Merge branch 'dependabot/npm_and_yarn/follow-redirects-1.14.7' into master
See https://github.com/timvisee/send/pull/63
2022-01-17 13:05:15 +01:00
dependabot[bot]
2b7164f589
Bump follow-redirects from 1.14.5 to 1.14.7
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.5 to 1.14.7.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.5...v1.14.7)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-14 22:50:28 +00:00
timvisee
08399059e9
Bump version to 3.4.15 2021-12-19 23:07:24 +01:00
timvisee
aea40fa11b
Update dependencies 2021-12-19 23:04:26 +01:00
timvisee
e51c753c0d
Merge branch 'goxlur-patch-1' into master
See https://github.com/timvisee/send/pull/60
2021-12-19 23:00:14 +01:00
goxlur
6520d71faa
Fix page scroll overflow 2021-12-19 00:36:47 +01:00
Tim Visée
97b0b10863 Merge branch 'node-16' into 'master'
Bump node to latest LTS v16.13

See merge request timvisee/send!20
2021-12-01 18:00:21 +00:00
timvisee
50e76e0895
Do not use --openssl-legacy-provider 2021-12-01 18:23:25 +01:00
timvisee
610e036e26
Bump node to latest LTS v16.13 2021-12-01 18:20:43 +01:00
timvisee
e695a8b481
Update browserlist 2021-12-01 18:14:01 +01:00
timvisee
d33ddf643b
Update dependencies 2021-12-01 18:13:10 +01:00
timvisee
512bd32368
Use 64x64 PNG icon in README 2021-11-24 14:42:29 +01:00
timvisee
3c42de0efd
Fix Docker artifact build on CI 2021-11-01 12:44:49 +01:00
timvisee
b7582230cf
Update dependencies 2021-10-24 15:10:28 +02:00
timvisee
592ff3fb4a
Bump version to 3.4.14 2021-10-06 18:11:54 +02:00
timvisee
927203cb96
Add double-ended-queue dependency
See https://gitlab.com/timvisee/send/-/issues/23
2021-10-06 18:10:46 +02:00
timvisee
48237807fa
Update dependencies 2021-10-06 18:08:47 +02:00
timvisee
38a4552d52
List Thunderbird FileLink provider extension as client in README
Fixes https://github.com/timvisee/send/issues/15
2021-08-30 15:28:29 +02:00
timvisee
9d2d81e063
Merge branch 'dependabot/npm_and_yarn/url-parse-1.5.3' into master
See https://github.com/timvisee/send/pull/53
2021-08-13 14:42:36 +02:00
dependabot[bot]
81d6c90c4e
Bump url-parse from 1.5.1 to 1.5.3
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.1 to 1.5.3.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.1...1.5.3)

---
updated-dependencies:
- dependency-name: url-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-13 11:05:08 +00:00
timvisee
2bdaa0c4bd
Merge branch 'dependabot/npm_and_yarn/path-parse-1.0.7' into master
See https://github.com/timvisee/send/pull/52
2021-08-13 13:02:29 +02:00
dependabot[bot]
00d3bebc27
Bump path-parse from 1.0.6 to 1.0.7
Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7.
- [Release notes](https://github.com/jbgutierrez/path-parse/releases)
- [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7)

---
updated-dependencies:
- dependency-name: path-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-12 22:09:37 +00:00
timvisee
ea384ff5d3
Update dependencies 2021-08-08 20:36:26 +02:00
timvisee
062c439ec0
Bump version to 3.4.13 2021-07-08 23:13:15 +02:00
Tim Visée
54e528980b Merge branch 'master' into 'master'
fix: remove iOS saveFile workaround #20

See merge request timvisee/send!19
2021-07-08 21:12:06 +00:00
Paul Zeinlinger
b9292abefe
fix: remove iOS saveFile workaround #20 2021-07-08 23:05:39 +02:00
timvisee
1520942ac9
Fix UI error after upload when share link is too long
The QR-code generation logic had a character limit. This broke the
upload page when the share URL is too long. This has now been fixed to
support an arbitrary number of characters.

Fixes https://gitlab.com/timvisee/send/-/issues/19
2021-07-08 21:21:35 +02:00
timvisee
0e17cd567c
Update qrcode snippet 2021-07-08 21:20:27 +02:00
timvisee
7b21b199c2
Update dependencies 2021-07-08 21:12:17 +02:00
timvisee
6214b07a30
Merge branch 'dependabot/npm_and_yarn/redis-3.1.1' into master
See https://github.com/timvisee/send/pull/20
2021-06-28 17:28:31 +02:00
dependabot[bot]
941d87976b
Bump redis from 2.8.0 to 3.1.1
Bumps [redis](https://github.com/NodeRedis/node-redis) from 2.8.0 to 3.1.1.
- [Release notes](https://github.com/NodeRedis/node-redis/releases)
- [Changelog](https://github.com/NodeRedis/node-redis/blob/master/CHANGELOG.md)
- [Commits](https://github.com/NodeRedis/node-redis/compare/v.2.8.0...v3.1.1)

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-28 15:28:06 +00:00
timvisee
8db3fed6fb
Merge branch 'dependabot/npm_and_yarn/color-string-1.5.5' into master 2021-06-28 17:24:05 +02:00
dependabot[bot]
78ca1f06e0
Bump color-string from 1.5.3 to 1.5.5
Bumps [color-string](https://github.com/Qix-/color-string) from 1.5.3 to 1.5.5.
- [Release notes](https://github.com/Qix-/color-string/releases)
- [Changelog](https://github.com/Qix-/color-string/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Qix-/color-string/commits/1.5.5)

---
updated-dependencies:
- dependency-name: color-string
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-28 15:22:18 +00:00
timvisee
9fdc079878
Remove annoying husky post merge and checkout hooks 2021-06-28 17:19:30 +02:00
timvisee
f08d078236
Update dependencies 2021-06-23 21:02:46 +02:00
timvisee
46ae4a220b
Merge branch 'dependabot/npm_and_yarn/trim-newlines-3.0.1' into master
See https://github.com/timvisee/send/pull/43
2021-06-09 13:28:26 +02:00
dependabot[bot]
d0932c26ea
Bump trim-newlines from 3.0.0 to 3.0.1
Bumps [trim-newlines](https://github.com/sindresorhus/trim-newlines) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/sindresorhus/trim-newlines/releases)
- [Commits](https://github.com/sindresorhus/trim-newlines/commits)

---
updated-dependencies:
- dependency-name: trim-newlines
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-09 11:26:31 +00:00
timvisee
798c399a38
Update dependencies 2021-06-09 12:48:02 +02:00
timvisee
825e3942a2
Bump version to v3.4.12 2021-06-04 14:08:25 +02:00
timvisee
755459f57e
Update dependencies 2021-06-04 14:07:19 +02:00
Tim Visée
42f5ca9701 Merge branch 'default-download-count' into 'master'
Add DEFAULT_DOWNLOADS variable to set default download count

See merge request timvisee/send!18
2021-06-04 12:06:05 +00:00
timvisee
1a923d21b5
Add DEFAULT_DOWNLOADS variable to set default download count
Fixes https://github.com/timvisee/send/issues/39
2021-06-04 14:03:58 +02:00
timvisee
3bd9f00c25
Merge branch 'dependabot/npm_and_yarn/ws-6.2.2'
See https://github.com/timvisee/send/pull/42
2021-06-04 13:50:02 +02:00
dependabot[bot]
fa1c64369f
Bump ws from 6.2.1 to 6.2.2
Bumps [ws](https://github.com/websockets/ws) from 6.2.1 to 6.2.2.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/commits)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-04 11:47:46 +00:00
timvisee
9280f47afc
Update dependencies 2021-06-04 13:46:24 +02:00
timvisee
3707b90d09
Update dependencies 2021-05-30 12:41:42 +02:00
timvisee
21392f1157
Merge branch 'dependabot/npm_and_yarn/dns-packet-1.3.4' into master
See https://github.com/timvisee/send/pull/37
2021-05-30 12:40:45 +02:00
dependabot[bot]
680d3ed948
Bump dns-packet from 1.3.1 to 1.3.4
Bumps [dns-packet](https://github.com/mafintosh/dns-packet) from 1.3.1 to 1.3.4.
- [Release notes](https://github.com/mafintosh/dns-packet/releases)
- [Changelog](https://github.com/mafintosh/dns-packet/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mafintosh/dns-packet/compare/v1.3.1...v1.3.4)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-29 01:54:35 +00:00
timvisee
dee1e84e58
Mention Docker page in deployment section 2021-05-19 16:49:13 +02:00
timvisee
214191e743
Replace links from mozilla/send to timvisee/send 2021-05-19 16:09:01 +02:00
timvisee
84da34169d
Create static robots.txt file, remove dynamic route
Fixes https://gitlab.com/timvisee/send/-/issues/17
2021-05-19 16:00:58 +02:00
Tim Visée
93e1d2f41a Merge branch 'deploy' into 'master'
Fix chmod command

See merge request timvisee/send!17
2021-05-19 12:34:35 +00:00
David Dumas
43e1845d28 Fix chmod command 2021-05-19 12:34:35 +00:00
70 changed files with 22227 additions and 16201 deletions

View file

@ -1,10 +1,22 @@
image: "node:15-slim"
stages: stages:
- test - test
- artifact
- release - release
# Build Send, run npm tests
test:
stage: test
image: "node:16-slim"
only:
- api
- branches
- chat
- merge_requests
- pushes
- schedules
- tags
- triggers
- web
before_script: before_script:
# Install dependencies # Install dependencies
- apt-get update - apt-get update
@ -15,91 +27,46 @@ before_script:
- wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - - wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
- sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' - sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
- apt-get update - apt-get update
- apt-get install -y gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils
- apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 --no-install-recommends - apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 --no-install-recommends
# Build Send, run npm tests
test:
stage: test
script: script:
- npm ci - npm ci
- npm run lint - npm run lint
- npm test - npm test
# Build Docker image, export Docker image artifact
artifact-docker:
stage: artifact
image: docker:latest
needs: []
services:
- docker:dind
variables:
IMG_FILE: "send:git-$CI_COMMIT_SHORT_SHA.tar"
IMG_NAME: "send:git-$CI_COMMIT_SHORT_SHA"
before_script: []
script:
- docker build -t $IMG_NAME .
- docker image save -o $IMG_FILE $IMG_NAME
artifacts:
name: artifact-docker
paths:
- $IMG_FILE
expire_in: 1 week
# Release public Docker image for the master branch
release-docker-master:
stage: release
image: docker:latest
dependencies:
- artifact-docker
services:
- docker:dind
only:
- master
variables:
IMG_IMPORT_FILE: "send:git-$CI_COMMIT_SHORT_SHA.tar"
IMG_IMPORT_NAME: "send:git-$CI_COMMIT_SHORT_SHA"
IMG_NAME: "registry.gitlab.com/timvisee/send:master-$CI_COMMIT_SHORT_SHA"
before_script: []
script:
# Login in to registry
- 'docker login registry.gitlab.com -u $DOCKER_USER -p $DOCKER_PASS'
# Load existing, retag for new image images
- docker image load -i $IMG_IMPORT_FILE
- docker tag $IMG_IMPORT_NAME $IMG_NAME
# Publish tagged image
- docker push $IMG_NAME
- 'echo "Docker image artifact published, available as:" && echo " docker pull $IMG_NAME"'
# Release public Docker image for a version tag
release-docker: release-docker:
stage: release stage: release
image: docker:latest image: docker:latest
dependencies:
- artifact-docker
services: services:
- docker:dind - docker:dind
only: only:
- /^v(\d+\.)*\d+$/ - api
variables: - branches
IMG_IMPORT_FILE: "send:git-$CI_COMMIT_SHORT_SHA.tar" - chat
IMG_IMPORT_NAME: "send:git-$CI_COMMIT_SHORT_SHA" - merge_requests
IMG_NAME: "registry.gitlab.com/timvisee/send:$CI_COMMIT_REF_NAME" - pushes
IMG_NAME_LATEST: "registry.gitlab.com/timvisee/send:latest" - schedules
before_script: [] - tags
- triggers
- web
script: script:
# Login in to registry - docker login "$CI_REGISTRY" -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD"
- 'docker login registry.gitlab.com -u $DOCKER_USER -p $DOCKER_PASS' - docker buildx create --name sendBuilder
- docker buildx use sendBuilder
# Load existing, retag for new image images - |
- docker image load -i $IMG_IMPORT_FILE if [ "$CI_PIPELINE_SOURCE" == "merge_request_event" ]; then
- docker tag $IMG_IMPORT_NAME $IMG_NAME IMAGE_NAMES="$CI_REGISTRY_IMAGE/mr:$CI_MERGE_REQUEST_IID"
- docker tag $IMG_IMPORT_NAME $IMG_NAME_LATEST elif [ "$CI_COMMIT_TAG" != "" ]; then
IMAGE_NAMES="$CI_REGISTRY_IMAGE:$CI_COMMIT_TAG $CI_REGISTRY_IMAGE:latest"
# Publish tagged image else
- docker push $IMG_NAME IMAGE_NAMES="$CI_REGISTRY_IMAGE/$CI_COMMIT_BRANCH:$CI_COMMIT_SHORT_SHA"
- docker push $IMG_NAME_LATEST fi
- |
- 'echo "Docker image artifact published, available as:" && echo " docker pull $IMG_NAME_LATEST" && echo " docker pull $IMG_NAME"' for image in $IMAGE_NAMES; do
docker buildx build --platform linux/amd64,linux/arm64 -t $image . --push
done
- |
echo "Container image pushed. You can pull it with";
for image in $IMAGE_NAMES; do
echo "docker pull $image"
done

View file

@ -11,3 +11,5 @@ rules:
selector-list-comma-newline-after: null selector-list-comma-newline-after: null
value-list-comma-newline-after: null value-list-comma-newline-after: null
at-rule-no-unknown: null at-rule-no-unknown: null
# Conflicts with prettier
string-quotes: null

View file

@ -4,41 +4,57 @@
# License https://gitlab.com/timvisee/send/blob/master/LICENSE # License https://gitlab.com/timvisee/send/blob/master/LICENSE
## ##
# Build project # Build project
FROM node:current-alpine AS builder FROM node:16.13-alpine3.13 AS builder
RUN set -x \
# Change node uid/gid
&& apk --no-cache add shadow \
&& groupmod -g 1001 node \
&& usermod -u 1001 -g 1001 node
RUN set -x \ RUN set -x \
# Add user # Add user
&& addgroup --gid 10001 app \ && addgroup --gid 1000 app \
&& adduser --disabled-password \ && adduser --disabled-password \
--gecos '' \ --gecos '' \
--ingroup app \ --ingroup app \
--home /app \ --home /app \
--uid 10001 \ --uid 1000 \
app app
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
&& PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true npm ci \ && PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true npm ci \
&& npm run build && npm run build
# Main image # Main image
FROM node:current-alpine FROM node:16.13-alpine3.13
RUN set -x \
# Change node uid/gid
&& apk --no-cache add shadow \
&& groupmod -g 1001 node \
&& usermod -u 1001 -g 1001 node
RUN set -x \ RUN set -x \
# Add user # Add user
&& addgroup --gid 10001 app \ && addgroup --gid 1000 app \
&& adduser --disabled-password \ && adduser --disabled-password \
--gecos '' \ --gecos '' \
--ingroup app \ --ingroup app \
--home /app \ --home /app \
--uid 10001 \ --uid 1000 \
app app
USER app USER app
WORKDIR /app WORKDIR /app
COPY --chown=app:app package*.json ./ COPY --chown=app:app package*.json ./
COPY --chown=app:app app app COPY --chown=app:app app app
COPY --chown=app:app common common COPY --chown=app:app common common

View file

@ -1,4 +1,4 @@
# [![Send](./assets/icon.svg)](https://gitlab.com/timvisee/send/) Send # [![Send](./assets/icon-64x64.png)](https://gitlab.com/timvisee/send/) Send
[![Build status on GitLab CI][gitlab-ci-master-badge]][gitlab-ci-link] [![Build status on GitLab CI][gitlab-ci-master-badge]][gitlab-ci-link]
[![Latest release][release-badge]][release-link] [![Latest release][release-badge]][release-link]
@ -81,7 +81,7 @@ A file sharing experiment which allows you to send encrypted files to other user
## Requirements ## Requirements
- [Node.js 15.x](https://nodejs.org/) - [Node.js 16.x](https://nodejs.org/)
- [Redis server](https://redis.io/) (optional for development) - [Redis server](https://redis.io/) (optional for development)
- [AWS S3](https://aws.amazon.com/s3/) or compatible service (optional) - [AWS S3](https://aws.amazon.com/s3/) or compatible service (optional)
@ -121,7 +121,7 @@ The server is configured with environment variables. See [server/config.js](serv
## Localization ## Localization
see [docs/localization.md](docs/localization.md) See: [docs/localization.md](docs/localization.md)
--- ---
@ -139,9 +139,11 @@ Find a list of public instances here: https://github.com/timvisee/send-instances
## Deployment ## Deployment
See also [docs/deployment.md](docs/deployment.md) See: [docs/deployment.md](docs/deployment.md)
AWS example using Ubuntu Server `20.04` [docs/AWS.md](docs/AWS.md) Docker quickstart: [docs/docker.md](docs/docker.md)
AWS example using Ubuntu Server `20.04`: [docs/AWS.md](docs/AWS.md)
--- ---
@ -150,6 +152,7 @@ AWS example using Ubuntu Server `20.04` [docs/AWS.md](docs/AWS.md)
- Web: _this repository_ - Web: _this repository_
- Command-line: [`ffsend`](https://github.com/timvisee/ffsend) - Command-line: [`ffsend`](https://github.com/timvisee/ffsend)
- Android: _see [Android](#android) section_ - Android: _see [Android](#android) section_
- Thunderbird: [FileLink provider for Send](https://addons.thunderbird.net/thunderbird/addon/filelink-provider-for-send/)
#### Android #### Android

View file

@ -77,7 +77,11 @@ function body(main) {
state.capabilities = { state.capabilities = {
account: true account: true
}; //TODO }; //TODO
state.archive = new Archive([], DEFAULTS.EXPIRE_SECONDS); state.archive = new Archive(
[],
DEFAULTS.EXPIRE_SECONDS,
DEFAULTS.DOWNLOADS
);
state.storage = storage; state.storage = storage;
state.user = new User(storage, LIMITS); state.user = new User(storage, LIMITS);
state.sentry = Sentry; state.sentry = Sentry;

View file

@ -43,7 +43,7 @@ function post(obj, bearerToken) {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}; };
if (bearerToken) { if (bearerToken) {
h['Authentication'] = `Bearer ${bearerToken}`; h['Authorization'] = `Bearer ${bearerToken}`;
} }
return { return {
method: 'POST', method: 'POST',

View file

@ -14,11 +14,12 @@ function isDupe(newFile, array) {
} }
export default class Archive { export default class Archive {
constructor(files = [], defaultTimeLimit = 86400) { constructor(files = [], defaultTimeLimit = 86400, defaultDownloadLimit = 1) {
this.files = Array.from(files); this.files = Array.from(files);
this.defaultTimeLimit = defaultTimeLimit; this.defaultTimeLimit = defaultTimeLimit;
this.defaultDownloadLimit = defaultDownloadLimit;
this.timeLimit = defaultTimeLimit; this.timeLimit = defaultTimeLimit;
this.dlimit = 1; this.dlimit = defaultDownloadLimit;
this.password = null; this.password = null;
} }
@ -76,7 +77,7 @@ export default class Archive {
clear() { clear() {
this.files = []; this.files = [];
this.dlimit = 1; this.dlimit = this.defaultDownloadLimit;
this.timeLimit = this.defaultTimeLimit; this.timeLimit = this.defaultTimeLimit;
this.password = null; this.password = null;
} }

View file

@ -7,7 +7,7 @@ const experiments = {
return true; return true;
}, },
variant: function() { variant: function() {
return ['white-blue', 'blue', 'white-violet', 'violet'][ return ['white-primary', 'primary', 'white-violet', 'violet'][
Math.floor(Math.random() * 4) Math.floor(Math.random() * 4)
]; ];
}, },

View file

@ -224,24 +224,6 @@ async function saveFile(file) {
if (navigator.msSaveBlob) { if (navigator.msSaveBlob) {
navigator.msSaveBlob(blob, file.name); navigator.msSaveBlob(blob, file.name);
return resolve(); return resolve();
} else if (/iPhone|fxios/i.test(navigator.userAgent)) {
// This method is much slower but createObjectURL
// is buggy on iOS
const reader = new FileReader();
reader.addEventListener('loadend', function() {
if (reader.error) {
return reject(reader.error);
}
if (reader.result) {
const a = document.createElement('a');
a.href = reader.result;
a.download = file.name;
document.body.appendChild(a);
a.click();
}
resolve();
});
reader.readAsDataURL(blob);
} else { } else {
const downloadUrl = URL.createObjectURL(blob); const downloadUrl = URL.createObjectURL(blob);
const a = document.createElement('a'); const a = document.createElement('a');

View file

@ -1,8 +1,8 @@
import { FluentBundle } from '@fluent/bundle'; import { FluentBundle, FluentResource } from '@fluent/bundle';
function makeBundle(locale, ftl) { function makeBundle(locale, ftl) {
const bundle = new FluentBundle(locale, { useIsolating: false }); const bundle = new FluentBundle(locale, { useIsolating: false });
bundle.addMessages(ftl); bundle.addResource(new FluentResource(ftl));
return bundle; return bundle;
} }
@ -19,7 +19,7 @@ export async function getTranslator(locale) {
return function(id, data) { return function(id, data) {
for (let bundle of bundles) { for (let bundle of bundles) {
if (bundle.hasMessage(id)) { if (bundle.hasMessage(id)) {
return bundle.format(bundle.getMessage(id), data); return bundle.formatPattern(bundle.getMessage(id).value, data);
} }
} }
}; };

View file

@ -7,17 +7,14 @@ html {
@tailwind components; @tailwind components;
:not(input) { :not(input) {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none; user-select: none;
} }
:root { :root {
--violet-gradient: linear-gradient( --violet-gradient: linear-gradient(
-180deg, -180deg,
rgba(144, 89, 255, 0.8) 0%, rgb(144 89 255 / 80%) 0%,
rgba(144, 89, 255, 0.4) 100% rgb(144 89 255 / 40%) 100%
); );
} }
@ -39,7 +36,7 @@ body {
} }
.btn { .btn {
@apply bg-blue-60; @apply bg-primary;
@apply text-white; @apply text-white;
@apply cursor-pointer; @apply cursor-pointer;
@apply py-4; @apply py-4;
@ -48,11 +45,11 @@ body {
} }
.btn:hover { .btn:hover {
@apply bg-blue-70; @apply bg-primary_accent;
} }
.btn:focus { .btn:focus {
@apply bg-blue-70; @apply bg-primary_accent;
} }
.checkbox { .checkbox {
@ -71,7 +68,7 @@ body {
.checkbox > label::before { .checkbox > label::before {
/* @apply bg-grey-10; */ /* @apply bg-grey-10; */
@apply border; @apply border-default;
@apply rounded-sm; @apply rounded-sm;
content: ''; content: '';
@ -82,16 +79,16 @@ body {
} }
.checkbox > label:hover::before { .checkbox > label:hover::before {
@apply border-blue-50; @apply border-primary;
} }
.checkbox > input:focus + label::before { .checkbox > input:focus + label::before {
@apply border-blue-50; @apply border-primary;
} }
.checkbox > input:checked + label::before { .checkbox > input:checked + label::before {
@apply bg-blue-50; @apply bg-primary;
@apply border-blue-50; @apply border-primary;
background-image: url('../assets/lock.svg'); background-image: url('../assets/lock.svg');
background-position: center; background-position: center;
@ -104,8 +101,8 @@ body {
} }
.checkbox > input:disabled + label::before { .checkbox > input:disabled + label::before {
@apply bg-blue-50; @apply bg-primary;
@apply border-blue-50; @apply border-primary;
background-image: url('../assets/lock.svg'); background-image: url('../assets/lock.svg');
background-position: center; background-position: center;
@ -153,16 +150,16 @@ footer li a:hover {
white-space: nowrap; white-space: nowrap;
} }
.link-blue { .link-primary {
@apply text-blue-60; @apply text-primary;
} }
.link-blue:hover { .link-primary:hover {
@apply text-blue-70; @apply text-primary_accent;
} }
.link-blue:focus { .link-primary:focus {
@apply text-blue-70; @apply text-primary_accent;
} }
.main-header img { .main-header img {
@ -170,12 +167,27 @@ footer li a:hover {
width: auto; width: auto;
} }
.text-underline {
text-decoration: underline;
}
.d-block {
display: block;
}
.d-inline-block {
display: inline-block;
}
.align-middle {
vertical-align: middle;
}
.main { .main {
display: flex; display: flex;
position: relative; position: relative;
max-width: 64rem; max-width: 64rem;
width: 100%; width: 100%;
height: 100%;
} }
.main > section { .main > section {
@ -205,19 +217,18 @@ progress::-webkit-progress-value {
background-image: -webkit-linear-gradient( background-image: -webkit-linear-gradient(
-45deg, -45deg,
transparent 20%, transparent 20%,
rgba(255, 255, 255, 0.4) 20%, rgb(255 255 255 / 40%) 20%,
rgba(255, 255, 255, 0.4) 40%, rgb(255 255 255 / 40%) 40%,
transparent 40%, transparent 40%,
transparent 60%, transparent 60%,
rgba(255, 255, 255, 0.4) 60%, rgb(255 255 255 / 40%) 60%,
rgba(255, 255, 255, 0.4) 80%, rgb(255 255 255 / 40%) 80%,
transparent 80% transparent 80%
), ),
-webkit-linear-gradient(left, #0a84ff, #0a84ff); -webkit-linear-gradient(left, var(--color-primary), var(--color-primary));
/* stylelint-enable */ /* stylelint-enable */
border-radius: 2px; border-radius: 2px;
background-size: 21px 20px, 100% 100%, 100% 100%; background-size: 21px 20px, 100% 100%, 100% 100%;
-webkit-animation: animate-stripes 1s linear infinite;
} }
progress::-moz-progress-bar { progress::-moz-progress-bar {
@ -225,27 +236,21 @@ progress::-moz-progress-bar {
background-image: -moz-linear-gradient( background-image: -moz-linear-gradient(
135deg, 135deg,
transparent 20%, transparent 20%,
rgba(255, 255, 255, 0.4) 20%, rgb(255 255 255 / 40%) 20%,
rgba(255, 255, 255, 0.4) 40%, rgb(255 255 255 / 40%) 40%,
transparent 40%, transparent 40%,
transparent 60%, transparent 60%,
rgba(255, 255, 255, 0.4) 60%, rgb(255 255 255 / 40%) 60%,
rgba(255, 255, 255, 0.4) 80%, rgb(255 255 255 / 40%) 80%,
transparent 80% transparent 80%
), ),
-moz-linear-gradient(left, #0a84ff, #0a84ff); -moz-linear-gradient(left, var(--color-primary), var(--color-primary));
/* stylelint-enable */ /* stylelint-enable */
border-radius: 2px; border-radius: 2px;
background-size: 21px 20px, 100% 100%, 100% 100%; background-size: 21px 20px, 100% 100%, 100% 100%;
animation: animate-stripes 1s linear infinite; animation: animate-stripes 1s linear infinite;
} }
@-webkit-keyframes animate-stripes {
100% {
background-position: -21px 0;
}
}
@keyframes animate-stripes { @keyframes animate-stripes {
100% { 100% {
background-position: -21px 0; background-position: -21px 0;
@ -271,7 +276,6 @@ select {
@apply m-auto; @apply m-auto;
@apply py-8; @apply py-8;
min-height: 42rem;
max-height: 42rem; max-height: 42rem;
width: calc(100% - 3rem); width: calc(100% - 3rem);
} }
@ -285,28 +289,28 @@ select {
} }
.btn { .btn {
@apply bg-blue-40; @apply bg-primary;
@apply text-white; @apply text-white;
} }
.btn:hover { .btn:hover {
@apply bg-blue-50; @apply bg-primary_accent;
} }
.btn:focus { .btn:focus {
@apply bg-blue-50; @apply bg-primary_accent;
} }
.link-blue { .link-primary {
@apply text-blue-40; @apply text-primary;
} }
.link-blue:hover { .link-primary:hover {
@apply text-blue-50; @apply text-primary_accent;
} }
.link-blue:focus { .link-primary:focus {
@apply text-blue-50; @apply text-primary_accent;
} }
.main > section { .main > section {
@ -315,7 +319,7 @@ select {
@screen md { @screen md {
.main > section { .main > section {
@apply border; @apply border-default;
@apply border-grey-80; @apply border-grey-80;
} }
} }
@ -325,13 +329,12 @@ select {
@responsive { @responsive {
.shadow-light { .shadow-light {
box-shadow: 0 0 8px 0 rgba(12, 12, 13, 0.1); box-shadow: 0 0 8px 0 rgb(12 12 13 / 10%);
} }
.shadow-big { .shadow-big {
box-shadow: 0 12px 18px 2px rgba(34, 0, 51, 0.04), box-shadow: 0 12px 18px 2px rgb(34 0 51 / 4%),
0 6px 22px 4px rgba(7, 48, 114, 0.12), 0 6px 22px 4px rgb(7 48 114 / 12%), 0 6px 10px -4px rgb(14 13 26 / 12%);
0 6px 10px -4px rgba(14, 13, 26, 0.12);
} }
} }
@ -365,20 +368,20 @@ select {
/* begin signin button color experiment */ /* begin signin button color experiment */
.white-blue { .white-primary {
@apply border-blue-60; @apply border-primary;
@apply border-2; @apply border-2;
@apply text-blue-60; @apply text-primary;
} }
.white-blue:hover, .white-primary:hover,
.white-blue:focus { .white-primary:focus {
@apply bg-blue-60; @apply bg-primary;
@apply text-white; @apply text-white;
} }
.blue { .primary {
@apply bg-blue-60; @apply bg-primary;
@apply text-white; @apply text-white;
} }

View file

@ -52,7 +52,7 @@ if (process.env.NODE_ENV === 'production') {
DEFAULTS, DEFAULTS,
WEB_UI, WEB_UI,
PREFS, PREFS,
archive: new Archive([], DEFAULTS.EXPIRE_SECONDS), archive: new Archive([], DEFAULTS.EXPIRE_SECONDS, DEFAULTS.DOWNLOADS),
capabilities, capabilities,
translate, translate,
storage, storage,

File diff suppressed because it is too large Load diff

View file

@ -9,7 +9,6 @@ module.exports = function(app = choo({ hash: true })) {
app.route('/unsupported/:reason', body(require('./ui/unsupported'))); app.route('/unsupported/:reason', body(require('./ui/unsupported')));
app.route('/error', body(require('./ui/error'))); app.route('/error', body(require('./ui/error')));
app.route('/blank', body(require('./ui/blank'))); app.route('/blank', body(require('./ui/blank')));
app.route('/robots.txt', function() {return 'User-agent: * Disallow: /'});
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);
}); });

View file

@ -69,7 +69,7 @@ class Account extends Component {
return html` return html`
<send-account> <send-account>
<button <button
class="px-4 py-2 md:px-8 md:py-4 focus:outline signin border-2 link-blue border-blue-60 hover:border-blue-70 dark:border-blue-40 dark:hover:border-blue-50" class="px-4 py-2 md:px-8 md:py-4 focus:outline signin border-2 link-primary border-primary hover:border-primary dark:border-primary dark:hover:border-primary"
onclick="${e => this.login(e)}" onclick="${e => this.login(e)}"
title="${translate('signInOnlyButton')}" title="${translate('signInOnlyButton')}"
> >
@ -83,19 +83,19 @@ class Account extends Component {
<input <input
type="image" type="image"
alt="${user.email}" alt="${user.email}"
class="w-8 h-8 rounded-full border text-blue-50 md:text-white focus:outline" class="w-8 h-8 rounded-full border-default text-primary md:text-white focus:outline"
src="${user.avatar}" src="${user.avatar}"
onclick="${e => this.avatarClick(e)}" onclick="${e => this.avatarClick(e)}"
/> />
<ul <ul
id="accountMenu" id="accountMenu"
class="invisible absolute top-0 right-0 mt-10 pt-2 pb-2 bg-white shadow-md whitespace-no-wrap outline-none z-50 dark:bg-grey-80" class="invisible absolute top-0 right-0 mt-10 pt-2 pb-2 bg-white shadow-md whitespace-nowrap outline-none z-50 dark:bg-grey-80"
onblur="${e => this.hideMenu(e)}" onblur="${e => this.hideMenu(e)}"
> >
<li class="p-2 text-grey-60 dark:text-grey-50">${user.email}</li> <li class="p-2 text-grey-60 dark:text-grey-50">${user.email}</li>
<li> <li>
<button <button
class="block w-full text-left px-4 py-2 text-grey-80 dark:text-grey-30 hover:bg-blue-50 hover:text-white cursor-pointer focus:outline" class="block w-full text-left px-4 py-2 text-grey-80 dark:text-grey-30 hover:bg-primary hover:text-white cursor-pointer focus:outline"
onclick="${e => this.logout(e)}" onclick="${e => this.logout(e)}"
title="${translate('signOut')}" title="${translate('signOut')}"
> >

View file

@ -26,7 +26,7 @@ function expiryInfo(translate, archive) {
} }
function password(state) { function password(state) {
const MAX_LENGTH = 32; const MAX_LENGTH = 4096;
return html` return html`
<div class="mb-2 px-1"> <div class="mb-2 px-1">
@ -53,7 +53,7 @@ function password(state) {
id="password-input" id="password-input"
class="${state.archive.password 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" : 'invisible'} border-default rounded-default focus:border-primary leading-normal my-1 py-1 px-2 h-8 dark:bg-grey-80"
autocomplete="off" autocomplete="off"
maxlength="${MAX_LENGTH}" maxlength="${MAX_LENGTH}"
type="password" type="password"
@ -150,7 +150,7 @@ function password(state) {
function fileInfo(file, action) { function fileInfo(file, action) {
return html` return html`
<send-file class="flex flex-row items-center p-3 w-full"> <send-file class="flex flex-row items-center p-3 w-full">
<svg class="h-8 w-8 text-white dark:text-grey-90"> <svg class="h-8 w-8 text-primary">
<use xlink:href="${assets.get('blue_file.svg')}#icon"/> <use xlink:href="${assets.get('blue_file.svg')}#icon"/>
</svg> </svg>
<p class="ml-4 w-full"> <p class="ml-4 w-full">
@ -166,7 +166,7 @@ function fileInfo(file, action) {
function archiveInfo(archive, action) { function archiveInfo(archive, action) {
return html` return html`
<p class="w-full flex items-center"> <p class="w-full flex items-center">
<svg class="h-8 w-6 mr-3 flex-shrink-0 text-white dark:text-grey-90"> <svg class="h-8 w-6 mr-3 flex-shrink-0 text-primary">
<use xlink:href="${assets.get('blue_file.svg')}#icon"/> <use xlink:href="${assets.get('blue_file.svg')}#icon"/>
</svg> </svg>
<p class="flex-grow"> <p class="flex-grow">
@ -188,7 +188,7 @@ function archiveDetails(translate, archive) {
ontoggle="${toggled}" ontoggle="${toggled}"
> >
<summary <summary
class="flex items-center link-blue text-sm cursor-pointer outline-none" class="flex items-center link-primary text-sm cursor-pointer outline-none"
> >
<svg <svg
class="fill-current w-4 h-4 mr-1" class="fill-current w-4 h-4 mr-1"
@ -218,7 +218,7 @@ module.exports = function(state, emit, archive) {
state.capabilities.share || platform() === 'android' state.capabilities.share || platform() === 'android'
? html` ? html`
<button <button
class="link-blue self-end flex items-start" class="link-primary self-end flex items-start"
onclick=${share} onclick=${share}
title="Share link" title="Share link"
> >
@ -230,7 +230,7 @@ module.exports = function(state, emit, archive) {
` `
: html` : html`
<button <button
class="link-blue focus:outline self-end flex items-center" class="link-primary focus:outline self-end flex items-center"
onclick=${copy} onclick=${copy}
title="${state.translate('copyLinkButton')}" title="${state.translate('copyLinkButton')}"
> >
@ -244,7 +244,7 @@ module.exports = function(state, emit, archive) {
platform() === 'web' platform() === 'web'
? html` ? html`
<a <a
class="flex items-baseline link-blue" class="flex items-baseline link-primary"
href="${archive.url}" href="${archive.url}"
title="${state.translate('downloadButtonLabel')}" title="${state.translate('downloadButtonLabel')}"
tabindex="0" tabindex="0"
@ -261,7 +261,7 @@ module.exports = function(state, emit, archive) {
return html` return html`
<send-archive <send-archive
id="archive-${archive.id}" id="archive-${archive.id}"
class="flex flex-col items-start rounded shadow-light bg-white p-4 w-full dark:bg-grey-90 dark:border dark:border-grey-70" class="flex flex-col items-start rounded-default shadow-light bg-white p-4 w-full dark:bg-grey-90 dark:border-default dark:border-grey-70"
> >
${archiveInfo( ${archiveInfo(
archive, archive,
@ -335,7 +335,7 @@ module.exports.wip = function(state, emit) {
fileInfo(f, remove(f, state.translate('deleteButtonHover'))) fileInfo(f, remove(f, state.translate('deleteButtonHover')))
), ),
'flex-shrink bg-grey-10 rounded-t overflow-y-auto px-6 py-4 md:h-full md:max-h-half-screen dark:bg-black', 'flex-shrink bg-grey-10 rounded-t overflow-y-auto px-6 py-4 md:h-full md:max-h-half-screen dark:bg-black',
'bg-white px-2 my-2 shadow-light rounded dark:bg-grey-90 dark:border dark:border-grey-80' 'bg-white px-2 my-2 shadow-light rounded-default dark:bg-grey-90 dark:border-default dark:border-grey-80'
)} )}
<div <div
class="flex-shrink-0 flex-grow flex items-end p-4 bg-grey-10 rounded-b mb-1 font-medium dark:bg-grey-90" class="flex-shrink-0 flex-grow flex items-end p-4 bg-grey-10 rounded-b mb-1 font-medium dark:bg-grey-90"
@ -358,7 +358,7 @@ module.exports.wip = function(state, emit) {
class="flex items-center cursor-pointer" class="flex items-center cursor-pointer"
title="${state.translate('addFilesButton')}" title="${state.translate('addFilesButton')}"
> >
<svg class="w-6 h-6 mr-2 link-blue"> <svg class="w-6 h-6 mr-2 link-primary">
<use xlink:href="${assets.get('addfiles.svg')}#plus" /> <use xlink:href="${assets.get('addfiles.svg')}#plus" />
</svg> </svg>
${state.translate('addFilesButton')} ${state.translate('addFilesButton')}
@ -438,7 +438,7 @@ module.exports.uploading = function(state, emit) {
return html` return html`
<send-upload-area <send-upload-area
id="${archive.id}" id="${archive.id}"
class="flex flex-col items-start rounded shadow-light bg-white p-4 w-full dark:bg-grey-90" class="flex flex-col items-start rounded-default shadow-light bg-white p-4 w-full dark:bg-grey-90"
> >
${archiveInfo(archive)} ${archiveInfo(archive)}
<div class="text-xs opacity-75 w-full mt-2 mb-2"> <div class="text-xs opacity-75 w-full mt-2 mb-2">
@ -448,12 +448,12 @@ module.exports.uploading = function(state, emit) {
expiresAt: Date.now() + 500 + state.archive.timeLimit * 1000 expiresAt: Date.now() + 500 + state.archive.timeLimit * 1000
})} })}
</div> </div>
<div class="link-blue text-sm font-medium mt-2"> <div class="link-primary text-sm font-medium mt-2">
${progressPercent} ${progressPercent}
</div> </div>
<progress class="my-3" value="${progress}">${progressPercent}</progress> <progress class="my-3" value="${progress}">${progressPercent}</progress>
<button <button
class="link-blue self-end font-medium" class="link-primary self-end font-medium"
onclick=${cancel} onclick=${cancel}
title="${state.translate('deletePopupCancel')}" title="${state.translate('deletePopupCancel')}"
> >
@ -475,7 +475,7 @@ module.exports.empty = function(state, emit) {
? '' ? ''
: html` : html`
<button <button
class="center font-medium text-sm link-blue mt-4 mb-2" class="center font-medium text-sm link-primary mt-4 mb-2"
onclick="${event => { onclick="${event => {
event.stopPropagation(); event.stopPropagation();
emit('signup-cta', 'drop'); emit('signup-cta', 'drop');
@ -486,16 +486,26 @@ module.exports.empty = function(state, emit) {
})} })}
</button> </button>
`; `;
const uploadNotice = state.WEB_UI.UPLOAD_AREA_NOTICE_HTML
? html`
<p
class="w-full mt-8 p-2 border-default dark:border-grey-70 rounded-default text-orange-60 bg-yellow-40 text-center leading-normal"
>
${raw(state.WEB_UI.UPLOAD_AREA_NOTICE_HTML)}
</p>
`
: '';
return html` return html`
<send-upload-area <send-upload-area
class="flex flex-col items-center justify-center border-2 border-dashed border-grey-transparent rounded px-6 py-16 h-full w-full dark:border-grey-60" class="flex flex-col items-center justify-center border-2 border-dashed border-grey-transparent rounded-default px-6 py-16 h-full w-full dark:border-grey-60"
onclick="${e => { onclick="${e => {
if (e.target.tagName !== 'LABEL') { if (e.target.tagName !== 'LABEL') {
document.getElementById('file-upload').click(); document.getElementById('file-upload').click();
} }
}}" }}"
> >
<svg class="w-10 h-10 link-blue"> <svg class="w-10 h-10 link-primary">
<use xlink:href="/${assets.get('addfiles.svg')}#plus" /> <use xlink:href="/${assets.get('addfiles.svg')}#plus" />
</svg> </svg>
<div class="pt-6 pb-2 text-center text-lg font-bold tracking-wide"> <div class="pt-6 pb-2 text-center text-lg font-bold tracking-wide">
@ -526,16 +536,16 @@ module.exports.empty = function(state, emit) {
> >
${state.translate('addFilesButton')} ${state.translate('addFilesButton')}
</label> </label>
${upsell} ${upsell} ${uploadNotice}
</send-upload-area> </send-upload-area>
`; `;
function focus(event) { function focus(event) {
event.target.nextElementSibling.classList.add('bg-blue-70', 'outline'); event.target.nextElementSibling.classList.add('bg-primary', 'outline');
} }
function blur(event) { function blur(event) {
event.target.nextElementSibling.classList.remove('bg-blue-70', 'outline'); event.target.nextElementSibling.classList.remove('bg-primary', 'outline');
} }
function add(event) { function add(event) {
@ -559,11 +569,43 @@ module.exports.preview = function(state, emit) {
${archiveDetails(state.translate, archive)} ${archiveDetails(state.translate, archive)}
</div> </div>
`; `;
const notice = state.WEB_UI.DOWNLOAD_NOTICE_HTML
? html`
<p
class="w-full mt-4 p-2 border-default dark:border-grey-70 rounded-default text-orange-60 bg-yellow-40 text-center leading-normal"
>
${raw(state.WEB_UI.DOWNLOAD_NOTICE_HTML)}
</p>
`
: '';
const sponsor = state.WEB_UI.SHOW_THUNDERBIRD_SPONSOR
? html`
<a
class="w-full mt-5 mb-2 p-2 border-default dark:border-grey-70 rounded-default text-orange-60 bg-yellow-40 text-center leading-normal"
href="https://www.thunderbird.net/"
>
<svg
width="30"
height="30"
class="m-2 mr-3 d-inline-block align-middle"
>
<image
xlink:href="${assets.get('thunderbird-icon.svg')}"
src="${assets.get('thunderbird-icon.svg')}"
width="30"
height="30"
/>
</svg>
${state.translate('sponsoredByThunderbird')}
</a>
`
: '';
return html` return html`
<send-archive <send-archive
class="flex flex-col max-h-full bg-white p-4 w-full md:w-128 dark:bg-grey-90" class="flex flex-col max-h-full bg-white p-4 w-full md:w-128 dark:bg-grey-90"
> >
<div class="border rounded py-3 px-6 dark:border-grey-70"> <div class="border-default rounded-default py-3 px-6 dark:border-grey-70">
${archiveInfo(archive)} ${details} ${archiveInfo(archive)} ${details}
</div> </div>
<button <button
@ -574,6 +616,7 @@ module.exports.preview = function(state, emit) {
> >
${state.translate('downloadButtonLabel')} ${state.translate('downloadButtonLabel')}
</button> </button>
${notice} ${sponsor}
</send-archive> </send-archive>
`; `;
@ -590,10 +633,10 @@ module.exports.downloading = function(state) {
const progressPercent = percent(progress); const progressPercent = percent(progress);
return html` return html`
<send-archive <send-archive
class="flex flex-col bg-white rounded shadow-light p-4 w-full max-w-sm md:w-128 dark:bg-grey-90" class="flex flex-col bg-white rounded-default shadow-light p-4 w-full max-w-sm md:w-128 dark:bg-grey-90"
> >
${archiveInfo(archive)} ${archiveInfo(archive)}
<div class="link-blue text-sm font-medium mt-2"> <div class="link-primary text-sm font-medium mt-2">
${progressPercent} ${progressPercent}
</div> </div>
<progress class="my-3" value="${progress}">${progressPercent}</progress> <progress class="my-3" value="${progress}">${progressPercent}</progress>

View file

@ -21,7 +21,7 @@ module.exports = function(name, url) {
<input <input
type="text" type="text"
id="share-url" id="share-url"
class="block w-full my-4 border rounded-lg leading-loose h-12 px-2 py-1 dark:bg-grey-80" class="block w-full my-4 border-default rounded-lg leading-loose h-12 px-2 py-1 dark:bg-grey-80"
value="${url}" value="${url}"
readonly="true" readonly="true"
/> />
@ -42,7 +42,7 @@ module.exports = function(name, url) {
${state.translate('copyLinkButton')} ${state.translate('copyLinkButton')}
</button> </button>
<button <button
class="link-blue my-4 font-medium cursor-pointer focus:outline" class="link-primary my-4 font-medium cursor-pointer focus:outline"
onclick="${close}" onclick="${close}"
title="${state.translate('okButton')}" title="${state.translate('okButton')}"
> >

View file

@ -11,7 +11,9 @@ 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-8 h-48" /> <svg class="my-8 h-48 text-primary">
<use xlink:href="${assets.get('completed.svg')}#Page-1" />
</svg>
<p <p
class="text-grey-80 leading-normal dark:text-grey-40 ${state.user class="text-grey-80 leading-normal dark:text-grey-40 ${state.user
.loggedIn .loggedIn

View file

@ -17,7 +17,7 @@ module.exports = function(state, emit) {
${state.translate('downloadDescription')} ${state.translate('downloadDescription')}
</p> </p>
<form <form
class="flex flex-row flex-no-wrap w-full md:w-4/5" class="flex flex-row flex-nowrap w-full md:w-4/5"
onsubmit="${checkPassword}" onsubmit="${checkPassword}"
data-no-csrf data-no-csrf
> >
@ -32,7 +32,7 @@ module.exports = function(state, emit) {
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
? 'border-red dark:border-red-40' ? 'border-red dark:border-red-40'
: 'border-grey'} leading-loose px-2 py-1 dark:bg-grey-80" : 'border-grey'} leading-loose px-2 py-1 dark:bg-grey-80"
maxlength="32" maxlength="4096"
autocomplete="off" autocomplete="off"
placeholder="${state.translate('unlockInputPlaceholder')}" placeholder="${state.translate('unlockInputPlaceholder')}"
oninput="${inputChanged}" oninput="${inputChanged}"

View file

@ -13,7 +13,9 @@ module.exports = function(state, emit) {
<h1 class="text-center text-3xl font-bold my-2"> <h1 class="text-center text-3xl font-bold my-2">
${state.translate('errorPageHeader')} ${state.translate('errorPageHeader')}
</h1> </h1>
<img class="my-12 h-48" src="${assets.get('error.svg')}" /> <svg class="text-primary my-12 h-48">
<use xlink:href="${assets.get('error.svg')}#svg114" />
</svg>
<p <p
class="max-w-md text-center text-grey-80 leading-normal dark:text-grey-40 ${state class="max-w-md text-center text-grey-80 leading-normal dark:text-grey-40 ${state
.user.loggedIn .user.loggedIn

View file

@ -1,9 +1,11 @@
/*global WEB_UI*/
const { platform } = require('../utils'); const { platform } = require('../utils');
const assets = require('../../common/assets'); const assets = require('../../common/assets');
const size = 32; const size = 32;
const loaderWidth = 5; const loaderWidth = 5;
const loaderColor = '#0090ed'; const loaderColor = WEB_UI.COLORS.PRIMARY;
function drawCircle(canvas, context, color, lineWidth, outerWidth, percent) { function drawCircle(canvas, context, color, lineWidth, outerWidth, percent) {
canvas.width = canvas.height = outerWidth; canvas.width = canvas.height = outerWidth;
@ -32,7 +34,10 @@ module.exports.updateFavicon = function(progressRatio) {
const progress = progressRatio * 100; const progress = progressRatio * 100;
if (progress === 0 || progress === 100) { if (progress === 0 || progress === 100) {
link.type = 'image/png'; link.type = 'image/png';
link.href = assets.get('favicon-32x32.png'); link.href =
WEB_UI.CUSTOM_ASSETS.favicon_32px !== ''
? WEB_UI.CUSTOM_ASSETS.favicon_32px
: assets.get('favicon-32x32.png');
return; return;
} }

View file

@ -65,6 +65,45 @@ class Footer extends Component {
`); `);
} }
// Defining a custom footer
var footer = [];
if (this.state != undefined && this.state.WEB_UI != undefined) {
const WEB_UI = this.state.WEB_UI;
if (WEB_UI.CUSTOM_FOOTER_URL != '' && WEB_UI.CUSTOM_FOOTER_TEXT != '') {
footer.push(html`
<li class="m-2">
<a href="${WEB_UI.CUSTOM_FOOTER_URL}" target="_blank">
${WEB_UI.CUSTOM_FOOTER_TEXT}
</a>
</li>
`);
}
else if (WEB_UI.CUSTOM_FOOTER_URL != '') {
footer.push(html`
<li class="m-2">
<a href="${WEB_UI.CUSTOM_FOOTER_URL}" target="_blank">
${WEB_UI.CUSTOM_FOOTER_URL}
</a>
</li>
`);
}
else if (WEB_UI.CUSTOM_FOOTER_TEXT != '') {
footer.push(html`
<li class="m-2">
${WEB_UI.CUSTOM_FOOTER_TEXT}
</li>
`)
}
else {
footer.push(html`
<li class="m-2">
${translate('footerText')}
</li>
`);
}
}
return html` return html`
<footer <footer
class="flex flex-col md:flex-row items-start w-full flex-none self-start p-6 md:p-8 font-medium text-xs text-grey-60 dark:text-grey-40 md:items-center justify-between" class="flex flex-col md:flex-row items-start w-full flex-none self-start p-6 md:p-8 font-medium text-xs text-grey-60 dark:text-grey-40 md:items-center justify-between"
@ -72,7 +111,7 @@ class Footer extends Component {
<ul <ul
class="flex flex-col md:flex-row items-start md:items-center md:justify-start" class="flex flex-col md:flex-row items-start md:items-center md:justify-start"
> >
<li class="m-2">${translate('footerText')}</li> ${footer}
</ul> </ul>
<ul <ul
class="flex flex-col md:flex-row items-start md:items-center md:justify-end" class="flex flex-col md:flex-row items-start md:items-center md:justify-end"

View file

@ -18,13 +18,26 @@ class Header extends Component {
} }
createElement() { createElement() {
let assetMap = {};
if (this.state.ui !== undefined) assetMap = this.state.ui.assets;
else
assetMap = {
icon:
this.state.WEB_UI.CUSTOM_ASSETS.icon !== ''
? this.state.WEB_UI.CUSTOM_ASSETS.icon
: assets.get('icon.svg'),
wordmark:
this.state.WEB_UI.CUSTOM_ASSETS.wordmark !== ''
? this.state.WEB_UI.CUSTOM_ASSETS.wordmark
: assets.get('wordmark.svg') + '#logo'
};
const title = const title =
platform() === 'android' platform() === 'android'
? html` ? html`
<a class="flex flex-row items-center"> <a class="flex flex-row items-center">
<img src="${assets.get('icon.svg')}" /> <img src="${assetMap.icon}" />
<svg class="w-48"> <svg class="w-48">
<use xlink:href="${assets.get('wordmark.svg')}#logo" /> <use xlink:href="${assetMap.wordmark}" />
</svg> </svg>
</a> </a>
` `
@ -32,10 +45,10 @@ class Header extends Component {
<a class="flex flex-row items-center" href="/"> <a class="flex flex-row items-center" href="/">
<img <img
alt="${this.state.translate('title')}" alt="${this.state.translate('title')}"
src="${assets.get('icon.svg')}" src="${assetMap.icon}"
/> />
<svg viewBox="66 0 340 64" 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="${assetMap.wordmark}" />
</svg> </svg>
</a> </a>
`; `;

View file

@ -1,8 +1,10 @@
const html = require('choo/html'); const html = require('choo/html');
const raw = require('choo/html/raw');
const { list } = require('../utils'); const { list } = require('../utils');
const archiveTile = require('./archiveTile'); const archiveTile = require('./archiveTile');
const modal = require('./modal'); const modal = require('./modal');
const intro = require('./intro'); const intro = require('./intro');
const assets = require('../../common/assets');
module.exports = function(state, emit) { module.exports = function(state, emit) {
const archives = state.storage.files const archives = state.storage.files
@ -16,7 +18,42 @@ module.exports = function(state, emit) {
} else { } else {
left = archiveTile.empty(state, emit); left = archiveTile.empty(state, emit);
} }
if (archives.length > 0 && state.WEB_UI.UPLOADS_LIST_NOTICE_HTML) {
archives.push(html`
<p
class="w-full p-2 border-default dark:border-grey-70 rounded-default text-orange-60 bg-yellow-40 text-center leading-normal"
>
${raw(state.WEB_UI.UPLOADS_LIST_NOTICE_HTML)}
</p>
`);
}
archives.reverse(); archives.reverse();
if (archives.length > 0 && state.WEB_UI.SHOW_THUNDERBIRD_SPONSOR) {
archives.push(html`
<a
class="w-full p-2 border-default dark:border-grey-70 rounded-default text-orange-60 bg-yellow-40 text-center leading-normal d-block"
href="https://www.thunderbird.net/"
>
<svg
width="30"
height="30"
class="m-2 mr-3 d-inline-block align-middle"
>
<image
xlink:href="${assets.get('thunderbird-icon.svg')}"
src="${assets.get('thunderbird-icon.svg')}"
width="30"
height="30"
/>
</svg>
Sponsored by Thunderbird
</a>
`);
}
const right = const right =
archives.length === 0 archives.length === 0
? intro(state) ? intro(state)

View file

@ -1,10 +1,46 @@
const html = require('choo/html'); const html = require('choo/html');
const raw = require('choo/html/raw');
const assets = require('../../common/assets');
module.exports = function intro(state) { module.exports = function intro(state) {
const notice = state.WEB_UI.MAIN_NOTICE_HTML
? html`
<p
class="w-full mt-2 p-2 border-default dark:border-grey-70 rounded-default text-orange-60 bg-yellow-40 text-center leading-normal"
>
${raw(state.WEB_UI.MAIN_NOTICE_HTML)}
</p>
`
: '';
const sponsor = state.WEB_UI.SHOW_THUNDERBIRD_SPONSOR
? html`
<a
class="w-full mt-5 mb-2 p-2 border-default dark:border-grey-70 rounded-default text-orange-60 bg-yellow-40 text-center leading-normal"
href="https://www.thunderbird.net/"
>
<svg
width="30"
height="30"
class="m-2 mr-3 d-inline-block align-middle"
>
<image
xlink:href="${assets.get('thunderbird-icon.svg')}"
src="${assets.get('thunderbird-icon.svg')}"
width="30"
height="30"
/>
</svg>
Sponsored by Thunderbird
</a>
`
: '';
return html` return html`
<send-intro <send-intro
class="flex flex-col items-center justify-center bg-white px-6 md:py-0 py-6 mb-0 h-full w-full dark:bg-grey-90" class="flex flex-col items-center justify-center bg-white px-6 md:py-0 py-6 mb-0 h-full w-full dark:bg-grey-90"
> >
${notice}
<div class="mt-12 flex flex-col h-full"> <div class="mt-12 flex flex-col h-full">
<h1 class="text-3xl font-bold md:pb-2"> <h1 class="text-3xl font-bold md:pb-2">
${state.translate('introTitle')} ${state.translate('introTitle')}
@ -13,6 +49,7 @@ module.exports = function intro(state) {
${state.translate('introDescription')} ${state.translate('introDescription')}
</p> </p>
</div> </div>
${sponsor}
</send-intro> </send-intro>
`; `;
}; };

View file

@ -12,14 +12,14 @@ module.exports = function(state, emit) {
'downloadTitle' 'downloadTitle'
)}</h1> )}</h1>
<p <p
class="w-full p-2 border border-yellow-50 rounded md:w-4/5 text-orange-60 bg-yellow-40 text-center leading-normal" class="w-full p-2 border-default border-yellow-50 rounded-default md:w-4/5 text-orange-60 bg-yellow-40 text-center leading-normal"
> >
${state.translate('noStreamsWarning')} ${state.translate('noStreamsWarning')}
</p> </p>
<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-default rounded-default p-4 my-4" onchange=${optionChanged}>
<div class="flex items-center mb-2"> <div class="flex items-center mb-2">
<svg class="h-8 w-6 mr-3 flex-shrink-0 text-white dark:text-grey-90"> <svg class="h-8 w-6 mr-3 flex-shrink-0 text-primary">
<use xlink:href="${assets.get('blue_file.svg')}#icon"/> <use xlink:href="${assets.get('blue_file.svg')}#icon"/>
</svg> </svg>
<p class="flex-grow"> <p class="flex-grow">

View file

@ -13,7 +13,9 @@ module.exports = function(state, emit) {
<h1 class="text-center text-3xl font-bold my-2"> <h1 class="text-center text-3xl font-bold my-2">
${state.translate('expiredTitle')} ${state.translate('expiredTitle')}
</h1> </h1>
<img src="${assets.get('notFound.svg')}" class="my-12" /> <svg class="text-primary my-12">
<use xlink:href="${assets.get('notFound.svg')}#svg124" />
</svg>
<p <p
class="max-w-md text-center text-grey-80 leading-normal dark:text-grey-40 ${state class="max-w-md text-center text-grey-80 leading-normal dark:text-grey-40 ${state
.user.loggedIn .user.loggedIn

View file

@ -2,7 +2,7 @@ const raw = require('choo/html/raw');
const qrcode = require('../qrcode'); const qrcode = require('../qrcode');
module.exports = function(url) { module.exports = function(url) {
const gen = qrcode(5, 'L'); const gen = qrcode(0, 'L');
gen.addData(url); gen.addData(url);
gen.make(); gen.make();
const qr = gen.createSvgTag({ scalable: true }); const qr = gen.createSvgTag({ scalable: true });

View file

@ -3,7 +3,14 @@ const html = require('choo/html');
module.exports = function(selected, options, translate, changed, htmlId) { module.exports = function(selected, options, translate, changed, htmlId) {
function choose(event) { function choose(event) {
if (event.target.value != selected) { if (event.target.value != selected) {
console.log('Selected new value from dropdown', htmlId, ':', selected, '->', event.target.value) console.log(
'Selected new value from dropdown',
htmlId,
':',
selected,
'->',
event.target.value
);
changed(event.target.value); changed(event.target.value);
} }
} }
@ -11,7 +18,7 @@ module.exports = function(selected, options, translate, changed, htmlId) {
return html` return html`
<select <select
id="${htmlId}" id="${htmlId}"
class="appearance-none cursor-pointer border rounded bg-grey-10 hover:border-blue-50 focus:border-blue-50 pl-1 pr-8 py-1 my-1 h-8 dark:bg-grey-80" class="appearance-none cursor-pointer border-default rounded-default bg-grey-10 hover:border-primary focus:border-primary pl-1 pr-8 py-1 my-1 h-8 dark:bg-grey-80"
data-selected="${selected}" data-selected="${selected}"
onchange="${choose}" onchange="${choose}"
> >

View file

@ -18,7 +18,7 @@ module.exports = function(name, url) {
<input <input
type="text" type="text"
id="share-url" id="share-url"
class="w-full my-4 border rounded-lg leading-loose h-12 px-2 py-1 dark:bg-grey-80" class="w-full my-4 border-default rounded-lg leading-loose h-12 px-2 py-1 dark:bg-grey-80"
value="${url}" value="${url}"
readonly="true" readonly="true"
/> />
@ -30,7 +30,7 @@ module.exports = function(name, url) {
${state.translate('shareLinkButton')} ${state.translate('shareLinkButton')}
</button> </button>
<button <button
class="link-blue my-4 font-medium cursor-pointer focus:outline" class="link-primary my-4 font-medium cursor-pointer focus:outline"
onclick="${close}" onclick="${close}"
title="${state.translate('okButton')}" title="${state.translate('okButton')}"
> >

View file

@ -35,7 +35,7 @@ module.exports = function() {
<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-default 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
@ -50,7 +50,7 @@ module.exports = function() {
? '' ? ''
: html` : html`
<button <button
class="my-3 link-blue font-medium" class="my-3 link-primary font-medium"
title="${state.translate('deletePopupCancel')}" title="${state.translate('deletePopupCancel')}"
onclick=${cancel} onclick=${cancel}
> >

View file

@ -30,7 +30,7 @@ module.exports = function() {
Give feedback Give feedback
</a> </a>
<button <button
class="link-blue font-medium cursor-pointer focus:outline" class="link-primary font-medium cursor-pointer focus:outline"
onclick="${close}" onclick="${close}"
title="Skip" title="Skip"
> >

View file

@ -10,8 +10,8 @@ module.exports = function(state, emit) {
strings = unsupportedStrings(state); strings = unsupportedStrings(state);
why = html` why = html`
<a <a
class="text-blue" class="text-primary"
href="https://github.com/mozilla/send/blob/master/docs/faq.md#why-is-my-browser-not-supported" href="https://github.com/timvisee/send/blob/master/docs/faq.md#why-is-my-browser-not-supported"
> >
${state.translate('notSupportedLink')} ${state.translate('notSupportedLink')}
</a> </a>
@ -27,7 +27,7 @@ module.exports = function(state, emit) {
<main class="main"> <main class="main">
${state.modal && modal(state, emit)} ${state.modal && modal(state, emit)}
<section <section
class="flex flex-col items-center justify-center text-center bg-white m-6 px-6 py-8 border border-grey-30 md:border-none md:px-12 md:py-16 shadow w-full md:h-full dark:bg-grey-90" class="flex flex-col items-center justify-center text-center bg-white m-6 px-6 py-8 border-default border-grey-30 md:border-none md:px-12 md:py-16 shadow-default w-full md:h-full dark:bg-grey-90"
> >
<h1 class="text-3xl font-bold">${strings.header}</h1> <h1 class="text-3xl font-bold">${strings.header}</h1>
<p class="mt-4 mb-8 max-w-md leading-normal">${strings.description}</p> <p class="mt-4 mb-8 max-w-md leading-normal">${strings.description}</p>

View file

@ -29,7 +29,7 @@ class File {
const v = new DataView(h); const v = new DataView(h);
v.setUint32(0, 0x04034b50, true); // sig v.setUint32(0, 0x04034b50, true); // sig
v.setUint16(4, 20, true); // version v.setUint16(4, 20, true); // version
v.setUint16(6, 8, true); // bit flags (8 = use data descriptor) v.setUint16(6, 0x808, true); // bit flags (use data descriptor(8) + utf8-encoded(8 << 8))
v.setUint16(8, 0, true); // compression v.setUint16(8, 0, true); // compression
v.setUint16(10, this.dateTime.time, true); // modified time v.setUint16(10, this.dateTime.time, true); // modified time
v.setUint16(12, this.dateTime.date, true); // modified date v.setUint16(12, this.dateTime.date, true); // modified date
@ -60,7 +60,7 @@ class File {
v.setUint32(0, 0x02014b50, true); // sig v.setUint32(0, 0x02014b50, true); // sig
v.setUint16(4, 20, true); // version made v.setUint16(4, 20, true); // version made
v.setUint16(6, 20, true); // version required v.setUint16(6, 20, true); // version required
v.setUint16(8, 8, true); // bit flags (8 = use data descriptor) v.setUint16(8, 0x808, true); // bit flags (use data descriptor(8) + utf8-encoded(8 << 8))
v.setUint16(10, 0, true); // compression v.setUint16(10, 0, true); // compression
v.setUint16(12, this.dateTime.time, true); // modified time v.setUint16(12, this.dateTime.time, true); // modified time
v.setUint16(14, this.dateTime.date, true); // modified date v.setUint16(14, this.dateTime.date, true); // modified date

View file

@ -1,26 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
<!--
This would be the elegant way, but chrome cannot handle masks in external SVGs.
See https://bugs.chromium.org/p/chromium/issues/detail?id=109212
-->
<!--
<symbol id="icon" viewBox="0 0 26 32"> <symbol id="icon" viewBox="0 0 26 32">
<defs> <g id="Fire-Icon">
<path d="M21.848475,31.6653183 L2.89005487,31.6653183 C1.32717435,31.6653183 0.104050469,30.3742431 0.104050469,28.8793139 L0.104050469,2.7860044 C0.104050469,1.22312388 1.39512568,0 2.89005487,0 L14.7135857,0 C15.4610503,0 16.2085149,0.271805307 16.6841742,0.815415921 L23.8190635,7.95030523 C24.3626741,8.49391584 24.6344794,9.17342911 24.6344794,9.9208937 L24.6344794,28.8793139 C24.6344794,30.3742431 23.4113555,31.6653183 21.848475,31.6653183 Z" id="path-1"></path> <mask id="mask">
</defs> <rect x="0" y="0" width="100" height="100" fill="white"/>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <path d="M7.2830232,8.93885547 L8.91906464,8.93885547" stroke="black" stroke-width="2" stroke-linecap="round"/>
<g id="Send_Ready_to_Send-Spec" transform="translate(-277.000000, -206.000000)"> <path d="M7.2830232,15.7798836 L17.5412669,15.7798836" stroke="black" stroke-width="2" stroke-linecap="round"/>
<g id="List-Item-1" transform="translate(253.000000, 192.000000)"> <path d="M7.2830232,22.6209117 L17.5412669,22.6209117" stroke="black" stroke-width="2" stroke-linecap="round"/>
<g id="Locked-File-Icon" transform="translate(24.000000, 14.000000)"> <path d="M24.3031318,10.6474633 L16.7826187,10.6474633 C15.2742552,10.6474633 14.051485,9.42469306 14.051485,7.91632957 L14.051485,0.395816478" id="Path" stroke-linecap="square" stroke="black" stroke-width="2" fill="none"/>
<g id="File-Icon">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask> </mask>
<use id="Mask" fill="#45a1ff" xlink:href="#path-1"></use> <path d="M21.848475,31.6653183 L2.89005487,31.6653183 C1.32717435,31.6653183 0.104050469,30.3742431 0.104050469,28.8793139 L0.104050469,2.7860044 C0.104050469,1.22312388 1.39512568,0 2.89005487,0 L14.7135857,0 C15.4610503,0 16.2085149,0.271805307 16.6841742,0.815415921 L23.8190635,7.95030523 C24.3626741,8.49391584 24.6344794,9.17342911 24.6344794,9.9208937 L24.6344794,28.8793139 C24.6344794,30.3742431 23.4113555,31.6653183 21.848475,31.6653183 Z" id="path-1" fill="currentColor" mask="url(#mask)" />
<path d="M24.3031318,10.6474633 L16.7826187,10.6474633 C15.2742552,10.6474633 14.051485,9.42469306 14.051485,7.91632957 L14.051485,0.395816478" id="Path" stroke="currentColor" stroke-width="2" stroke-linecap="round" mask="url(#mask-2)"></path>
<path d="M7.2830232,8.93885547 L8.91906464,8.93885547" id="Path" stroke="currentColor" stroke-width="2" stroke-linecap="round" mask="url(#mask-2)"></path>
<path d="M7.2830232,15.7798836 L17.5412669,15.7798836" id="Path" stroke="currentColor" stroke-width="2" stroke-linecap="round" mask="url(#mask-2)"></path>
<path d="M7.2830232,22.6209117 L17.5412669,22.6209117" id="Path" stroke="currentColor" stroke-width="2" stroke-linecap="round" mask="url(#mask-2)"></path>
</g>
</g>
</g>
</g>
</g> </g>
</symbol> </symbol>
-->
<symbol id="icon" viewBox="0 0 26 32">
<path d="m 15 0 c 0.7 0.1 1.233 0.331 1.7 0.8 l 7.1 7.1 c 0.5 0.5 0.8 1.1 0.8 1.8 h -7.9 c -1 0 -1.7 -0.8 -1.7 -1.7 V 0.4 z M 24.65 11.647 v 17.23 c 0 1.5 -1.2 2.8 -2.8 2.8 h -19 c -1.234 -0.017 -2.694 -1.094 -2.7 -2.8 V 2.8 C 0.1 1.2 1.4 0 2.9 0 h 10.15 v 7.5 c -0.135 2.533 1.669 4.119 3.7 4.15 h 7.9 z M 6.3 8.9 c 0 0.6 0.4 1 1 1 h 1.6 c 0.5 0 1 -0.4 1 -1 c 0 -0.5 -0.5 -1 -1 -1 H 7.3 C 6.7 7.9 6.3 8.4 6.3 8.9 z M 18.5 22.6 c 0 -0.5 -0.4 -1 -1 -1 H 7.3 c -0.6 0 -1 0.5 -1 1 s 0.4 1 1 1 h 10.3 C 18.1 23.6 18.5 23.2 18.5 22.6 z M 18.5 15.8 c 0 -0.6 -0.4 -1 -1 -1 H 7.3 c -0.6 0 -1 0.4 -1 1 s 0.4 1 1 1 h 10.3 C 18.1 16.8 18.5 16.3 18.5 15.8 z" fill="currentColor" />
</symbol>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Before After
Before After

View file

@ -253,7 +253,7 @@
<path <path
id="cloud-check" id="cloud-check"
d="m 240.12048,110.31165 a 39.582604,39.582604 0 0 1 -10.23938,26.55813 33.935974,33.935974 0 0 1 -20.28366,10.27635 39.949372,39.949372 0 0 0 0.80301,-16.48404 16.944722,16.944722 0 0 0 7.65405,-4.47239 23.665469,23.665469 0 0 0 6.1311,-15.87805 26.589359,26.589359 0 0 0 -26.55812,-26.558123 c -0.87568,0 -5.3742,0.56186 -8.11085,0.91445 a 2.6398778,2.6398778 0 0 1 -2.83769,-1.77451 l -1.08155,-3.155106 A 32.772357,32.772357 0 0 0 158.37085,57.356128 31.757517,31.757517 0 0 0 124.14114,96.347867 l 1.13419,4.851433 a 2.6558127,2.6558127 0 0 1 -1.8179,3.14687 l -4.77313,1.44232 a 15.788381,15.788381 0 0 0 -11.35445,15.14642 10.699791,10.699791 0 0 0 2.19933,6.52543 12.871343,12.871343 0 0 0 9.50281,4.09782 h 7.25749 a 40.137987,40.137987 0 0 0 1.02966,15.93487 h -8.28715 A 28.433555,28.433555 0 0 1 96.535402,136.68302 26.739094,26.739094 0 0 1 91.39497,120.93491 31.54075,31.54075 0 0 1 107.53217,93.318597 c -0.13492,-1.42644 -0.20238,-2.84772 -0.20238,-4.25345 a 47.786197,47.786197 0 0 1 90.59848,-21.246498 42.542454,42.542454 0 0 1 42.19216,42.493001 z m -39.83719,26.55813 a 31.869752,31.869752 0 1 1 -31.86975,-31.86975 31.869752,31.869752 0 0 1 31.86975,31.86975 z m -15.15067,-11.86394 -2.71673,-2.01199 a 1.5763311,1.5763311 0 0 0 -2.00127,0.14182 l -16.73162,15.72576 -9.38033,-4.48657 a 1.7144864,1.7144864 0 0 0 -2.00221,0.5062 l -2.30275,2.94497 a 1.576756,1.576756 0 0 0 0.14182,2.00158 l 11.86234,11.8768 a 4.410933,4.410933 0 0 0 6.89242,-0.53116 l 16.51629,-24.2992 a 1.346922,1.346922 0 0 0 -0.27833,-1.86831 z" d="m 240.12048,110.31165 a 39.582604,39.582604 0 0 1 -10.23938,26.55813 33.935974,33.935974 0 0 1 -20.28366,10.27635 39.949372,39.949372 0 0 0 0.80301,-16.48404 16.944722,16.944722 0 0 0 7.65405,-4.47239 23.665469,23.665469 0 0 0 6.1311,-15.87805 26.589359,26.589359 0 0 0 -26.55812,-26.558123 c -0.87568,0 -5.3742,0.56186 -8.11085,0.91445 a 2.6398778,2.6398778 0 0 1 -2.83769,-1.77451 l -1.08155,-3.155106 A 32.772357,32.772357 0 0 0 158.37085,57.356128 31.757517,31.757517 0 0 0 124.14114,96.347867 l 1.13419,4.851433 a 2.6558127,2.6558127 0 0 1 -1.8179,3.14687 l -4.77313,1.44232 a 15.788381,15.788381 0 0 0 -11.35445,15.14642 10.699791,10.699791 0 0 0 2.19933,6.52543 12.871343,12.871343 0 0 0 9.50281,4.09782 h 7.25749 a 40.137987,40.137987 0 0 0 1.02966,15.93487 h -8.28715 A 28.433555,28.433555 0 0 1 96.535402,136.68302 26.739094,26.739094 0 0 1 91.39497,120.93491 31.54075,31.54075 0 0 1 107.53217,93.318597 c -0.13492,-1.42644 -0.20238,-2.84772 -0.20238,-4.25345 a 47.786197,47.786197 0 0 1 90.59848,-21.246498 42.542454,42.542454 0 0 1 42.19216,42.493001 z m -39.83719,26.55813 a 31.869752,31.869752 0 1 1 -31.86975,-31.86975 31.869752,31.869752 0 0 1 31.86975,31.86975 z m -15.15067,-11.86394 -2.71673,-2.01199 a 1.5763311,1.5763311 0 0 0 -2.00127,0.14182 l -16.73162,15.72576 -9.38033,-4.48657 a 1.7144864,1.7144864 0 0 0 -2.00221,0.5062 l -2.30275,2.94497 a 1.576756,1.576756 0 0 0 0.14182,2.00158 l 11.86234,11.8768 a 4.410933,4.410933 0 0 0 6.89242,-0.53116 l 16.51629,-24.2992 a 1.346922,1.346922 0 0 0 -0.27833,-1.86831 z"
style="fill:#45a1ff;fill-opacity:1;stroke-width:5.31163" /> style="fill-opacity:1;stroke-width:5.31163" fill="currentColor" />
</g> </g>
</g> </g>
</g> </g>

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Before After
Before After

View file

@ -5,8 +5,6 @@
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
width="356px"
height="210px"
viewBox="0 0 356 210" viewBox="0 0 356 210"
version="1.1" version="1.1"
id="svg114"> id="svg114">
@ -256,5 +254,5 @@
<path <path
id="cloud-alert" id="cloud-alert"
d="m 254.54362,110.61709 a 41.858804,41.858804 0 0 1 -10.8282,28.08534 35.887465,35.887465 0 0 1 -21.45007,10.8673 42.246663,42.246663 0 0 0 0.84918,-17.43196 17.919131,17.919131 0 0 0 8.09421,-4.72957 25.026353,25.026353 0 0 0 6.48366,-16.79111 28.118382,28.118382 0 0 0 -28.08535,-28.085359 c -0.92602,0 -5.68324,0.594174 -8.57727,0.967035 a 2.7916842,2.7916842 0 0 1 -3.0008,-1.876551 l -1.14369,-3.336147 A 34.656989,34.656989 0 0 0 168.09302,54.616462 33.58368,33.58368 0 0 0 131.89488,95.850311 l 1.19942,5.130409 a 2.8085354,2.8085354 0 0 1 -1.92244,3.32783 l -5.04762,1.52526 a 16.696293,16.696293 0 0 0 -12.00739,16.01742 11.315083,11.315083 0 0 0 2.32581,6.90069 13.611511,13.611511 0 0 0 10.04928,4.33345 h 7.67482 a 42.446125,42.446125 0 0 0 1.08887,16.85122 h -8.76369 A 30.06863,30.06863 0 0 1 102.70166,138.50495 28.276728,28.276728 0 0 1 97.265633,121.85123 33.354503,33.354503 0 0 1 114.33081,92.64684 c -0.14268,-1.508465 -0.21401,-3.01148 -0.21401,-4.498037 a 50.534146,50.534146 0 0 1 95.80834,-22.468284 44.988861,44.988861 0 0 1 44.61843,44.936571 z m -42.12804,28.08534 a 33.702425,33.702425 0 1 1 -33.70241,-33.70242 33.702425,33.702425 0 0 1 33.70241,33.70242 z m -28.08535,14.04269 a 2.8085354,2.8085354 0 0 0 -2.80853,-2.80853 h -5.61707 a 2.8085354,2.8085354 0 0 0 -2.80853,2.80853 v 5.61706 a 2.8085354,2.8085354 0 0 0 2.80853,2.80855 h 5.61707 a 2.8085354,2.8085354 0 0 0 2.80853,-2.80855 z m 0,-33.70243 a 2.8166239,2.8166239 0 0 0 -2.80853,-2.80853 h -5.61707 a 2.8166239,2.8166239 0 0 0 -2.80853,2.80853 v 11.23415 a 22.144684,22.144684 0 0 0 0.83447,5.49022 l 2.24351,7.21126 a 2.0333796,2.0333796 0 0 0 1.82117,1.34118 h 1.43583 a 2.0333796,2.0333796 0 0 0 1.82118,-1.34118 l 2.2435,-7.21126 a 22.144684,22.144684 0 0 0 0.83447,-5.49022 z" d="m 254.54362,110.61709 a 41.858804,41.858804 0 0 1 -10.8282,28.08534 35.887465,35.887465 0 0 1 -21.45007,10.8673 42.246663,42.246663 0 0 0 0.84918,-17.43196 17.919131,17.919131 0 0 0 8.09421,-4.72957 25.026353,25.026353 0 0 0 6.48366,-16.79111 28.118382,28.118382 0 0 0 -28.08535,-28.085359 c -0.92602,0 -5.68324,0.594174 -8.57727,0.967035 a 2.7916842,2.7916842 0 0 1 -3.0008,-1.876551 l -1.14369,-3.336147 A 34.656989,34.656989 0 0 0 168.09302,54.616462 33.58368,33.58368 0 0 0 131.89488,95.850311 l 1.19942,5.130409 a 2.8085354,2.8085354 0 0 1 -1.92244,3.32783 l -5.04762,1.52526 a 16.696293,16.696293 0 0 0 -12.00739,16.01742 11.315083,11.315083 0 0 0 2.32581,6.90069 13.611511,13.611511 0 0 0 10.04928,4.33345 h 7.67482 a 42.446125,42.446125 0 0 0 1.08887,16.85122 h -8.76369 A 30.06863,30.06863 0 0 1 102.70166,138.50495 28.276728,28.276728 0 0 1 97.265633,121.85123 33.354503,33.354503 0 0 1 114.33081,92.64684 c -0.14268,-1.508465 -0.21401,-3.01148 -0.21401,-4.498037 a 50.534146,50.534146 0 0 1 95.80834,-22.468284 44.988861,44.988861 0 0 1 44.61843,44.936571 z m -42.12804,28.08534 a 33.702425,33.702425 0 1 1 -33.70241,-33.70242 33.702425,33.702425 0 0 1 33.70241,33.70242 z m -28.08535,14.04269 a 2.8085354,2.8085354 0 0 0 -2.80853,-2.80853 h -5.61707 a 2.8085354,2.8085354 0 0 0 -2.80853,2.80853 v 5.61706 a 2.8085354,2.8085354 0 0 0 2.80853,2.80855 h 5.61707 a 2.8085354,2.8085354 0 0 0 2.80853,-2.80855 z m 0,-33.70243 a 2.8166239,2.8166239 0 0 0 -2.80853,-2.80853 h -5.61707 a 2.8166239,2.8166239 0 0 0 -2.80853,2.80853 v 11.23415 a 22.144684,22.144684 0 0 0 0.83447,5.49022 l 2.24351,7.21126 a 2.0333796,2.0333796 0 0 0 1.82117,1.34118 h 1.43583 a 2.0333796,2.0333796 0 0 0 1.82118,-1.34118 l 2.2435,-7.21126 a 22.144684,22.144684 0 0 0 0.83447,-5.49022 z"
style="stroke-width:5.61707;fill:#45a1ff;fill-opacity:1" /> style="stroke-width:5.61707;fill:currentColor;fill-opacity:1" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Before After
Before After

BIN
assets/icon-64x64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -5,8 +5,6 @@
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
width="348px"
height="210px"
viewBox="0 0 348 210" viewBox="0 0 348 210"
version="1.1" version="1.1"
id="svg124"> id="svg124">
@ -272,5 +270,5 @@
<path <path
id="cloud-off" id="cloud-off"
d="M 232.66609,50.155807 A 8.2118103,8.2118103 0 0 0 221.05286,38.54253 l -24.58739,24.587284 a 49.087021,49.087021 0 0 0 -82.69072,35.970548 c 0,1.448998 0.0696,2.914018 0.20861,4.384368 a 32.511588,32.511588 0 0 0 -16.633903,28.46635 27.562135,27.562135 0 0 0 5.298643,16.23286 22.799931,22.799931 0 0 0 4.2838,4.4793 l -7.176402,7.17673 a 8.2118072,8.2118072 0 1 0 11.613272,11.61322 z M 118.72657,140.86955 a 8.5946237,8.5946237 0 0 1 -2.68479,-2.19217 11.029135,11.029135 0 0 1 -2.26703,-6.7263 16.274355,16.274355 0 0 1 11.70415,-15.61263 l 4.92005,-1.48644 a 2.738162,2.738162 0 0 0 1.8737,-3.24418 l -1.16893,-5.00059 a 32.735029,32.735029 0 0 1 35.28314,-40.191861 31.860268,31.860268 0 0 1 18.36694,8.426592 z m 131.92616,-19.86871 a 40.800975,40.800975 0 0 1 -10.55455,27.3756 35.587128,35.587128 0 0 1 -25.2904,10.95024 h -71.10166 l 16.42536,-16.42536 h 54.6763 a 19.17354,19.17354 0 0 0 13.09966,-5.53393 24.393903,24.393903 0 0 0 6.31993,-16.36655 27.319807,27.319807 0 0 0 -25.05414,-27.140158 l 13.61114,-13.61313 a 43.833807,43.833807 0 0 1 27.86836,40.753288 z" d="M 232.66609,50.155807 A 8.2118103,8.2118103 0 0 0 221.05286,38.54253 l -24.58739,24.587284 a 49.087021,49.087021 0 0 0 -82.69072,35.970548 c 0,1.448998 0.0696,2.914018 0.20861,4.384368 a 32.511588,32.511588 0 0 0 -16.633903,28.46635 27.562135,27.562135 0 0 0 5.298643,16.23286 22.799931,22.799931 0 0 0 4.2838,4.4793 l -7.176402,7.17673 a 8.2118072,8.2118072 0 1 0 11.613272,11.61322 z M 118.72657,140.86955 a 8.5946237,8.5946237 0 0 1 -2.68479,-2.19217 11.029135,11.029135 0 0 1 -2.26703,-6.7263 16.274355,16.274355 0 0 1 11.70415,-15.61263 l 4.92005,-1.48644 a 2.738162,2.738162 0 0 0 1.8737,-3.24418 l -1.16893,-5.00059 a 32.735029,32.735029 0 0 1 35.28314,-40.191861 31.860268,31.860268 0 0 1 18.36694,8.426592 z m 131.92616,-19.86871 a 40.800975,40.800975 0 0 1 -10.55455,27.3756 35.587128,35.587128 0 0 1 -25.2904,10.95024 h -71.10166 l 16.42536,-16.42536 h 54.6763 a 19.17354,19.17354 0 0 0 13.09966,-5.53393 24.393903,24.393903 0 0 0 6.31993,-16.36655 27.319807,27.319807 0 0 0 -25.05414,-27.140158 l 13.61114,-13.61313 a 43.833807,43.833807 0 0 1 27.86836,40.753288 z"
style="fill:#45a1ff;fill-opacity:1;stroke-width:5.47512" /> style="fill:currentColor;fill-opacity:1;stroke-width:5.47512" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Before After
Before After

View file

@ -0,0 +1,65 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 750 750">
<path fill="url(#a)" d="m 314.805,154.949 h 0.06 c 22.04,-77.0499 118.08,-114.6599 215.95,-114.6599 67.63,0 128.341,21.41 169.961,55.4 -24.838,1.1712 -49.362,6.0449 -72.76,14.4599 33.63,12.5 62.519,31.73 83.929,55.52 -16.153,-2.78 -32.532,-4.019 -48.919,-3.7 40.276,58.343 61.794,127.585 61.68,198.48 0,193.3 -156.701,350 -350.001,350 -190.32,0 -349.9999,-159.35 -349.9999,-350 0,-30.11 4,-61.2 11.77,-90.36 2.04,-6.12 4.88,-11.99 8.65,-14.14 4.72,-2.69 9.02,5.33 9.71,7.94 5.1177,19.17 12.0039,37.823 20.57,55.72 -0.75,-39.96 16.32,-76.36 39.7999,-107.84 15.66,-20.99 30.18,-40.44 36.88,-96.57 0.45,-3.77 4.02,-6.48 7.63,-5.3 50.96,16.68 78.2,101.54 73.97,172.5 28.15,4.03 28.02,-25.38 28.02,-25.38 -9,-27.66 -3,-79.07 53,-102.07 z"/>
<path fill="url(#b)" d="m 713.254,271.32 c 8.51,192.5 -149.74,358.47 -342.71,358.47 -180.65,0 -328.6792,-139.63 -342.0692,-316.85 -2.3889,16.596 -3.6452,33.334 -3.76,50.1 1.37,189.62 160.6592,347.41 349.9992,347.41 193.3,0 350,-156.7 350,-350 0,-30.8 -3.99,-60.67 -11.46,-89.13 z" opacity="0.9"/>
<path fill="url(#c)" d="m 366.175,180.459 c -3.77,-6.67 -21.18,-16.54 -28.79,-18.26 28.8,-92.2499 175.521,-120.5699 265.321,-104.2499 37.37,6.8 83.91,27.16 98.07,37.74 -41.62,-33.99 -102.341,-55.4 -169.961,-55.4 -97.87,0 -193.91,37.61 -215.95,114.6599 h -0.16 c -56,23 -62,74.43 -53,102.08 8.64,-32.99 49.75,-73.53 104.47,-76.57 z" style="mix-blend-mode:screen"/>
<path fill="url(#d)" d="m 467.885,116.748 c -78.62,15.47 -104.31,20.53 -130.62,45.54 29.55,-78.2297 104.98,-94.0897 194.86,-58.43 -21.391,4.41 -42.805,8.71 -64.24,12.9 z"/>
<path fill="url(#e)" d="m 43.7049,259.38 c -21.48,87.94 -4.88,191.3 92.6991,278.04 -29.05,-31.77 -64.5191,-149.07 13.75,-232.87 5.27,-5.65 14.34,-1.5 14.63,6.22 6.45,174.16 146.98,280.53 309,260.64 -50.2,-2.82 -216.22,-60.97 -92.72,-83.97 64.55,-12.03 165.76,-30.88 165.76,-121.7 0,-147.22 -113.83,-190.26 -182.86,-183.86 -47.24,4.38 -89.29,34.36 -102.23,75.13 4.97,16.07 -14.84,27.32 -28.05,25.43 4.24,-70.95 -23,-155.86 -73.97,-172.54 -3.6,-1.18 -7.18,1.53 -7.63,5.3 -6.7,56.13 -21.22,75.58 -36.87,96.57 -23.4891,31.49 -40.5591,67.88 -39.8091,107.84 -8.5659,-17.897 -15.4521,-36.55 -20.57,-55.72 -0.57,-2.16 -3.7,-8.19 -7.48,-8.47 -2.05,-0.15 -3.14,1.85 -3.65,3.96 z"/>
<path fill="url(#f)" d="m 337.695,496.349 c 95.04,77.17 286.17,19.31 286.17,-168.32 -77.16,116.96 -175.44,197.64 -286.16,168.32 z" style="mix-blend-mode:screen"/>
<path fill="url(#g)" d="m 150.155,304.55 c 0.864,-0.967 1.953,-1.706 3.17,-2.153 1.217,-0.446 2.526,-0.586 3.81,-0.407 -70.0595,85.45 -13.549,235.52 25.231,272.39 2.17,6.14 -36.791,-25.79 -42.161,-33.26 -29.5,-25.03 -71.7795,-149.06 9.95,-236.57 z" style="mix-blend-mode:screen"/>
<path fill="url(#h)" d="m 374.705,503.419 c 95.06,0 172.13,-62.879 172.13,-140.449 0,-77.57 -77.07,-140.45 -172.13,-140.45 -81.1,0 -172.17,52.76 -172.13,142.5 0.04,138.67 146.54,218.45 271.42,206.37 -9.38,-1.09 -67.9,-4.2 -107.45,-48.94 -3.57,-4.03 -9.76,-11.07 -6.95,-15.64 2.8,-4.57 10.52,-3.4 15.1,-3.4 z"/>
<path fill="#fff" d="m 528.085,299.15 -136.04,130.18 c -12.07,8.58 -24.92,9.2 -37.6,1.42 L 221.015,299.63 c 3.807,-6.118 8.087,-11.929 12.8,-17.38 l 14,13.1 c 35.04,32.84 63.37,59.37 103.3,93.45 18.02,15.38 23.62,15.08 41.3,0 45.68,-39 79.09,-68.5 122.52,-107.29 4.841,5.526 9.235,11.428 13.14,17.65 z" opacity="0.6"/>
<mask id="i" width="345" height="276" x="202" y="297" maskUnits="userSpaceOnUse">
<path fill="#fff" d="m 546.835,362.969 c 0,77.57 -77.07,140.45 -172.13,140.45 -4.59,0 -12.3,-1.18 -15.11,3.4 -2.81,4.56 3.38,11.6 6.95,15.63 37.16,42.04 91.07,47.33 105.22,48.72 l 2.23,0.22 c -124.88,12.08 -271.38,-67.7 -271.42,-206.37 -0.131,-23.089 6.295,-45.74 18.53,-65.32 l 134.08,121.78 c 9.54,8.66 25.61,8.66 35.15,0 l 136.62,-124.09 c 12.7,19.58 19.88,41.9 19.88,65.58 z"/>
</mask>
<g mask="url(#i)">
<path fill="url(#j)" d="m 162.705,200.979 h 435.07 v 394.47 h -435.07 z" opacity="0.7"/>
<g filter="url(#k)">
<path fill="#458fcd" fill-rule="evenodd" d="m 334.745,422.298 c -25.35,-26.38 -101.27,-114.03 -101.27,-114.03 l 5.87,0.26 118.86,88.77 c 8.9,6.47 21.6,6.4 30.42,-0.15 l 116.55,-88.5 6.18,-0.49 c 0,0 -73.44,85.57 -101.57,113.76 -28.13,28.19 -49.69,26.76 -75.04,0.38 z" clip-rule="evenodd"/>
</g>
</g>
<path fill="#fff" d="m 398.855,152.258 c 18.42,-5.8 16.8,-24.03 16.8,-24.03 0,0 -9.21,-10.85 -27.46,-4.84 -17.08,5.63 -19.73,17.8 -19.73,17.8 0,0 9.33,17.7 30.39,11.07 z"/>
<defs>
<linearGradient id="a" x1="146.185" x2="639.58502" y1="155.649" y2="615.86902" gradientUnits="userSpaceOnUse">
<stop stop-color="#1B91F3"/>
<stop offset="1" stop-color="#0B68CB"/>
</linearGradient>
<linearGradient id="d" x1="283.47501" x2="461.01501" y1="273.45801" y2="75.818298" gradientUnits="userSpaceOnUse">
<stop stop-color="#0F5DB0"/>
<stop offset="1" stop-color="#0F5DB0" stop-opacity="0"/>
</linearGradient>
<linearGradient id="f" x1="594.625" x2="512.07501" y1="416.55899" y2="619.24902" gradientUnits="userSpaceOnUse">
<stop stop-color="#E247C4" stop-opacity="0"/>
<stop offset="1" stop-color="#E247C4" stop-opacity="0.64"/>
</linearGradient>
<linearGradient id="g" x1="82.7155" x2="155.44501" y1="234.78999" y2="527.51001" gradientUnits="userSpaceOnUse">
<stop offset="0.1" stop-color="#EF3ACC"/>
<stop offset="1" stop-color="#EF3ACC" stop-opacity="0"/>
</linearGradient>
<linearGradient id="h" x1="374.70499" x2="374.70499" y1="273.95001" y2="569.94897" gradientUnits="userSpaceOnUse">
<stop stop-color="#fff"/>
<stop offset="0.91" stop-color="#BEE1FE"/>
<stop offset="1" stop-color="#96CEFD"/>
</linearGradient>
<linearGradient id="j" x1="380.245" x2="380.245" y1="441.44901" y2="565.44897" gradientUnits="userSpaceOnUse">
<stop stop-color="#BCE0FD"/>
<stop offset="1" stop-color="#88CCFC"/>
</linearGradient>
<radialGradient id="b" cx="0" cy="0" r="1" gradientTransform="matrix(117.92992,271.44954,-260.03887,112.97261,145.274,314)" gradientUnits="userSpaceOnUse">
<stop offset="0.53" stop-color="#0B4186" stop-opacity="0"/>
<stop offset="1" stop-color="#0B4186" stop-opacity="0.45"/>
</radialGradient>
<radialGradient id="c" cx="0" cy="0" r="1" gradientTransform="matrix(-38.950414,-49.859637,82.506525,-64.454205,383.705,192.449)" gradientUnits="userSpaceOnUse">
<stop stop-color="#EF3ACC" stop-opacity="0"/>
<stop offset="1" stop-color="#EF3ACC" stop-opacity="0.64"/>
</radialGradient>
<radialGradient id="e" cx="0" cy="0" r="1" gradientTransform="matrix(200.50032,-415.91019,513.77136,247.67684,242.704,551.15)" gradientUnits="userSpaceOnUse">
<stop offset="0.02" stop-color="#094188"/>
<stop offset="0.97" stop-color="#0B4186" stop-opacity="0"/>
</radialGradient>
<filter id="k" width="341.88" height="198.416" x="201.47501" y="276.15799" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur result="effect1_foregroundBlur_106_1002" stdDeviation="16"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 7.1 KiB

View file

@ -195,7 +195,7 @@ Lower files and folders permissions to user and group `www-data`:
``` ```
sudo find /var/www/send -type d -exec chmod 750 {} \; sudo find /var/www/send -type d -exec chmod 750 {} \;
sudo find /var/www/send -type f -exec chmod 640 {} \; sudo find /var/www/send -type f -exec chmod 640 {} \;
sudo chmod 750 /var/www/send/node_modules/.bin/* sudo find -L /var/www/send/node_modules/.bin/ -exec chmod 750 {} \;
``` ```
### Systemd ### Systemd

View file

@ -9,6 +9,7 @@ docker pull registry.gitlab.com/timvisee/send:latest
docker run -v $PWD/uploads:/uploads -p 1443:1443 \ docker run -v $PWD/uploads:/uploads -p 1443:1443 \
-e 'DETECT_BASE_URL=true' \ -e 'DETECT_BASE_URL=true' \
-e 'REDIS_HOST=localhost' \ -e 'REDIS_HOST=localhost' \
-e 'FILE_DIR=/uploads' \
registry.gitlab.com/timvisee/send:latest registry.gitlab.com/timvisee/send:latest
``` ```
@ -33,7 +34,7 @@ Config options expecting array values (e.g. `EXPIRE_TIMES_SECONDS`, `DOWNLOAD_CO
| `PORT` | Port the server will listen on (defaults to `1443`) | `PORT` | Port the server will listen on (defaults to `1443`)
| `NODE_ENV` | Run in `development` mode (unsafe) or `production` mode (the default) | `NODE_ENV` | Run in `development` mode (unsafe) or `production` mode (the default)
| `SEND_FOOTER_DMCA_URL` | A URL to a contact page for DMCA requests (empty / not shown by default) | `SEND_FOOTER_DMCA_URL` | A URL to a contact page for DMCA requests (empty / not shown by default)
| `SENTRY_CLIENT`, `SENTRY_DSN` | Sentry Client ID and DNS for error tracking (optional, disabled by default) | `SENTRY_CLIENT`, `SENTRY_DSN` | Sentry Client ID and DSN for error tracking (optional, disabled by default)
*Note: more options can be found here: https://github.com/timvisee/send/blob/master/server/config.js* *Note: more options can be found here: https://github.com/timvisee/send/blob/master/server/config.js*
@ -49,6 +50,8 @@ Configure the limits for uploads and downloads. Long expiration times are risky
| `MAX_DOWNLOADS` | Maximum number of downloads (defaults to `100`) | `MAX_DOWNLOADS` | Maximum number of downloads (defaults to `100`)
| `DOWNLOAD_COUNTS` | Download limit options to show in UI dropdown, e.g. `10,1,2,5,10,15,25,50,100,1000` | `DOWNLOAD_COUNTS` | Download limit options to show in UI dropdown, e.g. `10,1,2,5,10,15,25,50,100,1000`
| `EXPIRE_TIMES_SECONDS` | Expire time options to show in UI dropdown, e.g. `3600,86400,604800,2592000,31536000` | `EXPIRE_TIMES_SECONDS` | Expire time options to show in UI dropdown, e.g. `3600,86400,604800,2592000,31536000`
| `DEFAULT_DOWNLOADS` | Default download limit in UI (defaults to `1`)
| `DEFAULT_EXPIRE_SECONDS` | Default expire time in UI (defaults to `86400`)
*Note: more options can be found here: https://github.com/timvisee/send/blob/master/server/config.js* *Note: more options can be found here: https://github.com/timvisee/send/blob/master/server/config.js*
@ -75,6 +78,31 @@ Redis is used as the metadata database for the backend and is required no matter
*Note: more options can be found here: https://github.com/timvisee/send/blob/master/server/config.js* *Note: more options can be found here: https://github.com/timvisee/send/blob/master/server/config.js*
## Branding
To change the look the colors aswell as some graphics can be changed via environment variables.
See the table below for the variables and their default values.
| Name | Default | Description |
|---|---|---|
| UI_COLOR_PRIMARY | #0a84ff | The primary color |
| UI_COLOR_ACCENT | #003eaa | The accent color (eg. for hover-effects) |
| UI_CUSTOM_ASSETS_ANDROID_CHROME_192PX | | A custom icon for Android (192x192px) |
| UI_CUSTOM_ASSETS_ANDROID_CHROME_512PX | | A custom icon for Android (512x512px) |
| UI_CUSTOM_ASSETS_APPLE_TOUCH_ICON | | A custom icon for Apple |
| UI_CUSTOM_ASSETS_FAVICON_16PX | | A custom favicon (16x16px) |
| UI_CUSTOM_ASSETS_FAVICON_32PX | | A custom favicon (32x32px) |
| UI_CUSTOM_ASSETS_ICON | | A custom icon (Logo on the top-left of the UI) |
| UI_CUSTOM_ASSETS_SAFARI_PINNED_TAB | | A custom icon for Safari |
| UI_CUSTOM_ASSETS_FACEBOOK | | A custom header image for Facebook |
| UI_CUSTOM_ASSETS_TWITTER | | A custom header image for Twitter |
| UI_CUSTOM_ASSETS_WORDMARK | | A custom wordmark (Text next to the logo) |
| UI_CUSTOM_CSS | | Allows you to define a custom CSS file for custom styling |
| CUSTOM_FOOTER_TEXT | | Allows you to define a custom footer |
| CUSTOM_FOOTER_URL | | Allows you to define a custom URL in your footer |
Side note: If you define a custom URL and a custom footer, only the footer text will display, but will be hyperlinked to the URL.
## Examples ## Examples
**Run using an Amazon Elasticache for the Redis DB, Amazon S3 for the storage backend, and Sentry for error reporting.** **Run using an Amazon Elasticache for the Redis DB, Amazon S3 for the storage backend, and Sentry for error reporting.**
@ -113,6 +141,18 @@ Then open http://localhost:1443 to view the UI. (change the `localhost` to your
To run with HTTPS, you will need to set up a reverse proxy with SSL termination in front of the backend. See Docker Compose below for an example setup. To run with HTTPS, you will need to set up a reverse proxy with SSL termination in front of the backend. See Docker Compose below for an example setup.
**Run with custom branding.**
```bash
$ docker run -p 1443:1443 \
-v $PWD/custom_assets:/app/dist/custom_assets \
-e 'UI_COLOR_PRIMARY=#f00' \
-e 'UI_COLOR_ACCENT=#a00' \
-e 'UI_CUSTOM_ASSETS_ICON=custom_assets/logo.svg' \
registry.gitlab.com/timvisee/send:latest
```
## Docker Compose ## Docker Compose
For a Docker compose configuration example, see: For a Docker compose configuration example, see:

View file

@ -1,12 +1,12 @@
## How big of a file can I transfer with Send? ## How big of a file can I transfer with Send?
There is a 2.5GB file size limit built in to Send(1GB for non-signed in users), however, in practice you may There is a 2GB file size limit built in to Send, but this may be changed by the
be unable to send files that large. Send encrypts and decrypts the files in hoster. Send encrypts and decrypts the files in the browser which is great for
the browser which is great for security but will tax your system resources. In security but will tax your system resources. In particular you can expect to
particular you can expect to see your memory usage go up by at least the size see your memory usage go up by at least the size of the file when the transfer
of the file when the transfer is processing. You can see [the results of some is processing. You can see [the results of some
testing](https://github.com/mozilla/send/issues/170#issuecomment-314107793). testing](https://github.com/mozilla/send/issues/170#issuecomment-314107793). For
For the most reliable operation on common computers, its probably best to stay the most reliable operation on common computers, its probably best to stay
under a few hundred megabytes. under a few hundred megabytes.
## Why is my browser not supported? ## Why is my browser not supported?
@ -23,10 +23,10 @@ Send uses JavaScript to:
- Encrypt and decrypt files locally on the client instead of the server. - Encrypt and decrypt files locally on the client instead of the server.
- Render the user interface. - Render the user interface.
- Manage translations on the website into [various different languages](https://github.com/mozilla/send#localization). - Manage translations on the website into [various different languages](https://github.com/timvisee/send#localization).
- Collect data to help us improve Send in accordance with our [Terms & Privacy](https://send.firefox.com/legal). - Collect data to help us improve Send in accordance with our [Terms & Privacy](https://send.firefox.com/legal).
Since Send is an open source project, you can see all of the cool ways we use JavaScript by [examining our code](https://github.com/mozilla/send/). Since Send is an open source project, you can see all of the cool ways we use JavaScript by [examining our code](https://github.com/timvisee/send/).
## How long are files available for? ## How long are files available for?

34698
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
{ {
"name": "send", "name": "send",
"description": "File Sharing Experiment", "description": "File Sharing Experiment",
"version": "3.4.11", "version": "3.4.27",
"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)"
@ -37,9 +37,7 @@
"husky": { "husky": {
"hooks": { "hooks": {
"pre-commit": "lint-staged", "pre-commit": "lint-staged",
"pre-push": "npm test", "pre-push": "npm test"
"post-merge": "npm install",
"post-checkout": "scripts/sync-npm-dependencies.sh"
} }
}, },
"lint-staged": { "lint-staged": {
@ -61,29 +59,29 @@
"cache": true "cache": true
}, },
"engines": { "engines": {
"node": "^15.5.1" "node": "^16.13.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.14.3", "@babel/core": "^7.17.9",
"@babel/plugin-proposal-class-properties": "^7.13.0", "@babel/plugin-proposal-class-properties": "^7.16.7",
"@babel/plugin-syntax-dynamic-import": "^7.2.0", "@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@babel/preset-env": "^7.14.2", "@babel/preset-env": "^7.16.11",
"@dannycoates/webcrypto-liner": "^0.1.37", "@dannycoates/webcrypto-liner": "^0.1.37",
"@fullhuman/postcss-purgecss": "^1.3.0", "@fullhuman/postcss-purgecss": "^4.1.3",
"@mattiasbuelens/web-streams-polyfill": "0.2.1", "@mattiasbuelens/web-streams-polyfill": "0.2.1",
"@sentry/browser": "^5.30.0", "@sentry/browser": "^5.30.0",
"asmcrypto.js": "^0.22.0", "asmcrypto.js": "^0.22.0",
"babel-loader": "^8.2.2", "babel-loader": "^8.2.4",
"babel-plugin-istanbul": "^5.2.0", "babel-plugin-istanbul": "^5.2.0",
"base64-js": "^1.5.1", "base64-js": "^1.5.1",
"content-disposition": "^0.5.3", "content-disposition": "^0.5.4",
"copy-webpack-plugin": "^5.1.2", "copy-webpack-plugin": "^6.4.0",
"core-js": "^3.12.1", "core-js": "^3.21.1",
"crc": "^3.8.0", "crc": "^3.8.0",
"cross-env": "^6.0.3", "cross-env": "^6.0.3",
"css-loader": "^3.6.0", "css-loader": "^5.2.7",
"css-mqpacker": "^7.0.0", "css-mqpacker": "^7.0.0",
"cssnano": "^4.1.11", "cssnano": "^5.1.12",
"eslint": "^6.6.0", "eslint": "^6.6.0",
"eslint-config-prettier": "^6.15.0", "eslint-config-prettier": "^6.15.0",
"eslint-plugin-mocha": "^6.2.1", "eslint-plugin-mocha": "^6.2.1",
@ -93,22 +91,23 @@
"extract-loader": "^3.2.0", "extract-loader": "^3.2.0",
"extract-text-webpack-plugin": "^4.0.0-beta.0", "extract-text-webpack-plugin": "^4.0.0-beta.0",
"fast-text-encoding": "^1.0.3", "fast-text-encoding": "^1.0.3",
"file-loader": "^4.2.0", "file-loader": "^6.2.0",
"git-rev-sync": "^1.12.0", "git-rev-sync": "^3.0.2",
"html-loader": "^0.5.5", "html-loader": "^0.5.5",
"http_ece": "^1.1.0", "http_ece": "^1.1.0",
"husky": "^3.0.9", "husky": "^3.0.9",
"intl-pluralrules": "^1.2.2", "intl-pluralrules": "^1.3.1",
"lint-staged": "^9.4.2", "lint-staged": "^9.4.2",
"mocha": "^6.2.2", "mocha": "^10.1.0",
"morgan": "^1.9.1", "morgan": "^1.9.1",
"nanobus": "^4.5.0", "nanobus": "^4.5.0",
"nanohtml": "^1.9.0", "nanohtml": "^1.9.0",
"nanotiming": "^7.3.1", "nanotiming": "^7.3.1",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"nyc": "^14.1.1", "nyc": "^14.1.1",
"postcss-loader": "^3.0.0", "postcss": "^8.4.14",
"postcss-preset-env": "^6.7.0", "postcss-loader": "^4.2.0",
"postcss-preset-env": "^7.7.2",
"prettier": "^1.19.1", "prettier": "^1.19.1",
"proxyquire": "^2.1.3", "proxyquire": "^2.1.3",
"puppeteer": "^2.0.0", "puppeteer": "^2.0.0",
@ -117,41 +116,42 @@
"script-loader": "^0.7.2", "script-loader": "^0.7.2",
"sinon": "^7.5.0", "sinon": "^7.5.0",
"string-hash": "^1.1.3", "string-hash": "^1.1.3",
"stylelint": "^13.13.1", "stylelint": "^14.9.1",
"stylelint-config-standard": "^19.0.0", "stylelint-config-standard": "^26.0.0",
"stylelint-no-unsupported-browser-features": "^4.1.4", "stylelint-no-unsupported-browser-features": "^5.0.3",
"svgo": "^1.3.2", "svgo": "^2.8.0",
"svgo-loader": "^2.2.2", "svgo-loader": "^3.0.1",
"tailwindcss": "^1.9.6", "tailwindcss": "^2",
"val-loader": "^1.1.1", "val-loader": "^2.1.2",
"webpack": "4.38.0", "webpack": "4.38.0",
"webpack-cli": "^3.3.12", "webpack-cli": "^3.3.12",
"webpack-dev-middleware": "^3.7.3", "webpack-dev-middleware": "^3.7.3",
"webpack-dev-server": "^3.11.2", "webpack-dev-server": "^3.11.3",
"webpack-manifest-plugin": "^2.2.0", "webpack-manifest-plugin": "^2.2.0",
"webpack-unassert-loader": "^1.2.0" "webpack-unassert-loader": "^1.2.0"
}, },
"dependencies": { "dependencies": {
"@dannycoates/express-ws": "^5.0.3", "@dannycoates/express-ws": "^5.0.3",
"@fluent/bundle": "^0.13.0", "@fluent/bundle": "^0.17.1",
"@fluent/langneg": "^0.3.0", "@fluent/langneg": "^0.6.2",
"@google-cloud/storage": "^5.8.5", "@google-cloud/storage": "^6.2.3",
"@sentry/node": "^5.30.0", "@sentry/node": "^7.7.0",
"aws-sdk": "^2.909.0", "aws-sdk": "^2.1109.0",
"body-parser": "^1.19.0", "body-parser": "^1.20.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": "^6.2.4",
"express": "^4.17.1", "convict-format-with-validator": "^6.2.0",
"double-ended-queue": "^2.1.0-0",
"express": "^4.17.3",
"helmet": "^3.23.3", "helmet": "^3.23.3",
"mkdirp": "^0.5.1", "mozlog": "^3.0.1",
"mozlog": "^2.2.0", "node-fetch": "^2.6.7",
"node-fetch": "^2.6.1", "redis": "^3.1.1",
"redis": "^2.8.0",
"redis-mock": "^0.47.0", "redis-mock": "^0.47.0",
"selenium-standalone": "^6.23.0", "selenium-standalone": "^6.24.0",
"ua-parser-js": "^0.7.28" "ua-parser-js": "^0.7.31"
}, },
"availableLanguages": [ "availableLanguages": [
"en-US", "en-US",

View file

@ -1,8 +1,6 @@
class TailwindExtractor { const TailwindExtractor = content => {
static extract(content) {
return content.match(/[A-Za-z0-9-_:/]+/g) || []; return content.match(/[A-Za-z0-9-_:/]+/g) || [];
} };
}
const options = { const options = {
plugins: [ plugins: [

View file

@ -1,22 +1,17 @@
{ {
"name": "firefox-send", "name": "send",
"description": "File Sharing Experiment", "description": "File Sharing Experiment",
"repository": { "repository": {
"url": "https://github.com/mozilla/send/", "url": "https://github.com/timvisee/send/",
"license": "MPL-2.0" "license": "MPL-2.0"
}, },
"participate": { "participate": {
"home": "https://github.com/mozilla/send/blob/master/README.md", "home": "https://github.om/timvisee/send/blob/master/README.md",
"docs": "https://github.com/mozilla/send/blob/master/README.md" "docs": "https://github.com/timvisee/send/blob/master/README.md"
}, },
"bugs": { "bugs": {
"list": "https://github.com/mozilla/send/issues", "list": "https://github.com/timvisee/send/issues",
"report": "https://github.com/mozilla/send/issues/new" "report": "https://github.com/timvisee/send/issues/new"
},
"urls": {
"prod": "https://send.firefox.com/",
"stage": "https://stage.send.nonprod.cloudops.mozgcp.net/",
"dev": "https://send2.dev.lcip.org/"
}, },
"keywords": [ "keywords": [
"JavaScript", "JavaScript",

View file

@ -48,12 +48,12 @@ passwordSetError = Toto heslo nemohlo být nastaveno
-send-brand = -send-brand =
{ $case -> { $case ->
*[nom] Send *[nom] Send
[gen] Send [gen] Sendu
[dat] Send [dat] Sendu
[acc] Send [acc] Send
[voc] Send [voc] Sende
[loc] Send [loc] Sendu
[ins] Send [ins] Sendem
} }
-send-short-brand = -send-short-brand =
{ $case -> { $case ->
@ -86,7 +86,7 @@ passwordSetError = Toto heslo nemohlo být nastaveno
[ins] Mozillou [ins] Mozillou
} }
introTitle = Jednoduché a soukromé sdílení souborů introTitle = Jednoduché a soukromé sdílení souborů
introDescription = S { -send-brand(case: "ins") } jsou sdílené soubory šifrované end-to-end, takže ani my nevíme, co sdílíte. Platnost odkazů je navíc omezená. Soubory tak můžete sdílet soukromě a s jistotou, že se nezůstanou na internetu válet navždy. introDescription = Se { -send-brand(case: "ins") } jsou sdílené soubory šifrované end-to-end, takže ani my nevíme, co sdílíte. Platnost odkazů je navíc omezená. Soubory tak můžete sdílet soukromě a s jistotou, že se nezůstanou na internetu válet navždy.
notifyUploadEncryptDone = Váš soubor je zašifrovaný a připraven k odeslání notifyUploadEncryptDone = Váš soubor je zašifrovaný a připraven k odeslání
# 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 = Platnost vyprší po { $downloadCount } nebo za { $timespan } archiveExpiryInfo = Platnost vyprší po { $downloadCount } nebo za { $timespan }
@ -131,7 +131,7 @@ copyLinkDescription = Soubor můžete sdílet tímto odkazem:
copyLinkButton = Zkopírovat odkaz copyLinkButton = Zkopírovat odkaz
downloadTitle = Stáhnout soubory downloadTitle = Stáhnout soubory
downloadDescription = Tento soubor byl sdílen přes { -send-brand(case: "acc") } s end-to-end šifrováním a odkazem s omezenou platností. downloadDescription = Tento soubor byl sdílen přes { -send-brand(case: "acc") } s end-to-end šifrováním a odkazem s omezenou platností.
trySendDescription = Vyzkoušejte jednoduché a bezpečné sdílení souborů s { -send-brand(case: "ins") } trySendDescription = Vyzkoušejte jednoduché a bezpečné sdílení souborů se { -send-brand(case: "ins") }
# count will always be > 10 # count will always be > 10
tooManyFiles = tooManyFiles =
{ $count -> { $count ->
@ -189,6 +189,6 @@ downloadFirefoxPromo = { -send-short-brand } od aplikace { -firefox }.
shareLinkDescription = Sdílet odkaz na soubor: shareLinkDescription = Sdílet odkaz na soubor:
shareLinkButton = Sdílet odkaz shareLinkButton = Sdílet odkaz
# $name is the name of the file # $name is the name of the file
shareMessage = Stáhněte si soubor „{ $name }“ s { -send-brand(case: "ins") } - jednoduché a bezpečné sdílení souborů shareMessage = Stáhněte si soubor „{ $name }“ se { -send-brand(case: "ins") } - jednoduché a bezpečné sdílení souborů
trailheadPromo = Existuje způsob, jak ochránit své soukromí. Používejte Firefox. trailheadPromo = Existuje způsob, jak ochránit své soukromí. Používejte Firefox.
learnMore = Zjistit více. learnMore = Zjistit více.

View file

@ -147,3 +147,5 @@ shareLinkButton = Share link
shareMessage = Download “{ $name }” with { -send-brand }: simple, safe file sharing shareMessage = Download “{ $name }” with { -send-brand }: simple, safe file sharing
trailheadPromo = There is a way to protect your privacy. Join Firefox. trailheadPromo = There is a way to protect your privacy. Join Firefox.
learnMore = Learn more. learnMore = Learn more.
sponsoredByThunderbird = Sponsored by Thunderbird

View file

@ -152,3 +152,5 @@ shareLinkButton = Share link
shareMessage = Download “{ $name }” with { -send-brand }: simple, safe file sharing shareMessage = Download “{ $name }” with { -send-brand }: simple, safe file sharing
trailheadPromo = There is a way to protect your privacy. Join Firefox. trailheadPromo = There is a way to protect your privacy. Join Firefox.
learnMore = Learn more. learnMore = Learn more.
sponsoredByThunderbird = Sponsored by Thunderbird

View file

@ -143,3 +143,5 @@ shareLinkButton = Share link
# $name is the name of the file # $name is the name of the file
shareMessage = Download “{ $name }” with { -send-brand }: simple, safe file sharing shareMessage = Download “{ $name }” with { -send-brand }: simple, safe file sharing
learnMore = Learn more. learnMore = Learn more.
sponsoredByThunderbird = Sponsored by Thunderbird

View file

@ -152,3 +152,5 @@ shareLinkButton = Koppeling delen
shareMessage = Download { $name } met { -send-brand }: eenvoudig, veilig bestanden delen shareMessage = Download { $name } met { -send-brand }: eenvoudig, veilig bestanden delen
trailheadPromo = Er is een manier om uw privacy te beschermen. Doe mee met Firefox. trailheadPromo = Er is een manier om uw privacy te beschermen. Doe mee met Firefox.
learnMore = Meer info. learnMore = Meer info.
sponsoredByThunderbird = Gesponsord door Thunderbird

View file

@ -53,7 +53,7 @@ introTitle = Простой и безопасный обмен файлами
introDescription = { -send-brand } позволяет вам делиться файлами со сквозным шифрованием и ограниченным сроком действия ссылки на загрузку. Так что, вы сможете делиться файлами приватно и они не останутся в сети навсегда. introDescription = { -send-brand } позволяет вам делиться файлами со сквозным шифрованием и ограниченным сроком действия ссылки на загрузку. Так что, вы сможете делиться файлами приватно и они не останутся в сети навсегда.
notifyUploadEncryptDone = Ваш файл зашифрован и готов к отправке notifyUploadEncryptDone = Ваш файл зашифрован и готов к отправке
# 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 = Срок хранения истекает после { $downloadCount } или через { $timespan } archiveExpiryInfo = Удалить после { $downloadCount } или через { $timespan }
timespanMinutes = timespanMinutes =
{ $num -> { $num ->
[one] { $num } минуту [one] { $num } минуту
@ -89,7 +89,7 @@ gb = ГБ
# localized number and byte abbreviation. example "2.5MB" # localized number and byte abbreviation. example "2.5MB"
fileSize = { $num }{ $units } fileSize = { $num }{ $units }
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB") # $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
totalSize = Общий размер: { $size } totalSize = Всего: { $size }
# the next line after the colon contains a file name # the next line after the colon contains a file name
copyLinkDescription = Скопируйте ссылку, чтобы поделиться своим файлом: copyLinkDescription = Скопируйте ссылку, чтобы поделиться своим файлом:
copyLinkButton = Копировать ссылку copyLinkButton = Копировать ссылку
@ -117,13 +117,13 @@ legalTitle = Уведомление о конфиденциальности { -s
legalDateStamp = Версия 1.0, от 12 марта 2019 года legalDateStamp = Версия 1.0, от 12 марта 2019 года
# 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 } мин.
addFilesButton = Выберите файлы для выгрузки addFilesButton = Добавить
uploadButton = Выгрузить uploadButton = Выгрузить
# the first part of the string 'Drag and drop files or click to send up to 1GB' # the first part of the string 'Drag and drop files or click to send up to 1GB'
dragAndDropFiles = Перетащите файлы сюда dragAndDropFiles = Перетащите файлы сюда
# the second part of the string 'Drag and drop files or click to send up to 1GB' # the second part of the string 'Drag and drop files or click to send up to 1GB'
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB") # $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")
orClickWithSize = или щёлкните здесь, чтобы отправить их (до { $size }) orClickWithSize = или кликните сюда для отправки файлов до { $size }
addPassword = Защитить паролем addPassword = Защитить паролем
emailPlaceholder = Введите ваш адрес электронной почты emailPlaceholder = Введите ваш адрес электронной почты
# $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB") # $size is the size of the file, displayed using the fileSize message as format (e.g. "2.5MB")

View file

@ -2,12 +2,12 @@ title = Send
importingFile = 正在导入… importingFile = 正在导入…
encryptingFile = 正在加密… encryptingFile = 正在加密…
decryptingFile = 正在解密… decryptingFile = 正在解密…
downloadCount = downloadCount = { $num ->
{ $num -> [one] 1 次下载
*[other] { $num } 次下载 *[other] { $num } 次下载
} }
timespanHours = timespanHours = { $num ->
{ $num -> [one] 1 小时
*[other] { $num } 小时 *[other] { $num } 小时
} }
copiedUrl = 已复制! copiedUrl = 已复制!
@ -26,6 +26,11 @@ notSupportedOutdatedDetail = 很可惜,此版本的 Firefox 不支持 Send 所
updateFirefox = 更新 Firefox updateFirefox = 更新 Firefox
deletePopupCancel = 取消 deletePopupCancel = 取消
deleteButtonHover = 删除 deleteButtonHover = 删除
footerText = 不附属于 Mozilla 或 Firefox。
footerLinkDonate = 捐助
footerLinkCli = 命令行
footerLinkDmca = DMCA
footerLinkSource = 源代码
passwordTryAgain = 密码不正确。请重试。 passwordTryAgain = 密码不正确。请重试。
javascriptRequired = Send 需要 JavaScript javascriptRequired = Send 需要 JavaScript
whyJavascript = 为什么 Send 需要 JavaScript whyJavascript = 为什么 Send 需要 JavaScript
@ -142,5 +147,4 @@ shareLinkDescription = 您的文件链接:
shareLinkButton = 分享链接 shareLinkButton = 分享链接
# $name is the name of the file # $name is the name of the file
shareMessage = 使用 { -send-brand } 下载“{ $name }”:简单、安全的文件分享服务 shareMessage = 使用 { -send-brand } 下载“{ $name }”:简单、安全的文件分享服务
trailheadPromo = 捍卫隐私不是幻想。加入 Firefox 一同抗争。
learnMore = 详细了解。 learnMore = 详细了解。

View file

@ -2,12 +2,12 @@ title = Send
importingFile = 匯入中… importingFile = 匯入中…
encryptingFile = 加密中… encryptingFile = 加密中…
decryptingFile = 解密中… decryptingFile = 解密中…
downloadCount = downloadCount = { $num ->
{ $num -> [one] 1 次下載
*[other] { $num } 次下載 *[other] { $num } 次下載
} }
timespanHours = timespanHours = { $num ->
{ $num -> [one] 1 小時
*[other] { $num } 小時 *[other] { $num } 小時
} }
copiedUrl = 已複製! copiedUrl = 已複製!
@ -26,6 +26,11 @@ notSupportedOutdatedDetail = 很可惜,此版本的 Firefox 不支援 Send 所
updateFirefox = 更新 Firefox updateFirefox = 更新 Firefox
deletePopupCancel = 取消 deletePopupCancel = 取消
deleteButtonHover = 刪除 deleteButtonHover = 刪除
footerText = 不隸屬於 Mozilla 或 Firefox。
footerLinkDonate = 捐助
footerLinkCli = 命令列
footerLinkDmca = DMCA
footerLinkSource = 原始碼
passwordTryAgain = 密碼不正確,請再試一次。 passwordTryAgain = 密碼不正確,請再試一次。
javascriptRequired = Send 需要開啟 JavaScript 功能 javascriptRequired = Send 需要開啟 JavaScript 功能
whyJavascript = 為什麼 Send 需要 JavaScript 才能使用? whyJavascript = 為什麼 Send 需要 JavaScript 才能使用?
@ -45,25 +50,26 @@ passwordSetError = 無法設定此密碼
-send-short-brand = Send -send-short-brand = Send
-firefox = Firefox -firefox = Firefox
-mozilla = Mozilla -mozilla = Mozilla
introTitle = 簡單而私密的檔案共享服務 introTitle = 簡單而私密的檔案共享服務
introDescription = { -send-brand } 讓您可透過點對點加密的方式來分享檔案,並提供會自動失效的鏈結。這樣一來就可以保留分享時的隱私,也確保檔案不會永久保存於網路上。 introDescription = { -send-brand } 讓您可透過點對點加密的方式來分享檔案,並提供會自動失效的鏈結。這樣一來就可以保留分享時的隱私,也確保檔案不會永久保存於網路上。
notifyUploadEncryptDone = 已加密您的檔案,可以傳送 notifyUploadEncryptDone = 已加密您的檔案,可以傳送
# 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 = { $downloadCount } 或 { $timespan } 後失效 archiveExpiryInfo = { $downloadCount } 或 { $timespan } 後失效
timespanMinutes = timespanMinutes = { $num ->
{ $num -> [one] 1 分鐘
*[other] { $num } 分鐘 *[other] { $num } 分鐘
} }
timespanDays = timespanDays = { $num ->
{ $num -> [one] 1 天
*[other] { $num } 天 *[other] { $num } 天
} }
timespanWeeks = timespanWeeks = { $num ->
{ $num -> [one] 1 週
*[other] { $num } 週 *[other] { $num } 週
} }
fileCount = fileCount = { $num ->
{ $num -> [one] 1 個檔案
*[other] { $num } 個檔案 *[other] { $num } 個檔案
} }
# byte abbreviation # byte abbreviation
@ -85,13 +91,13 @@ downloadTitle = 下載檔案
downloadDescription = 此檔案是透過 { -send-brand } 進行分享,以點對點加密的方式來分享檔案,並提供會自動失效的鏈結。 downloadDescription = 此檔案是透過 { -send-brand } 進行分享,以點對點加密的方式來分享檔案,並提供會自動失效的鏈結。
trySendDescription = 快試試 { -send-brand },簡單安全的檔案分享機制。 trySendDescription = 快試試 { -send-brand },簡單安全的檔案分享機制。
# count will always be > 10 # count will always be > 10
tooManyFiles = tooManyFiles = { $count ->
{ $count -> [one] 一次僅能上傳 1 個檔案。
*[other] 一次僅能上傳 { $count } 個檔案。 *[other] 一次僅能上傳 { $count } 個檔案。
} }
# count will always be > 10 # count will always be > 10
tooManyArchives = tooManyArchives = { $count ->
{ $count -> [one] 僅允許 1 個壓縮檔。
*[other] 僅允許 { $count } 個壓縮檔。 *[other] 僅允許 { $count } 個壓縮檔。
} }
expiredTitle = 此鏈結已經失效。 expiredTitle = 此鏈結已經失效。
@ -136,5 +142,4 @@ shareLinkDescription = 您的檔案鏈結:
shareLinkButton = 分享鏈結 shareLinkButton = 分享鏈結
# $name is the name of the file # $name is the name of the file
shareMessage = 使用 { -send-brand } 下載「{ $name }」: 簡單安全的檔案分享機制 shareMessage = 使用 { -send-brand } 下載「{ $name }」: 簡單安全的檔案分享機制
trailheadPromo = 有種方法可以保護您的隱私,加入 Firefox。
learnMore = 了解更多。 learnMore = 了解更多。

2
public/robots.txt Normal file
View file

@ -0,0 +1,2 @@
User-agent: *
Disallow: /

View file

@ -12,9 +12,22 @@ module.exports = {
FOOTER_DONATE_URL: config.footer_donate_url, FOOTER_DONATE_URL: config.footer_donate_url,
FOOTER_CLI_URL: config.footer_cli_url, FOOTER_CLI_URL: config.footer_cli_url,
FOOTER_DMCA_URL: config.footer_dmca_url, FOOTER_DMCA_URL: config.footer_dmca_url,
FOOTER_SOURCE_URL: config.footer_source_url FOOTER_SOURCE_URL: config.footer_source_url,
CUSTOM_FOOTER_TEXT: config.custom_footer_text,
CUSTOM_FOOTER_URL: config.custom_footer_url,
MAIN_NOTICE_HTML: config.main_notice_html,
UPLOAD_AREA_NOTICE_HTML: config.upload_area_notice_html,
UPLOADS_LIST_NOTICE_HTML: config.uploads_list_notice_html,
DOWNLOAD_NOTICE_HTML: config.download_notice_html,
SHOW_THUNDERBIRD_SPONSOR: config.show_thunderbird_sponsor,
COLORS: {
PRIMARY: config.ui_color_primary,
ACCENT: config.ui_color_accent
},
CUSTOM_ASSETS: config.ui_custom_assets
}, },
DEFAULTS: { DEFAULTS: {
DOWNLOADS: config.default_downloads,
DOWNLOAD_COUNTS: config.download_counts, DOWNLOAD_COUNTS: config.download_counts,
EXPIRE_TIMES_SECONDS: config.expire_times_seconds, EXPIRE_TIMES_SECONDS: config.expire_times_seconds,
EXPIRE_SECONDS: config.default_expire_seconds EXPIRE_SECONDS: config.default_expire_seconds

View file

@ -1,8 +1,11 @@
const convict = require('convict'); const convict = require('convict');
const convict_format_with_validator = require('convict-format-with-validator');
const { tmpdir } = require('os'); const { tmpdir } = require('os');
const path = require('path'); const path = require('path');
const { randomBytes } = require('crypto'); const { randomBytes } = require('crypto');
convict.addFormats(convict_format_with_validator);
convict.addFormat({ convict.addFormat({
name: 'positive-int-array', name: 'positive-int-array',
coerce: ints => { coerce: ints => {
@ -64,6 +67,11 @@ const conf = convict({
default: [1, 2, 3, 4, 5, 20, 50, 100], default: [1, 2, 3, 4, 5, 20, 50, 100],
env: 'DOWNLOAD_COUNTS' env: 'DOWNLOAD_COUNTS'
}, },
default_downloads: {
format: Number,
default: 1,
env: 'DEFAULT_DOWNLOADS'
},
max_downloads: { max_downloads: {
format: Number, format: Number,
default: 100, default: 100,
@ -157,9 +165,20 @@ const conf = convict({
}, },
base_url: { base_url: {
format: 'url', format: 'url',
default: 'https://send.firefox.com', default: 'https://send.example.com',
env: 'BASE_URL' env: 'BASE_URL'
}, },
custom_title: {
format: String,
default: 'Send',
env: 'CUSTOM_TITLE'
},
custom_description: {
format: String,
default:
'Encrypt and send files with a link that automatically expires to ensure your important documents dont stay online forever.',
env: 'CUSTOM_DESCRIPTION'
},
detect_base_url: { detect_base_url: {
format: Boolean, format: Boolean,
default: false, default: false,
@ -234,6 +253,113 @@ const conf = convict({
format: String, format: String,
default: 'https://github.com/timvisee/send', default: 'https://github.com/timvisee/send',
env: 'SEND_FOOTER_SOURCE_URL' env: 'SEND_FOOTER_SOURCE_URL'
},
custom_footer_text: {
format: String,
default: '',
env: 'CUSTOM_FOOTER_TEXT'
},
custom_footer_url: {
format: String,
default: '',
env: 'CUSTOM_FOOTER_URL'
},
main_notice_html: {
format: String,
default: '',
env: 'SEND_MAIN_NOTICE_HTML'
},
upload_area_notice_html: {
format: String,
default: '',
env: 'SEND_UPLOAD_AREA_NOTICE_HTML'
},
uploads_list_notice_html: {
format: String,
default: '',
env: 'SEND_UPLOADS_LIST_NOTICE_HTML'
},
download_notice_html: {
format: String,
default: '',
env: 'SEND_DOWNLOAD_NOTICE_HTML'
},
show_thunderbird_sponsor: {
format: Boolean,
default: false,
env: 'SHOW_THUNDERBIRD_SPONSOR'
},
ui_color_primary: {
format: String,
default: '#0a84ff',
env: 'UI_COLOR_PRIMARY'
},
ui_color_accent: {
format: String,
default: '#003eaa',
env: 'UI_COLOR_ACCENT'
},
custom_locale: {
format: String,
default: '',
env: 'CUSTOM_LOCALE'
},
ui_custom_assets: {
android_chrome_192px: {
format: String,
default: '',
env: 'UI_CUSTOM_ASSETS_ANDROID_CHROME_192PX'
},
android_chrome_512px: {
format: String,
default: '',
env: 'UI_CUSTOM_ASSETS_ANDROID_CHROME_512PX'
},
apple_touch_icon: {
format: String,
default: '',
env: 'UI_CUSTOM_ASSETS_APPLE_TOUCH_ICON'
},
favicon_16px: {
format: String,
default: '',
env: 'UI_CUSTOM_ASSETS_FAVICON_16PX'
},
favicon_32px: {
format: String,
default: '',
env: 'UI_CUSTOM_ASSETS_FAVICON_32PX'
},
icon: {
format: String,
default: '',
env: 'UI_CUSTOM_ASSETS_ICON'
},
safari_pinned_tab: {
format: String,
default: '',
env: 'UI_CUSTOM_ASSETS_SAFARI_PINNED_TAB'
},
facebook: {
format: String,
default: '',
env: 'UI_CUSTOM_ASSETS_FACEBOOK'
},
twitter: {
format: String,
default: '',
env: 'UI_CUSTOM_ASSETS_TWITTER'
},
wordmark: {
format: String,
default: '',
env: 'UI_CUSTOM_ASSETS_WORDMARK'
},
custom_css: {
format: String,
default: '',
env: 'UI_CUSTOM_CSS'
}
} }
}); });

View file

@ -3,6 +3,10 @@ const assets = require('../common/assets');
const initScript = require('./initScript'); const initScript = require('./initScript');
module.exports = function(state, body = '') { module.exports = function(state, body = '') {
const custom_css = state.ui.assets.custom_css !== ''
? html`<link rel="stylesheet" type="text/css" href="${state.ui.assets.custom_css}" />`
: ''
return html` return html`
<!DOCTYPE html> <!DOCTYPE html>
<html lang="${state.locale}"> <html lang="${state.locale}">
@ -21,45 +25,46 @@ module.exports = function(state, body = '') {
<meta property="og:description" content="${state.description}" /> <meta property="og:description" content="${state.description}" />
<meta name="twitter:description" content="${state.description}" /> <meta name="twitter:description" content="${state.description}" />
<meta name="twitter:card" content="summary" /> <meta name="twitter:card" content="summary" />
<meta <meta property="og:image" content="${state.ui.assets.facebook}" />
property="og:image" <meta name="twitter:image" content="${state.ui.assets.twitter}" />
content="${state.baseUrl}/${assets.get('send-fb.jpg')}"
/>
<meta
name="twitter:image"
content="${state.baseUrl}/${assets.get('send-twitter.jpg')}"
/>
<meta property="og:url" content="${state.baseUrl}" /> <meta property="og:url" content="${state.baseUrl}" />
<meta name="theme-color" content="#220033" /> <meta name="theme-color" content="#220033" />
<meta name="msapplication-TileColor" content="#220033" /> <meta name="msapplication-TileColor" content="#220033" />
<link rel="manifest" href="/app.webmanifest" /> <link rel="manifest" href="/app.webmanifest" />
<link rel="stylesheet" type="text/css" href="/inter.css" /> <link rel="stylesheet" type="text/css" href="/inter.css" />
<style nonce=${state.cspNonce}>
:root {
--color-primary: ${state.ui.colors.primary};
--color-primary-accent: ${state.ui.colors.accent};
}
</style>
<link <link
rel="stylesheet" rel="stylesheet"
type="text/css" type="text/css"
href="${assets.get('app.css')}" href="${assets.get('app.css')}"
/> />
${custom_css}
<link <link
rel="apple-touch-icon" rel="apple-touch-icon"
sizes="180x180" sizes="180x180"
href="${assets.get('apple-touch-icon.png')}" href="${state.ui.assets.apple_touch_icon}"
/> />
<link <link
rel="icon" rel="icon"
type="image/png" type="image/png"
sizes="32x32" sizes="32x32"
href="${assets.get('favicon-32x32.png')}" href="${state.ui.assets.favicon_32px}"
/> />
<link <link
rel="icon" rel="icon"
type="image/png" type="image/png"
sizes="16x16" sizes="16x16"
href="${assets.get('favicon-16x16.png')}" href="${state.ui.assets.favicon_16px}"
/> />
<link <link
rel="mask-icon" rel="mask-icon"
href="${assets.get('safari-pinned-tab.svg')}" href="${state.ui.assets.safari_pinned_tab}"
color="#838383" color="#838383"
/> />
<script defer src="${assets.get('app.js')}"></script> <script defer src="${assets.get('app.js')}"></script>

View file

@ -1,13 +1,15 @@
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const { FluentBundle } = require('@fluent/bundle'); const { FluentBundle, FluentResource } = require('@fluent/bundle');
const localesPath = path.resolve(__dirname, '../public/locales'); const localesPath = path.resolve(__dirname, '../public/locales');
const locales = fs.readdirSync(localesPath); const locales = fs.readdirSync(localesPath);
function makeBundle(locale) { function makeBundle(locale) {
const bundle = new FluentBundle(locale, { useIsolating: false }); const bundle = new FluentBundle(locale, { useIsolating: false });
bundle.addMessages( bundle.addResource(
new FluentResource(
fs.readFileSync(path.resolve(localesPath, locale, 'send.ftl'), 'utf8') fs.readFileSync(path.resolve(localesPath, locale, 'send.ftl'), 'utf8')
)
); );
return [locale, bundle]; return [locale, bundle];
} }
@ -19,8 +21,11 @@ module.exports = function getTranslator(locale) {
const bundle = bundles.get(locale) || defaultBundle; const bundle = bundles.get(locale) || defaultBundle;
return function(id, data) { return function(id, data) {
if (bundle.hasMessage(id)) { if (bundle.hasMessage(id)) {
return bundle.format(bundle.getMessage(id), data); return bundle.formatPattern(bundle.getMessage(id).value, data);
} }
return defaultBundle.format(defaultBundle.getMessage(id), data); return defaultBundle.formatPattern(
defaultBundle.getMessage(id).value,
data
);
}; };
}; };

View file

@ -1,6 +1,7 @@
const assert = require('assert'); const assert = require('assert');
const crypto = require('crypto'); const crypto = require('crypto');
const storage = require('../storage'); const storage = require('../storage');
const config = require('../config');
const fxa = require('../fxa'); const fxa = require('../fxa');
module.exports = { module.exports = {
@ -70,10 +71,11 @@ module.exports = {
const token = authHeader.split(' ')[1]; const token = authHeader.split(' ')[1];
req.user = await fxa.verify(token); req.user = await fxa.verify(token);
} }
if (req.user) {
next(); if (config.fxa_required && !req.user) {
} else {
res.sendStatus(401); res.sendStatus(401);
} else {
next();
} }
} }
}; };

View file

@ -50,6 +50,12 @@ module.exports = function(app) {
return `'nonce-${req.cspNonce}'`; return `'nonce-${req.cspNonce}'`;
} }
], ],
styleSrc: [
"'self'",
function(req) {
return `'nonce-${req.cspNonce}'`;
}
],
formAction: ["'none'"], formAction: ["'none'"],
frameAncestors: ["'none'"], frameAncestors: ["'none'"],
objectSrc: ["'none'"], objectSrc: ["'none'"],

View file

@ -1,18 +1,20 @@
const assets = require('../../common/assets'); const state = require('../state');
module.exports = async function(req, res) {
const appState = await state(req);
module.exports = function(req, res) {
const manifest = { const manifest = {
name: 'Send', name: 'Send',
short_name: 'Send', short_name: 'Send',
lang: req.language, lang: req.language,
icons: [ icons: [
{ {
src: assets.get('android-chrome-192x192.png'), src: appState.ui.assets.android_chrome_192px,
type: 'image/png', type: 'image/png',
sizes: '192x192' sizes: '192x192'
}, },
{ {
src: assets.get('android-chrome-512x512.png'), src: appState.ui.assets.android_chrome_512px,
type: 'image/png', type: 'image/png',
sizes: '512x512' sizes: '512x512'
} }

View file

@ -26,7 +26,7 @@ module.exports = function(ws, req) {
const fileInfo = JSON.parse(message); const fileInfo = JSON.parse(message);
const timeLimit = fileInfo.timeLimit || config.default_expire_seconds; const timeLimit = fileInfo.timeLimit || config.default_expire_seconds;
const dlimit = fileInfo.dlimit || 1; const dlimit = fileInfo.dlimit || config.default_downloads;
const metadata = fileInfo.fileMetadata; const metadata = fileInfo.fileMetadata;
const auth = fileInfo.authorization; const auth = fileInfo.authorization;
const user = await fxa.verify(fileInfo.bearer); const user = await fxa.verify(fileInfo.bearer);

View file

@ -3,9 +3,18 @@ const layout = require('./layout');
const assets = require('../common/assets'); const assets = require('../common/assets');
const getTranslator = require('./locale'); const getTranslator = require('./locale');
const { getFxaConfig } = require('./fxa'); const { getFxaConfig } = require('./fxa');
const fs = require('fs');
const path = require('path');
module.exports = async function(req) { module.exports = async function(req) {
const locale = req.language || 'en-US'; const locale = (() => {
if (config.custom_locale != '' && fs.existsSync(path.join(__dirname,'../public/locales',config.custom_locale))) {
return config.custom_locale;
}
else {
return req.language || 'en-US';
}
})();
let authConfig = null; let authConfig = null;
let robots = 'none'; let robots = 'none';
if (req.route && req.route.path === '/') { if (req.route && req.route.path === '/') {
@ -24,6 +33,23 @@ module.exports = async function(req) {
prefs.surveyUrl = config.survey_url; prefs.surveyUrl = config.survey_url;
} }
const baseUrl = config.deriveBaseUrl(req); const baseUrl = config.deriveBaseUrl(req);
const uiAssets = {
android_chrome_192px: assets.get('android-chrome-192x192.png'),
android_chrome_512px: assets.get('android-chrome-512x512.png'),
apple_touch_icon: assets.get('apple-touch-icon.png'),
favicon_16px: assets.get('favicon-16x16.png'),
favicon_32px: assets.get('favicon-32x32.png'),
icon: assets.get('icon.svg'),
safari_pinned_tab: assets.get('safari-pinned-tab.svg'),
facebook: baseUrl + '/' + assets.get('send-fb.jpg'),
twitter: baseUrl + '/' + assets.get('send-twitter.jpg'),
wordmark: assets.get('wordmark.svg') + '#logo',
custom_css: ''
};
Object.keys(uiAssets).forEach(index => {
if (config.ui_custom_assets[index] !== '')
uiAssets[index] = config.ui_custom_assets[index];
});
return { return {
archive: { archive: {
numFiles: 0 numFiles: 0
@ -31,11 +57,16 @@ module.exports = async function(req) {
locale, locale,
capabilities: { account: false }, capabilities: { account: false },
translate: getTranslator(locale), translate: getTranslator(locale),
title: 'Send', title: config.custom_title,
description: description: config.custom_description,
'Encrypt and send files with a link that automatically expires to ensure your important documents dont stay online forever.',
baseUrl, baseUrl,
ui: {}, ui: {
colors: {
primary: config.ui_color_primary,
accent: config.ui_color_accent
},
assets: uiAssets
},
storage: { storage: {
files: [] files: []
}, },

View file

@ -1,7 +1,6 @@
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const promisify = require('util').promisify; const promisify = require('util').promisify;
const mkdirp = require('mkdirp');
const stat = promisify(fs.stat); const stat = promisify(fs.stat);
@ -9,7 +8,9 @@ class FSStorage {
constructor(config, log) { constructor(config, log) {
this.log = log; this.log = log;
this.dir = config.file_dir; this.dir = config.file_dir;
mkdirp.sync(this.dir); fs.mkdirSync(this.dir, {
recursive: true
});
} }
async length(id) { async length(id) {

View file

@ -1,5 +1,7 @@
const colors = { const colors = {
transparent: 'transparent', transparent: 'transparent',
primary: 'var(--color-primary)',
primary_accent: 'var(--color-primary-accent)',
black: '#000000', black: '#000000',
'grey-90': '#0c0c0d', 'grey-90': '#0c0c0d',
@ -16,93 +18,12 @@ const colors = {
'grey-10': '#f9f9fa', 'grey-10': '#f9f9fa',
white: '#ffffff', white: '#ffffff',
'red-90': '#3e0200',
'red-80': '#5a0002',
'red-70': '#a4000f',
'red-60': '#d70022',
red: '#d70022',
'red-50': '#ff0039',
// unspec
'red-40': '#ff3363',
'red-30': '#ff99aa',
'orange-90': '#3e1300',
'orange-80': '#712b00',
'orange-70': '#a44900',
'orange-60': '#d76e00',
'orange-50': '#ff9400',
// unspec
'orange-40': '#ffb24c',
'orange-30': '#ffd399',
'yellow-90': '#3e2800',
'yellow-80': '#715100',
'yellow-70': '#a47f00',
'yellow-60': '#d7b600',
yellow: '#d7b600',
'yellow-50': '#ffe900',
'yellow-40': '#ffed4c',
'yellow-30': '#fff599',
// 'green-darkest': '#003706',
// 'green-darker': '#006504',
// 'green-dark': '#058b00',
// green: '#12bc00',
// 'green-light': '#51d88a',
// 'green-lighter': '#a2f5bf',
// 'green-lightest': '#e3fcec',
// 'teal-darkest': '#0d3331',
// 'teal-darker': '#20504f',
// 'teal-dark': '#38a89d',
// teal: '#4dc0b5',
// 'teal-light': '#64d5ca',
// 'teal-lighter': '#a0f0ed',
// 'teal-lightest': '#e8fffe',
'blue-90': '#000f40',
'blue-80': '#002275',
'blue-70': '#003eaa',
'blue-60': '#0060df',
'blue-50': '#0a84ff',
blue: '#0a84ff',
'blue-40': '#45a1ff',
'blue-30': '#99ccff',
'blue-20': '#cce6ff',
'ink-90': '#0f1126',
'ink-80': '#202340',
'ink-70': '#363959',
// 'indigo-darkest': '#191e38',
// 'indigo-darker': '#2f365f',
// 'indigo-dark': '#5661b3',
// indigo: '#6574cd',
// 'indigo-light': '#7886d7',
// 'indigo-lighter': '#b2b7ff',
// 'indigo-lightest': '#e6e8ff',
'purple-90': '#25003e',
'purple-80': '#440071',
'purple-70': '#6200a4',
'purple-60': '#8000d7',
'purple-50': '#9400ff',
'purple-40': '#ad3bff',
'purple-30': '#c069ff',
'purple-20': '#d7a3ff',
// 'pink-darkest': '#451225',
// 'pink-darker': '#6f213f',
// 'pink-dark': '#eb5286',
// pink: '#f66d9b',
// 'pink-light': '#fa7ea8',
// 'pink-lighter': '#ffbbca',
// 'pink-lightest': '#ffebef',
cloud: 'rgba(255, 255, 255, 0.8)', cloud: 'rgba(255, 255, 255, 0.8)',
violet: 'hsl(258, 57%, 35%)' violet: 'hsl(258, 57%, 35%)'
}; };
module.exports = { module.exports = {
purge: false,
theme: { theme: {
colors: colors, colors: colors,
screens: { screens: {

View file

@ -1,7 +1,6 @@
/* eslint-disable no-undef, no-process-exit */ /* eslint-disable no-undef, no-process-exit */
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const mkdirp = require('mkdirp');
const puppeteer = require('puppeteer'); const puppeteer = require('puppeteer');
const webpack = require('webpack'); const webpack = require('webpack');
const config = require('../../webpack.config'); const config = require('../../webpack.config');
@ -44,7 +43,9 @@ const server = app.listen(async function() {
const coverage = await page.evaluate(() => __coverage__); const coverage = await page.evaluate(() => __coverage__);
if (coverage) { if (coverage) {
const dir = path.resolve(__dirname, '../../.nyc_output'); const dir = path.resolve(__dirname, '../../.nyc_output');
mkdirp.sync(dir); fs.mkdirSync(dir, {
recursive: true
});
fs.writeFileSync( fs.writeFileSync(
path.resolve(dir, 'frontend.json'), path.resolve(dir, 'frontend.json'),
JSON.stringify(coverage) JSON.stringify(coverage)

View file

@ -1,9 +1,11 @@
const path = require('path'); const path = require('path');
const mkdirp = require('mkdirp'); const fs = require('fs');
const rimraf = require('rimraf'); const rimraf = require('rimraf');
const dir = path.join(__dirname, 'integration', 'downloads'); const dir = path.join(__dirname, 'integration', 'downloads');
mkdirp.sync(dir); fs.mkdirSync(dir, {
recursive: true
});
rimraf.sync(`${dir}${path.sep}*`); rimraf.sync(`${dir}${path.sep}*`);
exports.config = { exports.config = {

View file

@ -6,6 +6,13 @@ const VersionPlugin = require('./build/version_plugin');
const AndroidIndexPlugin = require('./build/android_index_plugin'); const AndroidIndexPlugin = require('./build/android_index_plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin'); const ExtractTextPlugin = require('extract-text-webpack-plugin');
// Fix for node 18+
// See: <https://stackoverflow.com/a/78005686/1000145>
const crypto = require('crypto');
const crypto_orig_createHash = crypto.createHash;
crypto.createHash = algorithm =>
crypto_orig_createHash(algorithm == 'md4' ? 'sha256' : algorithm);
const webJsOptions = { const webJsOptions = {
babelrc: false, babelrc: false,
presets: [ presets: [
@ -42,7 +49,8 @@ const serviceWorker = {
test: /\.(png|jpg)$/, test: /\.(png|jpg)$/,
loader: 'file-loader', loader: 'file-loader',
options: { options: {
name: '[name].[contenthash:8].[ext]' name: '[name].[contenthash:8].[ext]',
esModule: false
} }
}, },
{ {
@ -51,16 +59,26 @@ const serviceWorker = {
{ {
loader: 'file-loader', loader: 'file-loader',
options: { options: {
name: '[name].[contenthash:8].[ext]' name: '[name].[contenthash:8].[ext]',
esModule: false
} }
}, },
{ {
loader: 'svgo-loader', loader: 'svgo-loader',
options: { options: {
plugins: [ plugins: [
{ removeViewBox: false }, // true causes stretched images {
{ convertStyleToAttrs: true }, // for CSP, no unsafe-eval name: 'removeViewBox',
{ removeTitle: true } // for smallness active: false // true causes stretched images
},
{
name: 'convertStyleToAttrs',
active: true // for CSP, no unsafe-eval
},
{
name: 'removeTitle',
active: true // for smallness
}
] ]
} }
} }
@ -127,7 +145,8 @@ const web = {
test: /\.(png|jpg)$/, test: /\.(png|jpg)$/,
loader: 'file-loader', loader: 'file-loader',
options: { options: {
name: '[name].[contenthash:8].[ext]' name: '[name].[contenthash:8].[ext]',
esModule: false
} }
}, },
{ {
@ -136,17 +155,30 @@ const web = {
{ {
loader: 'file-loader', loader: 'file-loader',
options: { options: {
name: '[name].[contenthash:8].[ext]' name: '[name].[contenthash:8].[ext]',
esModule: false
} }
}, },
{ {
loader: 'svgo-loader', loader: 'svgo-loader',
options: { options: {
plugins: [ plugins: [
{ cleanupIDs: false }, {
{ removeViewBox: false }, // true causes stretched images name: 'cleanupIDs',
{ convertStyleToAttrs: true }, // for CSP, no unsafe-eval active: false
{ removeTitle: true } // for smallness },
{
name: 'removeViewBox',
active: false // true causes stretched images
},
{
name: 'convertStyleToAttrs',
active: true // for CSP, no unsafe-eval
},
{
name: 'removeTitle',
active: true // for smallness
}
] ]
} }
} }
@ -160,7 +192,8 @@ const web = {
{ {
loader: 'css-loader', loader: 'css-loader',
options: { options: {
importLoaders: 1 importLoaders: 1,
esModule: false
} }
}, },
'postcss-loader' 'postcss-loader'
@ -184,12 +217,14 @@ const web = {
] ]
}, },
plugins: [ plugins: [
new CopyPlugin([ new CopyPlugin({
patterns: [
{ {
context: 'public', context: 'public',
from: '*.*' from: '*.*'
} }
]), ]
}),
new webpack.EnvironmentPlugin(['NODE_ENV']), new webpack.EnvironmentPlugin(['NODE_ENV']),
new webpack.IgnorePlugin(/\.\.\/dist/), // used in common/*.js new webpack.IgnorePlugin(/\.\.\/dist/), // used in common/*.js
new ExtractTextPlugin({ new ExtractTextPlugin({