Compare commits

...

205 Commits

Author SHA1 Message Date
Danny Coates 837747f8f7 bump version 2017-10-10 10:34:45 -07:00
Danny Coates a8c32ae49c Merge pull request #583 from mozilla/beef
Promote the beefy UI to default
2017-10-10 10:27:10 -07:00
Danny Coates 32c5b414de use beefy ui 2017-10-10 10:20:49 -07:00
Danny Coates 12c81a22e8 updated deps 2017-10-10 10:08:11 -07:00
Danny Coates 0c5d0d4bb2 Merge pull request #581 from tiagomoraismorgado88/patch-4
introducing ToC to README.md
2017-10-09 14:10:12 -07:00
tiagomoraismorgado 234f9c624d introducing ToC to README.md
**this PR does basically aim at:**
- *introducing ToC to README.md file*
2017-10-06 20:03:14 +01:00
Danny Coates da669b44ff Merge pull request #579 from mozilla/cancel
Hide cancel button when upload reaches 100%
2017-10-06 11:41:09 -07:00
Danny Coates 3c39f5f085 Merge pull request #580 from mozilla/favicon
Change Favicon in to look better in a variety of cases
2017-10-06 11:40:06 -07:00
Erica Wright 6de91b5872 Change Favicon in to look better in a variety of cases 2017-10-06 11:24:17 -04:00
Rhoslyn Prys ff9a0979f6 Pontoon: Update Welsh (cy) localization of Test Pilot: Firefox Send
Localization authors:
- Rhoslyn Prys <rprys@yahoo.com>
2017-10-05 16:13:35 +00:00
Erica Wright e1e8af2489 Hide cancel button when upload reached 100% 2017-10-04 16:34:41 -04:00
Erica 1eb000f615 Merge pull request #571 from ehuggett/svg-logo
Centre logo
2017-10-04 13:25:35 -04:00
ehuggett e20fd97e59 Centre logo by using transform (not optimal) 2017-10-04 00:05:45 +01:00
Erica d10ceacd67 Merge pull request #574 from ehuggett/tab-upload
Make upload button focusable (accessibility/tab navigation)
2017-10-02 20:15:37 -04:00
ehuggett 208c28ee01 Make upload button focusable (accessibility/tab navigation) 2017-10-02 23:04:55 +01:00
Danny Coates cdd1bb3c29 updated deps 2017-10-02 13:03:56 -07:00
Danny Coates 3d9c4fa320 added .nsprc 2017-10-02 12:04:03 -07:00
Danny Coates 9c4d18ef3b updated deps 2017-10-02 11:44:35 -07:00
Juraj Cigáň ce9ff3959f Pontoon: Update Slovak (sk) localization of Test Pilot: Firefox Send
Localization authors:
- Juraj Cigáň <kusavica@gmail.com>
2017-09-30 17:51:09 +00:00
eljuno 51aef4e1e5 Pontoon: Update Indonesian (id) localization of Test Pilot: Firefox Send
Localization authors:
- eljuno <eljunotrie_anggoro@yahoo.co.id>
2017-09-28 18:50:47 +00:00
hello 90247059d0 Pontoon: Update Hebrew (he) localization of Test Pilot: Firefox Send
Localization authors:
- Yaron Shahrabani <sh.yaron@gmail.com>
- hello <hello@ira.abramov.org>
2017-09-27 18:11:56 +00:00
Danny Coates c97abb46ed bump version 2017-09-26 10:29:26 -07:00
Danny Coates b8f5e371c7 updated deps 2017-09-26 10:23:30 -07:00
Danny Coates 401311a05f updated deps. removed choo-log 2017-09-20 13:09:33 -07:00
Sahithi 652b8e4e15 Pontoon: Update Telugu (te) localization of Test Pilot: Firefox Send
Localization authors:
- Sahithi <sahithi.thinker@gmail.com>
2017-09-19 11:31:21 +00:00
Merike Sell 99b7e7c0f1 Pontoon: Update Estonian (et) localization of Test Pilot: Firefox Send
Localization authors:
- Merike Sell <merikes@gmail.com>
2017-09-16 12:52:29 +00:00
Danny Coates 81442bb6f2 set default server states for fira and fileInfo 2017-09-14 12:15:08 -07:00
Danny Coates 137f474b69 fixed A/B test control group selection 2017-09-14 10:02:47 -07:00
Danny Coates 8e14d3f8f7 QA bug fixes 2017-09-13 12:01:55 -07:00
Danny Coates 07b7bc003a v1.2.0 2017-09-12 15:42:56 -07:00
Danny Coates df691c1516 Merge pull request #559 from mozilla/beefy
added first A/B experiment
2017-09-12 10:39:36 -07:00
Danny Coates 17e61bb09d added first A/B experiment 2017-09-11 17:30:05 -07:00
Tema 14e21988b2 Pontoon: Update Russian (ru) localization of Test Pilot: Firefox Send
Localization authors:
- Tema <Tema@Smirnov.one>
- Victor Bychek <a@bychek.ru>
2017-09-11 18:11:20 +00:00
Tema 205de5a633 Pontoon: Update Russian (ru) localization of Test Pilot: Firefox Send
Localization authors:
- Tema <Tema@Smirnov.one>
2017-09-11 17:51:57 +00:00
Jae Hyeon Park eabdc903b9 Pontoon: Update Korean (ko) localization of Test Pilot: Firefox Send
Localization authors:
- Jae Hyeon Park <wogus150@naver.com>
2017-09-11 06:11:02 +00:00
Sander Lepik 0628e71ec9 Pontoon: Update Estonian (et) localization of Test Pilot: Firefox Send
Localization authors:
- Sander Lepik <sander.lepik@eesti.ee>
2017-09-09 09:11:09 +00:00
avelper ebbcb38c7a Pontoon: Update Spanish (Spain) (es-ES) localization of Test Pilot: Firefox Send
Localization authors:
- avelper <avelper@mozilla-hispano.org>
2017-09-08 19:39:49 +00:00
Sander Lepik 5c1f535291 Pontoon: Update Estonian (et) localization of Test Pilot: Firefox Send
Localization authors:
- Sander Lepik <sander.lepik@eesti.ee>
2017-09-08 19:39:46 +00:00
Sander Lepik 2c8e488611 Pontoon: Update Estonian (et) localization of Test Pilot: Firefox Send
Localization authors:
- Sander Lepik <sander.lepik@eesti.ee>
2017-09-08 15:12:17 +00:00
manxmensch 6f3eac659c Pontoon: Update Malay (ms) localization of Test Pilot: Firefox Send
Localization authors:
- manxmensch <manxmensch@gmail.com>
2017-09-08 12:31:23 +00:00
Cristian Silaghi 86bca790bc Pontoon: Update Romanian (ro) localization of Test Pilot: Firefox Send
Localization authors:
- Cristian Silaghi <cristian.silaghi@mozilla.ro>
- danraduristea <danraduristea@gmail.com>
2017-09-07 19:51:39 +00:00
Cristian Silaghi 895d196876 Pontoon: Update Romanian (ro) localization of Test Pilot: Firefox Send
Localization authors:
- Cristian Silaghi <cristian.silaghi@mozilla.ro>
- danraduristea <danraduristea@gmail.com>
2017-09-07 19:31:58 +00:00
Danny Coates 3d8b38ffe4 fixed delete dialog broken in last commit 🙄 2017-09-06 14:27:09 -07:00
Danny Coates fddc415c86 fixes #539 2017-09-06 14:09:17 -07:00
Danny Coates 7a8e9b5de1 fixes #543 added FILE_DIR environment variable 2017-09-06 13:25:27 -07:00
Juan Esteban Ajsivinac Sián bbaeb44b26 Pontoon: Update Kaqchikel (cak) localization of Test Pilot: Firefox Send
Localization authors:
- Juan Esteban Ajsivinac Sián <ajtzibsyan@yahoo.com>
2017-09-02 00:12:56 +00:00
Juan Esteban Ajsivinac Sián a95f659474 Pontoon: Update Kaqchikel (cak) localization of Test Pilot: Firefox Send
Localization authors:
- Juan Esteban Ajsivinac Sián <ajtzibsyan@yahoo.com>
2017-09-01 23:51:10 +00:00
Juan Esteban Ajsivinac Sián 4d311b134f Pontoon: Update Kaqchikel (cak) localization of Test Pilot: Firefox Send
Localization authors:
- Juan Esteban Ajsivinac Sián <ajtzibsyan@yahoo.com>
2017-09-01 23:31:35 +00:00
Juan Esteban Ajsivinac Sián 5f90de577f Pontoon: Update Kaqchikel (cak) localization of Test Pilot: Firefox Send
Localization authors:
- Juan Esteban Ajsivinac Sián <ajtzibsyan@yahoo.com>
2017-09-01 23:11:09 +00:00
Juan Esteban Ajsivinac Sián 3c32ce946a Pontoon: Update Kaqchikel (cak) localization of Test Pilot: Firefox Send
Localization authors:
- Juan Esteban Ajsivinac Sián <ajtzibsyan@yahoo.com>
2017-09-01 22:51:02 +00:00
Juan Esteban Ajsivinac Sián 5ca89d0e0d Pontoon: Update Kaqchikel (cak) localization of Test Pilot: Firefox Send
Localization authors:
- Juan Esteban Ajsivinac Sián <ajtzibsyan@yahoo.com>
2017-09-01 22:31:32 +00:00
Juan Esteban Ajsivinac Sián 781d1f5b0a Pontoon: Update Kaqchikel (cak) localization of Test Pilot: Firefox Send
Localization authors:
- Juan Esteban Ajsivinac Sián <ajtzibsyan@yahoo.com>
2017-09-01 22:10:41 +00:00
Michal Stanke ef9bfae319 Pontoon: Update Czech (cs) localization of Test Pilot: Firefox Send
Localization authors:
- Michal Stanke <mstanke@mozilla.cz>
2017-08-30 19:30:44 +00:00
Danny Coates 7abbc60e17 fixes #546 drag effect 2017-08-29 11:36:40 -07:00
Danny Coates 15244e1a64 fixes #545 copy effect 2017-08-29 11:25:41 -07:00
Danny Coates 4b39d61ff4 don't upload empty files 2017-08-29 11:20:34 -07:00
Danny Coates 74718d6361 disable CSP when env = development 2017-08-29 11:19:21 -07:00
Peter deHaan ced640c24a Merge pull request #542 from ehuggett/patch-2
fix docker link typo
2017-08-28 09:08:04 -07:00
Fjoerfoks cdaa92c86d Pontoon: Update Frisian (fy-NL) localization of Test Pilot: Firefox Send
Localization authors:
- Fjoerfoks <fryskefirefox@gmail.com>
2017-08-28 11:50:50 +00:00
Danny Coates 57012f0660 added source maps to dev 2017-08-27 15:19:58 -07:00
ehuggett 6fde6e0a79 fix docker link typo 2017-08-27 21:45:38 +01:00
Danny Coates 182bde30fa Merge pull request #541 from mozilla/refactor-ftl
removed .title and .alt attributes from ftl
2017-08-27 00:06:03 -07:00
Danny Coates 59e2267513 removed .title and .alt attributes from ftl 2017-08-26 20:34:26 -07:00
Danny Coates 01a064ef7f added local dev url to readme 2017-08-25 15:41:53 -07:00
Danny Coates 9759338e6a shrink vendor bundle a bit 2017-08-25 15:38:26 -07:00
Danny Coates 5ac4560157 cram more into vendor bundle 2017-08-25 15:12:16 -07:00
Danny Coates 8e60ca1ac9 fixed readme typo 2017-08-25 14:01:08 -07:00
Danny Coates 131a8b5564 updated readme. made redis optional in dev 2017-08-25 13:58:51 -07:00
Danny Coates 663023a204 updated docker.md 2017-08-25 13:43:11 -07:00
Danny Coates 2b5c9dfb35 removed unused data-l10n attributes 2017-08-25 13:14:17 -07:00
Danny Coates a9a34fdd0a fixed GA var in jsconfig 2017-08-25 13:13:45 -07:00
Danny Coates 1655094ce3 fixed locale path on dev 2017-08-25 11:43:59 -07:00
Danny Coates 9ae7e3df11 fixed prod listen port 2017-08-25 10:21:38 -07:00
Danny Coates 0a31e2d521 fixed __heartbeat__ route 2017-08-25 10:03:49 -07:00
Danny Coates b6849661a6 Merge pull request #537 from mozilla/choo
a few changes to make A/B testing easier
2017-08-25 09:51:18 -07:00
Danny Coates 53e822964e a few changes to make A/B testing easier 2017-08-25 09:44:52 -07:00
Danny Coates b2f76d2df9 Merge pull request #533 from youwenliang/master
minor UI fixes
2017-08-24 15:56:39 -07:00
Danny Coates 574a3ce894 Merge pull request #531 from pdehaan/yo-changelog
Add CHANGELOG script
2017-08-24 15:55:49 -07:00
Danny Coates c68f796891 Merge pull request #535 from LuFlo/master
Fixed minimum NodeJS version in README
2017-08-24 15:51:55 -07:00
Danny Coates c592f84d7d Merge pull request #528 from tiagmoraismorgado/patch-2
adding separators to README
2017-08-24 15:48:35 -07:00
LuFlo 31faaf147e Fixed minimum NodeJS version
NodeJS version was increased due to http header splitting vulnerability
2017-08-24 21:00:28 +02:00
Mark Liang 09c20f5933 Update UI 2017-08-23 17:10:10 +08:00
Mark Liang fa4ab7bd5c Update master 2017-08-23 16:27:56 +08:00
Peter deHaan de4a24a7f8 Add CHANGELOG script 2017-08-21 15:26:19 -07:00
reza.habibi2008 8f1c404724 Pontoon: Update Persian (fa) localization of Test Pilot: Firefox Send
Localization authors:
- reza.habibi2008 <reza.habibi2008@gmail.com>
2017-08-20 12:10:48 +00:00
Tiago Morais Morgado 1b975e7ba7 adding separators to README
**in this PR I did basically:**

- *add separators to README file*

---

**I did this because:**

- *i feel it improves the overall flow of the file*
2017-08-20 13:05:48 +01:00
reza.habibi2008 1d7473c489 Pontoon: Update Persian (fa) localization of Test Pilot: Firefox Send
Localization authors:
- reza.habibi2008 <reza.habibi2008@gmail.com>
2017-08-20 11:50:57 +00:00
Arash Mousavi a7d3992ba1 Pontoon: Update Persian (fa) localization of Test Pilot: Firefox Send
Localization authors:
- Arash Mousavi <mousavi.arash@gmail.com>
2017-08-19 18:31:32 +00:00
Amin Mahmudian d81e9a76db Pontoon: Update Persian (fa) localization of Test Pilot: Firefox Send
Localization authors:
- Amin Mahmudian <amin.mahmudian@gmail.com>
2017-08-19 08:10:30 +00:00
xcffl 0624e59776 Pontoon: Update Chinese (zh-CN) localization of Test Pilot: Firefox Send
Localization authors:
- xcffl <xcffl@outlook.com>
2017-08-19 03:31:32 +00:00
xcffl 546064a7ee Pontoon: Update Chinese (zh-CN) localization of Test Pilot: Firefox Send
Localization authors:
- xcffl <xcffl@outlook.com>
2017-08-19 03:10:24 +00:00
Arash Mousavi 9d49cc876c Pontoon: Update Persian (fa) localization of Test Pilot: Firefox Send
Localization authors:
- Arash Mousavi <mousavi.arash@gmail.com>
2017-08-18 16:50:52 +00:00
Danny Coates 0bf8481fd0 v1.1.2 2017-08-17 10:52:33 -07:00
Danny Coates ae0758ac14 fixed download test 2017-08-17 10:27:18 -07:00
Danny Coates e9405f49ee xhr download as octet-stream 2017-08-17 10:19:18 -07:00
Danny Coates a1d0eef8a5 debugging #524 2017-08-17 09:46:51 -07:00
Danny Coates 254b806fb4 fixes #523 copy & share text 2017-08-17 09:27:06 -07:00
Danny Coates a7aee1450f fixes #522 copy button check mark 2017-08-17 09:16:03 -07:00
Sahithi fa5573a5ff Pontoon: Update Telugu (te) localization of Test Pilot: Firefox Send
Localization authors:
- Sahithi <sahithi.thinker@gmail.com>
2017-08-17 11:31:19 +00:00
Danny Coates 9714bb0a0a v1.1.1 2017-08-16 18:29:35 -07:00
Danny Coates ad82d30dd9 Merge pull request #516 from mozilla/cache-assets
cache assets
2017-08-16 17:44:09 -07:00
Danny Coates 757ac14d1a webpacked the heck out of the build 2017-08-16 14:21:01 -07:00
Danny Coates 3e066258c4 Merge pull request #520 from mozilla/i519
fix drag & drop
2017-08-16 11:11:46 -07:00
Danny Coates 127f73b4fe fixes #519 drag & drop 2017-08-16 11:03:17 -07:00
Emin Mastizada ae5009e1e3 Pontoon: Update Azerbaijani (az) localization of Test Pilot: Firefox Send
Localization authors:
- Emin Mastizada <emin@mastizada.com>
2017-08-16 07:31:19 +00:00
Danny Coates 0ab8ddc894 groundwork for asset caching 2017-08-15 11:55:52 -07:00
Danny Coates b429841534 use new upload button string 2017-08-15 10:30:19 -07:00
jesferman1993 279f6df6f4 Pontoon: Update Spanish (es-ES) localization of Test Pilot: Firefox Send
Localization authors:
- jesferman1993 <jesferman1993@hotmail.com>
2017-08-15 09:11:11 +00:00
Slimane Amiri 634e6b2834 Pontoon: Update Kabyle (kab) localization of Test Pilot: Firefox Send
Localization authors:
- Slimane Amiri <slimane.amiri@gmail.com>
2017-08-15 07:31:06 +00:00
Danny Coates 856b2cdc60 Merge pull request #515 from mozilla/refactor-upload
removed jquery from upload.js
2017-08-14 21:23:04 -07:00
Danny Coates 41351f877c removed jquery from upload.js 2017-08-14 20:00:14 -07:00
Andreas Pettersson afbb89fbe8 Pontoon: Update Swedish (sv-SE) localization of Test Pilot: Firefox Send
Localization authors:
- Andreas Pettersson <az@kth.se>
2017-08-14 22:31:48 +00:00
Pierre Neter b40b45273d Pontoon: Update Vietnamese (vi) localization of Test Pilot: Firefox Send
Localization authors:
- Pierre Neter <pierreneter@gmail.com>
2017-08-14 19:31:32 +00:00
Danny Coates f1fb877c7f Merge pull request #514 from mozilla/refactor-download
use async and removed jquery from download.js
2017-08-14 12:12:11 -07:00
Jon Vadillo 9d7ad06b1a Pontoon: Update Spanish (es-ES) localization of Test Pilot: Firefox Send
Localization authors:
- Jon Vadillo <vadillo.jon@gmail.com>
2017-08-14 18:30:39 +00:00
Danny Coates c6a4b089d9 use async and removed jquery from download.js 2017-08-14 11:14:47 -07:00
Danny Coates 24917f8aa5 Merge pull request #513 from mozilla/svg-progress
use svg for progress
2017-08-14 10:05:03 -07:00
Danny Coates eada94b262 use svg for progress 2017-08-13 18:46:05 -07:00
Danny Coates 43fa551a64 improved exist check 2017-08-13 18:44:59 -07:00
Roberto Alvarado e1137db946 Pontoon: Update Spanish (es-MX) localization of Test Pilot: Firefox Send
Localization authors:
- Roberto Alvarado <ralv888@gmail.com>
2017-08-14 00:50:56 +00:00
Enol c1878649b3 Pontoon: Update Asturian (ast) localization of Test Pilot: Firefox Send
Localization authors:
- Enol <enolp@softastur.org>
2017-08-13 17:50:44 +00:00
Michael Wolf 30b86b14ed Pontoon: Update Sorbian, Upper (hsb) localization of Test Pilot: Firefox Send
Localization authors:
- Michael Wolf <milupo@sorbzilla.de>
2017-08-13 15:31:13 +00:00
Michael Wolf e91b341f8a Pontoon: Update Sorbian, Lower (dsb) localization of Test Pilot: Firefox Send
Localization authors:
- Michael Wolf <milupo@sorbzilla.de>
2017-08-13 15:31:11 +00:00
Jakub Rychlý 70148232c6 Pontoon: Update Czech (cs) localization of Test Pilot: Firefox Send
Localization authors:
- Jakub Rychlý <jrychly@jakubrychly.cz>
- sajdl.vojtech <sajdl.vojtech@gmail.com>
2017-08-13 12:31:06 +00:00
Alexander Slovesnik 56e3d5766c Pontoon: Update Russian (ru) localization of Test Pilot: Firefox Send
Localization authors:
- Alexander Slovesnik <unghost@mozilla-russia.org>
2017-08-12 22:11:20 +00:00
Rhoslyn Prys 350e31ae4a Pontoon: Update Welsh (cy) localization of Test Pilot: Firefox Send
Localization authors:
- Rhoslyn Prys <rprys@yahoo.com>
2017-08-12 19:31:25 +00:00
Marcelo Poli 0794bcc458 Pontoon: Update Spanish (es-AR) localization of Test Pilot: Firefox Send
Localization authors:
- Marcelo Poli <enzomatrix@gmail.com>
2017-08-12 18:31:01 +00:00
Belayet Hossain a6aee8ad62 Pontoon: Update Bengali (bn-BD) localization of Test Pilot: Firefox Send
Localization authors:
- Belayet Hossain <bellayet@gmail.com>
- S M Sarwar Nobin <smsarwar1996@gmail.com>
2017-08-12 18:30:59 +00:00
josotrix 8305d13dab Pontoon: Update Spanish (es-CL) localization of Test Pilot: Firefox Send
Localization authors:
- josotrix <josotrix@ravmn.cl>
2017-08-12 17:11:33 +00:00
Selim Şumlu 441a520765 Pontoon: Update Turkish (tr) localization of Test Pilot: Firefox Send
Localization authors:
- Selim Şumlu <selim@sum.lu>
2017-08-12 15:50:46 +00:00
josotrix ba84e59f39 Pontoon: Update Spanish (es-CL) localization of Test Pilot: Firefox Send
Localization authors:
- josotrix <josotrix@ravmn.cl>
- ravmn <ravmn@ravmn.cl>
2017-08-12 15:50:43 +00:00
Pin-guang Chen 22a316ab58 Pontoon: Update Chinese (zh-TW) localization of Test Pilot: Firefox Send
Localization authors:
- Pin-guang Chen <petercpg@mail.moztw.org>
2017-08-12 15:31:26 +00:00
Juraj Cigáň 6b9502d252 Pontoon: Update Slovak (sk) localization of Test Pilot: Firefox Send
Localization authors:
- Juraj Cigáň <kusavica@gmail.com>
2017-08-12 12:11:21 +00:00
Danny Coates cdc3a5340d defer main js scripts 2017-08-11 19:13:57 -07:00
Danny Coates f03f7a0286 Merge pull request #510 from mozilla/hooks
added precommit hook for format
2017-08-11 18:34:48 -07:00
Danny Coates d8a5789701 added precommit hook for format 2017-08-11 18:06:16 -07:00
Danny Coates 8d26e0e742 Merge pull request #502 from mozilla/refactor-filelist
extracted filelist into its own file
2017-08-11 14:18:35 -07:00
Danny Coates e142d76cb4 Merge pull request #428 from mozilla/add-twitter-og-cards
add twitter and open graph cards
2017-08-11 14:12:44 -07:00
Danny Coates c488c1d724 added BASE_URL environment variable 2017-08-11 14:02:44 -07:00
Danny Coates bed57af6c5 extracted filelist into its own file 2017-08-11 13:50:58 -07:00
Jim Spentzos 7500bd8326 Pontoon: Update Greek (el) localization of Test Pilot: Firefox Send
Localization authors:
- Jim Spentzos <jamesspentzos@hotmail.com>
- Μιχάλης <mikem132@protonmail.com>
2017-08-11 20:31:46 +00:00
Danny Coates 0250924961 Merge pull request #506 from varghesethomase/404-page
404 page
2017-08-11 12:20:02 -07:00
Varghese Thomas 70813556ad Reverting unwanted notfound page response 2017-08-12 00:29:25 +05:30
Марко Костић (Marko Kostić) 2bb9af1943 Pontoon: Update Serbian (sr) localization of Test Pilot: Firefox Send
Localization authors:
- Марко Костић (Marko Kostić) <marko.m.kostic@gmail.com>
2017-08-11 18:51:01 +00:00
Danny Coates 55bd44a8f5 Merge pull request #508 from mozilla/fixes478
fixes 478
2017-08-11 10:58:24 -07:00
Abhinav Adduri d83900f272 fixes 478 2017-08-11 10:50:37 -07:00
Jordi Serratosa fa4f9299b2 Pontoon: Update Catalan (ca) localization of Test Pilot: Firefox Send
Localization authors:
- Jordi Serratosa <jordis@softcatala.cat>
2017-08-11 16:31:45 +00:00
Danny Coates 0f7b19c385 Merge pull request #504 from mozilla/fix-japanese-browse-btn
fix japanese browse button
2017-08-11 08:37:34 -07:00
Varghese Thomas a9c1dd0180 Replacing all send status 404 with notfound page 2017-08-11 20:52:18 +05:30
Varghese Thomas c468e2f34e Sending not found page for invalid url id 2017-08-11 20:46:59 +05:30
Michael Köhler 718f42897f Pontoon: Update German (de) localization of Test Pilot: Firefox Send
Localization authors:
- Michael Köhler <michael.koehler1@gmx.de>
2017-08-11 13:31:09 +00:00
John Gruen fb468bd1bc fix japanese browse button 2017-08-11 13:41:14 +02:00
John Gruen dafe00cabb add twitter and open graph cards 2017-08-11 13:39:04 +02:00
Matjaž Horvat 98aebb7f70 Pontoon: Update Slovenian (sl) localization of Test Pilot: Firefox Send
Localization authors:
- Matjaž Horvat <matjaz.horvat@gmail.com>
2017-08-11 11:31:10 +00:00
Tymur Faradzhev a990d78bc0 Pontoon: Update Ukrainian (uk) localization of Test Pilot: Firefox Send
Localization authors:
- Tymur Faradzhev <faradzhev.timur@gmail.com>
2017-08-11 08:31:11 +00:00
Balázs Meskó 9b4069be3e Pontoon: Update Hungarian (hu) localization of Test Pilot: Firefox Send
Localization authors:
- Balázs Meskó <meskobalazs@gmail.com>
2017-08-11 08:31:08 +00:00
Håvar Henriksen ff3bc0dd62 Pontoon: Update Norwegian Bokmål (nb-NO) localization of Test Pilot: Firefox Send
Localization authors:
- Håvar Henriksen <havar@firefox.no>
2017-08-11 06:50:58 +00:00
Luna Jernberg b39b131928 Pontoon: Update Swedish (sv-SE) localization of Test Pilot: Firefox Send
Localization authors:
- Luna Jernberg <bittin@cafe8bitar.se>
2017-08-11 03:31:14 +00:00
Danny Coates 2646fb9b3c Merge pull request #503 from skystar-p/editorconfig
Added editorconfig
2017-08-10 19:50:46 -07:00
skystar-p c2b84650e2 added editorconfig 2017-08-11 11:39:56 +09:00
YFdyh000 fecf938ae7 Pontoon: Update Chinese (zh-CN) localization of Test Pilot: Firefox Send
Localization authors:
- YFdyh000 <yfdyh000@gmail.com>
2017-08-11 02:31:45 +00:00
Cláudio Esperança 8abf631430 Pontoon: Update Portuguese (pt-PT) localization of Test Pilot: Firefox Send
Localization authors:
- Cláudio Esperança <cesperanc@gmail.com>
2017-08-11 02:10:43 +00:00
manxmensch d69c535dda Pontoon: Update Malay (ms) localization of Test Pilot: Firefox Send
Localization authors:
- manxmensch <manxmensch@gmail.com>
2017-08-11 00:50:39 +00:00
Kohei Yoshino 082ca6c57b Pontoon: Update Japanese (ja) localization of Test Pilot: Firefox Send
Localization authors:
- Kohei Yoshino <kohei.yoshino@gmail.com>
2017-08-10 22:10:52 +00:00
Bjørn I b263231068 Pontoon: Update Norwegian Nynorsk (nn-NO) localization of Test Pilot: Firefox Send
Localization authors:
- Bjørn I. <bjorn.svindseth@online.no>
2017-08-10 20:31:46 +00:00
Francesco Lodolo 947a6d9992 Pontoon: Update Italian (it) localization of Test Pilot: Firefox Send
Localization authors:
- Francesco Lodolo <francesco.lodolo@mozillaitalia.org>
2017-08-10 20:10:54 +00:00
Danny Coates 1ad7edf5a9 fixed bad merge 2017-08-10 12:59:07 -07:00
Schieck :) 0c26204ea1 Pontoon: Update Portuguese (pt-BR) localization of Test Pilot: Firefox Send
Localization authors:
- Schieck :) <ricardoschieck@gmail.com>
2017-08-10 18:51:14 +00:00
Ton 1e3bbee7f1 Pontoon: Update Dutch (nl) localization of Test Pilot: Firefox Send
Localization authors:
- Ton <tonnes.mb@gmail.com>
2017-08-10 18:11:25 +00:00
Danny Coates ec80e8e622 Merge pull request #499 from mozilla/pier1
use import/export in the frontend code
2017-08-10 11:07:38 -07:00
Théo Chevalier 61e2c0d85b Pontoon: Update French (fr) localization of Test Pilot: Firefox Send
Localization authors:
- Théo Chevalier <theo.chevalier11@gmail.com>
2017-08-10 17:50:53 +00:00
Danny Coates 80db74fc3a Merge pull request #500 from mozilla/i495
fixed build:css on windows
2017-08-10 10:43:07 -07:00
Danny Coates 30936eb2fa fixed build:css on windows 2017-08-10 10:38:36 -07:00
Danny Coates 31e29d58b9 Merge pull request #481 from pdehaan/fix-l10n-id
Cater for mobile and desktop
2017-08-10 10:19:21 -07:00
Danny Coates 702134b3b1 use import/export in the frontend code 2017-08-10 10:03:22 -07:00
Danny Coates 11ae7f857c Merge pull request #493 from mozilla/webpack-dev
added webpack-dev-middleware
2017-08-10 09:29:43 -07:00
Peter deHaan 8827556974 Add new l10n string, but don't use it yet 2017-08-10 09:26:25 -07:00
Danny Coates 21b7f16b1e added webpack-dev-middleware for recompiling on source changes 2017-08-10 09:23:33 -07:00
Danny Coates 314ab237ec Merge pull request #491 from mozilla/i387
added missing exit event cases
2017-08-10 09:06:57 -07:00
Danny Coates 0fa0416c3f Merge pull request #492 from mozilla/no-cookies
make the site mostly work when cookies (localStorage) are disabled
2017-08-10 09:06:15 -07:00
Danny Coates 09faedf059 make the site mostly work when cookies (localStorage) are disabled 2017-08-09 23:12:15 -07:00
Danny Coates 16aa7983ed added missing exit event cases 2017-08-09 16:44:09 -07:00
Marcelo Poli 493bf8dc89 Pontoon: Update Spanish (es-AR) localization of Test Pilot: Firefox Send
Localization authors:
- Marcelo Poli <enzomatrix@gmail.com>
2017-08-09 22:10:59 +00:00
Danny Coates 46432b9649 Merge pull request #490 from mozilla/i489
set the mime type in the download blob
2017-08-09 14:31:55 -07:00
Danny Coates 193664a8e8 set the mime type in the download blob 2017-08-09 14:25:37 -07:00
Danny Coates 626e578acb Merge pull request #485 from mozilla/i479
added progress to tab title when not in focus
2017-08-09 11:42:35 -07:00
Tymur Faradzhev 51bffe11a8 Pontoon: Update Ukrainian (uk) localization of Test Pilot: Firefox Send
Localization authors:
- Tymur Faradzhev <faradzhev.timur@gmail.com>
2017-08-09 08:10:36 +00:00
Danny Coates 08e2c6c112 Merge pull request #474 from varghesethomase/master
Fixing bug #438 by adding role attribute to anchor tags and alt attribute images
2017-08-08 22:41:31 -07:00
Danny Coates c38d91db98 added progress to tab title when not in focus 2017-08-08 20:23:38 -07:00
Danny Coates c13839a522 Merge pull request #480 from pdehaan/issue-443
Increase font weight to 500 on <button>s and <label>s
2017-08-08 19:43:46 -07:00
Peter deHaan 4894d5162f Update l10n id 2017-08-08 13:37:33 -07:00
Peter deHaan 77b6fb138f Increase font weight to 500 on <button>s and <label>s 2017-08-08 13:06:59 -07:00
Danny Coates 9dab74891d Merge pull request #419 from pdehaan/autoprefixer
Add autoprefixer and cssnano support
2017-08-08 12:43:56 -07:00
Enol 393d2a0052 Pontoon: Update Asturian (ast) localization of Test Pilot: Firefox Send
Localization authors:
- Enol <enolp@softastur.org>
2017-08-08 19:31:58 +00:00
Enol 44ac783f6a Pontoon: Update Asturian (ast) localization of Test Pilot: Firefox Send
Localization authors:
- Enol <enolp@softastur.org>
2017-08-08 18:50:58 +00:00
Enol 7ea8712538 Pontoon: Update Asturian (ast) localization of Test Pilot: Firefox Send
Localization authors:
- Enol <enolp@softastur.org>
2017-08-08 18:30:54 +00:00
Jordi Serratosa fb92a793e4 Pontoon: Update Catalan (ca) localization of Test Pilot: Firefox Send
Localization authors:
- Jordi Serratosa <jordis@softcatala.cat>
2017-08-08 12:50:40 +00:00
Luna Jernberg 87eaba6337 Pontoon: Update Swedish (sv-SE) localization of Test Pilot: Firefox Send
Localization authors:
- Luna Jernberg <bittin@cafe8bitar.se>
2017-08-08 11:31:17 +00:00
Selim Şumlu 7e13f2ab32 Pontoon: Update Turkish (tr) localization of Test Pilot: Firefox Send
Localization authors:
- Selim Şumlu <selim@sum.lu>
2017-08-08 11:11:10 +00:00
Slimane Amiri 3214d293ca Pontoon: Update Kabyle (kab) localization of Test Pilot: Firefox Send
Localization authors:
- Slimane Amiri <slimane.amiri@gmail.com>
2017-08-08 10:10:28 +00:00
Håvar Henriksen 1437116cf3 Pontoon: Update Norwegian Bokmål (nb-NO) localization of Test Pilot: Firefox Send
Localization authors:
- Håvar Henriksen <havar@firefox.no>
2017-08-08 07:31:23 +00:00
Varghese Thomas 740001ddde Fixing bug #438 by adding role attribute to anchor tags and alt attributes to images. Also solves #440 2017-08-08 08:05:02 +05:30
Peter deHaan 24af3207e9 Update browserslist 2017-08-07 16:38:19 -07:00
Peter deHaan 38746078ed Add autoprefixer and cssnano support 2017-08-07 16:19:40 -07:00
Jamie fcea981127 Cater for mobile and desktop
Fixes #421
2017-08-06 16:03:54 +01:00
168 changed files with 11270 additions and 4337 deletions
+4 -4
View File
@@ -1,8 +1,8 @@
node_modules
.git
.DS_Store
static
test
scripts
docs
firefox
assets
docs
public
test
+14
View File
@@ -0,0 +1,14 @@
root = true
[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
[*.{js,html,yml,json,handlebars}]
indent_style = space
indent_size = 2
[*.toml]
indent_style = space
indent_size = 4
+2 -2
View File
@@ -1,3 +1,3 @@
public
test/frontend/bundle.js
dist
assets
firefox
+1 -9
View File
@@ -1,10 +1,2 @@
.DS_Store
node_modules
public/upload.js
public/download.js
public/version.json
public/l20n.min.js
public/polyfill.min.js
static/*
!static/info.txt
test/frontend/bundle.js
dist
+3
View File
@@ -0,0 +1,3 @@
{
"exceptions": ["https://nodesecurity.io/advisories/534"]
}
+2
View File
@@ -0,0 +1,2 @@
dist
assets/*.js
+5
View File
@@ -1,6 +1,11 @@
extends: stylelint-config-standard
plugins:
- stylelint-no-unsupported-browser-features
rules:
plugin/no-unsupported-browser-features: [true, {severity: warning}]
color-hex-case: lower
declaration-colon-newline-after: null
selector-list-comma-newline-after: null
+218
View File
@@ -0,0 +1,218 @@
## Change Log
### v1.1.1 (2017/08/17 01:29 +00:00)
- [#516](https://github.com/mozilla/send/pull/516) cache assets (@dannycoates)
- [#520](https://github.com/mozilla/send/pull/520) fix drag & drop (@dannycoates)
- [#515](https://github.com/mozilla/send/pull/515) removed jquery from upload.js (@dannycoates)
- [#514](https://github.com/mozilla/send/pull/514) use async and removed jquery from download.js (@dannycoates)
- [#513](https://github.com/mozilla/send/pull/513) use svg for progress (@dannycoates)
- [#510](https://github.com/mozilla/send/pull/510) added precommit hook for format (@dannycoates)
- [#502](https://github.com/mozilla/send/pull/502) extracted filelist into its own file (@dannycoates)
- [#428](https://github.com/mozilla/send/pull/428) add twitter and open graph cards (@dannycoates, @johngruen)
- [#506](https://github.com/mozilla/send/pull/506) 404 page (@varghesethomase)
- [#508](https://github.com/mozilla/send/pull/508) fixes 478 (@abhinadduri)
- [#504](https://github.com/mozilla/send/pull/504) fix japanese browse button (@johngruen)
- [#503](https://github.com/mozilla/send/pull/503) Added editorconfig (@skystar-p)
- [#499](https://github.com/mozilla/send/pull/499) use import/export in the frontend code (@dannycoates)
- [#500](https://github.com/mozilla/send/pull/500) fixed build:css on windows (@dannycoates)
- [#481](https://github.com/mozilla/send/pull/481) Cater for mobile and desktop (@pdehaan, @hubdotcom)
- [#493](https://github.com/mozilla/send/pull/493) added webpack-dev-middleware (@dannycoates)
- [#491](https://github.com/mozilla/send/pull/491) added missing exit event cases (@dannycoates)
- [#492](https://github.com/mozilla/send/pull/492) make the site mostly work when cookies (localStorage) are disabled (@dannycoates)
- [#490](https://github.com/mozilla/send/pull/490) set the mime type in the download blob (@dannycoates)
- [#485](https://github.com/mozilla/send/pull/485) added progress to tab title when not in focus (@dannycoates)
- [#474](https://github.com/mozilla/send/pull/474) Fixing bug #438 by adding role attribute to anchor tags and alt attribute images (@varghesethomase)
- [#480](https://github.com/mozilla/send/pull/480) Increase font weight to 500 on <button>s and <label>s (@pdehaan)
- [#419](https://github.com/mozilla/send/pull/419) Add autoprefixer and cssnano support (@pdehaan)
### v1.1.0 (2017/08/08 03:59 +00:00)
- [#473](https://github.com/mozilla/send/pull/473) Sort contributors alphabetically to prevent churn (@pdehaan)
- [#472](https://github.com/mozilla/send/pull/472) removed references to checksums in frontend tests (@abhinadduri)
- [#470](https://github.com/mozilla/send/pull/470) removed the file sha256 hash (@dannycoates)
- [#469](https://github.com/mozilla/send/pull/469) Increase mimimum node version to 8.2.0 (@ehuggett)
- [#468](https://github.com/mozilla/send/pull/468) attach delete-file handler only after upload (@dannycoates)
- [#466](https://github.com/mozilla/send/pull/466) added webpack (@dannycoates)
- [#427](https://github.com/mozilla/send/pull/427) Extended system font list fixes:#408 (@gautamkrishnar)
- [#448](https://github.com/mozilla/send/pull/448) Migrate width attribute to CSS (Fixes #436) (@nskins)
- [#457](https://github.com/mozilla/send/pull/457) factored out progress into progress.js (@dannycoates)
- [#452](https://github.com/mozilla/send/pull/452) refactored metrics (@dannycoates)
- [#455](https://github.com/mozilla/send/pull/455) Add a few missing strings from es-CL and tr locales (@pdehaan)
- [#444](https://github.com/mozilla/send/pull/444) Chain jQuery calls, do not use events alias and store selectors (@Johann-S)
- [#416](https://github.com/mozilla/send/pull/416) WIP: use webcrypto-liner to support Safari 10 (@dannycoates)
- [#451](https://github.com/mozilla/send/pull/451) Add rel noopener noreferrer to target='_blank' anchor elements (Fixes #439) (@boopeshmahendran)
- [#449](https://github.com/mozilla/send/pull/449) Add X-UA-Compatible meta tag (@kenrick95)
- [#433](https://github.com/mozilla/send/pull/433) Prevent download button from being clicked multiple times (@pdehaan)
- [#432](https://github.com/mozilla/send/pull/432) Add contributors script (@pdehaan)
- [#409](https://github.com/mozilla/send/pull/409) Handle copy clipboard disabled (@Johann-S)
### v1.0.4 (2017/08/03 23:05 +00:00)
- [#418](https://github.com/mozilla/send/pull/418) _blank all footer links (@dannycoates)
- [#386](https://github.com/mozilla/send/pull/386) fix percentage view on mobile layout (@ariestiyansyah)
- [#414](https://github.com/mozilla/send/pull/414) Add link to FAQ in unsupported view (@pdehaan)
- [#415](https://github.com/mozilla/send/pull/415) Only include Fira CSS on /unsupported/* route (@pdehaan)
- [#412](https://github.com/mozilla/send/pull/412) throw key errors before download begins (@dannycoates)
- [#404](https://github.com/mozilla/send/pull/404) Use async function instead of promise (#325) (@weihanglo)
- [#406](https://github.com/mozilla/send/pull/406) Add noscript tag (@pdehaan)
- [#325](https://github.com/mozilla/send/pull/325) Use async function instead of promise (#325) (@weihanglo)
- [#325](https://github.com/mozilla/send/pull/325) Use async function instead of promise (#325) (@weihanglo)
### v1.0.3 (2017/08/02 23:59 +00:00)
- [#402](https://github.com/mozilla/send/pull/402) filter the hash from error reports (@dannycoates)
- [#400](https://github.com/mozilla/send/pull/400) fix link that breaks download by opening in new tab (@johngruen)
- [#369](https://github.com/mozilla/send/pull/369) Add ESLint no-alert shame rule (@pdehaan)
- [#396](https://github.com/mozilla/send/pull/396) add babel-polyfill (@dannycoates)
- [#394](https://github.com/mozilla/send/pull/394) catch JSON.parse errors of storage metadata (@dannycoates)
- [#367](https://github.com/mozilla/send/pull/367) Generate production locales using 'compare-locales' (@pdehaan)
- [#392](https://github.com/mozilla/send/pull/392) Adjust hover behavior on send-logo (#382)
Fixes: #382. (@weihanglo)
- [#382](https://github.com/mozilla/send/pull/382) Adjust hover behavior on send-logo (#382) (@weihanglo)
- [#382](https://github.com/mozilla/send/pull/382) Adjust hover behavior on send-logo (#382) (@weihanglo)
- [#380](https://github.com/mozilla/send/pull/380) Add Pontoon URL to README (@pdehaan)
### v1.0.2 (2017/07/31 18:58 +00:00)
- [#365](https://github.com/mozilla/send/pull/365) revert the IE fix to fix footer on chrome (@dannycoates)
### v1.0.1 (2017/07/31 17:28 +00:00)
- [#353](https://github.com/mozilla/send/pull/353) redirect ie to /unsupported (@abhinadduri, @dannycoates)
- [#360](https://github.com/mozilla/send/pull/360) Fix some linting nits (@pdehaan)
- [#362](https://github.com/mozilla/send/pull/362) Adjusts category of unsupported event (fixes #350). (@chuckharmston)
- [#355](https://github.com/mozilla/send/pull/355) Make order of uploaded files in list consistent (@pdehaan)
- [#356](https://github.com/mozilla/send/pull/356) Get rid of console.log statements (@pdehaan)
- [#358](https://github.com/mozilla/send/pull/358) Fix some missing .title attributes in dev-only locales (@pdehaan)
- [#354](https://github.com/mozilla/send/pull/354) Remove /en-US/ from cookies link in footer (@pdehaan)
- [#339](https://github.com/mozilla/send/pull/339) Show error page on firefox v49 and below (@ericawright, @abhinadduri)
- [#346](https://github.com/mozilla/send/pull/346) Add docs/CODEOWNERS file (@pdehaan)
- [#345](https://github.com/mozilla/send/pull/345) wrap long file names (@dnarcese)
- [#344](https://github.com/mozilla/send/pull/344) don't wrap file list headers (@dnarcese)
- [#327](https://github.com/mozilla/send/pull/327) Modify popup delete dialog (@youwenliang)
- [#341](https://github.com/mozilla/send/pull/341) center percentage text on all browser versions (@dnarcese)
- [#340](https://github.com/mozilla/send/pull/340) Remove duplicate entities in localized FTL files (@flodolo)
- [#337](https://github.com/mozilla/send/pull/337) support v 50 and 51 by not allowing const in loops (@ericawright)
- [#338](https://github.com/mozilla/send/pull/338) Remove duplicated strings in en-US, fix nn-NO file (@flodolo)
- [#336](https://github.com/mozilla/send/pull/336) German(de): Fixed missing value for deleteFileButton (#336) (@flodolo)
- [#334](https://github.com/mozilla/send/pull/334) fix functionality on firefox 50 and 51 (@dnarcese)
### v1.0.0 (2017/07/26 19:08 +00:00)
- [#323](https://github.com/mozilla/send/pull/323) disable upload/download notifications (@dannycoates)
- [#322](https://github.com/mozilla/send/pull/322) fix feedback button jump (@dnarcese)
- [#320](https://github.com/mozilla/send/pull/320) fix German footer (@dnarcese)
### v0.2.2 (2017/07/26 04:50 +00:00)
- [#314](https://github.com/mozilla/send/pull/314) added L10N_DEV environment variable for making all languages available (@dannycoates)
- [#313](https://github.com/mozilla/send/pull/313) removing timeout limit for front end tests (@abhinadduri)
- [#311](https://github.com/mozilla/send/pull/311) expired ids should reject instead of returning null (@dannycoates)
- [#302](https://github.com/mozilla/send/pull/302) UX Refine WIP (@youwenliang)
- [#310](https://github.com/mozilla/send/pull/310) if the download card is pressed, the expired card shows up properly (@abhinadduri)
- [#269](https://github.com/mozilla/send/pull/269) refactored ftl file (@abhinadduri)
- [#291](https://github.com/mozilla/send/pull/291) added legal page (@dannycoates)
- [#307](https://github.com/mozilla/send/pull/307) don't show error page on upload cancel (@dnarcese)
- [#299](https://github.com/mozilla/send/pull/299) use CIRCLE_TAG as version.json version if present (@dannycoates)
### v0.2.1 (2017/07/24 23:34 +00:00)
- [#296](https://github.com/mozilla/send/pull/296) restyle delete popup (@dnarcese)
- [#295](https://github.com/mozilla/send/pull/295) renamed environment variables to remove P2P_ prefix (@dannycoates)
- [#294](https://github.com/mozilla/send/pull/294) dealing with invalid drag and drops (@abhinadduri)
- [#297](https://github.com/mozilla/send/pull/297) added environment variable for expire time (@dannycoates)
- [#292](https://github.com/mozilla/send/pull/292) Fixes289 (@abhinadduri)
- [#288](https://github.com/mozilla/send/pull/288) fix: Don`t allow upload when not on the upload page. (@ericawright)
- [#285](https://github.com/mozilla/send/pull/285) added messages for processing phases (@dannycoates)
- [#267](https://github.com/mozilla/send/pull/267) make site responsive and add feedback link (@johngruen)
- [#286](https://github.com/mozilla/send/pull/286) Update download progress bar color (@pdehaan)
- [#281](https://github.com/mozilla/send/pull/281) Stop ESLint from linting the /public/ directory (@pdehaan)
- [#280](https://github.com/mozilla/send/pull/280) created /unsupported page and added gcmCompliant to /download page (@dannycoates)
- [#279](https://github.com/mozilla/send/pull/279) create separate js bundles for upload/download pages (@dannycoates)
- [#268](https://github.com/mozilla/send/pull/268) Testpilot ga (@abhinadduri)
### v0.2.0 (2017/07/21 19:27 +00:00)
- [#266](https://github.com/mozilla/send/pull/266) abort uploads over maxfilesize (@dannycoates)
- [#264](https://github.com/mozilla/send/pull/264) Remove duplicate custom metric. (@chuckharmston)
- [#259](https://github.com/mozilla/send/pull/259) add alert when uploading multiple files (@dnarcese)
- [#262](https://github.com/mozilla/send/pull/262) sync download progress bar with percentage (@dnarcese)
- [#258](https://github.com/mozilla/send/pull/258) better sync percent with progress bar (@dnarcese)
- [#257](https://github.com/mozilla/send/pull/257) add a dynamic js script for page config (@dannycoates)
- [#256](https://github.com/mozilla/send/pull/256) add file size limit message (@dnarcese)
- [#253](https://github.com/mozilla/send/pull/253) Add favicon.ico version of the Send logo (@pdehaan)
- [#254](https://github.com/mozilla/send/pull/254) Add nsp check to circle ci (@pdehaan)
- [#245](https://github.com/mozilla/send/pull/245) Localization (@abhinadduri)
- [#252](https://github.com/mozilla/send/pull/252) only allow drag and drop on upload page (@dnarcese)
- [#250](https://github.com/mozilla/send/pull/250) make footer not overlap (@dnarcese)
- [#251](https://github.com/mozilla/send/pull/251) minify all images (@ericawright)
- [#249](https://github.com/mozilla/send/pull/249) change how the file upload box expands (@dnarcese)
- [#246](https://github.com/mozilla/send/pull/246) remove P2P references. Fixes #224 (@clouserw)
- [#242](https://github.com/mozilla/send/pull/242) Make only icons clickable in file list (@dnarcese)
- [#236](https://github.com/mozilla/send/pull/236) add FAQ. Fixes #186 (@clouserw)
- [#235](https://github.com/mozilla/send/pull/235) allow send another file link to open in new tab (@dnarcese)
- [#234](https://github.com/mozilla/send/pull/234) fix download svg (@dnarcese)
- [#232](https://github.com/mozilla/send/pull/232) escape filename in the ui (@dannycoates)
- [#226](https://github.com/mozilla/send/pull/226) added functionality to cancel uploads (@abhinadduri)
- [#231](https://github.com/mozilla/send/pull/231) move head and html tags to main template (@dnarcese)
- [#228](https://github.com/mozilla/send/pull/228) add send logo (@dnarcese)
- [#229](https://github.com/mozilla/send/pull/229) change learn more and github links (@dnarcese)
- [#201](https://github.com/mozilla/send/pull/201) Adds metrics documentation (closes #5). (@chuckharmston)
- [#223](https://github.com/mozilla/send/pull/223) change size of send another file links (@dnarcese)
- [#222](https://github.com/mozilla/send/pull/222) add footer (@dnarcese)
- [#197](https://github.com/mozilla/send/pull/197) fixes issues 195 and 192 (@abhinadduri)
- [#204](https://github.com/mozilla/send/pull/204) added HSTS header (@dannycoates)
- [#193](https://github.com/mozilla/send/pull/193) Frontend tests (@abhinadduri)
- [#191](https://github.com/mozilla/send/pull/191) New ui! (@dnarcese)
### v0.1.4 (2017/07/12 18:21 +00:00)
- [#189](https://github.com/mozilla/send/pull/189) Add CSP directives (@dannycoates)
- [#188](https://github.com/mozilla/send/pull/188) fixes delete button error (@abhinadduri)
- [#185](https://github.com/mozilla/send/pull/185) added loading, hashing, and encrypting events for uploader; decryptin… (@abhinadduri)
- [#183](https://github.com/mozilla/send/pull/183) rename to 'Send' (@dannycoates)
- [#184](https://github.com/mozilla/send/pull/184) Server tests (@abhinadduri)
- [#178](https://github.com/mozilla/send/pull/178) fixed issues in branch title (@abhinadduri)
- [#177](https://github.com/mozilla/send/pull/177) Gcm compliance (@abhinadduri)
- [#106](https://github.com/mozilla/send/pull/106) Gcm (@abhinadduri, @dannycoates)
- [#168](https://github.com/mozilla/send/pull/168) Show error page if upload fails (@dnarcese)
- [#148](https://github.com/mozilla/send/pull/148) WIP: Add basic contribute.json (@pdehaan)
- [#162](https://github.com/mozilla/send/pull/162) Fix dev server URL in README.md file (@pdehaan)
- [#167](https://github.com/mozilla/send/pull/167) build docker image with new name (@relud)
- [#164](https://github.com/mozilla/send/pull/164) Add word wraps to table (@dnarcese)
- [#149](https://github.com/mozilla/send/pull/149) Add robots.txt (@pdehaan)
- [#161](https://github.com/mozilla/send/pull/161) Hide table header on empty list (@dnarcese)
- [#154](https://github.com/mozilla/send/pull/154) Remove expired uploads (@dnarcese)
- [#146](https://github.com/mozilla/send/pull/146) Update README with some more details (@pdehaan)
### v0.1.2 (2017/06/24 03:38 +00:00)
- [#138](https://github.com/mozilla/send/pull/138) remove notLocalHost (@dannycoates)
### v0.1.0 (2017/06/24 01:24 +00:00)
- [#137](https://github.com/mozilla/send/pull/137) refactored docker build (@dannycoates)
- [#132](https://github.com/mozilla/send/pull/132) Add /__version__ route (@pdehaan)
- [#135](https://github.com/mozilla/send/pull/135) make dockerfile more dockerflowy (@dannycoates)
- [#134](https://github.com/mozilla/send/pull/134) Load previous uploads (@dannycoates, @dnarcese)
- [#131](https://github.com/mozilla/send/pull/131) added __heartbeat__ (@dannycoates)
- [#133](https://github.com/mozilla/send/pull/133) Add LICENSE file (@pdehaan)
- [#130](https://github.com/mozilla/send/pull/130) added sentry to server code (@abhinadduri)
- [#124](https://github.com/mozilla/send/pull/124) Remove unused [dev]dependencies (@pdehaan)
- [#119](https://github.com/mozilla/send/pull/119) Move cross-env to a dep (@pdehaan)
- [#123](https://github.com/mozilla/send/pull/123) removed bitly integration (@abhinadduri)
- [#122](https://github.com/mozilla/send/pull/122) fix docker build (@dannycoates)
- [#121](https://github.com/mozilla/send/pull/121) added docker service to circle.yml (@dannycoates)
- [#120](https://github.com/mozilla/send/pull/120) added sentry (@abhinadduri)
- [#118](https://github.com/mozilla/send/pull/118) change docker image name and add builds for tags (@relud)
- [#116](https://github.com/mozilla/send/pull/116) add /__lbheartbeat__ endpoint (@relud)
- [#79](https://github.com/mozilla/send/pull/79) Optimize/minimize bundle.js for production (@pdehaan)
- [#104](https://github.com/mozilla/send/pull/104) Fix a bunch of ESLint and HTMLLint errors (@pdehaan)
- [#105](https://github.com/mozilla/send/pull/105) Progress bars (@dnarcese)
- [#111](https://github.com/mozilla/send/pull/111) added in anonmyized ip google analytics (@abhinadduri)
- [#110](https://github.com/mozilla/send/pull/110) added notifications (@abhinadduri)
- [#103](https://github.com/mozilla/send/pull/103) added Dockerfile (@dannycoates)
- [#100](https://github.com/mozilla/send/pull/100) Added Helmet Middleware (@abhinadduri)
- [#99](https://github.com/mozilla/send/pull/99) Testing (@abhinadduri)
- [#77](https://github.com/mozilla/send/pull/77) Fix the linter errors (@pdehaan)
- [#54](https://github.com/mozilla/send/pull/54) Adding basic ESLint config (@pdehaan)
- [#71](https://github.com/mozilla/send/pull/71) Drag & drop (@dnarcese)
- [#72](https://github.com/mozilla/send/pull/72) Logging (@abhinadduri, @dannycoates)
- [#45](https://github.com/mozilla/send/pull/45) S3 integration (@abhinadduri, @dannycoates)
- [#46](https://github.com/mozilla/send/pull/46) Download page and share link UI (@dnarcese)
- [#41](https://github.com/mozilla/send/pull/41) Added upload page and file list UI (@dnarcese)
- [#40](https://github.com/mozilla/send/pull/40) Tweak the package.json file (@pdehaan)
- [#43](https://github.com/mozilla/send/pull/43) added return (@abhinadduri)
- [#42](https://github.com/mozilla/send/pull/42) changed to handle 404 during download, also removing progress listene… (@abhinadduri)
- [#39](https://github.com/mozilla/send/pull/39) Refactor riff (@abhinadduri, @dannycoates)
- [#36](https://github.com/mozilla/send/pull/36) added prettier for js formatting (@dannycoates)
- [#28](https://github.com/mozilla/send/pull/28) Added a UI for the uploader end, made stylistic changes, implemented deleting (@abhinadduri)
- [#25](https://github.com/mozilla/send/pull/25) Changed naming for some pages, no longer stores files by name on server (@abhinadduri)
+14
View File
@@ -2,15 +2,19 @@ Abhinav Adduri
Alexander Slovesnik
Amin Mahmudian
Andreas Pettersson
Arash Mousavi
Balázs Meskó
Belayet Hossain
Bjørn I
Boopesh Mahendran
Chuck Harmston
Cláudio Esperança
Cynthia Pereira
Daniel Thorn
Daniela Arcese
Danny Coates
Emin Mastizada
Enol
Erica
Erica Wright
Fjoerfoks
@@ -18,9 +22,13 @@ Francesco Lodolo
Francesco Lodolo [:flod]
Gautam krishna.R
Håvar Henriksen
Jae Hyeon Park
Jakub Rychlý
Jamie
Jim Spentzos
Johann-S
John Gruen
Jon Vadillo
Jordi Serratosa
Juraj Cigáň
Kohei Yoshino
@@ -48,12 +56,14 @@ Rok Žerdin
Sahithi
Sairam Raavi
Sandro
Schieck :)
Selim Şumlu
Slimane Amiri
Théo Chevalier
Tomáš Zelina
Ton
Tymur Faradzhev
Varghese Thomas
Victor Bychek
Weihang Lo
Wil Clouser
@@ -69,10 +79,14 @@ erdem cobanoglu
gautamkrishnar
goofy
hi
jesferman1993
josotrix
kenrick95
manxmensch
ravmn
reza.habibi2008
siparon
skystar-p
xcffl
Μιχάλης
Марко Костић (Marko Kostić)
+1 -1
View File
@@ -12,4 +12,4 @@ RUN npm install --production && npm cache clean --force
ENV PORT=1443
EXPOSE $PORT
CMD ["npm", "start"]
CMD ["npm", "run", "prod"]
+52 -7
View File
@@ -5,39 +5,80 @@
**Docs:** [Docker](docs/docker.md), [Metrics](docs/metrics.md)
---
## Table of Contents
* [What it does](#what-it-does)
* [Requirements](#requirements)
* [Development](#development)
* [Commands](#commands)
* [Configuration](#configuration)
* [Localization](#localization)
* [Contributing](#contributing)
* [Testing](#testing)
* [License](#license)
---
## What it does
A file sharing experiment which allows you to send encrypted files to other users.
---
## Requirements
- [Node.js 8+](https://nodejs.org/)
- [Redis server](https://redis.io/)
- [Node.js 8.2+](https://nodejs.org/)
- [Redis server](https://redis.io/) (optional for development)
- [AWS S3](https://aws.amazon.com/s3/) or compatible service. (optional)
**NOTE:** To run the project, make sure you have a Redis server running locally:
---
## Development
To start an ephemeral development server run:
```sh
$ redis-server /usr/local/etc/redis.conf
npm install
npm start
```
## How to use it
Then browse to http://localhost:8080
---
## Commands
| Command | Description |
|------------------|-------------|
| `npm run dev` | Builds and starts the web server locally for development.
| `npm run format` | Formats the frontend and server code using **prettier**.
| `npm run lint` | Lints the CSS and JavaScript code.
| `npm start` | Starts the Express web server.
| `npm test` | Runs the suite of mocha tests.
| `npm start` | Runs the server in development configuration.
| `npm run build` | Builds the production assets.
| `npm run prod` | Runs the server in production configuration.
---
## Configuration
The server is configured with environment variables. See [server/config.js](server/config.js) for all options and [docs/docker.md](docs/docker.md) for examples.
---
## Localization
Firefox Send localization is managed via [Pontoon](https://pontoon.mozilla.org/projects/test-pilot-firefox-send/), not direct pull requests to the repository. If you want to fix a typo, add a new language, or simply know more about localization, please get in touch with the [existing localization team](https://pontoon.mozilla.org/teams/) for your language, or Mozillas [l10n-drivers](https://wiki.mozilla.org/L10n:Mozilla_Team#Mozilla_Corporation) for guidance.
---
## Contributing
Pull requests are always welcome! Feel free to check out the list of ["good first bugs"](https://github.com/mozilla/send/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+bug%22).
---
## Testing
| ENVIRONMENT | URL
@@ -46,6 +87,10 @@ Pull requests are always welcome! Feel free to check out the list of ["good firs
| Stage | <https://send.stage.mozaws.net/>
| Development | <https://send.dev.mozaws.net/>
---
## License
[Mozilla Public License Version 2.0](LICENSE)
---
+9
View File
@@ -0,0 +1,9 @@
env:
browser: true
node: true
parserOptions:
sourceType: module
rules:
node/no-unsupported-features: off
+24
View File
@@ -0,0 +1,24 @@
export default function(state, emitter) {
emitter.on('DOMContentLoaded', () => {
document.body.addEventListener('dragover', event => {
if (state.route === '/') {
event.preventDefault();
}
});
document.body.addEventListener('drop', event => {
if (state.route === '/' && !state.transfer) {
event.preventDefault();
document.querySelector('.upload-window').classList.remove('ondrag');
const target = event.dataTransfer;
if (target.files.length === 0) {
return;
}
if (target.files.length > 1 || target.files[0].size === 0) {
return alert(state.translate('uploadPageMultipleFilesAlert'));
}
const file = target.files[0];
emitter.emit('upload', { file, type: 'drop' });
}
});
});
}
+47
View File
@@ -0,0 +1,47 @@
import hash from 'string-hash';
const experiments = {};
//Returns a number between 0 and 1
// eslint-disable-next-line no-unused-vars
function luckyNumber(str) {
return hash(str) / 0xffffffff;
}
function checkExperiments(state, emitter) {
const all = Object.keys(experiments);
const id = all.find(id => experiments[id].eligible(state));
if (id) {
const variant = experiments[id].variant(state);
state.storage.enroll(id, variant);
experiments[id].run(variant, state, emitter);
}
}
export default function initialize(state, emitter) {
emitter.on('DOMContentLoaded', () => {
const xp = experiments[state.query.x];
if (xp) {
xp.run(+state.query.v, state, emitter);
}
});
if (!state.storage.get('testpilot_ga__cid')) {
// first ever visit. check again after cid is assigned.
emitter.on('DOMContentLoaded', () => {
checkExperiments(state, emitter);
});
} else {
const enrolled = state.storage.enrolled;
enrolled.forEach(([id, variant]) => {
const xp = experiments[id];
if (xp) {
xp.run(variant, state, emitter);
}
});
// single experiment per session for now
if (enrolled.length === 0) {
checkExperiments(state, emitter);
}
}
}
+218
View File
@@ -0,0 +1,218 @@
/* global EXPIRE_SECONDS */
import FileSender from './fileSender';
import FileReceiver from './fileReceiver';
import { copyToClipboard, delay, fadeOut, percent } from './utils';
import * as metrics from './metrics';
function saveFile(file) {
const dataView = new DataView(file.plaintext);
const blob = new Blob([dataView], { type: file.type });
const downloadUrl = URL.createObjectURL(blob);
if (window.navigator.msSaveBlob) {
return window.navigator.msSaveBlob(blob, file.name);
}
const a = document.createElement('a');
a.href = downloadUrl;
a.download = file.name;
document.body.appendChild(a);
a.click();
URL.revokeObjectURL(downloadUrl);
}
function openLinksInNewTab(links, should = true) {
links = links || Array.from(document.querySelectorAll('a:not([target])'));
if (should) {
links.forEach(l => {
l.setAttribute('target', '_blank');
l.setAttribute('rel', 'noopener noreferrer');
});
} else {
links.forEach(l => {
l.removeAttribute('target');
l.removeAttribute('rel');
});
}
return links;
}
function exists(id) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
resolve(xhr.status === 200);
}
};
xhr.onerror = () => resolve(false);
xhr.ontimeout = () => resolve(false);
xhr.open('get', '/api/exists/' + id);
xhr.timeout = 2000;
xhr.send();
});
}
export default function(state, emitter) {
let lastRender = 0;
let updateTitle = false;
function render() {
emitter.emit('render');
}
async function checkFiles() {
const files = state.storage.files;
let rerender = false;
for (const file of files) {
const ok = await exists(file.id);
if (!ok) {
state.storage.remove(file.id);
rerender = true;
}
}
if (rerender) {
render();
}
}
function updateProgress() {
if (updateTitle) {
emitter.emit('DOMTitleChange', percent(state.transfer.progressRatio));
}
render();
}
emitter.on('DOMContentLoaded', () => {
document.addEventListener('blur', () => (updateTitle = true));
document.addEventListener('focus', () => {
updateTitle = false;
emitter.emit('DOMTitleChange', 'Firefox Send');
});
checkFiles();
});
emitter.on('navigate', checkFiles);
emitter.on('render', () => {
lastRender = Date.now();
});
emitter.on('delete', async ({ file, location }) => {
try {
metrics.deletedUpload({
size: file.size,
time: file.time,
speed: file.speed,
type: file.type,
ttl: file.expiresAt - Date.now(),
location
});
state.storage.remove(file.id);
await FileSender.delete(file.id, file.deleteToken);
} catch (e) {
state.raven.captureException(e);
}
state.fileInfo = null;
});
emitter.on('cancel', () => {
state.transfer.cancel();
});
emitter.on('upload', async ({ file, type }) => {
const size = file.size;
const sender = new FileSender(file);
sender.on('progress', updateProgress);
sender.on('encrypting', render);
state.transfer = sender;
render();
const links = openLinksInNewTab();
await delay(200);
try {
const start = Date.now();
metrics.startedUpload({ size, type });
const info = await sender.upload();
const time = Date.now() - start;
const speed = size / (time / 1000);
metrics.completedUpload({ size, time, speed, type });
document.getElementById('cancel-upload').hidden = 'hidden';
await delay(1000);
await fadeOut('upload-progress');
info.name = file.name;
info.size = size;
info.type = type;
info.time = time;
info.speed = speed;
info.createdAt = Date.now();
info.url = `${info.url}#${info.secretKey}`;
info.expiresAt = Date.now() + EXPIRE_SECONDS * 1000;
state.fileInfo = info;
state.storage.addFile(state.fileInfo);
openLinksInNewTab(links, false);
state.transfer = null;
state.storage.totalUploads += 1;
emitter.emit('pushState', `/share/${info.id}`);
} catch (err) {
state.transfer = null;
if (err.message === '0') {
//cancelled. do nothing
metrics.cancelledUpload({ size, type });
return render();
}
state.raven.captureException(err);
metrics.stoppedUpload({ size, type, err });
emitter.emit('replaceState', '/error');
}
});
emitter.on('download', async file => {
const size = file.size;
const url = `/api/download/${file.id}`;
const receiver = new FileReceiver(url, file.key);
receiver.on('progress', updateProgress);
receiver.on('decrypting', render);
state.transfer = receiver;
const links = openLinksInNewTab();
render();
try {
const start = Date.now();
metrics.startedDownload({ size: file.size, ttl: file.ttl });
const f = await receiver.download();
const time = Date.now() - start;
const speed = size / (time / 1000);
await delay(1000);
await fadeOut('download-progress');
saveFile(f);
state.storage.totalDownloads += 1;
metrics.completedDownload({ size, time, speed });
emitter.emit('pushState', '/completed');
} catch (err) {
// TODO cancelled download
const location = err.message === 'notfound' ? '/404' : '/error';
if (location === '/error') {
state.raven.captureException(err);
metrics.stoppedDownload({ size, err });
}
emitter.emit('replaceState', location);
} finally {
state.transfer = null;
openLinksInNewTab(links, false);
}
});
emitter.on('copy', ({ url, location }) => {
copyToClipboard(url);
metrics.copiedLink({ location });
});
setInterval(() => {
// poll for rerendering the file list countdown timers
if (
state.route === '/' &&
state.storage.files.length > 0 &&
Date.now() - lastRender > 30000
) {
render();
}
}, 60000);
}
+100
View File
@@ -0,0 +1,100 @@
import Nanobus from 'nanobus';
import { hexToArray, bytes } from './utils';
export default class FileReceiver extends Nanobus {
constructor(url, k) {
super('FileReceiver');
this.key = window.crypto.subtle.importKey(
'jwk',
{
k,
kty: 'oct',
alg: 'A128GCM',
ext: true
},
{
name: 'AES-GCM'
},
false,
['decrypt']
);
this.url = url;
this.msg = 'fileSizeProgress';
this.progress = [0, 1];
}
get progressRatio() {
return this.progress[0] / this.progress[1];
}
get sizes() {
return {
partialSize: bytes(this.progress[0]),
totalSize: bytes(this.progress[1])
};
}
cancel() {
// TODO
}
downloadFile() {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onprogress = event => {
if (event.lengthComputable && event.target.status !== 404) {
this.progress = [event.loaded, event.total];
this.emit('progress', this.progress);
}
};
xhr.onload = function(event) {
if (xhr.status === 404) {
reject(new Error('notfound'));
return;
}
const blob = new Blob([this.response]);
const meta = JSON.parse(xhr.getResponseHeader('X-File-Metadata'));
const fileReader = new FileReader();
fileReader.onload = function() {
resolve({
data: this.result,
name: meta.filename,
type: meta.mimeType,
iv: meta.id
});
};
fileReader.readAsArrayBuffer(blob);
};
xhr.open('get', this.url);
xhr.responseType = 'blob';
xhr.send();
});
}
async download() {
const key = await this.key;
const file = await this.downloadFile();
this.msg = 'decryptingFile';
this.emit('decrypting');
const plaintext = await window.crypto.subtle.decrypt(
{
name: 'AES-GCM',
iv: hexToArray(file.iv),
tagLength: 128
},
key,
file.data
);
this.msg = 'downloadFinish';
return {
plaintext,
name: decodeURIComponent(file.name),
type: file.type
};
}
}
+146
View File
@@ -0,0 +1,146 @@
import Nanobus from 'nanobus';
import { arrayToHex, bytes } from './utils';
export default class FileSender extends Nanobus {
constructor(file) {
super('FileSender');
this.file = file;
this.msg = 'importingFile';
this.progress = [0, 1];
this.cancelled = false;
this.iv = window.crypto.getRandomValues(new Uint8Array(12));
this.uploadXHR = new XMLHttpRequest();
this.key = window.crypto.subtle.generateKey(
{
name: 'AES-GCM',
length: 128
},
true,
['encrypt']
);
}
static delete(id, token) {
return new Promise((resolve, reject) => {
if (!id || !token) {
return reject();
}
const xhr = new XMLHttpRequest();
xhr.open('POST', `/api/delete/${id}`);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onreadystatechange = () => {
if (xhr.readyState === XMLHttpRequest.DONE) {
resolve();
}
};
xhr.send(JSON.stringify({ delete_token: token }));
});
}
get progressRatio() {
return this.progress[0] / this.progress[1];
}
get sizes() {
return {
partialSize: bytes(this.progress[0]),
totalSize: bytes(this.progress[1])
};
}
cancel() {
this.cancelled = true;
if (this.msg === 'fileSizeProgress') {
this.uploadXHR.abort();
}
}
readFile() {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsArrayBuffer(this.file);
reader.onload = function(event) {
const plaintext = new Uint8Array(this.result);
resolve(plaintext);
};
reader.onerror = function(err) {
reject(err);
};
});
}
uploadFile(encrypted, keydata) {
return new Promise((resolve, reject) => {
const file = this.file;
const id = arrayToHex(this.iv);
const dataView = new DataView(encrypted);
const blob = new Blob([dataView], { type: file.type });
const fd = new FormData();
fd.append('data', blob, file.name);
const xhr = this.uploadXHR;
xhr.upload.addEventListener('progress', e => {
if (e.lengthComputable) {
this.progress = [e.loaded, e.total];
this.emit('progress', this.progress);
}
});
xhr.onreadystatechange = () => {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
this.progress = [1, 1];
this.msg = 'notifyUploadDone';
const responseObj = JSON.parse(xhr.responseText);
return resolve({
url: responseObj.url,
id: responseObj.id,
secretKey: keydata.k,
deleteToken: responseObj.delete
});
}
this.msg = 'errorPageHeader';
reject(new Error(xhr.status));
}
};
xhr.open('post', '/api/upload', true);
xhr.setRequestHeader(
'X-File-Metadata',
JSON.stringify({
id: id,
filename: encodeURIComponent(file.name)
})
);
xhr.send(fd);
this.msg = 'fileSizeProgress';
});
}
async upload() {
const key = await this.key;
const plaintext = await this.readFile();
if (this.cancelled) {
throw new Error(0);
}
this.msg = 'encryptingFile';
this.emit('encrypting');
const encrypted = await window.crypto.subtle.encrypt(
{
name: 'AES-GCM',
iv: this.iv,
tagLength: 128
},
key,
plaintext
);
if (this.cancelled) {
throw new Error(0);
}
const keydata = await window.crypto.subtle.exportKey('jwk', key);
return this.uploadFile(encrypted, keydata);
}
}
+44
View File
@@ -0,0 +1,44 @@
import app from './routes';
import locale from '../common/locales';
import fileManager from './fileManager';
import dragManager from './dragManager';
import { canHasSend } from './utils';
import assets from '../common/assets';
import storage from './storage';
import metrics from './metrics';
import experiments from './experiments';
import Raven from 'raven-js';
if (navigator.doNotTrack !== '1' && window.RAVEN_CONFIG) {
Raven.config(window.SENTRY_ID, window.RAVEN_CONFIG).install();
}
app.use((state, emitter) => {
// init state
state.transfer = null;
state.fileInfo = null;
state.translate = locale.getTranslator();
state.storage = storage;
state.raven = Raven;
emitter.on('DOMContentLoaded', async () => {
if (
/firefox/i.test(navigator.userAgent) &&
parseInt(navigator.userAgent.match(/firefox\/*([^\n\r]*)\./i)[1], 10) <=
49
) {
return emitter.emit('replaceState', '/unsupported/outdated');
}
const ok = await canHasSend(assets.get('cryptofill.js'));
if (!ok) {
const reason = /firefox/i.test(navigator.userAgent) ? 'outdated' : 'gcm';
emitter.emit('replaceState', `/unsupported/${reason}`);
}
});
});
app.use(metrics);
app.use(fileManager);
app.use(dragManager);
app.use(experiments);
app.mount('#page-one');
+79 -46
View File
@@ -1,6 +1,12 @@
const testPilotGA = require('testpilot-ga/src/TestPilotGA');
const Storage = require('./storage');
const storage = new Storage(localStorage);
import testPilotGA from 'testpilot-ga/src/TestPilotGA';
import storage from './storage';
let hasLocalStorage = false;
try {
hasLocalStorage = typeof localStorage !== 'undefined';
} catch (e) {
// when disabled, any mention of localStorage throws an error
}
const analytics = new testPilotGA({
an: 'Firefox Send',
@@ -8,17 +14,46 @@ const analytics = new testPilotGA({
tid: window.GOOGLE_ANALYTICS_ID
});
const category = location.pathname.includes('/download')
? 'recipient'
: 'sender';
let appState = null;
let experiment = null;
document.addEventListener('DOMContentLoaded', function() {
addExitHandlers();
addRestartHandlers();
});
export default function initialize(state, emitter) {
appState = state;
emitter.on('DOMContentLoaded', () => {
addExitHandlers();
experiment = storage.enrolled[0];
sendEvent(category(), 'visit', {
cm5: storage.totalUploads,
cm6: storage.files.length,
cm7: storage.totalDownloads
});
//TODO restart handlers... somewhere
});
}
function category() {
switch (appState.route) {
case '/':
case '/share/:id':
return 'sender';
case '/download/:id/:key':
case '/download/:id':
case '/completed':
return 'recipient';
default:
return 'other';
}
}
function sendEvent() {
return analytics.sendEvent.apply(analytics, arguments).catch(() => 0);
const args = Array.from(arguments);
if (experiment && args[2]) {
args[2].xid = experiment[0];
args[2].xvar = experiment[1];
}
return (
hasLocalStorage && analytics.sendEvent.apply(analytics, args).catch(() => 0)
);
}
function urlToMetric(url) {
@@ -41,17 +76,22 @@ function urlToMetric(url) {
return 'twitter';
case 'https://www.mozilla.org/firefox/new/?scene=2':
return 'download-firefox';
case 'https://qsurvey.mozilla.com/s3/txp-firefox-send':
return 'survey';
case 'https://testpilot.firefox.com/':
case 'https://testpilot.firefox.com/experiments/send':
return 'testpilot';
default:
return 'other';
}
}
function setReferrer(state) {
if (category === 'sender') {
if (category() === 'sender') {
if (state) {
storage.referrer = `${state}-upload`;
}
} else if (category === 'recipient') {
} else if (category() === 'recipient') {
if (state) {
storage.referrer = `${state}-download`;
}
@@ -72,10 +112,10 @@ function takeReferrer() {
}
function startedUpload(params) {
return sendEvent(category, 'upload-started', {
return sendEvent('sender', 'upload-started', {
cm1: params.size,
cm5: storage.totalUploads,
cm6: storage.numFiles + 1,
cm6: storage.files.length + 1,
cm7: storage.totalDownloads,
cd1: params.type,
cd5: takeReferrer()
@@ -84,10 +124,10 @@ function startedUpload(params) {
function cancelledUpload(params) {
setReferrer('cancelled');
return sendEvent(category, 'upload-stopped', {
return sendEvent('sender', 'upload-stopped', {
cm1: params.size,
cm5: storage.totalUploads,
cm6: storage.numFiles,
cm6: storage.files.length,
cm7: storage.totalDownloads,
cd1: params.type,
cd2: 'cancelled'
@@ -95,12 +135,12 @@ function cancelledUpload(params) {
}
function completedUpload(params) {
return sendEvent(category, 'upload-stopped', {
return sendEvent('sender', 'upload-stopped', {
cm1: params.size,
cm2: params.time,
cm3: params.speed,
cm5: storage.totalUploads,
cm6: storage.numFiles,
cm6: storage.files.length,
cm7: storage.totalDownloads,
cd1: params.type,
cd2: 'completed'
@@ -108,20 +148,20 @@ function completedUpload(params) {
}
function startedDownload(params) {
return sendEvent(category, 'download-started', {
return sendEvent('recipient', 'download-started', {
cm1: params.size,
cm4: params.ttl,
cm5: storage.totalUploads,
cm6: storage.numFiles,
cm6: storage.files.length,
cm7: storage.totalDownloads
});
}
function stoppedDownload(params) {
return sendEvent(category, 'download-stopped', {
return sendEvent('recipient', 'download-stopped', {
cm1: params.size,
cm5: storage.totalUploads,
cm6: storage.numFiles,
cm6: storage.files.length,
cm7: storage.totalDownloads,
cd2: 'errored',
cd6: params.err
@@ -130,20 +170,20 @@ function stoppedDownload(params) {
function cancelledDownload(params) {
setReferrer('cancelled');
return sendEvent(category, 'download-stopped', {
return sendEvent('recipient', 'download-stopped', {
cm1: params.size,
cm5: storage.totalUploads,
cm6: storage.numFiles,
cm6: storage.files.length,
cm7: storage.totalDownloads,
cd2: 'cancelled'
});
}
function stoppedUpload(params) {
return sendEvent(category, 'upload-stopped', {
return sendEvent('sender', 'upload-stopped', {
cm1: params.size,
cm5: storage.totalUploads,
cm6: storage.numFiles,
cm6: storage.files.length,
cm7: storage.totalDownloads,
cd1: params.type,
cd2: 'errored',
@@ -152,25 +192,25 @@ function stoppedUpload(params) {
}
function completedDownload(params) {
return sendEvent(category, 'download-stopped', {
return sendEvent('recipient', 'download-stopped', {
cm1: params.size,
cm2: params.time,
cm3: params.speed,
cm5: storage.totalUploads,
cm6: storage.numFiles,
cm6: storage.files.length,
cm7: storage.totalDownloads,
cd2: 'completed'
});
}
function deletedUpload(params) {
return sendEvent(category, 'upload-deleted', {
return sendEvent(category(), 'upload-deleted', {
cm1: params.size,
cm2: params.time,
cm3: params.speed,
cm4: params.ttl,
cm5: storage.totalUploads,
cm6: storage.numFiles,
cm6: storage.files.length,
cm7: storage.totalDownloads,
cd1: params.type,
cd4: params.location
@@ -178,19 +218,19 @@ function deletedUpload(params) {
}
function unsupported(params) {
return sendEvent(category, 'unsupported', {
return sendEvent(category(), 'unsupported', {
cd6: params.err
});
}
function copiedLink(params) {
return sendEvent(category, 'copied', {
return sendEvent('sender', 'copied', {
cd4: params.location
});
}
function exitEvent(target) {
return sendEvent(category, 'exited', {
return sendEvent(category(), 'exited', {
cd3: urlToMetric(target.currentTarget.href)
});
}
@@ -198,28 +238,20 @@ function exitEvent(target) {
function addExitHandlers() {
const links = Array.from(document.querySelectorAll('a'));
links.forEach(l => {
if (/^http/.test(l.href)) {
if (/^http/.test(l.getAttribute('href'))) {
l.addEventListener('click', exitEvent);
}
});
}
function restartEvent(state) {
function restart(state) {
setReferrer(state);
return sendEvent(category, 'restarted', {
return sendEvent(category(), 'restarted', {
cd2: state
});
}
function addRestartHandlers() {
const elements = Array.from(document.querySelectorAll('.send-new'));
elements.forEach(el => {
const state = el.getAttribute('data-state');
el.addEventListener('click', restartEvent.bind(null, state));
});
}
module.exports = {
export {
copiedLink,
startedUpload,
cancelledUpload,
@@ -230,5 +262,6 @@ module.exports = {
cancelledDownload,
stoppedDownload,
completedDownload,
restart,
unsupported
};
+9
View File
@@ -0,0 +1,9 @@
const preview = require('../templates/preview');
const download = require('../templates/download');
module.exports = function(state, emit) {
if (state.transfer) {
return download(state, emit);
}
return preview(state, emit);
};
+9
View File
@@ -0,0 +1,9 @@
const welcome = require('../templates/welcome');
const upload = require('../templates/upload');
module.exports = function(state, emit) {
if (state.transfer) {
return upload(state, emit);
}
return welcome(state, emit);
};
+17
View File
@@ -0,0 +1,17 @@
const choo = require('choo');
const download = require('./download');
const app = choo();
app.route('/', require('./home'));
app.route('/share/:id', require('../templates/share'));
app.route('/download/:id', download);
app.route('/download/:id/:key', download);
app.route('/completed', require('../templates/completed'));
app.route('/unsupported/:reason', require('../templates/unsupported'));
app.route('/legal', require('../templates/legal'));
app.route('/error', require('../templates/error'));
app.route('/blank', require('../templates/blank'));
app.route('*', require('../templates/notFound'));
module.exports = app;
+119
View File
@@ -0,0 +1,119 @@
import { isFile } from './utils';
class Mem {
constructor() {
this.items = new Map();
}
get length() {
return this.items.size;
}
getItem(key) {
return this.items.get(key);
}
setItem(key, value) {
return this.items.set(key, value);
}
removeItem(key) {
return this.items.delete(key);
}
key(i) {
return this.items.keys()[i];
}
}
class Storage {
constructor() {
try {
this.engine = localStorage || new Mem();
} catch (e) {
this.engine = new Mem();
}
this._files = this.loadFiles();
}
loadFiles() {
const fs = [];
for (let i = 0; i < this.engine.length; i++) {
const k = this.engine.key(i);
if (isFile(k)) {
try {
const f = JSON.parse(this.engine.getItem(k));
if (!f.id) {
f.id = f.fileId;
}
fs.push(f);
} catch (err) {
// obviously you're not a golfer
this.engine.removeItem(k);
}
}
}
return fs.sort((a, b) => a.createdAt - b.createdAt);
}
get totalDownloads() {
return Number(this.engine.getItem('totalDownloads'));
}
set totalDownloads(n) {
this.engine.setItem('totalDownloads', n);
}
get totalUploads() {
return Number(this.engine.getItem('totalUploads'));
}
set totalUploads(n) {
this.engine.setItem('totalUploads', n);
}
get referrer() {
return this.engine.getItem('referrer');
}
set referrer(str) {
this.engine.setItem('referrer', str);
}
get enrolled() {
return JSON.parse(this.engine.getItem('experiments') || '[]');
}
enroll(id, variant) {
const enrolled = this.enrolled;
// eslint-disable-next-line no-unused-vars
if (!enrolled.find(([i, v]) => i === id)) {
enrolled.push([id, variant]);
this.engine.setItem('experiments', JSON.stringify(enrolled));
}
}
get files() {
return this._files;
}
getFileById(id) {
try {
return JSON.parse(this.engine.getItem(id));
} catch (e) {
return null;
}
}
get(id) {
return this.engine.getItem(id);
}
remove(property) {
if (isFile(property)) {
this._files.splice(this._files.findIndex(f => f.id === property), 1);
}
this.engine.removeItem(property);
}
addFile(file) {
this._files.push(file);
this.engine.setItem(file.id, JSON.stringify(file));
}
}
export default new Storage();
+9
View File
@@ -0,0 +1,9 @@
const html = require('choo/html');
module.exports = function(state) {
const div = html`<div id="page-one"></div>`;
if (state.layout) {
return state.layout(state, div);
}
return div;
};
+31
View File
@@ -0,0 +1,31 @@
const html = require('choo/html');
const progress = require('./progress');
const { fadeOut } = require('../utils');
module.exports = function(state, emit) {
const div = html`
<div id="download" class="fadeIn">
<div id="download-progress">
<div id="dl-title" class="title">${state.translate(
'downloadFinish'
)}</div>
<div class="description"></div>
${progress(1)}
<div class="upload">
<div class="progress-text"></div>
</div>
</div>
<a class="send-new" data-state="completed" href="/" onclick=${sendNew}>${state.translate(
'sendYourFilesLink'
)}</a>
</div>
`;
async function sendNew(e) {
e.preventDefault();
await fadeOut('download');
emit('pushState', '/');
}
return div;
};
+28
View File
@@ -0,0 +1,28 @@
const html = require('choo/html');
const progress = require('./progress');
const { bytes } = require('../utils');
module.exports = function(state) {
const transfer = state.transfer;
const div = html`
<div id="download-progress" class="fadeIn">
<div id="dl-title" class="title">${state.translate(
'downloadingPageProgress',
{
filename: state.fileInfo.name,
size: bytes(state.fileInfo.size)
}
)}</div>
<div class="description">${state.translate('downloadingPageMessage')}</div>
${progress(transfer.progressRatio)}
<div class="upload">
<div class="progress-text">${state.translate(
transfer.msg,
transfer.sizes
)}</div>
</div>
</div>
`;
return div;
};
+10
View File
@@ -0,0 +1,10 @@
const html = require('choo/html');
const assets = require('../../common/assets');
module.exports = function(state) {
return html`
<div id="upload-error">
<div class="title">${state.translate('errorPageHeader')}</div>
<img id="upload-error-img" src="${assets.get('illustration_error.svg')}"/>
</div>`;
};
+84
View File
@@ -0,0 +1,84 @@
const html = require('choo/html');
const assets = require('../../common/assets');
function timeLeft(milliseconds) {
const minutes = Math.floor(milliseconds / 1000 / 60);
const hours = Math.floor(minutes / 60);
const seconds = Math.floor((milliseconds / 1000) % 60);
if (hours >= 1) {
return `${hours}h ${minutes % 60}m`;
} else if (hours === 0) {
return `${minutes}m ${seconds}s`;
}
return null;
}
module.exports = function(file, state, emit) {
const ttl = file.expiresAt - Date.now();
const remaining = timeLeft(ttl) || state.translate('linkExpiredAlt');
const row = html`
<tr id="${file.id}">
<td class="overflow-col" title="${file.name}">${file.name}</td>
<td class="center-col">
<img onclick=${copyClick} src="${assets.get(
'copy-16.svg'
)}" class="icon-copy" title="${state.translate('copyUrlHover')}">
<span class="text-copied" hidden="true">${state.translate(
'copiedUrl'
)}</span>
</td>
<td>${remaining}</td>
<td class="center-col">
<img onclick=${showPopup} src="${assets.get(
'close-16.svg'
)}" class="icon-delete" title="${state.translate('deleteButtonHover')}">
<div class="popup">
<div class="popuptext" onblur=${cancel} tabindex="-1">
<div class="popup-message">${state.translate('deletePopupText')}</div>
<div class="popup-action">
<span class="popup-no" onclick=${cancel}>${state.translate(
'deletePopupCancel'
)}</span>
<span class="popup-yes" onclick=${deleteFile}>${state.translate(
'deletePopupYes'
)}</span>
</div>
</div>
</div>
</td>
</tr>
`;
function copyClick(e) {
emit('copy', { url: file.url, location: 'upload-list' });
const icon = e.target;
const text = e.target.nextSibling;
icon.hidden = true;
text.hidden = false;
setTimeout(() => {
icon.hidden = false;
text.hidden = true;
}, 500);
}
function showPopup() {
const tr = document.getElementById(file.id);
const popup = tr.querySelector('.popuptext');
popup.classList.add('show');
popup.focus();
}
function cancel(e) {
e.stopPropagation();
const tr = document.getElementById(file.id);
const popup = tr.querySelector('.popuptext');
popup.classList.remove('show');
}
function deleteFile() {
emit('delete', { file, location: 'upload-list' });
emit('render');
}
return row;
};
+32
View File
@@ -0,0 +1,32 @@
const html = require('choo/html');
const file = require('./file');
module.exports = function(state, emit) {
let table = '';
if (state.storage.files.length) {
table = html`
<table id="uploaded-files">
<thead>
<tr>
<th id="uploaded-file">${state.translate('uploadedFile')}</th>
<th id="copy-file-list" class="center-col">${state.translate(
'copyFileList'
)}</th>
<th id="expiry-file-list">${state.translate('expiryFileList')}</th>
<th id="delete-file-list" class="center-col">${state.translate(
'deleteFileList'
)}</th>
</tr>
</thead>
<tbody>
${state.storage.files.map(f => file(f, state, emit))}
</tbody>
</table>
`;
}
return html`
<div id="file-list">
${table}
</div>
`;
};
+38
View File
@@ -0,0 +1,38 @@
const html = require('choo/html');
function replaceLinks(str, urls) {
let i = -1;
const s = str.replace(/<a>([^<]+)<\/a>/g, (m, v) => {
i++;
return `<a href="${urls[i]}">${v}</a>`;
});
return [`<div class="description">${s}</div>`];
}
module.exports = function(state) {
const div = html`
<div id="page-one">
<div id="legal">
<div class="title">${state.translate('legalHeader')}</div>
${html(
replaceLinks(state.translate('legalNoticeTestPilot'), [
'https://testpilot.firefox.com/terms',
'https://testpilot.firefox.com/privacy',
'https://testpilot.firefox.com/experiments/send'
])
)}
${html(
replaceLinks(state.translate('legalNoticeMozilla'), [
'https://www.mozilla.org/privacy/websites/',
'https://www.mozilla.org/about/legal/terms/mozilla/'
])
)}
</div>
</div>
`;
if (state.layout) {
return state.layout(state, div);
}
return div;
};
+25
View File
@@ -0,0 +1,25 @@
const html = require('choo/html');
const assets = require('../../common/assets');
module.exports = function(state) {
const div = html`
<div id="page-one">
<div id="download">
<div class="title">${state.translate('expiredPageHeader')}</div>
<div class="share-window">
<img src="${assets.get('illustration_expired.svg')}" id="expired-img">
</div>
<div class="expired-description">${state.translate(
'uploadPageExplainer'
)}</div>
<a class="send-new" href="/" data-state="notfound">${state.translate(
'sendYourFilesLink'
)}</a>
</div>
</div>`;
if (state.layout) {
return state.layout(state, div);
}
return div;
};
+70
View File
@@ -0,0 +1,70 @@
const html = require('choo/html');
const assets = require('../../common/assets');
const notFound = require('./notFound');
const { bytes } = require('../utils');
function getFileFromDOM() {
const el = document.getElementById('dl-file');
if (!el) {
return null;
}
const data = el.dataset;
return {
name: data.name,
size: parseInt(data.size, 10),
ttl: parseInt(data.ttl, 10)
};
}
module.exports = function(state, emit) {
state.fileInfo = state.fileInfo || getFileFromDOM();
if (!state.fileInfo) {
return notFound(state, emit);
}
state.fileInfo.id = state.params.id;
state.fileInfo.key = state.params.key;
const fileInfo = state.fileInfo;
const size = bytes(fileInfo.size);
const div = html`
<div id="page-one">
<div id="download">
<div id="download-page-one">
<div class="title">
<span id="dl-file"
data-name="${fileInfo.name}"
data-size="${fileInfo.size}"
data-ttl="${fileInfo.ttl}">${state.translate('downloadFileName', {
filename: fileInfo.name
})}</span>
<span id="dl-filesize">${' ' +
state.translate('downloadFileSize', { size })}</span>
</div>
<div class="description">${state.translate('downloadMessage')}</div>
<img
src="${assets.get('illustration_download.svg')}"
id="download-img"
alt="${state.translate('downloadAltText')}"/>
<div>
<button
id="download-btn"
class="btn"
title="${state.translate('downloadButtonLabel')}"
onclick=${download}>${state.translate(
'downloadButtonLabel'
)}</button>
</div>
</div>
<a class="send-new" href="/">${state.translate('sendYourFilesLink')}</a>
</div>
</div>
`;
function download(event) {
event.preventDefault();
emit('download', fileInfo);
}
if (state.layout) {
return state.layout(state, div);
}
return div;
};
+21
View File
@@ -0,0 +1,21 @@
const html = require('choo/html');
const radius = 73;
const oRadius = radius + 10;
const oDiameter = oRadius * 2;
const circumference = 2 * Math.PI * radius;
module.exports = function(progressRatio) {
const dashOffset = (1 - progressRatio) * circumference;
const percent = Math.floor(progressRatio * 100);
const div = html`
<div class="progress-bar">
<svg id="progress" width="${oDiameter}" height="${oDiameter}" viewPort="0 0 ${oDiameter} ${oDiameter}" version="1.1">
<circle r="${radius}" cx="${oRadius}" cy="${oRadius}" fill="transparent"/>
<circle id="bar" r="${radius}" cx="${oRadius}" cy="${oRadius}" fill="transparent" transform="rotate(-90 ${oRadius} ${oRadius})" stroke-dasharray="${circumference}" stroke-dashoffset="${dashOffset}"/>
<text class="percentage" text-anchor="middle" x="50%" y="98"><tspan class="percent-number">${percent}</tspan><tspan class="percent-sign">%</tspan></text>
</svg>
</div>
`;
return div;
};
+64
View File
@@ -0,0 +1,64 @@
const html = require('choo/html');
const assets = require('../../common/assets');
const notFound = require('./notFound');
const { allowedCopy, delay, fadeOut } = require('../utils');
module.exports = function(state, emit) {
const file = state.storage.getFileById(state.params.id);
if (!file) {
return notFound(state, emit);
}
const div = html`
<div id="share-link" class="fadeIn">
<div class="title">${state.translate('uploadSuccessTimingHeader')}</div>
<div id="share-window">
<div id="copy-text">${state.translate('copyUrlFormLabelWithName', {
filename: file.name
})}</div>
<div id="copy">
<input id="link" type="url" value="${file.url}" readonly="true"/>
<button id="copy-btn" class="btn" title="${state.translate(
'copyUrlFormButton'
)}" onclick=${copyLink}>${state.translate('copyUrlFormButton')}</button>
</div>
<button id="delete-file" class="btn" title="${state.translate(
'deleteFileButton'
)}" onclick=${deleteFile}>${state.translate('deleteFileButton')}</button>
<a class="send-new" data-state="completed" href="/" onclick=${sendNew}>${state.translate(
'sendAnotherFileLink'
)}</a>
</div>
</div>
`;
async function sendNew(e) {
e.preventDefault();
await fadeOut('share-link');
emit('pushState', '/');
}
async function copyLink() {
if (allowedCopy()) {
emit('copy', { url: file.url, location: 'success-screen' });
const input = document.getElementById('link');
input.disabled = true;
const copyBtn = document.getElementById('copy-btn');
copyBtn.disabled = true;
copyBtn.replaceChild(
html`<img src="${assets.get('check-16.svg')}" class="icon-check">`,
copyBtn.firstChild
);
await delay(2000);
input.disabled = false;
copyBtn.disabled = false;
copyBtn.textContent = state.translate('copyUrlFormButton');
}
}
async function deleteFile() {
emit('delete', { file, location: 'success-screen' });
await fadeOut('share-link');
emit('pushState', '/');
}
return div;
};
+50
View File
@@ -0,0 +1,50 @@
const html = require('choo/html');
const assets = require('../../common/assets');
module.exports = function(state) {
const msg =
state.params.reason === 'outdated'
? html`
<div id="unsupported-browser">
<div class="title">${state.translate('notSupportedHeader')}</div>
<div class="description">${state.translate(
'notSupportedOutdatedDetail'
)}</div>
<a id="update-firefox" href="https://support.mozilla.org/kb/update-firefox-latest-version">
<img src="${assets.get(
'firefox_logo-only.svg'
)}" class="firefox-logo" alt="Firefox"/>
<div class="unsupported-button-text">${state.translate(
'updateFirefox'
)}</div>
</a>
<div class="unsupported-description">${state.translate(
'uploadPageExplainer'
)}</div>
</div>`
: html`
<div id="unsupported-browser">
<div class="title">${state.translate('notSupportedHeader')}</div>
<div class="description">${state.translate('notSupportedDetail')}</div>
<div class="description"><a href="https://github.com/mozilla/send/blob/master/docs/faq.md#why-is-my-browser-not-supported">${state.translate(
'notSupportedLink'
)}</a></div>
<a id="dl-firefox" href="https://www.mozilla.org/firefox/new/?scene=2">
<img src="${assets.get(
'firefox_logo-only.svg'
)}" class="firefox-logo" alt="Firefox"/>
<div class="unsupported-button-text">Firefox<br>
<span>${state.translate('downloadFirefoxButtonSub')}</span>
</div>
</a>
<div class="unsupported-description">${state.translate(
'uploadPageExplainer'
)}</div>
</div>`;
const div = html`<div id="page-one">${msg}</div>`;
if (state.layout) {
return state.layout(state, div);
}
return div;
};
+38
View File
@@ -0,0 +1,38 @@
const html = require('choo/html');
const progress = require('./progress');
const { bytes } = require('../utils');
module.exports = function(state, emit) {
const transfer = state.transfer;
const div = html`
<div id="upload-progress" class="fadeIn">
<div class="title" id="upload-filename">${state.translate(
'uploadingPageProgress',
{
filename: transfer.file.name,
size: bytes(transfer.file.size)
}
)}</div>
<div class="description"></div>
${progress(transfer.progressRatio)}
<div class="upload">
<div class="progress-text">${state.translate(
transfer.msg,
transfer.sizes
)}</div>
<button id="cancel-upload" title="${state.translate(
'uploadingPageCancel'
)}" onclick=${cancel}>${state.translate('uploadingPageCancel')}</button>
</div>
</div>
`;
function cancel() {
const btn = document.getElementById('cancel-upload');
btn.disabled = true;
btn.textContent = state.translate('uploadCancelNotification');
emit('cancel');
}
return div;
};
+68
View File
@@ -0,0 +1,68 @@
const html = require('choo/html');
const assets = require('../../common/assets');
const fileList = require('./fileList');
const { fadeOut } = require('../utils');
module.exports = function(state, emit) {
const div = html`
<div id="page-one" class="fadeIn">
<div class="title">${state.translate('uploadPageHeader')}</div>
<div class="description">
<div>${state.translate('uploadPageExplainer')}</div>
<a href="https://testpilot.firefox.com/experiments/send" class="link">${state.translate(
'uploadPageLearnMore'
)}</a>
</div>
<div class="upload-window" ondragover=${dragover} ondragleave=${dragleave}>
<div id="upload-img"><img src="${assets.get(
'upload.svg'
)}" title="${state.translate('uploadSvgAlt')}"/></div>
<div id="upload-text">${state.translate('uploadPageDropMessage')}</div>
<span id="file-size-msg"><em>${state.translate(
'uploadPageSizeMessage'
)}</em></span>
<form method="post" action="upload" enctype="multipart/form-data">
<input id="file-upload" type="file" name="fileUploaded" onchange=${upload} onfocus=${onfocus} onblur=${onblur} />
<label for="file-upload" id="browse" class="btn browse" title="${state.translate(
'uploadPageBrowseButton1'
)}">${state.translate('uploadPageBrowseButton1')}</label>
</form>
</div>
${fileList(state, emit)}
</div>
`;
function dragover(event) {
const div = document.querySelector('.upload-window');
div.classList.add('ondrag');
}
function dragleave(event) {
const div = document.querySelector('.upload-window');
div.classList.remove('ondrag');
}
function onfocus(event) {
event.target.classList.add('has-focus');
}
function onblur(event) {
event.target.classList.remove('has-focus');
}
async function upload(event) {
event.preventDefault();
const target = event.target;
const file = target.files[0];
if (file.size === 0) {
return;
}
await fadeOut('page-one');
emit('upload', { file, type: 'click' });
}
if (state.layout) {
return state.layout(state, div);
}
return div;
};
+60 -41
View File
@@ -35,47 +35,39 @@ function notify(str) {
*/
}
function gcmCompliant() {
function loadShim(polyfill) {
return new Promise((resolve, reject) => {
const shim = document.createElement('script');
shim.src = polyfill;
shim.addEventListener('load', () => resolve(true));
shim.addEventListener('error', () => resolve(false));
document.head.appendChild(shim);
});
}
async function canHasSend(polyfill) {
try {
return window.crypto.subtle
.generateKey(
{
name: 'AES-GCM',
length: 128
},
true,
['encrypt', 'decrypt']
)
.then(key => {
return window.crypto.subtle
.encrypt(
{
name: 'AES-GCM',
iv: window.crypto.getRandomValues(new Uint8Array(12)),
additionalData: window.crypto.getRandomValues(new Uint8Array(6)),
tagLength: 128
},
key,
new ArrayBuffer(8)
)
.then(() => {
return Promise.resolve();
});
})
.catch(err => {
return loadShim();
});
const key = await window.crypto.subtle.generateKey(
{
name: 'AES-GCM',
length: 128
},
true,
['encrypt', 'decrypt']
);
await window.crypto.subtle.encrypt(
{
name: 'AES-GCM',
iv: window.crypto.getRandomValues(new Uint8Array(12)),
tagLength: 128
},
key,
new ArrayBuffer(8)
);
return true;
} catch (err) {
return loadShim();
}
function loadShim() {
return new Promise((resolve, reject) => {
const shim = document.createElement('script');
shim.src = '/cryptofill.js';
shim.addEventListener('load', resolve);
shim.addEventListener('error', reject);
document.head.appendChild(shim);
});
return loadShim(polyfill);
}
}
@@ -107,7 +99,8 @@ function copyToClipboard(str) {
const LOCALIZE_NUMBERS = !!(
typeof Intl === 'object' &&
Intl &&
typeof Intl.NumberFormat === 'function'
typeof Intl.NumberFormat === 'function' &&
typeof navigator === 'object'
);
const UNITS = ['B', 'kB', 'MB', 'GB'];
@@ -123,15 +116,41 @@ function bytes(num) {
return `${nStr}${UNITS[exponent]}`;
}
function percent(ratio) {
return LOCALIZE_NUMBERS
? ratio.toLocaleString(navigator.languages, { style: 'percent' })
: `${Math.floor(ratio * 100)}%`;
}
function allowedCopy() {
const support = !!document.queryCommandSupported;
return support ? document.queryCommandSupported('copy') : false;
}
function delay(delay = 100) {
return new Promise(resolve => setTimeout(resolve, delay));
}
function fadeOut(id) {
const classes = document.getElementById(id).classList;
classes.remove('fadeIn');
classes.add('fadeOut');
return delay(300);
}
const ONE_DAY_IN_MS = 86400000;
module.exports = {
fadeOut,
delay,
allowedCopy,
bytes,
percent,
copyToClipboard,
arrayToHex,
hexToArray,
notify,
gcmCompliant,
canHasSend,
isFile,
ONE_DAY_IN_MS
};

Before

Width:  |  Height:  |  Size: 257 B

After

Width:  |  Height:  |  Size: 257 B

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path fill="#4A4A4A" d="M9.414 8l5.293-5.293a1 1 0 0 0-1.414-1.414L8 6.586 2.707 1.293a1 1 0 0 0-1.414 1.414L6.586 8l-5.293 5.293a1 1 0 1 0 1.414 1.414L8 9.414l5.293 5.293a1 1 0 0 0 1.414-1.414z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 16 16"><path fill="#4A4A4A" d="M9.414 8l5.293-5.293a1 1 0 0 0-1.414-1.414L8 6.586 2.707 1.293a1 1 0 0 0-1.414 1.414L6.586 8l-5.293 5.293a1 1 0 1 0 1.414 1.414L8 9.414l5.293 5.293a1 1 0 0 0 1.414-1.414z"/></svg>

Before

Width:  |  Height:  |  Size: 286 B

After

Width:  |  Height:  |  Size: 287 B

Before

Width:  |  Height:  |  Size: 416 B

After

Width:  |  Height:  |  Size: 416 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Before

Width:  |  Height:  |  Size: 649 B

After

Width:  |  Height:  |  Size: 649 B

Before

Width:  |  Height:  |  Size: 239 KiB

After

Width:  |  Height:  |  Size: 239 KiB

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

+102 -27
View File
@@ -1,6 +1,6 @@
/*** index.html ***/
html {
background: url('resources/send_bg.svg');
background: url('./send_bg.svg');
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'segoe ui',
'helvetica neue', helvetica, ubuntu, roboto, noto, arial, sans-serif;
font-weight: 200;
@@ -22,6 +22,16 @@ body {
position: relative;
}
#progress circle {
stroke: #eee;
stroke-width: 0.75em;
}
#progress #bar {
transition: stroke-dashoffset 300ms linear;
stroke: #3b9dff;
}
.header {
align-items: flex-start;
box-sizing: border-box;
@@ -79,7 +89,7 @@ body {
.feedback {
background-color: #0297f8;
background-image: url('resources/feedback.svg');
background-image: url('./feedback.svg');
background-position: 2px 4px;
background-repeat: no-repeat;
background-size: 18px;
@@ -138,15 +148,49 @@ a {
text-decoration: none;
}
.btn {
font-weight: 500;
}
/** page-one **/
.fadeOut {
opacity: 0;
animation: fadeout 200ms linear;
}
@keyframes fadeout {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.fadeIn {
opacity: 1;
animation: fadein 200ms linear;
}
@keyframes fadein {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.title {
font-size: 33px;
line-height: 40px;
margin: 20px auto;
text-align: center;
max-width: 520px;
font-family: 'SF Pro Display', sans-serif;
font-family: 'SF Pro Text', sans-serif;
word-wrap: break-word;
}
@@ -161,7 +205,7 @@ a {
}
.upload-window {
border: 1px dashed rgba(0, 148, 251, 0.5);
border: 3px dashed rgba(0, 148, 251, 0.5);
margin: 0 auto;
height: 255px;
border-radius: 4px;
@@ -175,7 +219,7 @@ a {
}
.upload-window.ondrag {
border: 3px dashed rgba(0, 148, 251, 0.5);
border: 5px dashed rgba(0, 148, 251, 0.5);
margin: 0 auto;
height: 251px;
transform: scale(1.04);
@@ -200,28 +244,39 @@ a {
font-size: 22px;
color: #737373;
margin: 20px 0 10px;
font-family: 'SF Pro Display', sans-serif;
font-family: 'SF Pro Text', sans-serif;
}
#browse {
.browse {
background: #0297f8;
border-radius: 5px;
font-size: 15px;
font-size: 20px;
color: #fff;
width: 240px;
height: 44px;
min-width: 240px;
height: 60px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
padding: 0 10px;
}
#browse:hover {
.browse:hover {
background-color: #0287e8;
}
input[type="file"] {
display: none;
input[type='file'] {
opacity: 0;
overflow: hidden;
position: absolute;
z-index: -1;
}
input[type='file'].has-focus + #browse,
input[type='file']:focus + #browse {
background-color: #0287e8;
outline: 1px dotted #000;
outline: -webkit-focus-ring-color auto 5px;
}
#file-size-msg {
@@ -284,17 +339,32 @@ tbody {
width: 12%;
}
.overflow-col {
text-overflow: ellipsis;
max-width: 0;
overflow: hidden;
white-space: nowrap;
}
.center-col {
text-align: center;
}
.icon-delete,
.icon-copy,
.icon-check {
cursor: pointer;
}
.icon-copy[disabled="disabled"] {
.icon-copy[disabled='disabled'] {
pointer-events: none;
opacity: 0.3;
}
.text-copied {
color: #0a8dff;
}
/* Popup container */
.popup {
position: absolute;
@@ -325,7 +395,7 @@ tbody {
/* Popup arrow */
.popup .popuptext::after {
content: "";
content: '';
position: absolute;
bottom: -11px;
left: 20px;
@@ -412,12 +482,8 @@ tbody {
}
.percentage {
position: absolute;
letter-spacing: -0.78px;
font-family: 'Segoe UI', 'SF Pro Text', sans-serif;
top: 53px;
left: 50%;
transform: translateX(-50%);
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
@@ -430,7 +496,8 @@ tbody {
.percent-sign {
font-size: 28.8px;
color: rgb(104, 104, 104);
stroke: none;
fill: #686868;
}
.upload {
@@ -452,10 +519,18 @@ tbody {
#cancel-upload {
color: #d70022;
background: #fff;
font-size: 15px;
border: 0;
cursor: pointer;
text-decoration: underline;
}
#cancel-upload:disabled {
text-decoration: none;
cursor: auto;
}
/** share-link **/
#share-window {
margin: 0 auto;
@@ -463,6 +538,8 @@ tbody {
justify-content: center;
align-items: center;
flex-direction: column;
width: 100%;
max-width: 640px;
}
#share-window-r > div {
@@ -473,7 +550,7 @@ tbody {
#copy {
display: flex;
flex-wrap: nowrap;
width: 640px;
width: 100%;
}
#copy-text {
@@ -490,9 +567,9 @@ tbody {
height: 56px;
border: 1px solid #0297f8;
border-radius: 6px 0 0 6px;
font-size: 24px;
font-size: 20px;
color: #737373;
font-family: 'SF Pro Display', sans-serif;
font-family: 'SF Pro Text', sans-serif;
letter-spacing: 0;
line-height: 23px;
font-weight: 300;
@@ -527,7 +604,6 @@ tbody {
background: #05a700;
border: 1px solid #05a700;
cursor: auto;
opacity: 0.3;
}
#delete-file {
@@ -604,7 +680,7 @@ tbody {
#update-firefox {
margin-bottom: 181px;
height: 80px;
background: #12bc00;
background: #98e02b;
border-radius: 3px;
cursor: pointer;
border: 0;
@@ -644,7 +720,6 @@ tbody {
background: #0297f8;
border: 1px solid #0297f8;
border-radius: 5px;
font-weight: 300;
cursor: pointer;
}
@@ -713,7 +788,7 @@ tbody {
}
.legal-links {
width: 81vw;
max-width: 81vw;
display: flex;
align-items: center;
flex-direction: row;

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

+1
View File
@@ -0,0 +1 @@
<svg width="30" height="27" viewBox="0 0 30 27" xmlns="http://www.w3.org/2000/svg"><title>send logo</title><g stroke="#3E3D40" fill="none" fill-rule="evenodd" transform="translate(-0.231,0.11948695)"><path d="M22.364 19.989l-2.153-2.103a2.046 2.046 0 0 0-2.665-.151l3.402 3.323a.531.531 0 0 1 0 .766l-2.466 2.408a.563.563 0 0 1-.784 0l-3.398-3.32a1.932 1.932 0 0 0 .188 2.564l2.153 2.103c.788.77 2.066.77 2.855 0l2.868-2.802a1.94 1.94 0 0 0 0-2.788M8.77 14.745a.534.534 0 0 0 0 .766l3.399 3.32a2.05 2.05 0 0 1-2.625-.184l-2.153-2.102a1.94 1.94 0 0 1 0-2.79l2.869-2.801a2.052 2.052 0 0 1 2.854 0l2.153 2.103c.73.713.775 1.83.154 2.603l-3.401-3.323a.565.565 0 0 0-.784 0L8.77 14.745zm9.464 5.682a.777.777 0 0 1 0 1.118.822.822 0 0 1-1.144 0l-5.6-5.47a.777.777 0 0 1 0-1.118.822.822 0 0 1 1.144 0l5.6 5.47z" stroke-width=".618" fill="#3E3D40"/><path d="M6.065 20.606c-2.913-1.586-3.988-3.656-3.988-6.468 0-2.81 2.265-6.425 5.786-6.289.1.004.55-.006.649 0 .895-3.27 2.508-6.353 6.898-6.353 4.557 0 7.336 3.716 6.75 7.785.08-.005 1.232.17 1.31.186 3.096.644 4.915 3.275 4.915 5.18 0 1.905-.107 3.029-2.023 4.947" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Before

Width:  |  Height:  |  Size: 873 B

After

Width:  |  Height:  |  Size: 873 B

Before

Width:  |  Height:  |  Size: 336 B

After

Width:  |  Height:  |  Size: 336 B

+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square70x70logo src=“favicon-76.png”/>
<square150x150logo src="favicon-228.png"/>
<TileColor>#0297F8</TileColor>
</tile>
</msapplication>
</browserconfig>
+5
View File
@@ -0,0 +1,5 @@
last 2 chrome versions
last 2 firefox versions
firefox esr
ie >= 9
safari >= 9
+38
View File
@@ -0,0 +1,38 @@
const { MessageContext } = require('fluent');
function toJSON(map) {
return JSON.stringify(Array.from(map));
}
module.exports = function(source) {
const localeExp = this.options.locale || /([^/]+)\/[^/]+\.ftl$/;
const result = localeExp.exec(this.resourcePath);
const locale = result && result[1];
// pre-parse the ftl
const context = new MessageContext(locale);
context.addMessages(source);
if (!locale) {
throw new Error(`couldn't find locale in: ${this.resourcePath}`);
}
return `
module.exports = \`
if (typeof window === 'undefined') {
var fluent = require('fluent');
}
var ctx = new fluent.MessageContext('${locale}', {useIsolating: false});
ctx._messages = new Map(${toJSON(context._messages)});
function translate(id, data) {
var msg = ctx.getMessage(id);
if (typeof(msg) !== 'string' && !msg.val && msg.attrs) {
msg = msg.attrs.title || msg.attrs.alt
}
return ctx.format(msg, data);
}
if (typeof window === 'undefined') {
module.exports = translate;
}
else {
window.translate = translate;
}
\``;
};
+19
View File
@@ -0,0 +1,19 @@
const fs = require('fs');
const path = require('path');
function kv(f) {
return `"${f}": require('../assets/${f}')`;
}
module.exports = function() {
const files = fs.readdirSync(path.join(__dirname, '..', 'assets'));
const code = `module.exports = {
"package.json": require('../package.json'),
${files.map(kv).join(',\n')}
};`;
return {
code,
dependencies: files.map(f => require.resolve('../assets/' + f)),
cacheable: false
};
};
+22
View File
@@ -0,0 +1,22 @@
const fs = require('fs');
const path = require('path');
function kv(d) {
return `"${d}": require('../public/locales/${d}/send.ftl')`;
}
module.exports = function() {
const dirs = fs.readdirSync(path.join(__dirname, '..', 'public', 'locales'));
const code = `
module.exports = {
translate: function (id, data) { return window.translate(id, data) },
${dirs.map(kv).join(',\n')}
};`;
return {
code,
dependencies: dirs.map(d =>
require.resolve(`../public/locales/${d}/send.ftl`)
),
cacheable: false
};
};
+11
View File
@@ -0,0 +1,11 @@
const commit = require('git-rev-sync').short();
module.exports = function(source) {
const pkg = JSON.parse(source);
const version = {
commit,
source: pkg.homepage,
version: process.env.CIRCLE_TAG || `v${pkg.version}`
};
return `module.exports = '${JSON.stringify(version)}'`;
};
+1 -3
View File
@@ -16,7 +16,6 @@ deployment:
latest:
branch: master
commands:
- npm run build
- docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
- docker build -t mozilla/send:latest .
- docker push mozilla/send:latest
@@ -24,14 +23,13 @@ deployment:
tag: /.*/
owner: mozilla
commands:
- npm run build
- docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
- docker build -t mozilla/send:$CIRCLE_TAG .
- docker push mozilla/send:$CIRCLE_TAG
test:
override:
- npm run build:version
- npm run build
- npm run lint
- npm test
- nsp check
+32
View File
@@ -0,0 +1,32 @@
const genmap = require('../build/generate_asset_map');
const isServer = typeof genmap === 'function';
const prefix = isServer ? '/' : '';
let manifest = {};
try {
//eslint-disable-next-line node/no-missing-require
manifest = require('../dist/manifest.json');
} catch (e) {
// use middleware
}
const assets = isServer ? manifest : genmap;
function getAsset(name) {
return prefix + assets[name];
}
const instance = {
get: getAsset,
setMiddleware: function(middleware) {
if (middleware) {
instance.get = function getAssetWithMiddleware(name) {
const f = middleware.fileSystem.readFileSync(
middleware.getFilenameFromUrl('/manifest.json')
);
return prefix + JSON.parse(f)[name];
};
}
}
};
module.exports = instance;
+51
View File
@@ -0,0 +1,51 @@
const gen = require('../build/generate_l10n_map');
const isServer = typeof gen === 'function';
const prefix = isServer ? '/' : '';
let manifest = {};
try {
//eslint-disable-next-line node/no-missing-require
manifest = require('../dist/manifest.json');
} catch (e) {
// use middleware
}
const locales = isServer ? manifest : gen;
function getLocale(name) {
return prefix + locales[`public/locales/${name}/send.ftl`];
}
function serverTranslator(name) {
return require(`../dist/${locales[`public/locales/${name}/send.ftl`]}`);
}
function browserTranslator() {
return locales.translate;
}
const translator = isServer ? serverTranslator : browserTranslator;
const instance = {
get: getLocale,
getTranslator: translator,
setMiddleware: function(middleware) {
if (middleware) {
const _eval = require('require-from-string');
instance.get = function getLocaleWithMiddleware(name) {
const f = middleware.fileSystem.readFileSync(
middleware.getFilenameFromUrl('/manifest.json')
);
return prefix + JSON.parse(f)[`public/locales/${name}/send.ftl`];
};
instance.getTranslator = function(name) {
const f = middleware.fileSystem.readFileSync(
middleware.getFilenameFromUrl(instance.get(name))
);
return _eval(f.toString());
};
}
}
};
module.exports = instance;
+1
View File
@@ -8,5 +8,6 @@ services:
- "1443:1443"
environment:
- REDIS_HOST=redis
- NODE_ENV=production
redis:
image: redis:alpine
+11
View File
@@ -1,3 +1,14 @@
## Setup
Before building the Docker image, you must build the production assets:
```sh
npm run build
```
Then you can run either `docker build` or `docker-compose up`.
## Environment variables:
| Name | Description
-3
View File
@@ -1,3 +0,0 @@
env:
browser: true
jquery: true
-22
View File
@@ -1,22 +0,0 @@
const Raven = require('raven-js');
const { unsupported } = require('./metrics');
if (navigator.doNotTrack !== '1' && window.RAVEN_CONFIG) {
Raven.config(window.SENTRY_ID, window.RAVEN_CONFIG).install();
}
const ua = navigator.userAgent.toLowerCase();
if (
ua.indexOf('firefox') > -1 &&
parseInt(ua.match(/firefox\/*([^\n\r]*)\./)[1], 10) <= 49
) {
unsupported({
err: new Error('Firefox is outdated.')
}).then(() => {
location.replace('/unsupported/outdated');
});
}
module.exports = {
Raven
};
-118
View File
@@ -1,118 +0,0 @@
const { Raven } = require('./common');
const FileReceiver = require('./fileReceiver');
const { bytes, notify, gcmCompliant } = require('./utils');
const Storage = require('./storage');
const storage = new Storage(localStorage);
const links = require('./links');
const metrics = require('./metrics');
const progress = require('./progress');
const $ = require('jquery');
function onUnload(size) {
metrics.cancelledDownload({ size });
}
function download() {
const $downloadBtn = $('#download-btn');
const $title = $('.title');
const $file = $('#dl-file');
const size = Number($file.attr('data-size'));
const ttl = Number($file.attr('data-ttl'));
const unloadHandler = onUnload.bind(null, size);
const startTime = Date.now();
const fileReceiver = new FileReceiver();
$downloadBtn.attr('disabled', 'disabled');
$('#download-page-one').attr('hidden', true);
$('#download-progress').removeAttr('hidden');
metrics.startedDownload({ size, ttl });
links.setOpenInNewTab(true);
window.addEventListener('unload', unloadHandler);
fileReceiver.on('progress', data => {
progress.setProgress({ complete: data[0], total: data[1] });
});
let downloadEnd;
fileReceiver.on('decrypting', () => {
downloadEnd = Date.now();
window.removeEventListener('unload', unloadHandler);
fileReceiver.removeAllListeners('progress');
document.l10n.formatValue('decryptingFile').then(progress.setText);
});
fileReceiver
.download()
.catch(err => {
metrics.stoppedDownload({ size, err });
if (err.message === 'notfound') {
location.reload();
} else {
document.l10n.formatValue('errorPageHeader').then(translated => {
$title.text(translated);
});
$downloadBtn.attr('hidden', true);
$('#expired-img').removeAttr('hidden');
}
throw err;
})
.then(([decrypted, fname]) => {
const endTime = Date.now();
const time = endTime - startTime;
const downloadTime = endTime - downloadEnd;
const speed = size / (downloadTime / 1000);
storage.totalDownloads += 1;
metrics.completedDownload({ size, time, speed });
progress.setText(' ');
document.l10n
.formatValues('downloadNotification', 'downloadFinish')
.then(translated => {
notify(translated[0]);
$title.text(translated[1]);
});
const dataView = new DataView(decrypted);
const blob = new Blob([dataView]);
const downloadUrl = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = downloadUrl;
if (window.navigator.msSaveBlob) {
// if we are in microsoft edge or IE
window.navigator.msSaveBlob(blob, fname);
return;
}
a.download = fname;
document.body.appendChild(a);
a.click();
})
.catch(err => {
Raven.captureException(err);
return Promise.reject(err);
})
.then(() => links.setOpenInNewTab(false));
}
$(() => {
const $file = $('#dl-file');
const filename = $file.attr('data-filename');
const b = Number($file.attr('data-size'));
const size = bytes(b);
document.l10n
.formatValue('downloadFileSize', { size })
.then(str => $('#dl-filesize').text(str));
document.l10n
.formatValue('downloadingPageProgress', { filename, size })
.then(str => $('#dl-title').text(str));
gcmCompliant()
.then(() => {
$('#download-btn').on('click', download);
})
.catch(err => {
metrics.unsupported({ err }).then(() => {
location.replace('/unsupported/gcm');
});
});
});
-85
View File
@@ -1,85 +0,0 @@
const EventEmitter = require('events');
const { hexToArray } = require('./utils');
class FileReceiver extends EventEmitter {
constructor() {
super();
}
download() {
return window.crypto.subtle
.importKey(
'jwk',
{
kty: 'oct',
k: location.hash.slice(1),
alg: 'A128GCM',
ext: true
},
{
name: 'AES-GCM'
},
true,
['encrypt', 'decrypt']
)
.then(key => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onprogress = event => {
if (event.lengthComputable && event.target.status !== 404) {
this.emit('progress', [event.loaded, event.total]);
}
};
xhr.onload = function(event) {
if (xhr.status === 404) {
reject(new Error('notfound'));
return;
}
const blob = new Blob([this.response]);
const fileReader = new FileReader();
fileReader.onload = function() {
const meta = JSON.parse(xhr.getResponseHeader('X-File-Metadata'));
resolve([
{
data: this.result,
filename: meta.filename,
iv: meta.id
},
key
]);
};
fileReader.readAsArrayBuffer(blob);
};
xhr.open('get', '/assets' + location.pathname.slice(0, -1), true);
xhr.responseType = 'blob';
xhr.send();
});
})
.then(([fdata, key]) => {
this.emit('decrypting');
return Promise.all([
window.crypto.subtle
.decrypt(
{
name: 'AES-GCM',
iv: hexToArray(fdata.iv),
tagLength: 128
},
key,
fdata.data
)
.then(decrypted => {
return Promise.resolve(decrypted);
}),
decodeURIComponent(fdata.filename)
]);
});
}
}
module.exports = FileReceiver;
-120
View File
@@ -1,120 +0,0 @@
const EventEmitter = require('events');
const { arrayToHex } = require('./utils');
class FileSender extends EventEmitter {
constructor(file) {
super();
this.file = file;
this.iv = window.crypto.getRandomValues(new Uint8Array(12));
this.uploadXHR = new XMLHttpRequest();
}
static delete(fileId, token) {
return new Promise((resolve, reject) => {
if (!fileId || !token) {
return reject();
}
const xhr = new XMLHttpRequest();
xhr.open('post', '/delete/' + fileId, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onreadystatechange = () => {
if (xhr.readyState === XMLHttpRequest.DONE) {
resolve();
}
};
xhr.send(JSON.stringify({ delete_token: token }));
});
}
cancel() {
this.uploadXHR.abort();
}
upload() {
const self = this;
self.emit('loading');
return Promise.all([
window.crypto.subtle.generateKey(
{
name: 'AES-GCM',
length: 128
},
true,
['encrypt', 'decrypt']
),
new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsArrayBuffer(this.file);
reader.onload = function(event) {
const plaintext = new Uint8Array(this.result);
resolve(plaintext);
};
reader.onerror = function(err) {
reject(err);
};
})
])
.then(([secretKey, plaintext]) => {
self.emit('encrypting');
return Promise.all([
window.crypto.subtle.encrypt(
{
name: 'AES-GCM',
iv: this.iv,
tagLength: 128
},
secretKey,
plaintext
),
window.crypto.subtle.exportKey('jwk', secretKey)
]);
})
.then(([encrypted, keydata]) => {
return new Promise((resolve, reject) => {
const file = this.file;
const fileId = arrayToHex(this.iv);
const dataView = new DataView(encrypted);
const blob = new Blob([dataView], { type: file.type });
const fd = new FormData();
fd.append('data', blob, file.name);
const xhr = self.uploadXHR;
xhr.upload.addEventListener('progress', e => {
if (e.lengthComputable) {
self.emit('progress', [e.loaded, e.total]);
}
});
xhr.onreadystatechange = () => {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
const responseObj = JSON.parse(xhr.responseText);
return resolve({
url: responseObj.url,
fileId: responseObj.id,
secretKey: keydata.k,
deleteToken: responseObj.delete
});
}
reject(xhr.status);
}
};
xhr.open('post', '/upload', true);
xhr.setRequestHeader(
'X-File-Metadata',
JSON.stringify({
id: fileId,
filename: encodeURIComponent(file.name)
})
);
xhr.send(fd);
});
});
}
}
module.exports = FileSender;
-23
View File
@@ -1,23 +0,0 @@
let links = [];
document.addEventListener('DOMContentLoaded', function() {
links = Array.from(document.querySelectorAll('a:not([target])'));
});
function setOpenInNewTab(bool) {
if (bool === false) {
links.forEach(l => {
l.removeAttribute('target');
l.removeAttribute('rel');
});
} else {
links.forEach(l => {
l.setAttribute('target', '_blank');
l.setAttribute('rel', 'noopener noreferrer');
});
}
}
module.exports = {
setOpenInNewTab
};
-41
View File
@@ -1,41 +0,0 @@
const { bytes } = require('./utils');
const $ = require('jquery');
require('jquery-circle-progress');
let $progress = null;
let $percent = null;
let $text = null;
document.addEventListener('DOMContentLoaded', function() {
$percent = $('.percent-number');
$text = $('.progress-text');
$progress = $('.progress-bar');
$progress.circleProgress({
value: 0.0,
startAngle: -Math.PI / 2,
fill: '#3B9DFF',
size: 158,
animation: { duration: 300 }
});
});
function setProgress(params) {
const percent = params.complete / params.total;
$progress.circleProgress('value', percent);
$percent.text(`${Math.floor(percent * 100)}`);
document.l10n
.formatValue('fileSizeProgress', {
partialSize: bytes(params.complete),
totalSize: bytes(params.total)
})
.then(setText);
}
function setText(str) {
$text.text(str);
}
module.exports = {
setProgress,
setText
};
-75
View File
@@ -1,75 +0,0 @@
const { isFile } = require('./utils');
class Storage {
constructor(engine) {
this.engine = engine;
}
get totalDownloads() {
return Number(this.engine.getItem('totalDownloads'));
}
set totalDownloads(n) {
this.engine.setItem('totalDownloads', n);
}
get totalUploads() {
return Number(this.engine.getItem('totalUploads'));
}
set totalUploads(n) {
this.engine.setItem('totalUploads', n);
}
get referrer() {
return this.engine.getItem('referrer');
}
set referrer(str) {
this.engine.setItem('referrer', str);
}
get files() {
const fs = [];
for (let i = 0; i < this.engine.length; i++) {
const k = this.engine.key(i);
if (isFile(k)) {
try {
fs.push(JSON.parse(this.engine.getItem(k)));
} catch (err) {
// obviously you're not a golfer
this.engine.removeItem(k);
}
}
}
return fs.sort((file1, file2) => {
const creationDate1 = new Date(file1.creationDate);
const creationDate2 = new Date(file2.creationDate);
return creationDate1 - creationDate2;
});
}
get numFiles() {
let length = 0;
for (let i = 0; i < this.engine.length; i++) {
const k = this.engine.key(i);
if (isFile(k)) {
length += 1;
}
}
return length;
}
getFileById(id) {
return this.engine.getItem(id);
}
has(property) {
return this.engine.hasOwnProperty(property);
}
remove(property) {
this.engine.removeItem(property);
}
addFile(id, file) {
this.engine.setItem(id, JSON.stringify(file));
}
}
module.exports = Storage;
-476
View File
@@ -1,476 +0,0 @@
/* global MAXFILESIZE EXPIRE_SECONDS */
const { Raven } = require('./common');
const FileSender = require('./fileSender');
const {
bytes,
copyToClipboard,
notify,
gcmCompliant,
ONE_DAY_IN_MS
} = require('./utils');
const Storage = require('./storage');
const storage = new Storage(localStorage);
const metrics = require('./metrics');
const progress = require('./progress');
const $ = require('jquery');
const allowedCopy = () => {
const support = !!document.queryCommandSupported;
return support ? document.queryCommandSupported('copy') : false;
};
$(() => {
gcmCompliant()
.then(function() {
const $pageOne = $('#page-one');
const $copyBtn = $('#copy-btn');
const $link = $('#link');
const $uploadWindow = $('.upload-window');
const $uploadError = $('#upload-error');
const $uploadProgress = $('#upload-progress');
const $fileList = $('#file-list');
$pageOne.removeAttr('hidden');
$('#file-upload').on('change', onUpload);
$(document.body).on('dragover', allowDrop).on('drop', onUpload);
// reset copy button
$copyBtn.attr({
disabled: !allowedCopy(),
'data-l10n-id': 'copyUrlFormButton'
});
$link.attr('disabled', false);
const toggleHeader = () => {
//hide table header if empty list
if (document.querySelector('tbody').childNodes.length === 1) {
$fileList.attr('hidden', true);
} else {
$fileList.removeAttr('hidden');
}
};
const files = storage.files;
if (files.length === 0) {
toggleHeader();
} else {
// eslint-disable-next-line prefer-const
for (let index in files) {
const id = files[index].fileId;
//check if file still exists before adding to list
checkExistence(id, files[index], true);
}
}
// copy link to clipboard
$copyBtn.on('click', () => {
if (allowedCopy() && copyToClipboard($link.attr('value'))) {
metrics.copiedLink({ location: 'success-screen' });
//disable button for 3s
$copyBtn.attr('disabled', true);
$link.attr('disabled', true);
$copyBtn.html(
'<img src="/resources/check-16.svg" class="icon-check"></img>'
);
setTimeout(() => {
$copyBtn.attr({
disabled: false,
'data-l10n-id': 'copyUrlFormButton'
});
$link.attr('disabled', false);
}, 3000);
}
});
$uploadWindow
.on('dragover', () => {
$uploadWindow.addClass('ondrag');
})
.on('dragleave', () => {
$uploadWindow.removeClass('ondrag');
});
// on file upload by browse or drag & drop
function onUpload(event) {
event.preventDefault();
const clickOrDrop = event.type === 'drop' ? 'drop' : 'click';
// don't allow upload if not on upload page
if ($pageOne.attr('hidden')) {
return;
}
storage.totalUploads += 1;
let file = '';
if (clickOrDrop === 'drop') {
if (!event.originalEvent.dataTransfer.files[0]) {
$uploadWindow.removeClass('ondrag');
return;
}
if (
event.originalEvent.dataTransfer.files.length > 1 ||
event.originalEvent.dataTransfer.files[0].size === 0
) {
$uploadWindow.removeClass('ondrag');
document.l10n
.formatValue('uploadPageMultipleFilesAlert')
.then(str => {
alert(str);
});
return;
}
file = event.originalEvent.dataTransfer.files[0];
} else {
file = event.target.files[0];
}
if (file.size > MAXFILESIZE) {
return document.l10n
.formatValue('fileTooBig', { size: bytes(MAXFILESIZE) })
.then(alert);
}
$pageOne.attr('hidden', true);
$uploadError.attr('hidden', true);
$uploadProgress.removeAttr('hidden');
document.l10n
.formatValue('uploadingPageProgress', {
size: bytes(file.size),
filename: file.name
})
.then(str => {
$('#upload-filename').text(str);
});
document.l10n.formatValue('importingFile').then(progress.setText);
//don't allow drag and drop when not on page-one
$(document.body).off('drop', onUpload);
const fileSender = new FileSender(file);
$('#cancel-upload').on('click', () => {
fileSender.cancel();
metrics.cancelledUpload({
size: file.size,
type: clickOrDrop
});
location.reload();
});
let uploadStart;
fileSender.on('progress', data => {
uploadStart = uploadStart || Date.now();
progress.setProgress({
complete: data[0],
total: data[1]
});
});
fileSender.on('encrypting', () => {
document.l10n.formatValue('encryptingFile').then(progress.setText);
});
let t;
const startTime = Date.now();
metrics.startedUpload({
size: file.size,
type: clickOrDrop
});
// For large files we need to give the ui a tick to breathe and update
// before we kick off the FileSender
setTimeout(() => {
fileSender
.upload()
.then(info => {
const endTime = Date.now();
const time = endTime - startTime;
const uploadTime = endTime - uploadStart;
const speed = file.size / (uploadTime / 1000);
const expiration = EXPIRE_SECONDS * 1000;
metrics.completedUpload({
size: file.size,
time,
speed,
type: clickOrDrop
});
const fileData = {
name: file.name,
size: file.size,
fileId: info.fileId,
url: info.url,
secretKey: info.secretKey,
deleteToken: info.deleteToken,
creationDate: new Date(),
expiry: expiration,
totalTime: time,
typeOfUpload: clickOrDrop,
uploadSpeed: speed
};
$('#delete-file').on('click', () => {
FileSender.delete(
fileData.fileId,
fileData.deleteToken
).then(() => {
const ttl =
ONE_DAY_IN_MS -
(Date.now() - fileData.creationDate.getTime());
metrics
.deletedUpload({
size: fileData.size,
time: fileData.totalTime,
speed: fileData.uploadSpeed,
type: fileData.typeOfUpload,
location: 'success-screen',
ttl
})
.then(() => {
storage.remove(fileData.fileId);
location.reload();
});
});
});
storage.addFile(info.fileId, fileData);
$pageOne.attr('hidden', true);
$uploadProgress.attr('hidden', true);
$uploadError.attr('hidden', true);
$('#share-link').removeAttr('hidden');
populateFileList(fileData);
document.l10n.formatValue('notifyUploadDone').then(str => {
notify(str);
});
})
.catch(err => {
// err is 0 when coming from a cancel upload event
if (err === 0) {
return;
}
// only show error page when the error is anything other than user cancelling the upload
Raven.captureException(err);
$pageOne.attr('hidden', true);
$uploadProgress.attr('hidden', true);
$uploadError.removeAttr('hidden');
window.clearTimeout(t);
metrics.stoppedUpload({
size: file.size,
type: clickOrDrop,
err
});
});
}, 10);
}
function allowDrop(ev) {
ev.preventDefault();
}
function checkExistence(id, file, populate) {
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState === XMLHttpRequest.DONE) {
if (xhr.status === 200) {
if (populate) {
populateFileList(file);
}
} else if (xhr.status === 404) {
storage.remove(id);
if (storage.numFiles === 0) {
toggleHeader();
}
}
}
};
xhr.open('get', '/exists/' + id, true);
xhr.send();
}
//update file table with current files in storage
const populateFileList = file => {
const row = document.createElement('tr');
const name = document.createElement('td');
const link = document.createElement('td');
const $copyIcon = $('<img>', {
src: '/resources/copy-16.svg',
class: 'icon-copy',
'data-l10n-id': 'copyUrlHover',
disabled: !allowedCopy()
});
const expiry = document.createElement('td');
const del = document.createElement('td');
const $delIcon = $('<img>', {
src: '/resources/close-16.svg',
class: 'icon-delete',
'data-l10n-id': 'deleteButtonHover'
});
const popupDiv = document.createElement('div');
const $popupText = $('<div>', { class: 'popuptext' });
const cellText = document.createTextNode(file.name);
const url = file.url.trim() + `#${file.secretKey}`.trim();
$link.attr('value', url);
$('#copy-text')
.attr('data-l10n-args', JSON.stringify({ filename: file.name }))
.attr('data-l10n-id', 'copyUrlFormLabelWithName');
$popupText.attr('tabindex', '-1');
name.appendChild(cellText);
// create delete button
const delSpan = document.createElement('span');
$(delSpan)
.addClass('icon-cancel-1')
.attr('data-l10n-id', 'deleteButtonHover');
del.appendChild(delSpan);
const linkSpan = document.createElement('span');
$(linkSpan).addClass('icon-docs').attr('data-l10n-id', 'copyUrlHover');
link.appendChild(linkSpan);
link.style.color = '#0A8DFF';
//copy link to clipboard when icon clicked
$copyIcon.on('click', () => {
// record copied event from upload list
metrics.copiedLink({ location: 'upload-list' });
copyToClipboard(url);
document.l10n.formatValue('copiedUrl').then(translated => {
link.innerHTML = translated;
});
setTimeout(() => {
const linkImg = document.createElement('img');
$(linkImg)
.addClass('icon-copy')
.attr('data-l10n-id', 'copyUrlHover')
.attr('src', '/resources/copy-16.svg');
$(link).html(linkImg);
}, 500);
});
file.creationDate = new Date(file.creationDate);
const future = new Date();
future.setTime(file.creationDate.getTime() + file.expiry);
let countdown = 0;
countdown = future.getTime() - Date.now();
let minutes = Math.floor(countdown / 1000 / 60);
let hours = Math.floor(minutes / 60);
let seconds = Math.floor(countdown / 1000 % 60);
const poll = () => {
countdown = future.getTime() - Date.now();
minutes = Math.floor(countdown / 1000 / 60);
hours = Math.floor(minutes / 60);
seconds = Math.floor(countdown / 1000 % 60);
let t;
if (hours >= 1) {
expiry.innerHTML = hours + 'h ' + minutes % 60 + 'm';
t = setTimeout(() => {
poll();
}, 60000);
} else if (hours === 0) {
expiry.innerHTML = minutes + 'm ' + seconds + 's';
t = window.setTimeout(() => {
poll();
}, 1000);
}
//remove from list when expired
if (countdown <= 0) {
storage.remove(file.fileId);
$(expiry).parents('tr').remove();
window.clearTimeout(t);
toggleHeader();
}
};
poll();
// create popup
popupDiv.classList.add('popup');
const $popupMessage = $('<div>', { class: 'popup-message' });
$popupMessage.attr('data-l10n-id', 'deletePopupText');
const $popupAction = $('<div>', { class: 'popup-action' });
const $popupNvmSpan = $('<span>', { class: 'popup-no' });
$popupNvmSpan.attr('data-l10n-id', 'deletePopupCancel');
const $popupDelSpan = $('<span>', { class: 'popup-yes' });
$popupDelSpan.attr('data-l10n-id', 'deletePopupYes');
$popupText.html([$popupMessage, $popupAction]);
$popupAction.html([$popupNvmSpan, $popupDelSpan]);
// add data cells to table row
row.appendChild(name);
$(link).append($copyIcon);
row.appendChild(link);
row.appendChild(expiry);
$(popupDiv).append($popupText);
$(del).append($delIcon);
del.appendChild(popupDiv);
row.appendChild(del);
$('tbody').append(row); //add row to table
// delete file
$popupText.find('.popup-yes').on('click', e => {
FileSender.delete(file.fileId, file.deleteToken).then(() => {
$(e.target).parents('tr').remove();
const ttl =
ONE_DAY_IN_MS - (Date.now() - file.creationDate.getTime());
metrics
.deletedUpload({
size: file.size,
time: file.totalTime,
speed: file.uploadSpeed,
type: file.typeOfUpload,
location: 'upload-list',
ttl
})
.then(() => {
storage.remove(file.fileId);
});
toggleHeader();
});
});
// show popup
$delIcon.on('click', () => {
$popupText.addClass('show').focus();
});
// hide popup
$popupText.find('.popup-no').on('click', e => {
e.stopPropagation();
$popupText.removeClass('show');
});
$popupText.on('click', e => {
e.stopPropagation();
});
//close when popup loses focus
$popupText.on('blur', () => {
$popupText.removeClass('show');
});
toggleHeader();
};
})
.catch(err => {
metrics.unsupported({ err }).then(() => {
location.replace('/unsupported/gcm');
});
});
});
+7427 -1628
View File
File diff suppressed because it is too large Load Diff
+107 -69
View File
@@ -1,69 +1,129 @@
{
"name": "firefox-send",
"description": "File Sharing Experiment",
"version": "1.1.0",
"version": "1.2.4",
"author": "Mozilla (https://mozilla.org)",
"dependencies": {
"aws-sdk": "^2.89.0",
"body-parser": "^1.17.2",
"connect-busboy": "0.0.2",
"convict": "^3.0.0",
"express": "^4.15.3",
"express-handlebars": "^3.0.0",
"helmet": "^3.8.0",
"mozlog": "^2.1.1",
"raven": "^2.1.0",
"redis": "^2.7.1"
"repository": "mozilla/send",
"homepage": "https://github.com/mozilla/send/",
"license": "MPL-2.0",
"private": true,
"scripts": {
"precommit": "lint-staged",
"clean": "rimraf dist",
"build": "npm run clean && webpack -p",
"lint": "npm-run-all lint:*",
"lint:css": "stylelint 'assets/*.css'",
"lint:js": "eslint .",
"lint-locales": "node scripts/lint-locales",
"lint-locales:dev": "npm run lint-locales",
"lint-locales:prod": "npm run lint-locales -- --production",
"format": "prettier '**/*.js' 'assets/*.css' --single-quote --write",
"get-prod-locales": "node scripts/get-prod-locales",
"get-prod-locales:write": "npm run get-prod-locales -- --write",
"changelog": "github-changes -o mozilla -r send --only-pulls --use-commit-body --no-merges",
"contributors": "git shortlog -s | awk -F\\t '{print $2}' > CONTRIBUTORS",
"release": "npm-run-all contributors changelog",
"test": "mocha test/unit",
"start": "cross-env NODE_ENV=development webpack-dev-server",
"prod": "node server/prod.js"
},
"devDependencies": {
"asmcrypto.js": "0.0.11",
"babel-core": "^6.25.0",
"babel-loader": "^7.1.1",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-polyfill": "^6.23.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-2": "^6.24.1",
"browserify": "^14.4.0",
"eslint": "^4.3.0",
"eslint-plugin-mocha": "^4.11.0",
"eslint-plugin-node": "^5.1.1",
"eslint-plugin-security": "^1.4.0",
"git-rev-sync": "^1.9.1",
"jquery": "^3.2.1",
"jquery-circle-progress": "^1.2.2",
"l20n": "^5.0.0",
"mocha": "^3.4.2",
"npm-run-all": "^4.0.2",
"prettier": "^1.5.3",
"proxyquire": "^1.8.0",
"raven-js": "^3.17.0",
"selenium-webdriver": "^3.5.0",
"sinon": "^2.3.8",
"stylelint": "^8.0.0",
"stylelint-config-standard": "^17.0.0",
"supertest": "^3.0.0",
"testpilot-ga": "^0.3.0",
"webcrypto-liner": "^0.1.25",
"webpack": "^3.4.1"
"lint-staged": {
"*.js": [
"prettier --single-quote --write",
"eslint",
"git add"
],
"*.css": [
"prettier --single-quote --write",
"stylelint",
"git add"
]
},
"engines": {
"node": ">=8.2.0"
},
"homepage": "https://github.com/mozilla/send/",
"license": "MPL-2.0",
"repository": "mozilla/send",
"devDependencies": {
"autoprefixer": "^7.1.5",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-plugin-yo-yoify": "^1.0.1",
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.6.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-2": "^6.24.1",
"copy-webpack-plugin": "^4.1.1",
"cross-env": "^5.0.5",
"css-loader": "^0.28.7",
"css-mqpacker": "^6.0.1",
"cssnano": "^3.10.0",
"eslint": "^4.8.0",
"eslint-plugin-mocha": "^4.11.0",
"eslint-plugin-node": "^5.2.0",
"eslint-plugin-security": "^1.4.0",
"expose-loader": "^0.7.3",
"extract-loader": "^1.0.1",
"file-loader": "^1.1.5",
"git-rev-sync": "^1.9.1",
"github-changes": "^1.1.0",
"html-loader": "^0.5.1",
"husky": "^0.14.3",
"lint-staged": "^4.2.3",
"mocha": "^3.5.3",
"nanobus": "^4.2.0",
"npm-run-all": "^4.1.1",
"postcss-loader": "^2.0.6",
"prettier": "^1.7.4",
"proxyquire": "^1.8.0",
"raven-js": "^3.18.1",
"redis-mock": "^0.20.0",
"require-from-string": "^2.0.1",
"rimraf": "^2.6.2",
"selenium-webdriver": "^3.6.0",
"sinon": "^4.0.1",
"string-hash": "^1.1.3",
"stylelint-config-standard": "^17.0.0",
"stylelint-no-unsupported-browser-features": "^1.0.1",
"supertest": "^3.0.0",
"testpilot-ga": "^0.3.0",
"val-loader": "^1.0.2",
"webpack": "^3.6.0",
"webpack-dev-server": "^2.9.1",
"webpack-manifest-plugin": "^1.3.2",
"webpack-unassert-loader": "^1.2.0"
},
"dependencies": {
"aws-sdk": "^2.130.0",
"body-parser": "^1.18.2",
"choo": "^6.4.2",
"connect-busboy": "0.0.2",
"convict": "^4.0.1",
"express": "^4.16.2",
"express-request-language": "^1.1.12",
"fluent": "^0.4.1",
"fluent-langneg": "^0.1.0",
"helmet": "^3.8.2",
"mkdirp": "^0.5.1",
"mozlog": "^2.1.1",
"raven": "^2.2.1",
"redis": "^2.8.0"
},
"availableLanguages": [
"en-US",
"ast",
"az",
"ca",
"cak",
"cs",
"cy",
"de",
"dsb",
"el",
"en-US",
"es-AR",
"es-CL",
"es-ES",
"es-MX",
"et",
"fa",
"fr",
"fy-NL",
"hsb",
@@ -89,27 +149,5 @@
"vi",
"zh-CN",
"zh-TW"
],
"scripts": {
"build": "npm-run-all build:*",
"build:js": "webpack -p",
"build:version": "node scripts/version",
"build:vendor": "cp node_modules/l20n/dist/web/l20n.min.js node_modules/babel-polyfill/dist/polyfill.min.js public",
"contributors": "git shortlog -s | awk -F\\t '{print $2}' > CONTRIBUTORS",
"dev": "npm run build && npm start",
"format": "prettier '{frontend/src/,scripts/,server/,test/**/!(bundle)}*.js' 'public/*.css' --single-quote --write",
"get-prod-locales": "node scripts/get-prod-locales",
"get-prod-locales:write": "npm run get-prod-locales -- --write",
"lint": "npm-run-all lint:*",
"lint:css": "stylelint 'public/*.css'",
"lint:js": "eslint .",
"lint-locales": "node scripts/lint-locales",
"lint-locales:dev": "npm run lint-locales",
"lint-locales:prod": "npm run lint-locales -- --production",
"start": "node server/server",
"test": "npm-run-all test:*",
"test:unit": "mocha test/unit",
"test:server": "mocha test/server",
"test--browser": "browserify test/frontend/frontend.bundle.js -o test/frontend/bundle.js -d && node test/frontend/driver.js"
}
]
}
+15
View File
@@ -0,0 +1,15 @@
const autoprefixer = require('autoprefixer');
const cssnano = require('cssnano');
const mqpacker = require('css-mqpacker');
const config = require('./server/config');
const options = {
plugins: [autoprefixer, mqpacker, cssnano]
};
if (config.env === 'development') {
options.map = { inline: true };
}
module.exports = options;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

+82
View File
@@ -0,0 +1,82 @@
// Firefox Send is a brand name and should not be localized.
title = Firefox Send
siteSubtitle = esperimentu web
siteFeedback = Feedback
uploadPageHeader = Compartición privada y cifrada de ficheros
uploadPageExplainer = Unvia ficheros pente un enllaz seguru, priváu y cifráu que caduca automáticamente p'asegurar que les tos coses nun queden siempres na rede.
uploadPageLearnMore = Deprendi más
uploadPageDropMessage = Suelta equí'l to ficheru p'aniciar la xuba
uploadPageSizeMessage = Pal meyor funcionamientu, lo meyor ye que'l to ficheru seya menor de 1GB
uploadPageBrowseButton = Esbilla un ficheru nel to ordenador
uploadPageBrowseButton1 = Esbilla un ficheru pa unviar
uploadPageMultipleFilesAlert = Anguaño nun se sofita la xuba múltiple de ficheros o carpetes.
uploadPageBrowseButtonTitle = Xubir ficheru
uploadingPageProgress = Xubiendo { $filename } ({ $size })
importingFile = Importando...
verifyingFile = Verificando...
encryptingFile = Cifrando...
decryptingFile = Descifrando...
notifyUploadDone = Finó la to xuba.
uploadingPageMessage = Namái que'l ficheru xuba, sedrás a afitar les opciones de caducidá.
uploadingPageCancel = Encaboxar xuba
uploadCancelNotification = Encaboxóse la to xuba.
uploadingPageLargeFileMessage = Esti ficheru ye grande y pue entardar daqué en xubir. ¡Paciencia!
uploadingFileNotification = Avísame cuando se complete la xuba.
uploadSuccessConfirmHeader = Preparáu pa unviar
uploadSvgAlt = Xubir
uploadSuccessTimingHeader = L'enllaz del to ficheru caducará dempués d'una descarga o en 24 hores.
copyUrlFormLabelWithName = Copia y comparti l'enllaz pa unviar el to ficheru: { $filename }
copyUrlFormButton = Copiar al cartafueyu
copiedUrl = ¡Copióse!
deleteFileButton = Desaniciar ficheru
sendAnotherFileLink = Unviar otru ficheru
// Alternative text used on the download link/button (indicates an action).
downloadAltText = Baxar
downloadFileName = Baxar { $filename }
downloadFileSize = ({ $size })
// Firefox Send is a brand name and should not be localized.
downloadMessage = El to collaciu unvióte un ficheru usando Firefox Send, un serviciu que te permite compartir ficheros con un enllaz seguru, priváu y cifráu que caduca automáticamente p'asegurar que les to coses nun queden siempres na rede.
// Text and title used on the download link/button (indicates an action).
downloadButtonLabel = Baxar
downloadNotification = Completóse la to descarga.
downloadFinish = Descarga completada
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
fileSizeProgress = ({ $partialSize } de { $totalSize })
// Firefox Send is a brand name and should not be localized.
sendYourFilesLink = Prueba Firefox Send
downloadingPageProgress = Baxando { $filename } ({ $size })
downloadingPageMessage = Dexa esta llingüeta abierta entrín vamos en cata del to ficheru y lu desciframos, por favor.
errorAltText = Fallu de xuba
errorPageHeader = ¡Daqué foi mal!
errorPageMessage = Hebo un fallu xubiendo'l ficheru.
errorPageLink = Unviar otru ficheru
fileTooBig = Esti ficheru ye mui grande como pa xubilu. Debería tener menos de { $size }.
linkExpiredAlt = Enllaz caducáu
expiredPageHeader = ¡Esti enllaz caducó o enxamás nun esistó!
notSupportedHeader = El to restolador nun ta sofitáu.
// Firefox Send is a brand name and should not be localized.
notSupportedDetail = Desafortunadamente esti restolador nun sofita la teunoloxía web qu'usa Firefox Send. Precisarás d'usar otru restolador. ¡Aconseyámoste Firefox!
notSupportedLink = ¿Por qué'l mio restolador nun ta sofitáu?
notSupportedOutdatedDetail = Desafortunadamente esta versión de Firefox nun sofita la teunoloxía web qu'usa Firefox Send. Precisarás d'anovar Firefox.
updateFirefox = Anovar Firefox
downloadFirefoxButtonSub = Descarga de baldre
uploadedFile = Ficheru
copyFileList = Copiar URL
// expiryFileList is used as a column header
expiryFileList = Caduca en
deleteFileList = Desaniciar
nevermindButton = Nun m'importa
legalHeader = Términos y privacidá
legalNoticeTestPilot = Anguaño Firefox Send ye un esperimentu de Test Pilot y ta suxetu a los <a>Términos de serviciu</a> y l'<a>Avisu de privacidá</a> de Test Pilot. <a>Equí</a> pues deprender más tocante a esti esperimentu y la so recoyida de datos.
legalNoticeMozilla = L'usu de Firefox Send tamién ta suxetu al <a>Avisu de privacidá</a> y a los <a>Términos d'usu de la páxina web</a> de Mozilla.
deletePopupText = ¿Desaniciar esti ficheru?
deletePopupYes = Sí
deletePopupCancel = Encaboxar
deleteButtonHover = Desaniciar
copyUrlHover = Copiar URL
footerLinkLegal = Llegal
// Test Pilot is a proper name and should not be localized.
footerLinkAbout = Tocante a Test Pilot
footerLinkPrivacy = Privacidá
footerLinkTerms = Términos
footerLinkCookies = Cookies
+11 -24
View File
@@ -8,10 +8,10 @@ uploadPageLearnMore = Ətraflı öyrən
uploadPageDropMessage = Yükləmək üçün faylınızı buraya daşıyın
uploadPageSizeMessage = Xidmətin daha yaxşı işləməsi üçün faylınız 1 GB-dan az olmalıdır
uploadPageBrowseButton = Kompüterinizdən fayl seçin
.title = Kompüterinizdən fayl seçin
uploadPageBrowseButton1 = Yüklənəcək faylı seçin
uploadPageMultipleFilesAlert = Birdən çox fayl və ya qovluq yükləmə hələlik dəstəklənmir.
uploadPageBrowseButtonTitle = Fayl yüklə
uploadingPageHeader = Faylınız yüklənir
uploadingPageProgress = { $filename } ({ $size }) yüklənir
importingFile = İdxal edilir…
verifyingFile = Təsdiqlənir…
encryptingFile = Şifrələnir...
@@ -19,50 +19,39 @@ decryptingFile = Şifrə açılır...
notifyUploadDone = Yükləməniz hazırdır.
uploadingPageMessage = Faylınız yükləndikdən sonra vaxtı çıxma seçimlərini qura biləcəksiz.
uploadingPageCancel = Yükləməni ləğv et
.title = Yükləməni ləğv et
uploadCancelNotification = Yükləməniz ləğv edildi.
uploadingPageLargeFileMessage = Fayl böyükdür və yükləmək çox vaxt ala bilər. Səbirli olun!
uploadingFileNotification = Yükləmə bitdiyində xəbər ver.
uploadSuccessConfirmHeader = Göndərməyə hazır
uploadSvgAlt
.alt = Yüklə
uploadSvgAlt = Yüklə
uploadSuccessTimingHeader = Faylınızın keçidinin 1 endirmədən və ya 24 saatdan sonra vaxtı çıxacaq.
copyUrlFormLabelWithName = Faylınızı göndərmək üçün keçidi köçürün: { $filename }
// Note: Title text for button should be the same.
copyUrlFormButton = Buferə köçür
.title = Mübadilə buferinə köçür
copiedUrl = Köçürüldü!
// Note: Title text for button should be the same.
deleteFileButton = Faylı sil
.title = Faylı sil
// Note: Title text for button should be the same.
sendAnotherFileLink = Başqa fayl göndər
.title = Başqa fayl göndər
// Alternative text used on the download link/button (indicates an action).
downloadAltText
.alt = Endir
downloadAltText = Endir
downloadFileName = { $filename } faylını endir
downloadFileSize = ({ $size })
// Firefox Send is a brand name and should not be localized.
downloadMessage = Yoldaşınız Firefox Send ilə sizə fayl göndərir, fayllarınızı təhlükəsiz, məxfi, şifrələnmiş və daima onlayn qalmaması üçün avtomatik silən fayl göndərmə xidməti.
// Text and title used on the download link/button (indicates an action).
downloadButtonLabel = Endir
.title = Endir
downloadNotification = Endirməniz tamamlandı.
downloadFinish = Endirmə Tamamlandı
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
fileSizeProgress = ({ $partialSize } / { $totalSize })
// Firefox Send is a brand name and should not be localized.
sendYourFilesLink = Firefox Send Yoxla
.title = Firefox Send Yoxla
downloadingPageProgress = { $filename } faylı ({ $size }) endirilir
downloadingPageMessage = Lütfən faylı endirib şifrəsini açarkən vərəqi açıq buraxın.
errorAltText
.alt = Yükləmə xətası
errorAltText = Yükləmə xətası
errorPageHeader = Nəsə səhv getdi!
errorPageMessage = Faylı yüklərkən xəta baş verdi.
errorPageLink = Başqa fayl göndər
fileTooBig = Fayl yükləmək üçün çox böyükdür. Fayl { $size }-dan az olmalıdır.
linkExpiredAlt
.alt = Keçidin vaxtı çıxıb
linkExpiredAlt = Keçidin vaxtı çıxıb
expiredPageHeader = Keçidin vaxtı çıxıb və ya heç vaxt olmayıb!
notSupportedHeader = Səyyahınız dəstəklənmir.
// Firefox Send is a brand name and should not be localized.
@@ -83,10 +72,8 @@ legalNoticeMozilla = Firefox Send saytının istifadəsi həmçinin Mozilla-nın
deletePopupText = Fayl silinsin?
deletePopupYes = Bəli
deletePopupCancel = Ləğv et
deleteButtonHover
.title = Sil
copyUrlHover
.title = Keçidi Köçürt
deleteButtonHover = Sil
copyUrlHover = Keçidi Köçürt
footerLinkLegal = Hüquqi
// Test Pilot is a proper name and should not be localized.
footerLinkAbout = Test Pilot Haqqında
+51
View File
@@ -0,0 +1,51 @@
// Firefox Send is a brand name and should not be localized.
title = Firefox Send
siteSubtitle = ওয়েব গবেষণা
siteFeedback = প্রতিক্রিয়া
uploadPageLearnMore = আরও জানুন
uploadPageBrowseButton = আপনার কম্পিউটারে ফাইল নির্বাচন করুন
uploadPageBrowseButtonTitle = ফাইল আপলোড
importingFile = ইম্পোর্ট হচ্ছে...
verifyingFile = যাচাই হচ্ছে...
encryptingFile = ইনক্রিপট হচ্ছে...
decryptingFile = ডিক্রিপট হচ্ছে...
notifyUploadDone = আপনার আপলোড সম্পন্ন হয়েছে।
uploadingPageCancel = আপলোড বাতিল করুন
uploadCancelNotification = আপনার অাপলোড বাতিল করা হয়েছে।
uploadSuccessConfirmHeader = পাঠানোর জন্য প্রস্তুত
uploadSvgAlt = আপলোড
copyUrlFormButton = ক্লিপবোর্ডে কপি করুন
copiedUrl = কপি করা হয়েছে!
deleteFileButton = ফাইল মুছুন
sendAnotherFileLink = আরেকটি ফাইল পাঠান
// Alternative text used on the download link/button (indicates an action).
downloadAltText = ডাউনলোড
downloadFileName = ডাউনলোড { $filename }
downloadFileSize = ({ $size })
// Text and title used on the download link/button (indicates an action).
downloadButtonLabel = ডাউনলোড
downloadNotification = আপনার ডাউনলোড সম্পন্ন হয়েছে।
downloadFinish = ডাউনলোড সম্পন্ন
errorAltText = আপালোডে ত্রুটি
errorPageHeader = কোন সমস্যা হয়েছে!
errorPageLink = আরেকটি ফাইল পাঠান
updateFirefox = Firefox হালনাগাদ করুন
downloadFirefoxButtonSub = বিনামূল্যে ডাউনলোড
uploadedFile = ফাইল
copyFileList = URL অনুলিপি করুন
// expiryFileList is used as a column header
expiryFileList = মেয়াদোত্তীর্ণ তারিখ
deleteFileList = মুছে ফেলুন
nevermindButton = কিছু মনে করবেন না
legalHeader = শর্তাবলী এবং গোপনীয়তা
deletePopupText = ফাইলটি মুছতে চান?
deletePopupYes = হ্যাঁ
deletePopupCancel = বাতিল
deleteButtonHover = মুছে ফেলুন
copyUrlHover = URL অনুলিপি করুন
footerLinkLegal = আইনগত
// Test Pilot is a proper name and should not be localized.
footerLinkAbout = Test Pilot পরিচিতি
footerLinkPrivacy = গোপনীয়তা
footerLinkTerms = শর্তাবলী
footerLinkCookies = কুকি
+11 -24
View File
@@ -8,10 +8,10 @@ uploadPageLearnMore = Més informació
uploadPageDropMessage = Arrossegueu el fitxer aquí per començar a pujar-lo
uploadPageSizeMessage = Funciona millor quan els fitxers tenen menys d'1 GB
uploadPageBrowseButton = Trieu un fitxer de l'ordinador
.title = Trieu un fitxer de l'ordinador
uploadPageBrowseButton1 = Seleccioneu el fitxer que voleu pujar
uploadPageMultipleFilesAlert = Actualment no es permet pujar diversos fitxers ni una carpeta.
uploadPageBrowseButtonTitle = Puja el fitxer
uploadingPageHeader = S'està pujant el fitxer
uploadingPageProgress = S'està pujant { $filename } ({ $size })
importingFile = S'està important…
verifyingFile = S'està verificant…
encryptingFile = S'està xifrant…
@@ -19,50 +19,39 @@ decryptingFile = S'està desxifrant…
notifyUploadDone = La pujada ha acabat.
uploadingPageMessage = Quan s'hagi acabat de pujat el fitxer, podreu definir les opcions de caducitat.
uploadingPageCancel = Cancel·la la pujada
.title = Cancel·la la pujada
uploadCancelNotification = La pujada s'ha cancel·lat.
uploadingPageLargeFileMessage = Aquest fitxer és gros i pot trigar una estona a pujar. Espereu assegut…
uploadingFileNotification = Notifica'm quan s'acabi de pujar.
uploadSuccessConfirmHeader = Llest per enviar
uploadSvgAlt
.alt = Puja
uploadSvgAlt = Puja
uploadSuccessTimingHeader = L'enllaç al fitxer caducarà quan es baixi una vegada o d'aquí 24 hores.
copyUrlFormLabelWithName = Copieu l'enllaç i compartiu-lo per enviar el fitxer: { $filename }
// Note: Title text for button should be the same.
copyUrlFormButton = Copia al porta-retalls
.title = Copia al porta-retalls
copiedUrl = Copiat!
// Note: Title text for button should be the same.
deleteFileButton = Suprimeix el fitxer
.title = Suprimeix el fitxer
// Note: Title text for button should be the same.
sendAnotherFileLink = Envieu un altre fitxer
.title = Envieu un altre fitxer
// Alternative text used on the download link/button (indicates an action).
downloadAltText
.alt = Baixa
downloadAltText = Baixa
downloadFileName = Baixeu { $filename }
downloadFileSize = ({ $size })
// Firefox Send is a brand name and should not be localized.
downloadMessage = Un amic us ha enviat un fitxer amb el Firefox Send, un servei que permet compartir fitxers mitjançant un enllaç segur, privat i xifrat que caduca automàticament per tal que les vostres dades no es conservin a Internet per sempre.
// Text and title used on the download link/button (indicates an action).
downloadButtonLabel = Baixa
.title = Baixa
downloadNotification = La baixada ha acabat.
downloadFinish = Ha acabat la baixada
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
fileSizeProgress = ({ $partialSize } de { $totalSize })
// Firefox Send is a brand name and should not be localized.
sendYourFilesLink = Proveu el Firefox Send
.title = Proveu el Firefox Send
downloadingPageProgress = S'està baixant { $filename } ({ $size })
downloadingPageMessage = Deixeu aquesta pestanya oberta per tal que el fitxer es pugui baixar i desxifrar.
errorAltText
.alt = S'ha produït un error en pujar
errorAltText = S'ha produït un error en pujar
errorPageHeader = Hi ha hagut un problema
errorPageMessage = S'ha produït un error en pujar el fitxer.
errorPageLink = Envieu un altre fitxer
fileTooBig = Aquest fitxer és massa gros per pujar-lo. Ha de tenir menys de { $size }.
linkExpiredAlt
.alt = L'enllaç ha caducat
linkExpiredAlt = L'enllaç ha caducat
expiredPageHeader = Aquest enllaç ha caducat o no existeix.
notSupportedHeader = El vostre navegador no és compatible.
// Firefox Send is a brand name and should not be localized.
@@ -83,10 +72,8 @@ legalNoticeMozilla = L'ús del Firefox Send també està subjecte a l'<a>Avís d
deletePopupText = Voleu suprimir aquest fitxer?
deletePopupYes = Sí
deletePopupCancel = Cancel·la
deleteButtonHover
.title = Suprimeix
copyUrlHover
.title = Copia l'URL
deleteButtonHover = Suprimeix
copyUrlHover = Copia l'URL
footerLinkLegal = Avís legal
// Test Pilot is a proper name and should not be localized.
footerLinkAbout = Quant al Test Pilot
+82
View File
@@ -0,0 +1,82 @@
// Firefox Send is a brand name and should not be localized.
title = Firefox Send
siteSubtitle = ajk'amaya'l solna'onem
siteFeedback = Rutzijol
uploadPageHeader = Kekomonïx Ichinan chuqa' Ewan Kisik'ixik taq Yakb'äl
uploadPageExplainer = Ketaq taq yakb'äl rik'in jun ewan rusik'ixik, ichinan chuqa' jikon ximonel, ri ruyonil xtikis ruq'ijul richin ke ri' ri taq atzij man e okel ta pa k'amaya'l junelïk.
uploadPageLearnMore = Tetamäx ch'aqa' chik
uploadPageDropMessage = Tajik'a' pe ri ayakb'al wawe' richin nachäp kijotob'axik
uploadPageSizeMessage = Richin chi ütz nel ri samaj, k'o ta chi ri yakb'äl man tik'o chi re ri 1GB
uploadPageBrowseButton = Tacha' jun yakb'äl pan akematz'ib'
uploadPageBrowseButton1 = Tacha' jun yakb'äl richin najotob'a'
uploadPageMultipleFilesAlert = K'a man nuk'öch ta nijotob'äx jalajöj yakb'äl o jun molwuj.
uploadPageBrowseButtonTitle = Tijotob'äx yakb'äl
uploadingPageProgress = Tajin nijotob'äx { $filename } ({ $size })
importingFile = Tajin nijik…
verifyingFile = Tajin nijikib'äx...
encryptingFile = Tajin newäx rusik'ixik...
decryptingFile = Tajin netamäx rusik'ixik...
notifyUploadDone = Xak'is rujotob'axik.
uploadingPageMessage = Toq xtijotob'äx ri yakb'äl xkatikïr xtak'ëx pa taq cha'oj ri ruq'ijul xtik'is.
uploadingPageCancel = Tiq'at jotob'anïk
uploadCancelNotification = Xq'at ri ajotob'anik
uploadingPageLargeFileMessage = Yalan nïm re yakb'äl re' ruma ri' toq xtiyoke' richin xtijote'. ¡Man tik'o ak'u'x!
uploadingFileNotification = Tiya' pe rutzijol chwe toq xtitz'aqät rujotob'axik.
uploadSuccessConfirmHeader = Ütz chik richin Nitaq
uploadSvgAlt = Tijotob'äx
uploadSuccessTimingHeader = Ri ruximonel yakb'äl xtik'is ruq'ijul toq xtiqasäx jumul o pa 24 ramaj.
copyUrlFormLabelWithName = Tiwachib'ëx chuqa' tikomonïx ri ximonel richin nitaq ri ayakb'äl: { $filename }
copyUrlFormButton = Tiwachib'ëx pa molwuj
copiedUrl = ¡Xwachib'ëx!
deleteFileButton = Tiyuj yakb'äl
sendAnotherFileLink = Titaq jun chik yakb'äl
// Alternative text used on the download link/button (indicates an action).
downloadAltText = Tiqasäx
downloadFileName = Tiqasäx { $filename }
downloadFileSize = ({ $size })
// Firefox Send is a brand name and should not be localized.
downloadMessage = Jun awachib'il xutäq jun yakb'äl chawe rik'in ri Firefox Send, jun samaj ri nuya' q'ij chawe ye'akomonij taq yakb'äl rik'in jun jikïl, ichinan chuqa' ewan rusik'ixik ximonel, ri nik'is ruq'ijul pa ruyonil richin chi ri taq awachinaq man junelïk ta e okel pa k'amab'ey.
// Text and title used on the download link/button (indicates an action).
downloadButtonLabel = Tiqasäx
downloadNotification = Xtz'aqät ri aqasanik.
downloadFinish = Xtz'aqät qasanïk
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
fileSizeProgress = ({ $partialSize } richin { $totalSize })
// Firefox Send is a brand name and should not be localized.
sendYourFilesLink = Titojtob'ëx Firefox Send
downloadingPageProgress = Tajin niqasäx { $filename } ({ $size })
downloadingPageMessage = Tijaq kan re ruwi' re' richin niqaqasaj ri yakb'äl chuqa' richin niqetamaj rusik'ixik.
errorAltText = Xsach toq nijotob'äx
errorPageHeader = ¡K'o ri man ütz ta xub'än!
errorPageMessage = Xk'ulwachitäj jun sachoj toq tajin nijotob'äx ri yakb'äl.
errorPageLink = Titaq jun chik yakb'äl
fileTooBig = Yalan nïm re yakb'äl re' richin nijotob'äx. K'o ta chi man nik'o ta chi re ri { $size }.
linkExpiredAlt = Xk'is ruq'ijul ri ximonel
expiredPageHeader = ¡Xk'is ruq'ijul re ximonel re' o rik'in jub'a' majub'ey xk'oje'!
notSupportedHeader = Man koch'el ta ri awokik'amaya'l.
// Firefox Send is a brand name and should not be localized.
notSupportedDetail = K'ayew ruma re okik'amaya'l re' man nuköch' ta ajk'amaya'l na'ob'äl nik'atzin chi re ri Firefox Send. K'o chi natojtob'ej jun chik okik'amaya'l. ¡Niqachilab'ej chawe ri Firefox!
notSupportedLink = ¿Achike ruma man nikoch' taq ri wokik'amaya'l?
notSupportedOutdatedDetail = K'ayew ruma re ruwäch Firefox re' man nuköch' ta ri ajk'amaya'l na'ob'äl nrajo' ri Firefox Send. Rajowaxik nak'ëx ri awokik'amaya'l.
updateFirefox = Tik'ex ri Firefox
downloadFirefoxButtonSub = Sipan Ruqasaxik
uploadedFile = Yakb'äl
copyFileList = Tiwachib'ëx URL
// expiryFileList is used as a column header
expiryFileList = Nik'is Ruq'ijul Pa
deleteFileList = Tiyuj
nevermindButton = Junam nub'än
legalHeader = Ojqanem chuqa' Ichinanem
legalNoticeTestPilot = Firefox Send k'a jun rutojtob'enik Test Pilot, chuqa' rutaqen rutzij ri <a>Rojqanem Samaj</a> chuqa' rik'in ri <a>Rutzijol Ichinanem</a>. Yatikïr nawetamaj ch'aq'a' chik chi rij re solna'oj re' chuqa' ri rumolik tzij <a>wawe'</a>.
legalNoticeMozilla = Richin nokisäx ri ruxaq ruk'amaya'l Firefox Send k'o chi nitaqëx ri <a>Rutzijol Richinanem Ajk'amaya'l Ruxaq</a> chuqa' <a>Rojqanem rokisaxik Ajk'amaya'l Ruxaq</a>.
deletePopupText = ¿La niyuj el re yakb'äl re'?
deletePopupYes = Ja'
deletePopupCancel = Tiq'at
deleteButtonHover = Tiyuj
copyUrlHover = Tiwachib'ëx URL
footerLinkLegal = Taqanel tzijol
// Test Pilot is a proper name and should not be localized.
footerLinkAbout = Chi rij Test Pilot
footerLinkPrivacy = Ichinanem
footerLinkTerms = Taq ojqanem
footerLinkCookies = Taq kaxlanwey
+13 -25
View File
@@ -8,10 +8,10 @@ uploadPageLearnMore = Zjistit více
uploadPageDropMessage = Přesunutím souboru sem spustíte jeho nahrávání
uploadPageSizeMessage = Nahrávání funguje nejlépe pro soubory do velikosti 1 GB.
uploadPageBrowseButton = Vybrat soubor z počítače
.title = Výběr souboru z počítače
uploadPageBrowseButton1 = Zvolte soubor k nahrání
uploadPageMultipleFilesAlert = Nahrávání více souborů najednou nebo celých složek zatím není podporováno.
uploadPageBrowseButtonTitle = Nahrát soubor
uploadingPageHeader = Nahrávání vašeho souboru
uploadingPageProgress = Nahrávání souboru { $filename } ({ $size })
importingFile = Probíhá import…
verifyingFile = Probíhá ověřování…
encryptingFile = Probíhá šifrování…
@@ -19,54 +19,44 @@ decryptingFile = Probíhá dešifrování…
notifyUploadDone = Nahrávání vašeho souboru bylo dokončeno.
uploadingPageMessage = Po dokončení nahrávání můžete nastavit dobu expirace souboru.
uploadingPageCancel = Zrušit nahrávání
.title = Zrušit nahrávání
uploadCancelNotification = Nahrávání vašeho souboru bylo zrušeno.
uploadingPageLargeFileMessage = Tento soubor je veliký a jeho nahrávání může chvíli trvat. Posaďte se na chvilku.
uploadingFileNotification = Upozornit, až bude nahrávání dokončeno.
uploadSuccessConfirmHeader = Připraveno k odeslání
uploadSvgAlt
.alt = Nahrát
uploadSvgAlt = Nahrát
uploadSuccessTimingHeader = Platnost odkazu na váš soubor vyprší po jeho prvním stažení, nebo po 24 hodinách.
copyUrlFormLabelWithName = Zkopírujte a sdílejte odkaz na váš soubor: { $filename }
// Note: Title text for button should be the same.
copyUrlFormButton = Zkopírovat do schránky
.title = Zkopírovat do schránky
copiedUrl = Zkopírováno!
// Note: Title text for button should be the same.
deleteFileButton = Smazat soubor
.title = Smazání souboru
// Note: Title text for button should be the same.
sendAnotherFileLink = Poslat další soubor
.title = Poslat další soubor
// Alternative text used on the download link/button (indicates an action).
downloadAltText
.alt = Stáhnout
downloadAltText = Stáhnout
downloadFileName = Stáhnout { $filename }
downloadFileSize = ({ $size })
// Firefox Send is a brand name and should not be localized.
downloadMessage = Někdo vám posílá soubor pomocí služby Firefox Send, které umožňuje bezpečné, soukromí a šifrované sdílení souborů, které jsou pak automaticky smazány, aby nezůstaly na internetu navěky.
downloadMessage = Někdo vám posílá soubor pomocí služby Firefox Send, které umožňuje bezpečné, soukromé a šifrované sdílení souborů, které jsou pak automaticky smazány, aby nezůstaly na internetu navěky.
// Text and title used on the download link/button (indicates an action).
downloadButtonLabel = Stáhnout
.title = Stáhnout
downloadNotification = Stahování bylo dokončeno.
downloadFinish = Stahování dokončeno
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
fileSizeProgress = ({ $partialSize } z { $totalSize })
// Firefox Send is a brand name and should not be localized.
sendYourFilesLink = Vyzkoušejte Firefox Send
.title = Vyzkoušejte Firefox Send
downloadingPageProgress = Stahování { $filename } ({ $size })
downloadingPageMessage = Ponechte prosím tento panel otevřený, dokud nepřipravíme váš soubor a nedešifrujeme ho.
errorAltText
.alt = Chyba při nahrávání souboru
errorAltText = Chyba při nahrávání souboru
errorPageHeader = Nastala chyba!
errorPageMessage = Při nahrávání souboru se vyskytl problém.
errorPageLink = Poslat další soubor
fileTooBig = Tento soubor je příliš veliký. Velikost nahrávaných souborů by neměla překročit { $size }.
linkExpiredAlt
.alt = Platnost odkazu vypršela
linkExpiredAlt = Platnost odkazu vypršela
expiredPageHeader = Platnost tohoto odkazu buď vypršela, nebo vůbec nikdy neexistoval.
notSupportedHeader = Váš prohlížeč není podporován.
// Firefox Send is a brand name and should not be localized.
notSupportedDetail = Bohužel tento prohlížeč nepodporuje technologii, kterou Firefox Send používá. Zkuste prosím jiný prohlížeč, doporučujeme Firefox!
notSupportedLink = Proč není můj prohlížeč podporovaný?
notSupportedOutdatedDetail = Tato verze Firefoxu bohužel nepodporuje webovou technologii, která pohání Firefox Send. Musíte aktualizovat svůj prohlížeč.
updateFirefox = Aktualizovat Firefox
downloadFirefoxButtonSub = Stáhnout zdarma
@@ -82,10 +72,8 @@ legalNoticeMozilla = Používání webové služby Firefox Send se řídí <a>Z
deletePopupText = Smazat tento soubor?
deletePopupYes = Ano
deletePopupCancel = Zrušit
deleteButtonHover
.title = Smazat
copyUrlHover
.title = Kopírovat URL
deleteButtonHover = Smazat
copyUrlHover = Kopírovat URL
footerLinkLegal = Právní informace
// Test Pilot is a proper name and should not be localized.
footerLinkAbout = O programu Test Pilot
+21 -33
View File
@@ -2,72 +2,62 @@
title = Firefox Send
siteSubtitle = arbrawf gwe
siteFeedback = Adborth
uploadPageHeader = Rhannu Ffeiliau wedi eu Hamgryptio Preifat
uploadPageHeader = Rhannu Ffeiliau wedi eu Hamgryptio yn Breifat
uploadPageExplainer = Anfon ffeiliau drwy ddolen diogel, breifat ac wedi ei amgryptio sy'n dod i ben yn awtomatig er mwyn sicrhau nad yw eich pethau'n bodoli ar lein am byth.
uploadPageLearnMore = Dysgu rhagor
uploadPageDropMessage = Gollyngwch eich ffeiliau yma i gychwyn llwytho i fyny
uploadPageSizeMessage = Mae'n well cadw maint y ffeiliau o dan 1GB er mwyn iddo weithio ar ei orau.
uploadPageBrowseButton = Dewiswch ffeil ar eich cyfrifiadur
.title = Dewiswch ffeil ar eich cyfrifiadur
uploadPageMultipleFilesAlert = Nid yw llwytho nifer lluosog o ffeilia neu ffolder yn cael ei gynnal ar hyn o bryd.
uploadPageBrowseButton1 = Dewiswch ffeil i'w llwytho i fyny
uploadPageMultipleFilesAlert = Nid yw llwytho nifer lluosog o ffeiliau neu ffolder yn cael ei gynnal ar hyn o bryd.
uploadPageBrowseButtonTitle = Llwytho ffeil i fyny
uploadingPageHeader = Llwytho eich Ffeiliau i Fyny
uploadingPageProgress = Llwytho $filename} i fyny ({ $size })
importingFile = Mewnforio…
verifyingFile = Wrthi'n gwirio…
encryptingFile = Wrthi'n amgryptio…
decryptingFile = Wrthi'n dadgryptio…
notifyUploadDone = Mae eich llwytho wedi gorffen.
uploadingPageMessage = Unwaith y bydd eich ffeil wedi llwytho bydd modd gosod manylion dod i ben.
uploadingPageMessage = Unwaith y bydd eich ffeil wedi llwytho bydd modd gosod y manylion dod i ben.
uploadingPageCancel = Diddymu'r llwytho
.title = Diddymu'r llwytho
uploadCancelNotification = Cafodd eich llwytho ei ddiddymu.
uploadingPageLargeFileMessage = Mae'r ffeil yn fawr a gall gymryd peth amser i'w llwytho. Arhoswch!
uploadingFileNotification = Dweud wrtha i pan fydd y llwytho wedi gorffen.
uploadingPageLargeFileMessage = Mae'r ffeil yn fawr a gall gymryd peth amser i'w llwytho. Amynedd!
uploadingFileNotification = Dweud pan fydd y llwytho wedi gorffen.
uploadSuccessConfirmHeader = Yn Barod i Anfon
uploadSvgAlt
.alt = LLwytho i Fyny
uploadSvgAlt = Llwytho i Fyny
uploadSuccessTimingHeader = Bydd y ddolen i'ch ffeil y dod i ben ar ôl 1 llwytho neu o fewn 24 awr.
copyUrlFormLabelWithName = Copïo a rhannu'r ddolen i anfon eich ffeil: { $filename }
// Note: Title text for button should be the same.
copyUrlFormButton = Copïo i'r clipfwrdd
.title = Copïo i'r clipfwrdd
copiedUrl = Wedi eu copïo!
// Note: Title text for button should be the same.
deleteFileButton = Dileu ffeil
.title = Dileu ffeil
// Note: Title text for button should be the same.
sendAnotherFileLink = Anfon ffeil arall
.title = Anfon ffeil arall
// Alternative text used on the download link/button (indicates an action).
downloadAltText
.alt = Llwytho i lawr
downloadAltText = Llwytho i lawr
downloadFileName = Llwytho i lawr { $filename }
downloadFileSize = ({ $size })
// Firefox Send is a brand name and should not be localized.
downloadMessage = Mae ffrind i chi yn anfon ffeil atoch drwy Firefox Send, gwasanaeth sy'n caniatáu i chi rannu ffeiliau drwy ddolen ddiogel, breifat ac wedi ei amgryptio sy'n dod i ben yn awtomatig er mwyn sicrhau nad yw eich deunydd yn aros ar-lein am byth.
// Text and title used on the download link/button (indicates an action).
downloadButtonLabel = Llwytho i Lawr
.title = Llwytho i Lawr
downloadNotification = Mae eich llwytho wedi gorffen
downloadFinish = Llwytho wedi Gorffen
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
sendYourFilesLink = Profwch Firefox Send
.title = Profwch Firefox Send
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
fileSizeProgress = ({ $partialSize } o { $totalSize })
// Firefox Send is a brand name and should not be localized.
sendYourFilesLink = Rhowch gynnig ar Firefox Send
downloadingPageProgress = Llwytho i lawr { $filename } ({ $size })
downloadingPageMessage = Gadewch y tab yma ar agor tra fyddwn yn estyn eich ffeil a'i dad-amgryptio.
errorAltText
.alt = Gwall llwytho
errorAltText = Gwall llwytho
errorPageHeader = Aeth rhywbeth o'i le!
errorPageMessage = Bu gwall wrth lwytho'r ffeil.
errorPageLink = Anfon ffeil arall
fileTooBig = Mae'r ffeil yn rhy fawr i'w llwytho. Dylai fod yn llai na { $size }.
linkExpiredAlt
.alt = Mae'r ddolen wedi dod i ben
linkExpiredAlt = Mae'r ddolen wedi dod i ben
expiredPageHeader = Mae'r ddolen wedi dod i ben neu nad yw wedi bodoli erioed!
notSupportedHeader = Nid yw eich porwr yn cael ei gynnal.
// Firefox Send is a brand name and should not be localized.
notSupportedDetail = Yn anffodus nid yw'r porwr hwn yn cynnal y technoleg gwe sy'n cynnal Firefox Send. Bydd angen i chi ddefnyddio porwr arall. Rydym ni'n argymell Firefox!
notSupportedOutdatedDetail = Yn anffodus nid yw'r fersiwn yma o Firefox yn cynnal y technoleg gwe sy'n gyrru Firefox Send. Bydd angen i chi ddiweddaru eich porwr.
notSupportedDetail = Yn anffodus, nid yw'r porwr hwn yn cynnal y technoleg gwe sy'n cynnal Firefox Send. Bydd angen i chi ddefnyddio porwr arall. Rydym ni'n argymell Firefox!
notSupportedLink = Pam nad yw fy mhorwr yn cael ei gynnal?
notSupportedOutdatedDetail = Yn anffodus, nid yw'r fersiwn yma o Firefox yn cynnal y technoleg gwe sy'n gyrru Firefox Send. Bydd angen i chi ddiweddaru eich porwr.
updateFirefox = Diweddaru Firefox
downloadFirefoxButtonSub = Llwytho i Lawr am Ddim
uploadedFile = Ffeil
@@ -77,15 +67,13 @@ expiryFileList = Daw i ben ymhen
deleteFileList = Dileu
nevermindButton = Dim ots
legalHeader = Amodau a Phreifatrwydd
legalNoticeTestPilot = Ar hyn o mae Firefox Send yn arbrawf o fewn rhaglen Test Pilot ac yn destun <a>Amodau Gwasanaeth</a> a <a>Hysbysiad Preifatrwydd</a> Test Pilot . Gallwch ddysgu rhagor am yr arbrawf a'i gasglu data <a>yma</a>.
legalNoticeTestPilot = Ar hyn o mae Firefox Send yn arbrawf o fewn rhaglen Test Pilot ac yn destun <a>Amodau Gwasanaeth</a> a <a>Hysbysiad Preifatrwydd</a> Test Pilot . Gallwch ddysgu rhagor am yr arbrawf a'r data mae'n ei gasglu <a>yma</a>.
legalNoticeMozilla = Mae'r defnydd o wefan Firefox Send hefyd yn destun <a>Hysbysiad Preifatrwydd Gwefannau</a> ac <a>Amodau Defnydd Gwefannau</a> Mozilla.
deletePopupText = Dileu'r ffeil?
deletePopupYes = Iawn
deletePopupCancel = Diddymu
deleteButtonHover
.title = Dileu
copyUrlHover
.title = Copïo'r URL
deleteButtonHover = Dileu
copyUrlHover = Copïo'r URL
footerLinkLegal = Cyfreithiol
// Test Pilot is a proper name and should not be localized.
footerLinkAbout = Ynghylch Test Pilot
+8 -23
View File
@@ -8,7 +8,7 @@ uploadPageLearnMore = Mehr erfahren
uploadPageDropMessage = Ziehen Sie eine Datei zum Hochladen hierher
uploadPageSizeMessage = Dateien unter 1 GB sorgen für erhöhte Zuverlässigkeit des Betriebs
uploadPageBrowseButton = Wählen Sie eine Datei auf Ihrem Computer aus
.title = Wählen Sie eine Datei auf Ihrem Computer aus
uploadPageBrowseButton1 = Datei zum Hochladen auswählen
uploadPageMultipleFilesAlert = Hochladen mehrerer Dateien oder eines Ordners wird derzeit nicht unterstützt.
uploadPageBrowseButtonTitle = Datei hochladen
uploadingPageProgress = { $filename } ({ $size }) wird hochgeladen
@@ -19,52 +19,39 @@ decryptingFile = Wird entschlüsselt…
notifyUploadDone = Ihr Upload ist abgeschlossen.
uploadingPageMessage = Sobald Ihre Datei hochgeladen wird, können Sie die Optionen zum Ablaufdatum auswählen.
uploadingPageCancel = Hochladen abbrechen
.title = Hochladen abbrechen
uploadCancelNotification = Ihr Upload wurde abgebrochen.
uploadingPageLargeFileMessage = Diese Datei ist groß, sodass das hochladen einige Zeit dauern könnte. Haben Sie Geduld!
uploadingFileNotification = Mich benachrichtigen, wenn der Upload abgeschlossen ist.
uploadSuccessConfirmHeader = Bereit zum Senden
uploadSvgAlt
.alt = Hochladen
uploadSvgAlt = Hochladen
uploadSuccessTimingHeader = Der Link zu Ihrer Datei läuft nach einem Download oder in 24 Stunden ab.
copyUrlFormLabelWithName = Kopieren und teilen Sie den Link, um Ihre Datei zu senden: { $filename }
// Note: Title text for button should be the same.
copyUrlFormButton = In Zwischenablage kopieren
.title = In Zwischenablage kopieren
copiedUrl = Kopiert!
// Note: Title text for button should be the same.
deleteFileButton = Datei löschen
.title = Datei löschen
// Note: Title text for button should be the same.
sendAnotherFileLink = Eine weitere Datei senden
.title = Eine weitere Datei senden
// Alternative text used on the download link/button (indicates an action).
downloadAltText
.alt = Herunterladen
downloadAltText = Herunterladen
downloadFileName = { $filename } herunterladen
downloadFileSize = ({ $size })
// Firefox Send is a brand name and should not be localized.
downloadMessage = Ihr Freund schickt Ihnen eine Datei mit Firefox Send, einem Dienst, mit dem Sie Dateien über einen sicheren, privaten und verschlüsselten Link teilen können, der automatisch abläuft, damit Ihre Daten nicht für immer im Internet bleiben.
// Text and title used on the download link/button (indicates an action).
downloadButtonLabel = Herunterladen
.title = Herunterladen
downloadNotification = Der Download wurde abgeschlossen.
downloadFinish = Download abgeschlossen
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
fileSizeProgress = ({ $partialSize } von { $totalSize })
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
// Firefox Send is a brand name and should not be localized.
sendYourFilesLink = Firefox Send ausprobieren
.title = Firefox Send ausprobieren
downloadingPageProgress = { $filename } ({ $size }) wird heruntergeladen
downloadingPageMessage = Bitte lassen Sie diesen Tab geöffnet, während Ihre Datei heruntergeladen und entschlüsselt wird.
errorAltText
.alt = Fehler beim Hochladen
errorAltText = Fehler beim Hochladen
errorPageHeader = Ein Fehler ist aufgetreten!
errorPageMessage = Beim Hochladen der Datei ist ein Fehler aufgetreten.
errorPageLink = Eine weitere Datei senden
fileTooBig = Die Datei ist zu groß zum Hochladen. Sie sollte maximal { $size } groß sein.
linkExpiredAlt
.alt = Link abgelaufen
linkExpiredAlt = Link abgelaufen
expiredPageHeader = Dieser Link ist abgelaufen oder hat nie existiert!
notSupportedHeader = Ihr Browser wird nicht unterstützt.
// Firefox Send is a brand name and should not be localized.
@@ -85,10 +72,8 @@ legalNoticeMozilla = Die Nutzung der Website von Firefox Send unterliegt außerd
deletePopupText = Diese Datei löschen?
deletePopupYes = Ja
deletePopupCancel = Abbrechen
deleteButtonHover
.title = Löschen
copyUrlHover
.title = Adresse kopieren
deleteButtonHover = Löschen
copyUrlHover = Adresse kopieren
footerLinkLegal = Rechtliches
// Test Pilot is a proper name and should not be localized.
footerLinkAbout = Über Test Pilot
+8 -23
View File
@@ -8,7 +8,7 @@ uploadPageLearnMore = Dalšne informacije
uploadPageDropMessage = Śěgniśo swóju dataju sem, aby ju nagrał
uploadPageSizeMessage = Wužywajśo nejlěpje dataje, kótarež su mjeńše ako 1 GB za lěpšu spušćobnosć.
uploadPageBrowseButton = Wubjeŕśo dataju na swójom licadle
.title = Wubjeŕśo dataju na swójom licadle
uploadPageBrowseButton1 = Wubjeŕśo dataju za nagraśe
uploadPageMultipleFilesAlert = Nagrawanje někotarych datajow abo zarědnika se tuchylu njepódpěra.
uploadPageBrowseButtonTitle = Dataju nagraś
uploadingPageProgress = { $filename } ({ $size }) se nagrawa
@@ -19,52 +19,39 @@ decryptingFile = Dešifrěrujo se...
notifyUploadDone = Wašo nagraśe jo dokóńcone.
uploadingPageMessage = Gaž se waša dataja nagrawa, móžośo nastajenja spadnjenja póstajiś.
uploadingPageCancel = Nagraśe pśetergnus
.title = Nagraśe pśetergnus
uploadCancelNotification = Wašo nagraśe jo se pśetergnuło.
uploadingPageLargeFileMessage = Toś ta dataja jo wjelika a nagrawanje mógło chylku traś. Buźćo sćerpliwy!
uploadingFileNotification = K wěsći daś, gaž nagraśe jo dokóńcone.
uploadSuccessConfirmHeader = Gótowy za słanje
uploadSvgAlt
.alt = Nagraś
uploadSvgAlt = Nagraś
uploadSuccessTimingHeader = Wótkaz k wašej dataji pó 1 ześěgnjenju abo 24 góźinach spadnjo.
copyUrlFormLabelWithName = Kopěrujśo a źělśo wótkaz, aby swóju dataju pósłał: { $filename }
// Note: Title text for button should be the same.
copyUrlFormButton = Do mjazywótkłada kopěrowaś
.title = Do mjazywótkłada kopěrowaś
copiedUrl = Kopěrowany!
// Note: Title text for button should be the same.
deleteFileButton = Dataju wulašowaś
.title = Dataju wulašowaś
// Note: Title text for button should be the same.
sendAnotherFileLink = Drugu dataju pósłaś
.title = Drugu dataju pósłaś
// Alternative text used on the download link/button (indicates an action).
downloadAltText
.alt = Ześěgnuś
downloadAltText = Ześěgnuś
downloadFileName = { $filename } ześěgnuś
downloadFileSize = ({ $size })
// Firefox Send is a brand name and should not be localized.
downloadMessage = Waš pśijaśel wam dataju z Firefox Send sćelo, słužba, kótaraž wam zmóžnja, dataje pśez wěsty, priwatny a skoděrowany wótkaz źěliś, kótaryž awtomatiski spadnjo, až njeby waše daty na pśecej online wóstawali.
// Text and title used on the download link/button (indicates an action).
downloadButtonLabel = Ześěgnuś
.title = Ześěgnuś
downloadNotification = Wašo ześěgnjenje jo dokóńcone.
downloadFinish = Ześěgnjenje dokóńcone
// This message is displayed when uploading or downloading a file, e.g. "(1,3 MB of 10 MB)".
fileSizeProgress = ({ $partialSize } z { $totalSize })
// Firefox Send is a brand name and should not be localized. Title text for button should be the same.
// Firefox Send is a brand name and should not be localized.
sendYourFilesLink = Firefox Send wopytaś
.title = Firefox Send wopytaś
downloadingPageProgress = { $filename } ({ $size }) se ześěgujo
downloadingPageMessage = Pšosym wóstajśo toś ten rejtark wócynjony, mjaztym až wašu dataju ześěgujomy a dešifrěrujomy.
errorAltText
.alt = Nagrawańska zmólka
errorAltText = Nagrawańska zmólka
errorPageHeader = Něco njejo se raźiło!
errorPageMessage = Pśi nagrawanju dataje jo zmólka nastała.
errorPageLink = Drugu dataju pósłaś
fileTooBig = Toś ta dataja jo pśewjelika za nagraśe. Měła mjeńša ako { $size } byś.
linkExpiredAlt
.alt = Wótkaz spadnjony
linkExpiredAlt = Wótkaz spadnjony
expiredPageHeader = Toś ten wótkaz jo spadnjony abo njejo nigda eksistěrował!
notSupportedHeader = Waš wobglědowak se njepódpěra.
// Firefox Send is a brand name and should not be localized.
@@ -85,10 +72,8 @@ legalNoticeMozilla = Teke wužywanje websedła Firefox Send <a>pokazce priwatnos
deletePopupText = Toś tu dataju lašowaś?
deletePopupYes = Jo
deletePopupCancel = Pśetergnuś
deleteButtonHover
.title = Wulašowaś
copyUrlHover
.title = URL kopěrowaś
deleteButtonHover = Wulašowaś
copyUrlHover = URL kopěrowaś
footerLinkLegal = Pšawniske
// Test Pilot is a proper name and should not be localized.
footerLinkAbout = Wó Test Pilot

Some files were not shown because too many files have changed in this diff Show More