Compare commits

...
341 Commits
Author SHA1 Message Date
Armin Schrenk 0c0060262a prepare 1.9.0 2023-05-26 16:37:53 +02:00
Armin Schrenk 9af4ffe83b use correct webdav adapter version 2023-05-26 15:44:10 +02:00
Armin Schrenk c6f963793d bump dependencies 2023-05-26 13:10:11 +02:00
Armin Schrenk 8c34fc76c5 prevent regressions for google drive preset 2023-05-24 12:07:08 +02:00
Armin SchrenkandGitHub 785cf7a9a6 Merge pull request #2918 from cryptomator/feature/refactor-location-presets
Feature: Refactor finding and showing cloud location presets
2023-05-23 17:32:48 +02:00
Armin Schrenk c63837c4ce renaming class 2023-05-23 17:01:14 +02:00
Armin Schrenk b1a3ef9023 prevent dealing with unclosed directory streams 2023-05-23 12:35:14 +02:00
Armin Schrenk 32436f779f increase readability 2023-05-23 10:54:34 +02:00
Sebastian Stenzel ccc6f605ba Merge branch 'develop' into feature/refactor-location-presets 2023-05-23 10:19:00 +02:00
Sebastian Stenzel f338d2447b improved AutoUnlocker readability 2023-05-23 09:48:27 +02:00
Armin Schrenk 179240b325 Readd mac specifc google drive location provider 2023-05-23 09:44:37 +02:00
Armin Schrenk 32a65bddce Add OneDrive Mac location provider 2023-05-22 17:16:03 +02:00
Armin Schrenk 710cdf800d fix compile errors 2023-05-22 15:21:19 +02:00
Armin Schrenk 1d6edb8373 Apply code suggestions 2023-05-22 15:19:15 +02:00
Armin Schrenk a3d30612ec Add linux paths for Dropbox and OneDrive 2023-05-22 14:51:52 +02:00
Armin Schrenk 6acda9b13c also adjust styleClass of location label 2023-05-17 18:48:12 +02:00
Armin Schrenk 28cb812dab add uses field to module info 2023-05-17 18:38:24 +02:00
Armin Schrenk 68ea4af0ad use correct import 2023-05-17 17:26:37 +02:00
Armin Schrenk 0af0a9e440 refactor location ui in addVault workflow to new locationPreset framework 2023-05-17 17:21:02 +02:00
Armin Schrenk 0989c735c0 improve error handling when querying registry 2023-05-17 14:25:46 +02:00
Armin Schrenk a3492b9ea3 use correct registry keys for onedrive detection 2023-05-17 14:25:16 +02:00
Armin Schrenk e345e6415f use @CheckAvailability annotation correctly 2023-05-17 14:17:28 +02:00
Armin Schrenk 5b6d09308b Create SPI for cloud location presets 2023-05-16 17:16:42 +02:00
Armin SchrenkandGitHub 49bda58993 Merge pull request #2690 from Rexbas/auto-unlock
Auto unlock vaults that were missing at startup
2023-05-15 10:46:28 +02:00
Rexbas 32d7189a12 Add time unit parameter 2023-05-12 21:52:30 +02:00
Rexbas 1253b7db2b Make unlock method private and simplify missing vaults unlocker 2023-05-11 20:43:23 +02:00
Armin SchrenkandGitHub 067a7ad3ee Merge pull request #2897 from cryptomator/feature/jdk20
Upgrade to jdk20 and jfx20
2023-05-10 14:16:42 +02:00
Armin Schrenk a9ec76a344 update wix main file due to updated jpackage installer template 2023-05-09 17:40:13 +02:00
Armin Schrenk 085f762a35 further fixing debian 2023-05-09 15:48:06 +02:00
Armin Schrenk 7dd1c3576f always use the same JDK version in debian workflow 2023-05-09 15:02:15 +02:00
Armin Schrenk d23bd2865a update location preset for Dropbox 2023-05-09 14:56:44 +02:00
Armin Schrenk 4429d57b5e ensure mutability of temporary collection 2023-05-09 14:52:15 +02:00
Armin Schrenk 2ff71ed7b0 remove langauges with insufficient translation 2023-05-09 14:51:44 +02:00
Armin Schrenk 82de8b6994 remove unrelated change 2023-05-09 09:57:23 +02:00
Armin Schrenk d4cba2fd6e fix errors 2023-05-09 09:55:56 +02:00
ff80f634d2 Apply suggestions from code review
Co-authored-by: Sebastian Stenzel <overheadhunter@users.noreply.github.com>
2023-05-09 09:42:01 +02:00
Armin Schrenk 6386dd3d50 update workflows 2023-05-08 19:41:58 +02:00
Armin Schrenk a3f05db189 bump javafx 2023-05-08 19:41:02 +02:00
Armin Schrenk 151ef6c7b2 upgrade to jdk20
* use pattern matching preview feature
* bump fuse-nio-adapter
2023-05-08 19:12:35 +02:00
Rexbas 72fd38baf1 Add timeout to periodic missing vaults check 2023-05-06 15:40:24 +02:00
Tobias HagemannandGitHub 532ffb1202 Merge pull request #2882 from bluen/develop
Respect user's locale when sorting language list
2023-05-05 11:51:17 +02:00
Tobias Hagemann 2a704d5eb4 init collator once 2023-05-05 11:45:02 +02:00
Sebastian Stenzel e8f8466d9a adjusted labels used in auto-generated release notes
[ci skip]
2023-05-05 10:56:44 +02:00
Sebastian Stenzel 9297562c99 improve auto-generated release notes
[ci skip]
2023-05-05 10:52:51 +02:00
Jürgen Kleer 7d62fc78de Set preferred locale in constructor, make it default in applyPreferred 2023-04-27 18:03:41 +02:00
Rexbas ba627d0d60 Add a scheduled service to auto unlock vaults that were missing at startup 2023-04-27 11:06:09 +02:00
Jürgen Kleer 8e7e7de358 Refactoring
make LANGUAGE_TAGS private and provide a getter
2023-04-26 17:34:47 +02:00
Jürgen Kleer 10c60d7492 https://github.com/cryptomator/cryptomator/issues/2813
> List of languages should have system default, English and then all other languages in alphabetic order.
> That is, in alphabetic order with respect to the language the list is localized in (seems to be English always)
2023-04-26 15:24:50 +02:00
Armin Schrenk aa03bd119a Merge branch 'main' into develop 2023-04-25 10:45:51 +02:00
Armin Schrenk 325ffda9af Merge branch 'release/1.8.0' 2023-04-25 10:45:08 +02:00
Armin Schrenk d1270ceeb2 finalize 1.8.0 2023-04-25 10:44:41 +02:00
Armin Schrenk 901a290dd9 prepare 1.8.0 2023-04-24 17:35:25 +02:00
CryptobotandGitHub 35b9dadfc2 New Crowdin updates (#2848)
New translations strings.properties

Arabic; Belarusian; Bengali; Bosnian; Catalan; Chinese Simplified; Chinese Traditional; Chinese Traditional, Hong Kong; Croatian; Czech; Danish; Dutch; Filipino; French; Galician; German; Greek; Hebrew; Hindi; Hungarian; Indonesian; Italian; Japanese; Korean; Latvian; Macedonian; Norwegian Bokmal; Norwegian Nynorsk; Persian; Polish; Portuguese; Portuguese, Brazilian; Punjabi; Romanian; Russian; Serbian (Cyrillic); Serbian (Latin); Sinhala; Slovak; Slovenian; Spanish; Swahili, Tanzania; Swedish; Tamil; Telugu; Thai; Turkish; Ukrainian; Vietnamese; 

[ci skip]
2023-04-24 17:33:59 +02:00
Armin SchrenkandGitHub 5f57678edc Merge pull request #2840 from cryptomator/feature/convert-hub-to-local
Feature: convert hub-based vault to password-based
2023-04-21 15:31:28 +02:00
Tobias Hagemann 30e1922bc9 fixed spacing
[ci skip]
2023-04-21 15:23:06 +02:00
Armin Schrenk 2e0908ab15 replace config manually instead of using CryptoFileSystem.init() 2023-04-21 09:40:34 +02:00
Julian Raufelder 689ce5b985 Revive status and no-response bot 2023-04-20 15:38:57 +02:00
Tobias Hagemann a71a23aa31 replaced password bullet point with a different char that exists in open sans
[ci skip]
2023-04-18 16:36:27 +02:00
Tobias Hagemann 864454e6fc updated strings
[ci skip]
2023-04-18 16:03:05 +02:00
Armin Schrenk 94c3381723 forgot one renaming 2023-04-18 15:40:44 +02:00
d9f945e70a Apply suggestions from code review
more renaming

Co-authored-by: Tobias Hagemann <tobias.hagemann@skymatic.de>
2023-04-18 15:34:20 +02:00
Armin Schrenk dc9b39202f rename classes 2023-04-18 14:34:48 +02:00
Armin Schrenk 2a01aba3cf clean up 2023-04-17 12:51:36 +02:00
Armin Schrenk 4305fd3285 close also vault options window to prevent invalid state of options window 2023-04-17 12:50:46 +02:00
a24cd1ba7f Apply suggestions from code review
Co-authored-by: Tobias Hagemann <tobias.hagemann@skymatic.de>
2023-04-14 16:47:45 +02:00
Tobias Hagemann 2ba0d963ec updated insets
[ci skip]
2023-04-13 16:12:08 +02:00
Julian Raufelder cd0c6fbd33 Merge branch 'hotfix/1.7.5' into develop 2023-04-07 11:45:08 +02:00
Julian Raufelder f4374a2606 Merge branch 'hotfix/1.7.5' 2023-04-07 11:41:24 +02:00
Julian Raufelder a1d5b8a4e2 Prepare 1.7.5 2023-04-07 11:39:21 +02:00
Julian Raufelder 34e430aff6 Revert "bump cryptofs"
This reverts commit db2560fccf.
2023-04-07 11:35:38 +02:00
Armin Schrenk c79766cdf6 Merge branch 'main' into develop 2023-04-05 09:58:30 +02:00
Armin Schrenk bf76bad626 Merge branch 'release/1.7.4' 2023-04-05 09:57:55 +02:00
Armin Schrenk c3f654b454 finalize release 2023-04-05 09:56:34 +02:00
Armin Schrenk d1d990d47c prepare 1.7.4 2023-04-04 18:17:24 +02:00
CryptobotandGitHub 6052c0589e New Crowdin updates (#2800)
New translations strings.properties

Belarusian; Catalan; Chinese Simplified; Chinese Traditional; Chinese Traditional, Hong Kong; Danish; Dutch; French; German; Greek; Hebrew; Hungarian; Italian; Japanese; Norwegian Bokmal; Polish; Portuguese; Portuguese, Brazilian; Romanian; Russian; Slovak; Spanish; Swahili, Tanzania; Swedish; Turkish; 

[ci skip]
2023-04-04 18:15:07 +02:00
Armin Schrenk db2560fccf bump cryptofs 2023-04-04 13:44:19 +02:00
Armin Schrenk 3a50c32e50 rework convert button logic 2023-04-04 12:42:23 +02:00
Armin Schrenk 65eca31d26 integrate internationalization 2023-04-04 12:17:22 +02:00
Armin Schrenk 3462e0b540 further design adjustment 2023-04-03 10:42:25 +02:00
Armin Schrenk 697529136e use regular jdk 2023-03-31 18:27:35 +02:00
Armin Schrenk 50d31bdc18 integrate debug installer feature into regular windows ci workflow 2023-03-31 18:24:10 +02:00
Armin Schrenk 84caf96d3f closes #2814
Zulu JDK does not create required directory structure, so use temurin + gluon jfx jmods instead
2023-03-31 18:21:30 +02:00
Armin Schrenk a1a5fd3609 adjust design 2023-03-30 17:35:32 +02:00
Armin Schrenk 6c11cc8f1d complete workflow 2023-03-30 16:47:30 +02:00
Armin Schrenk 2b391a6ee3 Merge branch 'develop' into feature/convert-hub-to-local 2023-03-30 15:54:20 +02:00
Armin Schrenk b7fc03213d bump fuse-nio-adapter
Fixes #2801
2023-03-30 11:28:07 +02:00
Armin SchrenkandGitHub dfe17569e1 Merge pull request #2789 from cryptomator/feature/2786-only-restart-macfuset
Feature: Only require app restart if switching between macFUSE and FUSE-T
2023-03-30 11:23:09 +02:00
Armin Schrenk 827f9ad141 adjust comment 2023-03-30 11:18:28 +02:00
Armin Schrenk c8a6d0339e Use in volume preferences controller same objet as in MountModule to store first used fuse mount service 2023-03-29 17:42:18 +02:00
Tobias Hagemann b5bbd21f25 refactored the refactoring to a macfuse/fuse-t workaround again 2023-03-29 16:50:02 +02:00
Tobias Hagemann 771468c8c6 refactored macfuse/fuse-t specific workaround to a generic fuse workaround 2023-03-29 16:16:04 +02:00
Armin Schrenk ea2a48771f Closes #2829 2023-03-29 12:03:35 +02:00
Tobias Hagemann 0e10da25b3 Update README.md
[ci skip]
2023-03-29 11:58:14 +02:00
Armin Schrenk 943a3e9cfd adjust visibility 2023-03-29 11:42:14 +02:00
Armin Schrenk c988fb50a7 increase readability 2023-03-29 11:39:18 +02:00
Armin Schrenk 219ee0da9a implement core functionality 2023-03-28 14:02:11 +02:00
Armin Schrenk 5665e92839 deduplicate and add convenience method 2023-03-28 14:01:57 +02:00
Armin Schrenk 04ff188624 rename method in recoveryKeyFactory 2023-03-28 13:59:59 +02:00
Armin Schrenk ec7d6eafec add new password screen for convert hub vault flow 2023-03-24 18:11:39 +01:00
Armin Schrenk 28bb2ff9b1 add stub for vault conversion (hub to local) 2023-03-24 17:22:05 +01:00
Armin Schrenk a92ebfdc7b replace builder by stateless, threadsafe factory 2023-03-24 16:42:04 +01:00
Armin Schrenk f1e97fa64b fix workflow 2023-03-22 10:44:54 +01:00
Armin Schrenk b9d5cf04c2 fix workflow 2023-03-22 10:40:52 +01:00
Armin Schrenk 75cd3e44d8 change win-debug workflow to use temurin and openjfx jmods from gluon 2023-03-22 10:39:00 +01:00
Armin Schrenk 3cf1b829b8 make recovery key ui validation reusable 2023-03-20 21:40:16 +01:00
Armin Schrenk 6e4e9cd261 Merge branch 'develop' into feature/hub-local-access 2023-03-20 20:43:34 +01:00
Armin Schrenk e15dd7565f add workflow to build a windows debug launcher 2023-03-20 10:35:42 +01:00
Tobias Hagemann 77bc60fe5b Update README.md 2023-03-17 17:56:46 +01:00
Tobias HagemannandGitHub 9f633a1ecb Update README.md 2023-03-17 17:06:34 +01:00
Armin Schrenk fcf59d12a8 remove winget workflow 2023-03-15 16:47:34 +01:00
Armin Schrenk 6721075831 Merge branch 'main' into develop 2023-03-15 13:51:59 +01:00
Armin Schrenk 4bb0026415 Merge branch 'release/1.7.3' 2023-03-15 13:51:20 +01:00
Armin Schrenk bebae14744 finalize release 2023-03-15 13:51:09 +01:00
Armin Schrenk 997315eaf5 prepare 1.7.3 2023-03-15 13:49:53 +01:00
CryptobotandGitHub 16d677c40f New Crowdin updates (#2766)
New translations strings.properties

Belarusian; Catalan; Chinese Simplified; Chinese Traditional; Chinese Traditional, Hong Kong; French; German; Hebrew; Norwegian Bokmal; Russian; Swahili, Tanzania; Turkish; 

[ci skip]
2023-03-15 13:47:22 +01:00
Armin Schrenk 42a1913c17 Fixes #2797 and fixes #2760 2023-03-15 13:42:03 +01:00
Armin Schrenk c3f6655e48 add developer 2023-03-15 12:34:13 +01:00
Armin Schrenk fa1b0f2de8 reestablish interrupt state 2023-03-15 12:29:19 +01:00
Armin Schrenk 385574a618 prevent infinite loop 2023-03-15 12:10:15 +01:00
Armin Schrenk a67477bf3b Fixes #2778
ensure that mountpoint is ready
2023-03-15 11:40:44 +01:00
Armin Schrenk 03a362e9b4 fix compilation 2023-03-13 13:01:13 +01:00
Armin Schrenk 2223bc5e78 use correct selection logic 2023-03-13 12:58:34 +01:00
Armin Schrenk fdc0d2d6b5 only require restart in case if macFUSE or FUSE-T
Closes #2786
2023-03-13 12:44:56 +01:00
Armin Schrenk 58ed48b097 UI:
* remove restart notice for volume type
* only show restart label, when switching between macFUSE and FUSET
2023-03-13 11:17:56 +01:00
Julian Raufelder 7a0d255bd3 Use the same source tarball for signing that is linked in the release 2023-03-07 13:44:36 +01:00
Armin Schrenk 228fa099cb Merge branch 'main' into develop 2023-03-07 12:24:26 +01:00
Armin Schrenk a60ff20f15 Merge branch 'release/1.7.2' 2023-03-07 12:23:30 +01:00
Armin Schrenk 2328a5e3a8 finalize release 2023-03-07 12:19:35 +01:00
Armin Schrenk e7e181b1a5 Merge branch 'develop' into release/1.7.2 2023-03-07 12:19:23 +01:00
Armin Schrenk f3e7c08b43 deactivate winget workflow 2023-03-07 12:19:05 +01:00
Armin Schrenk 2a41afcfa9 prepare 1.7.2 2023-03-07 11:52:04 +01:00
CryptobotandGitHub 5bf38a328c New Crowdin updates (#2743)
New translations strings.properties

Arabic; Belarusian; Bosnian; Catalan; Chinese Simplified; Chinese Traditional; Chinese Traditional, Hong Kong; Croatian; Czech; Danish; Dutch; French; German; Greek; Hebrew; Hungarian; Indonesian; Italian; Japanese; Korean; Latvian; Norwegian Bokmal; Norwegian Nynorsk; Polish; Portuguese; Portuguese, Brazilian; Punjabi; Romanian; Russian; Serbian (Cyrillic); Serbian (Latin); Slovak; Spanish; Swahili, Tanzania; Swedish; Tamil; Turkish; Ukrainian; Vietnamese; 

[ci skip]
2023-03-07 11:49:50 +01:00
Armin Schrenk f983b29034 use correct docs URL for volume type 2023-03-07 11:40:10 +01:00
Armin Schrenk 4bc217e489 fixes #2761 2023-03-07 11:36:59 +01:00
Armin Schrenk b24f52a4ec fixes 2741 2023-03-07 10:58:34 +01:00
Armin Schrenk 91e7fa3de3 fixes #2758, fixes #2754 2023-03-06 15:58:02 +01:00
Armin Schrenk 1365efab3f use recommended notation of unit prefixes 2023-03-06 15:54:43 +01:00
Armin Schrenk 852963b785 check for correct WinFsp version 2023-03-06 15:50:21 +01:00
Armin Schrenk c47d4eaf02 Merge branch 'main' into develop 2023-03-03 16:37:45 +01:00
Armin Schrenk 36da26c6b9 Merge branch 'release/1.7.1' 2023-03-03 16:19:49 +01:00
Armin Schrenk 33e1cb3131 finalize release 2023-03-03 16:19:37 +01:00
Armin Schrenk ed4b433df0 prepare 1.7.1 2023-03-03 16:14:01 +01:00
Armin Schrenk d2ece543c8 suppress false positive 2023-03-03 16:04:34 +01:00
Armin Schrenk 4bb2df7d8f Fixes #2730 2023-03-03 16:03:36 +01:00
CryptobotandGitHub 4d5c6ca29a New Crowdin updates (#2712)
New translations strings.properties

Danish; German; Hebrew; 

[ci skip]

Closes #2724
2023-03-03 16:02:09 +01:00
Armin Schrenk f0d597ba73 require fuse3 packge for deb to have fusermount3 2023-03-01 19:28:40 +01:00
Armin Schrenk 310329d0b5 use correct javafx patch version for debia build 2023-03-01 15:51:42 +01:00
Julian Raufelder 30f86a7f2a Fix issue template 2023-03-01 15:23:30 +01:00
Armin Schrenk 5237dc8cae Merge branch 'main' into develop 2023-03-01 12:07:46 +01:00
Armin Schrenk 67ff4da05b Merge branch 'release/1.7.0' 2023-03-01 12:06:40 +01:00
Armin Schrenk 947eb11198 set correct version in pom 2023-03-01 12:06:25 +01:00
Armin Schrenk c6a9af1a04 update metainfo.xml 2023-03-01 12:03:03 +01:00
Armin Schrenk 0ddf221e26 Merge branch 'develop' into release/1.7.0 2023-03-01 11:43:49 +01:00
CryptobotandGitHub 3f2b5ccde9 New Crowdin updates (#2698)
New translations strings.properties

Chinese Simplified; Chinese Traditional; Chinese Traditional, Hong Kong; French; Japanese; 

[ci skip]
2023-03-01 11:42:57 +01:00
Armin Schrenk 4fc07c27b3 Merge branch 'develop' into feature/hub-local-access 2023-02-27 15:35:40 +01:00
Armin SchrenkandGitHub 3d0b6dde28 Update README.md 2023-02-27 13:09:56 +01:00
Armin Schrenk 45534b0a2b suppress false positive 2023-02-27 12:19:13 +01:00
Armin Schrenk 6d906beeb8 bump dependency-check 2023-02-27 12:17:47 +01:00
Tobias Hagemann e577c64c35 arm64 dmg installer (link + bg) for fuse-t 2023-02-27 11:06:19 +01:00
Armin Schrenk b848e78372 Merge branch 'develop' into release/1.7.0 2023-02-24 14:16:38 +01:00
Armin Schrenk 39e9395b4b bump fuse-nio-adapter 2023-02-24 14:16:20 +01:00
CryptobotandGitHub ca3157cc70 New Crowdin updates (#2695)
New translations strings.properties

Arabic; Belarusian; Bengali; Bosnian; Catalan; Chinese Simplified; Chinese Traditional; Chinese Traditional, Hong Kong; Croatian; Czech; Danish; Dutch; Filipino; French; Galician; German; Greek; Hebrew; Hindi; Hungarian; Indonesian; Italian; Japanese; Korean; Latvian; Macedonian; Norwegian Bokmal; Norwegian Nynorsk; Persian; Polish; Portuguese; Portuguese, Brazilian; Punjabi; Romanian; Russian; Serbian (Cyrillic); Serbian (Latin); Sinhala; Slovak; Slovenian; Spanish; Swahili, Tanzania; Swedish; Tamil; Telugu; Thai; Turkish; Ukrainian; Vietnamese; 

[ci skip]
2023-02-24 14:15:50 +01:00
Armin Schrenk f94c1f07d6 add new wix extension to ci build 2023-02-24 13:23:10 +01:00
Armin Schrenk d43f197c11 fix 67e566832c 2023-02-24 13:14:14 +01:00
Armin Schrenk 67e566832c use correct path to get winfsp download url 2023-02-24 13:13:07 +01:00
Armin Schrenk 6f5a88af1d extend winfsp uninstall instruction by reboot step 2023-02-24 13:10:15 +01:00
Armin Schrenk 210b891616 block exe installation if winFsp is outdated 2023-02-24 12:50:20 +01:00
Armin Schrenk 20e820c903 update IDE specific files 2023-02-24 12:48:41 +01:00
Armin Schrenk 5307e93c1b bump fuse-nio-adapter
fix illegalArgumentException when setting loopbackHostName
2023-02-24 12:48:29 +01:00
Armin Schrenk ec1d25bf65 Merge branch 'develop' into feature/hub-local-access 2023-02-23 21:10:03 +01:00
Armin Schrenk 7aa554498b move new password files to changepassword package 2023-02-23 13:00:51 +01:00
Armin Schrenk 85ac3c244d rename forgetPassword package 2023-02-23 12:55:30 +01:00
Armin Schrenk 5db5346c88 refactor error component to own package 2023-02-23 12:53:29 +01:00
Armin Schrenk e221019b57 Merge branch 'develop' into release/1.7.0 2023-02-23 12:09:03 +01:00
Armin Schrenk eeaaced976 reorder settingsJsonAdapter switch statements 2023-02-23 12:08:48 +01:00
Armin Schrenk d246b54268 ignore lastWrittenByVersion when reading settings 2023-02-23 12:00:14 +01:00
Armin Schrenk 8f4bf144c3 Merge branch 'develop' into feature/hub-local-access 2023-02-23 11:38:33 +01:00
Armin Schrenk e94572960e enable drag and drop for linux aswell 2023-02-23 11:16:48 +01:00
Armin Schrenk 2d1c59bea9 Renamed objects related to license exceeded user flow 2023-02-23 10:45:55 +01:00
Armin Schrenk 921cbd6439 Merge branch 'develop' into release/1.7.0 2023-02-22 17:47:14 +01:00
Armin Schrenk f811144ffa pom cleanup [ci skip] 2023-02-22 17:46:56 +01:00
Armin Schrenk 2ecc711f50 bump dependencies 2023-02-22 17:28:34 +01:00
Armin Schrenk cfcc8782ef bump cryptomator dependencies to stable versions 2023-02-22 17:19:40 +01:00
Armin Schrenk a1379bac40 For Windows try to migrate all user settings, not only the ones of local users 2023-02-22 15:33:37 +01:00
Armin Schrenk fe3f2b5bd3 Merge branch 'develop' into release/1.7.0 2023-02-22 15:14:43 +01:00
CryptobotandGitHub 7fc07ae02c New Crowdin updates (#2689)
New translations strings.properties

Arabic; Belarusian; Bosnian; Catalan; Chinese Simplified; Chinese Traditional; Chinese Traditional, Hong Kong; Croatian; Czech; Danish; Dutch; French; German; Greek; Hebrew; Hungarian; Indonesian; Italian; Japanese; Korean; Latvian; Norwegian Bokmal; Norwegian Nynorsk; Polish; Portuguese, Brazilian; Punjabi; Romanian; Russian; Serbian (Cyrillic); Slovak; Slovenian; Spanish; Swahili, Tanzania; Swedish; Turkish; Vietnamese; 

[ci skip]
2023-02-22 15:12:58 +01:00
Armin Schrenk 268c66a108 add hub specific tab to vault options 2023-02-21 23:18:00 +01:00
Armin SchrenkandGitHub 2a70e2f0f4 Merge pull request #2686 from cryptomator/feature/recovery-key-wrong-key
Display message if recovery key is not valid
2023-02-17 15:41:39 +01:00
Tobias Hagemann ffe0302fba updated access modifier 2023-02-17 15:33:00 +01:00
Armin Schrenk c5b86bc355 Closes #2648 2023-02-17 14:46:45 +01:00
Armin Schrenk 5f86473e3e fix recovery key state logic 2023-02-17 12:49:38 +01:00
Armin Schrenk a91c74b6eb Revert "Update translation key"
This reverts commit 71a09eae67.
2023-02-17 11:19:21 +01:00
76949d6ccb Update src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyRecoverController.java
Co-authored-by: Tobias Hagemann <tobias.hagemann@skymatic.de>
2023-02-17 11:18:55 +01:00
Armin Schrenk 71a09eae67 Update translation key 2023-02-17 10:59:04 +01:00
8087fcecfb Apply suggestions from code review
Co-authored-by: Tobias Hagemann <tobias.hagemann@skymatic.de>
2023-02-17 10:56:18 +01:00
Armin Schrenk 29c73e1bc8 display different messages if recovery key is either not valid or does not belong to the vault 2023-02-16 11:51:03 +01:00
Armin Schrenk 8bbdb69cda Update doc links to 1.7 2023-02-16 09:55:42 +01:00
Armin Schrenk e9ee15dcd5 add info about html comments to error form 2023-02-16 09:42:28 +01:00
Armin Schrenk 03f6e0a33c Use Label instead of Text 2023-02-15 23:44:51 +01:00
Armin Schrenk c5b21b0d8c Add warning about error report deletion to the error controller 2023-02-15 11:44:37 +01:00
Armin Schrenk c5c5e297b7 Fix getCiphertextPath for Windows again. 2023-02-14 17:39:34 +01:00
Armin Schrenk 24839985e9 Merge branch 'develop' into release/1.7.0 2023-02-14 11:40:10 +01:00
Armin Schrenk a7b2802f34 show correct error message when using custom mountpoint with webdav (Http address) 2023-02-14 11:39:16 +01:00
Armin Schrenk c85d0b4beb bump webdav-nio-adapter 2023-02-14 11:22:11 +01:00
Armin Schrenk 3dff3a8664 Fixes #2682
* allow windows installer to remove same version
* add revisionNumber to installer version
2023-02-14 11:20:22 +01:00
Armin Schrenk 5b0bbf539b improve FailOnRunningApp action 2023-02-13 23:34:43 +01:00
Armin Schrenk 1ff7c40fd9 Fixes #2672 and fixes #2668 2023-02-13 10:42:17 +01:00
Armin SchrenkandGitHub d0875ef49e Merge pull request #2669 from cryptomator/feature/virtual-volume-doc-link
Add link to volume type documentation
2023-02-09 13:06:03 +01:00
Armin Schrenk e35ed9af72 enable localization of tooltip 2023-02-08 20:11:34 +01:00
Armin Schrenk ac43efe149 change UI to be not so clunky:
* only use question mark icon
* use tooltip at icon instead of explicit label
* icon is the hyperlink
2023-02-08 11:33:41 +01:00
Armin Schrenk 202a2ea79f Load revealPathServiceProvider at app startup 2023-02-08 11:14:54 +01:00
Armin Schrenk c19a86a348 add link to mounting documentation 2023-02-07 15:23:04 +01:00
Armin Schrenk 539dcaa85a Update issue template 2023-02-07 12:23:25 +01:00
Armin Schrenk fb91c1a461 Merge branch 'develop' into release/1.7.0 2023-02-06 14:45:56 +01:00
CryptobotandGitHub bd75370dfd New Crowdin updates (#2646)
New translations strings.properties

Catalan; Chinese Simplified; Dutch; Italian; Persian; Polish; Slovak;

[ci skip]
2023-02-06 14:44:45 +01:00
Armin Schrenk 7a9a9cf4eb Follow up of 69d73d0fb9: Remove standalone launchers 2023-02-06 12:31:56 +01:00
Armin Schrenk 489e9fce90 bump integrations-win to 1.2.0-beta2
Closes #2657
2023-02-03 13:19:53 +01:00
Armin Schrenk d378d84832 bump fuse-nio-adapter 2023-02-03 13:19:43 +01:00
Armin Schrenk 69d73d0fb9 Remove standalone launchers 2023-02-03 13:15:03 +01:00
Armin Schrenk 97c0cb4f5f add to settings.json the app version written to it last 2023-02-02 16:44:03 +01:00
Armin Schrenk b4faae7fa0 make debug logs readable by filter out internal fuse-nio locking 2023-02-02 10:36:31 +01:00
Armin Schrenk 55d76b65cc Add IOException to log message during revealPath 2023-02-01 22:31:27 +01:00
Armin Schrenk fd6e1e6741 fix bug 2023-02-01 19:23:28 +01:00
Armin Schrenk 155558caa8 add style class to text object 2023-02-01 13:50:56 +01:00
Armin Schrenk 28217b2de3 only perform mountpoint move and cleanup, if mountpoint is not a drive letter 2023-02-01 13:44:57 +01:00
Armin SchrenkandGitHub b9e57ce895 Merge pull request #2654 from cryptomator/feature/2652-migrate-dir-mounts
Feature/2652 migrate dir mounts
2023-02-01 11:17:11 +01:00
Armin Schrenk 95ea23ee6e add more comments regarding removal evaluation of this workaround 2023-02-01 11:07:23 +01:00
Armin Schrenk c269184217 ensure that settings.json is a file 2023-01-31 18:05:31 +01:00
Armin Schrenk 68d32957e4 fix errors 2023-01-31 16:37:25 +01:00
Armin Schrenk a771f0a5b7 doc doc doc 2023-01-31 13:59:18 +01:00
Armin Schrenk e56e6a8359 integrate script into installer 2023-01-31 13:58:56 +01:00
Armin Schrenk 5f9b77241f extend migration script to all local users 2023-01-31 13:40:25 +01:00
Armin Schrenk fb54ee04a6 Remove Dokany advertisement from msi installer 2023-01-30 13:32:56 +01:00
Armin Schrenk a106b04c7e prototpye for powershell script to be executed after installation 2023-01-30 13:30:06 +01:00
Armin Schrenk 285d48b70b Merge branch 'develop' into release/1.7.0 2023-01-27 13:27:31 +01:00
Armin Schrenk 0d8d7e4ee5 fix debian artifact upload 2023-01-27 13:27:03 +01:00
Armin Schrenk f232f9d958 Merge branch 'develop' into release/1.7.0 2023-01-27 12:31:00 +01:00
Armin Schrenk 88c3b0cc4f remove tag-name from release action to just add to current release on debian build 2023-01-27 12:30:44 +01:00
Armin Schrenk ef190db739 Merge branch 'develop' into release/1.7.0 2023-01-27 11:36:28 +01:00
CryptobotandGitHub b378354bb9 New Crowdin updates (#2562)
New translations strings.properties

Arabic; Belarusian; Bengali; Bosnian; Catalan; Chinese Simplified; Chinese Traditional; Chinese Traditional, Hong Kong; Croatian(Cyrillic); Czech; Danish; Dutch; Filipino; French; Galician; German; Greek; Hebrew; Hindi; Hungarian; Indonesian; Italian; Japanese; Korean( Latin); Latvian; Macedonian; Norwegian Bokmal; Norwegian Nynorsk; Persian; Polish; Portuguese; Portuguese, Brazilian; Punjabi; Romanian; Russian; Sinhala; Slovak; Slovenian; Spanish; Swahili, Tanzania; Swedish; Tamil; Telugu; Thai; Turkish; Ukrainian; Vietnamese; 

[ci skip]
2023-01-27 11:35:50 +01:00
Armin Schrenk 822e863e27 partially revert 220782b84f 2023-01-26 16:29:43 +01:00
Armin Schrenk 40fbe4f59d remove more libffi workaround leftovers 2023-01-26 16:05:53 +01:00
Tobias Hagemann bf779b5b41 updated dmg background 2023-01-26 15:57:10 +01:00
Tobias Hagemann ce5dbd14d8 reverted be7ac50928 2023-01-26 15:57:10 +01:00
Armin Schrenk 48744018a2 Merge branch 'release/1.7.0' into develop 2023-01-26 15:56:48 +01:00
Armin Schrenk bd9f79cb56 add cryptomator.mountPointsDir property to macOS installer scripts 2023-01-26 15:54:31 +01:00
Armin Schrenk f4c4f72539 remove libjffi stuff from appimage 2023-01-26 14:31:23 +01:00
Armin Schrenk 74718754ad fix merge 2023-01-26 13:48:30 +01:00
Armin Schrenk eb595379d6 Merge branch 'develop' into release/1.7.0
# Conflicts:
#	dist/linux/debian/control
#	dist/linux/debian/cryptomator.sh
2023-01-26 13:47:46 +01:00
Armin Schrenk 220782b84f reduce jars neede to stay on classpath due to missing module info 2023-01-26 13:28:55 +01:00
Armin SchrenkandGitHub 1c104737c1 Merge pull request #2639 from cryptomator/feature/mount-provider
Refactoring: Use mount service
2023-01-26 13:20:11 +01:00
Armin Schrenk 7c8a519919 bump webdav-nio-adapter 2023-01-26 13:10:32 +01:00
Armin Schrenk ae1fa5851f remove traces of ActualMountService from volume preferences controller 2023-01-26 13:02:21 +01:00
Armin Schrenk 86ccb1a58f changing volume provider requires restart due to macFUSE/FUSE-T lib loaded in same JVM 2023-01-26 12:05:34 +01:00
Armin Schrenk c3fb58f7d0 bump fuse-nio-adapter 2023-01-25 16:49:00 +01:00
Armin Schrenk b4c384acc9 use speciaized translation key 2023-01-25 12:44:09 +01:00
Armin Schrenk 8580e97791 cleanup 2023-01-23 14:39:46 +01:00
Armin Schrenk 5d348ee229 Bump WebDAV dependency 2023-01-23 14:39:21 +01:00
Armin Schrenk dda0ff545c add point of automatic mount point selection 2023-01-23 13:47:00 +01:00
Armin Schrenk 708b5938ac Add info about the dependency of volume type and mountOptions 2023-01-23 13:11:01 +01:00
Armin SchrenkandGitHub a3cb8cd2f1 Merge pull request #2641 from purejava/jdk.security.auth
Add jdk.security.auth module as it's required by dbus-java-core

Closes #2640
2023-01-23 11:10:59 +01:00
Armin Schrenk 3587d53d15 bump integrations-mac, fixes NoSuchServiceException for RevealPathService on macOS 2023-01-23 11:09:15 +01:00
Tobias HagemannandGitHub 2f5e2af8d9 Merge pull request #2638 from cryptomator/feature/traymenu-onbeforeopenmenu-macos-fix
Fixed vault list refresh when tray icon is clicked on macOS
2023-01-23 10:24:57 +01:00
Ralph PlawetzkiandGitHub 8139cb8c38 Add jdk.security.auth module to rules 2023-01-22 20:05:13 +01:00
Armin Schrenk 09d5f71335 do not reset mountflags to default ones when window opens 2023-01-22 19:24:35 +01:00
Ralph Plawetzki 3a638735b7 Add jdk.security.auth module to appimage.yml 2023-01-22 18:11:50 +01:00
Ralph Plawetzki f1f5f7e02f Add jdk.security.auth module as it's required by dbus-java-core 2023-01-22 17:59:20 +01:00
Tobias Hagemann 94fe8ca449 updated string
[ci skip]
2023-01-20 17:18:05 +01:00
Tobias Hagemann 1251e1b873 updated separator styling 2023-01-20 17:14:02 +01:00
Armin Schrenk 50405c0bd5 remove debug message 2023-01-20 17:07:19 +01:00
Armin Schrenk 774d24625c change styling of volume preferences 2023-01-20 17:07:04 +01:00
Tobias Hagemann ba4902a5bc Fixed vault list refresh when tray icon is clicked on macOS 2023-01-20 16:45:35 +01:00
Armin Schrenk 90408504e2 Merge branch 'develop' into feature/mount-provider
# Conflicts:
#	pom.xml
#	src/main/java/org/cryptomator/common/vaults/Vault.java
#	src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnlockedController.java
2023-01-20 15:27:48 +01:00
Armin Schrenk c8c44e0554 bump fuse-nio-adapter dependency 2023-01-20 15:01:31 +01:00
Armin Schrenk 7afab6fe78 add auto option to volume type selection 2023-01-20 12:29:17 +01:00
Armin Schrenk ad321dfe55 migrate 1.6.x volumeimpl to hardcoded mountservices 2023-01-20 11:49:15 +01:00
d6388d6205 Added drop zone for revealing encrypted files or folders (#2592)
* Added drop zone for revealing encrypted files or folders

* Split god drop zone into distinct drop zones in vault list and vault detail unlocked

* Prevent cursor from changing if content doesn't match during drag over

[ci skip]

* Removed unused methods / css classes

[ci skip]

* Updated method name

* Refactor Vault::getCiphertextPath to only accept strings starting with "/"

* bump cryptofs

* ensure that path cleartext path always starts with "/"

* added file chooser for revealing encrypted items

* Trying to fix path parsing again

* Updated drag & drop design for buttons

* use RevealPathService to reveal files in file manager

* fix compilation error

* Copy paths to clipboard if no revealService is present

* reintegrate wongFileAlert

* Only accept TrasnferMode.LINK

* updated drag-n-drop button styling

* added tooltip

* updated string

* cleanup

Co-authored-by: Armin Schrenk <armin.schrenk@skymatic.de>
2023-01-20 10:46:00 +01:00
Armin SchrenkandGitHub b8326907bf Merge pull request #2624 from purejava/update-appimage-build-script
Update build.sh to .github/workflows/appimage.yml
2023-01-19 13:37:10 +01:00
Armin Schrenk 5beeeae27f Sign integrations.dll during build 2023-01-16 18:47:41 +01:00
Armin Schrenk fb1f3c4757 fix bug using wrong mount flags 2023-01-16 14:14:03 +01:00
Armin Schrenk 5e32cbcdd0 show supported mount features in preferences/volume 2023-01-13 18:11:36 +01:00
Armin Schrenk 08d741ecf5 address TODOs 2023-01-13 16:24:15 +01:00
Armin Schrenk 23060a8497 reinitate workaround for MOUNT_WITHIN_PARENT 2023-01-13 15:59:44 +01:00
Armin Schrenk 47a32893f0 Refactor mounter class 2023-01-13 13:46:41 +01:00
Armin Schrenk 0f7ba4e00e remove updating driveletter strings 2023-01-13 12:53:41 +01:00
Armin Schrenk 0d75b999a3 cleanup 2023-01-13 12:50:38 +01:00
Armin Schrenk b6d97528d2 fix driveletter selection 2023-01-13 12:49:20 +01:00
Armin Schrenk 94c53989b1 MountOptions window: Reset to auto mount, if no dir selected 2023-01-13 11:27:30 +01:00
Armin Schrenk a72ea1b9f5 move mount prepartions to own class 2023-01-13 11:20:23 +01:00
Armin Schrenk 6395f17736 Handle illegelArgumentException when setting custom mountpoint 2023-01-12 17:21:54 +01:00
Armin Schrenk 5c61944757 fix minor ui bugs 2023-01-12 12:53:58 +01:00
Armin Schrenk c641695a40 migrate 1.6.x vault settings on-the-fly 2023-01-12 12:11:03 +01:00
Armin Schrenk d93ef2e905 Reinitiate force lock 2023-01-11 16:40:14 +01:00
Armin Schrenk 8b9377cf4e only fix custom mount flags, if explicitly desired. Otherwise use the ones provided by mount service 2023-01-11 16:35:12 +01:00
Armin Schrenk 991b03e000 use function paramter, not instance variable 2023-01-11 16:21:49 +01:00
Armin Schrenk 73d8c4098e resolve TODOs 2023-01-11 16:18:05 +01:00
Armin Schrenk 6a52d15510 Show mountpath in reveal button 2023-01-11 16:01:59 +01:00
Armin Schrenk d07b1b96dd Use first available mount provider if none is selected or selected is not present 2023-01-11 16:01:51 +01:00
Armin Schrenk 24d472ed8b Merge branch 'develop' into feature/mount-provider
# Conflicts:
#	dist/linux/appimage/build.sh
#	dist/linux/debian/rules
2023-01-11 16:01:27 +01:00
Armin Schrenk 6fe2d73c52 copy uri to clipboard when using fallback mounter 2023-01-11 15:59:39 +01:00
Armin Schrenk 523e5d7904 bump webdav- and dokany-adapter 2023-01-11 15:59:17 +01:00
Tobias Hagemann 304064d9ab updated dependency-check version 2023-01-09 11:59:51 +01:00
Tobias Hagemann 0d49c60d4d reverted 1a6258eb17 2023-01-09 11:32:11 +01:00
Ralph Plawetzki 0e0e00f116 Remove stuff not needed when run locally
From: changes requested for PR #2624
2023-01-08 14:10:38 +01:00
Ralph Plawetzki 77c0a3e265 Update build.sh to .github/workflows/appimage.yml 2023-01-07 15:31:32 +01:00
Tobias Hagemann 1807888860 updated sponsors
[ci skip]
2023-01-05 11:16:22 +01:00
Tobias Hagemann be7ac50928 added new app icon for macos, fixes #2517 2023-01-04 16:32:40 +01:00
Julian Raufelder 9182c415eb Hello 2023 🎉 2023-01-04 13:35:58 +01:00
Armin Schrenk 1a6258eb17 revert eea568ca4e and e2898f0c8b 2023-01-04 12:52:16 +01:00
Armin SchrenkandGitHub 9c0c6a91fb Merge pull request #2580 from jacob-willden/develop
Add more info to Migration Screen
2023-01-03 16:47:18 +01:00
Armin Schrenk 53436520c9 fix using the wrong property 2023-01-03 12:38:18 +01:00
Armin Schrenk fd5aeaf90a Merge branch 'develop' into feature/mount-setting-per-vault 2023-01-02 13:47:30 +01:00
Armin Schrenk f3fcfc913b Remove unused class 2023-01-02 12:10:46 +01:00
Armin SchrenkandGitHub 0b0870e313 Merge pull request #2575 from VsevolodGolovanov/issue_2557_unlocked_status_indicator_in_tray_icon
Unlocked status indicator in tray icon 

Closes #2557
2022-12-30 11:40:51 +01:00
Armin SchrenkandGitHub 6704bb1f8c Merge pull request #2612 from cryptomator/feature/2597-no-keychain-dialog
Feature: Show dialog for hub vaults, if keychain is disabled'

Closes #2597
2022-12-30 11:32:40 +01:00
Armin Schrenk 48d1938b99 Refine dialog text 2022-12-30 11:19:37 +01:00
Armin Schrenk 6199277002 Add Button to open preferences 2022-12-29 18:26:13 +01:00
Armin Schrenk 9fefe8e462 Show info dialog when keychain is deactivated 2022-12-29 18:20:46 +01:00
Armin Schrenk 5fcd53be18 load device key before showing UI to prevent uncatched failure of UI loading 2022-12-29 18:17:47 +01:00
Jacob Willden 7147636428 Switch term for new vault migration dialog 2022-12-21 18:56:17 -07:00
Jacob Willden 690bd833e8 Add more info to Migration Screen 2022-12-16 13:28:57 -07:00
1e12590681 Update src/main/java/org/cryptomator/ui/traymenu/AwtTrayMenuController.java
Co-authored-by: Tobias Hagemann <tobias.hagemann@gmail.com>
2022-12-15 13:34:52 +04:00
Tobias Hagemann eea568ca4e GCM is explicitly ready! 2022-12-14 22:27:34 +01:00
Armin Schrenk 8009205da7 Merge branch 'main' into develop
# Conflicts:
#	pom.xml
2022-12-14 20:07:24 +01:00
Armin Schrenk c0f73a2802 Merge branch 'hotfix/1.6.17' 2022-12-14 20:06:35 +01:00
Armin Schrenk 8e902877a3 Update dependency-check plugin and exclude false positive
(cherry picked from commit ebcd0adf78)
2022-12-14 20:06:23 +01:00
Armin Schrenk fd76c89393 update metainfo 2022-12-14 20:02:12 +01:00
Armin Schrenk 975baf594c Fixes #2576 2022-12-14 19:58:22 +01:00
Vsevolod Golovanov 5a99c7bb61 Unlocked status indicator in tray icon #2557
Now tracking unlockedness and updating the icon accordingly.
2022-12-14 21:18:37 +04:00
Tobias Hagemann e2898f0c8b GCM is ready! 2022-12-14 17:36:06 +01:00
Tobias Hagemann cf2b236df5 added tray icons for unlocked state 2022-12-14 17:28:59 +01:00
Tobias Hagemann 819fa803f3 cleaned up tray icons 2022-12-14 16:47:07 +01:00
Armin Schrenk 980e2b184b use correct tag name for gh release in debian workflow 2022-12-13 12:48:29 +01:00
Sebastian Stenzel ebad677e84 fix path to downloaded jmod files 2022-12-12 09:14:24 +01:00
Sebastian Stenzel 4fda4a2b2e fix makefile 2022-12-12 09:09:25 +01:00
Sebastian Stenzel ffaf7ad360 adjust package dependencies to new mount api and jfuse 2022-12-12 09:03:56 +01:00
Sebastian Stenzel 76689705f5 remove LD_PRELOAD workaround, which should no longer be required with jfuse 2022-12-12 08:54:18 +01:00
Armin Schrenk 0d6d7b0dd6 directly use inputs object 2022-12-09 16:56:45 +01:00
Armin Schrenk 9dfd8adcce revert 0725a63b09 and fix workflow 2022-12-09 16:56:02 +01:00
Armin Schrenk 433eecc6a8 adjust matching rules for version type detection
(cherry picked from commit cd358916260e713d4119c20b1bcb5b448a017365)
2022-12-09 16:50:39 +01:00
Armin Schrenk 36ed4554b2 Fixes #2570
Dabian build: Make libffi7 a runtime dependency and preload it.
2022-12-09 15:12:04 +01:00
233 changed files with 6164 additions and 2517 deletions
+10 -5
View File
@@ -37,12 +37,17 @@ body:
id: volume-type
attributes:
label: Volume Type
description: What is selected under Settings → Virtual Drive?
multiple: true
description: What volume type is selected under Settings → Virtual Drive?
options:
- FUSE
- Dokany
- WebDAV
- WinFsp
- WinFsp (Local Drive)
- FUSE-T
- macFUSE
- WebDAV (Windows Explorer)
- WebDAV (AppleScript)
- WebDAV (gio)
- WebDAV (HTTP Address)
- Dokany (1.5)
validations:
required: false
- type: textarea
-13
View File
@@ -1,13 +0,0 @@
# Configuration for probot-no-response - https://github.com/probot/no-response
# Number of days of inactivity before an Issue is closed for lack of response
daysUntilClose: 14
# Label requiring a response
responseRequiredLabel: state:awaiting-response
# Comment to post when closing an Issue for lack of response. Set to `false` to disable
closeComment: >
This issue has been automatically closed because there has been no response
to our request for more information from the original author. With only the
information that is currently in the issue, we don't have enough information
to take action. Please reach out if you have or find the answers we need so
that we can investigate further.
+29
View File
@@ -0,0 +1,29 @@
# .github/release.yml
# see https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes#configuring-automatically-generated-release-notes
changelog:
exclude:
authors:
- cryptobot
- dependabot
- github-actions
categories:
- title: What's New 🎉
labels:
- type:feature-request
- type:enhancement
- title: Bugfixes 🐛
labels:
- type:security-issue
- type:bug
- type:minor-bug
- title: Other Changes 📎
labels:
- "*"
exclude:
labels:
- type:feature-request
- type:enhancement
- type:security-issue
- type:bug
- type:minor-bug
-24
View File
@@ -1,24 +0,0 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 365
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 90
# Issues with these labels will never be considered stale
exemptLabels:
- type:security-issue # never close automatically
- type:feature-request # never close automatically
- type:enhancement # never close automatically
- type:upstream-bug # never close automatically
- state:awaiting-response # handled by different bot
- state:blocked
- state:confirmed
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: true
# Label to use when marking an issue as stale
staleLabel: state:stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
+4 -11
View File
@@ -10,13 +10,13 @@ on:
required: false
env:
JAVA_VERSION: 19
JAVA_VERSION: 20
jobs:
get-version:
uses: ./.github/workflows/get-version.yml
with:
version: ${{ github.event.inputs.version }}
version: ${{ inputs.version }}
build:
name: Build AppImage
@@ -47,7 +47,6 @@ jobs:
- name: Patch target dir
run: |
cp LICENSE.txt target
cp dist/linux/launcher.sh target
cp target/cryptomator-*.jar target/mods
- name: Run jlink
run: >
@@ -55,7 +54,7 @@ jobs:
--verbose
--output runtime
--module-path "${JAVA_HOME}/jmods"
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.security.auth,jdk.accessibility,jdk.management.jfr
--strip-native-commands
--no-header-files
--no-man-pages
@@ -78,7 +77,7 @@ jobs:
--dest appdir
--name Cryptomator
--vendor "Skymatic GmbH"
--copyright "(C) 2016 - 2022 Skymatic GmbH"
--copyright "(C) 2016 - 2023 Skymatic GmbH"
--app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}"
--java-options "--enable-preview"
--java-options "--enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64"
@@ -111,12 +110,6 @@ jobs:
ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/.DirIcon
ln -s usr/share/applications/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/Cryptomator.desktop
ln -s bin/cryptomator.sh Cryptomator.AppDir/AppRun
- name: Extract libjffi.so # workaround for https://github.com/cryptomator/cryptomator-linux/issues/27
run: |
JFFI_NATIVE_JAR=`ls lib/app/ | grep -e 'jffi-[1-9]\.[0-9]\{1,2\}.[0-9]\{1,2\}-native.jar'`
${JAVA_HOME}/bin/jar -xf lib/app/${JFFI_NATIVE_JAR} /jni/x86_64-Linux/
mv jni/x86_64-Linux/* lib/app/libjffi.so
working-directory: Cryptomator.AppDir
- name: Download AppImageKit
run: |
curl -L https://github.com/AppImage/AppImageKit/releases/download/13/appimagetool-x86_64.AppImage -o appimagetool.AppImage
+5 -1
View File
@@ -6,7 +6,7 @@ on:
types: [labeled]
env:
JAVA_VERSION: 19
JAVA_VERSION: 20
defaults:
run:
@@ -53,4 +53,8 @@ jobs:
body: |-
:construction: Work in Progress
Please be patient, the builds are still running. We will publish new versions of Cryptomator here in a few moments.
As usual, the GPG signatures can be checked using [our public key `5811 7AFA 1F85 B3EE C154 677D 615D 449F E6E6 A235`](https://gist.github.com/cryptobot/211111cf092037490275f39d408f461a).
---
<!-- Don't forget to include the 💾 SHA-256 checksums of release artifacts: -->
+11 -14
View File
@@ -19,9 +19,9 @@ on:
type: boolean
env:
JAVA_VERSION: 19
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/19/openjfx-19_linux-x64_bin-jmods.zip'
OPENJFX_JMODS_AARCH64: 'https://download2.gluonhq.com/openjfx/19/openjfx-19_linux-aarch64_bin-jmods.zip'
JAVA_VERSION: 20
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/20.0.1/openjfx-20.0.1_linux-x64_bin-jmods.zip'
OPENJFX_JMODS_AARCH64: 'https://download2.gluonhq.com/openjfx/20.0.1/openjfx-20.0.1_linux-aarch64_bin-jmods.zip'
jobs:
build:
@@ -45,7 +45,7 @@ jobs:
run: |
sudo add-apt-repository ppa:coffeelibs/openjdk
sudo apt-get update
sudo apt-get install debhelper devscripts dput coffeelibs-jdk-19 libgtk2.0-0
sudo apt-get install debhelper devscripts dput coffeelibs-jdk-${{ env.JAVA_VERSION }} libgtk2.0-0
- name: Setup Java
uses: actions/setup-java@v3
with:
@@ -65,10 +65,10 @@ jobs:
unzip -j openjfx-aarch64.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d jmods/aarch64
- name: Ensure major jfx version in pom and in jmods is the same
run: |
JMOD_VERSION_AMD64=$(jmod describe ${JAVA_HOME}/jmods/amd64/javafx.base.jmod | head -1)
JMOD_VERSION_AMD64=$(jmod describe jmods/amd64/javafx.base.jmod | head -1)
JMOD_VERSION_AMD64=${JMOD_VERSION_AMD64#*@}
JMOD_VERSION_AMD64=${JMOD_VERSION_AMD64%%.*}
JMOD_VERSION_AARCH64=$(jmod describe ${JAVA_HOME}/jmods/aarch64/javafx.base.jmod | head -1)
JMOD_VERSION_AARCH64=$(jmod describe jmods/aarch64/javafx.base.jmod | head -1)
JMOD_VERSION_AARCH64=${JMOD_VERSION_AARCH64#*@}
JMOD_VERSION_AARCH64=${JMOD_VERSION_AARCH64%%.*}
POM_JFX_VERSION=$(mvn help:evaluate "-Dexpression=javafx.version" -q -DforceStdout)
@@ -148,11 +148,8 @@ jobs:
echo "TAG_NAME=${REF##*/}" >> $GITHUB_ENV
- name: Publish Debian package on GitHub Releases
if: startsWith(inputs.ref, 'refs/tags/')
uses: softprops/action-gh-release@v1
with:
fail_on_unmatched_files: true
tag_name: ${{ github.env.TAG_NAME }}
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
files: |
cryptomator_*_amd64.deb
cryptomator_*.asc
env:
GITHUB_TOKEN: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
run: |
artifacts=$(ls | grep cryptomator*.deb)
gh release upload ${{ env.TAG_NAME }} $artifacts
+1 -1
View File
@@ -22,7 +22,7 @@ on:
value: ${{ jobs.determine-version.outputs.type }}
env:
JAVA_VERSION: 19
JAVA_VERSION: 20
JAVA_DIST: 'temurin'
JAVA_CACHE: 'maven'
+10 -8
View File
@@ -10,13 +10,13 @@ on:
required: false
env:
JAVA_VERSION: 19
JAVA_VERSION: 20
jobs:
get-version:
uses: ./.github/workflows/get-version.yml
with:
version: ${{ github.event.inputs.version }}
version: ${{ inputs.version }}
build:
name: Build Cryptomator.app for ${{ matrix.output-suffix }}
@@ -30,10 +30,12 @@ jobs:
architecture: x64
output-suffix: x64
xcode-path: '/Applications/Xcode_13.2.1.app'
fuse-lib: macFUSE
- os: [self-hosted, macOS, ARM64]
architecture: aarch64
output-suffix: arm64
xcode-path: '/Applications/Xcode_13.2.1.app'
fuse-lib: FUSE-T
steps:
- uses: actions/checkout@v3
- name: Setup Java
@@ -61,7 +63,6 @@ jobs:
- name: Patch target dir
run: |
cp LICENSE.txt target
cp dist/mac/launcher.sh target
cp target/cryptomator-*.jar target/mods
- name: Run jlink
run: >
@@ -87,7 +88,7 @@ jobs:
--dest appdir
--name Cryptomator
--vendor "Skymatic GmbH"
--copyright "(C) 2016 - 2022 Skymatic GmbH"
--copyright "(C) 2016 - 2023 Skymatic GmbH"
--app-version "${{ needs.get-version.outputs.semVerNum }}"
--java-options "--enable-preview"
--java-options "--enable-native-access=org.cryptomator.jfuse.mac"
@@ -103,6 +104,7 @@ jobs:
--java-options "-Dcryptomator.p12Path=\"~/Library/Application Support/Cryptomator/key.p12\""
--java-options "-Dcryptomator.ipcSocketPath=\"~/Library/Application Support/Cryptomator/ipc.socket\""
--java-options "-Dcryptomator.integrationsMac.keychainServiceName=\"Cryptomator\""
--java-options "-Dcryptomator.mountPointsDir=\"~/Cryptomator\""
--java-options "-Dcryptomator.showTrayIcon=true"
--java-options "-Dcryptomator.buildNumber=\"dmg-${{ needs.get-version.outputs.revNum }}\""
--mac-package-identifier org.cryptomator
@@ -177,7 +179,7 @@ jobs:
run: |
mkdir dmg
mv Cryptomator.app dmg
cp dist/mac/dmg/resources/macFUSE.webloc dmg
cp dist/mac/dmg/resources/${{ matrix.fuse-lib }}.webloc dmg
ls -l dmg
- name: Install create-dmg
run: |
@@ -188,14 +190,14 @@ jobs:
create-dmg
--volname Cryptomator
--volicon "dist/mac/dmg/resources/Cryptomator-Volume.icns"
--background "dist/mac/dmg/resources/Cryptomator-background.tiff"
--background "dist/mac/dmg/resources/Cryptomator-${{ matrix.fuse-lib }}-background.tiff"
--window-pos 400 100
--window-size 640 694
--icon-size 128
--icon "Cryptomator.app" 128 245
--hide-extension "Cryptomator.app"
--icon "macFUSE.webloc" 320 501
--hide-extension "macFUSE.webloc"
--icon "${{ matrix.fuse-lib }}.webloc" 320 501
--hide-extension "${{ matrix.fuse-lib }}.webloc"
--app-drop-link 512 245
--eula "dist/mac/dmg/resources/license.rtf"
--icon ".background" 128 758
+22
View File
@@ -0,0 +1,22 @@
# Configuration for close-stale-issues - https://github.com/marketplace/actions/close-stale-issues
name: 'Close awaiting response issues'
on:
schedule:
- cron: '00 09 * * *'
jobs:
no-response:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v8
with:
days-before-stale: 14
days-before-close: 0
days-before-pr-close: -1
stale-issue-label: 'state:stale'
close-issue-message: "This issue has been automatically closed because there has been no response to our request for more information from the original author. With only the information that is currently in the issue, we don't have enough information to take action. Please reach out if you have or find the answers we need so that we can investigate further."
only-labels: 'state:awaiting-response'
+1 -1
View File
@@ -10,7 +10,7 @@ jobs:
steps:
- name: Download source tarball
run: |
curl -L -H "Accept: application/vnd.github+json" ${{ github.event.release.tarball_url }} --output cryptomator-${{ github.event.release.tag_name }}.tar.gz
curl -L -H "Accept: application/vnd.github+json" https://github.com/cryptomator/cryptomator/archive/refs/tags/${{ github.event.release.tag_name }}.tar.gz --output cryptomator-${{ github.event.release.tag_name }}.tar.gz
- name: Sign source tarball with key 615D449FE6E6A235
run: |
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
+1 -1
View File
@@ -4,7 +4,7 @@ on:
pull_request:
env:
JAVA_VERSION: 19
JAVA_VERSION: 20
defaults:
run:
+1 -1
View File
@@ -7,7 +7,7 @@ on:
- 'hotfix/**'
env:
JAVA_VERSION: 19
JAVA_VERSION: 20
defaults:
run:
+24
View File
@@ -0,0 +1,24 @@
# Configuration for close-stale-issues - https://github.com/marketplace/actions/close-stale-issues
name: 'Close stale issues'
on:
schedule:
- cron: '00 09 * * *'
jobs:
stale:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v8
with:
days-before-stale: 365
days-before-close: 90
exempt-issue-labels: 'type:security-issue,type:feature-request,type:enhancement,type:upstream-bug,state:awaiting-response,state:blocked,state:confirmed'
exempt-all-milestones: true
stale-issue-label: 'state:stale'
stale-pr-label: 'state:stale'
stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'
stale-pr-message: 'This PR has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'
+52 -27
View File
@@ -8,11 +8,17 @@ on:
version:
description: 'Version'
required: false
isDebug:
description: 'Build debug version with console output'
type: boolean
env:
JAVA_VERSION: 19
JAVA_DIST: 'zulu'
JAVA_VERSION: 20
JAVA_DIST: 'temurin'
JAVA_CACHE: 'maven'
JFX_JMODS_URL: 'https://download2.gluonhq.com/openjfx/20.0.1/openjfx-20.0.1_windows-x64_bin-jmods.zip'
JFX_JMODS_HASH: 'D00767334C43B8832B5CF10267D34CA8F563D187C4655B73EB6020DD79C054B5'
defaults:
run:
@@ -22,7 +28,7 @@ jobs:
get-version:
uses: ./.github/workflows/get-version.yml
with:
version: ${{ github.event.inputs.version }}
version: ${{ inputs.version }}
build-msi:
name: Build .msi Installer
@@ -30,6 +36,7 @@ jobs:
needs: [get-version]
env:
LOOPBACK_ALIAS: 'cryptomator-vault'
WIN_CONSOLE_FLAG: ''
steps:
- uses: actions/checkout@v3
- name: Setup Java
@@ -37,17 +44,31 @@ jobs:
with:
distribution: ${{ env.JAVA_DIST }}
java-version: ${{ env.JAVA_VERSION }}
java-package: 'jdk+fx'
java-package: 'jdk'
cache: ${{ env.JAVA_CACHE }}
- name: Ensure major jfx version in pom equals in jdk
shell: pwsh
- name: Download and extract JavaFX jmods from Gluon
#In the last step we move all jmods files a dir level up because jmods are placed inside a directory in the zip
run: |
$jfxPomVersion = (&mvn help:evaluate "-Dexpression=javafx.version" -q -DforceStdout) -split "\."
$jfxJdkVersion = ((Get-Content -path "${env:JAVA_HOME}/lib/javafx.properties" | Where-Object {$_ -like 'javafx.version=*' }) -replace '.*=','') -split "\."
if ($jfxPomVersion[0] -ne $jfxJdkVersion[0]) {
Write-Error "Major part of JavaFX version in pom($($jfxPomVersion[0])) does not match the version in JDK($($jfxJdkVersion[0])) "
exit 1
curl --output jfxjmods.zip -L "${{ env.JFX_JMODS_URL }}"
if(!(Get-FileHash -Path jfxjmods.zip -Algorithm SHA256).Hash.equals("${{ env.JFX_JMODS_HASH }}")) {
throw "Wrong checksum of JMOD archive downloaded from ${{ env.JFX_JMODS_URL }}.";
}
Expand-Archive -Path jfxjmods.zip -DestinationPath jfxjmods
Get-ChildItem -Path jfxjmods -Recurse -Filter "*.jmod" | ForEach-Object { Move-Item -Path $_ -Destination $_.Directory.Parent}
shell: pwsh
- name: Ensure major jfx version in pom and in jmods is the same
run: |
JMOD_VERSION_AMD64=$(jmod describe jfxjmods/javafx.base.jmod | head -1)
JMOD_VERSION_AMD64=${JMOD_VERSION_AMD64#*@}
JMOD_VERSION_AMD64=${JMOD_VERSION_AMD64%%.*}
POM_JFX_VERSION=$(mvn help:evaluate "-Dexpression=javafx.version" -q -DforceStdout)
POM_JFX_VERSION=${POM_JFX_VERSION#*@}
POM_JFX_VERSION=${POM_JFX_VERSION%%.*}
if [ $POM_JFX_VERSION -ne $JMOD_VERSION_AMD64 ]; then
>&2 echo "Major JavaFX version in pom.xml (${POM_JFX_VERSION}) != amd64 jmod version (${JMOD_VERSION_AMD64})"
exit 1
fi
- name: Set version
run : mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }}
- name: Run maven
@@ -55,20 +76,22 @@ jobs:
- name: Patch target dir
run: |
cp LICENSE.txt target
cp dist/linux/launcher.sh target
cp target/cryptomator-*.jar target/mods
- name: Run jlink
run: >
${JAVA_HOME}/bin/jlink
--verbose
--output runtime
--module-path "${JAVA_HOME}/jmods"
--module-path "jfxjmods;${JAVA_HOME}/jmods"
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr
--strip-native-commands
--no-header-files
--no-man-pages
--strip-debug
--compress=1
- name: Change win-console flag if debug is active
if: ${{ inputs.isDebug }}
run: echo "WIN_CONSOLE_FLAG=--win-console" >> $GITHUB_ENV
- name: Run jpackage
run: >
${JAVA_HOME}/bin/jpackage
@@ -81,7 +104,7 @@ jobs:
--dest appdir
--name Cryptomator
--vendor "Skymatic GmbH"
--copyright "(C) 2016 - 2022 Skymatic GmbH"
--copyright "(C) 2016 - 2023 Skymatic GmbH"
--app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}"
--java-options "--enable-preview"
--java-options "--enable-native-access=org.cryptomator.jfuse.win"
@@ -100,8 +123,10 @@ jobs:
--java-options "-Dcryptomator.buildNumber=\"msi-${{ needs.get-version.outputs.revNum }}\""
--java-options "-Dcryptomator.integrationsWin.autoStartShellLinkName=\"Cryptomator\""
--java-options "-Dcryptomator.integrationsWin.keychainPaths=\"~/AppData/Roaming/Cryptomator/keychain.json\""
--java-options "-Djavafx.verbose=${{ inputs.isDebug }}"
--resource-dir dist/win/resources
--icon dist/win/resources/Cryptomator.ico
${WIN_CONSOLE_FLAG}
- name: Patch Application Directory
run: |
cp dist/win/contrib/* appdir/Cryptomator
@@ -118,6 +143,9 @@ jobs:
- name: Fix permissions
run: attrib -r appdir/Cryptomator/Cryptomator.exe
shell: pwsh
- name: Extract integrations DLL for code signing
shell: pwsh
run: gci ./appdir/Cryptomator/app/mods/ -File integrations-win-*.jar | ForEach-Object {Set-Location -Path $_.Directory; jar --file=$($_.FullName) --extract integrations.dll }
- name: Codesign
uses: skymatic/code-sign-action@v2
with:
@@ -128,6 +156,10 @@ jobs:
timestampUrl: 'http://timestamp.digicert.com'
folder: appdir/Cryptomator
recursive: true
- name: Repack signed DLL into jar
shell: pwsh
run: |
gci ./appdir/Cryptomator/app/mods/ -File integrations-win-*.jar | ForEach-Object {Set-Location -Path $_.Directory; jar --file=$($_.FullName) --update integrations.dll; Remove-Item integrations.dll}
- name: Generate license for MSI
run: >
mvn -B license:add-third-party
@@ -149,8 +181,8 @@ jobs:
--dest installer
--name Cryptomator
--vendor "Skymatic GmbH"
--copyright "(C) 2016 - 2022 Skymatic GmbH"
--app-version "${{ needs.get-version.outputs.semVerNum }}"
--copyright "(C) 2016 - 2023 Skymatic GmbH"
--app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum}}"
--win-menu
--win-dir-chooser
--win-shortcut-prompt
@@ -197,15 +229,6 @@ jobs:
*.msi
*.asc
call-winget-flow:
needs: [get-version, build-msi]
if: github.event.action == 'published' && needs.get-version.outputs.versionType == 'stable'
uses: ./.github/workflows/winget.yml
with:
releaseTag: ${{ github.event.release.tag_name }}
secrets: inherit
build-exe:
name: Build .exe installer
runs-on: windows-latest
@@ -237,17 +260,18 @@ jobs:
shell: pwsh
- name: Download WinFsp
run: |
$winfspUrl= (Select-String -Path ".\dist\win\bundle\resources\winfsp-download.url" -Pattern 'https:.*').Matches.Value
$winfspUrl = (Select-String -Path ".\dist\win\bundle\resources\winFspMetaData.wxi" -Pattern '<\?define BundledWinFspDownloadLink="(.+)".*?>').Matches.Groups[1].Value
curl --output dist/win/bundle/resources/winfsp.msi -L $winfspUrl
shell: pwsh
- name: Compile to wixObj file
run: >
"${WIX}/bin/candle.exe" dist/win/bundle/bundleWithWinfsp.wxs
-ext WixBalExtension
-ext WixUtilExtension
-out dist/win/bundle/
-dBundleVersion="${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}"
-dBundleVendor="Skymatic GmbH"
-dBundleCopyright="(C) 2016 - 2022 Skymatic GmbH"
-dBundleCopyright="(C) 2016 - 2023 Skymatic GmbH"
-dAboutUrl="https://cryptomator.org"
-dHelpUrl="https://cryptomator.org/contact"
-dUpdateUrl="https://cryptomator.org/downloads/"
@@ -255,6 +279,7 @@ jobs:
run: >
"${WIX}/bin/light.exe" -b dist/win/ dist/win/bundle/bundleWithWinfsp.wixobj
-ext WixBalExtension
-ext WixUtilExtension
-out installer/unsigned/Cryptomator-Installer.exe
- name: Detach burn engine in preparation to sign
run: >
-49
View File
@@ -1,49 +0,0 @@
name: Release to Winget
on:
workflow_call:
inputs:
releaseTag:
required: true
type: string
workflow_dispatch:
inputs:
releaseTag:
description: 'Release tag name'
required: true
type: string
jobs:
publish-winget:
name: Publish on winget repo
runs-on: windows-latest
steps:
- name: Get download url for release assets
id: get-release-assets
uses: actions/github-script@v6
with:
script: |
const query =`query($tag:String!) {
repository(owner:"cryptomator", name:"cryptomator"){
release(tagName: $tag) {
releaseAssets(first:20) {
nodes {
name
downloadUrl
}
}
}
}
}`;
const variables = {
tag: "${{ inputs.releaseTag }}"
}
return await github.graphql(query, variables)
- name: Submit package to Windows Package Manager Community Repository
id: submit-winget
run: |
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
$releaseAssets = (ConvertFrom-Json '${{ steps.get-release-assets.outputs.result }}').repository.release.releaseAssets.nodes
$installerUrl = $releaseAssets | Where-Object -Property name -match '^Cryptomator-.*\.msi$' | Select -ExpandProperty downloadUrl -First 1
.\wingetcreate.exe update Cryptomator.Cryptomator -s -v "${{ inputs.releaseTag }}" -u "$installerUrl" -t ${{ secrets.CRYPTOBOT_WINGET_TOKEN }}
shell: pwsh
+6 -4
View File
@@ -14,10 +14,10 @@
<option name="dagger.fastInit" value="enabled" />
<option name="dagger.formatGeneratedSource" value="enabled" />
<processorPath useClasspath="false">
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-compiler/2.44/dagger-compiler-2.44.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger/2.44/dagger-2.44.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-compiler/2.45/dagger-compiler-2.45.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger/2.45/dagger-2.45.jar" />
<entry name="$MAVEN_REPOSITORY$/javax/inject/javax.inject/1/javax.inject-1.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-producers/2.44/dagger-producers-2.44.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-producers/2.45/dagger-producers-2.45.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/guava/guava/31.0.1-jre/guava-31.0.1-jre.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar" />
@@ -26,14 +26,16 @@
<entry name="$MAVEN_REPOSITORY$/com/google/errorprone/error_prone_annotations/2.7.1/error_prone_annotations-2.7.1.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/j2objc/j2objc-annotations/1.3/j2objc-annotations-1.3.jar" />
<entry name="$MAVEN_REPOSITORY$/org/checkerframework/checker-compat-qual/2.5.5/checker-compat-qual-2.5.5.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-spi/2.44/dagger-spi-2.44.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-spi/2.45/dagger-spi-2.45.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/devtools/ksp/symbol-processing-api/1.7.0-1.0.6/symbol-processing-api-1.7.0-1.0.6.jar" />
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.7.0/kotlin-stdlib-1.7.0.jar" />
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-common/1.7.0/kotlin-stdlib-common-1.7.0.jar" />
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar" />
<entry name="$MAVEN_REPOSITORY$/com/squareup/javapoet/1.13.0/javapoet-1.13.0.jar" />
<entry name="$MAVEN_REPOSITORY$/com/squareup/kotlinpoet/1.11.0/kotlinpoet-1.11.0.jar" />
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.7.0/kotlin-stdlib-jdk8-1.7.0.jar" />
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.7.0/kotlin-stdlib-jdk7-1.7.0.jar" />
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-reflect/1.6.10/kotlin-reflect-1.6.10.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/googlejavaformat/google-java-format/1.5/google-java-format-1.5.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/errorprone/javac-shaded/9-dev-r4023-3/javac-shaded-9-dev-r4023-3.jar" />
<entry name="$MAVEN_REPOSITORY$/net/ltgt/gradle/incap/incap/0.2/incap-0.2.jar" />
+1 -1
View File
@@ -8,7 +8,7 @@
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_19" default="true" project-jdk-name="19" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_20_PREVIEW" project-jdk-name="20" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
+2 -2
View File
@@ -21,7 +21,6 @@ Cryptomator is provided free of charge as an open-source project despite the hig
<tbody>
<tr>
<td><a href="https://www.gee-whiz.de/"><img src="https://cryptomator.org/img/sponsors/geewhiz.svg" alt="gee-whiz" height="80"></a></td>
<td><a href="https://proxy-hub.com/"><img src="https://cryptomator.org/img/sponsors/proxyhub.svg" alt="Proxy-Hub" height="80"></a></td>
</tr>
</tbody>
</table>
@@ -33,6 +32,7 @@ Cryptomator is provided free of charge as an open-source project despite the hig
<tr>
<td><a href="https://mowcapital.com/"><img src="https://cryptomator.org/img/sponsors/mowcapital.svg" alt="Mow Capital" height="40"></a></td>
<td><a href="https://www.easeus.com/"><img src="https://cryptomator.org/img/sponsors/easeus.png" alt="EaseUS" height="40"></a></td>
<td><a href="https://www.hassmann-it-forensik.de/"><img src="https://cryptomator.org/img/sponsors/hassmannitforensik.png" alt="Hassmann IT-Forensik" height="40"></a></td>
</tr>
</tbody>
</table>
@@ -73,7 +73,7 @@ Download native binaries of Cryptomator on [cryptomator.org](https://cryptomator
### Consistency
- HMAC over file contents to recognize changed ciphertext before decryption
- Authenticated encryption is used for file content to recognize changed ciphertext before decryption
- I/O operations are transactional and atomic, if the filesystems support it
- Each file contains all information needed for decryption (except for the key of course), no common metadata means no [SPOF](http://en.wikipedia.org/wiki/Single_point_of_failure)
+19 -14
View File
@@ -11,15 +11,20 @@ command -v curl >/dev/null 2>&1 || { echo >&2 "curl not found."; exit 1; }
VERSION=$(mvn -f ../../../pom.xml help:evaluate -Dexpression=project.version -q -DforceStdout)
SEMVER_STR=${VERSION}
mvn -f ../../../pom.xml versions:set -DnewVersion=${SEMVER_STR}
# compile
mvn -B -f ../../../pom.xml clean package -DskipTests -Plinux
mvn -B -f ../../../pom.xml clean package -Plinux -DskipTests
cp ../../../LICENSE.txt ../../../target
cp ../launcher.sh ../../../target
cp ../../../target/cryptomator-*.jar ../../../target/mods
# add runtime
${JAVA_HOME}/bin/jlink \
--verbose \
--output runtime \
--module-path "${JAVA_HOME}/jmods" \
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr \
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.security.auth,jdk.accessibility,jdk.management.jfr \
--strip-native-commands \
--no-header-files \
--no-man-pages \
@@ -27,7 +32,7 @@ ${JAVA_HOME}/bin/jlink \
--compress=1
# create app dir
envsubst '${SEMVER_STR} ${REVISION_NUM}' < dist/linux/launcher-gtk2.properties > launcher-gtk2.properties
envsubst '${SEMVER_STR} ${REVISION_NUM}' < ../launcher-gtk2.properties > launcher-gtk2.properties
${JAVA_HOME}/bin/jpackage \
--verbose \
--type app-image \
@@ -35,12 +40,12 @@ ${JAVA_HOME}/bin/jpackage \
--input ../../../target/libs \
--module-path ../../../target/mods \
--module org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator \
--dest . \
--dest appdir \
--name Cryptomator \
--vendor "Skymatic GmbH" \
--copyright "(C) 2016 - 2022 Skymatic GmbH" \
--java-options "--enable-preview" \
--java-options "--enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64" \
--copyright "(C) 2016 - 2023 Skymatic GmbH" \
--java-options "-Xss5m" \
--java-options "-Xmx256m" \
--app-version "${VERSION}.${REVISION_NO}" \
@@ -48,6 +53,7 @@ ${JAVA_HOME}/bin/jpackage \
--java-options "-Dcryptomator.logDir=\"~/.local/share/Cryptomator/logs\"" \
--java-options "-Dcryptomator.pluginDir=\"~/.local/share/Cryptomator/plugins\"" \
--java-options "-Dcryptomator.settingsPath=\"~/.config/Cryptomator/settings.json:~/.Cryptomator/settings.json\"" \
--java-options "-Dcryptomator.p12Path=\"~/.config/Cryptomator/key.p12\"" \
--java-options "-Dcryptomator.ipcSocketPath=\"~/.config/Cryptomator/ipc.socket\"" \
--java-options "-Dcryptomator.mountPointsDir=\"~/.local/share/Cryptomator/mnt\"" \
--java-options "-Dcryptomator.showTrayIcon=false" \
@@ -56,9 +62,8 @@ ${JAVA_HOME}/bin/jpackage \
--resource-dir ../resources
# transform AppDir
mv Cryptomator Cryptomator.AppDir
mv appdir/Cryptomator Cryptomator.AppDir
cp -r resources/AppDir/* Cryptomator.AppDir/
chmod +x Cryptomator.AppDir/lib/runtime/bin/java
envsubst '${REVISION_NO}' < resources/AppDir/bin/cryptomator.sh > Cryptomator.AppDir/bin/cryptomator.sh
cp ../common/org.cryptomator.Cryptomator256.png Cryptomator.AppDir/usr/share/icons/hicolor/256x256/apps/org.cryptomator.Cryptomator.png
cp ../common/org.cryptomator.Cryptomator512.png Cryptomator.AppDir/usr/share/icons/hicolor/512x512/apps/org.cryptomator.Cryptomator.png
@@ -72,12 +77,6 @@ ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryp
ln -s usr/share/applications/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/Cryptomator.desktop
ln -s bin/cryptomator.sh Cryptomator.AppDir/AppRun
# extract jffi
JFFI_NATIVE_JAR=`ls Cryptomator.AppDir/lib/app | grep -e 'jffi-[1-9]\.[0-9]\{1,2\}.[0-9]\{1,2\}-native.jar'`
${JAVA_HOME}/bin/jar -xf Cryptomator.AppDir/lib/app/${JFFI_NATIVE_JAR} /jni/x86_64-Linux/
mv jni/x86_64-Linux/* Cryptomator.AppDir/lib/app/libjffi.so
rm -r jni/x86_64-Linux
# load AppImageTool
curl -L https://github.com/AppImage/AppImageKit/releases/download/13/appimagetool-x86_64.AppImage -o /tmp/appimagetool.AppImage
chmod +x /tmp/appimagetool.AppImage
@@ -85,5 +84,11 @@ chmod +x /tmp/appimagetool.AppImage
# create AppImage
/tmp/appimagetool.AppImage \
Cryptomator.AppDir \
cryptomator-SNAPSHOT-x86_64.AppImage \
cryptomator-${SEMVER_STR}-x86_64.AppImage \
-u 'gh-releases-zsync|cryptomator|cryptomator|latest|cryptomator-*-x86_64.AppImage.zsync'
echo ""
echo "Done. AppImage successfully created: cryptomator-${SEMVER_STR}-x86_64.AppImage"
echo ""
echo >&2 "To clean up, run: rm -rf Cryptomator.AppDir appdir jni runtime squashfs-root; rm launcher-gtk2.properties /tmp/appimagetool.AppImage"
echo ""
@@ -15,9 +15,6 @@ elif command -v pacman &> /dev/null; then # don't forget arch
GTK3_PRESENT=`pacman -Qi gtk3 &> /dev/null; echo $?`
fi
# workaround for https://github.com/cryptomator/cryptomator-linux/issues/27
export LD_PRELOAD=lib/app/libjffi.so
if [ "$GTK2_PRESENT" -eq 0 ] && [ "$GTK3_PRESENT" -ne 0 ]; then
bin/Cryptomator-gtk2 $@
else
@@ -66,6 +66,14 @@
</content_rating>
<releases>
<release date="2023-04-25" version="1.8.0"/>
<release date="2023-04-07" version="1.7.5"/>
<release date="2023-04-05" version="1.7.4"/>
<release date="2023-03-15" version="1.7.3"/>
<release date="2023-03-07" version="1.7.2"/>
<release date="2023-03-03" version="1.7.1"/>
<release date="2023-03-01" version="1.7.0"/>
<release date="2022-12-14" version="1.6.17"/>
<release date="2022-12-06" version="1.6.16"/>
<release date="2022-10-06" version="1.6.15"/>
<release date="2022-08-31" version="1.6.14"/>
+2 -2
View File
@@ -2,7 +2,7 @@ Source: cryptomator
Maintainer: Cryptobot <releases@cryptomator.org>
Section: utils
Priority: optional
Build-Depends: debhelper (>=10), coffeelibs-jdk-19, libgtk2.0-0, libgtk-3-0, libxxf86vm1, libgl1
Build-Depends: debhelper (>=10), coffeelibs-jdk-20, libgtk2.0-0, libgtk-3-0, libxxf86vm1, libgl1
Standards-Version: 4.5.0
Homepage: https://cryptomator.org
Vcs-Git: https://github.com/cryptomator/cryptomator.git
@@ -12,7 +12,7 @@ Package: cryptomator
Architecture: any
Section: utils
Priority: optional
Depends: ${shlibs:Depends}, ${misc:Depends}, libfuse2, xdg-utils, libjffi-jni
Depends: ${shlibs:Depends}, ${misc:Depends}, fuse3
Recommends: gvfs-backends, gvfs-fuse, gnome-keyring
XB-AppName: Cryptomator
XB-Category: Utility;Security;FileTools;
+2 -2
View File
@@ -4,11 +4,11 @@ Upstream-Contact: Cryptomator <info@cryptomator.org>
Source: https://cryptomator.org
Files: *
Copyright: 2016-2022 Skymatic GmbH
Copyright: 2016-2023 Skymatic GmbH
License: GPL-3+
Files: debian/org.cryptomator.Cryptomator.appdata.xml
Copyright: 2016-2022 Skymatic GmbH
Copyright: 2016-2023 Skymatic GmbH
License: FSFAP
License: GPL-3+
-1
View File
@@ -1,5 +1,4 @@
cryptomator usr/lib
debian/cryptomator.sh usr/lib/cryptomator/bin
common/org.cryptomator.Cryptomator.desktop usr/share/applications
common/org.cryptomator.Cryptomator.svg usr/share/icons/hicolor/scalable/apps
common/org.cryptomator.Cryptomator256.png usr/share/icons/hicolor/256x256/apps
+1 -1
View File
@@ -1 +1 @@
usr/lib/cryptomator/bin/cryptomator.sh usr/bin/cryptomator
usr/lib/cryptomator/bin/cryptomator usr/bin/cryptomator
-6
View File
@@ -1,6 +0,0 @@
#!/bin/sh
# fix for https://github.com/cryptomator/cryptomator/issues/1370
export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/jni/libjffi-1.2.so
/usr/lib/cryptomator/bin/cryptomator $@
+3 -10
View File
@@ -4,7 +4,7 @@
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
JAVA_HOME = /usr/lib/jvm/java-19-coffeelibs
JAVA_HOME = /usr/lib/jvm/java-20-coffeelibs
DEB_BUILD_ARCH ?= $(shell dpkg-architecture -qDEB_BUILD_ARCH)
ifeq ($(DEB_BUILD_ARCH),amd64)
JMODS_PATH = jmods/amd64:${JAVA_HOME}/jmods
@@ -27,7 +27,7 @@ override_dh_auto_build:
$(JAVA_HOME)/bin/jlink \
--output runtime \
--module-path "${JMODS_PATH}" \
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr \
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.security.auth,jdk.accessibility,jdk.management.jfr \
--strip-native-commands \
--no-header-files \
--no-man-pages \
@@ -42,9 +42,9 @@ override_dh_auto_build:
--dest . \
--name cryptomator \
--vendor "Skymatic GmbH" \
--copyright "(C) 2016 - 2022 Skymatic GmbH" \
--java-options "--enable-preview" \
--java-options "--enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64" \
--copyright "(C) 2016 - 2023 Skymatic GmbH" \
--java-options "-Xss5m" \
--java-options "-Xmx256m" \
--java-options "-Dfile.encoding=\"utf-8\"" \
@@ -60,10 +60,3 @@ override_dh_auto_build:
--app-version "${VERSION_NUM}.${REVISION_NUM}" \
--resource-dir resources \
--verbose
override_dh_fixperms:
dh_fixperms
chmod +x debian/cryptomator/usr/lib/cryptomator/bin/cryptomator.sh
# override_dh_strip:
# no-op
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
cd $(dirname $0)
java \
-p "mods" \
-cp "libs/*" \
-Dcryptomator.settingsPath="~/.config/Cryptomator/settings.json" \
-Dcryptomator.ipcSocketPath="~/.config/Cryptomator/ipc.socket" \
-Dcryptomator.logDir="~/.local/share/Cryptomator/logs" \
-Dcryptomator.mountPointsDir="~/.local/share/Cryptomator/mnt" \
-Djdk.gtk.version=2 \
-Xss2m \
-Xmx512m \
--enable-preview \
--enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64 \
-m org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator
+7 -5
View File
@@ -21,12 +21,13 @@ rm -rf runtime dmg *.app *.dmg
# set variables
APP_NAME="Cryptomator"
VENDOR="Skymatic GmbH"
COPYRIGHT_YEARS="2016 - 2022"
COPYRIGHT_YEARS="2016 - 2023"
PACKAGE_IDENTIFIER="org.cryptomator"
MAIN_JAR_GLOB="cryptomator-*.jar"
MODULE_AND_MAIN_CLASS="org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator"
REVISION_NO=`git rev-list --count HEAD`
VERSION_NO=`mvn -f../../../pom.xml help:evaluate -Dexpression=project.version -q -DforceStdout | sed -rn 's/.*([0-9]+\.[0-9]+\.[0-9]+).*/\1/p'`
FUSE_LIB="FUSE-T"
# check preconditions
if [ -z "${JAVA_HOME}" ]; then echo "JAVA_HOME not set. Run using JAVA_HOME=/path/to/jdk ./build.sh"; exit 1; fi
@@ -79,6 +80,7 @@ ${JAVA_HOME}/bin/jpackage \
--java-options "-Dcryptomator.ipcSocketPath=\"~/Library/Application Support/${APP_NAME}/ipc.socket\"" \
--java-options "-Dcryptomator.p12Path=\"~/Library/Application Support/${APP_NAME}/key.p12\"" \
--java-options "-Dcryptomator.integrationsMac.keychainServiceName=\"${APP_NAME}\"" \
--java-options "-Dcryptomator.mountPointsDir=\"~/${APP_NAME}\"" \
--java-options "-Dcryptomator.showTrayIcon=true" \
--java-options "-Dcryptomator.buildNumber=\"dmg-${REVISION_NO}\"" \
--mac-package-identifier ${PACKAGE_IDENTIFIER} \
@@ -124,20 +126,20 @@ fi
# prepare dmg contents
mkdir dmg
mv ${APP_NAME}.app dmg
cp resources/macFUSE.webloc dmg
cp resources/${FUSE_LIB}.webloc dmg
# create dmg
create-dmg \
--volname ${APP_NAME} \
--volicon "resources/${APP_NAME}-Volume.icns" \
--background "resources/${APP_NAME}-background.tiff" \
--background "resources/${APP_NAME}-${FUSE_LIB}-background.tiff" \
--window-pos 400 100 \
--window-size 640 694 \
--icon-size 128 \
--icon "${APP_NAME}.app" 128 245 \
--hide-extension "${APP_NAME}.app" \
--icon "macFUSE.webloc" 320 501 \
--hide-extension "macFUSE.webloc" \
--icon "${FUSE_LIB}.webloc" 320 501 \
--hide-extension "${FUSE_LIB}.webloc" \
--app-drop-link 512 245 \
--eula "resources/license.rtf" \
--icon ".background" 128 758 \
Binary file not shown.
Binary file not shown.
Binary file not shown.
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>URL</key>
<string>https://www.fuse-t.org/</string>
</dict>
</plist>
+1 -1
View File
@@ -17,7 +17,7 @@
\f1\b0 \
\
\f0\b \'a9 2016 \'96 2022 Skymatic GmbH
\f0\b \'a9 2016 \'96 2023 Skymatic GmbH
\f1\b0 \
\
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\
-14
View File
@@ -1,14 +0,0 @@
#!/bin/sh
cd $(dirname $0)
java \
-p "mods" \
-cp "libs/*" \
-Dcryptomator.settingsPath="~/Library/Application Support/Cryptomator/settings.json" \
-Dcryptomator.ipcSocketPath="~/Library/Application Support/Cryptomator/ipc.socket" \
-Dcryptomator.logDir="~/Library/Logs/Cryptomator" \
-Dcryptomator.mountPointsDir="/Volumes" \
-Xss20m \
-Xmx512m \
--enable-preview \
--enable-native-access=org.cryptomator.jfuse.mac \
-m org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator
+4 -4
View File
@@ -129,7 +129,7 @@ $Env:JP_WIXWIZARD_RESOURCES = "$buildDir\resources"
--name $AppName `
--vendor $Vendor `
--copyright $copyright `
--app-version "$semVerNo" `
--app-version "$semVerNo.$revisionNo" `
--win-menu `
--win-dir-chooser `
--win-shortcut-prompt `
@@ -153,7 +153,7 @@ $Env:JP_WIXWIZARD_RESOURCES = "$buildDir\resources"
# download Winfsp
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$ProgressPreference = 'SilentlyContinue' # disables Invoke-WebRequest's progress bar, which slows down downloads to a few bytes/s
$winfspMsiUrl= (Select-String -Path ".\bundle\resources\winfsp-download.url" -Pattern 'https:.*').Matches.Value
$winfspMsiUrl= (Select-String -Path ".\bundle\resources\winFspMetaData.wxi" -Pattern '<\?define BundledWinFspDownloadLink="(.+)".*?>').Matches.Groups[1].Value
Write-Output "Downloading ${winfspMsiUrl}..."
Invoke-WebRequest $winfspMsiUrl -OutFile ".\bundle\resources\winfsp.msi" # redirects are followed by default
@@ -161,11 +161,11 @@ Invoke-WebRequest $winfspMsiUrl -OutFile ".\bundle\resources\winfsp.msi" # redir
Copy-Item ".\installer\$AppName-*.msi" -Destination ".\bundle\resources\$AppName.msi"
# create bundle including winfsp
& "$env:WIX\bin\candle.exe" .\bundle\bundleWithWinfsp.wxs -ext WixBalExtension -out bundle\ `
& "$env:WIX\bin\candle.exe" .\bundle\bundleWithWinfsp.wxs -ext WixBalExtension -ext WixUtilextension -out bundle\ `
-dBundleVersion="$semVerNo.$revisionNo" `
-dBundleVendor="$Vendor" `
-dBundleCopyright="$copyright" `
-dAboutUrl="$AboutUrl" `
-dHelpUrl="$HelpUrl" `
-dUpdateUrl="$UpdateUrl"
& "$env:WIX\bin\light.exe" -b . .\bundle\BundlewithWinfsp.wixobj -ext WixBalExtension -out installer\$AppName-Installer.exe
& "$env:WIX\bin\light.exe" -b . .\bundle\BundlewithWinfsp.wixobj -ext WixBalExtension -ext WixUtilextension -out installer\$AppName-Installer.exe
+19 -1
View File
@@ -1,13 +1,31 @@
<?xml version="1.0"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:bal="http://schemas.microsoft.com/wix/BalExtension">
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:bal="http://schemas.microsoft.com/wix/BalExtension" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<!-- see https://wixtoolset.org/documentation/manual/v3/xsd/wix/bundle.html-->
<!-- Attributes explicitly not used:
Condition - the single msi files have their own install conditions, no need to copy them here
-->
<Bundle Name="Cryptomator" UpgradeCode="29eea626-2e5b-4449-b5f8-4602925ddf7b" Version="$(var.BundleVersion)" Manufacturer="$(var.BundleVendor)"
AboutUrl="$(var.AboutUrl)" HelpUrl="$(var.HelpUrl)" UpdateUrl="$(var.UpdateUrl)" Copyright="$(var.BundleCopyright)" IconSourceFile="bundle\resources\Cryptomator.ico">
<!-- detect outdated WinFsp installations -->
<?include "resources\winFspMetaData.wxi" ?>
<util:ProductSearch
Variable="InstalledWinFspVersion"
Result="version"
UpgradeCode="82F812D9-4083-4EF1-8BC8-0F1EDA05B46B"
/>
<!-- Note: The bundle engine takes the Message format literaly -->
<bal:Condition Message=
"The WinFsp driver used by Cryptomator is outdated and must be removed before the installation.
1. Open the view of installed apps
2. Search for &quot;WinFsp&quot;
3. Uninstall the listed application
4. Reboot your device
5. Restart this installer">(InstalledWinFspVersion = v0.0.0.0) OR ($(var.BundledWinFspVersion) &lt;= InstalledWinFspVersion)</bal:Condition>
<!-- for definition of the standard themes, see https://github.com/wixtoolset/wix3/blob/master/src/ext/BalExtension/wixstdba/Resources/-->
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLargeLicense">
<!-- see https://wixtoolset.org/documentation/manual/v3/xsd/bal/wixstandardbootstrapperapplication.html -->
+2 -1
View File
@@ -10,6 +10,7 @@
<Font Id="2" Height="-22" Weight="500" Foreground="666666">Segoe UI</Font>
<Font Id="3" Height="-12" Weight="500" Foreground="000000" Background="FFFFFF">Segoe UI</Font>
<Font Id="4" Height="-12" Weight="500" Foreground="ff0000" Background="FFFFFF" Underline="yes">Segoe UI</Font>
<Font Id="5" Height="-12" Weight="700" Foreground="000000" Background="FFFFFF">Segoe UI</Font>
<Image X="11" Y="11" Width="64" Height="64" ImageFile="logo.png" />
<Text X="80" Y="11" Width="-11" Height="64" FontId="1" DisablePrefix="yes">#(loc.Title)</Text>
@@ -82,7 +83,7 @@
<Text Name="FailureUninstallHeader" X="185" Y="50" Width="-11" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureUninstallHeader)</Text>
<Text Name="FailureRepairHeader" X="185" Y="50" Width="-11" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureRepairHeader)</Text>
<Hypertext Name="FailureLogFileLink" X="185" Y="121" Width="-11" Height="68" FontId="3" TabStop="yes" HideWhenDisabled="yes">#(loc.FailureHyperlinkLogText)</Hypertext>
<Hypertext Name="FailureMessageText" X="185" Y="-115" Width="-11" Height="80" FontId="3" TabStop="yes" HideWhenDisabled="yes" />
<Hypertext Name="FailureMessageText" X="185" Y="-80" Width="-11" Height="140" FontId="5" TabStop="yes" HideWhenDisabled="yes" />
<Text Name="FailureRestartText" X="185" Y="-57" Width="-11" Height="80" FontId="3" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureRestartText)</Text>
<Button Name="FailureRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.FailureRestartButton)</Button>
<Button Name="FailureCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.FailureCloseButton)</Button>
+1 -1
View File
@@ -10,7 +10,7 @@
\vieww12000\viewh15840\viewkind0
\pard\tx283\tx567\tx850\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\b\fs16\lang7 Cryptomator is distributed under the GPLv3 License, found below. Please see the bottom of this document for any other license applicable to code used within Cryptomator.\b0\par
\par
\b\'a9 2016 \'96 2022 Skymatic GmbH \b0\par
\b\'a9 2016 \'96 2023 Skymatic GmbH \b0\par
\par
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\par
\par
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Include xmlns="http://schemas.microsoft.com/wix/2006/wi">
<!-- A version number MUST be prefixed with letter "v", otherwise it is considered a normal string -->
<?define BundledWinFspVersion="v1.12.22339" ?>
<?define BundledWinFspDownloadLink="https://github.com/winfsp/winfsp/releases/download/v1.12.22339/winfsp-1.12.22339.msi" ?> <!-- Only used by external build scripts -->
</Include>
-2
View File
@@ -1,2 +0,0 @@
[InternetShortcut]
URL=https://github.com/winfsp/winfsp/releases/download/v1.12/winfsp-1.12.22301.msi
-12
View File
@@ -1,12 +0,0 @@
@echo off
java ^
-p "app/mods" ^
-cp "app/*" ^
-Dcryptomator.settingsPath="~/AppData/Roaming/Cryptomator/settings.json" ^
-Dcryptomator.ipcSocketPath="~/AppData/Roaming/Cryptomator/ipc.socket" ^
-Dcryptomator.logDir="~/AppData/Roaming/Cryptomator" ^
-Dcryptomator.mountPointsDir="~/Cryptomator" ^
-Dcryptomator.keychainPath="~/AppData/Roaming/Cryptomator/keychain.json" ^
-Xss20m ^
-Xmx512m ^
-m org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator
+5
View File
@@ -0,0 +1,5 @@
@echo off
:: see comments in file ./version170-migrate-settings.ps1
cd %~dp0
powershell -NoLogo -NonInteractive -ExecutionPolicy Unrestricted -Command .\version170-migrate-settings.ps1
+35
View File
@@ -0,0 +1,35 @@
# This script migrates Cryptomator settings for all local users on Windows in case the users uses custom directories as mountpoint
# See also https://github.com/cryptomator/cryptomator/pull/2654.
#
# TODO: This script should be evaluated in a yearly interval if it is still needed and if not, should be removed
#
#Requires -RunAsAdministrator
#Get all active, local user profiles
$profileList = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList'
Get-ChildItem $profileList | ForEach-Object {
$profilePath = $_.GetValue("ProfileImagePath")
$settingsPath = "$profilePath\AppData\Roaming\Cryptomator\settings.json"
if(!(Test-Path -Path $settingsPath -PathType Leaf)) {
#No settings file, nothing to do.
return;
}
$settings = Get-Content -Path $settingsPath | ConvertFrom-Json
if($settings.preferredVolumeImpl -ne "FUSE") {
#Fuse not used, nothing to do
return;
}
#check if customMountPoints are used
$atLeastOneCustomPath = $false;
foreach ($vault in $settings.directories){
$atLeastOneCustomPath = $atLeastOneCustomPath -or ($vault.useCustomMountPath -eq "True")
}
#if so, use WinFsp Local Drive
if( $atLeastOneCustomPath ) {
Add-Member -Force -InputObject $settings -Name "mountService" -Value "org.cryptomator.frontend.fuse.mount.WinFspMountProvider" -MemberType NoteProperty
$newSettings = $settings | Select-Object * -ExcludeProperty "preferredVolumeImpl"
ConvertTo-Json $newSettings | Set-Content -Path $settingsPath
}
}
+2 -5
View File
@@ -65,13 +65,10 @@
<Control Id="Title" Type="Text" X="135" Y="20" Width="220" Height="60" Transparent="yes" NoPrefix="yes" Text="!(loc.ExitDialogTitle)" />
<!-- TODO: localize? -->
<Control Id="Suggestion" Type="Text" X="135" Y="100" Width="220" Height="60" Transparent="yes" NoPrefix="yes">
<Text>We recommend for the best user experience to download and install one of the following third party Windows drivers:</Text>
<Text>We recommend for the best user experience to download and install the following third party Windows driver:</Text>
</Control>
<Control Id="WinFsp" Type="Hyperlink" X="140" Y="125" Width="220" Height="60" Transparent="yes">
<Text><![CDATA[WinFsp (<a href="http://www.secfs.net/winfsp/rel/">Homepage</a>)]]></Text>
</Control>
<Control Id="Dokany" Type="Hyperlink" X="140" Y="137" Width="220" Height="60" Transparent="yes">
<Text><![CDATA[• Dokany (<a href="https://dokan-dev.github.io/">Homepage</a>)]]></Text>
<Text><![CDATA[WinFsp (<a href="https://winfsp.dev/">Homepage</a>)]]></Text>
</Control>
</Dialog>
+1 -1
View File
@@ -10,7 +10,7 @@
\vieww12000\viewh15840\viewkind0
\pard\tx283\tx567\tx850\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\b\fs16\lang7 Cryptomator is distributed under the GPLv3 License, found below. Please see the bottom of this document for any other license applicable to code used within Cryptomator.\b0\par
\par
\b\'a9 2016 \'96 2022 Skymatic GmbH \b0\par
\b\'a9 2016 \'96 2023 Skymatic GmbH \b0\par
\par
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\par
\par
+18 -6
View File
@@ -54,7 +54,7 @@
Property="JP_UPGRADABLE_FOUND"
Maximum="$(var.JpAppVersion)"
MigrateFeatures="yes"
IncludeMaximum="$(var.JpUpgradeVersionOnlyDetectUpgrade)" />
IncludeMaximum="yes" /> <!-- TODO: check if this needs to be set to yes-->
<UpgradeVersion
OnlyDetect="$(var.JpUpgradeVersionOnlyDetectDowngrade)"
Property="JP_DOWNGRADABLE_FOUND"
@@ -70,6 +70,9 @@
<CustomAction Id="JpDisallowDowngrade" Error="!(loc.DowngradeErrorMessage)" />
<?endif?>
<Binary Id="JpCaDll" SourceFile="wixhelper.dll"/>
<CustomAction Id="JpFindRelatedProducts" BinaryKey="JpCaDll" DllEntry="FindRelatedProductsEx" />
<?ifndef SkipCryptomatorLegacyCheck ?>
<!-- Block installation if innosetup entry of Cryptomator is found -->
<Property Id="OLDEXEINSTALLER">
@@ -132,6 +135,9 @@
<!-- WebDAV patches -->
<CustomAction Id="PatchWebDAV" Impersonate="no" ExeCommand="[INSTALLDIR]patchWebDAV.bat" Directory="INSTALLDIR" Execute="deferred" Return="asyncWait" />
<!-- Special Settings migration for 1.7.0,. Should be removed eventually, for more info, see ../contrib/version170-migrate-settings.ps1-->
<CustomAction Id="V170MigrateSettings" Impersonate="no" ExeCommand="[INSTALLDIR]version170-migrate-settings.bat" Directory="INSTALLDIR" Execute="deferred" Return="asyncWait" />
<!-- Running App detection and exit -->
<Property Id="FOUNDRUNNINGAPP" Admin="yes"/>
<util:CloseApplication
@@ -140,11 +146,11 @@
CloseMessage="no"
RebootPrompt="no"
PromptToContinue="yes"
Description="A running instance of $(var.JpAppName) is found. Please close it to continue."
Description="A running instance of $(var.JpAppName) is found, using files marked for update. Please close it to continue."
Property="FOUNDRUNNINGAPP"
>
</util:CloseApplication>
<CustomAction Id="FailOnRunningApp" Impersonate="no" ExeCommand="[SystemFolder]\cmd.exe /c &quot;exit 1&quot;" Directory="INSTALLDIR" Execute="immediate" Return="check" />
<CustomAction Id="FailOnRunningApp" Error="Installation aborted, because files marked for update are used by a running instance of $(var.JpAppName)."/>
<?ifdef JpIcon ?>
<Property Id="ARPPRODUCTICON" Value="JpARPPRODUCTICON"/>
@@ -169,21 +175,27 @@
<?endif?>
<?ifndef JpAllowUpgrades ?>
<Custom Action="JpDisallowUpgrade" After="FindRelatedProducts">JP_UPGRADABLE_FOUND</Custom>
<Custom Action="JpDisallowUpgrade" After="JpFindRelatedProducts">JP_UPGRADABLE_FOUND</Custom>
<?endif?>
<?ifndef JpAllowDowngrades ?>
<Custom Action="JpDisallowDowngrade" After="FindRelatedProducts">JP_DOWNGRADABLE_FOUND</Custom>
<Custom Action="JpDisallowDowngrade" After="JpFindRelatedProducts">JP_DOWNGRADABLE_FOUND</Custom>
<?endif?>
<Custom Action="JpFindRelatedProducts" After="FindRelatedProducts"/>
<!-- Check and fail if Cryptomator is running -->
<Custom Action="WixCloseApplications" Before="InstallValidate"></Custom>
<Custom Action="FailOnRunningApp" After="WixCloseApplications" >FOUNDRUNNINGAPP</Custom>
<RemoveExistingProducts After="InstallValidate"/>
<RemoveExistingProducts After="InstallValidate"/> <!-- Moved from CostInitialize, due to WixCloseApplications -->
<Custom Action="PatchWebDAV" After="InstallFiles">NOT Installed OR REINSTALL</Custom>
<Custom Action="V170MigrateSettings" After="InstallFiles">NOT Installed OR REINSTALL</Custom>
</InstallExecuteSequence>
<InstallUISequence>
<Custom Action="JpFindRelatedProducts" After="FindRelatedProducts"/>
</InstallUISequence>
<WixVariable Id="WixUIBannerBmp" Value="$(env.JP_WIXWIZARD_RESOURCES)\banner.bmp" />
<WixVariable Id="WixUIDialogBmp" Value="$(env.JP_WIXWIZARD_RESOURCES)\background.bmp" />
</Product>
+31 -58
View File
@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.cryptomator</groupId>
<artifactId>cryptomator</artifactId>
<version>1.7.0</version>
<version>1.9.0</version>
<name>Cryptomator Desktop App</name>
<organization>
@@ -17,49 +17,54 @@
<email>sebastian.stenzel@gmail.com</email>
<timezone>+1</timezone>
</developer>
<developer>
<name>Armin Schrenk</name>
<email>armin.schrenk+dev@mailbox.org</email>
<timezone>+1</timezone>
</developer>
</developers>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.jdk.version>19</project.jdk.version>
<project.jdk.version>20</project.jdk.version>
<!-- Group IDs of jars that need to stay on the class path for now -->
<!-- Check progress on https://github.com/swiesend/secret-service/issues/31 to remove hypfvieh, swiesend and jnr -->
<nonModularGroupIds>com.github.jnr,org.ow2.asm,org.apache.jackrabbit,org.apache.httpcomponents,de.swiesend,org.purejava,com.github.hypfvieh</nonModularGroupIds>
<!-- Once hypfvieh, swiesend, purejava and integrations-linux have module-info, remove them-->
<nonModularGroupIds>org.ow2.asm,org.apache.jackrabbit,org.apache.httpcomponents,de.swiesend,org.purejava,com.github.hypfvieh</nonModularGroupIds>
<!-- cryptomator dependencies -->
<cryptomator.cryptofs.version>2.5.3</cryptomator.cryptofs.version>
<cryptomator.integrations.version>1.2.0-beta2</cryptomator.integrations.version>
<cryptomator.integrations.win.version>1.1.2</cryptomator.integrations.win.version>
<cryptomator.integrations.mac.version>1.1.2</cryptomator.integrations.mac.version>
<cryptomator.integrations.linux.version>1.1.0</cryptomator.integrations.linux.version>
<cryptomator.fuse.version>2.0.0-beta2</cryptomator.fuse.version>
<cryptomator.dokany.version>2.0.0-beta1</cryptomator.dokany.version>
<cryptomator.webdav.version>2.0.0-beta1</cryptomator.webdav.version>
<cryptomator.cryptofs.version>2.6.4</cryptomator.cryptofs.version>
<cryptomator.integrations.version>1.2.0</cryptomator.integrations.version>
<cryptomator.integrations.win.version>1.2.0</cryptomator.integrations.win.version>
<cryptomator.integrations.mac.version>1.2.0</cryptomator.integrations.mac.version>
<cryptomator.integrations.linux.version>1.2.1</cryptomator.integrations.linux.version>
<cryptomator.fuse.version>3.0.0</cryptomator.fuse.version>
<cryptomator.dokany.version>2.0.0</cryptomator.dokany.version>
<cryptomator.webdav.version>2.0.3</cryptomator.webdav.version>
<!-- 3rd party dependencies -->
<commons-lang3.version>3.12.0</commons-lang3.version>
<dagger.version>2.44</dagger.version>
<dagger.version>2.45</dagger.version>
<easybind.version>2.2</easybind.version>
<guava.version>31.1-jre</guava.version>
<gson.version>2.9.1</gson.version>
<javafx.version>19</javafx.version>
<jwt.version>4.2.1</jwt.version>
<nimbus-jose.version>9.25.4</nimbus-jose.version>
<logback.version>1.4.4</logback.version>
<slf4j.version>2.0.3</slf4j.version>
<gson.version>2.10.1</gson.version>
<javafx.version>20.0.1</javafx.version>
<jwt.version>4.4.0</jwt.version>
<nimbus-jose.version>9.31</nimbus-jose.version>
<logback.version>1.4.7</logback.version>
<slf4j.version>2.0.7</slf4j.version>
<tinyoauth2.version>0.5.1</tinyoauth2.version>
<zxcvbn.version>1.7.0</zxcvbn.version>
<!-- test dependencies -->
<junit.jupiter.version>5.9.1</junit.jupiter.version>
<mockito.version>4.8.0</mockito.version>
<junit.jupiter.version>5.9.3</junit.jupiter.version>
<mockito.version>5.3.1</mockito.version>
<hamcrest.version>2.2</hamcrest.version>
<!-- build-time dependencies -->
<jetbrains.annotations.version>23.0.0</jetbrains.annotations.version>
<dependency-check.version>7.4.0</dependency-check.version>
<jacoco.version>0.8.8</jacoco.version>
<dependency-check.version>8.1.0</dependency-check.version>
<jacoco.version>0.8.9</jacoco.version>
</properties>
<dependencies>
@@ -312,41 +317,6 @@
</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>compile-light-theme</id>
<phase>compile</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>javafx.graphics/com.sun.javafx.css.parser.Css2Bin</mainClass>
<arguments>
<arg>${project.basedir}/src/main/resources/css/light_theme.css</arg>
<arg>${project.build.outputDirectory}/css/light_theme.bss</arg>
</arguments>
</configuration>
</execution>
<execution>
<id>compile-dark-theme</id>
<phase>compile</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>javafx.graphics/com.sun.javafx.css.parser.Css2Bin</mainClass>
<arguments>
<arg>${project.basedir}/src/main/resources/css/dark_theme.css</arg>
<arg>${project.build.outputDirectory}/css/dark_theme.bss</arg>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
@@ -362,6 +332,9 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>--enable-preview</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
+21
View File
@@ -1,4 +1,16 @@
import ch.qos.logback.classic.spi.Configurator;
import org.cryptomator.common.locationpresets.DropboxLinuxLocationPresetsProvider;
import org.cryptomator.common.locationpresets.DropboxMacLocationPresetsProvider;
import org.cryptomator.common.locationpresets.DropboxWindowsLocationPresetsProvider;
import org.cryptomator.common.locationpresets.GoogleDriveLocationPresetsProvider;
import org.cryptomator.common.locationpresets.ICloudMacLocationPresetsProvider;
import org.cryptomator.common.locationpresets.ICloudWindowsLocationPresetsProvider;
import org.cryptomator.common.locationpresets.LocationPresetsProvider;
import org.cryptomator.common.locationpresets.MegaLocationPresetsProvider;
import org.cryptomator.common.locationpresets.OneDriveLinuxLocationPresetsProvider;
import org.cryptomator.common.locationpresets.OneDriveMacLocationPresetsProvider;
import org.cryptomator.common.locationpresets.OneDriveWindowsLocationPresetsProvider;
import org.cryptomator.common.locationpresets.PCloudLocationPresetsProvider;
import org.cryptomator.integrations.tray.TrayMenuController;
import org.cryptomator.logging.LogbackConfiguratorFactory;
import org.cryptomator.ui.traymenu.AwtTrayMenuController;
@@ -37,6 +49,15 @@ open module org.cryptomator.desktop {
/* TODO: filename-based modules: */
requires static javax.inject; /* ugly dagger/guava crap */
uses org.cryptomator.common.locationpresets.LocationPresetsProvider;
provides TrayMenuController with AwtTrayMenuController;
provides Configurator with LogbackConfiguratorFactory;
provides LocationPresetsProvider with DropboxMacLocationPresetsProvider, //
DropboxWindowsLocationPresetsProvider, DropboxLinuxLocationPresetsProvider, //
ICloudMacLocationPresetsProvider, ICloudWindowsLocationPresetsProvider, //
GoogleDriveLocationPresetsProvider, //
PCloudLocationPresetsProvider, MegaLocationPresetsProvider, //
OneDriveLinuxLocationPresetsProvider, OneDriveWindowsLocationPresetsProvider, //
OneDriveMacLocationPresetsProvider;
}
@@ -16,6 +16,7 @@ import org.cryptomator.common.settings.SettingsProvider;
import org.cryptomator.common.vaults.VaultComponent;
import org.cryptomator.common.vaults.VaultListModule;
import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
import org.cryptomator.integrations.revealpath.RevealPathService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -26,6 +27,7 @@ import java.net.InetSocketAddress;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Comparator;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.SynchronousQueue;
@@ -83,6 +85,13 @@ public abstract class CommonsModule {
return new SemVerComparator();
}
@Provides
@Singleton
static Optional<RevealPathService> provideRevealPathService() {
return RevealPathService.get().findFirst();
}
@Provides
@Singleton
static Settings provideSettings(SettingsProvider settingsProvider) {
@@ -1,5 +1,9 @@
package org.cryptomator.common;
import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingStrategy;
import java.net.URI;
public interface Constants {
String MASTERKEY_FILENAME = "masterkey.cryptomator";
@@ -7,6 +11,7 @@ public interface Constants {
String VAULTCONFIG_FILENAME = "vault.cryptomator";
String CRYPTOMATOR_FILENAME_EXT = ".cryptomator";
String CRYPTOMATOR_FILENAME_GLOB = "*.cryptomator";
URI DEFAULT_KEY_ID = URI.create(MasterkeyFileLoadingStrategy.SCHEME + ":" + MASTERKEY_FILENAME);
byte[] PEPPER = new byte[0];
}
@@ -1,64 +0,0 @@
package org.cryptomator.common;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
/**
* Enum of common cloud providers and their default local storage location path.
*/
public enum LocationPreset {
DROPBOX("Dropbox", "~/Dropbox"),
ICLOUDDRIVE("iCloud Drive", "~/Library/Mobile Documents/com~apple~CloudDocs", "~/iCloudDrive"),
GDRIVE("Google Drive", "~/Google Drive/My Drive", "~/Google Drive"),
MEGA("MEGA", "~/MEGA"),
ONEDRIVE("OneDrive", "~/OneDrive"),
PCLOUD("pCloud", "~/pCloudDrive"),
LOCAL("local");
private final String name;
private final List<Path> candidates;
LocationPreset(String name, String... candidates) {
this.name = name;
this.candidates = Arrays.stream(candidates).map(UserHome::resolve).map(Path::of).toList();
}
/**
* Checks for this LocationPreset if any of the associated paths exist.
*
* @return the first existing path or null, if none exists.
*/
public Path existingPath() {
return candidates.stream().filter(Files::isDirectory).findFirst().orElse(null);
}
public String getDisplayName() {
return name;
}
@Override
public String toString() {
return getDisplayName();
}
//this contruct is needed, since static members are initialized after every enum member is initialized
//TODO: refactor this to normal class and use this also in different parts of the project
private static class UserHome {
private static final String USER_HOME = System.getProperty("user.home");
private static String resolve(String path) {
if (path.startsWith("~/")) {
return UserHome.USER_HOME + path.substring(1);
} else {
return path;
}
}
}
}
@@ -0,0 +1,30 @@
package org.cryptomator.common;
import javafx.beans.binding.Bindings;
import javafx.beans.value.ObservableValue;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;
public class ObservableUtil {
public static <T, U> ObservableValue<U> mapWithDefault(ObservableValue<T> observable, Function<? super T, ? extends U> mapper, U defaultValue) {
return Bindings.createObjectBinding(() -> {
if (observable.getValue() == null) {
return defaultValue;
} else {
return mapper.apply(observable.getValue());
}
}, observable);
}
public static <T, U> ObservableValue<U> mapWithDefault(ObservableValue<T> observable, Function<? super T, ? extends U> mapper, Supplier<U> defaultValue) {
return Bindings.createObjectBinding(() -> {
if (observable.getValue() == null) {
return defaultValue.get();
} else {
return mapper.apply(observable.getValue());
}
}, observable);
}
}
@@ -0,0 +1,32 @@
package org.cryptomator.common.locationpresets;
import org.cryptomator.integrations.common.OperatingSystem;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import static org.cryptomator.integrations.common.OperatingSystem.Value.LINUX;
@OperatingSystem(LINUX)
public final class DropboxLinuxLocationPresetsProvider implements LocationPresetsProvider {
private static final Path USER_HOME = LocationPresetsProvider.resolveLocation("~/.").toAbsolutePath();
private static final Predicate<String> PATTERN = Pattern.compile("Dropbox \\(.+\\)").asMatchPredicate();
@Override
public Stream<LocationPreset> getLocations() {
try (var dirStream = Files.list(USER_HOME)) {
var presets = dirStream.filter(p -> Files.isDirectory(p) && PATTERN.test(p.getFileName().toString())) //
.map(p -> new LocationPreset(p.getFileName().toString(), p)) //
.toList();
return presets.stream(); //workaround to ensure that the directory stream is always closed
} catch (IOException | UncheckedIOException e) { //UncheckedIOException thrown by the stream of Files.list()
return Stream.of();
}
}
}
@@ -0,0 +1,35 @@
package org.cryptomator.common.locationpresets;
import org.cryptomator.integrations.common.CheckAvailability;
import org.cryptomator.integrations.common.OperatingSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;
import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
@OperatingSystem(MAC)
@CheckAvailability
public final class DropboxMacLocationPresetsProvider implements LocationPresetsProvider {
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/Library/CloudStorage/Dropbox");
private static final Path FALLBACK_LOCATION = LocationPresetsProvider.resolveLocation("~/Dropbox");
@CheckAvailability
public static boolean isPresent() {
return Files.isDirectory(LOCATION) || Files.isDirectory(FALLBACK_LOCATION);
}
@Override
public Stream<LocationPreset> getLocations() {
if(Files.isDirectory(LOCATION)) {
return Stream.of(new LocationPreset("Dropbox", LOCATION));
} else if(Files.isDirectory(FALLBACK_LOCATION)) {
return Stream.of(new LocationPreset("Dropbox", FALLBACK_LOCATION));
} else {
return Stream.of();
}
}
}
@@ -0,0 +1,28 @@
package org.cryptomator.common.locationpresets;
import org.cryptomator.integrations.common.CheckAvailability;
import org.cryptomator.integrations.common.OperatingSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;
import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
@OperatingSystem(WINDOWS)
@CheckAvailability
public final class DropboxWindowsLocationPresetsProvider implements LocationPresetsProvider {
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/Dropbox");
@CheckAvailability
public static boolean isPresent() {
return Files.isDirectory(LOCATION);
}
@Override
public Stream<LocationPreset> getLocations() {
return Stream.of(new LocationPreset("Dropbox", LOCATION));
}
}
@@ -0,0 +1,37 @@
package org.cryptomator.common.locationpresets;
import org.cryptomator.integrations.common.CheckAvailability;
import org.cryptomator.integrations.common.OperatingSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;
import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
@OperatingSystem(WINDOWS)
@OperatingSystem(MAC)
@CheckAvailability
public final class GoogleDriveLocationPresetsProvider implements LocationPresetsProvider {
private static final Path LOCATION1 = LocationPresetsProvider.resolveLocation("~/GoogleDrive");
private static final Path LOCATION2 = LocationPresetsProvider.resolveLocation("~/GoogleDrive/My Drive");
@CheckAvailability
public static boolean isPresent() {
return Files.isDirectory(LOCATION1) || Files.isDirectory(LOCATION2);
}
@Override
public Stream<LocationPreset> getLocations() {
if(Files.isDirectory(LOCATION1)) {
return Stream.of(new LocationPreset("Google Drive", LOCATION1));
} else if(Files.isDirectory(LOCATION2)) {
return Stream.of(new LocationPreset("Google Drive", LOCATION2));
} else {
return Stream.of();
}
}
}
@@ -0,0 +1,27 @@
package org.cryptomator.common.locationpresets;
import org.cryptomator.integrations.common.CheckAvailability;
import org.cryptomator.integrations.common.OperatingSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;
import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
@OperatingSystem(MAC)
@CheckAvailability
public final class ICloudMacLocationPresetsProvider implements LocationPresetsProvider {
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/Library/Mobile Documents/com~apple~CloudDocs");
@CheckAvailability
public static boolean isPresent() {
return Files.isDirectory(LOCATION);
}
@Override
public Stream<LocationPreset> getLocations() {
return Stream.of(new LocationPreset("iCloud Drive", LOCATION));
}
}
@@ -0,0 +1,27 @@
package org.cryptomator.common.locationpresets;
import org.cryptomator.integrations.common.CheckAvailability;
import org.cryptomator.integrations.common.OperatingSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;
import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
@OperatingSystem(WINDOWS)
@CheckAvailability
public final class ICloudWindowsLocationPresetsProvider implements LocationPresetsProvider {
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/iCloudDrive");
@CheckAvailability
public static boolean isPresent() {
return Files.isDirectory(LOCATION);
}
@Override
public Stream<LocationPreset> getLocations() {
return Stream.of(new LocationPreset("iCloud Drive", LOCATION));
}
}
@@ -0,0 +1,9 @@
package org.cryptomator.common.locationpresets;
import java.nio.file.Path;
public record LocationPreset(String name, Path path) {
}
@@ -0,0 +1,97 @@
package org.cryptomator.common.locationpresets;
import org.cryptomator.integrations.common.CheckAvailability;
import org.cryptomator.integrations.common.IntegrationsLoader;
import org.cryptomator.integrations.common.OperatingSystem;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.ServiceLoader;
import java.util.stream.Stream;
public interface LocationPresetsProvider {
Logger LOG = LoggerFactory.getLogger(LocationPresetsProvider.class);
String USER_HOME = System.getProperty("user.home");
/**
* Streams account-separated location presets found by this provider
* @return Stream of LocationPresets
*/
Stream<LocationPreset> getLocations();
static Path resolveLocation(String p) {
if (p.startsWith("~/")) {
return Path.of(USER_HOME, p.substring(2));
} else {
return Path.of(p);
}
}
//copied from org.cryptomator.integrations.common.IntegrationsLoader
//TODO: delete, once migrated to integrations-api
static <T> Stream<T> loadAll(Class<T> clazz) {
return ServiceLoader.load(clazz)
.stream()
.filter(LocationPresetsProvider::isSupportedOperatingSystem)
.filter(LocationPresetsProvider::passesStaticAvailabilityCheck)
.map(ServiceLoader.Provider::get)
.peek(impl -> logServiceIsAvailable(clazz, impl.getClass()));
}
private static boolean isSupportedOperatingSystem(ServiceLoader.Provider<?> provider) {
var annotations = provider.type().getAnnotationsByType(OperatingSystem.class);
return annotations.length == 0 || Arrays.stream(annotations).anyMatch(OperatingSystem.Value::isCurrent);
}
private static boolean passesStaticAvailabilityCheck(ServiceLoader.Provider<?> provider) {
return passesStaticAvailabilityCheck(provider.type());
}
static boolean passesStaticAvailabilityCheck(Class<?> type) {
return passesAvailabilityCheck(type, null);
}
private static void logServiceIsAvailable(Class<?> apiType, Class<?> implType) {
if (LOG.isDebugEnabled()) {
LOG.debug("{}: Implementation is available: {}", apiType.getSimpleName(), implType.getName());
}
}
private static <T> boolean passesAvailabilityCheck(Class<? extends T> type, @Nullable T instance) {
if (!type.isAnnotationPresent(CheckAvailability.class)) {
return true; // if type is not annotated, skip tests
}
if (!type.getModule().isExported(type.getPackageName(), IntegrationsLoader.class.getModule())) {
LOG.error("Can't run @CheckAvailability tests for class {}. Make sure to export {} to {}!", type.getName(), type.getPackageName(), IntegrationsLoader.class.getPackageName());
return false;
}
return Arrays.stream(type.getMethods())
.filter(m -> isAvailabilityCheck(m, instance == null))
.allMatch(m -> passesAvailabilityCheck(m, instance));
}
private static boolean passesAvailabilityCheck(Method m, @Nullable Object instance) {
assert Boolean.TYPE.equals(m.getReturnType());
try {
return (boolean) m.invoke(instance);
} catch (ReflectiveOperationException e) {
LOG.warn("Failed to invoke @CheckAvailability test {}#{}", m.getDeclaringClass(), m.getName(), e);
return false;
}
}
private static boolean isAvailabilityCheck(Method m, boolean isStatic) {
return m.isAnnotationPresent(CheckAvailability.class)
&& Boolean.TYPE.equals(m.getReturnType())
&& m.getParameterCount() == 0
&& Modifier.isStatic(m.getModifiers()) == isStatic;
}
}
@@ -0,0 +1,29 @@
package org.cryptomator.common.locationpresets;
import org.cryptomator.integrations.common.CheckAvailability;
import org.cryptomator.integrations.common.OperatingSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;
import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
@OperatingSystem(WINDOWS)
@OperatingSystem(MAC)
@CheckAvailability
public final class MegaLocationPresetsProvider implements LocationPresetsProvider {
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/MEGA");
@CheckAvailability
public static boolean isPresent() {
return Files.isDirectory(LOCATION);
}
@Override
public Stream<LocationPreset> getLocations() {
return Stream.of(new LocationPreset("MEGA", LOCATION));
}
}
@@ -0,0 +1,28 @@
package org.cryptomator.common.locationpresets;
import org.cryptomator.integrations.common.CheckAvailability;
import org.cryptomator.integrations.common.OperatingSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;
import static org.cryptomator.integrations.common.OperatingSystem.Value.LINUX;
@OperatingSystem(LINUX)
@CheckAvailability
public final class OneDriveLinuxLocationPresetsProvider implements LocationPresetsProvider {
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/OneDrive");
@CheckAvailability
public static boolean isPresent() {
return Files.isDirectory(LOCATION);
}
@Override
public Stream<LocationPreset> getLocations() {
return Stream.of(new LocationPreset("OneDrive", LOCATION));
}
}
@@ -0,0 +1,44 @@
package org.cryptomator.common.locationpresets;
import org.cryptomator.integrations.common.OperatingSystem;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
@OperatingSystem(MAC)
public final class OneDriveMacLocationPresetsProvider implements LocationPresetsProvider {
private static final Path FALLBACK_LOCATION = LocationPresetsProvider.resolveLocation("~/OneDrive");
private static final Path PARENT_LOCATION = LocationPresetsProvider.resolveLocation("~/Library/CloudStorage");
@Override
public Stream<LocationPreset> getLocations() {
var newLocations = getNewLocations().toList();
if (newLocations.size() >= 1) {
return newLocations.stream();
} else {
return getOldLocation();
}
}
private Stream<LocationPreset> getNewLocations() {
try (var dirStream = Files.newDirectoryStream(PARENT_LOCATION, "OneDrive*")) {
return StreamSupport.stream(dirStream.spliterator(), false) //
.filter(Files::isDirectory) //
.map(p -> new LocationPreset(String.join(" - ", p.getFileName().toString().split("-")), p));
} catch (IOException e) {
return Stream.of();
}
}
private Stream<LocationPreset> getOldLocation() {
return Stream.of(new LocationPreset("OneDrive", FALLBACK_LOCATION)).filter(preset -> Files.isDirectory(preset.path()));
}
}
@@ -0,0 +1,108 @@
package org.cryptomator.common.locationpresets;
import org.cryptomator.integrations.common.OperatingSystem;
import org.jetbrains.annotations.Blocking;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
@OperatingSystem(WINDOWS)
public final class OneDriveWindowsLocationPresetsProvider implements LocationPresetsProvider {
private static final Logger LOG = LoggerFactory.getLogger(OneDriveWindowsLocationPresetsProvider.class);
private static final String REGSTR_TOKEN = "REG_SZ";
private static final String REG_ONEDRIVE_ACCOUNTS = "HKEY_CURRENT_USER\\Software\\Microsoft\\OneDrive\\Accounts\\";
@Override
public Stream<LocationPreset> getLocations() {
try {
var accountRegKeys = queryRegistry(REG_ONEDRIVE_ACCOUNTS, List.of(), l -> l.startsWith(REG_ONEDRIVE_ACCOUNTS)).toList();
var cloudLocations = new ArrayList<LocationPreset>();
for (var accountRegKey : accountRegKeys) {
var path = queryRegistry(accountRegKey, List.of("/v", "UserFolder"), l -> l.contains("UserFolder")).map(result -> result.substring(result.indexOf(REGSTR_TOKEN) + REGSTR_TOKEN.length()).trim()) //
.map(Path::of) //
.findFirst().orElseThrow();
var name = "OneDrive"; //we assume personal oneDrive account by default
if (!accountRegKey.endsWith("Personal")) {
name = queryRegistry(accountRegKey, List.of("/v", "DisplayName"), l -> l.contains("DisplayName")).map(result -> result.substring(result.indexOf(REGSTR_TOKEN) + REGSTR_TOKEN.length()).trim()) //
.map("OneDrive - "::concat) //
.findFirst().orElseThrow();
}
cloudLocations.add(new LocationPreset(name, path));
}
return cloudLocations.stream();
} catch (IOException | CommandFailedException | TimeoutException e) {
LOG.error("Unable to determine OneDrive location", e);
return Stream.of();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LOG.error("Determination of OneDrive location interrupted", e);
return Stream.of();
}
}
private Stream<String> queryRegistry(String keyname, List<String> moreArgs, Predicate<String> outputFilter) throws InterruptedException, CommandFailedException, TimeoutException, IOException {
var args = new ArrayList<String>();
args.add("reg");
args.add("query");
args.add(keyname);
args.addAll(moreArgs);
ProcessBuilder command = new ProcessBuilder(args);
Process p = command.start();
waitForSuccess(p, 3, "`reg query`");
return p.inputReader(StandardCharsets.UTF_8).lines().filter(outputFilter);
}
/**
* Waits {@code timeoutSeconds} seconds for {@code process} to finish with exit code {@code 0}.
*
* @param process The process to wait for
* @param timeoutSeconds How long to wait (in seconds)
* @param cmdDescription A short description of the process used to generate log and exception messages
* @throws TimeoutException Thrown when the process doesn't finish in time
* @throws InterruptedException Thrown when the thread is interrupted while waiting for the process to finish
* @throws CommandFailedException Thrown when the process exit code is non-zero
*/
@Blocking
private static void waitForSuccess(Process process, int timeoutSeconds, String cmdDescription) throws TimeoutException, InterruptedException, CommandFailedException {
boolean exited = process.waitFor(timeoutSeconds, TimeUnit.SECONDS);
if (!exited) {
throw new TimeoutException(cmdDescription + " timed out after " + timeoutSeconds + "s");
}
if (process.exitValue() != 0) {
@SuppressWarnings("resource") var stdout = process.inputReader(StandardCharsets.UTF_8).lines().collect(Collectors.joining("\n"));
@SuppressWarnings("resource") var stderr = process.errorReader(StandardCharsets.UTF_8).lines().collect(Collectors.joining("\n"));
throw new CommandFailedException(cmdDescription, process.exitValue(), stdout, stderr);
}
}
private static class CommandFailedException extends Exception {
int exitCode;
String stdout;
String stderr;
private CommandFailedException(String cmdDescription, int exitCode, String stdout, String stderr) {
super(cmdDescription + " returned with non-zero exit code " + exitCode);
this.exitCode = exitCode;
this.stdout = stdout;
this.stderr = stderr;
}
}
}
@@ -0,0 +1,30 @@
package org.cryptomator.common.locationpresets;
import org.cryptomator.integrations.common.CheckAvailability;
import org.cryptomator.integrations.common.OperatingSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;
import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
@OperatingSystem(WINDOWS)
@OperatingSystem(MAC)
@CheckAvailability
public final class PCloudLocationPresetsProvider implements LocationPresetsProvider {
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/pCloudDrive");
@CheckAvailability
public static boolean isPresent() {
return Files.isDirectory(LOCATION);
}
@Override
public Stream<LocationPreset> getLocations() {
return Stream.of(new LocationPreset("pCloud", LOCATION));
}
}
@@ -0,0 +1,6 @@
package org.cryptomator.common.mount;
import org.cryptomator.integrations.mount.MountService;
public record ActualMountService(MountService service, boolean isDesired) {
}
@@ -0,0 +1,9 @@
package org.cryptomator.common.mount;
public class IllegalMountPointException extends IllegalArgumentException {
public IllegalMountPointException(String msg) {
super(msg);
}
}
@@ -2,16 +2,23 @@ package org.cryptomator.common.mount;
import dagger.Module;
import dagger.Provides;
import org.cryptomator.common.ObservableUtil;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.integrations.mount.Mount;
import org.cryptomator.integrations.mount.MountService;
import javax.inject.Named;
import javax.inject.Singleton;
import javafx.beans.value.ObservableValue;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
@Module
public class MountModule {
private static final AtomicReference<MountService> formerSelectedMountService = new AtomicReference<>(null);
private static final List<String> problematicFuseMountServices = List.of("org.cryptomator.frontend.fuse.mount.MacFuseMountProvider", "org.cryptomator.frontend.fuse.mount.FuseTMountProvider");
@Provides
@Singleton
static List<MountService> provideSupportedMountServices() {
@@ -20,11 +27,46 @@ public class MountModule {
@Provides
@Singleton
static ObservableValue<MountService> provideMountService(Settings settings, List<MountService> serviceImpls) {
return settings.mountService().map(desiredServiceImpl -> {
var fallbackProvider = serviceImpls.stream().findFirst().orElse(null);
return serviceImpls.stream().filter(serviceImpl -> serviceImpl.getClass().getName().equals(desiredServiceImpl)).findAny().orElse(fallbackProvider);
});
@Named("FUPFMS")
static AtomicReference<MountService> provideFirstUsedProblematicFuseMountService() {
return new AtomicReference<>(null);
}
@Provides
@Singleton
static ObservableValue<ActualMountService> provideMountService(Settings settings, List<MountService> serviceImpls, @Named("FUPFMS") AtomicReference<MountService> fupfms) {
var fallbackProvider = serviceImpls.stream().findFirst().orElse(null);
var observableMountService = ObservableUtil.mapWithDefault(settings.mountService(), //
desiredServiceImpl -> { //
var serviceFromSettings = serviceImpls.stream().filter(serviceImpl -> serviceImpl.getClass().getName().equals(desiredServiceImpl)).findAny(); //
var targetedService = serviceFromSettings.orElse(fallbackProvider);
return applyWorkaroundForProblematicFuse(targetedService, serviceFromSettings.isPresent(), fupfms);
}, //
() -> { //
return applyWorkaroundForProblematicFuse(fallbackProvider, true, fupfms);
});
return observableMountService;
}
//see https://github.com/cryptomator/cryptomator/issues/2786
private synchronized static ActualMountService applyWorkaroundForProblematicFuse(MountService targetedService, boolean isDesired, AtomicReference<MountService> firstUsedProblematicFuseMountService) {
//set the first used problematic fuse service if applicable
var targetIsProblematicFuse = isProblematicFuseService(targetedService);
if (targetIsProblematicFuse && firstUsedProblematicFuseMountService.get() == null) {
firstUsedProblematicFuseMountService.set(targetedService);
}
//do not use the targeted mount service and fallback to former one, if the service is problematic _and_ not the first problematic one used.
if (targetIsProblematicFuse && !firstUsedProblematicFuseMountService.get().equals(targetedService)) {
return new ActualMountService(formerSelectedMountService.get(), false);
} else {
formerSelectedMountService.set(targetedService);
return new ActualMountService(targetedService, isDesired);
}
}
public static boolean isProblematicFuseService(MountService service) {
return problematicFuseMountServices.contains(service.getClass().getName());
}
}
@@ -0,0 +1,8 @@
package org.cryptomator.common.mount;
public class MountPointNotExistsException extends IllegalMountPointException {
public MountPointNotExistsException(String msg) {
super(msg);
}
}
@@ -0,0 +1,8 @@
package org.cryptomator.common.mount;
public class MountPointNotSupportedException extends IllegalMountPointException {
public MountPointNotSupportedException(String msg) {
super(msg);
}
}
@@ -0,0 +1,12 @@
package org.cryptomator.common.mount;
public class MountPointPreparationException extends RuntimeException {
public MountPointPreparationException(String msg) {
super(msg);
}
public MountPointPreparationException(Throwable cause) {
super(cause);
}
}
@@ -0,0 +1,121 @@
package org.cryptomator.common.mount;
import org.apache.commons.lang3.SystemUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.file.DirectoryNotEmptyException;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.NoSuchFileException;
import java.nio.file.NotDirectoryException;
import java.nio.file.Path;
public final class MountWithinParentUtil {
private static final Logger LOG = LoggerFactory.getLogger(Mounter.class);
private static final String HIDEAWAY_PREFIX = ".~$";
private static final String HIDEAWAY_SUFFIX = ".tmp";
private static final String WIN_HIDDEN_ATTR = "dos:hidden";
private MountWithinParentUtil() {}
static void prepareParentNoMountPoint(Path mountPoint) throws MountPointPreparationException {
Path hideaway = getHideaway(mountPoint);
var mpExists = Files.exists(mountPoint, LinkOption.NOFOLLOW_LINKS);
var hideExists = Files.exists(hideaway, LinkOption.NOFOLLOW_LINKS);
//TODO: possible improvement by just deleting an _empty_ hideaway
if (mpExists && hideExists) { //both resources exist (whatever type)
throw new MountPointPreparationException(new FileAlreadyExistsException(hideaway.toString()));
} else if (!mpExists && !hideExists) { //neither mountpoint nor hideaway exist
throw new MountPointPreparationException(new NoSuchFileException(mountPoint.toString()));
} else if (!mpExists) { //only hideaway exists
checkIsDirectory(hideaway);
LOG.info("Mountpoint {} seems to be not properly cleaned up. Will be fixed on unmount.", mountPoint);
try {
if (SystemUtils.IS_OS_WINDOWS) {
Files.setAttribute(hideaway, WIN_HIDDEN_ATTR, true, LinkOption.NOFOLLOW_LINKS);
}
} catch (IOException e) {
throw new MountPointPreparationException(e);
}
} else { //only mountpoint exists
try {
checkIsDirectory(mountPoint);
checkIsEmpty(mountPoint);
Files.move(mountPoint, hideaway);
if (SystemUtils.IS_OS_WINDOWS) {
Files.setAttribute(hideaway, WIN_HIDDEN_ATTR, true, LinkOption.NOFOLLOW_LINKS);
}
int attempts = 0;
while (!Files.notExists(mountPoint)) {
if (attempts >= 10) {
throw new MountPointPreparationException("Path " + mountPoint + " could not be cleared");
}
Thread.sleep(1000);
attempts++;
}
} catch (IOException e) {
throw new MountPointPreparationException(e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new MountPointPreparationException(e);
}
}
}
static void cleanup(Path mountPoint) {
Path hideaway = getHideaway(mountPoint);
try {
waitForMountpointRestoration(mountPoint);
Files.move(hideaway, mountPoint);
if (SystemUtils.IS_OS_WINDOWS) {
Files.setAttribute(mountPoint, WIN_HIDDEN_ATTR, false);
}
} catch (IOException e) {
LOG.error("Unable to restore hidden directory to mountpoint {}.", mountPoint, e);
}
}
//on Windows removing the mountpoint takes some time, so we poll for at most 3 seconds
private static void waitForMountpointRestoration(Path mountPoint) throws FileAlreadyExistsException {
int attempts = 0;
while (!Files.notExists(mountPoint, LinkOption.NOFOLLOW_LINKS)) {
attempts++;
if (attempts >= 5) {
throw new FileAlreadyExistsException("Timeout waiting for mountpoint cleanup for " + mountPoint + " .");
}
try {
Thread.sleep(300);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new FileAlreadyExistsException("Interrupted before mountpoint " + mountPoint + " was cleared");
}
}
}
private static void checkIsDirectory(Path toCheck) throws MountPointPreparationException {
if (!Files.isDirectory(toCheck, LinkOption.NOFOLLOW_LINKS)) {
throw new MountPointPreparationException(new NotDirectoryException(toCheck.toString()));
}
}
private static void checkIsEmpty(Path toCheck) throws MountPointPreparationException, IOException {
try (var dirStream = Files.list(toCheck)) {
if (dirStream.findFirst().isPresent()) {
throw new MountPointPreparationException(new DirectoryNotEmptyException(toCheck.toString()));
}
}
}
//visible for testing
static Path getHideaway(Path mountPoint) {
return mountPoint.resolveSibling(HIDEAWAY_PREFIX + mountPoint.getFileName().toString() + HIDEAWAY_SUFFIX);
}
}
@@ -0,0 +1,141 @@
package org.cryptomator.common.mount;
import org.cryptomator.common.Environment;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.settings.VaultSettings;
import org.cryptomator.integrations.mount.Mount;
import org.cryptomator.integrations.mount.MountBuilder;
import org.cryptomator.integrations.mount.MountFailedException;
import org.cryptomator.integrations.mount.MountService;
import javax.inject.Inject;
import javax.inject.Singleton;
import javafx.beans.value.ObservableValue;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.cryptomator.integrations.mount.MountCapability.MOUNT_AS_DRIVE_LETTER;
import static org.cryptomator.integrations.mount.MountCapability.MOUNT_TO_EXISTING_DIR;
import static org.cryptomator.integrations.mount.MountCapability.MOUNT_TO_SYSTEM_CHOSEN_PATH;
import static org.cryptomator.integrations.mount.MountCapability.MOUNT_WITHIN_EXISTING_PARENT;
import static org.cryptomator.integrations.mount.MountCapability.UNMOUNT_FORCED;
@Singleton
public class Mounter {
private final Settings settings;
private final Environment env;
private final WindowsDriveLetters driveLetters;
private final ObservableValue<ActualMountService> mountServiceObservable;
@Inject
public Mounter(Settings settings, Environment env, WindowsDriveLetters driveLetters, ObservableValue<ActualMountService> mountServiceObservable) {
this.settings = settings;
this.env = env;
this.driveLetters = driveLetters;
this.mountServiceObservable = mountServiceObservable;
}
private class SettledMounter {
private MountService service;
private MountBuilder builder;
private VaultSettings vaultSettings;
public SettledMounter(MountService service, MountBuilder builder, VaultSettings vaultSettings) {
this.service = service;
this.builder = builder;
this.vaultSettings = vaultSettings;
}
Runnable prepare() throws IOException {
for (var capability : service.capabilities()) {
switch (capability) {
case FILE_SYSTEM_NAME -> builder.setFileSystemName("cryptoFs");
case LOOPBACK_PORT ->
builder.setLoopbackPort(settings.port().get()); //TODO: move port from settings to vaultsettings (see https://github.com/cryptomator/cryptomator/tree/feature/mount-setting-per-vault)
case LOOPBACK_HOST_NAME -> env.getLoopbackAlias().ifPresent(builder::setLoopbackHostName);
case READ_ONLY -> builder.setReadOnly(vaultSettings.usesReadOnlyMode().get());
case MOUNT_FLAGS -> {
var mountFlags = vaultSettings.mountFlags().get();
if (mountFlags == null || mountFlags.isBlank()) {
builder.setMountFlags(service.getDefaultMountFlags());
} else {
builder.setMountFlags(mountFlags);
}
}
case VOLUME_ID -> builder.setVolumeId(vaultSettings.getId());
case VOLUME_NAME -> builder.setVolumeName(vaultSettings.mountName().get());
}
}
return prepareMountPoint();
}
private Runnable prepareMountPoint() throws IOException {
Runnable cleanup = () -> {};
var userChosenMountPoint = vaultSettings.getMountPoint();
var defaultMountPointBase = env.getMountPointsDir().orElseThrow();
var canMountToDriveLetter = service.hasCapability(MOUNT_AS_DRIVE_LETTER);
var canMountToParent = service.hasCapability(MOUNT_WITHIN_EXISTING_PARENT);
var canMountToDir = service.hasCapability(MOUNT_TO_EXISTING_DIR);
var canMountToSystem = service.hasCapability(MOUNT_TO_SYSTEM_CHOSEN_PATH);
if (userChosenMountPoint == null) {
if (canMountToSystem) {
// no need to set a mount point
} else if (canMountToDriveLetter) {
builder.setMountpoint(driveLetters.getFirstDesiredAvailable().orElseThrow()); //TODO: catch exception and translate
} else if (canMountToParent) {
Files.createDirectories(defaultMountPointBase);
builder.setMountpoint(defaultMountPointBase);
} else if (canMountToDir) {
var mountPoint = defaultMountPointBase.resolve(vaultSettings.mountName().get());
Files.createDirectories(mountPoint);
builder.setMountpoint(mountPoint);
}
} else {
var mpIsDriveLetter = userChosenMountPoint.toString().matches("[A-Z]:\\\\");
if (!mpIsDriveLetter && canMountToParent && !canMountToDir) {
MountWithinParentUtil.prepareParentNoMountPoint(userChosenMountPoint);
cleanup = () -> {
MountWithinParentUtil.cleanup(userChosenMountPoint);
};
}
try {
builder.setMountpoint(userChosenMountPoint);
} catch (IllegalArgumentException | UnsupportedOperationException e) {
var configNotSupported = (!canMountToDriveLetter && mpIsDriveLetter) //mounting as driveletter, albeit not supported
|| (!canMountToDir && !mpIsDriveLetter) //mounting to directory, albeit not supported
|| (!canMountToParent && !mpIsDriveLetter) //
|| (!canMountToDir && !canMountToParent && !canMountToSystem && !canMountToDriveLetter);
if (configNotSupported) {
throw new MountPointNotSupportedException(e.getMessage());
} else if (canMountToDir && !canMountToParent && !Files.exists(userChosenMountPoint)) {
//mountpoint must exist
throw new MountPointNotExistsException(e.getMessage());
} else {
//TODO: add specific exception for !canMountToDir && canMountToParent && !Files.notExists(userChosenMountPoint)
throw new IllegalMountPointException(e.getMessage());
}
}
}
return cleanup;
}
}
public MountHandle mount(VaultSettings vaultSettings, Path cryptoFsRoot) throws IOException, MountFailedException {
var mountService = this.mountServiceObservable.getValue().service();
var builder = mountService.forFileSystem(cryptoFsRoot);
var internal = new SettledMounter(mountService, builder, vaultSettings);
var cleanup = internal.prepare();
return new MountHandle(builder.mount(), mountService.hasCapability(UNMOUNT_FORCED), cleanup);
}
public record MountHandle(Mount mountObj, boolean supportsUnmountForced, Runnable specialCleanup) {
}
}
@@ -76,6 +76,11 @@ public class DeviceKey {
private P384KeyPair createAndStoreNewKeyPair(char[] passphrase, Path p12File) throws IOException {
var keyPair = P384KeyPair.generate();
var tmpFile = p12File.resolveSibling(p12File.getFileName().toString() + ".tmp");
if(Files.exists(tmpFile)) {
LOG.debug("Leftover from devicekey creation detected. Deleting {}", tmpFile);
Files.delete(tmpFile);
}
LOG.debug("Store new device key to {}", p12File);
keyPair.store(p12File, passphrase);
return keyPair;
@@ -9,6 +9,7 @@ import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.common.Environment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -36,29 +37,30 @@ public class SettingsJsonAdapter extends TypeAdapter<Settings> {
@Override
public void write(JsonWriter out, Settings value) throws IOException {
out.beginObject();
out.name("writtenByVersion").value(env.getAppVersion() + env.getBuildNumber().map("-"::concat).orElse(""));
out.name("directories");
writeVaultSettingsArray(out, value.getDirectories());
out.name("askedForUpdateCheck").value(value.askedForUpdateCheck().get());
out.name("checkForUpdatesEnabled").value(value.checkForUpdates().get());
out.name("startHidden").value(value.startHidden().get());
out.name("autoCloseVaults").value(value.autoCloseVaults().get());
out.name("port").value(value.port().get());
out.name("numTrayNotifications").value(value.numTrayNotifications().get());
out.name("checkForUpdatesEnabled").value(value.checkForUpdates().get());
out.name("debugMode").value(value.debugMode().get());
out.name("theme").value(value.theme().get().name());
out.name("uiOrientation").value(value.userInterfaceOrientation().get().name());
out.name("displayConfiguration").value((value.displayConfigurationProperty().get()));
out.name("keychainProvider").value(value.keychainProvider().get());
out.name("useKeychain").value(value.useKeychain().get());
out.name("language").value((value.languageProperty().get()));
out.name("licenseKey").value(value.licenseKey().get());
out.name("mountService").value(value.mountService().get());
out.name("numTrayNotifications").value(value.numTrayNotifications().get());
out.name("port").value(value.port().get());
out.name("showMinimizeButton").value(value.showMinimizeButton().get());
out.name("showTrayIcon").value(value.showTrayIcon().get());
out.name("startHidden").value(value.startHidden().get());
out.name("theme").value(value.theme().get().name());
out.name("uiOrientation").value(value.userInterfaceOrientation().get().name());
out.name("useKeychain").value(value.useKeychain().get());
out.name("windowHeight").value((value.windowHeightProperty().get()));
out.name("windowWidth").value((value.windowWidthProperty().get()));
out.name("windowXPosition").value((value.windowXPositionProperty().get()));
out.name("windowYPosition").value((value.windowYPositionProperty().get()));
out.name("windowWidth").value((value.windowWidthProperty().get()));
out.name("windowHeight").value((value.windowHeightProperty().get()));
out.name("displayConfiguration").value((value.displayConfigurationProperty().get()));
out.name("language").value((value.languageProperty().get()));
out.name("mountService").value(value.mountService().get());
out.endObject();
}
@@ -73,50 +75,84 @@ public class SettingsJsonAdapter extends TypeAdapter<Settings> {
@Override
public Settings read(JsonReader in) throws IOException {
Settings settings = new Settings(env);
//1.6.x legacy
String volumeImpl = null;
//legacy end
in.beginObject();
while (in.hasNext()) {
String name = in.nextName();
switch (name) {
case "writtenByVersion" -> in.skipValue(); //noop
case "directories" -> settings.getDirectories().addAll(readVaultSettingsArray(in));
case "askedForUpdateCheck" -> settings.askedForUpdateCheck().set(in.nextBoolean());
case "checkForUpdatesEnabled" -> settings.checkForUpdates().set(in.nextBoolean());
case "startHidden" -> settings.startHidden().set(in.nextBoolean());
case "autoCloseVaults" -> settings.autoCloseVaults().set(in.nextBoolean());
case "port" -> settings.port().set(in.nextInt());
case "numTrayNotifications" -> settings.numTrayNotifications().set(in.nextInt());
case "checkForUpdatesEnabled" -> settings.checkForUpdates().set(in.nextBoolean());
case "debugMode" -> settings.debugMode().set(in.nextBoolean());
case "theme" -> settings.theme().set(parseUiTheme(in.nextString()));
case "uiOrientation" -> settings.userInterfaceOrientation().set(parseUiOrientation(in.nextString()));
case "keychainProvider" -> settings.keychainProvider().set(in.nextString());
case "useKeychain" -> settings.useKeychain().set(in.nextBoolean());
case "licenseKey" -> settings.licenseKey().set(in.nextString());
case "showMinimizeButton" -> settings.showMinimizeButton().set(in.nextBoolean());
case "showTrayIcon" -> settings.showTrayIcon().set(in.nextBoolean());
case "windowXPosition" -> settings.windowXPositionProperty().set(in.nextInt());
case "windowYPosition" -> settings.windowYPositionProperty().set(in.nextInt());
case "windowWidth" -> settings.windowWidthProperty().set(in.nextInt());
case "windowHeight" -> settings.windowHeightProperty().set(in.nextInt());
case "displayConfiguration" -> settings.displayConfigurationProperty().set(in.nextString());
case "keychainProvider" -> settings.keychainProvider().set(in.nextString());
case "language" -> settings.languageProperty().set(in.nextString());
case "licenseKey" -> settings.licenseKey().set(in.nextString());
case "mountService" -> {
var token = in.peek();
if (JsonToken.STRING == token) {
settings.mountService().set(in.nextString());
}
}
case "numTrayNotifications" -> settings.numTrayNotifications().set(in.nextInt());
case "port" -> settings.port().set(in.nextInt());
case "showMinimizeButton" -> settings.showMinimizeButton().set(in.nextBoolean());
case "showTrayIcon" -> settings.showTrayIcon().set(in.nextBoolean());
case "startHidden" -> settings.startHidden().set(in.nextBoolean());
case "theme" -> settings.theme().set(parseUiTheme(in.nextString()));
case "uiOrientation" -> settings.userInterfaceOrientation().set(parseUiOrientation(in.nextString()));
case "useKeychain" -> settings.useKeychain().set(in.nextBoolean());
case "windowHeight" -> settings.windowHeightProperty().set(in.nextInt());
case "windowWidth" -> settings.windowWidthProperty().set(in.nextInt());
case "windowXPosition" -> settings.windowXPositionProperty().set(in.nextInt());
case "windowYPosition" -> settings.windowYPositionProperty().set(in.nextInt());
//1.6.x legacy
case "preferredVolumeImpl" -> volumeImpl = in.nextString();
//legacy end
default -> {
LOG.warn("Unsupported vault setting found in JSON: {}", name);
in.skipValue();
}
}
}
in.endObject();
//1.6.x legacy
if (volumeImpl != null) {
settings.mountService().set(convertLegacyVolumeImplToMountService(volumeImpl));
}
//legacy end
return settings;
}
private String convertLegacyVolumeImplToMountService(String volumeImpl) {
if (volumeImpl.equals("Dokany")) {
return "org.cryptomator.frontend.dokany.mount.DokanyMountProvider";
} else if (volumeImpl.equals("FUSE")) {
if (SystemUtils.IS_OS_WINDOWS) {
return "org.cryptomator.frontend.fuse.mount.WinFspNetworkMountProvider";
} else if (SystemUtils.IS_OS_MAC) {
return "org.cryptomator.frontend.fuse.mount.MacFuseMountProvider";
} else {
return "org.cryptomator.frontend.fuse.mount.LinuxFuseMountProvider";
}
} else {
if (SystemUtils.IS_OS_WINDOWS) {
return "org.cryptomator.frontend.webdav.mount.WindowsMounter";
} else if (SystemUtils.IS_OS_MAC) {
return "org.cryptomator.frontend.webdav.mount.MacAppleScriptMounter";
} else {
return "org.cryptomator.frontend.webdav.mount.LinuxGioMounter";
}
}
}
private UiTheme parseUiTheme(String uiThemeName) {
try {
return UiTheme.valueOf(uiThemeName.toUpperCase());
@@ -45,7 +45,7 @@ public class VaultSettings {
private final BooleanProperty unlockAfterStartup = new SimpleBooleanProperty(DEFAULT_UNLOCK_AFTER_STARTUP);
private final BooleanProperty revealAfterMount = new SimpleBooleanProperty(DEFAULT_REVEAL_AFTER_MOUNT);
private final BooleanProperty usesReadOnlyMode = new SimpleBooleanProperty(DEFAULT_USES_READONLY_MODE);
private final StringProperty mountFlags = new SimpleStringProperty(DEFAULT_MOUNT_FLAGS);
private final StringProperty mountFlags = new SimpleStringProperty(DEFAULT_MOUNT_FLAGS); //TODO: remove empty default mount flags and let this property be null if not used
private final IntegerProperty maxCleartextFilenameLength = new SimpleIntegerProperty(DEFAULT_MAX_CLEARTEXT_FILENAME_LENGTH);
private final ObjectProperty<WhenUnlocked> actionAfterUnlock = new SimpleObjectProperty<>(DEFAULT_ACTION_AFTER_UNLOCK);
private final BooleanProperty autoLockWhenIdle = new SimpleBooleanProperty(DEFAULT_AUTOLOCK_WHEN_IDLE);
@@ -38,8 +38,6 @@ class VaultSettingsJsonAdapter {
out.endObject();
}
//TODO: usesCustomMountPath, customMountPath and winDriveLetter removed
// -> migration required
public VaultSettings read(JsonReader in) throws IOException {
String id = null;
String path = null;
@@ -55,6 +53,12 @@ class VaultSettingsJsonAdapter {
boolean autoLockWhenIdle = VaultSettings.DEFAULT_AUTOLOCK_WHEN_IDLE;
int autoLockIdleSeconds = VaultSettings.DEFAULT_AUTOLOCK_IDLE_SECONDS;
//legacy from 1.6.x
boolean useCustomMountPath = false;
String customMountPath = "";
String winDriveLetter = "";
//legacy end
in.beginObject();
while (in.hasNext()) {
String name = in.nextName();
@@ -78,6 +82,11 @@ class VaultSettingsJsonAdapter {
case "actionAfterUnlock" -> actionAfterUnlock = parseActionAfterUnlock(in.nextString());
case "autoLockWhenIdle" -> autoLockWhenIdle = in.nextBoolean();
case "autoLockIdleSeconds" -> autoLockIdleSeconds = in.nextInt();
//legacy from 1.6.x
case "winDriveLetter" -> winDriveLetter = in.nextString();
case "usesIndividualMountPath", "useCustomMountPath" -> useCustomMountPath = in.nextBoolean();
case "individualMountPath", "customMountPath" -> customMountPath = in.nextString();
//legacy end
default -> {
LOG.warn("Unsupported vault setting found in JSON: {}", name);
in.skipValue();
@@ -102,6 +111,13 @@ class VaultSettingsJsonAdapter {
vaultSettings.autoLockWhenIdle().set(autoLockWhenIdle);
vaultSettings.autoLockIdleSeconds().set(autoLockIdleSeconds);
vaultSettings.mountPoint().set(mountPoint);
//legacy from 1.6.x
if(useCustomMountPath && !customMountPath.isBlank()) {
vaultSettings.mountPoint().set(parseMountPoint(customMountPath));
} else if(!winDriveLetter.isBlank() ) {
vaultSettings.mountPoint().set(parseMountPoint(winDriveLetter+":\\"));
}
//legacy end
return vaultSettings;
}
@@ -1,18 +0,0 @@
package org.cryptomator.common.settings;
public enum VolumeImpl {
WEBDAV("WebDAV"),
FUSE("FUSE"),
DOKANY("Dokany");
private String displayName;
VolumeImpl(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return displayName;
}
}
@@ -6,6 +6,7 @@ import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Singleton;
import javafx.application.Platform;
import javafx.collections.ObservableList;
import java.io.IOException;
import java.time.Instant;
@@ -40,6 +41,7 @@ public class AutoLocker {
private void autolock(Vault vault) {
try {
vault.lock(false);
Platform.runLater(() -> vault.stateProperty().set(VaultState.Value.LOCKED));
LOG.info("Autolocked {} after idle timeout", vault.getDisplayName());
} catch (UnmountFailedException | IOException e) {
LOG.error("Autolocking failed.", e);
@@ -8,12 +8,10 @@
*******************************************************************************/
package org.cryptomator.common.vaults;
import com.google.common.base.Strings;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.common.Constants;
import org.cryptomator.common.Environment;
import org.cryptomator.common.mount.Mounter;
import org.cryptomator.common.mount.WindowsDriveLetters;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.settings.VaultSettings;
import org.cryptomator.cryptofs.CryptoFileSystem;
import org.cryptomator.cryptofs.CryptoFileSystemProperties;
@@ -23,11 +21,7 @@ import org.cryptomator.cryptofs.common.FileSystemCapabilityChecker;
import org.cryptomator.cryptolib.api.CryptoException;
import org.cryptomator.cryptolib.api.MasterkeyLoader;
import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
import org.cryptomator.integrations.mount.Mount;
import org.cryptomator.integrations.mount.MountBuilder;
import org.cryptomator.integrations.mount.MountCapability;
import org.cryptomator.integrations.mount.MountFailedException;
import org.cryptomator.integrations.mount.MountService;
import org.cryptomator.integrations.mount.Mountpoint;
import org.cryptomator.integrations.mount.UnmountFailedException;
import org.slf4j.Logger;
@@ -44,9 +38,7 @@ import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ObservableValue;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.EnumSet;
@@ -54,11 +46,6 @@ import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import static org.cryptomator.integrations.mount.MountCapability.MOUNT_AS_DRIVE_LETTER;
import static org.cryptomator.integrations.mount.MountCapability.MOUNT_TO_EXISTING_DIR;
import static org.cryptomator.integrations.mount.MountCapability.MOUNT_TO_SYSTEM_CHOSEN_PATH;
import static org.cryptomator.integrations.mount.MountCapability.MOUNT_WITHIN_EXISTING_PARENT;
@PerVault
public class Vault {
@@ -66,14 +53,10 @@ public class Vault {
private static final Path HOME_DIR = Paths.get(SystemUtils.USER_HOME);
private static final int UNLIMITED_FILENAME_LENGTH = Integer.MAX_VALUE;
private final Environment env;
private final Settings settings;
private final VaultSettings vaultSettings;
private final AtomicReference<CryptoFileSystem> cryptoFileSystem;
private final VaultState state;
private final ObjectProperty<Exception> lastKnownException;
private final ObservableValue<MountService> mountService;
private final ObservableValue<String> defaultMountFlags;
private final VaultConfigCache configCache;
private final VaultStats stats;
private final StringBinding displayablePath;
@@ -84,22 +67,18 @@ public class Vault {
private final BooleanBinding needsMigration;
private final BooleanBinding unknownError;
private final ObjectBinding<Mountpoint> mountPoint;
private final WindowsDriveLetters windowsDriveLetters;
private final Mounter mounter;
private final BooleanProperty showingStats;
private AtomicReference<MountHandle> mountHandle = new AtomicReference<>(null);
private AtomicReference<Mounter.MountHandle> mountHandle = new AtomicReference<>(null);
@Inject
Vault(Environment env, Settings settings, VaultSettings vaultSettings, VaultConfigCache configCache, AtomicReference<CryptoFileSystem> cryptoFileSystem, VaultState state, @Named("lastKnownException") ObjectProperty<Exception> lastKnownException, ObservableValue<MountService> mountService, VaultStats stats, WindowsDriveLetters windowsDriveLetters) {
this.env = env;
this.settings = settings;
Vault(VaultSettings vaultSettings, VaultConfigCache configCache, AtomicReference<CryptoFileSystem> cryptoFileSystem, VaultState state, @Named("lastKnownException") ObjectProperty<Exception> lastKnownException, VaultStats stats, WindowsDriveLetters windowsDriveLetters, Mounter mounter) {
this.vaultSettings = vaultSettings;
this.configCache = configCache;
this.cryptoFileSystem = cryptoFileSystem;
this.state = state;
this.lastKnownException = lastKnownException;
this.mountService = mountService;
this.defaultMountFlags = mountService.map(MountService::getDefaultMountFlags);
this.stats = stats;
this.displayablePath = Bindings.createStringBinding(this::getDisplayablePath, vaultSettings.path());
this.locked = Bindings.createBooleanBinding(this::isLocked, state);
@@ -109,7 +88,7 @@ public class Vault {
this.needsMigration = Bindings.createBooleanBinding(this::isNeedsMigration, state);
this.unknownError = Bindings.createBooleanBinding(this::isUnknownError, state);
this.mountPoint = Bindings.createObjectBinding(this::getMountPoint, state);
this.windowsDriveLetters = windowsDriveLetters;
this.mounter = mounter;
this.showingStats = new SimpleBooleanProperty(false);
}
@@ -159,45 +138,6 @@ public class Vault {
}
}
private MountBuilder prepareMount(Path cryptoRoot) throws IOException {
var mountProvider = mountService.getValue();
var builder = mountProvider.forFileSystem(cryptoRoot);
for (var capability : mountProvider.capabilities()) {
switch (capability) {
case FILE_SYSTEM_NAME -> builder.setFileSystemName("crypto");
case LOOPBACK_PORT -> builder.setLoopbackPort(settings.port().get()); //TODO: move port from settings to vaultsettings?
case LOOPBACK_HOST_NAME -> builder.setLoopbackHostName("cryptomator-vault"); //TODO: Read from system property
case READ_ONLY -> builder.setReadOnly(vaultSettings.usesReadOnlyMode().get());
case MOUNT_FLAGS -> builder.setMountFlags(defaultMountFlags.getValue()); // TODO use custom mount flags (pre-populated with default mount flags)
case VOLUME_ID -> builder.setVolumeId(vaultSettings.getId());
case VOLUME_NAME -> builder.setVolumeName(vaultSettings.mountName().get());
}
}
var userChosenMountPoint = vaultSettings.getMountPoint();
var defaultMountPointBase = env.getMountPointsDir().orElseThrow();
if (userChosenMountPoint == null) {
if (mountProvider.hasCapability(MOUNT_TO_SYSTEM_CHOSEN_PATH)) {
// no need to set a mount point
} else if (mountProvider.hasCapability(MOUNT_AS_DRIVE_LETTER)) {
builder.setMountpoint(windowsDriveLetters.getFirstDesiredAvailable().orElseThrow());
} else if (mountProvider.hasCapability(MOUNT_WITHIN_EXISTING_PARENT)) {
Files.createDirectories(defaultMountPointBase);
builder.setMountpoint(defaultMountPointBase);
} else if (mountProvider.hasCapability(MOUNT_TO_EXISTING_DIR) ) {
var mountPoint = defaultMountPointBase.resolve(vaultSettings.mountName().get());
Files.createDirectories(mountPoint);
builder.setMountpoint(mountPoint);
}
} else if (mountProvider.hasCapability(MOUNT_TO_EXISTING_DIR) || mountProvider.hasCapability(MOUNT_WITHIN_EXISTING_PARENT) || mountProvider.hasCapability(MOUNT_AS_DRIVE_LETTER)) {
// TODO: move the mount point away in case of MOUNT_WITHIN_EXISTING_PARENT?
builder.setMountpoint(userChosenMountPoint);
}
return builder;
}
public synchronized void unlock(MasterkeyLoader keyLoader) throws CryptoException, IOException, MountFailedException {
if (cryptoFileSystem.get() != null) {
throw new IllegalStateException("Already unlocked.");
@@ -207,8 +147,7 @@ public class Vault {
try {
cryptoFileSystem.set(fs);
var rootPath = fs.getRootDirectories().iterator().next();
var supportsForcedUnmount = mountService.getValue().hasCapability(MountCapability.UNMOUNT_FORCED);
var mountHandle = new MountHandle(prepareMount(rootPath).mount(), supportsForcedUnmount);
var mountHandle = mounter.mount(vaultSettings, rootPath);
success = this.mountHandle.compareAndSet(null, mountHandle);
} finally {
if (!success) {
@@ -217,7 +156,6 @@ public class Vault {
}
}
public synchronized void lock(boolean forced) throws UnmountFailedException, IOException {
var mountHandle = this.mountHandle.get();
if (mountHandle == null) {
@@ -225,14 +163,15 @@ public class Vault {
return;
}
if (forced && mountHandle.supportsUnmountForced) {
mountHandle.mount.unmountForced();
if (forced && mountHandle.supportsUnmountForced()) {
mountHandle.mountObj().unmountForced();
} else {
mountHandle.mount.unmount();
mountHandle.mountObj().unmount();
}
try {
mountHandle.mount.close();
mountHandle.mountObj().close();
mountHandle.specialCleanup().run();
} finally {
destroyCryptoFileSystem();
}
@@ -327,7 +266,7 @@ public class Vault {
public Mountpoint getMountPoint() {
var handle = mountHandle.get();
return handle == null ? null : handle.mount.getMountpoint();
return handle == null ? null : handle.mountObj().getMountpoint();
}
public StringBinding displayablePathProperty() {
@@ -375,24 +314,30 @@ public class Vault {
return vaultSettings.path().getValue();
}
public boolean isHavingCustomMountFlags() {
return !Strings.isNullOrEmpty(vaultSettings.mountFlags().get());
}
/**
* Gets from the cleartext path its ciphertext counterpart.
*
* @return Local os path to the ciphertext resource
* @throws IOException if an I/O error occurs
* @throws IllegalStateException if the vault is not unlocked
*/
public Path getCiphertextPath(Path cleartextPath) throws IOException {
if (!state.getValue().equals(VaultState.Value.UNLOCKED)) {
throw new IllegalStateException("Vault is not unlocked");
}
var fs = cryptoFileSystem.get();
var osPathSeparator = cleartextPath.getFileSystem().getSeparator();
var cryptoFsPathSeparator = fs.getSeparator();
public ObservableValue<String> defaultMountFlagsProperty() {
return defaultMountFlags;
}
public String getDefaultMountFlags() {
return defaultMountFlags.getValue();
}
public String getEffectiveMountFlags() {
String mountFlags = vaultSettings.mountFlags().get();
if (Strings.isNullOrEmpty(mountFlags)) {
return ""; //TODO: should the provider provide dem defaults??
if (getMountPoint() instanceof Mountpoint.WithPath mp) {
var absoluteCryptoFsPath = cryptoFsPathSeparator + mp.path().relativize(cleartextPath).toString();
if (!cryptoFsPathSeparator.equals(osPathSeparator)) {
absoluteCryptoFsPath = absoluteCryptoFsPath.replace(osPathSeparator, cryptoFsPathSeparator);
}
var cryptoPath = fs.getPath(absoluteCryptoFsPath);
return fs.getCiphertextPath(cryptoPath);
} else {
return mountFlags;
throw new UnsupportedOperationException("URI mount points not supported.");
}
}
@@ -400,10 +345,6 @@ public class Vault {
return configCache;
}
public void setCustomMountFlags(String mountFlags) {
vaultSettings.mountFlags().set(mountFlags);
}
public String getId() {
return vaultSettings.getId();
}
@@ -426,15 +367,12 @@ public class Vault {
}
}
/* TODO: reactivate/ needed at all?
public boolean supportsForcedUnmount() {
return volume.supportsForcedUnmount();
var mh = mountHandle.get();
if (mh == null) {
throw new IllegalStateException("Vault is not mounted");
}
return mountHandle.get().supportsUnmountForced();
}
*/
private record MountHandle(Mount mount, boolean supportsUnmountForced) {
}
}
@@ -9,8 +9,8 @@ import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.function.Function;
// TODO make sealed, remove enum
interface IpcMessage {
//TODO can the enum be removed?
sealed interface IpcMessage permits HandleLaunchArgsMessage, RevealRunningAppMessage {
enum MessageType {
REVEAL_RUNNING_APP(RevealRunningAppMessage::decode),
@@ -5,10 +5,9 @@ import java.util.List;
public interface IpcMessageListener {
default void handleMessage(IpcMessage message) {
if (message instanceof RevealRunningAppMessage) {
revealRunningApp();
} else if (message instanceof HandleLaunchArgsMessage m) {
handleLaunchArgs(m.args());
switch (message) {
case RevealRunningAppMessage m -> revealRunningApp(); // TODO: rename to _ with JEP 443
case HandleLaunchArgsMessage m -> handleLaunchArgs(m.args());
}
}
@@ -1,12 +1,14 @@
package org.cryptomator.launcher;
import org.cryptomator.common.settings.Settings;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
@@ -14,26 +16,39 @@ import java.util.Locale;
public class SupportedLanguages {
private static final Logger LOG = LoggerFactory.getLogger(SupportedLanguages.class);
// these are BCP 47 language codes, not ISO. Note the "-" instead of the "_":
public static final List<String> LANGUAGAE_TAGS = List.of("en", "ar", "be", "bn", "bs", "ca", "cs", "da", "de", "el", "es", "fil", "fa", "fr", "gl", "he", //
"hi", "hr", "hu", "id", "it", "ja", "ko", "lv", "mk", "nb", "nl", "nn", "no", "pa", "pl", "pt", "pt-BR", "ro", "ru", "si", "sk", "sr", "sr-Latn", "sv", "sw", //
"ta", "te", "th", "tr", "uk", "vi", "zh", "zh-HK", "zh-TW");
// these are BCP 47 language codes, not ISO. Note the "-" instead of the "_".
// "en" is not part of this list - it is always inserted at the top.
public static final List<String> LANGUAGE_TAGS = List.of("ar", "be", "bn", "bs", "ca", "cs", "da", "de", "el", "es", "fr", "gl", "he", //
"hi", "hr", "hu", "id", "it", "ja", "ko", "lv", "nb", "nl", "nn", "pa", "pl", "pt", "pt-BR", "ro", "ru", "sk", "sr", "sr-Latn", "sv", "sw", //
"ta", "th", "tr", "uk", "vi", "zh", "zh-HK", "zh-TW");
public static final String ENGLISH = "en";
@Nullable
private final String preferredLanguage;
private final List<String> sortedLanguageTags;
private final Locale preferredLocale;
@Inject
public SupportedLanguages(Settings settings) {
this.preferredLanguage = settings.languageProperty().get();
var preferredLanguage = settings.languageProperty().get();
preferredLocale = preferredLanguage == null ? Locale.getDefault() : Locale.forLanguageTag(preferredLanguage);
var collator = Collator.getInstance(preferredLocale);
collator.setStrength(Collator.PRIMARY);
var sorted = new ArrayList<String>();
sorted.add(0, Settings.DEFAULT_LANGUAGE);
sorted.add(1, ENGLISH);
LANGUAGE_TAGS.stream() //
.sorted((a, b) -> collator.compare(Locale.forLanguageTag(a).getDisplayName(), Locale.forLanguageTag(b).getDisplayName())) //
.forEach(sorted::add);
sortedLanguageTags = Collections.unmodifiableList(sorted);
}
public void applyPreferred() {
if (preferredLanguage == null) {
LOG.debug("Using system locale");
return;
}
var preferredLocale = Locale.forLanguageTag(preferredLanguage);
LOG.debug("Applying preferred locale {}", preferredLocale.getDisplayName(Locale.ENGLISH));
LOG.debug("Using locale {}", preferredLocale);
Locale.setDefault(preferredLocale);
}
public List<String> getLanguageTags() {
return sortedLanguageTags;
}
}
@@ -84,6 +84,10 @@ public class LogbackConfigurator extends ContextAwareBase implements Configurato
upgrades.addAppender(upgrade);
upgrades.addAppender(file);
upgrades.setAdditive(false);
// configure fuse file locking logger:
Logger fuseLocking = context.getLogger("org.cryptomator.frontend.fuse.locks");
fuseLocking.setLevel(Level.OFF);
}
return ExecutionStatus.DO_NOT_INVOKE_NEXT_IF_ANY;
}
@@ -11,8 +11,8 @@ import org.cryptomator.ui.common.FxControllerKey;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlLoaderFactory;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.common.NewPasswordController;
import org.cryptomator.ui.common.PasswordStrengthUtil;
import org.cryptomator.ui.changepassword.NewPasswordController;
import org.cryptomator.ui.changepassword.PasswordStrengthUtil;
import org.cryptomator.ui.common.StageFactory;
import org.cryptomator.ui.fxapp.PrimaryStage;
import org.cryptomator.ui.recoverykey.RecoveryKeyDisplayController;
@@ -1,6 +1,9 @@
package org.cryptomator.ui.addvaultwizard;
import dagger.Lazy;
import org.cryptomator.common.ObservableUtil;
import org.cryptomator.common.locationpresets.LocationPreset;
import org.cryptomator.common.locationpresets.LocationPresetsProvider;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
@@ -10,22 +13,19 @@ import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Named;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.VBox;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
import java.io.File;
@@ -34,6 +34,9 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.ResourceBundle;
@AddVaultWizardScoped
@@ -46,70 +49,72 @@ public class CreateNewVaultLocationController implements FxController {
private final Stage window;
private final Lazy<Scene> chooseNameScene;
private final Lazy<Scene> choosePasswordScene;
private final ObservedLocationPresets locationPresets;
private final List<RadioButton> locationPresetBtns;
private final ObjectProperty<Path> vaultPath;
private final StringProperty vaultName;
private final ResourceBundle resourceBundle;
private final BooleanBinding validVaultPath;
private final ObservableValue<VaultPathStatus> vaultPathStatus;
private final ObservableValue<Boolean> validVaultPath;
private final BooleanProperty usePresetPath;
private final StringProperty statusText;
private final ObjectProperty<Node> statusGraphic;
private Path customVaultPath = DEFAULT_CUSTOM_VAULT_PATH;
//FXML
public ToggleGroup predefinedLocationToggler;
public RadioButton iclouddriveRadioButton;
public RadioButton dropboxRadioButton;
public RadioButton gdriveRadioButton;
public RadioButton onedriveRadioButton;
public RadioButton megaRadioButton;
public RadioButton pcloudRadioButton;
public ToggleGroup locationPresetsToggler;
public VBox radioButtonVBox;
public RadioButton customRadioButton;
public Label vaultPathStatus;
public Label locationStatusLabel;
public FontAwesome5IconView goodLocation;
public FontAwesome5IconView badLocation;
@Inject
CreateNewVaultLocationController(@AddVaultWizardWindow Stage window, @FxmlScene(FxmlFile.ADDVAULT_NEW_NAME) Lazy<Scene> chooseNameScene, @FxmlScene(FxmlFile.ADDVAULT_NEW_PASSWORD) Lazy<Scene> choosePasswordScene, ObservedLocationPresets locationPresets, ObjectProperty<Path> vaultPath, @Named("vaultName") StringProperty vaultName, ResourceBundle resourceBundle) {
CreateNewVaultLocationController(@AddVaultWizardWindow Stage window, @FxmlScene(FxmlFile.ADDVAULT_NEW_NAME) Lazy<Scene> chooseNameScene, @FxmlScene(FxmlFile.ADDVAULT_NEW_PASSWORD) Lazy<Scene> choosePasswordScene, ObjectProperty<Path> vaultPath, @Named("vaultName") StringProperty vaultName, ResourceBundle resourceBundle) {
this.window = window;
this.chooseNameScene = chooseNameScene;
this.choosePasswordScene = choosePasswordScene;
this.locationPresets = locationPresets;
this.vaultPath = vaultPath;
this.vaultName = vaultName;
this.resourceBundle = resourceBundle;
this.validVaultPath = Bindings.createBooleanBinding(this::validateVaultPathAndSetStatus, this.vaultPath);
this.vaultPathStatus = ObservableUtil.mapWithDefault(vaultPath, this::validatePath, new VaultPathStatus(false, "error.message"));
this.validVaultPath = ObservableUtil.mapWithDefault(vaultPathStatus, VaultPathStatus::valid, false);
this.vaultPathStatus.addListener(this::updateStatusLabel);
this.usePresetPath = new SimpleBooleanProperty();
this.statusText = new SimpleStringProperty();
this.statusGraphic = new SimpleObjectProperty<>();
this.locationPresetBtns = LocationPresetsProvider.loadAll(LocationPresetsProvider.class) //
.flatMap(LocationPresetsProvider::getLocations) //
.sorted(Comparator.comparing(LocationPreset::name)) //
.map(preset -> { //
var btn = new RadioButton(preset.name());
btn.setUserData(preset.path());
return btn;
}).toList();
}
private boolean validateVaultPathAndSetStatus() {
final Path p = vaultPath.get();
if (p == null) {
statusText.set("Error: Path is NULL.");
statusGraphic.set(badLocation);
return false;
} else if (!Files.exists(p.getParent())) {
statusText.set(resourceBundle.getString("addvaultwizard.new.locationDoesNotExist"));
statusGraphic.set(badLocation);
return false;
private VaultPathStatus validatePath(Path p) throws NullPointerException {
if (!Files.exists(p.getParent())) {
return new VaultPathStatus(false, "addvaultwizard.new.locationDoesNotExist");
} else if (!isActuallyWritable(p.getParent())) {
statusText.set(resourceBundle.getString("addvaultwizard.new.locationIsNotWritable"));
statusGraphic.set(badLocation);
return false;
return new VaultPathStatus(false, "addvaultwizard.new.locationIsNotWritable");
} else if (!Files.notExists(p)) {
statusText.set(resourceBundle.getString("addvaultwizard.new.fileAlreadyExists"));
statusGraphic.set(badLocation);
return false;
return new VaultPathStatus(false, "addvaultwizard.new.fileAlreadyExists");
} else {
statusText.set(resourceBundle.getString("addvaultwizard.new.locationIsOk"));
statusGraphic.set(goodLocation);
return true;
return new VaultPathStatus(true, "addvaultwizard.new.locationIsOk");
}
}
private void updateStatusLabel(ObservableValue<? extends VaultPathStatus> observable, VaultPathStatus oldValue, VaultPathStatus newValue) {
if (newValue.valid()) {
locationStatusLabel.setGraphic(goodLocation);
locationStatusLabel.getStyleClass().remove("label-red");
locationStatusLabel.getStyleClass().add("label-muted");
} else {
locationStatusLabel.setGraphic(badLocation);
locationStatusLabel.getStyleClass().remove("label-muted");
locationStatusLabel.getStyleClass().add("label-red");
}
this.locationStatusLabel.setText(resourceBundle.getString(newValue.localizationKey()));
}
private boolean isActuallyWritable(Path p) {
Path tmpFile = p.resolve(TEMP_FILE_FORMAT);
try (var chan = Files.newByteChannel(tmpFile, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE, StandardOpenOption.DELETE_ON_CLOSE)) {
@@ -127,26 +132,15 @@ public class CreateNewVaultLocationController implements FxController {
@FXML
public void initialize() {
predefinedLocationToggler.selectedToggleProperty().addListener(this::togglePredefinedLocation);
usePresetPath.bind(predefinedLocationToggler.selectedToggleProperty().isNotEqualTo(customRadioButton));
radioButtonVBox.getChildren().addAll(1, locationPresetBtns); //first item is the list header
locationPresetsToggler.getToggles().addAll(locationPresetBtns);
locationPresetsToggler.selectedToggleProperty().addListener(this::togglePredefinedLocation);
usePresetPath.bind(locationPresetsToggler.selectedToggleProperty().isNotEqualTo(customRadioButton));
}
private void togglePredefinedLocation(@SuppressWarnings("unused") ObservableValue<? extends Toggle> observable, @SuppressWarnings("unused") Toggle oldValue, Toggle newValue) {
if (iclouddriveRadioButton.equals(newValue)) {
vaultPath.set(locationPresets.getIclouddriveLocation().resolve(vaultName.get()));
} else if (dropboxRadioButton.equals(newValue)) {
vaultPath.set(locationPresets.getDropboxLocation().resolve(vaultName.get()));
} else if (gdriveRadioButton.equals(newValue)) {
vaultPath.set(locationPresets.getGdriveLocation().resolve(vaultName.get()));
} else if (onedriveRadioButton.equals(newValue)) {
vaultPath.set(locationPresets.getOnedriveLocation().resolve(vaultName.get()));
} else if (megaRadioButton.equals(newValue)) {
vaultPath.set(locationPresets.getMegaLocation().resolve(vaultName.get()));
} else if (pcloudRadioButton.equals(newValue)) {
vaultPath.set(locationPresets.getPcloudLocation().resolve(vaultName.get()));
} else if (customRadioButton.equals(newValue)) {
vaultPath.set(customVaultPath.resolve(vaultName.get()));
}
var storagePath = Optional.ofNullable((Path) newValue.getUserData()).orElse(customVaultPath);
vaultPath.set(storagePath.resolve(vaultName.get()));
}
@FXML
@@ -156,10 +150,8 @@ public class CreateNewVaultLocationController implements FxController {
@FXML
public void next() {
if (validateVaultPathAndSetStatus()) {
if (validVaultPath.getValue()) {
window.setScene(choosePasswordScene.get());
} else {
validVaultPath.invalidate();
}
}
@@ -179,6 +171,12 @@ public class CreateNewVaultLocationController implements FxController {
}
}
/* Internal classes */
private record VaultPathStatus(boolean valid, String localizationKey) {
}
/* Getter/Setter */
public Path getVaultPath() {
@@ -189,47 +187,28 @@ public class CreateNewVaultLocationController implements FxController {
return vaultPath;
}
public BooleanBinding validVaultPathProperty() {
public ObservableValue<Boolean> validVaultPathProperty() {
return validVaultPath;
}
public Boolean getValidVaultPath() {
return validVaultPath.get();
}
public ObservedLocationPresets getObservedLocationPresets() {
return locationPresets;
public boolean isValidVaultPath() {
return validVaultPath.getValue();
}
public BooleanProperty usePresetPathProperty() {
return usePresetPath;
}
public boolean getUsePresetPath() {
public boolean isUsePresetPath() {
return usePresetPath.get();
}
public BooleanBinding anyRadioButtonSelectedProperty() {
return predefinedLocationToggler.selectedToggleProperty().isNotNull();
return locationPresetsToggler.selectedToggleProperty().isNotNull();
}
public boolean isAnyRadioButtonSelected() {
return anyRadioButtonSelectedProperty().get();
}
public StringProperty statusTextProperty() {
return statusText;
}
public String getStatusText() {
return statusText.get();
}
public ObjectProperty<Node> statusGraphicProperty() {
return statusGraphic;
}
public Node getStatusGraphic() {
return statusGraphic.get();
}
}
@@ -13,7 +13,7 @@ import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.common.NewPasswordController;
import org.cryptomator.ui.changepassword.NewPasswordController;
import org.cryptomator.ui.common.Tasks;
import org.cryptomator.ui.fxapp.FxApplicationWindows;
import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingStrategy;
@@ -48,13 +48,13 @@ import java.util.ResourceBundle;
import java.util.concurrent.ExecutorService;
import static java.nio.charset.StandardCharsets.US_ASCII;
import static org.cryptomator.common.Constants.DEFAULT_KEY_ID;
import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
@AddVaultWizardScoped
public class CreateNewVaultPasswordController implements FxController {
private static final Logger LOG = LoggerFactory.getLogger(CreateNewVaultPasswordController.class);
private static final URI DEFAULT_KEY_ID = URI.create(MasterkeyFileLoadingStrategy.SCHEME + ":" + MASTERKEY_FILENAME); // TODO better place?
private final Stage window;
private final Lazy<Scene> chooseLocationScene;
@@ -176,7 +176,7 @@ public class CreateNewVaultPasswordController implements FxController {
// 2. initialize vault:
try {
MasterkeyLoader loader = ignored -> masterkey.copy();
CryptoFileSystemProperties fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties().withCipherCombo(CryptorProvider.Scheme.SIV_CTRMAC).withKeyLoader(loader).build();
CryptoFileSystemProperties fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties().withCipherCombo(CryptorProvider.Scheme.SIV_GCM).withKeyLoader(loader).build();
CryptoFileSystemProvider.initialize(path, fsProps, DEFAULT_KEY_ID);
// 3. write vault-internal readme file:
@@ -1,141 +0,0 @@
package org.cryptomator.ui.addvaultwizard;
import org.cryptomator.common.LocationPreset;
import javax.inject.Inject;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import java.nio.file.Path;
@AddVaultWizardScoped
public class ObservedLocationPresets {
private final ReadOnlyObjectProperty<Path> iclouddriveLocation;
private final ReadOnlyObjectProperty<Path> dropboxLocation;
private final ReadOnlyObjectProperty<Path> gdriveLocation;
private final ReadOnlyObjectProperty<Path> onedriveLocation;
private final ReadOnlyObjectProperty<Path> megaLocation;
private final ReadOnlyObjectProperty<Path> pcloudLocation;
private final BooleanBinding foundIclouddrive;
private final BooleanBinding foundDropbox;
private final BooleanBinding foundGdrive;
private final BooleanBinding foundOnedrive;
private final BooleanBinding foundMega;
private final BooleanBinding foundPcloud;
@Inject
public ObservedLocationPresets() {
this.iclouddriveLocation = new SimpleObjectProperty<>(LocationPreset.ICLOUDDRIVE.existingPath());
this.dropboxLocation = new SimpleObjectProperty<>(LocationPreset.DROPBOX.existingPath());
this.gdriveLocation = new SimpleObjectProperty<>(LocationPreset.GDRIVE.existingPath());
this.onedriveLocation = new SimpleObjectProperty<>(LocationPreset.ONEDRIVE.existingPath());
this.megaLocation = new SimpleObjectProperty<>(LocationPreset.MEGA.existingPath());
this.pcloudLocation = new SimpleObjectProperty<>(LocationPreset.PCLOUD.existingPath());
this.foundIclouddrive = iclouddriveLocation.isNotNull();
this.foundDropbox = dropboxLocation.isNotNull();
this.foundGdrive = gdriveLocation.isNotNull();
this.foundOnedrive = onedriveLocation.isNotNull();
this.foundMega = megaLocation.isNotNull();
this.foundPcloud = pcloudLocation.isNotNull();
}
/* Observables */
public ReadOnlyObjectProperty<Path> iclouddriveLocationProperty() {
return iclouddriveLocation;
}
public Path getIclouddriveLocation() {
return iclouddriveLocation.get();
}
public BooleanBinding foundIclouddriveProperty() {
return foundIclouddrive;
}
public boolean isFoundIclouddrive() {
return foundIclouddrive.get();
}
public ReadOnlyObjectProperty<Path> dropboxLocationProperty() {
return dropboxLocation;
}
public Path getDropboxLocation() {
return dropboxLocation.get();
}
public BooleanBinding foundDropboxProperty() {
return foundDropbox;
}
public boolean isFoundDropbox() {
return foundDropbox.get();
}
public ReadOnlyObjectProperty<Path> gdriveLocationProperty() {
return gdriveLocation;
}
public Path getGdriveLocation() {
return gdriveLocation.get();
}
public BooleanBinding foundGdriveProperty() {
return foundGdrive;
}
public boolean isFoundGdrive() {
return foundGdrive.get();
}
public ReadOnlyObjectProperty<Path> onedriveLocationProperty() {
return onedriveLocation;
}
public Path getOnedriveLocation() {
return onedriveLocation.get();
}
public BooleanBinding foundOnedriveProperty() {
return foundOnedrive;
}
public boolean isFoundOnedrive() {
return foundOnedrive.get();
}
public ReadOnlyObjectProperty<Path> megaLocationProperty() {
return megaLocation;
}
public Path getMegaLocation() {
return megaLocation.get();
}
public BooleanBinding foundMegaProperty() {
return foundMega;
}
public boolean isFoundMega() {
return foundMega.get();
}
public ReadOnlyObjectProperty<Path> pcloudLocationProperty() {
return pcloudLocation;
}
public Path getPcloudLocation() {
return pcloudLocation.get();
}
public BooleanBinding foundPcloudProperty() {
return foundPcloud;
}
public boolean isFoundPcloud() {
return foundPcloud.get();
}
}
@@ -9,7 +9,6 @@ import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
import org.cryptomator.integrations.keychain.KeychainAccessException;
import org.cryptomator.ui.common.Animations;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.NewPasswordController;
import org.cryptomator.ui.controls.NiceSecurePasswordField;
import org.cryptomator.ui.fxapp.FxApplicationWindows;
import org.slf4j.Logger;
@@ -10,8 +10,6 @@ import org.cryptomator.ui.common.FxControllerKey;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlLoaderFactory;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.common.NewPasswordController;
import org.cryptomator.ui.common.PasswordStrengthUtil;
import org.cryptomator.ui.common.StageFactory;
import javax.inject.Named;
@@ -1,5 +1,7 @@
package org.cryptomator.ui.common;
package org.cryptomator.ui.changepassword;
import org.cryptomator.common.Passphrase;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.controls.FontAwesome5IconView;
import org.cryptomator.ui.controls.NiceSecurePasswordField;
@@ -91,4 +93,8 @@ public class NewPasswordController implements FxController {
return passwordStrength.get();
}
public Passphrase getNewPassword() {
return passwordField.getCharacters();
}
}
@@ -6,7 +6,7 @@
* Contributors:
* Jean-Noël Charon - initial API and implementation
*******************************************************************************/
package org.cryptomator.ui.common;
package org.cryptomator.ui.changepassword;
import com.nulabinc.zxcvbn.Zxcvbn;
import org.cryptomator.common.Environment;
@@ -9,12 +9,16 @@ public enum FxmlFile {
ADDVAULT_SUCCESS("/fxml/addvault_success.fxml"), //
ADDVAULT_WELCOME("/fxml/addvault_welcome.fxml"), //
CHANGEPASSWORD("/fxml/changepassword.fxml"), //
CONVERTVAULT_HUBTOPASSWORD_START("/fxml/convertvault_hubtopassword_start.fxml"), //
CONVERTVAULT_HUBTOPASSWORD_CONVERT("/fxml/convertvault_hubtopassword_convert.fxml"), //
CONVERTVAULT_HUBTOPASSWORD_SUCCESS("/fxml/convertvault_hubtopassword_success.fxml"), //
ERROR("/fxml/error.fxml"), //
FORGET_PASSWORD("/fxml/forget_password.fxml"), //
HEALTH_START("/fxml/health_start.fxml"), //
HEALTH_CHECK_LIST("/fxml/health_check_list.fxml"), //
HUB_NO_KEYCHAIN("/fxml/hub_no_keychain.fxml"), //
HUB_AUTH_FLOW("/fxml/hub_auth_flow.fxml"), //
HUB_LICENSE_EXCEEDED("/fxml/hub_license_exceeded.fxml"), //
HUB_INVALID_LICENSE("/fxml/hub_invalid_license.fxml"), //
HUB_RECEIVE_KEY("/fxml/hub_receive_key.fxml"), //
HUB_REGISTER_DEVICE("/fxml/hub_register_device.fxml"), //
HUB_REGISTER_SUCCESS("/fxml/hub_register_success.fxml"), //
@@ -18,6 +18,7 @@ public enum FontAwesome5Icon {
COPY("\uF0C5"), //
CROWN("\uF521"), //
EDIT("\uF044"), //
EXCHANGE_ALT("\uF362"), //
EXCLAMATION("\uF12A"), //
EXCLAMATION_CIRCLE("\uF06A"), //
EXCLAMATION_TRIANGLE("\uF071"), //
@@ -25,6 +26,7 @@ public enum FontAwesome5Icon {
EYE_SLASH("\uF070"), //
FAST_FORWARD("\uF050"), //
FILE("\uF15B"), //
FILE_DOWNLOAD("\uF56D"), //
FILE_IMPORT("\uF56F"), //
FOLDER_OPEN("\uF07C"), //
FUNNEL("\uF0B0"), //
@@ -41,6 +43,7 @@ public enum FontAwesome5Icon {
PLUS("\uF067"), //
PRINT("\uF02F"), //
QUESTION("\uF128"), //
QUESTION_CIRCLE("\uf059"), //
REDO("\uF01E"), //
SEARCH("\uF002"), //
SPINNER("\uF110"), //
@@ -43,7 +43,7 @@ public class SecurePasswordField extends TextField {
private static final char WIPE_CHAR = ' ';
private static final int INITIAL_BUFFER_SIZE = 50;
private static final int GROW_BUFFER_SIZE = 50;
private static final String DEFAULT_PLACEHOLDER = "";
private static final String DEFAULT_PLACEHOLDER = "";
private static final String STYLE_CLASS = "secure-password-field";
private static final KeyCodeCombination SHORTCUT_BACKSPACE = new KeyCodeCombination(KeyCode.BACK_SPACE, KeyCombination.SHORTCUT_DOWN);
@@ -0,0 +1,41 @@
/*******************************************************************************
* Copyright (c) 2017 Skymatic UG (haftungsbeschränkt).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the accompanying LICENSE file.
*******************************************************************************/
package org.cryptomator.ui.convertvault;
import dagger.BindsInstance;
import dagger.Lazy;
import dagger.Subcomponent;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import javax.inject.Named;
import javafx.scene.Scene;
import javafx.stage.Stage;
@ConvertVaultScoped
@Subcomponent(modules = {ConvertVaultModule.class})
public interface ConvertVaultComponent {
@ConvertVaultWindow
Stage window();
@FxmlScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_START)
Lazy<Scene> hubToPasswordScene();
default void showHubToPasswordWindow() {
Stage stage = window();
stage.setScene(hubToPasswordScene().get());
stage.sizeToScene();
stage.show();
}
@Subcomponent.Factory
interface Factory {
ConvertVaultComponent create(@BindsInstance @ConvertVaultWindow Vault vault, @BindsInstance @Named("convertVaultOwner") Stage owner);
}
}
@@ -0,0 +1,126 @@
package org.cryptomator.ui.convertvault;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.cryptofs.VaultConfig;
import org.cryptomator.ui.changepassword.NewPasswordController;
import org.cryptomator.ui.changepassword.PasswordStrengthUtil;
import org.cryptomator.ui.common.DefaultSceneFactory;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxControllerKey;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlLoaderFactory;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.common.StageFactory;
import org.cryptomator.ui.recoverykey.RecoveryKeyFactory;
import org.cryptomator.ui.recoverykey.RecoveryKeyValidateController;
import javax.inject.Named;
import javax.inject.Provider;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Scene;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.Map;
import java.util.ResourceBundle;
@Module
abstract class ConvertVaultModule {
//TODO: if this fails, we cannot display an error
@Provides
@ConvertVaultWindow
@ConvertVaultScoped
static VaultConfig.UnverifiedVaultConfig vaultConfig(@ConvertVaultWindow Vault vault) {
try {
return vault.getVaultConfigCache().get();
} catch (IOException e) {
return null;
}
}
@Provides
@ConvertVaultWindow
@ConvertVaultScoped
static StringProperty provideRecoveryKeyProperty() {
return new SimpleStringProperty();
}
@Provides
@ConvertVaultWindow
@ConvertVaultScoped
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
}
@Provides
@ConvertVaultWindow
@ConvertVaultScoped
static Stage provideStage(StageFactory factory, @Named("convertVaultOwner") Stage owner, ResourceBundle resourceBundle) {
Stage stage = factory.create();
stage.setResizable(false);
stage.initModality(Modality.WINDOW_MODAL);
stage.initOwner(owner);
stage.setTitle(resourceBundle.getString("convertVault.title"));
return stage;
}
@Provides
@FxmlScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_START)
@ConvertVaultScoped
static Scene provideHubToPasswordStartScene(@ConvertVaultWindow FxmlLoaderFactory fxmlLoaders) {
return fxmlLoaders.createScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_START);
}
@Provides
@FxmlScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_CONVERT)
@ConvertVaultScoped
static Scene provideHubToPasswordConvertScene(@ConvertVaultWindow FxmlLoaderFactory fxmlLoaders) {
return fxmlLoaders.createScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_CONVERT);
}
@Provides
@FxmlScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_SUCCESS)
@ConvertVaultScoped
static Scene provideHubToPasswordSuccessScene(@ConvertVaultWindow FxmlLoaderFactory fxmlLoaders) {
return fxmlLoaders.createScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_SUCCESS);
}
// ------------------
@Binds
@IntoMap
@FxControllerKey(HubToPasswordStartController.class)
abstract FxController bindHubToPasswordStartController(HubToPasswordStartController controller);
@Binds
@IntoMap
@FxControllerKey(HubToPasswordConvertController.class)
abstract FxController bindHubToPasswordConvertController(HubToPasswordConvertController controller);
@Binds
@IntoMap
@FxControllerKey(HubToPasswordSuccessController.class)
abstract FxController bindHubToPasswordSuccessController(HubToPasswordSuccessController controller);
@Provides
@IntoMap
@FxControllerKey(NewPasswordController.class)
static FxController provideNewPasswordController(ResourceBundle resourceBundle, PasswordStrengthUtil strengthRater) {
return new NewPasswordController(resourceBundle, strengthRater);
}
@Provides
@IntoMap
@FxControllerKey(RecoveryKeyValidateController.class)
static FxController bindRecoveryKeyValidateController(@ConvertVaultWindow Vault vault, @ConvertVaultWindow VaultConfig.UnverifiedVaultConfig vaultConfig, @ConvertVaultWindow StringProperty recoveryKey, RecoveryKeyFactory recoveryKeyFactory) {
return new RecoveryKeyValidateController(vault, vaultConfig, recoveryKey, recoveryKeyFactory);
}
}
@@ -0,0 +1,13 @@
package org.cryptomator.ui.convertvault;
import javax.inject.Scope;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
@interface ConvertVaultScoped {
}

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