Compare commits

...

584 Commits

Author SHA1 Message Date
Tobias Hagemann
565ab4a09b Merge branch 'hotfix/1.16.2' 2025-05-15 08:47:31 +02:00
Armin Schrenk
f797491a17 prepare 1.16.2 2025-05-15 00:50:12 +02:00
Armin Schrenk
cff83b6ac6 closes #3852 2025-05-15 00:47:35 +02:00
Armin Schrenk
85c2901484 Merge branch 'release/1.16.1' 2025-04-30 14:04:43 +02:00
Armin Schrenk
434030b139 finalize 1.16.1 2025-04-30 14:04:32 +02:00
Armin Schrenk
e43bb37758 prepare 1.16.1 2025-04-30 12:12:59 +02:00
Armin Schrenk
2eb9f0fca8 Fixes #3838 2025-04-30 12:12:04 +02:00
Armin Schrenk
9503feb9c4 Feature: Use user and system certificate stores on macOS (#3837) 2025-04-29 17:02:14 +02:00
Armin Schrenk
08e9f130e4 [skip ci] Merge branch 'main' into develop 2025-04-29 11:28:38 +02:00
Armin Schrenk
4e39eaa1f1 Merge branch 'release/1.16.0' 2025-04-29 11:27:56 +02:00
Armin Schrenk
eaca95e8dc finalize 1.16.0 2025-04-29 11:27:44 +02:00
Armin Schrenk
cf32e794c8 Merge branch 'develop' into release/1.16.0 2025-04-29 11:26:48 +02:00
Armin Schrenk
b5b221a5c7 remove manual wix installation from ci 2025-04-29 11:15:13 +02:00
Cryptobot
d7cb99a12d New Crowdin updates (#3819)
New translations strings.properties

Chinese Traditional; Dutch; French; Hebrew; Italian; Latvian; Persian; Portuguese; Portuguese, Brazilian; Russian; Slovak; Spanish; Swedish; 

[ci skip]
2025-04-29 10:55:33 +02:00
Armin Schrenk
b1893c63d4 Bump cryptofs from version 2.9.0-beta2 to 2.9.0 2025-04-28 13:00:21 +02:00
Armin Schrenk
b50cc703b6 Merge branch 'develop' into release/1.16.0 2025-04-15 13:46:30 +02:00
Armin Schrenk
9dc4a1dc5a [skip ci] update distribution build files to jfx 23.0.2 2025-04-15 13:45:14 +02:00
Armin Schrenk
f1a63a1679 update debian workflow to use JDK 23.0.2 2025-04-15 13:42:49 +02:00
Armin Schrenk
d53d4e3452 Merge branch 'develop' into release/1.16.0 2025-04-15 11:42:17 +02:00
Armin Schrenk
b7fa1ae6d8 Merge branch 'develop' into release/1.16.0
# Conflicts:
#	src/main/java/org/cryptomator/common/vaults/Vault.java
#	src/main/java/org/cryptomator/ui/eventview/EventListCellController.java
#	src/main/java/org/cryptomator/ui/eventview/EventListCellFactory.java
#	src/main/java/org/cryptomator/ui/eventview/EventViewController.java
#	src/main/java/org/cryptomator/ui/eventview/EventViewModule.java
#	src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnlockedController.java
#	src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java
#	src/main/resources/css/dark_theme.css
#	src/main/resources/css/light_theme.css
#	src/main/resources/fxml/eventview.fxml
#	src/main/resources/fxml/vault_detail_unlocked.fxml
#	src/main/resources/fxml/vault_list.fxml
#	src/main/resources/i18n/strings.properties
2025-04-15 11:41:39 +02:00
Cryptobot
3f192a587c New Crowdin updates (#3725)
New translations strings.properties

Afrikaans; Arabic; Bashkir; Belarusian; Bengali; Bosnian; Bulgarian; Catalan; Chinese Simplified; Chinese Traditional; Chinese Traditional, Hong Kong; Croatian; Czech; Danish; Dutch; Filipino; Finnish; French; Galician; German; Greek; Hebrew; Hindi; Hungarian; Indonesian; Italian; Japanese; Korean; Latvian; Macedonian; Marathi; Norwegian; 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; Urdu (Pakistan); Uyghur; Vietnamese; 

[ci skip]
2025-04-15 11:31:16 +02:00
Armin Schrenk
3a1b0b17d6 fix translations 2025-04-15 11:23:46 +02:00
dependabot[bot]
5d2a243c55 Bump the java-test-dependencies group across 1 directory with 2 updates (#3776) 2025-04-15 08:59:50 +00:00
dependabot[bot]
008a2a3301 Bump the java-production-dependencies group with 4 updates (#3796) 2025-04-15 08:59:01 +00:00
Armin Schrenk
0680437004 Set a mininum width for the vault choice box in the event view 2025-04-14 17:38:21 +02:00
Armin Schrenk
db6cf5459e CI: Update and split up anti virus whitelisting flow (#3817) 2025-04-14 16:09:22 +02:00
Armin Schrenk
1d8466a9e3 Feature: Decrypt encrypted file name (#3788)
Closes #2713
2025-04-10 17:44:55 +02:00
Armin Schrenk
dcbcd692e7 [skip ci] Merge branch 'main' into develop 2025-04-09 14:02:14 +02:00
Armin Schrenk
87fd6c712a Merge branch 'hotfix/1.15.3' 2025-04-09 13:59:50 +02:00
Armin Schrenk
958505559f finalize 1.15.3 2025-04-09 13:54:50 +02:00
Armin Schrenk
4736e5e7e7 prepare 1.15.3 2025-04-09 13:53:07 +02:00
Armin Schrenk
55d217887a fixes #3809 2025-04-09 11:04:20 +02:00
dependabot[bot]
34ccd3ff73 Bump the maven-build-plugins group across 1 directory with 4 updates (#3813) 2025-04-08 15:49:18 +00:00
Tobias Hagemann
989c349331 Merge tag '1.15.2' into develop
# -----BEGIN SSH SIGNATURE-----
# U1NIU0lHAAAAAQAAAhcAAAAHc3NoLXJzYQAAAAMBAAEAAAIBAKgu9N6lXOixsGNEmzxZhA
# Rc8ABi3MlOHGT30s3zCQEtvbE/j1QXRycgru5n/TZPKiEqZz5OGLM7FG3lNqHTjrQG1jfZ
# rH9JfmTRX9kLWyDmsiKJkB0L19NcCJQKwhkAdcJkbhQHP4bk1o3uMS+M89n6Y0nmUocGrk
# j7yX/79iQn7PQXdDRk7I+p0p1hCMC7fRlhxPwBX8iPOoty9L75ZoteRoWMGoq4T2fhDdUd
# 5ASRKfdVDjUnFrYvI+o8mhXdbzxNLjp5oN9VWQsb+YIkzApcI1+42BT5WABk+3cLlheqPR
# SocNgYdoZZPA1x6Zlzy2gggm33m/uU7gww2iATphdoyXoj1Nv9loMDOaCQUe6s7Fnnn+xH
# hC1fJoCRlrWJ2QjQmZj18KkrXp2/ZNfvLYUIoQVONF40iizb5GJewH00m1ZV+/oAqbJ/W1
# nfLmXJ/ShwACe3hyZFVOaB2582UyTDFCFJL2Bgbiw8y1ayS15+gs9TkFJlAtbpwofPqVB2
# 16iiE8ViFf//J5ommM1S2sHXaPvu1D038OScIGnz0grhnCjzBr3BduW7EYQ6RhVOqMaEUy
# mQiRKIAtfj+6eHgk3IxB3ynReUFQqE3wreE9buA0vrCO4aWEet+qJsg+395K+/l7E6LQOg
# 5rkgcVj9rtFeo4gFBT2AUUSLmHaqpfABAAAAA2dpdAAAAAAAAAAGc2hhNTEyAAACFAAAAA
# xyc2Etc2hhMi0yNTYAAAIAMAXINugL3MrR1dUYQILEttmSOilND0hlz90eGBXuKRcijebq
# TbIwOrTJBPBlHM5aJC1lzBPcfB5Irz0DWc8eg0u2W/vHxtDXP5VL6me6u92Rz6WV73VWMD
# P8otZlMci0n3C5mM8DhrI9Nvg3qthRS2JW5vt3TFA7rL6IiAqsbA/nXWNGZuQwP+tJGCXg
# lWMD9NHaE1mmCcH+im2Vvnhz0y2Q0IEJCN8MDTrOA3ydnmF+YJ1b2QyQFBGrX3TNitZajX
# Uft3Jw5glpSlcaNEZOPR0cMCPBYy0skMUs4ykq4bVTy3I2qASdY3vb4l795OJPrK5FYyed
# ML5Zad7V8yrif0Cy/Ywy1C4TN6ftoEVH6HFEmJTohEY5BjT5qNK5tpmEs/o7z8W2oJa9Su
# G+KMAGe6AS/4ryQ+OQRJXzzFnAQRnR2Ou3iAA2ypsGWmP09Sr+1bb2qRSvy+lybaayfSLQ
# FouTQxecNq5TVfo1PWaGH9lLxd4i3J0PLk6uM8HfkIFimEN8h+4XT/4YXwO1czwun+IWaS
# nD92KIrdoHth+v05f8PpuqCz6odzojO33GfkMU/6Lkp2RgYeHD4eDb2/vyIJUtZHTPwPPJ
# tDybf2GbcDD4F43+fZdz7Q5A4a9DSDHeB6qZoqou6pUttbTneKQn/tq2yVa0TpyUjbGoCA
# QBvT4=
# -----END SSH SIGNATURE-----
# gpg verification failed.

# Conflicts:
#	pom.xml
2025-04-04 18:26:20 +02:00
Tobias Hagemann
b9df56a6de Merge branch 'hotfix/1.15.2' 2025-04-04 18:24:13 +02:00
Tobias Hagemann
38dbefff0b Updated webdav-nio-adapter dependency, fixes #3806, fixes #3807 2025-04-04 18:12:03 +02:00
Tobias Hagemann
4cbe45919b Moved jfuse dependency bump into dependencyManagement 2025-04-04 17:43:44 +02:00
Armin Schrenk
b7ccf7986d set version infos 2025-04-04 17:05:49 +02:00
Armin Schrenk
40d632a489 Closes #3807 2025-04-04 16:28:08 +02:00
Armin Schrenk
800aca5207 fix password enter dialog 2025-04-04 16:26:36 +02:00
Armin Schrenk
6a26d95c15 Feature: Event view (#3780) 2025-04-03 18:10:22 +02:00
Tobias Hagemann
439d3d7529 Update CONTRIBUTING.md 2025-03-29 18:00:22 +01:00
Armin Schrenk
7476e192a3 [skip ci] fix wrong JDK version in appimage build 2025-03-24 17:16:46 +01:00
Armin Schrenk
c6193bc259 update JDK for release builds to 23.0.2 (except ppa-builds) 2025-03-24 16:55:45 +01:00
Armin Schrenk
7446c69cd8 Update org.cryptomator:fuse-nio-adapter from 5.0.3 to 5.0.4
fixes #3797
2025-03-24 14:38:12 +01:00
Armin Schrenk
43c352e0d2 prepare 1.16.0 2025-03-18 11:39:46 +01:00
Armin Schrenk
61ec3bc465 Merge branch 'feature/event-view' into release/1.16.0
# Conflicts:
#	pom.xml
2025-03-18 11:39:22 +01:00
Armin Schrenk
36dd98127d update to cryptofs 2.9.0-beta2 2025-03-18 11:38:52 +01:00
Armin Schrenk
30862146b0 Merge branch 'feature/decrypt-name' into release/1.16.0
# Conflicts:
#	pom.xml
2025-03-18 11:21:54 +01:00
Armin Schrenk
c19734da6f decrypt name is always possible 2025-03-18 11:17:49 +01:00
Armin Schrenk
ba8fb273c7 cleanup 2025-03-18 11:14:38 +01:00
Armin Schrenk
5204a8e356 remove unused icons 2025-03-18 11:10:38 +01:00
Armin Schrenk
43b341860b extend styling to dark theme 2025-03-18 11:09:43 +01:00
dependabot[bot]
ad02e43daf Merge pull request #3787 from cryptomator/dependabot/maven/java-production-dependencies-af5d03dc73 2025-03-18 10:07:14 +00:00
Armin Schrenk
4942bcb52b exclude fasterxml:jackson-core dependency from auth0:java-jwt 2025-03-17 18:15:43 +01:00
dependabot[bot]
6b2e718e04 Bump the java-production-dependencies group across 1 directory with 13 updates
Bumps the java-production-dependencies group with 13 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [org.cryptomator:cryptolib](https://github.com/cryptomator/cryptolib) | `2.2.0` | `2.2.1` |
| [org.cryptomator:fuse-nio-adapter](https://github.com/cryptomator/fuse-nio-adapter) | `5.0.2` | `5.0.3` |
| [org.cryptomator:webdav-nio-adapter](https://github.com/cryptomator/webdav-nio-adapter) | `2.0.7` | `2.0.8` |
| [org.cryptomator:integrations-api](https://github.com/cryptomator/integrations-api) | `1.5.0` | `1.5.1` |
| org.slf4j:slf4j-api | `2.0.16` | `2.0.17` |
| [ch.qos.logback:logback-core](https://github.com/qos-ch/logback) | `1.5.16` | `1.5.17` |
| [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) | `1.5.16` | `1.5.17` |
| [io.github.coffeelibs:tiny-oauth2-client](https://github.com/coffeelibs/tiny-oauth2-client) | `0.8.0` | `0.8.1` |
| [com.auth0:java-jwt](https://github.com/auth0/java-jwt) | `4.4.0` | `4.5.0` |
| [com.fasterxml.jackson.core:jackson-databind](https://github.com/FasterXML/jackson) | `2.18.2` | `2.18.3` |
| com.fasterxml.jackson.datatype:jackson-datatype-jsr310 | `2.18.2` | `2.18.3` |
| [org.jetbrains:annotations](https://github.com/JetBrains/java-annotations) | `26.0.1` | `26.0.2` |
| [org.cryptomator:integrations-linux](https://github.com/cryptomator/integrations-linux) | `1.5.2` | `1.5.3` |



Updates `org.cryptomator:cryptolib` from 2.2.0 to 2.2.1
- [Release notes](https://github.com/cryptomator/cryptolib/releases)
- [Commits](https://github.com/cryptomator/cryptolib/compare/2.2.0...2.2.1)

Updates `org.cryptomator:fuse-nio-adapter` from 5.0.2 to 5.0.3
- [Release notes](https://github.com/cryptomator/fuse-nio-adapter/releases)
- [Commits](https://github.com/cryptomator/fuse-nio-adapter/compare/5.0.2...5.0.3)

Updates `org.cryptomator:webdav-nio-adapter` from 2.0.7 to 2.0.8
- [Release notes](https://github.com/cryptomator/webdav-nio-adapter/releases)
- [Commits](https://github.com/cryptomator/webdav-nio-adapter/compare/2.0.7...2.0.8)

Updates `org.cryptomator:integrations-api` from 1.5.0 to 1.5.1
- [Release notes](https://github.com/cryptomator/integrations-api/releases)
- [Commits](https://github.com/cryptomator/integrations-api/compare/1.5.0...1.5.1)

Updates `org.slf4j:slf4j-api` from 2.0.16 to 2.0.17

Updates `ch.qos.logback:logback-core` from 1.5.16 to 1.5.17
- [Release notes](https://github.com/qos-ch/logback/releases)
- [Commits](https://github.com/qos-ch/logback/compare/v_1.5.16...v_1.5.17)

Updates `ch.qos.logback:logback-classic` from 1.5.16 to 1.5.17
- [Release notes](https://github.com/qos-ch/logback/releases)
- [Commits](https://github.com/qos-ch/logback/compare/v_1.5.16...v_1.5.17)

Updates `ch.qos.logback:logback-classic` from 1.5.16 to 1.5.17
- [Release notes](https://github.com/qos-ch/logback/releases)
- [Commits](https://github.com/qos-ch/logback/compare/v_1.5.16...v_1.5.17)

Updates `io.github.coffeelibs:tiny-oauth2-client` from 0.8.0 to 0.8.1
- [Release notes](https://github.com/coffeelibs/tiny-oauth2-client/releases)
- [Commits](https://github.com/coffeelibs/tiny-oauth2-client/compare/0.8.0...0.8.1)

Updates `com.auth0:java-jwt` from 4.4.0 to 4.5.0
- [Release notes](https://github.com/auth0/java-jwt/releases)
- [Changelog](https://github.com/auth0/java-jwt/blob/master/CHANGELOG.md)
- [Commits](https://github.com/auth0/java-jwt/compare/4.4.0...4.5.0)

Updates `com.fasterxml.jackson.core:jackson-databind` from 2.18.2 to 2.18.3
- [Commits](https://github.com/FasterXML/jackson/commits)

Updates `com.fasterxml.jackson.datatype:jackson-datatype-jsr310` from 2.18.2 to 2.18.3

Updates `com.fasterxml.jackson.datatype:jackson-datatype-jsr310` from 2.18.2 to 2.18.3

Updates `org.jetbrains:annotations` from 26.0.1 to 26.0.2
- [Release notes](https://github.com/JetBrains/java-annotations/releases)
- [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md)
- [Commits](https://github.com/JetBrains/java-annotations/compare/26.0.1...26.0.2)

Updates `org.cryptomator:integrations-linux` from 1.5.2 to 1.5.3
- [Release notes](https://github.com/cryptomator/integrations-linux/releases)
- [Commits](https://github.com/cryptomator/integrations-linux/compare/1.5.2...1.5.3)

---
updated-dependencies:
- dependency-name: org.cryptomator:cryptolib
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: org.cryptomator:fuse-nio-adapter
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: org.cryptomator:webdav-nio-adapter
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: org.cryptomator:integrations-api
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: org.slf4j:slf4j-api
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: ch.qos.logback:logback-core
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: ch.qos.logback:logback-classic
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: ch.qos.logback:logback-classic
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: io.github.coffeelibs:tiny-oauth2-client
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: com.auth0:java-jwt
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: java-production-dependencies
- dependency-name: com.fasterxml.jackson.core:jackson-databind
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: com.fasterxml.jackson.datatype:jackson-datatype-jsr310
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: com.fasterxml.jackson.datatype:jackson-datatype-jsr310
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: org.jetbrains:annotations
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: org.cryptomator:integrations-linux
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-17 16:47:33 +00:00
Ralph Plawetzki
a1323b5e81 Merge pull request #3785 from purejava/fix/improve-symbolic-icons 2025-03-17 17:46:23 +01:00
dependabot[bot]
ab4f487de1 Bump the javafx group with 5 updates (#3703) 2025-03-17 16:40:48 +00:00
Armin Schrenk
d506e7472d Bump cryptofs from 2.8.0 to 2.9.0-beta2
Closes #3707
2025-03-17 17:32:48 +01:00
Armin Schrenk
2d33d02b46 Feature: TouchID [macOS]
Closes #2180
2025-03-17 17:29:39 +01:00
Armin Schrenk
06ddec4b70 more UI refinment:
* only copy decrypted names to clipboard
* indicate in UI
2025-03-17 17:14:52 +01:00
Armin Schrenk
24e31553fd refine UI:
* align locate/decrypt buttons horizontally
* change to text icons
* dedup code
2025-03-17 12:02:03 +01:00
Armin Schrenk
eaa6b31de8 bump cryptofs to 2.9.0-beta2 2025-03-14 16:15:17 +01:00
Ralph Plawetzki
060ae588a2 Improve symbolic icons (#3782)
* Remove the style attributes from the path tags
Fixes #3775
* Improve SVG code using a <g> tag and tighten current-color-scheme definition
* Add missing attribute from original SVG
2025-03-14 13:22:14 +01:00
Armin Schrenk
262f84e8db new design 2025-03-13 16:47:23 +01:00
Armin Schrenk
6d55331ef2 add missing translation key 2025-03-13 10:36:40 +01:00
Armin Schrenk
42269a6057 just a draft 2025-03-12 18:01:06 +01:00
Armin Schrenk
181e45a596 renamed event list item localization keys 2025-03-12 15:27:24 +01:00
Armin Schrenk
3c8e506805 add tooltip for clear all button 2025-03-12 15:21:32 +01:00
Armin Schrenk
401b0afe9f remove unnecessary code 2025-03-12 12:37:06 +01:00
Armin Schrenk
42ec41b991 clean up code 2025-03-12 12:19:27 +01:00
Armin Schrenk
7ec3c5d04f first delete, then write 2025-03-12 11:41:12 +01:00
Armin Schrenk
f0a7379575 hide count if vault is locked 2025-03-12 10:50:36 +01:00
Armin Schrenk
0d12b11c48 cleanup 2025-03-12 10:01:09 +01:00
Armin Schrenk
14a025f769 size restrict the eventMap 2025-03-12 10:00:56 +01:00
Armin Schrenk
598fc9bbc8 complete themes 2025-03-12 10:00:34 +01:00
Armin Schrenk
fbab2df00f add notification marker for new events 2025-03-12 09:38:56 +01:00
Armin Schrenk
fb56b61a75 add exceptionally clause to keychain migration task 2025-03-11 17:14:42 +01:00
Armin Schrenk
c5c3d55658 Merge branch 'develop' into feature/touch-id 2025-03-11 17:08:13 +01:00
Armin Schrenk
48c2d49c86 revert default version string 2025-03-11 17:07:46 +01:00
Armin Schrenk
00d68393f6 use beta version of cryptoFs 2025-03-11 17:07:17 +01:00
Armin Schrenk
7a50ba0b43 Merge branch 'develop' into feature/event-view 2025-03-11 17:03:58 +01:00
Armin Schrenk
b2bee99286 Refactor: Out-of-bounds-check (#3778)
fixes #3723, fixes #3722
2025-03-11 16:03:49 +01:00
Armin Schrenk
88d384afdf reduce tooltip show duration 2025-03-07 11:50:53 +01:00
Armin Schrenk
7af82b831f add event count to viewer 2025-03-07 11:50:40 +01:00
Armin Schrenk
a86f42fa44 replace eventList with a eventMap in model to group events 2025-03-07 11:21:23 +01:00
Sebastian Stenzel
70b0413777 replace labels with issue type
see https://github.blog/changelog/2025-01-13-evolving-github-issues-public-preview/#organize-your-work-with-issue-types
[ci skip]
2025-03-07 09:32:39 +01:00
Sebastian Stenzel
577a77af38 moved summary to the top for better link previews 2025-03-07 09:31:35 +01:00
Armin Schrenk
3ba7e9ba00 cleanup 2025-03-06 12:55:12 +01:00
Armin Schrenk
b2250e8ce0 add Tooltip 2025-03-06 12:54:58 +01:00
Armin Schrenk
f2a480c7a0 reworked event cell texts 2025-03-06 12:40:02 +01:00
Armin Schrenk
bda38096e1 fix minor inconsitencies 2025-03-04 12:34:45 +01:00
Armin Schrenk
7e66a61294 add choicebox to filter for single vaults 2025-03-04 12:34:17 +01:00
clkue
3aa627a467 fix unicode escaping for rtf file (#3609)
Signed-off-by: C1emency <>
Signed-off-by: clkue <clemens_kuennemann@protonmail.com>
2025-03-03 14:55:09 +01:00
Armin Schrenk
ae1b5fc925 Switch to ubuntu-22.04 for building the deb package 2025-03-03 12:05:25 +01:00
mindmonk
b1076f9c86 Merge pull request #3764 from cryptomator/feature/dialogBuilder-one-Button
Feature: Simple Dialog with one Button
2025-02-28 14:53:22 +01:00
Jan-Peter Klein
ede1c72595 cancelButtonVisible BooleanProperty to boolean 2025-02-28 13:29:04 +01:00
Armin Schrenk
d2fcd5b64f adjust stylings 2025-02-28 10:36:13 +01:00
Armin Schrenk
6d9704ffa2 adjust event description when locked 2025-02-28 10:36:03 +01:00
Armin Schrenk
40df3d015a remove optional wrapper of revealService 2025-02-28 10:01:52 +01:00
Armin Schrenk
4e22706d92 add alternative if revealService is not present 2025-02-28 09:51:58 +01:00
Armin Schrenk
341710f724 add time field to the eventcell 2025-02-27 18:56:41 +01:00
Armin Schrenk
8386183f7a * Hide button when not hovering or vault is locked
* localize
2025-02-27 17:25:31 +01:00
Armin Schrenk
b76a7d6895 implement event views for all filesystemevents 2025-02-26 18:36:52 +01:00
Jan-Peter Klein
4a397a8151 code cleanup 2025-02-26 12:36:03 +01:00
Armin Schrenk
2239a3e6a3 reduce API to only consider vault events 2025-02-26 11:56:17 +01:00
tturturiello
5318368879 Add underline effect to clickable notification labels (#3757) 2025-02-26 11:53:46 +01:00
Jan-Peter Klein
41a279da9d renamed property 2025-02-25 19:04:25 +01:00
Jan-Peter Klein
478c69f82c simple dialog without cancel button 2025-02-25 18:23:17 +01:00
Armin Schrenk
eb0e630a44 move migration to KeychainManager 2025-02-25 17:33:14 +01:00
Armin Schrenk
0bcbf9a13a add migration code and synchronize keychain edits 2025-02-25 16:32:38 +01:00
Armin Schrenk
e3073a3613 adjust wording for autoLock feature [skip ci] 2025-02-25 15:38:50 +01:00
Armin Schrenk
3333dc7f22 Fix not appearing removeCert dialog 2025-02-25 11:52:00 +01:00
Julian Raufelder
12ec6fbec8 Change /access-token deviceId header name to Hub-Device-ID 2025-02-19 14:25:34 +01:00
Armin Schrenk
43fc976ad7 reduce #3311 to touchID 2025-02-19 11:49:59 +01:00
Armin Schrenk
034278c0a0 changes:
* implement reveal conflictResolved
* removed showVault context menu entry
* cleanup
2025-02-19 11:27:39 +01:00
Julian Raufelder
92b3a9e1bd Merge pull request #3752 from cryptomator/feature/add-device-id-during-hub-unlock
Send DeviceId to Hub during vault key retrieval
2025-02-19 09:51:39 +01:00
Julian Raufelder
fc7169f2a0 Send DeviceId to Hub during vault key retrieval
See https://github.com/cryptomator/hub/pull/320
2025-02-19 09:05:13 +01:00
Armin Schrenk
c39710ede0 show event specific context menu 2025-02-18 18:32:06 +01:00
Armin Schrenk
cc0b6aed15 Update org.cryptomator.Cryptomator.metainfo.xml
* adjust screenshot captions
* reorder screenshots
* add keywords
2025-02-18 16:52:31 +01:00
Armin Schrenk
f8a83c9cc8 scope eventListcell factory 2025-02-18 15:32:34 +01:00
Armin Schrenk
43ce64f01e adjust styling 2025-02-18 11:44:48 +01:00
mindmonk
d585a03f76 Merge pull request #3699 from cryptomator/feature/vault-scheme-tag
Add lastKnownKeyLoader entry to VaultSettings
2025-02-17 17:35:47 +01:00
Armin Schrenk
f953be6237 Merge branch 'develop' into feature/event-view 2025-02-17 17:12:35 +01:00
Armin Schrenk
e81bbe197b if mainWindow is closed without tray menu, terminate app 2025-02-17 16:46:25 +01:00
Armin Schrenk
738fa4da12 cleanup 2025-02-17 16:08:09 +01:00
dependabot[bot]
9a08dcc46d Bump org.owasp:dependency-check-maven (#3748) 2025-02-17 10:04:30 +00:00
Armin Schrenk
74ef8d915d make eventView independent, but singleton window 2025-02-14 17:26:25 +01:00
Armin Schrenk
025a7a5582 add contextMenu to eventListCell 2025-02-14 17:11:43 +01:00
Armin Schrenk
3b2ddcf98d style the eventlist cell more 2025-02-14 16:47:15 +01:00
Armin Schrenk
c10fc0ee5b Update README.md
For build badge use develop branch.
2025-02-14 11:56:55 +01:00
Armin Schrenk
aaa37e2c7a Feature: Add UTM parameters to download uri (#3735)
Co-authored-by: Tobias Hagemann <tobias.hagemann@skymatic.de>
2025-02-14 11:55:22 +01:00
Armin Schrenk
7af7c920e3 use same listCell factory pattern as in vault list 2025-02-14 11:54:25 +01:00
Armin Schrenk
a4f79fb98a unify naming 2025-02-14 11:41:35 +01:00
Armin Schrenk
f429f2d3e7 rename method 2025-02-14 10:51:48 +01:00
Armin Schrenk
4f6e091c13 first proper design draft 2025-02-13 16:58:05 +01:00
Jan-Peter Klein
2df779f7ab introduce isMasterkeyFileVault() 2025-02-13 15:44:10 +01:00
Jan-Peter Klein
5b9d9150c5 remove extra try catch block 2025-02-13 15:39:06 +01:00
Jan-Peter Klein
f0aaec2058 comparison reversed 2025-02-13 15:15:29 +01:00
Jan-Peter Klein
4adc4a9175 removed unused StringBinding 2025-02-13 15:03:14 +01:00
Armin Schrenk
5a97060fac make the list synchronized 2025-02-13 11:06:48 +01:00
Armin Schrenk
db96074119 replace AppEvent by UpdateEvent and emit it on available update 2025-02-12 11:12:40 +01:00
Jan-Peter Klein
7ecc10bc79 removed setVaultScheme method; lastKnownKeyLoader is now set within the create method 2025-02-12 10:35:21 +01:00
Armin Schrenk
44fe4a6f8a displayable event view window 2025-02-11 17:37:04 +01:00
Jan-Peter Klein
76a4ef50cb improve exception handling 2025-02-11 16:21:53 +01:00
Armin Schrenk
ca2f80024a impl draft 2025-02-11 15:38:18 +01:00
Armin Schrenk
dcd7077b08 Feature: readd out of bounds check (#3729)
references #3091
2025-02-11 15:24:36 +01:00
Armin Schrenk
31482d7d18 [skip ci] update ide files 2025-02-11 12:37:45 +01:00
Armin Schrenk
5ef666154e use correct height in css [skip ci] 2025-02-11 10:16:34 +01:00
Armin Schrenk
a810eff797 make menu buttons in vault list appear clickable 2025-02-10 18:29:57 +01:00
Jan-Peter Klein
664158eb84 add isHubVault method to KeyLoadingStrategy 2025-02-10 18:09:03 +01:00
Armin Schrenk
6b43881909 [skip ci] update screenshot url in metainfo file 2025-02-10 17:08:03 +01:00
Jan-Peter Klein
126004b1f8 improve error handling 2025-02-10 12:58:54 +01:00
Jan-Peter Klein
ba34cfa9d5 renamed to lastKnownKeyLoader 2025-02-10 12:07:25 +01:00
Armin Schrenk
03b4ad85ef [skip ci] Merge branch 'main' into develop 2025-02-05 16:22:09 +01:00
Armin Schrenk
1abfcd495f Merge branch 'release/1.15.1' 2025-02-05 16:19:41 +01:00
Armin Schrenk
69964a80f1 finalize 1.15.1 2025-02-05 16:18:59 +01:00
Armin Schrenk
aa8306ea4a prepare 1.15.1 2025-02-05 16:16:53 +01:00
Cryptobot
3fecde37f4 New Crowdin updates (#3718)
New translations strings.properties

Korean

[ci skip]
2025-02-05 16:16:20 +01:00
Armin Schrenk
2fc5fd99fb remove english "localization" 2025-02-05 16:11:36 +01:00
Armin Schrenk
7edacfea70 fixes #3721 2025-02-05 16:02:27 +01:00
Armin Schrenk
7020fa49d9 [skip ci] remove copyright notice 2025-02-05 11:44:58 +01:00
Armin Schrenk
7cea0bb33c update appstream screenshots 2025-02-05 11:44:40 +01:00
Armin Schrenk
3d622b18dc update flatpak metadata 2025-02-04 11:55:14 +01:00
Kulesko
62cd506588 fix broken doc links (#3715) 2025-02-03 17:34:27 +01:00
Armin Schrenk
cd830f27a0 update IDE file 2025-02-03 12:54:34 +01:00
Armin Schrenk
3f75018369 fix link in README 2025-02-03 12:54:25 +01:00
Armin Schrenk
270a4c594d [skip ci] Merge branch 'main' into develop 2025-02-03 11:34:16 +01:00
Armin Schrenk
a5fdc5755b Merge branch 'release/1.15.0' 2025-02-03 11:16:18 +01:00
Armin Schrenk
0a5a554714 finalize 1.15.0 2025-02-03 11:15:59 +01:00
Armin Schrenk
976f22c27a Merge branch 'develop' into release/1.15.0 2025-02-03 11:12:20 +01:00
Cryptobot
8267574697 New Crowdin updates (#3697)
New translations strings.properties

Afrikaans; Arabic; Bashkir; Belarusian; Bengali; Bosnian; Bulgarian; Catalan; Chinese Simplified; Chinese Traditional; Chinese Traditional, Hong Kong; Croatian; Czech; Danish; Dutch; Filipino; Finnish; French; Galician; German; Greek; Hebrew; Hindi; Hungarian; Indonesian; Italian; Japanese; Korean; Latvian; Macedonian; Marathi; Norwegian; 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; Urdu (Pakistan); Uyghur; Vietnamese; 

[ci skip]
2025-02-03 10:56:49 +01:00
mindmonk
9077c964b3 Fix VaultListCell Padding in Compact Mode (#3709) 2025-02-03 10:50:06 +01:00
Armin Schrenk
f80467a3a4 Fixes #3705 2025-01-28 15:09:52 +01:00
Julian Raufelder
8c462c4cb7 RIP Twitter
[ci skip]
2025-01-23 12:21:54 +01:00
Jan-Peter Klein
b25b5bd5a3 add keyLoader to observables 2025-01-22 16:59:52 +01:00
Jan-Peter Klein
6365c22297 add keyLoader entry to VaultSettings 2025-01-22 16:46:18 +01:00
Armin Schrenk
d7dd24b94e linting 2025-01-22 16:26:25 +01:00
Armin Schrenk
aee8844558 Fixes #3698 2025-01-22 16:25:56 +01:00
Armin Schrenk
c536149c62 specify JDK 23 also in debian control file
References #3641

(cherry picked from commit ca1ae8181b)
2025-01-22 14:12:56 +01:00
Armin Schrenk
ca1ae8181b specify JDK 23 also in debian control file
References #3641
2025-01-22 14:11:19 +01:00
Armin Schrenk
2b19c9757b prepare 1.15.0 2025-01-22 12:06:00 +01:00
Armin Schrenk
d6871e3d82 clean up pom 2025-01-22 11:58:09 +01:00
Cryptobot
0432a64537 New Crowdin updates (#3606)
New translations strings.properties

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

[ci skip]
2025-01-22 11:10:17 +01:00
mindmonk
06988b06c7 Feature: Retry if Read-only (#3695)
Closes #3261, closes #2085.

Co-authored-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-01-22 11:02:48 +01:00
dependabot[bot]
9b72eb8219 Bump the java-production-dependencies group across 1 directory with 8 updates (#3694) 2025-01-21 16:06:50 +00:00
Armin Schrenk
ea188f6176 for testing add mockito as javaagent 2025-01-21 15:53:49 +01:00
dependabot[bot]
cf67d022c8 Bump the java-test-dependencies group across 1 directory with 2 updates (#3671) 2025-01-21 13:36:52 +00:00
dependabot[bot]
7ba6e12799 Bump the maven-build-plugins group across 1 directory with 3 updates (#3688) 2025-01-21 13:35:13 +00:00
Armin Schrenk
b512518ccc update README [skip ci] 2025-01-21 11:46:30 +01:00
Armin Schrenk
93dfd35627 update Windows build scripts 2025-01-21 11:46:15 +01:00
Armin Schrenk
50b92f9510 fix URL in README [skip ci] 2025-01-21 11:43:38 +01:00
Armin Schrenk
7cca8922d8 Closes #3623 2025-01-21 11:39:14 +01:00
Armin Schrenk
c00889b1c4 update to javafx 23.0.1 (#3691) 2025-01-21 11:32:48 +01:00
Armin Schrenk
b6224f355d Fixes #3693 2025-01-21 10:44:28 +01:00
Armin Schrenk
9a8f96d432 remove unused dll from windows build [skip ci] 2025-01-20 19:18:08 +01:00
Sebastian Stenzel
3cc199227b Include AppStream metadata in AppImage (#3687) 2025-01-20 17:59:59 +01:00
Sebastian Stenzel
3d0647bce3 fix appimage build (#3686)
* remove unsupported parameter `--sign-args`

apparently no longer wanted, despite being documented, see https://github.com/AppImage/appimagetool/issues/39

* add usr/share/metainfo/Cryptomator.appdata.xml

* appimagetool fails when adding AppStream metadata

see https://github.com/AppImage/AppImageKit/issues/603
2025-01-18 12:18:25 +01:00
DrSheppard
192f35a9dd resolve #3055 (again) (#3685)
* use new build tool with runtime support instead old build tool for appimage

* Update workflow file to use newer appimagetool
2025-01-18 11:09:42 +01:00
Armin Schrenk
f2b4c9a35b Update integrations-linux to 1.5.2
Fixes #3611
2025-01-17 18:05:10 +01:00
Armin Schrenk
3b8fec4c5a Feature: Use system certificate stores/custom pkcs12 file (#3675)
* for Windows use Windows certificate
* for macOS use macOS Keychain
* for Linux use a custom PKCS12 file under /etc/cryptomator/certs.p12
2025-01-17 15:12:38 +01:00
DrSheppard
60b74a018d AppImage: Use new build tool with runtime2 support (#3586)
Closes #3055
2025-01-17 13:49:11 +01:00
Armin Schrenk
be69e04f51 fix build due to breaking changes in cryptofs 2025-01-17 13:28:14 +01:00
Armin Schrenk
194f6009df Update cryptofs to version 2.7.2 2025-01-17 13:22:45 +01:00
Sebastian Stenzel
910a2eace8 build AppImage on ubuntu-24.04-arm (#3681) 2025-01-17 09:08:02 +01:00
Jan-Peter Klein
3c95618eec changed dokany dialog icon to EXCLAMATION 2025-01-15 16:16:40 +01:00
Armin Schrenk
fc709eb700 use caffeine for building a cache 2025-01-14 19:16:46 +01:00
Julian Raufelder
a6c60ac5d0 Hello 2025 🎉 2025-01-14 16:34:32 +01:00
mindmonk
b88b9c8f92 Merge pull request #3676 from cryptomator/feature/change-zulu-to-temurin
Changed JAVA_DIST zulu to temurin
2025-01-13 13:25:55 +01:00
dependabot[bot]
2b8cd36b7b Bump ch.qos.logback:logback-core from 1.5.12 to 1.5.13 (#3655)
Bumps [ch.qos.logback:logback-core](https://github.com/qos-ch/logback) from 1.5.12 to 1.5.13.
- [Commits](https://github.com/qos-ch/logback/compare/v_1.5.12...v_1.5.13)

---
updated-dependencies:
- dependency-name: ch.qos.logback:logback-core
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-12 15:27:30 +01:00
Jan-Peter Klein
3d23deb744 changed JAVA_DIST zulu to temurin 2025-01-12 14:42:04 +01:00
mindmonk
de3b2715c7 Merge pull request #3618 from cryptomator/feature/dialog-builder
Feature: SimpleDialogBuilder
2025-01-10 15:17:24 +01:00
Jan-Peter Klein
f3d8bd359d Merge branch 'develop' into feature/dialog-builder 2025-01-10 15:05:07 +01:00
Armin Schrenk
d7d6e46b2a Ensure JDK 23 is used in building mac dmg x64 2025-01-10 14:33:34 +01:00
Jan-Peter Klein
501f682d68 annotate Dialogs with @Singleton
removed redundant providers
2025-01-10 11:58:19 +01:00
Jan-Peter Klein
7cbf1e10e5 refactor dialogs with injected resourceBundle for builder creation 2025-01-09 17:39:02 +01:00
Jan-Peter Klein
fb00972bc1 improve naming 2025-01-09 15:31:07 +01:00
Jan-Peter Klein
387fb28c65 remove unused LOGs and improved var naming 2025-01-09 15:22:25 +01:00
Jan-Peter Klein
40fbfd10d1 moved all simple dialogs to Dialogs 2025-01-08 19:17:20 +01:00
Jan-Peter Klein
e5e4695cd6 replaced setters and extended the constructor of SimpleDialogController 2025-01-08 17:50:54 +01:00
Armin Schrenk
4a0c8ae80e fix check-jdk-update workflow [ci skip] 2025-01-08 17:09:53 +01:00
Armin Schrenk
384ca8eb2a for testing 2025-01-08 16:02:00 +01:00
Jan-Peter Klein
59f360bde7 improve formatting, rename and simplify vars 2025-01-08 15:07:04 +01:00
Jan-Peter Klein
8830e0f5fb Move repeated 'remove vault' dialog to Dialogs class 2025-01-07 15:19:06 +01:00
Jan-Peter Klein
7a391a2825 reformat code 2025-01-07 14:47:20 +01:00
Jan-Peter Klein
a1941911ef renamed to simple Dialog 2025-01-07 14:45:09 +01:00
Jan-Peter Klein
a0667ff361 add validation for required parameters and changed exception message 2025-01-07 14:39:22 +01:00
Armin Schrenk
cbc41d535d Merge pull request #3641 from cryptomator/feature/jdk23
Feature: JDK 23
2024-12-11 15:42:09 +01:00
Armin Schrenk
f51780dcb5 also update deb rules file [ci skip] 2024-12-10 18:03:07 +01:00
Armin Schrenk
c055488df7 update github workflows 2024-12-10 17:47:48 +01:00
Armin Schrenk
b15c376e59 fix and update JDK check workflow 2024-12-10 17:42:55 +01:00
Armin Schrenk
fdf03d2fdc enable JDK23 for IDE 2024-12-10 17:15:34 +01:00
Armin Schrenk
437350af9f reduce api diff 2024-12-10 17:14:09 +01:00
Julian Raufelder
5114e2ad22 Merge pull request #3640 from lamtrinhdev/develop
Correct the link of issues list for both iOS and Android.
2024-12-09 14:09:03 +01:00
LamTrinh.Dev
b3b4f61c42 Correct the link of issues list for both iOS and Android. 2024-12-09 19:13:44 +07:00
Armin Schrenk
fa16556af1 do not allow empty display name for vault
Fixes #3633
2024-12-02 11:02:11 +01:00
Armin Schrenk
de766c2653 Update suppression.xml 2024-12-02 09:40:40 +01:00
Armin Schrenk
dcc27efe5c remove unused option in app-image creation [skip ci]
references 84732337ca
2024-11-28 17:26:10 +01:00
Armin Schrenk
78ceb604f9 only use macos intel runner on releases 2024-11-27 16:47:42 +01:00
Armin Schrenk
7bdcdcba3d Update suppression.xml 2024-11-26 15:49:43 +01:00
Jan-Peter Klein
e929d41d67 reordered and renamed to org.ui.dialogs.SimpleDialog... 2024-11-25 19:23:48 +01:00
Jan-Peter Klein
600aca083c refactor CustomDialog.Builder provisioning to use Dagger's Provider 2024-11-25 15:09:29 +01:00
Jan-Peter Klein
02c20c01ee improve exception handling 2024-11-21 16:55:03 +01:00
mindmonk
50cfdbbc0b Merge pull request #3617 from cryptomator/feature/ui-cleanup
Enhance UI Components, Fix Issues, and Improve Visual Consistency
2024-11-20 12:21:31 +01:00
Gutyina Gergő
38c556af0b Update jdk version to 23 2024-11-19 23:31:24 +01:00
Gutyina Gergő
0b9d777109 Remove string templates 2024-11-19 23:31:24 +01:00
Armin Schrenk
eb3c1f3c7a Merge branch 'main' into develop
# Conflicts:
#	pom.xml
2024-11-19 10:01:00 +01:00
Armin Schrenk
311c490377 Merge branch 'hotfix/1.14.2' 2024-11-19 09:59:27 +01:00
Armin Schrenk
39ed00ff6f Use correct version 2024-11-19 09:57:56 +01:00
Armin Schrenk
28338d2dcf use stable version 2024-11-19 09:50:46 +01:00
Jan-Peter Klein
bba5d11bdc small fixes 2024-11-18 18:07:36 +01:00
mindmonk
36ef191874 Merge branch 'develop' into feature/dialog-builder 2024-11-18 17:58:59 +01:00
Jan-Peter Klein
3e4c6c1b61 del old logo file 2024-11-18 16:59:13 +01:00
Jan-Peter Klein
c9d0224814 fix logo scaling 2024-11-18 16:48:41 +01:00
Armin Schrenk
8aed6045a0 Feature: Show update reminder every 14 days (#3597)
fixes #3596

only show update reminder every 14 days
2024-11-15 18:14:57 +01:00
Jan-Peter Klein
8440705436 set resizable false 2024-11-15 15:49:11 +01:00
Jan-Peter Klein
af667b10cf code cleanup 2024-11-14 18:09:23 +01:00
Jan-Peter Klein
1b522fe9a0 undo add uiDesigner 2024-11-14 17:20:08 +01:00
Jan-Peter Klein
cb3c46744e removed replaced files 2024-11-14 16:38:44 +01:00
Jan-Peter Klein
c471289fb5 changed resolveText() to throw Exceptions
removed fxApplication scope
2024-11-14 16:19:50 +01:00
Jan-Peter Klein
18ca563865 custom dialog init 2024-11-14 11:35:23 +01:00
Jan-Peter Klein
2430526ee7 changed to class Builder
used FxmlLoaderFactory.forController
set title and other string values by key
2024-11-06 16:35:19 +01:00
Armin Schrenk
c9bb0235e2 use macos 15 for building [ci skip] 2024-11-05 16:18:32 +01:00
Armin Schrenk
2f8236e9db Update release template [ci skip] 2024-11-05 12:10:57 +01:00
Armin Schrenk
e4e757606d update dependencies for patch release
Fixes #3574 and #3499. Closes #3569
2024-11-05 11:11:32 +01:00
Cryptobot
6fcb796177 New Crowdin updates (#3559)
New translations strings.properties

Afrikaans; Arabic; Bashkir; Belarusian; Bengali; Bosnian; Bulgarian; Catalan; Chinese Simplified; Chinese Traditional; Chinese Traditional, Hong Kong; Croatian; Czech; Danish; Dutch; English; Filipino; Finnish; French; Galician; German; Greek; Hebrew; Hindi; Hungarian; Indonesian; Italian; Japanese; Korean; Latvian; Macedonian; Marathi; Norwegian; 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; Urdu (Pakistan); Uyghur; Vietnamese;

[ci skip]

(cherry picked from commit 0fb0bc8e1d)
2024-11-04 17:59:02 +01:00
Cryptobot
4d6b035c29 New Crowdin updates (#3553)
New translations strings.properties

Afrikaans; English; Norwegian; Thai; Uyghur;

[ci skip]

(cherry picked from commit 2939702842)
2024-11-04 17:57:43 +01:00
dependabot[bot]
68c206a4fa Bump the java-test-dependencies group across 1 directory with 2 updates (#3591) 2024-11-04 15:49:48 +00:00
dependabot[bot]
d258171131 Bump the maven-build-plugins group across 1 directory with 3 updates (#3598) 2024-11-04 15:47:08 +00:00
dependabot[bot]
adaf9ef5ce Bump the java-production-dependencies group across 1 directory with 8 updates (#3603) 2024-11-04 15:43:21 +00:00
Tobias Hagemann
22f299f67c Update README.md
[ci skip]
2024-11-04 15:13:40 +01:00
Cryptobot
0fb0bc8e1d New Crowdin updates (#3559)
New translations strings.properties

Afrikaans; Arabic; Bashkir; Belarusian; Bengali; Bosnian; Bulgarian; Catalan; Chinese Simplified; Chinese Traditional; Chinese Traditional, Hong Kong; Croatian; Czech; Danish; Dutch; English; Filipino; Finnish; French; Galician; German; Greek; Hebrew; Hindi; Hungarian; Indonesian; Italian; Japanese; Korean; Latvian; Macedonian; Marathi; Norwegian; 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; Urdu (Pakistan); Uyghur; Vietnamese; 

[ci skip]
2024-11-04 15:05:37 +01:00
Armin Schrenk
da666410fc update dependabot config 2024-11-04 14:56:02 +01:00
Armin Schrenk
ea007f3cfe fix IDE issues 2024-10-29 09:46:56 +01:00
Armin Schrenk
1c868a644f remove unused/obsolete static variable 2024-10-29 09:44:50 +01:00
Jan-Peter Klein
5ff6a8c258 used dialogBuilder for dokankySupportEndDialog 2024-10-23 19:48:55 +02:00
Jan-Peter Klein
62d7b7a0c0 replaced RemoveVaultComponent.Builder with CustomDialogBuilder in all places 2024-10-22 18:53:06 +02:00
Jan-Peter Klein
7fcbb57ab1 used builder pattern 2024-10-22 17:07:42 +02:00
Jan-Peter Klein
8e25dcd396 implement CustomDialogBuilder 2024-10-22 14:56:56 +02:00
mindmonk
a9f1e5b761 Merge pull request #3550 from cryptomator/feature/gdrive-presets
Feature: Refined GoogleDrive Presets - List Only "My Drive" Root Folders
2024-10-18 13:05:50 +02:00
Jan-Peter Klein
f642149723 used List.of() for FALLBACK_LOCATIONS 2024-10-16 18:00:47 +02:00
Jan-Peter Klein
4b359d98cb removed unnecessary stream support 2024-10-10 17:39:53 +02:00
Jan-Peter Klein
764fccf0b5 pr mentioned changes 2024-10-10 17:34:23 +02:00
Jan-Peter Klein
81d1059489 added generic 'Remove' string property 2024-10-09 17:35:33 +02:00
Jan-Peter Klein
a2574a5883 unified spacing 2024-10-09 16:59:13 +02:00
Jan-Peter Klein
118a1411d8 fixed empty vaultList contextMenu 2024-10-09 16:55:56 +02:00
Jan-Peter Klein
44310cbd0e set missing min width and height 2024-10-09 16:50:26 +02:00
Jan-Peter Klein
2dce7b6f71 removed drivePath param 2024-10-09 14:50:05 +02:00
Jan-Peter Klein
98db82d137 contains instead of stream 2024-10-09 14:48:40 +02:00
Jan-Peter Klein
fd55656261 filtered by 'My Drive' and translations 2024-10-08 20:08:37 +02:00
mindmonk
978dec64ee Merge pull request #3549 from cryptomator/feature/improve-preferences-contribute-tab
Feature: Optimize 'Support us' Tab in Preferences - Add Supporter Certificate Removal & Improved Layout
2024-10-04 12:27:13 +02:00
mindmonk
8d7bf3a370 Merge pull request #3467 from cryptomator/feature/redesign-mainwindow
Feature: Redesigned MainWindow
2024-10-04 12:13:09 +02:00
Jan-Peter Klein
1cea7bcffc set bigger minHeight 2024-10-02 17:03:52 +02:00
Jan-Peter Klein
16e77d4b9b add clear to setStyleClass 2024-10-02 16:56:39 +02:00
Jan-Peter Klein
f22111e36f revert unrelated changes 2024-10-02 16:46:41 +02:00
Jan-Peter Klein
c5d4c9a9c1 removed duplicate code 2024-10-02 14:20:09 +02:00
mindmonk
4bc9b1d60c Merge pull request #3474 from cryptomator/feature/notificationbar
Feature: Introduce NotificationBars for Update is available, Support Cryptomator, and DEBUG MODE
2024-10-02 11:05:58 +02:00
mindmonk
7a40a3cb0c Merge branch 'feature/redesign-mainwindow' into feature/notificationbar 2024-10-02 11:05:39 +02:00
mindmonk
ad555ece8e Merge pull request #3554 from cryptomator/feature/condensed-vault-list
Feature: Add Option to Enable Compact Vault List View
2024-10-02 10:55:51 +02:00
Jan-Peter Klein
2d96d2e5c6 optimised cellSize binding and removed unused imports 2024-10-01 18:56:21 +02:00
Armin Schrenk
0a968b60aa Remove Guava dependency and update Dagger 2024-10-01 17:19:31 +02:00
Jan-Peter Klein
3b4f82092d undo string removal 2024-10-01 13:31:43 +02:00
Jan-Peter Klein
de16647d00 reformat code 2024-09-26 11:24:57 +02:00
Ahmatjan
03403e53bc translation: Add Uyghur Language Translation (#3557) 2024-09-26 11:12:26 +02:00
Cryptobot
2939702842 New Crowdin updates (#3553)
New translations strings.properties

Afrikaans; English; Norwegian; Thai; Uyghur;

[ci skip]
2024-09-26 11:10:21 +02:00
Jan-Peter Klein
b3d09a4cae changed apostroph 2024-09-26 10:41:17 +02:00
Jan-Peter Klein
73c0af9749 changed wording and removed unnecessary method calls 2024-09-25 16:20:19 +02:00
Jan-Peter Klein
53c7e031a3 changes mentioned by infeo 2024-09-24 16:14:52 +02:00
Jan-Peter Klein
1e280f2c97 removed FXML loader, elements created programmatically in NotificationBar 2024-09-24 16:05:31 +02:00
Jan-Peter Klein
ce82593fc6 simplified bindings 2024-09-24 15:48:15 +02:00
Jan-Peter Klein
c2c3d778d1 added @CheckAvailability
changed exception handling
2024-09-24 15:29:13 +02:00
Jan-Peter Klein
7771181e15 changed wording to compact 2024-09-23 14:21:55 +02:00
Jan-Peter Klein
1a39333b4c cr mentioned changes 2024-09-23 14:02:42 +02:00
Armin Schrenk
85472db00a Merge branch 'main' into develop 2024-09-18 13:25:15 +02:00
Armin Schrenk
d6a020994e Merge branch 'hotfix/1.14.1' 2024-09-18 13:17:25 +02:00
Armin Schrenk
518f75be32 fixes #3538 2024-09-18 13:16:45 +02:00
Armin Schrenk
28c7dbad69 prepare 1.14.1 2024-09-18 13:16:16 +02:00
Jan-Peter Klein
31e9f3a025 Merge branch 'feature/redesign-mainwindow' into feature/condensed-vault-list 2024-09-17 18:06:14 +02:00
Jan-Peter Klein
a03d5af144 add tilter to display only folders with write permissions 2024-09-17 16:49:31 +02:00
Armin Schrenk
50a654d5af [ci skip] use recommended winget-releaser version 2024-09-17 11:37:27 +02:00
Armin Schrenk
1954f31910 [ci skip] Merge branch 'main' into develop 2024-09-17 10:04:32 +02:00
Armin Schrenk
68bf441fdd Merge branch 'release/1.14.0' 2024-09-17 10:03:02 +02:00
Armin Schrenk
a606bcb81e finalize 1.14.0 2024-09-17 09:59:22 +02:00
Armin Schrenk
fe93e51ffa Merge branch 'develop' into release/1.14.0 2024-09-17 09:51:23 +02:00
Cryptobot
f2949aae63 New Crowdin updates (#3520)
New translations strings.properties

Chinese Simplified; Chinese Traditional; Filipino; German; Punjabi; Romanian; Russian; Slovenian; Turkish; Ukrainian; 

[ci skip]
2024-09-17 09:49:55 +02:00
Armin Schrenk
80e101456b adjust keychainManager to new API 2024-09-16 17:40:49 +02:00
Armin Schrenk
2f311c1dfe use final releases 2024-09-16 17:29:24 +02:00
Jan-Peter Klein
c5cfe4d1b3 removed unnecessary properties 2024-09-16 15:40:52 +02:00
Jan-Peter Klein
a09b55c81b triggered updatechecker in constructor 2024-09-16 15:39:14 +02:00
Jan-Peter Klein
32f266c721 removed unused vbox in controller 2024-09-16 15:26:45 +02:00
Jan-Peter Klein
3adffad087 removed ALT+F4 shortcut, it is already registered by default 2024-09-16 14:55:51 +02:00
Jan-Peter Klein
84e3cf0762 removed green border and fixed margin for windows 2024-09-16 14:48:06 +02:00
Jan-Peter Klein
1292936904 clean up 2024-09-13 11:49:05 +02:00
Jan-Peter Klein
7a913c89c9 condensed vault list implemented 2024-09-12 11:36:14 +02:00
Jan-Peter Klein
4c4816bdab fixed missing import 2024-09-11 15:10:23 +02:00
Jan-Peter Klein
f9bfd5d1b1 set stage owner 2024-09-11 15:06:27 +02:00
Jan-Peter Klein
00e1e3654e implemented remove cert dialog 2024-09-10 18:01:09 +02:00
Tobias Hagemann
8aaee3710a Update README.md 2024-09-10 11:57:03 +02:00
Jan-Peter Klein
1946fc6c0e filter hidden directories 2024-09-04 15:05:24 +02:00
Jan-Peter Klein
8fb95b67d9 changes mentioned in pull #3270 2024-09-04 14:28:42 +02:00
Jan-Peter Klein
e6890e8fa5 Merge branch 'develop' of https://github.com/siard-y/cryptomator into feature/gdrive-presets 2024-09-04 13:56:47 +02:00
Jan-Peter Klein
7cdb2025dc improved supporter cert ui with cert stemp, donate/sponsors link buttons and remove button with dialog 2024-09-04 13:23:36 +02:00
Armin Schrenk
414d81dc06 Update mac-dmg.yml
Switch to macOS-12 due to errors
2024-08-20 18:17:08 +02:00
Armin Schrenk
b450ab028d Update mac-dmg.yml
macos-11 is no more
2024-08-20 17:42:32 +02:00
Armin Schrenk
5a51e53603 Merge branch 'develop' into release/1.14.0 2024-08-20 11:18:22 +02:00
Armin Schrenk
d65beb632d Fixes #3519 2024-08-20 11:10:26 +02:00
Armin Schrenk
2b03477d31 prepare 1.14.0 2024-08-19 16:36:31 +02:00
Cryptobot
f25e23da82 New Crowdin updates (#3463)
New translations strings.properties

Arabic; Chinese Simplified; Chinese Traditional; Dutch; Filipino; French; German; Greek; Italian; Japanese; Korean; Persian; Polish; Portuguese; Portuguese, Brazilian; Punjabi; Russian; Slovak; Spanish; Swedish; Turkish; Urdu (Pakistan); 

[ci skip]
2024-08-19 16:33:41 +02:00
dependabot[bot]
82368e2632 Bump the java-production-dependencies group across 1 directory with 9 updates (#3516) 2024-08-19 14:29:15 +00:00
dependabot[bot]
9057090b56 Bump the maven-build-plugins group across 1 directory with 3 updates (#3513) 2024-08-19 14:18:32 +00:00
dependabot[bot]
357937e0bf Bump the java-test-dependencies group across 1 directory with 2 updates (#3514) 2024-08-19 14:17:07 +00:00
Armin Schrenk
f84a2396eb ignore integrations-api 2.0.0-alpha1 2024-08-19 10:42:58 +02:00
dependabot[bot]
193dcad6e8 Bump the javafx group with 5 updates (#3498)
* Bump javafx from 22.0.1 to 22.0.2
* update build scripts to updated jfx version

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Armin Schrenk <armin.schrenk@skymatic.de>
2024-08-19 10:34:14 +02:00
Armin Schrenk
257f4427b8 catch all methods of adding a vault for #2880 2024-08-19 10:27:13 +02:00
Armin Schrenk
4778ba0770 add autostart for deb artifact 2024-08-16 15:56:58 +02:00
Armin Schrenk
77b908199e Mitigates #2880 (#3512) 2024-08-16 12:59:38 +02:00
Armin Schrenk
d448c42f87 Feature: JDK 22.0.2+9 for release artifacts (#3510)
* update jdks for release artifacts to jdk 22.02+9
2024-08-14 16:40:44 +02:00
Armin Schrenk
b9403222ba add java.compiler module to build scripts
references 93d0fd41a6 and https://github.com/google/dagger/issues/4321
2024-08-13 16:28:09 +02:00
Armin Schrenk
93d0fd41a6 Update cryptofs to 2.7.0-beta1
Closes #2058
2024-08-13 11:59:23 +02:00
Armin Schrenk
067bd4752c prevent leaking of NVD API key into logs 2024-08-09 11:30:16 +02:00
Armin Schrenk
fb4f9fc68f Update integrations-win and -linux for quickAccess service providers 2024-08-09 11:05:02 +02:00
Armin Schrenk
a20667a156 Merge pull request #3494 from cryptomator/feature/quick-access
Feature: Add unlocked vaults to an quick access area
2024-08-07 16:42:53 +02:00
Armin Schrenk
4d47544244 cleanup 2024-08-07 16:32:30 +02:00
Armin Schrenk
d59f149f7c Load quick access service lazy 2024-08-06 15:17:18 +02:00
Armin Schrenk
028f6e7a02 clean up 2024-08-06 15:08:29 +02:00
Armin Schrenk
71e4f98665 hard code default quickaccess service 2024-08-06 12:26:26 +02:00
Tobias Hagemann
d60ced52fe added codesigning jdk files in build.sh for local macos builds to match mac-dmg.yml ci build 2024-07-30 21:14:32 +02:00
Tobias Hagemann
45c7d2b071 added provisioning profile to mac build process with updated entitlements 2024-07-30 18:48:54 +02:00
Ralph Plawetzki
7a789d2eed Fixes #3501 (PR #3502) 2024-07-30 12:27:16 +02:00
Armin Schrenk
cc1e542146 clean up 2024-07-23 16:50:27 +02:00
Armin Schrenk
e4e84d46b6 hide option, if no quick access service is present 2024-07-23 16:50:15 +02:00
Armin Schrenk
61fc53bf9c rename internal method 2024-07-23 16:39:34 +02:00
Tobias Hagemann
f8386a5a99 Update README.md 2024-07-18 15:09:05 +02:00
Armin Schrenk
da7e89fc72 fix windows build script 2024-07-17 16:35:33 +02:00
Armin Schrenk
6b57a0ad9c add translation 2024-07-17 11:34:29 +02:00
Armin Schrenk
f1eb997804 make quickAccessService togglable & selectable in UI 2024-07-16 17:25:47 +02:00
Armin Schrenk
2fe5180721 cleanup 2024-07-16 17:19:52 +02:00
Jan-Peter Klein
958c22bed8 Merge branch 'feature/redesign-mainwindow' in feature/notificationbar 2024-07-16 14:52:50 +02:00
Jan-Peter Klein
6ff640648f Merge branch 'develop' into feature/redesign-mainwindow 2024-07-16 14:48:50 +02:00
Jan-Peter Klein
7b132adfe2 adjust add vault button position for improved UI 2024-07-16 14:31:11 +02:00
Armin Schrenk
2fa88490bd update to integrations-api 1.4.0-beta2
* differ between using quick access and actual impl
* rename properties
2024-07-16 13:36:37 +02:00
Jan-Peter Klein
5f5b5a5426 set preferences window min width and height 2024-07-09 13:48:45 +02:00
Jan-Peter Klein
cb054bb4f5 fix update available check in preference tab selection 2024-07-09 13:46:41 +02:00
Jan-Peter Klein
3497144034 introduced NotificationBar control 2024-07-08 16:42:49 +02:00
dependabot[bot]
b4f9bc62ca Bump the maven-build-plugins group across 1 directory with 3 updates (#3484) 2024-07-08 07:52:56 +00:00
Tobias Hagemann
34bface2d7 Merge pull request #3481 from purejava/fix-#3480 2024-07-07 16:40:40 +02:00
Ralph Plawetzki
70e52b1a31 Fix typo
Closes #3480
2024-07-07 15:41:28 +02:00
Tobias Hagemann
59a2398c4c Update README.md 2024-07-04 11:49:37 +02:00
Jan-Peter Klein
edbeea5502 fixed update check on start and bindings 2024-07-02 15:31:28 +02:00
Jan-Peter Klein
a88e08147d changed background color of pref button 2024-07-02 15:08:07 +02:00
Jan-Peter Klein
8ff06a3efd implement hideable notification bars 2024-07-02 12:43:27 +02:00
Jan-Peter Klein
902c66cf1e removed vbox id and renamed style 2024-07-01 18:19:30 +02:00
Jan-Peter Klein
d58307d1d6 optimize vaultList height update to avoid repeated bindings 2024-07-01 13:09:53 +02:00
Jan-Peter Klein
3e6204a657 remove showMinimizeButton setting 2024-07-01 12:32:50 +02:00
Jan-Peter Klein
e677a0beaa removed MainWindowTitleController and ResizeController and the corresponding fxml 2024-07-01 12:25:48 +02:00
Armin Schrenk
e5003c1783 use quick access service in unlock/lock 2024-06-27 17:47:05 +02:00
Jan-Peter Klein
d379ada100 addded debug, update and support notification bar 2024-06-26 15:13:28 +02:00
Jan-Peter Klein
cb7d0ade47 fixed some SonarCloud mentioned issues 2024-06-26 13:43:21 +02:00
Armin Schrenk
d6fd012f71 fix av whitelisting step in win-exe workflow 2024-06-26 13:28:37 +02:00
Armin Schrenk
d9d8c84230 adjust formatting of metainfo file 2024-06-26 13:23:38 +02:00
Jan-Peter Klein
4d9dc4312d Merge branch 'develop' into feature/redesign-mainwindow 2024-06-26 13:07:53 +02:00
Julian Raufelder
1ad2cc3ee5 Update to JDK 22 2024-06-26 11:57:17 +02:00
Armin Schrenk
2eac09f6be [ci skip] Merge branch 'main' into develop 2024-06-26 10:29:47 +02:00
Armin Schrenk
4114ea6163 Merge branch 'release/1.13.0' 2024-06-26 10:29:15 +02:00
Armin Schrenk
82da9f7a88 finalize release 2024-06-26 10:27:29 +02:00
Armin Schrenk
aa08046c4d Merge branch 'develop' into release/1.13.0 2024-06-21 15:18:39 +02:00
Armin Schrenk
b6d7f63470 [ci skip] also sign binaries from CraC project (dammn zulu jdk) 2024-06-21 15:10:47 +02:00
Armin Schrenk
624d18238c Merge branch 'develop' into release/1.13.0 2024-06-21 14:38:38 +02:00
Armin Schrenk
3bfe2b7a9e fix Windows build 2024-06-21 14:38:17 +02:00
Armin Schrenk
ba79cd0f8c prepare 1.13.0 2024-06-21 11:55:54 +02:00
Armin Schrenk
be63ea1104 Closes #3439 2024-06-21 11:51:49 +02:00
Cryptobot
a3ad2a5677 New Crowdin updates (#3355)
New translations strings.properties

Arabic; Bashkir; Belarusian; Bengali; Bosnian; Bulgarian; Catalan; Chinese Simplified; Chinese Traditional; Chinese Traditional, Hong Kong; Croatian; Czech; Danish; Dutch; Filipino; Finnish; French; Galician; German; Greek; Hebrew; Hindi; Hungarian; Indonesian; Italian; Japanese; Korean; Latvian; Macedonian; Marathi; 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]
2024-06-21 11:29:09 +02:00
dependabot[bot]
26e5ceea01 Bump the maven-build-plugins group with 2 updates (#3459) 2024-06-21 08:20:05 +00:00
dependabot[bot]
83f1c4ea41 Bump org.mockito:mockito-core in the java-test-dependencies group (#3427) 2024-06-21 08:19:43 +00:00
Armin Schrenk
8d78e1432a Merge pull request #3454 from cryptomator/feature/jfx22
Feature: Update to jfx22
2024-06-20 14:43:15 +02:00
mindmonk
d2ec5a5646 Merge pull request #3457 from cryptomator/feature/dokany-info-dialog
Feature: Migrate volume type Dokany to Default one and Display Info Dialog
2024-06-17 12:20:39 +02:00
Jan-Peter Klein
6bb0328799 removed dialog in naming 2024-06-14 14:20:18 +02:00
Jan-Peter Klein
8a8617b480 renamed method and code refactored 2024-06-14 11:07:21 +02:00
Jan-Peter Klein
92fad41b96 Merge branch 'develop' into feature/redesign-mainwindow 2024-06-13 12:49:59 +02:00
Jan-Peter Klein
7484744038 minor text change 2024-06-13 12:06:38 +02:00
Jan-Peter Klein
0bbc4ecae5 refactored code and new method handleDokanySupportEndAndShowDialog 2024-06-13 12:06:18 +02:00
Jan-Peter Klein
9fcb166047 close dialog by click on 'Open Preferences' 2024-06-13 12:04:34 +02:00
Jan-Peter Klein
1ac017e3ab changed dialog prefix 2024-06-13 11:51:01 +02:00
Jan-Peter Klein
1ba401b8e6 changed wording of button and description
primary color for icon
2024-06-12 12:02:40 +02:00
Armin Schrenk
07303b58f7 Merge branch 'develop' into feature/jfx22 2024-06-12 11:16:41 +02:00
Armin Schrenk
32a463768c Merge pull request #3456 from purejava/fix-#3453
Workaround for malformed javafx POM. Closes #3453.
2024-06-12 11:14:52 +02:00
Armin Schrenk
2307950e3b add javafx.platform property workaround to other build/ci scripts 2024-06-12 10:58:49 +02:00
Ralph Plawetzki
8108128c22 Temporary work around for JavaFX upstream bug
Occurs with Maven 3.9.7, fixed with Gluon JavaFX 23-ea+20, that contains a fixed parent POM
See https://mail.openjdk.org/pipermail/openjfx-dev/2024-May/047279.html
2024-06-11 19:59:18 +02:00
Jan-Peter Klein
58fe6da7a8 Merge branch 'develop' into feature/dokany-info-dialog 2024-06-11 15:25:23 +02:00
Jan-Peter Klein
92bf73297a add dokany info dialog 2024-06-11 14:43:56 +02:00
Armin Schrenk
0bf8fb39dd Update to javafx 22.0.1 2024-06-07 15:39:42 +02:00
Armin Schrenk
0dc9a3a834 align local build scripts 2024-06-07 14:56:54 +02:00
Armin Schrenk
91d6264b9f ignore downloaded artifact 2024-06-06 12:10:03 +02:00
Armin Schrenk
d2599ea525 closes #2656 2024-06-06 12:07:18 +02:00
dependabot[bot]
7180af9bc7 Bump the java-production-dependencies group across 1 directory with 9 updates (#3446) 2024-06-03 10:30:50 +00:00
Armin Schrenk
dc993dc57c fixes #3440 (PR in #3447) 2024-06-03 12:29:54 +02:00
dependabot[bot]
464c74ab6c Bump the maven-build-plugins group across 1 directory with 2 updates (#3431) 2024-06-03 09:39:36 +00:00
Jan-Peter Klein
e038348dca changed mainWindow StageStyle to UNDECORATED
removed main_window_title area
moved main_window_resize functions to MainWindowController
put add vault button under the vault list and wrapped both in a ScrollPane
bound vault list height properties to amount of entries and width to scroll pane width
add listener to scroll down after adding a vault
moved preferences button under vault list
new style classes for new elements
changed wording
2024-05-28 21:56:03 +02:00
Armin Schrenk
8c7dd8c74f Merge pull request #3435 from cryptomator/feature/jdk22
Feature: JDK22
2024-05-21 16:58:57 +02:00
Armin Schrenk
69bcf6fac6 do not forget to update debian files
(dammn you unflexible launchpad!)
2024-05-21 12:51:01 +02:00
Armin Schrenk
7c243dd434 pin cryptolib version due removed jdk.crypto.ec package 2024-05-16 17:51:04 +02:00
Armin Schrenk
357a0b9c31 closes #3376 2024-05-14 17:58:21 +02:00
Armin Schrenk
d69d11b82f update dependencies requiring JDK 22 2024-05-14 17:25:56 +02:00
mindmonk
863e9bbcb3 Merge pull request #3362 from cryptomator/feature/update-checker-refactoring
Feature: Expansion of Preferences Update Tab with UI Elements and Refactoring of UpdateChecker
2024-05-10 16:31:26 +02:00
Jan-Peter Klein
1c47012033 undo getter changes 2024-05-10 15:57:04 +02:00
Jan-Peter Klein
cd99eaa323 updateAvailable ObservableValue to BooleanBinding 2024-05-10 15:51:41 +02:00
Jan-Peter Klein
dda2afda92 refactored ObservableValues to BooleanBindings and code cleanup 2024-05-10 15:45:17 +02:00
Jan-Peter Klein
5519eefcfa cr related changes 2024-05-10 14:55:50 +02:00
Jan-Peter Klein
a81352800d removed twoWeeksAgo var 2024-05-08 11:38:23 +02:00
Jan-Peter Klein
6fec16e498 removed unused ui function 2024-05-08 10:57:42 +02:00
Jan-Peter Klein
42f31204a3 removed lastUpdateReminder setting 2024-05-08 09:41:58 +02:00
Jan-Peter Klein
7ab64cfe46 removed lastUpdateReminder setting 2024-05-08 09:05:26 +02:00
Jan-Peter Klein
1581a10c04 removed unused label id 2024-05-08 08:30:06 +02:00
Jan-Peter Klein
249becc25d removed unused instance var 2024-05-08 08:28:53 +02:00
Jan-Peter Klein
da8e84f39d removed unnecessary HBox 2024-05-07 13:27:52 +02:00
Jan-Peter Klein
9ad2d223c3 changed BooleanBinding updateAvailable to ObservableValue<Boolean> 2024-05-07 13:23:53 +02:00
Jan-Peter Klein
3bf1e659ef changed checkFailed text wording 2024-05-07 12:41:39 +02:00
Jan-Peter Klein
e79257e5ea changed checkFailed property to ObservableValue 2024-05-06 13:46:49 +02:00
Armin Schrenk
dac517a6fb update project ot jdk 22
Note: dependency bumps regarding jdk22 compatiblilty are missing!
2024-05-02 16:59:45 +02:00
mindmonk
1ab808f1b0 Merge pull request #3414 from MSevenR/feature/double-click-unlocked-vault
Double-click on an Unlocked Vault
2024-05-02 09:31:56 +02:00
Jan-Peter Klein
08f81b7df4 registered module in SettingsJsonTest 2024-04-29 11:12:14 +02:00
Jan-Peter Klein
b16f32ca83 introduced new dependency
removed latestVersion from Settings
changed SettingsJson from Date to Instant
new UpdateChecker Property checkFailed
optimized naming
changed wordning
refactoring
2024-04-29 10:34:17 +02:00
MSevenR
d6ed88b544 Double-click on an Unlocked Vault
Double-click on an Unlocked Vault in the List to Reveal It
2024-04-26 01:44:45 -05:00
Jan-Peter Klein
ae697d7b73 refactor isUpdateSuccessfulAndCurrent to instance variable 2024-04-25 10:54:00 +02:00
Jan-Peter Klein
ff3306cc17 removed blank line, unused instance variable, import and Logger
refactored DateTimeFormatter into an instance variable
2024-04-24 15:03:49 +02:00
Armin Schrenk
9ae2f4e0f6 add timezone id to timestamp in settings 2024-04-23 16:12:59 +02:00
Armin Schrenk
4230afcbac refactored timeDiff-message-method to updatePref controller 2024-04-23 16:12:36 +02:00
Armin Schrenk
7fc6ab05a4 use Instant also in UpdateChecker 2024-04-23 15:19:45 +02:00
Armin Schrenk
060f6bfc97 change storage of timestamps in model to Instant 2024-04-23 15:18:37 +02:00
Jan-Peter Klein
919dac6caa refactoring 2024-04-22 16:35:20 +02:00
Jan-Peter Klein
98bcf63b2c remove lastUpdateCheck from Settings; add lastUpdateReminder and lastSuccessfulUpdateCheck
implement updateTimeDifferenceMessage
reorder UI elements
refactor code for clarity and maintainability
2024-04-17 11:40:58 +02:00
Tobias Hagemann
0585262952 Merge pull request #3395 from purejava/flathub-colour-banners
Add coloured banners for app in Flathub store
2024-04-13 16:33:31 +02:00
Ralph Plawetzki
a33dc3980e Use colours from Cryptomator CD manual 2024-04-13 15:36:52 +02:00
Ralph Plawetzki
caa5e77386 Swap the light and dark colors, it's calmer for the eye 2024-04-13 08:48:20 +02:00
Ralph Plawetzki
c037920e79 Add coloured banners for app in Flathub store 2024-04-12 17:45:38 +02:00
Armin Schrenk
3cdd352d39 Update check-jdk-updates.yml
Use latest jdk version for jdk check
2024-04-10 12:27:05 +02:00
dependabot[bot]
8ae80e2932 Bump the maven-build-plugins group with 2 updates (#3391) 2024-04-09 08:34:03 +00:00
dependabot[bot]
2ffa1ee236 Bump the github-actions group with 2 updates (#3387) 2024-04-09 08:16:34 +00:00
Tobias Hagemann
2bf5b57823 Update README.md
[ci skip]
2024-04-05 12:33:38 +02:00
Jan-Peter Klein
853ea69180 updated log error message as suggested by coderabbit 2024-04-04 13:30:47 +02:00
Jan-Peter Klein
43d0dd99ec adjusted code as per PR suggestions 2024-04-04 12:37:56 +02:00
Armin Schrenk
b40e6db701 Merge branch 'main' into develop 2024-03-27 13:02:32 +01:00
Armin Schrenk
387eb420eb Merge branch 'hotfix/1.12.4' 2024-03-27 12:58:36 +01:00
Armin Schrenk
7785bb8820 finalize 1.12.4 2024-03-27 12:57:55 +01:00
Armin Schrenk
de4fa8c7b0 use latest WiX version
fixes CVE-2024-29187 and CVE-2024-29188
2024-03-27 12:55:13 +01:00
Armin Schrenk
17f519e01c prepare 1.12.4 2024-03-27 12:53:49 +01:00
dependabot[bot]
6c50023074 Bump the maven-build-plugins group with 2 updates (#3380) 2024-03-25 09:09:23 +00:00
Sebastian Stenzel
0009940e1e adjusted after dependency update 2024-03-14 12:09:10 +01:00
Armin Schrenk
f2a50b59b5 well, that should be the last reference to dokany 2024-03-12 09:56:30 +01:00
Armin Schrenk
ed03606981 One should also remove the actual dependency 2024-03-12 09:51:11 +01:00
Armin Schrenk
4a1eaf25c7 Closes #3361, Fixes #3351 2024-03-12 09:46:37 +01:00
dependabot[bot]
f5e445a610 Bump the java-production-dependencies group with 3 updates (#3365) 2024-03-12 07:57:00 +00:00
Jan-Peter Klein
6a3a256c0b Merge branch 'develop' into feature/update-checker-refactoring 2024-03-08 10:28:16 +01:00
Jan-Peter Klein
1ed77ebcc0 code cleanup 2024-03-08 10:27:35 +01:00
Jan-Peter Klein
db224e9e5c added latestVersion and lastUpdateCheck to settings and integrated with update checker 2024-03-08 09:58:59 +01:00
dependabot[bot]
c719982ef3 Bump the github-actions group with 1 update (#3354) 2024-03-05 17:24:28 +00:00
dependabot[bot]
f783f5d5ec Bump the java-test-dependencies group with 1 update (#3358) 2024-03-05 17:21:45 +00:00
dependabot[bot]
dd4f87b54c Bump the java-production-dependencies group with 4 updates (#3359) 2024-03-05 17:21:09 +00:00
Jan-Peter Klein
b3789700e1 add upToDateLabel and fix update indicator issue 2024-03-05 12:56:38 +01:00
Jan-Peter Klein
b39834f4eb Merge branch 'develop' into feature/update-checker-refactoring 2024-03-05 10:18:32 +01:00
Jan-Peter Klein
8064d75102 removed state label and reorganized ui elements 2024-03-05 10:15:11 +01:00
Jan-Peter Klein
4064b61cd7 refactored updateChecker by incorporating state management and date tracking 2024-02-29 09:29:26 +01:00
Armin Schrenk
ef3affece3 [ci skip] fix wrong PR description in flathub workflow 2024-02-28 13:42:37 +01:00
Armin Schrenk
414465371b [ci skip] refactor win-exe workflow
* only publish, if msi and exe succeed
* make stable release jobs dependent of publish
2024-02-28 13:19:54 +01:00
Armin Schrenk
feed72a729 [ci skip] fix flathub workflow 2024-02-27 22:52:56 +01:00
Armin Schrenk
bca20a7a66 [ci skip] seperate av whitelisting into own workflow to be able to upload assets on failure 2024-02-27 18:55:14 +01:00
Armin Schrenk
a38377baaa [ci skip] Merge branch 'main' into develop 2024-02-27 12:53:30 +01:00
Armin Schrenk
61a45fc738 Merge branch 'release/1.12.3' 2024-02-27 12:52:00 +01:00
Armin Schrenk
3a65b5551f adjust release check to changed metainfo file
references fcb940e29c
2024-02-27 12:48:36 +01:00
Armin Schrenk
94ed5c18b8 damnn merge from develop to release 2024-02-27 12:41:06 +01:00
Armin Schrenk
a559483d86 finalize 1.12.3 2024-02-27 12:38:52 +01:00
Armin Schrenk
3acdef1dd0 Merge branch 'develop' into release/1.12.3 2024-02-27 12:37:13 +01:00
Armin Schrenk
def6f8ab95 [ci skip] clean up 2024-02-27 12:35:55 +01:00
Armin Schrenk
11ba1f3ddc revert 1ab73be1f4 and 2d968eac8c 2024-02-27 12:32:37 +01:00
Cryptobot
3228f2cf5f New Crowdin updates (#3343)
New translations strings.properties

Chinese Simplified; Dutch; French; Japanese; Portuguese; Russian; Slovak; Swedish; 

[ci skip]
2024-02-27 10:23:56 +01:00
Armin Schrenk
9c4f7ad79d [ci skip] remove unknown env/style combination from appstream metadata 2024-02-26 17:41:18 +01:00
Armin Schrenk
3bd57d162b [ci skip] update appstream metadata 2024-02-26 17:37:04 +01:00
dependabot[bot]
5ea73a5a8d Bump the java-production-dependencies group with 1 update (#3347) 2024-02-26 09:50:42 +00:00
Armin Schrenk
38670838c7 [ci skip] Drop yq usage 2024-02-26 10:15:25 +01:00
Armin Schrenk
3e0b84dbce [ci skip] fix pr body description & reduce log noise 2024-02-23 17:39:38 +01:00
Armin Schrenk
2302db6206 [ci skip] fix create pr command in flathub job 2024-02-23 17:27:48 +01:00
Armin Schrenk
a94bf99660 [ci skip] automatically set up tracking branch on push 2024-02-23 17:13:11 +01:00
Armin Schrenk
0c5ce353b1 [ci skip] use github.actor 2024-02-23 17:05:26 +01:00
Armin Schrenk
b3ce777a42 [ci skip] configure git in flathub job 2024-02-23 16:29:18 +01:00
Armin Schrenk
3085df3397 [ci skip] further fixes:
* remove yq after update
* set token for git
2024-02-23 16:14:21 +01:00
Armin Schrenk
fb740b605f add missing quote char [ci skip] 2024-02-23 15:57:06 +01:00
Armin Schrenk
6a74d9f3b2 use same varaible in get-version job 2024-02-23 15:53:22 +01:00
Armin Schrenk
1c7dffb63f Add ci job to create flathub PR on release [ci skip] 2024-02-23 15:44:48 +01:00
Jan-Peter Klein
a213f073b1 enhance screen selection by adding primary fallback 2024-02-23 10:51:23 +01:00
Armin Schrenk
1ab73be1f4 fixes #3344 2024-02-22 16:11:54 +01:00
Armin Schrenk
8412871090 apply proper formatting and state to error dialog 2024-02-22 12:23:43 +01:00
Armin Schrenk
fa63f3ca67 Reset develop to SNAPSHOT version 2024-02-22 12:21:00 +01:00
Armin Schrenk
dbc0f52481 fix not-uploading artifacts on release 2024-02-21 22:04:35 +01:00
Armin Schrenk
b8cd1caeac also upload asc file as artifact for mac build 2024-02-21 13:09:14 +01:00
Armin Schrenk
43c25b6d97 fix ci
references 84732337ca
2024-02-21 12:53:01 +01:00
Armin Schrenk
e44bc09074 Merge branch 'develop' into release/1.12.3 2024-02-21 12:20:36 +01:00
Cryptobot
7b02f78ef5 New Crowdin updates (#3342)
New translations strings.properties

Arabic; Bashkir; Belarusian; Bengali; Bosnian; Bulgarian; Catalan; Chinese Simplified; Chinese Traditional; Chinese Traditional, Hong Kong; Croatian; Czech; Danish; Dutch; Filipino; Finnish; French; Galician; German; Greek; Hebrew; Hindi; Hungarian; Indonesian; Italian; Japanese; Korean; Latvian; Macedonian; Marathi; 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]
2024-02-21 12:13:24 +01:00
Armin Schrenk
f7e8a4d1e6 prepare 1.12.3 2024-02-20 18:13:01 +01:00
Armin Schrenk
664375d692 fix wrong method name 2024-02-20 18:06:55 +01:00
Armin Schrenk
2d968eac8c Merge pull request #3336 from cryptomator/feature/3272-vaultid-as-mountpoint
Feature: For FUSE-Ts default mountpoint use vault id as mountpoint
2024-02-20 17:34:09 +01:00
Armin Schrenk
542d2fcfe1 only create winget PR for stable versions [ci skip] 2024-02-19 16:42:42 +01:00
mindmonk
144e929896 Merge pull request #3335 from cryptomator/feature/center-unlock-dialog-on-mainstage
Center Unlock Success Dialog on Main Application Window
2024-02-19 15:05:28 +01:00
Armin Schrenk
803748f78d update code-sign-action [ci skip] 2024-02-19 14:46:58 +01:00
Armin Schrenk
3410e7243a Update minimal required macOS version for dmg
due to javafx update in 7d281e2878
2024-02-19 13:02:05 +01:00
Armin Schrenk
84732337ca removed GTK-2 support
due to javafx update in 7d281e2878
2024-02-19 12:17:11 +01:00
dependabot[bot]
c527808710 Bump the java-production-dependencies group with 4 updates (#3340) 2024-02-19 09:35:25 +00:00
Armin Schrenk
99c89dbf39 fix possible null comparsion 2024-02-19 10:22:22 +01:00
Jan-Peter Klein
829b64cd3d dialog centers on main app screen if mainWindow is hidden 2024-02-19 08:55:16 +01:00
Jan-Peter Klein
f4007267fb simplified the code and removed the function 2024-02-16 17:31:20 +01:00
Armin Schrenk
c82a0bfaf3 cleanup 2024-02-16 17:09:05 +01:00
Armin Schrenk
251ad65344 Merge pull request #3327 from cryptomator/feature/3233-load-presets-background
Feature: Load LocationPresets in background and show indicator in UI
2024-02-16 16:21:01 +01:00
Jan-Peter Klein
155ba4607b introduced functionality to center the unlock screen within the main application window 2024-02-16 15:24:52 +01:00
Armin Schrenk
62f6865d3e cleanup created directories after mount
fails silently
2024-02-14 10:30:51 +01:00
Armin Schrenk
ffb3290248 Merge branch 'develop' into feature/3272-vaultid-as-mountpoint 2024-02-14 10:29:30 +01:00
Armin Schrenk
a013ae3d91 [ci skip] change mountPointDir for macOS-Dev-run profile
aligns production build
2024-02-14 10:29:14 +01:00
Armin Schrenk
19a954e677 use correct mountProvider 2024-02-14 10:05:56 +01:00
Armin Schrenk
f262980acc closes #3272 2024-02-13 16:37:46 +01:00
Armin Schrenk
3b3aa18c92 fixes #3233
this time with gc prevention of a binding
2024-02-13 00:55:07 +01:00
Armin Schrenk
c7b8bc89c2 also don't bother upload to av scan, if not published 2024-02-12 13:18:17 +01:00
Armin Schrenk
5fc981abd3 prevent automatic overwrite of already released files 2024-02-12 13:16:45 +01:00
Armin Schrenk
36ec1a5ebc update windows update url [ci skip] 2024-02-09 18:37:19 +01:00
Armin Schrenk
be4aad4168 set default value for Windows debug flag 2024-02-09 17:03:22 +01:00
Armin Schrenk
fcb940e29c update release section of appstream metainfo file [ci skip] 2024-02-09 14:52:10 +01:00
Armin Schrenk
4f3ca2a6c4 fix appimage build script [ci skip] 2024-02-09 12:56:33 +01:00
Armin Schrenk
27cd34bee0 Merge branch 'main' into develop [ci skip] 2024-02-09 12:53:16 +01:00
Armin Schrenk
c07e51be51 Merge branch 'release/1.12.2' 2024-02-09 12:51:57 +01:00
Armin Schrenk
0421879b39 finalize 1.12.2 2024-02-09 12:51:19 +01:00
Armin Schrenk
2d627717a0 prepare 1.12.2 2024-02-09 10:59:33 +01:00
Armin Schrenk
dc0e88a694 fixes #3319 2024-02-09 10:55:27 +01:00
Armin Schrenk
a5e3630375 also specify version for winget release [ci skip] 2024-02-08 17:47:50 +01:00
Armin Schrenk
17335e8f70 shorten workflow name [ci skip] 2024-02-08 17:39:38 +01:00
Armin Schrenk
42dd2fba48 github cli needs special token in CI env [ci skip] 2024-02-08 17:37:50 +01:00
Armin Schrenk
e1cca6427c Add ci job for releasing to winget 2024-02-08 17:34:02 +01:00
Armin Schrenk
42d3dbaa23 always use latest version of winfsp-uninstaller 2024-02-08 17:10:40 +01:00
Armin Schrenk
185d67c492 Merge branch 'main' into develop [ci skip] 2024-02-07 11:43:59 +01:00
Armin Schrenk
a8af3c8b40 Merge branch 'release/1.12.1' 2024-02-07 11:42:58 +01:00
Armin Schrenk
038a7fac62 finalize 1.12.1 2024-02-07 11:42:37 +01:00
Armin Schrenk
48408fa40d prepare 1.12.1 2024-02-07 11:37:44 +01:00
Armin Schrenk
18a417667e Fixes #3315 2024-02-07 11:33:45 +01:00
JaniruTEC
aab07b13e3 Changed version specifier for dependency-check
See: https://github.com/cryptomator/cryptofs/pull/202#discussion_r1453615249
2024-02-06 22:28:16 +01:00
Armin Schrenk
869e40e351 use latest coffeelibs-jdk release 2024-02-06 15:34:09 +01:00
Armin Schrenk
bf91e3f15c Merge branch 'main' into develop [ci skip] 2024-02-06 14:29:19 +01:00
Siard
d85c6c8f41 Create separate files for GoogleDrive presets providers. cryptomator/2921
- Change imports accordingly in module-info.java
2024-01-03 16:42:46 +01:00
Siard
17057e8f8d Add Google Drive presets improvement. cryptomator/2921
- The code now defaults to searching through '~/Library/CloudStorage/GoogleDrive-*/*' before using the fallback options.
2024-01-03 16:41:11 +01:00
248 changed files with 12266 additions and 3060 deletions

View File

@@ -3,7 +3,7 @@
## Did you find a bug?
- Ensure you're running the latest version of Cryptomator.
- Ensure the bug is related to the desktop version of Cryptomator. Bugs concerning the Cryptomator iOS and Android app can be reported on the [Cryptomator for iOS issues list](https://github.com/cryptomator/cryptomator-ios/issues) and [Cryptomator for Android issues list](https://github.com/cryptomator/cryptomator-android/issues) respectively.
- Ensure the bug is related to the desktop version of Cryptomator. Bugs concerning the Cryptomator iOS and Android app can be reported on the [Cryptomator for iOS issues list](https://github.com/cryptomator/ios/issues) and [Cryptomator for Android issues list](https://github.com/cryptomator/android/issues) respectively.
- Ensure the bug was not [already reported](https://github.com/cryptomator/cryptomator/issues). You can also check out our [FAQ](https://community.cryptomator.org/c/kb/faq).
- If you're unable to find an open issue addressing the problem, [submit a new one](https://github.com/cryptomator/cryptomator/issues/new/choose).
@@ -16,6 +16,10 @@
- Suggest your change by [submitting a new issue](https://github.com/cryptomator/cryptomator/issues/new/choose) and start writing code.
## Do you intend to add a new translation or change an existing one?
Translations are not managed directly in this repository. Instead, we use [Crowdin](https://translate.cryptomator.org/), which automatically synchronizes translations with this repository. If you want to help us with translations, please visit our translation project on Crowdin.
## Code of Conduct
Help us keep Cryptomator open and inclusive. Please read and follow our [Code of Conduct](https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md).

View File

@@ -1,7 +1,14 @@
name: Bug Report
description: Create a report to help us improve
labels: ["type:bug"]
type: "Bug"
body:
- type: input
id: summary
attributes:
label: Summary
placeholder: Please summarize your problem.
validations:
required: true
- type: checkboxes
id: terms
attributes:
@@ -11,13 +18,6 @@ body:
required: true
- label: I agree to follow this project's [Code of Conduct](https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md)
required: true
- type: input
id: summary
attributes:
label: Summary
placeholder: Please summarize your problem.
validations:
required: true
- type: textarea
id: software-versions
attributes:
@@ -97,4 +97,4 @@ body:
id: further-info
attributes:
label: Anything else?
description: Links? References? Screenshots? Configurations? Any data that might be necessary to reproduce the issue?
description: Links? References? Screenshots? Configurations? Any data that might be necessary to reproduce the issue?

View File

@@ -1,7 +1,14 @@
name: Feature Request
description: Suggest an idea for this project
labels: ["type:feature-request"]
type: "Feature"
body:
- type: input
id: summary
attributes:
label: Summary
placeholder: Please summarize your feature request.
validations:
required: true
- type: checkboxes
id: terms
attributes:
@@ -11,13 +18,6 @@ body:
required: true
- label: I agree to follow this project's [Code of Conduct](https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md)
required: true
- type: input
id: summary
attributes:
label: Summary
placeholder: Please summarize your feature request.
validations:
required: true
- type: textarea
id: motivation
attributes:

View File

@@ -7,6 +7,13 @@ updates:
day: "monday"
time: "06:00"
timezone: "Etc/UTC"
ignore:
- dependency-name: "org.cryptomator:integrations-api"
versions: ["2.0.0-alpha1"]
- dependency-name: "jakarta.inject:jakarta.inject-api"
versions: ["2.0.1.MR"]
- dependency-name: "org.openjfx:*"
update-types: ["version-update:semver-major"]
groups:
java-test-dependencies:
patterns:

View File

@@ -10,8 +10,8 @@ on:
required: false
env:
JAVA_DIST: 'zulu'
JAVA_VERSION: '21.0.2+13'
JAVA_DIST: 'temurin'
JAVA_VERSION: '23.0.2'
jobs:
get-version:
@@ -29,12 +29,12 @@ jobs:
include:
- os: ubuntu-latest
appimage-suffix: x86_64
openjfx-url: 'https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_linux-x64_bin-jmods.zip'
openjfx-sha: '7baed11ca56d5fee85995fa6612d4299f1e8b7337287228f7f12fd50407c56f8'
- os: [self-hosted, Linux, ARM64]
openjfx-url: 'https://download2.gluonhq.com/openjfx/23.0.2/openjfx-23.0.2_linux-x64_bin-jmods.zip'
openjfx-sha: '063baebc6922e4a89c94b9dfb7a4f53e59e8d6fec400d4e670b31bc2ab324dec'
- os: ubuntu-24.04-arm
appimage-suffix: aarch64
openjfx-url: 'https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_linux-aarch64_bin-jmods.zip'
openjfx-sha: '871e7b9d7af16aef2e55c1b7830d0e0b2503b13dd8641374ba7e55ecb81d2ef9'
openjfx-url: 'https://download2.gluonhq.com/openjfx/23.0.2/openjfx-23.0.2_linux-aarch64_bin-jmods.zip'
openjfx-sha: '9bbedaeae1590b69e2b22237bda310936df33e344dbc243bea2e86acaab3a0d8'
steps:
- uses: actions/checkout@v4
- name: Setup Java
@@ -68,7 +68,7 @@ jobs:
- name: Set version
run : mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }}
- name: Run maven
run: mvn -B clean package -Plinux -DskipTests
run: mvn -B clean package -Plinux -DskipTests -Djavafx.platform=linux
- name: Patch target dir
run: |
cp LICENSE.txt target
@@ -80,17 +80,12 @@ jobs:
--verbose
--output runtime
--module-path "${JAVA_HOME}/jmods:openjfx-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.security.auth,jdk.accessibility,jdk.management.jfr,jdk.net
--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.security.auth,jdk.accessibility,jdk.management.jfr,jdk.net,java.compiler
--strip-native-commands
--no-header-files
--no-man-pages
--strip-debug
--compress zip-0
- name: Prepare additional launcher
run: envsubst '${SEMVER_STR} ${REVISION_NUM}' < dist/linux/launcher-gtk2.properties > launcher-gtk2.properties
env:
SEMVER_STR: ${{ needs.get-version.outputs.semVerStr }}
REVISION_NUM: ${{ needs.get-version.outputs.revNum }}
- name: Run jpackage
run: >
${JAVA_HOME}/bin/jpackage
@@ -103,7 +98,7 @@ jobs:
--dest appdir
--name Cryptomator
--vendor "Skymatic GmbH"
--copyright "(C) 2016 - 2024 Skymatic GmbH"
--copyright "(C) 2016 - 2025 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,org.purejava.appindicator"
@@ -121,7 +116,7 @@ jobs:
--java-options "-Dcryptomator.showTrayIcon=true"
--java-options "-Dcryptomator.integrationsLinux.trayIconsDir=\"@{appdir}/usr/share/icons/hicolor/symbolic/apps\""
--java-options "-Dcryptomator.buildNumber=\"appimage-${{ needs.get-version.outputs.revNum }}\""
--add-launcher Cryptomator-gtk2=launcher-gtk2.properties
--java-options "-Dcryptomator.networking.truststore.p12Path=\"/etc/cryptomator/certs.p12\""
--resource-dir dist/linux/resources
- name: Patch Cryptomator.AppDir
run: |
@@ -138,13 +133,13 @@ jobs:
cp dist/linux/common/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/usr/share/applications/org.cryptomator.Cryptomator.desktop
cp dist/linux/common/application-vnd.cryptomator.vault.xml Cryptomator.AppDir/usr/share/mime/packages/application-vnd.cryptomator.vault.xml
ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/org.cryptomator.Cryptomator.svg
ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/Cryptomator.svg
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 usr/share/applications/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/org.cryptomator.Cryptomator.desktop
ln -s org.cryptomator.Cryptomator.metainfo.xml Cryptomator.AppDir/usr/share/metainfo/org.cryptomator.Cryptomator.appdata.xml
ln -s bin/cryptomator.sh Cryptomator.AppDir/AppRun
- name: Download AppImageKit
run: |
curl -L https://github.com/AppImage/AppImageKit/releases/download/13/appimagetool-${{ matrix.appimage-suffix }}.AppImage -o appimagetool.AppImage
curl -L https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-${{ matrix.appimage-suffix }}.AppImage -o appimagetool.AppImage
chmod +x appimagetool.AppImage
./appimagetool.AppImage --appimage-extract
- name: Prepare GPG-Agent for signing with key 615D449FE6E6A235
@@ -158,7 +153,7 @@ jobs:
run: >
./squashfs-root/AppRun Cryptomator.AppDir cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.appimage-suffix }}.AppImage
-u 'gh-releases-zsync|cryptomator|cryptomator|latest|cryptomator-*-${{ matrix.appimage-suffix }}.AppImage.zsync'
--sign --sign-key=615D449FE6E6A235 --sign-args="--batch --pinentry-mode loopback"
--sign --sign-key=615D449FE6E6A235
- name: Create detached GPG signatures
run: |
gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator-*.AppImage
@@ -173,12 +168,12 @@ jobs:
cryptomator-*.asc
if-no-files-found: error
- name: Publish AppImage on GitHub Releases
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published'
uses: softprops/action-gh-release@v2
with:
fail_on_unmatched_files: true
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
files: |
cryptomator-*.AppImage
cryptomator-*.zsync
cryptomator-*.asc
cryptomator-*.asc

88
.github/workflows/av-whitelist.yml vendored Normal file
View File

@@ -0,0 +1,88 @@
name: AntiVirus Whitelisting
on:
workflow_call:
inputs:
url:
description: "Url to the file to upload"
required: true
type: string
workflow_dispatch:
inputs:
url:
description: "Url to the file to upload"
required: true
type: string
avast:
description: "Upload to Avast"
required: false
type: boolean
default: false
kaspersky:
description: "Upload to Kaspersky"
required: false
type: boolean
default: false
jobs:
download-file:
name: Downloads the file into the VM
runs-on: ubuntu-latest
outputs:
fileName: ${{ steps.extractName.outputs.fileName}}
steps:
- name: Extract file name
id: extractName
run: |
url="${{ inputs.url }}"
echo "fileName=${url##*/}" >> $GITHUB_OUTPUT
- name: Download file
run: curl --remote-name ${{ inputs.url }} -L -o ${{steps.extractName.outputs.fileName}}
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ steps.extractName.outputs.fileName }}
path: ${{ steps.extractName.outputs.fileName }}
if-no-files-found: error
allowlist-kaspersky:
name: Anti Virus Allowlisting Kaspersky
runs-on: ubuntu-latest
needs: download-file
if: github.event_name == 'workflow_call' || inputs.kaspersky
steps:
- name: Download artifact
uses: actions/download-artifact@v4
with:
name: ${{ needs.download-file.outputs.fileName }}
path: upload
- name: Upload to Kaspersky
uses: SamKirkland/FTP-Deploy-Action@v4.3.5
with:
protocol: ftps
server: allowlist.kaspersky-labs.com
port: 990
username: ${{ secrets.ALLOWLIST_KASPERSKY_USERNAME }}
password: ${{ secrets.ALLOWLIST_KASPERSKY_PASSWORD }}
local-dir: ./upload/
allowlist-avast:
name: Anti Virus Allowlisting Avast
runs-on: ubuntu-latest
needs: download-file
if: github.event_name == 'workflow_call' || inputs.avast
steps:
- name: Download artifact
uses: actions/download-artifact@v4
with:
name: ${{ needs.download-file.outputs.fileName }}
path: upload
- name: Upload to Avast
uses: wlixcc/SFTP-Deploy-Action@v1.2.5
with:
server: whitelisting.avast.com
port: 22
username: ${{ secrets.ALLOWLIST_AVAST_USERNAME }}
password: ${{ secrets.ALLOWLIST_AVAST_PASSWORD }}
ssh_private_key: ''
sftp_only: true
local_path: './upload/*'
remote_path: '/data'

View File

@@ -6,8 +6,8 @@ on:
types: [labeled]
env:
JAVA_DIST: 'zulu'
JAVA_VERSION: 21
JAVA_DIST: 'temurin'
JAVA_VERSION: 23
defaults:
run:
@@ -33,7 +33,7 @@ jobs:
- name: Build and Test
run: >
xvfb-run
mvn -B verify
mvn -B verify -Djavafx.platform=linux
jacoco:report
org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
-Pcoverage
@@ -45,7 +45,7 @@ jobs:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- name: Draft a release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v2
with:
draft: true
discussion_category_name: releases
@@ -53,10 +53,25 @@ jobs:
generate_release_notes: true
body: |-
:construction: Work in Progress
### What's New 🎉
⏳ Please be patient, the builds are still [running](https://github.com/cryptomator/cryptomator/actions). New versions of Cryptomator can be found here in a few moments. ⏳
### Bugfixes 🐛
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).
### Other Changes 📎
---
<!-- Don't forget to include the 💾 SHA-256 checksums of release artifacts: -->
TODO FULL CHANGELOG
📜 List of closed issues is available [here](TODO)
---
⏳ Please be patient, the builds are still [running](https://github.com/cryptomator/cryptomator/actions). New versions of Cryptomator can be found here in a few moments. ⏳
<!-- Don't forget to include the
💾 SHA-256 checksums of release artifacts:
```
```
-->
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).

View File

@@ -1,56 +1,75 @@
name: Checks JDK version for minor updates
name: Check JDK for non-major updates
on:
schedule:
- cron: '0 0 1 * *' # run once a month at the first day of month
workflow_dispatch:
env:
JDK_VERSION: '21.0.1+12'
JDK_VENDOR: zulu
JDK_VERSION: '23.0.1+11'
JDK_VENDOR: temurin
RUNTIME_VERSION_HELPER: >
public class Test {
public static void main(String[] args) {
System.out.println(Runtime.version());
}
}
jobs:
jdk-current:
name: Check out current version
runs-on: ubuntu-latest
outputs:
jdk-date: ${{ steps.get-data.outputs.jdk-date}}
steps:
- uses: actions/setup-java@v4
with:
java-version: ${{ env.JDK_VERSION }}
distribution: ${{ env.JDK_VENDOR }}
check-latest: false
- name: Read JAVA_VERSION_DATE and store in env variable
id: get-data
run: |
date=$(cat ${JAVA_HOME}/release | grep "JAVA_VERSION_DATE=\"" | awk -F'=' '{print $2}' | tr -d '"')
echo "jdk-date=${date}" >> "$GITHUB_OUTPUT"
jdk-latest:
check-version:
name: Checkout latest jdk version
runs-on: ubuntu-latest
outputs:
jdk-date: ${{ steps.get-data.outputs.jdk-date}}
jdk-version: ${{ steps.get-data.outputs.jdk-version}}
env:
JDK_MAJOR_VERSION: 'toBeFilled'
steps:
- uses: actions/setup-java@v4
- name: Determine current major version
run: echo 'JDK_MAJOR_VERSION=${{ env.JDK_VERSION }}'.substring(0,20) >> "$env:GITHUB_ENV"
shell: pwsh
- name: Checkout latest JDK ${{ env.JDK_MAJOR_VERSION }}
uses: actions/setup-java@v4
with:
java-version: 21
java-version: ${{ env.JDK_MAJOR_VERSION}}
distribution: ${{ env.JDK_VENDOR }}
check-latest: true
- name: Read JAVA_VERSION_DATE and store in env variable
id: get-data
- name: Determine if update is available
id: determine
shell: pwsh
run: |
date=$(cat ${JAVA_HOME}/release | grep "JAVA_VERSION_DATE=\"" | awk -F'=' '{print $2}' | tr -d '"')
echo "jdk-date=${date}" >> "$GITHUB_OUTPUT"
version=$(cat ${JAVA_HOME}/release | grep "JAVA_RUNTIME_VERSION=\"" | awk -F'=' '{print $2}' | tr -d '"')
echo "jdk-version=${version}" >> "$GITHUB_OUTPUT"
notify:
name: Notifies for jdk update
runs-on: ubuntu-latest
needs: [jdk-current, jdk-latest]
if: ${{ needs.jdk-latest.outputs.jdk-date }} > ${{ needs.jdk-current.outputs.jdk-date }}
steps:
- name: Slack Notification
$latestVersion = 0,0,0,0 #INTERIM, UPDATE, PATCH and BUILD
$currentVersion = 0,0,0,0
# Get the latest JDK runtime version
"${env:RUNTIME_VERSION_HELPER}" | Set-Content -Path "GetRuntimeVersion.java"
$latestVersionString = & java GetRuntimeVersion.java
$runtimeVersionAndBuild = $latestVersionString.Split('+')
if($runtimeVersionAndBuild.Length -eq 2) {
$latestVersion[3]=$runtimeVersionAndBuild[1];
}
$tmp=$runtimeVersionAndBuild[0].Split('.')
for($i=0;$i -lt $latestVersion.Length; $i++) {
$latestVersion[$i]=$tmp[$i+1];
}
# Get the current JDK version
$runtimeVersionAndBuild = '${{ env.JDK_VERSION}}'.Split('+')
if($runtimeVersionAndBuild.Length -eq 2) {
$currentVersion[3]=$runtimeVersionAndBuild[1];
}
$tmp=$runtimeVersionAndBuild[0].Split('.')
for($i=0;$i -lt $currentVersion.Length; $i++) {
$currentVersion[$i]=$tmp[$i+1];
}
# compare
for($i=0; $i -lt $currentVersion.Length ; $i++) {
if($latestVersion[$i] -gt $currentVersion[$i]){
echo 'UPDATE_AVAILABLE=true' >> "$env:GITHUB_OUTPUT"
echo "LATEST_JDK_VERSION='${latestVersionString}'" >> "$env:GITHUB_OUTPUT"
return 0;
}
}
- name: Notify
if: steps.determine.outputs.UPDATE_AVAILABLE == 'true'
uses: rtCamp/action-slack-notify@v2
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
@@ -59,6 +78,6 @@ jobs:
SLACK_ICON_EMOJI: ':bot:'
SLACK_CHANNEL: 'cryptomator-desktop'
SLACK_TITLE: "JDK update available"
SLACK_MESSAGE: "Cryptomator-CI JDK can be upgraded to ${{ needs.jdk-latest.outputs.jdk-version }}. See https://github.com/cryptomator/cryptomator/wiki/How-to-update-the-build-JDK for instructions."
SLACK_MESSAGE: "Cryptomator-CI JDK can be upgraded to ${{ steps.determine.outputs.LATEST_JDK_VERSION }}. Check the Nextcloud collective for instructions."
SLACK_FOOTER: false
MSG_MINIMAL: true
MSG_MINIMAL: true

View File

@@ -16,19 +16,19 @@ on:
type: boolean
env:
JAVA_DIST: 'zulu'
JAVA_VERSION: '21.0.2+13'
COFFEELIBS_JDK: 21
COFFEELIBS_JDK_VERSION: '21.0.2+13-0ppa1'
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_linux-x64_bin-jmods.zip'
OPENJFX_JMODS_AMD64_HASH: '7baed11ca56d5fee85995fa6612d4299f1e8b7337287228f7f12fd50407c56f8'
OPENJFX_JMODS_AARCH64: 'https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_linux-aarch64_bin-jmods.zip'
OPENJFX_JMODS_AARCH64_HASH: '871e7b9d7af16aef2e55c1b7830d0e0b2503b13dd8641374ba7e55ecb81d2ef9'
JAVA_DIST: 'temurin'
JAVA_VERSION: '23.0.2+7'
COFFEELIBS_JDK: 23
COFFEELIBS_JDK_VERSION: '23.0.2+7-0ppa1'
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/23.0.2/openjfx-23.0.2_linux-x64_bin-jmods.zip'
OPENJFX_JMODS_AMD64_HASH: '063baebc6922e4a89c94b9dfb7a4f53e59e8d6fec400d4e670b31bc2ab324dec'
OPENJFX_JMODS_AARCH64: 'https://download2.gluonhq.com/openjfx/23.0.2/openjfx-23.0.2_linux-aarch64_bin-jmods.zip'
OPENJFX_JMODS_AARCH64_HASH: '9bbedaeae1590b69e2b22237bda310936df33e344dbc243bea2e86acaab3a0d8'
jobs:
build:
name: Build Debian Package
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- id: versions
@@ -44,7 +44,7 @@ jobs:
run: |
sudo add-apt-repository ppa:coffeelibs/openjdk
sudo apt-get update
sudo apt-get install debhelper devscripts dput coffeelibs-jdk-${{ env.COFFEELIBS_JDK }}=${{ env.COFFEELIBS_JDK_VERSION }} libgtk2.0-0
sudo apt-get install debhelper devscripts dput coffeelibs-jdk-${{ env.COFFEELIBS_JDK }}=${{ env.COFFEELIBS_JDK_VERSION }}
- name: Setup Java
uses: actions/setup-java@v4
with:
@@ -53,7 +53,7 @@ jobs:
check-latest: true
cache: 'maven'
- name: Run maven
run: mvn -B clean package -Plinux -DskipTests
run: mvn -B clean package -Plinux -Djavafx.platform=linux -DskipTests
- name: Download OpenJFX jmods
id: download-jmods
run: |
@@ -142,10 +142,9 @@ jobs:
- name: Publish on PPA
if: inputs.dput
run: dput ppa:sebastian-stenzel/cryptomator-beta cryptomator_*_source.changes
# If ref is a tag, also upload to GitHub Releases:
- name: Publish Debian package on GitHub Releases
if: startsWith(github.ref, 'refs/tags/')
if: startsWith(github.ref, 'refs/tags/') && inputs.dput
env:
GITHUB_TOKEN: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
run: |

View File

@@ -7,11 +7,12 @@ on:
jobs:
check-dependencies:
uses: skymatic/workflows/.github/workflows/run-dependency-check.yml@main
uses: skymatic/workflows/.github/workflows/run-dependency-check.yml@v1
with:
runner-os: 'ubuntu-latest'
java-distribution: 'temurin'
java-version: 21
java-version: 23
check-command: 'mvn -B validate -Pdependency-check -Djavafx.platform=linux'
secrets:
nvd-api-key: ${{ secrets.NVD_API_KEY }}
slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}

88
.github/workflows/flathub.yml vendored Normal file
View File

@@ -0,0 +1,88 @@
name: Create PR for flathub
on:
release:
types: [published]
workflow_dispatch:
inputs:
tag:
description: 'Release tag'
required: true
jobs:
get-version:
uses: ./.github/workflows/get-version.yml
with:
version: ${{ inputs.tag }}
tarball:
name: Determines tarball url and compute checksum
runs-on: ubuntu-latest
needs: [get-version]
if: github.event_name == 'workflow_dispatch' || needs.get-version.outputs.versionType == 'stable'
outputs:
url: ${{ steps.url.outputs.url}}
sha512: ${{ steps.sha512.outputs.sha512}}
steps:
- name: Determine tarball url
id: url
run: |
URL="";
if [[ -n "${{ inputs.tag }}" ]]; then
URL="https://github.com/cryptomator/cryptomator/archive/refs/tags/${{ inputs.tag }}.tar.gz"
else
URL="https://github.com/cryptomator/cryptomator/archive/refs/tags/${{ github.event.release.tag_name }}.tar.gz"
fi
echo "url=${URL}" >> "$GITHUB_OUTPUT"
- name: Download source tarball and compute checksum
id: sha512
run: |
curl --silent --fail-with-body -L -H "Accept: application/vnd.github+json" ${{ steps.url.outputs.url }} --output cryptomator.tar.gz
TARBALL_SHA512=$(sha512sum cryptomator.tar.gz | cut -d ' ' -f1)
echo "sha512=${TARBALL_SHA512}" >> "$GITHUB_OUTPUT"
flathub:
name: Create PR for flathub
runs-on: ubuntu-latest
needs: [tarball, get-version]
env:
FLATHUB_PR_URL: tbd
steps:
- uses: actions/checkout@v4
with:
repository: 'flathub/org.cryptomator.Cryptomator'
token: ${{ secrets.CRYPTOBOT_WINGET_TOKEN }}
- name: Checkout release branch
run: |
git checkout -b release/${{ needs.get-version.outputs.semVerStr }}
- name: Update build file
run: |
sed -i -e 's/VERSION: [0-9]\+\.[0-9]\+\.[0-9]\+.*/VERSION: ${{ needs.get-version.outputs.semVerStr }}/g' org.cryptomator.Cryptomator.yaml
sed -i -e 's/sha512: [0-9A-Za-z_\+-]\{128\} #CRYPTOMATOR/sha512: ${{ needs.tarball.outputs.sha512 }} #CRYPTOMATOR/g' org.cryptomator.Cryptomator.yaml
sed -i -e 's;url: https://github.com/cryptomator/cryptomator/archive/refs/tags/[^[:blank:]]\+;url: ${{ needs.tarball.outputs.url }};g' org.cryptomator.Cryptomator.yaml
- name: Commit and push
run: |
git config user.name "${{ github.actor }}"
git config user.email "${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com"
git config push.autoSetupRemote true
git stage .
git commit -m "Prepare release ${{needs.get-version.outputs.semVerStr}}"
git push
- name: Create pull request
run: |
printf "> [!IMPORTANT]\n> Todos:\n> - [ ] Update maven dependencies\n> - [ ] Check for JDK update\n> - [ ] Check for JFX update" > pr_body.md
PR_URL=$(gh pr create --title "Release ${{ needs.get-version.outputs.semVerStr }}" --body-file pr_body.md)
echo "FLATHUB_PR_URL=$PR_URL" >> "$GITHUB_ENV"
env:
GH_TOKEN: ${{ secrets.CRYPTOBOT_WINGET_TOKEN }}
- name: Slack Notification
uses: rtCamp/action-slack-notify@v2
if: github.event_name == 'release'
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_USERNAME: 'Cryptobot'
SLACK_ICON: false
SLACK_ICON_EMOJI: ':bot:'
SLACK_CHANNEL: 'cryptomator-desktop'
SLACK_TITLE: "Flathub release PR created for ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} created."
SLACK_MESSAGE: "See <${{ env.FLATHUB_PR_URL }}|PR> on how to proceed.>."
SLACK_FOOTER: false
MSG_MINIMAL: true

View File

@@ -22,8 +22,8 @@ on:
value: ${{ jobs.determine-version.outputs.type }}
env:
JAVA_DIST: 'zulu'
JAVA_VERSION: 21
JAVA_DIST: 'temurin'
JAVA_VERSION: 23
jobs:
determine-version:
@@ -50,7 +50,7 @@ jobs:
if [[ $GITHUB_REF =~ refs/tags/[0-9]+\.[0-9]+\.[0-9]+.* ]]; then
SEM_VER_STR=${GITHUB_REF##*/}
elif [[ "${{ inputs.version }}" =~ [0-9]+\.[0-9]+\.[0-9]+.* ]]; then
SEM_VER_STR="${{ github.event.inputs.version }}"
SEM_VER_STR="${{ inputs.version }}"
else
SEM_VER_STR=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout`
fi
@@ -71,6 +71,6 @@ jobs:
echo "revNum=${REVCOUNT}" >> $GITHUB_OUTPUT
echo "type=${TYPE}" >> $GITHUB_OUTPUT
- name: Validate Version
uses: skymatic/semver-validation-action@v2
uses: skymatic/semver-validation-action@v3
with:
version: ${{ steps.versions.outputs.semVerStr }}
version: ${{ steps.versions.outputs.semVerStr }}

264
.github/workflows/mac-dmg-x64.yml vendored Normal file
View File

@@ -0,0 +1,264 @@
name: Build macOS .dmg for x64
#######################################
# STOP! DO NOT EDIT THIS FILE!
#
# It is a copy of mac-dmg.yml with tiny adjustements (mainly lines 42 to 47)
# It was made necessary, since Github does not offer free macos intel runners for macos 15 and above.
# This workflow can only be triggered by a release.
#
#######################################
on:
release:
types: [published]
env:
JAVA_DIST: 'temurin'
JAVA_VERSION: '23.0.2+7'
jobs:
get-version:
uses: ./.github/workflows/get-version.yml
with:
version: ${{ inputs.version }}
build-arm:
name: Build Cryptomator.app for ${{ matrix.output-suffix }}
runs-on: ${{ matrix.os }}
needs: [get-version]
strategy:
fail-fast: false
matrix:
include:
- os: macos-15-large
architecture: x64
output-suffix: x64
fuse-lib: macFUSE
openjfx-url: 'https://download2.gluonhq.com/openjfx/23.0.2/openjfx-23.0.2_osx-x64_bin-jmods.zip'
openjfx-sha: '5e6c65c065eea22430c0eab36f37a5985eb8ad99e19e8772262021740d338f68'
steps:
- uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: ${{ env.JAVA_DIST }}
java-version: ${{ env.JAVA_VERSION }}
architecture: ${{ matrix.architecture }}
check-latest: true
cache: 'maven'
- name: Download OpenJFX jmods
id: download-jmods
run: |
curl -L ${{ matrix.openjfx-url }} -o openjfx-jmods.zip
echo "${{ matrix.openjfx-sha }} *openjfx-jmods.zip" | shasum -a256 --check
mkdir -p openjfx-jmods/
unzip -jo openjfx-jmods.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d openjfx-jmods
- name: Ensure major jfx version in pom and in jmods is the same
run: |
JMOD_VERSION=$(jmod describe openjfx-jmods/javafx.base.jmod | head -1)
JMOD_VERSION=${JMOD_VERSION#*@}
JMOD_VERSION=${JMOD_VERSION%%.*}
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}" ]; then
>&2 echo "Major JavaFX version in pom.xml (${POM_JFX_VERSION}) != jmod version (${JMOD_VERSION})"
exit 1
fi
- name: Set version
run : mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }}
- name: Run maven
run: mvn -B -Djavafx.platform=mac clean package -Pmac -DskipTests
- name: Patch target dir
run: |
cp LICENSE.txt target
cp target/cryptomator-*.jar target/mods
- name: Run jlink
#Remark: no compression is applied for improved build compression later (here dmg)
run: >
${JAVA_HOME}/bin/jlink
--verbose
--output runtime
--module-path "${JAVA_HOME}/jmods:openjfx-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.accessibility,jdk.management.jfr,java.compiler
--strip-native-commands
--no-header-files
--no-man-pages
--strip-debug
--compress zip-0
- name: Run jpackage
run: >
${JAVA_HOME}/bin/jpackage
--verbose
--type app-image
--runtime-image runtime
--input target/libs
--module-path target/mods
--module org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator
--dest appdir
--name Cryptomator
--vendor "Skymatic GmbH"
--copyright "(C) 2016 - 2025 Skymatic GmbH"
--app-version "${{ needs.get-version.outputs.semVerNum }}"
--java-options "--enable-preview"
--java-options "--enable-native-access=org.cryptomator.jfuse.mac"
--java-options "-Xss5m"
--java-options "-Xmx256m"
--java-options "-Dfile.encoding=\"utf-8\""
--java-options "-Djava.net.useSystemProxies=true"
--java-options "-Dapple.awt.enableTemplateImages=true"
--java-options "-Dsun.java2d.metal=true"
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
--java-options "-Dcryptomator.logDir=\"@{userhome}/Library/Logs/Cryptomator\""
--java-options "-Dcryptomator.pluginDir=\"@{userhome}/Library/Application Support/Cryptomator/Plugins\""
--java-options "-Dcryptomator.settingsPath=\"@{userhome}/Library/Application Support/Cryptomator/settings.json\""
--java-options "-Dcryptomator.p12Path=\"@{userhome}/Library/Application Support/Cryptomator/key.p12\""
--java-options "-Dcryptomator.ipcSocketPath=\"@{userhome}/Library/Application Support/Cryptomator/ipc.socket\""
--java-options "-Dcryptomator.integrationsMac.keychainServiceName=\"Cryptomator\""
--java-options "-Dcryptomator.mountPointsDir=\"@{userhome}/Library/Application Support/Cryptomator/mnt\""
--java-options "-Dcryptomator.showTrayIcon=true"
--java-options "-Dcryptomator.buildNumber=\"dmg-${{ needs.get-version.outputs.revNum }}\""
--mac-package-identifier org.cryptomator
--resource-dir dist/mac/resources
- name: Patch Cryptomator.app
run: |
mv appdir/Cryptomator.app Cryptomator.app
mv dist/mac/resources/Cryptomator-Vault.icns Cryptomator.app/Contents/Resources/
sed -i '' "s|###BUNDLE_SHORT_VERSION_STRING###|${VERSION_NO}|g" Cryptomator.app/Contents/Info.plist
sed -i '' "s|###BUNDLE_VERSION###|${REVISION_NO}|g" Cryptomator.app/Contents/Info.plist
echo -n "$PROVISIONING_PROFILE_BASE64" | base64 --decode --output Cryptomator.app/Contents/embedded.provisionprofile
env:
VERSION_NO: ${{ needs.get-version.outputs.semVerNum }}
REVISION_NO: ${{ needs.get-version.outputs.revNum }}
PROVISIONING_PROFILE_BASE64: ${{ secrets.MACOS_PROVISIONING_PROFILE_BASE64 }}
- name: Generate license for dmg
run: >
mvn -B -Djavafx.platform=mac license:add-third-party
-Dlicense.thirdPartyFilename=license.rtf
-Dlicense.outputDirectory=dist/mac/dmg/resources
-Dlicense.fileTemplate=dist/mac/dmg/resources/licenseTemplate.ftl
-Dlicense.includedScopes=compile
-Dlicense.excludedGroups=^org\.cryptomator
-Dlicense.failOnMissing=true
-Dlicense.licenseMergesUrl=file://${{ github.workspace }}/license/merges
- name: Install codesign certificate
run: |
# create variables
CERTIFICATE_PATH=$RUNNER_TEMP/codesign.p12
KEYCHAIN_PATH=$RUNNER_TEMP/codesign.keychain-db
# import certificate and provisioning profile from secrets
echo -n "$CODESIGN_P12_BASE64" | base64 --decode --output $CERTIFICATE_PATH
# create temporary keychain
security create-keychain -p "$CODESIGN_TMP_KEYCHAIN_PW" $KEYCHAIN_PATH
security set-keychain-settings -lut 900 $KEYCHAIN_PATH
security unlock-keychain -p "$CODESIGN_TMP_KEYCHAIN_PW" $KEYCHAIN_PATH
# import certificate to keychain
security import $CERTIFICATE_PATH -P "$CODESIGN_P12_PW" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
env:
CODESIGN_P12_BASE64: ${{ secrets.MACOS_CODESIGN_P12_BASE64 }}
CODESIGN_P12_PW: ${{ secrets.MACOS_CODESIGN_P12_PW }}
CODESIGN_TMP_KEYCHAIN_PW: ${{ secrets.MACOS_CODESIGN_TMP_KEYCHAIN_PW }}
- name: Codesign
run: |
echo "Codesigning jdk files..."
find Cryptomator.app/Contents/runtime/Contents/Home/lib/ -name '*.dylib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \;
find Cryptomator.app/Contents/runtime/Contents/Home/lib/ \( -name 'jspawnhelper' -o -name 'pauseengine' -o -name 'simengine' \) -exec codesign --force -o runtime -s ${CODESIGN_IDENTITY} {} \;
echo "Codesigning jar contents..."
find Cryptomator.app/Contents/runtime/Contents/MacOS -name '*.dylib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \;
for JAR_PATH in `find Cryptomator.app -name "*.jar"`; do
if [[ `unzip -l ${JAR_PATH} | grep '.dylib\|.jnilib'` ]]; then
JAR_FILENAME=$(basename ${JAR_PATH})
OUTPUT_PATH=${JAR_PATH%.*}
echo "Codesigning libs in ${JAR_FILENAME}..."
unzip -q ${JAR_PATH} -d ${OUTPUT_PATH}
find ${OUTPUT_PATH} -name '*.dylib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \;
find ${OUTPUT_PATH} -name '*.jnilib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \;
rm ${JAR_PATH}
pushd ${OUTPUT_PATH} > /dev/null
zip -qr ../${JAR_FILENAME} *
popd > /dev/null
rm -r ${OUTPUT_PATH}
fi
done
echo "Codesigning Cryptomator.app..."
sed -i '' "s|###APP_IDENTIFIER_PREFIX###|${TEAM_IDENTIFIER}.|g" dist/mac/Cryptomator.entitlements
sed -i '' "s|###TEAM_IDENTIFIER###|${TEAM_IDENTIFIER}|g" dist/mac/Cryptomator.entitlements
codesign --force --deep --entitlements dist/mac/Cryptomator.entitlements -o runtime -s ${CODESIGN_IDENTITY} Cryptomator.app
env:
CODESIGN_IDENTITY: ${{ secrets.MACOS_CODESIGN_IDENTITY }}
TEAM_IDENTIFIER: ${{ secrets.MACOS_TEAM_IDENTIFIER }}
- name: Prepare .dmg contents
run: |
mkdir dmg
mv Cryptomator.app dmg
cp dist/mac/dmg/resources/${{ matrix.fuse-lib }}.webloc dmg
ls -l dmg
- name: Install create-dmg
run: |
brew install create-dmg
create-dmg --help
- name: Create .dmg
run: >
create-dmg
--volname Cryptomator
--volicon "dist/mac/dmg/resources/Cryptomator-Volume.icns"
--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 "${{ 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
--icon ".VolumeIcon.icns" 512 758
Cryptomator-${VERSION_NO}-${{ matrix.output-suffix }}.dmg dmg
env:
VERSION_NO: ${{ needs.get-version.outputs.semVerNum }}
- name: Notarize .dmg
if: startsWith(github.ref, 'refs/tags/') || inputs.notarize
uses: cocoalibs/xcode-notarization-action@v1
with:
app-path: 'Cryptomator-*.dmg'
apple-id: ${{ secrets.MACOS_NOTARIZATION_APPLE_ID }}
password: ${{ secrets.MACOS_NOTARIZATION_PW }}
team-id: ${{ secrets.MACOS_NOTARIZATION_TEAM_ID }}
xcode-path: '/Applications/Xcode_16.app'
- name: Add possible alpha/beta tags to installer name
run: mv Cryptomator-*.dmg Cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.output-suffix }}.dmg
- name: Create detached GPG signature with key 615D449FE6E6A235
run: |
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
echo "${GPG_PASSPHRASE}" | gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a Cryptomator-*.dmg
env:
GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }}
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
- name: Clean up codesign certificate
if: ${{ always() }}
run: security delete-keychain $RUNNER_TEMP/codesign.keychain-db
continue-on-error: true
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: dmg-${{ matrix.output-suffix }}
path: |
Cryptomator-*.dmg
Cryptomator-*.asc
if-no-files-found: error
- name: Publish dmg on GitHub Releases
if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published'
uses: softprops/action-gh-release@v2
with:
fail_on_unmatched_files: true
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
files: |
Cryptomator-*.dmg
Cryptomator-*.asc

View File

@@ -1,4 +1,4 @@
name: Build macOS .dmg
name: Build macOS .dmg for arm64
on:
release:
@@ -15,8 +15,8 @@ on:
type: boolean
env:
JAVA_DIST: 'zulu'
JAVA_VERSION: '21.0.2+13'
JAVA_DIST: 'temurin'
JAVA_VERSION: '23.0.2+7'
jobs:
get-version:
@@ -32,20 +32,12 @@ jobs:
fail-fast: false
matrix:
include:
- os: macos-11
architecture: x64
output-suffix: x64
xcode-path: '/Applications/Xcode_13.2.1.app'
fuse-lib: macFUSE
openjfx-url: 'https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_osx-x64_bin-jmods.zip'
openjfx-sha: 'bd6abab20da73d5a968dcf2fd915d81b5fb919340e3bb84979ee9a888a829939'
- os: [self-hosted, macOS, ARM64]
- os: macos-15
architecture: aarch64
output-suffix: arm64
xcode-path: '/Applications/Xcode_13.2.1.app'
fuse-lib: FUSE-T
openjfx-url: 'https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_osx-aarch64_bin-jmods.zip'
openjfx-sha: '7afaa1c57a6cc3c384d636e597b9a5364693e2db4aaec0a6e63d2fa964400b58'
openjfx-url: 'https://download2.gluonhq.com/openjfx/23.0.2/openjfx-23.0.2_osx-aarch64_bin-jmods.zip'
openjfx-sha: 'c690cc642a3924cf56622951f478ba57aec9ce09063761f800c3319331bed3fc'
steps:
- uses: actions/checkout@v4
- name: Setup Java
@@ -79,7 +71,7 @@ jobs:
- name: Set version
run : mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }}
- name: Run maven
run: mvn -B clean package -Pmac -DskipTests
run: mvn -B -Djavafx.platform=mac clean package -Pmac -DskipTests
- name: Patch target dir
run: |
cp LICENSE.txt target
@@ -91,7 +83,7 @@ jobs:
--verbose
--output runtime
--module-path "${JAVA_HOME}/jmods:openjfx-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.accessibility,jdk.management.jfr,java.compiler
--strip-native-commands
--no-header-files
--no-man-pages
@@ -109,7 +101,7 @@ jobs:
--dest appdir
--name Cryptomator
--vendor "Skymatic GmbH"
--copyright "(C) 2016 - 2024 Skymatic GmbH"
--copyright "(C) 2016 - 2025 Skymatic GmbH"
--app-version "${{ needs.get-version.outputs.semVerNum }}"
--java-options "--enable-preview"
--java-options "--enable-native-access=org.cryptomator.jfuse.mac"
@@ -137,12 +129,14 @@ jobs:
mv dist/mac/resources/Cryptomator-Vault.icns Cryptomator.app/Contents/Resources/
sed -i '' "s|###BUNDLE_SHORT_VERSION_STRING###|${VERSION_NO}|g" Cryptomator.app/Contents/Info.plist
sed -i '' "s|###BUNDLE_VERSION###|${REVISION_NO}|g" Cryptomator.app/Contents/Info.plist
echo -n "$PROVISIONING_PROFILE_BASE64" | base64 --decode --output Cryptomator.app/Contents/embedded.provisionprofile
env:
VERSION_NO: ${{ needs.get-version.outputs.semVerNum }}
REVISION_NO: ${{ needs.get-version.outputs.revNum }}
PROVISIONING_PROFILE_BASE64: ${{ secrets.MACOS_PROVISIONING_PROFILE_BASE64 }}
- name: Generate license for dmg
run: >
mvn -B license:add-third-party
mvn -B -Djavafx.platform=mac license:add-third-party
-Dlicense.thirdPartyFilename=license.rtf
-Dlicense.outputDirectory=dist/mac/dmg/resources
-Dlicense.fileTemplate=dist/mac/dmg/resources/licenseTemplate.ftl
@@ -175,7 +169,7 @@ jobs:
run: |
echo "Codesigning jdk files..."
find Cryptomator.app/Contents/runtime/Contents/Home/lib/ -name '*.dylib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \;
find Cryptomator.app/Contents/runtime/Contents/Home/lib/ -name 'jspawnhelper' -exec codesign --force -o runtime -s ${CODESIGN_IDENTITY} {} \;
find Cryptomator.app/Contents/runtime/Contents/Home/lib/ \( -name 'jspawnhelper' -o -name 'pauseengine' -o -name 'simengine' \) -exec codesign --force -o runtime -s ${CODESIGN_IDENTITY} {} \;
echo "Codesigning jar contents..."
find Cryptomator.app/Contents/runtime/Contents/MacOS -name '*.dylib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \;
for JAR_PATH in `find Cryptomator.app -name "*.jar"`; do
@@ -194,9 +188,12 @@ jobs:
fi
done
echo "Codesigning Cryptomator.app..."
sed -i '' "s|###APP_IDENTIFIER_PREFIX###|${TEAM_IDENTIFIER}.|g" dist/mac/Cryptomator.entitlements
sed -i '' "s|###TEAM_IDENTIFIER###|${TEAM_IDENTIFIER}|g" dist/mac/Cryptomator.entitlements
codesign --force --deep --entitlements dist/mac/Cryptomator.entitlements -o runtime -s ${CODESIGN_IDENTITY} Cryptomator.app
env:
CODESIGN_IDENTITY: ${{ secrets.MACOS_CODESIGN_IDENTITY }}
TEAM_IDENTIFIER: ${{ secrets.MACOS_TEAM_IDENTIFIER }}
- name: Prepare .dmg contents
run: |
mkdir dmg
@@ -235,7 +232,7 @@ jobs:
apple-id: ${{ secrets.MACOS_NOTARIZATION_APPLE_ID }}
password: ${{ secrets.MACOS_NOTARIZATION_PW }}
team-id: ${{ secrets.MACOS_NOTARIZATION_TEAM_ID }}
xcode-path: ${{ matrix.xcode-path }}
xcode-path: '/Applications/Xcode_16.app'
- name: Add possible alpha/beta tags to installer name
run: mv Cryptomator-*.dmg Cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.output-suffix }}.dmg
- name: Create detached GPG signature with key 615D449FE6E6A235
@@ -253,11 +250,13 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: dmg-${{ matrix.output-suffix }}
path: Cryptomator-*.dmg
path: |
Cryptomator-*.dmg
Cryptomator-*.asc
if-no-files-found: error
- name: Publish dmg on GitHub Releases
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published'
uses: softprops/action-gh-release@v2
with:
fail_on_unmatched_files: true
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}

View File

@@ -19,7 +19,7 @@ jobs:
GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }}
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
- name: Publish asc on GitHub Releases
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v2
with:
fail_on_unmatched_files: true
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}

View File

@@ -4,8 +4,8 @@ on:
pull_request:
env:
JAVA_DIST: 'zulu'
JAVA_VERSION: 21
JAVA_DIST: 'temurin'
JAVA_VERSION: 23
defaults:
run:
@@ -24,4 +24,4 @@ jobs:
java-version: ${{ env.JAVA_VERSION }}
cache: 'maven'
- name: Build and Test
run: xvfb-run mvn -B clean install jacoco:report -Pcoverage
run: xvfb-run mvn -B clean install jacoco:report -Pcoverage -Djavafx.platform=linux

View File

@@ -11,8 +11,8 @@ defaults:
shell: bash
env:
JAVA_DIST: 'zulu'
JAVA_VERSION: 21
JAVA_DIST: 'temurin'
JAVA_VERSION: 23
jobs:
check-preconditions:
@@ -44,7 +44,7 @@ jobs:
fi
- name: Validate release in org.cryptomator.Cryptomator.metainfo.xml file
run: |
if ! grep -q "<release date=\".*\" version=\"${{ steps.validate-pom-version.outputs.semVerStr }}\"/>" dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml; then
if ! grep -q "<release date=\".*\" version=\"${{ steps.validate-pom-version.outputs.semVerStr }}\">" dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml; then
echo "Release not set in dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml"
exit 1
fi
@@ -60,6 +60,6 @@ jobs:
- name: Run org.owasp:dependency-check plugin
id: dependency-check
continue-on-error: true
run: mvn -B verify -Pdependency-check -DskipTests
run: mvn -B verify -Pdependency-check -DskipTests -Djavafx.platform=linux
env:
NVD_API_KEY: ${{ secrets.NVD_API_KEY }}

View File

@@ -11,15 +11,16 @@ on:
isDebug:
description: 'Build debug version with console output'
type: boolean
default: false
env:
JAVA_DIST: 'zulu'
JAVA_VERSION: '21.0.2+13'
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_windows-x64_bin-jmods.zip'
OPENJFX_JMODS_AMD64_HASH: 'daf8acae631c016c24cfe23f88469400274d3441dd890615a42dfb501f3eb94a'
JAVA_VERSION: '23.0.2+7'
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/23.0.1/openjfx-23.0.1_windows-x64_bin-jmods.zip'
OPENJFX_JMODS_AMD64_HASH: 'ee176dcee3bd78bde7910735bd67f67c792882f5b89626796ae06f7a1c0119d3'
WINFSP_MSI: 'https://github.com/winfsp/winfsp/releases/download/v2.0/winfsp-2.0.23075.msi'
WINFSP_UNINSTALLER: 'https://github.com/cryptomator/winfsp-uninstaller/releases/download/1.0.0/winfsp-uninstaller.exe'
WINFSP_UNINSTALLER: 'https://github.com/cryptomator/winfsp-uninstaller/releases/latest/download/winfsp-uninstaller.exe'
defaults:
run:
@@ -73,7 +74,7 @@ jobs:
- name: Set version
run : mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }}
- name: Run maven
run: mvn -B clean package -Pwin -DskipTests
run: mvn -B clean package -Pwin -DskipTests -Djavafx.platform=win
- name: Patch target dir
run: |
cp LICENSE.txt target
@@ -85,7 +86,7 @@ jobs:
--verbose
--output runtime
--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
--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.crypto.mscapi,jdk.unsupported,jdk.accessibility,jdk.management.jfr,java.compiler
--strip-native-commands
--no-header-files
--no-man-pages
@@ -106,10 +107,10 @@ jobs:
--dest appdir
--name Cryptomator
--vendor "Skymatic GmbH"
--copyright "(C) 2016 - 2024 Skymatic GmbH"
--copyright "(C) 2016 - 2025 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"
--java-options "--enable-native-access=org.cryptomator.jfuse.win,org.cryptomator.integrations.win"
--java-options "-Xss5m"
--java-options "-Xmx256m"
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
@@ -170,7 +171,7 @@ jobs:
& $env:JAVA_HOME\bin\jmod.exe extract --dir jpackage-jmod "${env:JAVA_HOME}\jmods\jdk.jpackage.jmod"
Get-ChildItem -Recurse -Path "jpackage-jmod" -File wixhelper.dll | Select-Object -Last 1 | Copy-Item -Destination "appdir"
- name: Codesign
uses: skymatic/code-sign-action@v2
uses: skymatic/code-sign-action@v3
with:
certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
password: ${{ secrets.WIN_CODESIGN_P12_PW }}
@@ -195,7 +196,7 @@ jobs:
}
- name: Generate license for MSI
run: >
mvn -B license:add-third-party
mvn -B license:add-third-party "-Djavafx.platform=win"
"-Dlicense.thirdPartyFilename=license.rtf"
"-Dlicense.outputDirectory=dist/win/resources"
"-Dlicense.fileTemplate=dist/win/resources/licenseTemplate.ftl"
@@ -214,12 +215,12 @@ jobs:
--dest installer
--name Cryptomator
--vendor "Skymatic GmbH"
--copyright "(C) 2016 - 2024 Skymatic GmbH"
--copyright "(C) 2016 - 2025 Skymatic GmbH"
--app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum}}"
--win-menu
--win-dir-chooser
--win-shortcut-prompt
--win-update-url "https:\\cryptomator.org"
--win-update-url "https:\\cryptomator.org\downloads"
--win-menu-group Cryptomator
--resource-dir dist/win/resources
--license-file dist/win/resources/license.rtf
@@ -228,7 +229,7 @@ jobs:
JP_WIXWIZARD_RESOURCES: ${{ github.workspace }}/dist/win/resources # requires abs path, used in resources/main.wxs
JP_WIXHELPER_DIR: ${{ github.workspace }}\appdir
- name: Codesign MSI
uses: skymatic/code-sign-action@v2
uses: skymatic/code-sign-action@v3
with:
certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
password: ${{ secrets.WIN_CODESIGN_P12_PW }}
@@ -253,15 +254,6 @@ jobs:
Cryptomator-*.msi
Cryptomator-*.asc
if-no-files-found: error
- name: Publish .msi on GitHub Releases
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v1
with:
fail_on_unmatched_files: true
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
files: |
*.msi
*.asc
build-exe:
name: Build .exe installer
@@ -284,7 +276,7 @@ jobs:
cache: 'maven'
- name: Generate license for exe
run: >
mvn -B license:add-third-party
mvn -B license:add-third-party "-Djavafx.platform=win"
"-Dlicense.thirdPartyFilename=license.rtf"
"-Dlicense.fileTemplate=dist/win/bundle/resources/licenseTemplate.ftl"
"-Dlicense.outputDirectory=dist/win/bundle/resources"
@@ -309,7 +301,7 @@ jobs:
-out dist/win/bundle/
-dBundleVersion="${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}"
-dBundleVendor="Skymatic GmbH"
-dBundleCopyright="(C) 2016 - 2024 Skymatic GmbH"
-dBundleCopyright="(C) 2016 - 2025 Skymatic GmbH"
-dAboutUrl="https://cryptomator.org"
-dHelpUrl="https://cryptomator.org/contact"
-dUpdateUrl="https://cryptomator.org/downloads/"
@@ -325,7 +317,7 @@ jobs:
-ib installer/unsigned/Cryptomator-Installer.exe
-o tmp/engine.exe
- name: Codesign burn engine
uses: skymatic/code-sign-action@v2
uses: skymatic/code-sign-action@v3
with:
certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
password: ${{ secrets.WIN_CODESIGN_P12_PW }}
@@ -339,7 +331,7 @@ jobs:
-ab tmp/engine.exe installer/unsigned/Cryptomator-Installer.exe
-o installer/Cryptomator-Installer.exe
- name: Codesign EXE
uses: skymatic/code-sign-action@v2
uses: skymatic/code-sign-action@v3
with:
certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
password: ${{ secrets.WIN_CODESIGN_P12_PW }}
@@ -364,52 +356,61 @@ jobs:
Cryptomator-*.exe
Cryptomator-*.asc
if-no-files-found: error
publish:
name: Publish installers to the github release
if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published'
runs-on: ubuntu-latest
needs: [build-msi, build-exe]
outputs:
download-url-msi: ${{ fromJSON(steps.publish.outputs.assets)[0].browser_download_url }}
download-url-exe: ${{ fromJSON(steps.publish.outputs.assets)[1].browser_download_url }}
steps:
- name: Download installers
uses: actions/download-artifact@v4
with:
merge-multiple: true
- name: Publish .msi on GitHub Releases
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v1
id: publish
uses: softprops/action-gh-release@v2
with:
fail_on_unmatched_files: true
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
# do not change ordering of filelist, required for correct job output
files: |
Cryptomator-*.exe
Cryptomator-*.asc
*.msi
*.exe
*.asc
allowlist:
name: Anti Virus Allowlisting
if: startsWith(github.ref, 'refs/tags/')
allowlist-msi:
uses: ./.github/workflows/av-whitelist.yml
needs: [publish]
with:
url: ${{ needs.publish.outputs.download-url-msi }}
secrets: inherit
allowlist-exe:
uses: ./.github/workflows/av-whitelist.yml
needs: [publish, allowlist-msi]
with:
url: ${{ needs.publish.outputs.download-url-exe }}
secrets: inherit
notify-winget:
name: Notify for winget-release
if: needs.get-version.outputs.versionType == 'stable'
needs: [publish, get-version]
runs-on: ubuntu-latest
needs: [build-msi, build-exe]
steps:
- name: Download .msi
uses: actions/download-artifact@v4
with:
name: msi
path: msi
- name: Download .exe
uses: actions/download-artifact@v4
with:
name: exe
path: exe
- name: Collect files
run: |
mkdir files
cp msi/*.msi files
cp exe/*.exe files
- name: Upload to Kaspersky
uses: SamKirkland/FTP-Deploy-Action@v4.3.4
with:
protocol: ftps
server: allowlist.kaspersky-labs.com
port: 990
username: ${{ secrets.ALLOWLIST_KASPERSKY_USERNAME }}
password: ${{ secrets.ALLOWLIST_KASPERSKY_PASSWORD }}
local-dir: files/
- name: Upload to Avast
uses: SamKirkland/FTP-Deploy-Action@v4.3.4
with:
protocol: ftp
server: whitelisting.avast.com
port: 21
username: ${{ secrets.ALLOWLIST_AVAST_USERNAME }}
password: ${{ secrets.ALLOWLIST_AVAST_PASSWORD }}
local-dir: files/
- name: Slack Notification
uses: rtCamp/action-slack-notify@v2
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_USERNAME: 'Cryptobot'
SLACK_ICON: false
SLACK_ICON_EMOJI: ':bot:'
SLACK_CHANNEL: 'cryptomator-desktop'
SLACK_TITLE: "MSI of ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} published."
SLACK_MESSAGE: "Ready to <https://github.com/${{ github.repository }}/actions/workflows/winget.yml| release to winget>."
SLACK_FOOTER: false
MSG_MINIMAL: true

27
.github/workflows/winget.yml vendored Normal file
View File

@@ -0,0 +1,27 @@
name: Publish MSI to winget-pkgs
on:
workflow_dispatch:
inputs:
tag:
description: 'Release tag'
required: true
jobs:
winget:
name: Publish winget package
runs-on: windows-latest
steps:
- name: Sync winget-pkgs fork
run: |
gh repo sync cryptomator/winget-pkgs -b master --force
env:
GH_TOKEN: ${{ secrets.CRYPTOBOT_WINGET_TOKEN }}
- name: Submit package
uses: vedantmgoyal2009/winget-releaser@main
with:
identifier: Cryptomator.Cryptomator
version: ${{ inputs.tag }}
release-tag: ${{ inputs.tag }}
installers-regex: '\.msi$'
token: ${{ secrets.CRYPTOBOT_WINGET_TOKEN }}

30
.idea/compiler.xml generated
View File

@@ -14,23 +14,22 @@
<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.48.1/dagger-compiler-2.48.1.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger/2.48.1/dagger-2.48.1.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-compiler/2.55/dagger-compiler-2.55.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger/2.55/dagger-2.55.jar" />
<entry name="$MAVEN_REPOSITORY$/jakarta/inject/jakarta.inject-api/2.0.1/jakarta.inject-api-2.0.1.jar" />
<entry name="$MAVEN_REPOSITORY$/javax/inject/javax.inject/1/javax.inject-1.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-producers/2.48.1/dagger-producers-2.48.1.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" />
<entry name="$MAVEN_REPOSITORY$/org/jspecify/jspecify/1.0.0/jspecify-1.0.0.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-spi/2.55/dagger-spi-2.55.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar" />
<entry name="$MAVEN_REPOSITORY$/org/checkerframework/checker-qual/3.12.0/checker-qual-3.12.0.jar" />
<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.48.1/dagger-spi-2.48.1.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/devtools/ksp/symbol-processing-api/1.9.0-1.0.12/symbol-processing-api-1.9.0-1.0.12.jar" />
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.0/kotlin-stdlib-1.9.0.jar" />
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-common/1.9.0/kotlin-stdlib-common-1.9.0.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/devtools/ksp/symbol-processing-api/2.0.21-1.0.28/symbol-processing-api-2.0.21-1.0.28.jar" />
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.0.21/kotlin-stdlib-2.0.21.jar" />
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/guava/failureaccess/1.0.2/failureaccess-1.0.2.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/guava/guava/33.0.0-jre/guava-33.0.0-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" />
<entry name="$MAVEN_REPOSITORY$/org/checkerframework/checker-qual/3.41.0/checker-qual-3.41.0.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/errorprone/error_prone_annotations/2.23.0/error_prone_annotations-2.23.0.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/j2objc/j2objc-annotations/2.8/j2objc-annotations-2.8.jar" />
<entry name="$MAVEN_REPOSITORY$/com/squareup/javapoet/1.13.0/javapoet-1.13.0.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" />
@@ -39,6 +38,7 @@
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.6.10/kotlin-stdlib-jdk7-1.6.10.jar" />
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-reflect/1.6.10/kotlin-reflect-1.6.10.jar" />
<entry name="$MAVEN_REPOSITORY$/net/ltgt/gradle/incap/incap/0.2/incap-0.2.jar" />
<entry name="$MAVEN_REPOSITORY$/org/checkerframework/checker-compat-qual/2.5.5/checker-compat-qual-2.5.5.jar" />
</processorPath>
<module name="cryptomator" />
</profile>
@@ -46,7 +46,7 @@
</component>
<component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
<module name="cryptomator" options="-Adagger.fastInit=enabled -Adagger.formatGeneratedSource=enabled --enable-preview" />
<module name="cryptomator" options="-Adagger.fastInit=enabled -Adagger.formatGeneratedSource=enabled" />
</option>
</component>
</project>

2
.idea/misc.xml generated
View File

@@ -8,7 +8,7 @@
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_21_PREVIEW" project-jdk-name="21" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_23" project-jdk-name="23" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

View File

@@ -2,7 +2,7 @@
<configuration default="false" name="Cryptomator Windows" type="Application" factoryName="Application">
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
<module name="cryptomator" />
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath=&quot;@{appdata}/Cryptomator/settings.json;@{userhome}/AppData/Roaming/Cryptomator/settings.json&quot; -Dcryptomator.ipcSocketPath=&quot;@{localappdata}/Cryptomator/ipc.socket&quot; -Dcryptomator.logDir=&quot;@{localappdata}/Cryptomator&quot; -Dcryptomator.pluginDir=&quot;@{appdata}/Cryptomator/Plugins&quot; -Dcryptomator.integrationsWin.keychainPaths=&quot;@{appdata}/Cryptomator/keychain.json;@{userhome}/AppData/Roaming/Cryptomator/keychain.json&quot; -Dcryptomator.p12Path=&quot;@{appdata}/Cryptomator/key.p12;@{userhome}/AppData/Roaming/Cryptomator/key.p12&quot; -Dcryptomator.mountPointsDir=&quot;@{userhome}/Cryptomator&quot; -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.win" />
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath=&quot;@{appdata}/Cryptomator/settings.json;@{userhome}/AppData/Roaming/Cryptomator/settings.json&quot; -Dcryptomator.ipcSocketPath=&quot;@{localappdata}/Cryptomator/ipc.socket&quot; -Dcryptomator.logDir=&quot;@{localappdata}/Cryptomator&quot; -Dcryptomator.pluginDir=&quot;@{appdata}/Cryptomator/Plugins&quot; -Dcryptomator.integrationsWin.keychainPaths=&quot;@{appdata}/Cryptomator/keychain.json;@{userhome}/AppData/Roaming/Cryptomator/keychain.json&quot; -Dcryptomator.p12Path=&quot;@{appdata}/Cryptomator/key.p12;@{userhome}/AppData/Roaming/Cryptomator/key.p12&quot; -Dcryptomator.mountPointsDir=&quot;@{userhome}/Cryptomator&quot; -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.win,org.cryptomator.integrations.win" />
<method v="2">
<option name="Make" enabled="true" />
</method>

View File

@@ -2,7 +2,7 @@
<configuration default="false" name="Cryptomator Windows Dev" type="Application" factoryName="Application">
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
<module name="cryptomator" />
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath=&quot;@{appdata}/Cryptomator-Dev/settings.json;@{userhome}/AppData/Roaming/Cryptomator-Dev/settings.json&quot; -Dcryptomator.ipcSocketPath=&quot;@{localappdata}/Cryptomator-Dev/ipc.socket&quot; -Dcryptomator.logDir=&quot;@{localappdata}/Cryptomator-Dev&quot; -Dcryptomator.pluginDir=&quot;@{appdata}/Cryptomator-Dev/Plugins&quot; -Dcryptomator.integrationsWin.keychainPaths=&quot;@{appdata}/Cryptomator-Dev/keychain.json;@{userhome}/AppData/Roaming/Cryptomator-Dev/keychain.json&quot; -Dcryptomator.p12Path=&quot;@{appdata}/Cryptomator-Dev/key.p12;@{userhome}/AppData/Roaming/Cryptomator-Dev/key.p12&quot; -Dcryptomator.mountPointsDir=&quot;@{userhome}/Cryptomator-Dev&quot; -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.win" />
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath=&quot;@{appdata}/Cryptomator-Dev/settings.json;@{userhome}/AppData/Roaming/Cryptomator-Dev/settings.json&quot; -Dcryptomator.ipcSocketPath=&quot;@{localappdata}/Cryptomator-Dev/ipc.socket&quot; -Dcryptomator.logDir=&quot;@{localappdata}/Cryptomator-Dev&quot; -Dcryptomator.pluginDir=&quot;@{appdata}/Cryptomator-Dev/Plugins&quot; -Dcryptomator.integrationsWin.keychainPaths=&quot;@{appdata}/Cryptomator-Dev/keychain.json;@{userhome}/AppData/Roaming/Cryptomator-Dev/keychain.json&quot; -Dcryptomator.p12Path=&quot;@{appdata}/Cryptomator-Dev/key.p12;@{userhome}/AppData/Roaming/Cryptomator-Dev/key.p12&quot; -Dcryptomator.mountPointsDir=&quot;@{userhome}/Cryptomator-Dev&quot; -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.win,org.cryptomator.integrations.win" />
<method v="2">
<option name="Make" enabled="true" />
</method>

View File

@@ -5,7 +5,7 @@
</envs>
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
<module name="cryptomator" />
<option name="VM_PARAMETERS" value="-Dapple.awt.enableTemplateImages=true -Dcryptomator.settingsPath=&quot;@{userhome}/Library/Application Support/Cryptomator-Dev/settings.json&quot; -Dcryptomator.p12Path=&quot;@{userhome}/Library/Application Support/Cryptomator-Dev/key.p12&quot; -Dcryptomator.ipcSocketPath=&quot;@{userhome}/Library/Application Support/Cryptomator-Dev/ipc.socket&quot; -Dcryptomator.logDir=&quot;@{userhome}/Library/Logs/Cryptomator-Dev&quot; -Dcryptomator.pluginDir=&quot;@{userhome}/Library/Application Support/Cryptomator-Dev/Plugins&quot; -Dcryptomator.mountPointsDir=&quot;@{userhome}/Cryptomator&quot; -Dcryptomator.showTrayIcon=true -Dcryptomator.integrationsMac.keychainServiceName=Cryptomator -Xss2m -Xmx512m -ea --enable-preview --enable-native-access=org.cryptomator.jfuse.mac" />
<option name="VM_PARAMETERS" value="-Dapple.awt.enableTemplateImages=true -Dcryptomator.settingsPath=&quot;@{userhome}/Library/Application Support/Cryptomator-Dev/settings.json&quot; -Dcryptomator.p12Path=&quot;@{userhome}/Library/Application Support/Cryptomator-Dev/key.p12&quot; -Dcryptomator.ipcSocketPath=&quot;@{userhome}/Library/Application Support/Cryptomator-Dev/ipc.socket&quot; -Dcryptomator.logDir=&quot;@{userhome}/Library/Logs/Cryptomator-Dev&quot; -Dcryptomator.pluginDir=&quot;@{userhome}/Library/Application Support/Cryptomator-Dev/Plugins&quot; -Dcryptomator.mountPointsDir=&quot;@{userhome}/Library/Application Support/Cryptomator-Dev/mnt&quot; -Dcryptomator.showTrayIcon=true -Dcryptomator.integrationsMac.keychainServiceName=Cryptomator -Xss2m -Xmx512m -ea --enable-preview --enable-native-access=org.cryptomator.jfuse.mac" />
<method v="2">
<option name="Make" enabled="true" />
</method>

View File

@@ -1,9 +1,9 @@
[![cryptomator](cryptomator.png)](https://cryptomator.org/)
[![Build](https://github.com/cryptomator/cryptomator/workflows/Build/badge.svg)](https://github.com/cryptomator/cryptomator/actions?query=workflow%3ABuild)
[![Build](https://github.com/cryptomator/cryptomator/workflows/Build/badge.svg)](https://github.com/cryptomator/cryptomator/actions/workflows/build.yml?query=branch%3Adevelop)
[![Known Vulnerabilities](https://snyk.io/test/github/cryptomator/cryptomator/badge.svg)](https://snyk.io/test/github/cryptomator/cryptomator)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=cryptomator_cryptomator&metric=alert_status)](https://sonarcloud.io/dashboard?id=cryptomator_cryptomator)
[![Twitter](https://img.shields.io/badge/twitter-@Cryptomator-blue.svg?style=flat)](http://twitter.com/Cryptomator)
[![Mastodon](https://img.shields.io/mastodon/follow/176112?domain=mastodon.online&style=flat)](https://mastodon.online/@cryptomator)
[![Crowdin](https://badges.crowdin.net/cryptomator/localized.svg)](https://translate.cryptomator.org/)
[![Latest Release](https://img.shields.io/github/release/cryptomator/cryptomator.svg)](https://github.com/cryptomator/cryptomator/releases/latest)
[![Community](https://img.shields.io/badge/help-Community-orange.svg)](https://community.cryptomator.org)
@@ -17,32 +17,24 @@ Cryptomator is provided free of charge as an open-source project despite the hig
### Gold Sponsors
<table>
<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>
</tr>
</tbody>
</table>
Become our Gold Sponsor and showcase your brand to a targeted audience! Please contact us if you are interested.
### Silver Sponsors
<table>
<tbody>
<tr>
<td><a href="https://mowcapital.com/"><img src="https://cryptomator.org/img/sponsors/mowcapital.svg" alt="Mow Capital" height="28"></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>
<td><a href="https://ente.io/"><img src="https://cryptomator.org/img/sponsors/ente.svg" alt="Ente" height="58"></a></td>
<td><a href="https://www.gee-whiz.de/"><img src="https://cryptomator.org/img/sponsors/geewhiz.svg" alt="gee-whiz" height="56"></a></td>
<td><a href="https://www.route4me.com/"><img src="https://cryptomator.org/img/sponsors/route4me.svg" alt="Route4Me" height="56"></a></td>
</tr>
</tbody>
</table>
### Special Shoutout
Continuous integration hosting for ARM64 builds is provided by [MacStadium](https://www.macstadium.com/opensource).
Continuous integration hosting for ARM64 builds is provided by [MacStadium](https://www.macstadium.com/company/opensource).
<a href="https://www.macstadium.com/opensource"><img src="https://uploads-ssl.webflow.com/5ac3c046c82724970fc60918/5c019d917bba312af7553b49_MacStadium-developerlogo.png" alt="MacStadium" height="100"></a>
<a href="https://www.macstadium.com/company/opensource"><img src="https://uploads-ssl.webflow.com/5ac3c046c82724970fc60918/5c019d917bba312af7553b49_MacStadium-developerlogo.png" alt="MacStadium" height="100"></a>
---
@@ -62,7 +54,7 @@ Download native binaries of Cryptomator on [cryptomator.org](https://cryptomator
- File names get encrypted
- Folder structure gets obfuscated
- Use as many vaults in your Dropbox as you want, each having individual passwords
- Four thousand commits for the security of your data!! :tada:
- More than Five thousand commits for the security of your data!! :tada:
### Privacy
@@ -80,13 +72,13 @@ Download native binaries of Cryptomator on [cryptomator.org](https://cryptomator
### Security Architecture
For more information on the security details visit [cryptomator.org](https://docs.cryptomator.org/en/latest/security/architecture/).
For more information on the security details visit [cryptomator.org](https://docs.cryptomator.org/security/architecture/).
## Building
### Dependencies
* JDK 21 (e.g. temurin, zulu)
* JDK 23 (e.g. temurin, zulu)
* Maven 3
### Run Maven

View File

@@ -1,4 +1,6 @@
# created during build
# downloaded/created during build
openjfx-jmods.zip
*.jmod
Cryptomator.AppDir
*.AppImage
*.AppImage.zsync

View File

@@ -12,40 +12,40 @@ command -v unzip >/dev/null 2>&1 || { echo >&2 "unzip not found."; exit 1; }
VERSION=$(mvn -f ../../../pom.xml help:evaluate -Dexpression=project.version -q -DforceStdout)
SEMVER_STR=${VERSION}
MACHINE_TYPE=$(uname -m)
CPU_ARCH=$(uname -p)
if [[ ! "${MACHINE_TYPE}" =~ x86_64|aarch64 ]]; then echo "Platform ${MACHINE_TYPE} not supported"; exit 1; fi
if [[ ! "${CPU_ARCH}" =~ x86_64|aarch64 ]]; then echo "Platform ${CPU_ARCH} not supported"; exit 1; fi
mvn -f ../../../pom.xml versions:set -DnewVersion=${SEMVER_STR}
# compile
mvn -B -f ../../../pom.xml clean package -Plinux -DskipTests
mvn -B -f ../../../pom.xml clean package -Plinux -DskipTests -Djavafx.platform=linux
cp ../../../LICENSE.txt ../../../target
cp ../../../target/cryptomator-*.jar ../../../target/mods
# download javaFX jmods
OPENJFX_URL='https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_linux-x64_bin-jmods.zip'
OPENJFX_SHA='7baed11ca56d5fee85995fa6612d4299f1e8b7337287228f7f12fd50407c56f8'
OPENJFX_URL_aarch64='https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_linux-aarch64_bin-jmods.zip'
OPENJFX_SHA_aarch64='871e7b9d7af16aef2e55c1b7830d0e0b2503b13dd8641374ba7e55ecb81d2ef9'
if [[ "${MACHINE_TYPE}" = "aarch64" ]]; then
OPENJFX_URL="${OPENJFX_URL_aarch64}";
OPENJFX_SHA="${OPENJFX_SHA_aarch64}";
JAVAFX_VERSION=23.0.2
JAVAFX_ARCH="x64"
JAVAFX_JMODS_SHA256='063baebc6922e4a89c94b9dfb7a4f53e59e8d6fec400d4e670b31bc2ab324dec'
if [ "${CPU_ARCH}" = "aarch64" ]; then
JAVAFX_ARCH="aarch64"
JAVAFX_JMODS_SHA256='9bbedaeae1590b69e2b22237bda310936df33e344dbc243bea2e86acaab3a0d8'
fi
curl -L ${OPENJFX_URL} -o openjfx-jmods.zip
echo "${OPENJFX_SHA} openjfx-jmods.zip" | shasum -a256 --check
# download javaFX jmods
JAVAFX_JMODS_URL="https://download2.gluonhq.com/openjfx/${JAVAFX_VERSION}/openjfx-${JAVAFX_VERSION}_linux-${JAVAFX_ARCH}_bin-jmods.zip"
curl -L ${JAVAFX_JMODS_URL} -o openjfx-jmods.zip
echo "${JAVAFX_JMODS_SHA256} openjfx-jmods.zip" | shasum -a256 --check
mkdir -p openjfx-jmods
unzip -j openjfx-jmods.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d openjfx-jmods
JMOD_VERSION=$(jmod describe openjfx-jmods/javafx.base.jmod | head -1)
unzip -o -j openjfx-jmods.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d openjfx-jmods
JMOD_VERSION=$(jmod describe ./openjfx-jmods/javafx.base.jmod | head -1)
JMOD_VERSION=${JMOD_VERSION#*@}
JMOD_VERSION=${JMOD_VERSION%%.*}
POM_JFX_VERSION=$(mvn help:evaluate "-Dexpression=javafx.version" -q -DforceStdout)
POM_JFX_VERSION=$(mvn help:evaluate "-Dexpression=javafx.version" -q -DforceStdout -B -f ../../../pom.xml)
POM_JFX_VERSION=${POM_JFX_VERSION#*@}
POM_JFX_VERSION=${POM_JFX_VERSION%%.*}
if [ $POM_JFX_VERSION -ne $JMOD_VERSION_AMD64 ]; then
if [ $POM_JFX_VERSION -ne $JMOD_VERSION ]; then
>&2 echo "Major JavaFX version in pom.xml (${POM_JFX_VERSION}) != amd64 jmod version (${JMOD_VERSION})"
exit 1
fi
@@ -56,7 +56,7 @@ ${JAVA_HOME}/bin/jlink \
--verbose \
--output runtime \
--module-path "${JAVA_HOME}/jmods:openjfx-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.security.auth,jdk.accessibility,jdk.management.jfr,jdk.net \
--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.security.auth,jdk.accessibility,jdk.management.jfr,jdk.net,java.compiler \
--strip-native-commands \
--no-header-files \
--no-man-pages \
@@ -64,7 +64,6 @@ ${JAVA_HOME}/bin/jlink \
--compress zip-0
# create app dir
envsubst '${SEMVER_STR} ${REVISION_NUM}' < ../launcher-gtk2.properties > launcher-gtk2.properties
${JAVA_HOME}/bin/jpackage \
--verbose \
--type app-image \
@@ -77,7 +76,7 @@ ${JAVA_HOME}/bin/jpackage \
--vendor "Skymatic GmbH" \
--java-options "--enable-preview" \
--java-options "--enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator" \
--copyright "(C) 2016 - 2024 Skymatic GmbH" \
--copyright "(C) 2016 - 2025 Skymatic GmbH" \
--java-options "-Xss5m" \
--java-options "-Xmx256m" \
--app-version "${VERSION}.${REVISION_NO}" \
@@ -92,7 +91,7 @@ ${JAVA_HOME}/bin/jpackage \
--java-options "-Dcryptomator.showTrayIcon=true" \
--java-options "-Dcryptomator.integrationsLinux.trayIconsDir=\"@{appdir}/usr/share/icons/hicolor/symbolic/apps\"" \
--java-options "-Dcryptomator.buildNumber=\"appimage-${REVISION_NO}\"" \
--add-launcher cryptomator-gtk2=launcher-gtk2.properties \
--java-options "-Dcryptomator.networking.truststore.p12Path=\"/etc/cryptomator/certs.p12\"" \
--resource-dir ../resources
# transform AppDir
@@ -110,23 +109,23 @@ cp ../common/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/usr/share/ap
cp ../common/org.cryptomator.Cryptomator.metainfo.xml Cryptomator.AppDir/usr/share/metainfo/org.cryptomator.Cryptomator.metainfo.xml
cp ../common/application-vnd.cryptomator.vault.xml Cryptomator.AppDir/usr/share/mime/packages/application-vnd.cryptomator.vault.xml
ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/org.cryptomator.Cryptomator.svg
ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/Cryptomator.svg
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 usr/share/applications/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/org.cryptomator.Cryptomator.desktop
ln -s org.cryptomator.Cryptomator.metainfo.xml Cryptomator.AppDir/usr/share/metainfo/org.cryptomator.Cryptomator.appdata.xml
ln -s bin/cryptomator.sh Cryptomator.AppDir/AppRun
# load AppImageTool
curl -L https://github.com/AppImage/AppImageKit/releases/download/13/appimagetool-${MACHINE_TYPE}.AppImage -o /tmp/appimagetool.AppImage
curl -L https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-${CPU_ARCH}.AppImage -o /tmp/appimagetool.AppImage
chmod +x /tmp/appimagetool.AppImage
# create AppImage
/tmp/appimagetool.AppImage \
Cryptomator.AppDir \
cryptomator-${SEMVER_STR}-${MACHINE_TYPE}.AppImage \
-u 'gh-releases-zsync|cryptomator|cryptomator|latest|cryptomator-*-${MACHINE_TYPE}.AppImage.zsync'
cryptomator-${SEMVER_STR}-${CPU_ARCH}.AppImage \
-u 'gh-releases-zsync|cryptomator|cryptomator|latest|cryptomator-*-${CPU_ARCH}.AppImage.zsync'
echo ""
echo "Done. AppImage successfully created: cryptomator-${SEMVER_STR}-${MACHINE_TYPE}.AppImage"
echo "Done. AppImage successfully created: cryptomator-${SEMVER_STR}-${CPU_ARCH}.AppImage"
echo ""
echo >&2 "To clean up, run: rm -rf Cryptomator.AppDir appdir runtime squashfs-root openjfx-jmods; rm launcher-gtk2.properties /tmp/appimagetool.AppImage openjfx-jmods.zip"
echo >&2 "To clean up, run: rm -rf Cryptomator.AppDir appdir runtime squashfs-root openjfx-jmods; rm /tmp/appimagetool.AppImage openjfx-jmods.zip"
echo ""

View File

@@ -1,30 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright 2018 Armin Schrenk <armin.schrenk@zoho.eu> -->
<component type="desktop-application">
<id>org.cryptomator.Cryptomator</id>
<metadata_license>FSFAP</metadata_license>
<project_license>GPL-3.0-or-later</project_license>
<name>Cryptomator</name>
<summary>Multi-platform client-side encryption tool optimized for cloud storages</summary>
<summary>Encryption for your cloud made easy</summary>
<keywords>
<keyword>encryption</keyword>
<keyword>security</keyword>
<keyword>privacy</keyword>
</keywords>
<description>
<p>
Cryptomator provides transparent, client-side encryption for your cloud. Protect your documents from unauthorized
access. Cryptomator is free and open source software, so you can rest assured there are no backdoors.
Cryptomator provides easy-to-use, transparent, client-side encryption for your cloud.
It protects your documents from unauthorized access and prying eyes, while you will still be able to view and edit your documents locally.
By not requiring any registration or account and performing all encryption locally, it gives you back control over your data and ensures your privacy.
Cryptomator is offered for all major platforms (including Android and iOS).
</p>
<p>
Cryptomator encrypts file contents and names using AES. Your passphrase is protected against bruteforcing attempts
using scrypt. Directory structures get obfuscated. The only thing which cannot be encrypted without breaking your
cloud synchronization is the modification date of your files.
Cryptomator encrypts file contents and names using the widespread industry standard AES.
Your passphrase is protected against brute forcing attempts using scrypt.
Additionally, directory structures get obfuscated.
For more info about the Cryptomator encryption scheme, check out the online documentation.
</p>
<p>
Cryptomator is a free and open source software licensed under the GPLv3. This allows anyone to check our code. It
is impossible to introduce backdoors for third parties. Also we cannot hide vulnerabilities. And the best thing
is: There is no need to trust us, as you can control us!
</p>
<p>
Vendor lock-ins are impossible. Even if we decided to stop development: The source code is already cloned by
hundreds of other developers. As you don't need an account, you will never stand in front of locked doors.
Cryptomator is a free and open-source software licensed under the GPLv3.
This allows anyone to check our code.
Thus, it is impossible to introduce backdoors for third parties or to hide vulnerabilities, so you do not need to trust Cryptomator.
Also, vendor lock-ins are impossible.
Even if we decided to stop development: The source code is already cloned by hundreds of other developers and development can be picked up by others.
</p>
</description>
@@ -42,56 +48,163 @@
</provides>
<screenshots>
<screenshot>
<caption>Light theme</caption>
<image>https://user-images.githubusercontent.com/11858409/156986109-6e58f59c-8b8c-4501-b33b-bb1e33007cea.png</image>
<screenshot type="default">
<caption>Encrypts your data, protects your privacy</caption>
<image>https://static.cryptomator.org/desktop/flathubScreenshots/MainWindowUnlockDialog_light.png</image>
</screenshot>
<screenshot>
<caption>Dark theme</caption>
<image>https://user-images.githubusercontent.com/11858409/156986113-6c5d7801-86e0-4643-bc2f-aff9d95d3ce0.png</image>
<caption>Dark theme available</caption>
<image>https://static.cryptomator.org/desktop/flathubScreenshots/MainWindowUnlocked_dark.png</image>
</screenshot>
<screenshot>
<caption>Easy to use - work on encrypted files as if they were not</caption>
<image>https://static.cryptomator.org/desktop/flathubScreenshots/MainWindowUnlocked_light.png</image>
</screenshot>
</screenshots>
<branding>
<color type="primary" scheme_preference="light">#EBF5EB</color>
<color type="primary" scheme_preference="dark">#2F4858</color>
</branding>
<url type="homepage">https://cryptomator.org/</url>
<url type="bugtracker">https://github.com/cryptomator/cryptomator/issues/</url>
<url type="donation">https://cryptomator.org/donate</url>
<url type="faq">https://community.cryptomator.org/c/kb/faq</url>
<url type="help">https://community.cryptomator.org/</url>
<url type="help">https://docs.cryptomator.org/</url>
<url type="translate">https://translate.cryptomator.org</url>
<developer_name>Skymatic GmbH</developer_name>
<developer id="de.skymatic">
<name>Skymatic GmbH</name>
</developer>
<content_rating type="oars-1.1">
<content_attribute id="social-info">mild</content_attribute> <!-- update checker connects to https://api.cryptomator.org/updates/latestVersion.json -->
</content_rating>
<releases>
<release date="2024-02-06" version="1.12.0"/>
<release date="2023-12-05" version="1.11.1"/>
<release date="2023-11-08" version="1.11.0"/>
<release date="2023-09-20" version="1.10.1"/>
<release date="2023-09-11" version="1.10.0"/>
<release date="2023-08-11" version="1.9.4"/>
<release date="2023-08-07" version="1.9.3"/>
<release date="2023-07-24" version="1.9.2"/>
<release date="2023-06-07" version="1.9.1"/>
<release date="2023-05-30" version="1.9.0"/>
<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"/>
<release date="2022-07-27" version="1.6.12"/>
<release date="2022-07-26" version="1.6.11"/>
<release date="2022-05-03" version="1.6.10"/>
<release date="2022-04-27" version="1.6.9"/>
<release date="2022-03-30" version="1.6.8"/>
<release date="2021-12-16" version="1.6.5"/>
<release date="2025-05-15" version="1.16.2">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.16.2</url>
</release>
<release date="2025-04-30" version="1.16.1">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.16.1</url>
</release>
<release date="2025-04-29" version="1.16.0">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.16.0</url>
</release>
<release date="2025-04-09" version="1.15.3">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.15.3</url>
</release>
<release date="2025-04-04" version="1.15.2">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.15.2</url>
</release>
<release date="2025-02-05" version="1.15.1">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.15.1</url>
</release>
<release date="2025-02-03" version="1.15.0">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.15.0</url>
</release>
<release date="2024-11-19" version="1.14.2">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.14.2</url>
</release>
<release date="2024-09-17" version="1.14.0">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.14.0</url>
</release>
<release date="2024-06-26" version="1.13.0">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.13.0</url>
</release>
<release date="2024-03-27" version="1.12.4">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.12.4</url>
</release>
<release date="2024-02-27" version="1.12.3">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.12.3</url>
</release>
<release date="2024-02-09" version="1.12.2">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.12.2</url>
</release>
<release date="2024-02-07" version="1.12.1">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.12.1</url>
</release>
<release date="2024-02-06" version="1.12.0">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.12.0</url>
</release>
<release date="2023-12-05" version="1.11.1">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.11.1</url>
</release>
<release date="2023-11-08" version="1.11.0">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.11.0</url>
</release>
<release date="2023-09-20" version="1.10.1">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.10.1</url>
</release>
<release date="2023-09-11" version="1.10.0">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.10.0</url>
</release>
<release date="2023-08-11" version="1.9.4">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.9.4</url>
</release>
<release date="2023-08-07" version="1.9.3">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.9.3</url>
</release>
<release date="2023-07-24" version="1.9.2">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.9.2</url>
</release>
<release date="2023-06-07" version="1.9.1">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.9.1</url>
</release>
<release date="2023-05-30" version="1.9.0">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.9.0</url>
</release>
<release date="2023-04-25" version="1.8.0">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.8.0</url>
</release>
<release date="2023-04-07" version="1.7.5">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.7.5</url>
</release>
<release date="2023-04-05" version="1.7.4">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.7.4</url>
</release>
<release date="2023-03-15" version="1.7.3">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.7.3</url>
</release>
<release date="2023-03-07" version="1.7.2">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.7.2</url>
</release>
<release date="2023-03-03" version="1.7.1">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.7.1</url>
</release>
<release date="2023-03-01" version="1.7.0">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.7.0</url>
</release>
<release date="2022-12-14" version="1.6.17">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.6.17</url>
</release>
<release date="2022-12-06" version="1.6.16">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.6.16</url>
</release>
<release date="2022-10-06" version="1.6.15">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.6.15</url>
</release>
<release date="2022-08-31" version="1.6.14">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.6.14</url>
</release>
<release date="2022-07-27" version="1.6.12">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.6.12</url>
</release>
<release date="2022-07-26" version="1.6.11">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.6.11</url>
</release>
<release date="2022-05-03" version="1.6.10">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.6.10</url>
</release>
<release date="2022-04-27" version="1.6.9">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.6.9</url>
</release>
<release date="2022-03-30" version="1.6.8">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.6.8</url>
</release>
<release date="2021-12-16" version="1.6.5">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.6.5</url>
</release>
</releases>
</component>

View File

@@ -1,12 +1,16 @@
<svg height="16" viewBox="0 0 42 42" width="16" xmlns="http://www.w3.org/2000/svg">
<style
id="current-color-scheme" type="text/css">
.ColorScheme-Text {
color:#232629;
}
</style>
<g fill-rule="evenodd" style="fill:#f2f2f2;fill-opacity:1" class="ColorScheme-Text" fill="currentColor">
<path d="m15.591 35.824c-.019.009-.936.775-1.458 1.208a.418.418 0 0 1 -.627-.111 9.322 9.322 0 0 1 -.3-5.974 15.843 15.843 0 0 0 2.894 2.043c.051 1.03-.161 2.644-.509 2.834zm6.409-6.824h-2l.5-5a2 2 0 1 1 1 0zm-14.544-3.241.744-1.366a1.579 1.579 0 0 0 -.019-1.557l.653-1.2c.2.014-.03-.113.165-.14.051-.217-.051-.336 0-.5a3.269 3.269 0 0 0 0-1.5 7.151 7.151 0 0 1 0-3 2.366 2.366 0 0 0 -2.378 1.448 2.409 2.409 0 0 0 .229 2.661l-.7 1.278a1.779 1.779 0 0 0 -1.317.891l-.741 1.372a1.577 1.577 0 0 0 -.019 1.487 3.028 3.028 0 0 0 -2.746 1.525 2.648 2.648 0 0 0 .044 2.631.748.748 0 0 0 .981.266.656.656 0 0 0 .284-.92 1.37 1.37 0 0 1 -.023-1.361 1.6 1.6 0 0 1 2.079-.63 1.408 1.408 0 0 1 .672 1.95 1.546 1.546 0 0 1 -1.2.78.688.688 0 0 0 -.636.749.707.707 0 0 0 .717.6.789.789 0 0 0 .082 0 2.989 2.989 0 0 0 2.322-1.513 2.669 2.669 0 0 0 -.377-3.084 1.767 1.767 0 0 0 1.184-.867zm13.544-10.759a13.013 13.013 0 0 1 5-1 21.6 21.6 0 0 1 4.5.5 9.312 9.312 0 0 0 -9.5-8.5c-5.794 0-9.176 4-9.5 8.5a21.858 21.858 0 0 1 4.5-.5 12.819 12.819 0 0 1 5 1zm3.5-5c1.209 0 2.5.866 2.5 2h-5c0-1.134 1.291-2 2.5-2zm-7 0c1.209 0 2.5.866 2.5 2h-5c0-1.134 1.291-2 2.5-2zm14.473 6a8.067 8.067 0 0 0 -8.08 8v2.141a3.891 3.891 0 0 0 -2.893 3.734v5.125a23.166 23.166 0 0 1 -4.174-1.623 7.857 7.857 0 0 1 -.027.878 3.263 3.263 0 0 1 -.729 2.074l-1.794 1.483a.379.379 0 0 1 -.276.188h-4c-1.324 0-2.346-1.336-2.653-3.343a7.058 7.058 0 0 1 .234-3.18 3.477 3.477 0 0 1 1.636-2.157 1.868 1.868 0 0 1 .783-.32h1.5a8.035 8.035 0 0 1 -1.5-5 11.1 11.1 0 0 1 .5-3 2.519 2.519 0 0 0 0-1.5 13.272 13.272 0 0 1 -.5-3.5c6.687-1.936 11 0 11 0s4.319-1.955 11 0"/>
<path d="m39 28h-10v-4a3.13 3.13 0 0 1 3-3 3.087 3.087 0 0 1 3 3v1a1.034 1.034 0 0 0 1 1h1a1.034 1.034 0 0 0 1-1v-1a6 6 0 0 0 -12 0v4h-1a2.073 2.073 0 0 0 -2 2v6a2.073 2.073 0 0 0 2 2h14a2.073 2.073 0 0 0 2-2v-6a2.073 2.073 0 0 0 -2-2zm-5.391 5.94a1.609 1.609 0 0 1 -3.217 0v-1.876a1.609 1.609 0 0 1 3.217 0z"/>
<defs>
<style id="current-color-scheme" type="text/css">
.ColorScheme-Text {
color:#222222;
}
.ColorScheme-Highlight {
color:#49B04A;
}
</style>
</defs>
<g fill-rule="evenodd">
<path d="m15.591 35.824c-.019.009-.936.775-1.458 1.208a.418.418 0 0 1 -.627-.111 9.322 9.322 0 0 1 -.3-5.974 15.843 15.843 0 0 0 2.894 2.043c.051 1.03-.161 2.644-.509 2.834zm6.409-6.824h-2l.5-5a2 2 0 1 1 1 0zm-14.544-3.241.744-1.366a1.579 1.579 0 0 0 -.019-1.557l.653-1.2c.2.014-.03-.113.165-.14.051-.217-.051-.336 0-.5a3.269 3.269 0 0 0 0-1.5 7.151 7.151 0 0 1 0-3 2.366 2.366 0 0 0 -2.378 1.448 2.409 2.409 0 0 0 .229 2.661l-.7 1.278a1.779 1.779 0 0 0 -1.317.891l-.741 1.372a1.577 1.577 0 0 0 -.019 1.487 3.028 3.028 0 0 0 -2.746 1.525 2.648 2.648 0 0 0 .044 2.631.748.748 0 0 0 .981.266.656.656 0 0 0 .284-.92 1.37 1.37 0 0 1 -.023-1.361 1.6 1.6 0 0 1 2.079-.63 1.408 1.408 0 0 1 .672 1.95 1.546 1.546 0 0 1 -1.2.78.688.688 0 0 0 -.636.749.707.707 0 0 0 .717.6.789.789 0 0 0 .082 0 2.989 2.989 0 0 0 2.322-1.513 2.669 2.669 0 0 0 -.377-3.084 1.767 1.767 0 0 0 1.184-.867zm13.544-10.759a13.013 13.013 0 0 1 5-1 21.6 21.6 0 0 1 4.5.5 9.312 9.312 0 0 0 -9.5-8.5c-5.794 0-9.176 4-9.5 8.5a21.858 21.858 0 0 1 4.5-.5 12.819 12.819 0 0 1 5 1zm3.5-5c1.209 0 2.5.866 2.5 2h-5c0-1.134 1.291-2 2.5-2zm-7 0c1.209 0 2.5.866 2.5 2h-5c0-1.134 1.291-2 2.5-2zm14.473 6a8.067 8.067 0 0 0 -8.08 8v2.141a3.891 3.891 0 0 0 -2.893 3.734v5.125a23.166 23.166 0 0 1 -4.174-1.623 7.857 7.857 0 0 1 -.027.878 3.263 3.263 0 0 1 -.729 2.074l-1.794 1.483a.379.379 0 0 1 -.276.188h-4c-1.324 0-2.346-1.336-2.653-3.343a7.058 7.058 0 0 1 .234-3.18 3.477 3.477 0 0 1 1.636-2.157 1.868 1.868 0 0 1 .783-.32h1.5a8.035 8.035 0 0 1 -1.5-5 11.1 11.1 0 0 1 .5-3 2.519 2.519 0 0 0 0-1.5 13.272 13.272 0 0 1 -.5-3.5c6.687-1.936 11 0 11 0s4.319-1.955 11 0" class="ColorScheme-Text" fill="currentColor"/>
<path d="m39 28h-10v-4a3.13 3.13 0 0 1 3-3 3.087 3.087 0 0 1 3 3v1a1.034 1.034 0 0 0 1 1h1a1.034 1.034 0 0 0 1-1v-1a6 6 0 0 0 -12 0v4h-1a2.073 2.073 0 0 0 -2 2v6a2.073 2.073 0 0 0 2 2h14a2.073 2.073 0 0 0 2-2v-6a2.073 2.073 0 0 0 -2-2zm-5.391 5.94a1.609 1.609 0 0 1 -3.217 0v-1.876a1.609 1.609 0 0 1 3.217 0z" class="ColorScheme-Highlight" fill="currentColor"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -1,8 +1,10 @@
<svg height="16" viewBox="0 0 42 42" width="16" xmlns="http://www.w3.org/2000/svg">
<style id="current-color-scheme" type="text/css">
.ColorScheme-Text {
color:#232629;
}
</style>
<path d="m32.66 29.319a1.432 1.432 0 0 0 -.66-.319h-1.5a8.125 8.125 0 0 0 1.5-5 11.027 11.027 0 0 0 -.5-3 2.519 2.519 0 0 1 0-1.5 12.987 12.987 0 0 0 .5-3.5c-6.681-1.955-11 0-11 0s-4.313-1.936-11 0a13.272 13.272 0 0 0 .5 3.5 2.519 2.519 0 0 1 0 1.5 11.1 11.1 0 0 0 -.5 3 8.035 8.035 0 0 0 1.5 5h-1.5a1.868 1.868 0 0 0 -.783.319 3.477 3.477 0 0 0 -1.636 2.157 7.058 7.058 0 0 0 -.234 3.18c.307 2.008 1.329 3.344 2.653 3.344h4a.379.379 0 0 0 .277-.187l1.793-1.483a3.263 3.263 0 0 0 .729-2.074 7.857 7.857 0 0 0 .027-.878 23.166 23.166 0 0 0 4.174 1.622 24.4 24.4 0 0 0 4.051-1.614 7.848 7.848 0 0 0 .027.869 3.263 3.263 0 0 0 .729 2.074l1.793 1.484a.61.61 0 0 0 .4.187h4c1.324 0 2.223-1.336 2.529-3.343a7.057 7.057 0 0 0 -.234-3.18 3.477 3.477 0 0 0 -1.635-2.158zm-17.069 6.5c-.019.009-.936.775-1.458 1.208a.418.418 0 0 1 -.627-.111 9.322 9.322 0 0 1 -.3-5.974 15.843 15.843 0 0 0 2.894 2.048c.051 1.03-.161 2.644-.509 2.834zm6.409-6.819h-2l.5-5a2 2 0 1 1 1 0zm6.38 7.921a.418.418 0 0 1 -.627.111c-.522-.433-1.439-1.2-1.458-1.208-.348-.189-.56-1.8-.505-2.828a15.84 15.84 0 0 0 2.9-2.037 9.322 9.322 0 0 1 -.31 5.962zm-20.924-11.162.744-1.366a1.579 1.579 0 0 0 -.019-1.557l.653-1.2c.2.014-.03-.113.165-.14.051-.217-.051-.336 0-.5a3.269 3.269 0 0 0 0-1.5 7.151 7.151 0 0 1 0-3 2.366 2.366 0 0 0 -2.378 1.448 2.409 2.409 0 0 0 .229 2.661l-.7 1.278a1.779 1.779 0 0 0 -1.317.891l-.741 1.372a1.577 1.577 0 0 0 -.019 1.487 3.028 3.028 0 0 0 -2.746 1.525 2.648 2.648 0 0 0 .044 2.631.748.748 0 0 0 .981.266.656.656 0 0 0 .284-.92 1.37 1.37 0 0 1 -.023-1.361 1.6 1.6 0 0 1 2.079-.63 1.408 1.408 0 0 1 .672 1.95 1.546 1.546 0 0 1 -1.2.78.688.688 0 0 0 -.636.749.707.707 0 0 0 .717.6.789.789 0 0 0 .082 0 2.989 2.989 0 0 0 2.322-1.513 2.669 2.669 0 0 0 -.377-3.084 1.767 1.767 0 0 0 1.184-.867zm33.217 1.2a3.021 3.021 0 0 0 -2.658-1.525 1.574 1.574 0 0 0 -.107-1.283l-.745-1.367a1.779 1.779 0 0 0 -1.317-.891l-.7-1.278a2.409 2.409 0 0 0 .229-2.661 2.283 2.283 0 0 0 -2.375-1.454 7.039 7.039 0 0 1 0 3 3.272 3.272 0 0 0 0 1.5c.047.152-.047.3 0 .5.227.04-.069.156.165.14l.653 1.2a1.579 1.579 0 0 0 -.019 1.557l.745 1.367a1.753 1.753 0 0 0 1.045.832 2.66 2.66 0 0 0 -.238 2.916 2.989 2.989 0 0 0 2.326 1.509.79.79 0 0 0 .082 0 .707.707 0 0 0 .717-.6.688.688 0 0 0 -.636-.749 1.546 1.546 0 0 1 -1.2-.78 1.408 1.408 0 0 1 .672-1.95 1.628 1.628 0 0 1 1.179-.089 1.512 1.512 0 0 1 .9.719 1.37 1.37 0 0 1 -.023 1.361.656.656 0 0 0 .284.92.748.748 0 0 0 .981-.266 2.648 2.648 0 0 0 .04-2.633zm-19.673-11.959a13.013 13.013 0 0 1 5-1 21.6 21.6 0 0 1 4.5.5 9.312 9.312 0 0 0 -9.5-8.5c-5.794 0-9.176 4-9.5 8.5a21.858 21.858 0 0 1 4.5-.5 12.819 12.819 0 0 1 5 1zm3.5-5c1.209 0 2.5.866 2.5 2h-5c0-1.134 1.291-2 2.5-2zm-7 0c1.209 0 2.5.866 2.5 2h-5c0-1.134 1.291-2 2.5-2z" fill-rule="evenodd" style="fill:#f2f2f2;fill-opacity:1" class="ColorScheme-Text" fill="currentColor"/>
<defs>
<style id="current-color-scheme" type="text/css">
.ColorScheme-Text {
color:#222222;
}
</style>
</defs>
<path d="m32.66 29.319a1.432 1.432 0 0 0 -.66-.319h-1.5a8.125 8.125 0 0 0 1.5-5 11.027 11.027 0 0 0 -.5-3 2.519 2.519 0 0 1 0-1.5 12.987 12.987 0 0 0 .5-3.5c-6.681-1.955-11 0-11 0s-4.313-1.936-11 0a13.272 13.272 0 0 0 .5 3.5 2.519 2.519 0 0 1 0 1.5 11.1 11.1 0 0 0 -.5 3 8.035 8.035 0 0 0 1.5 5h-1.5a1.868 1.868 0 0 0 -.783.319 3.477 3.477 0 0 0 -1.636 2.157 7.058 7.058 0 0 0 -.234 3.18c.307 2.008 1.329 3.344 2.653 3.344h4a.379.379 0 0 0 .277-.187l1.793-1.483a3.263 3.263 0 0 0 .729-2.074 7.857 7.857 0 0 0 .027-.878 23.166 23.166 0 0 0 4.174 1.622 24.4 24.4 0 0 0 4.051-1.614 7.848 7.848 0 0 0 .027.869 3.263 3.263 0 0 0 .729 2.074l1.793 1.484a.61.61 0 0 0 .4.187h4c1.324 0 2.223-1.336 2.529-3.343a7.057 7.057 0 0 0 -.234-3.18 3.477 3.477 0 0 0 -1.635-2.158zm-17.069 6.5c-.019.009-.936.775-1.458 1.208a.418.418 0 0 1 -.627-.111 9.322 9.322 0 0 1 -.3-5.974 15.843 15.843 0 0 0 2.894 2.048c.051 1.03-.161 2.644-.509 2.834zm6.409-6.819h-2l.5-5a2 2 0 1 1 1 0zm6.38 7.921a.418.418 0 0 1 -.627.111c-.522-.433-1.439-1.2-1.458-1.208-.348-.189-.56-1.8-.505-2.828a15.84 15.84 0 0 0 2.9-2.037 9.322 9.322 0 0 1 -.31 5.962zm-20.924-11.162.744-1.366a1.579 1.579 0 0 0 -.019-1.557l.653-1.2c.2.014-.03-.113.165-.14.051-.217-.051-.336 0-.5a3.269 3.269 0 0 0 0-1.5 7.151 7.151 0 0 1 0-3 2.366 2.366 0 0 0 -2.378 1.448 2.409 2.409 0 0 0 .229 2.661l-.7 1.278a1.779 1.779 0 0 0 -1.317.891l-.741 1.372a1.577 1.577 0 0 0 -.019 1.487 3.028 3.028 0 0 0 -2.746 1.525 2.648 2.648 0 0 0 .044 2.631.748.748 0 0 0 .981.266.656.656 0 0 0 .284-.92 1.37 1.37 0 0 1 -.023-1.361 1.6 1.6 0 0 1 2.079-.63 1.408 1.408 0 0 1 .672 1.95 1.546 1.546 0 0 1 -1.2.78.688.688 0 0 0 -.636.749.707.707 0 0 0 .717.6.789.789 0 0 0 .082 0 2.989 2.989 0 0 0 2.322-1.513 2.669 2.669 0 0 0 -.377-3.084 1.767 1.767 0 0 0 1.184-.867zm33.217 1.2a3.021 3.021 0 0 0 -2.658-1.525 1.574 1.574 0 0 0 -.107-1.283l-.745-1.367a1.779 1.779 0 0 0 -1.317-.891l-.7-1.278a2.409 2.409 0 0 0 .229-2.661 2.283 2.283 0 0 0 -2.375-1.454 7.039 7.039 0 0 1 0 3 3.272 3.272 0 0 0 0 1.5c.047.152-.047.3 0 .5.227.04-.069.156.165.14l.653 1.2a1.579 1.579 0 0 0 -.019 1.557l.745 1.367a1.753 1.753 0 0 0 1.045.832 2.66 2.66 0 0 0 -.238 2.916 2.989 2.989 0 0 0 2.326 1.509.79.79 0 0 0 .082 0 .707.707 0 0 0 .717-.6.688.688 0 0 0 -.636-.749 1.546 1.546 0 0 1 -1.2-.78 1.408 1.408 0 0 1 .672-1.95 1.628 1.628 0 0 1 1.179-.089 1.512 1.512 0 0 1 .9.719 1.37 1.37 0 0 1 -.023 1.361.656.656 0 0 0 .284.92.748.748 0 0 0 .981-.266 2.648 2.648 0 0 0 .04-2.633zm-19.673-11.959a13.013 13.013 0 0 1 5-1 21.6 21.6 0 0 1 4.5.5 9.312 9.312 0 0 0 -9.5-8.5c-5.794 0-9.176 4-9.5 8.5a21.858 21.858 0 0 1 4.5-.5 12.819 12.819 0 0 1 5 1zm3.5-5c1.209 0 2.5.866 2.5 2h-5c0-1.134 1.291-2 2.5-2zm-7 0c1.209 0 2.5.866 2.5 2h-5c0-1.134 1.291-2 2.5-2z" fill-rule="evenodd" class="ColorScheme-Text" fill="currentColor"/>
</svg>

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -2,7 +2,7 @@ Source: cryptomator
Maintainer: Cryptobot <releases@cryptomator.org>
Section: utils
Priority: optional
Build-Depends: debhelper (>=10), coffeelibs-jdk-21 (= 21.0.1+12-0ppa1), libgtk2.0-0, libgtk-3-0, libxxf86vm1, libgl1
Build-Depends: debhelper (>=10), coffeelibs-jdk-23 (>= 23.0.2+7-0ppa1), libgtk-3-0, libxxf86vm1, libgl1
Standards-Version: 4.5.0
Homepage: https://cryptomator.org
Vcs-Git: https://github.com/cryptomator/cryptomator.git

View File

@@ -4,11 +4,11 @@ Upstream-Contact: Cryptomator <info@cryptomator.org>
Source: https://cryptomator.org
Files: *
Copyright: 2016-2024 Skymatic GmbH
Copyright: 2016-2025 Skymatic GmbH
License: GPL-3+
Files: debian/org.cryptomator.Cryptomator.appdata.xml
Copyright: 2016-2024 Skymatic GmbH
Copyright: 2016-2025 Skymatic GmbH
License: FSFAP
License: GPL-3+

View File

@@ -4,7 +4,7 @@
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
JAVA_HOME = /usr/lib/jvm/java-21-coffeelibs
JAVA_HOME = /usr/lib/jvm/java-23-coffeelibs
DEB_BUILD_ARCH ?= $(shell dpkg-architecture -qDEB_BUILD_ARCH)
ifeq ($(DEB_BUILD_ARCH),amd64)
JMODS_PATH = jmods/amd64:${JAVA_HOME}/jmods
@@ -28,7 +28,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.security.auth,jdk.accessibility,jdk.management.jfr,jdk.net \
--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.security.auth,jdk.accessibility,jdk.management.jfr,jdk.net,java.compiler \
--strip-native-commands \
--no-header-files \
--no-man-pages \
@@ -45,7 +45,7 @@ override_dh_auto_build:
--vendor "Skymatic GmbH" \
--java-options "--enable-preview" \
--java-options "--enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator" \
--copyright "(C) 2016 - 2024 Skymatic GmbH" \
--copyright "(C) 2016 - 2025 Skymatic GmbH" \
--java-options "-Xss5m" \
--java-options "-Xmx256m" \
--java-options "-Dfile.encoding=\"utf-8\"" \
@@ -61,6 +61,8 @@ override_dh_auto_build:
--java-options "-Dcryptomator.buildNumber=\"deb-${REVISION_NUM}\"" \
--java-options "-Dcryptomator.appVersion=\"${SEMVER_STR}\"" \
--java-options "-Dcryptomator.disableUpdateCheck=\"${DISABLE_UPDATE_CHECK}\"" \
--java-options "-Dcryptomator.integrationsLinux.autoStartCmd=\"cryptomator\"" \
--java-options "-Dcryptomator.networking.truststore.p12Path=\"/etc/cryptomator/certs.p12\"" \
--app-version "${VERSION_NUM}.${REVISION_NUM}" \
--resource-dir resources \
--verbose

View File

@@ -1,14 +0,0 @@
java-options=-Xss5m \
-Xmx256m \
--enable-preview \
--enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64 \
-Dfile.encoding=\"utf-8\" \
-Dcryptomator.appVersion=\"${SEMVER_STR}\" \
-Dcryptomator.logDir=\"~/.local/share/Cryptomator/logs\" \
-Dcryptomator.pluginDir=\"~/.local/share/Cryptomator/plugins\" \
-Dcryptomator.settingsPath=\"~/.config/Cryptomator/settings.json:~/.Cryptomator/settings.json\" \
-Dcryptomator.ipcSocketPath=\"~/.config/Cryptomator/ipc.socket\" \
-Dcryptomator.mountPointsDir=\"~/.local/share/Cryptomator/mnt\" \
-Dcryptomator.showTrayIcon=false \
-Dcryptomator.buildNumber=\"appimage-${REVISION_NUM}\" \
-Djdk.gtk.version=2

1
dist/mac/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
embedded.provisionprofile

View File

@@ -2,6 +2,10 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.application-identifier</key>
<string>###APP_IDENTIFIER_PREFIX###org.cryptomator</string>
<key>com.apple.developer.team-identifier</key>
<string>###TEAM_IDENTIFIER###</string>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
@@ -10,5 +14,9 @@
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>keychain-access-groups</key>
<array>
<string>###APP_IDENTIFIER_PREFIX###org.cryptomator</string>
</array>
</dict>
</plist>

View File

@@ -1,6 +1,9 @@
# created during build
# downloaded/created during build
Cryptomator.app/
runtime/
dmg/
*.dmg
license.rtf
license.rtf
openjfx-jmods.zip
*.jmod
Cryptomator.entitlements

42
dist/mac/dmg/build.sh vendored
View File

@@ -1,12 +1,15 @@
#!/bin/bash
# parse options
usage() { echo "Usage: $0 [-s <codesign-identity>]" 1>&2; exit 1; }
while getopts ":s:" o; do
usage() { echo "Usage: $0 [-s <codesign-identity>] [-t <team-identifier>]" 1>&2; exit 1; }
while getopts ":s:t:" o; do
case "${o}" in
s)
CODESIGN_IDENTITY=${OPTARG}
;;
t)
TEAM_IDENTIFIER=${OPTARG}
;;
*)
usage
;;
@@ -21,7 +24,7 @@ rm -rf runtime dmg *.app *.dmg
# set variables
APP_NAME="Cryptomator"
VENDOR="Skymatic GmbH"
COPYRIGHT_YEARS="2016 - 2024"
COPYRIGHT_YEARS="2016 - 2025"
PACKAGE_IDENTIFIER="org.cryptomator"
MAIN_JAR_GLOB="cryptomator-*.jar"
MODULE_AND_MAIN_CLASS="org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator"
@@ -29,13 +32,17 @@ 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"
ARCH="undefined"
JAVAFX_VERSION=23.0.2
JAVAFX_ARCH="undefined"
JAVAFX_JMODS_SHA256="undefined"
if [ "$(machine)" = "arm64e" ]; then
ARCH="aarch64"
JAVAFX_ARCH="aarch64"
JAVAFX_JMODS_SHA256="c690cc642a3924cf56622951f478ba57aec9ce09063761f800c3319331bed3fc"
else
ARCH="x64"
JAVAFX_ARCH="x64"
JAVAFX_JMODS_SHA256="5e6c65c065eea22430c0eab36f37a5985eb8ad99e19e8772262021740d338f68"
fi
OPENJFX_JMODS="https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_osx-${ARCH}_bin-jmods.zip"
JAVAFX_JMODS_URL="https://download2.gluonhq.com/openjfx/${JAVAFX_VERSION}/openjfx-${JAVAFX_VERSION}_osx-${JAVAFX_ARCH}_bin-jmods.zip"
# check preconditions
if [ -z "${JAVA_HOME}" ]; then echo "JAVA_HOME not set. Run using JAVA_HOME=/path/to/jdk ./build.sh"; exit 1; fi
@@ -47,7 +54,8 @@ if [ -n "${CODESIGN_IDENTITY}" ]; then
fi
# download and check jmods
curl -L ${OPENJFX_JMODS} -o openjfx-jmods.zip
curl -L ${JAVAFX_JMODS_URL} -o openjfx-jmods.zip
echo "${JAVAFX_JMODS_SHA256} openjfx-jmods.zip" | shasum -a256 --check
mkdir -p openjfx-jmods/
unzip -jo openjfx-jmods.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d openjfx-jmods
JMOD_VERSION=$(jmod describe openjfx-jmods/javafx.base.jmod | head -1)
@@ -63,7 +71,7 @@ if [ "${POM_JFX_VERSION}" -ne "${JMOD_VERSION}" ]; then
fi
# compile
mvn -B -f../../../pom.xml clean package -DskipTests -Pmac
mvn -B -Djavafx.platform=mac -f../../../pom.xml clean package -DskipTests -Pmac
cp ../../../LICENSE.txt ../../../target
cp ../../../target/${MAIN_JAR_GLOB} ../../../target/mods
@@ -71,7 +79,7 @@ cp ../../../target/${MAIN_JAR_GLOB} ../../../target/mods
${JAVA_HOME}/bin/jlink \
--output runtime \
--module-path "${JAVA_HOME}/jmods:openjfx-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.security.auth,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.security.auth,jdk.accessibility,jdk.management.jfr,java.compiler \
--strip-native-commands \
--no-header-files \
--no-man-pages \
@@ -116,9 +124,10 @@ ${JAVA_HOME}/bin/jpackage \
cp ../resources/${APP_NAME}-Vault.icns ${APP_NAME}.app/Contents/Resources/
sed -i '' "s|###BUNDLE_SHORT_VERSION_STRING###|${VERSION_NO}|g" ${APP_NAME}.app/Contents/Info.plist
sed -i '' "s|###BUNDLE_VERSION###|${REVISION_NO}|g" ${APP_NAME}.app/Contents/Info.plist
cp ../embedded.provisionprofile ${APP_NAME}.app/Contents/
# generate license
mvn -B -f../../../pom.xml license:add-third-party \
mvn -B -Djavafx.platform=mac -f../../../pom.xml license:add-third-party \
-Dlicense.thirdPartyFilename=license.rtf \
-Dlicense.outputDirectory=dist/mac/dmg/resources \
-Dlicense.fileTemplate=resources/licenseTemplate.ftl \
@@ -128,7 +137,11 @@ mvn -B -f../../../pom.xml license:add-third-party \
-Dlicense.licenseMergesUrl=file://$(pwd)/../../../license/merges
# codesign
if [ -n "${CODESIGN_IDENTITY}" ]; then
if [ -n "${CODESIGN_IDENTITY}" ] && [ -n "${TEAM_IDENTIFIER}" ]; then
echo "Codesigning jdk files..."
find ${APP_NAME}.app/Contents/runtime/Contents/Home/lib/ -name '*.dylib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \;
find ${APP_NAME}.app/Contents/runtime/Contents/Home/lib/ -name 'jspawnhelper' -exec codesign --force -o runtime -s ${CODESIGN_IDENTITY} {} \;
echo "Codesigning jar contents..."
find ${APP_NAME}.app/Contents/runtime/Contents/MacOS -name '*.dylib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \;
for JAR_PATH in `find ${APP_NAME}.app -name "*.jar"`; do
if [[ `unzip -l ${JAR_PATH} | grep '.dylib\|.jnilib'` ]]; then
@@ -146,7 +159,10 @@ if [ -n "${CODESIGN_IDENTITY}" ]; then
fi
done
echo "Codesigning ${APP_NAME}.app..."
codesign --force --deep --entitlements ../${APP_NAME}.entitlements -o runtime -s ${CODESIGN_IDENTITY} ${APP_NAME}.app
cp ../${APP_NAME}.entitlements .
sed -i '' "s|###APP_IDENTIFIER_PREFIX###|${TEAM_IDENTIFIER}.|g" ${APP_NAME}.entitlements
sed -i '' "s|###TEAM_IDENTIFIER###|${TEAM_IDENTIFIER}|g" ${APP_NAME}.entitlements
codesign --force --deep --entitlements ${APP_NAME}.entitlements -o runtime -s ${CODESIGN_IDENTITY} ${APP_NAME}.app
fi
# prepare dmg contents

View File

@@ -17,7 +17,7 @@
\f1\b0 \
\
\f0\b \'a9 2016 \'96 2024 Skymatic GmbH
\f0\b \'a9 2016 \'96 2025 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.\

View File

@@ -3,7 +3,7 @@
<plist version="1.0">
<dict>
<key>LSMinimumSystemVersion</key>
<string>10.13.0</string>
<string>11</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleAllowMixedLocalizations</key>

1
dist/win/.gitignore vendored
View File

@@ -6,4 +6,5 @@ installer
*.msi
*.exe
*.jmod
resources/jfxJmods.zip
license.rtf

2
dist/win/build.bat vendored
View File

@@ -11,7 +11,7 @@ SET HELP_URL="https://cryptomator.org/contact/"
SET MODULE_AND_MAIN_CLASS="org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator"
SET LOOPBACK_ALIAS="cryptomator-vault"
powershell -NoLogo -NoProfile -ExecutionPolicy Unrestricted -Command .\build.ps1^
pwsh -NoLogo -NoProfile -ExecutionPolicy Unrestricted -Command .\build.ps1^
-AppName %APPNAME%^
-MainJarGlob "%MAIN_JAR_GLOB%"^
-ModuleAndMainClass "%MODULE_AND_MAIN_CLASS%"^

37
dist/win/build.ps1 vendored
View File

@@ -41,7 +41,7 @@ Write-Output "`$Env:JAVA_HOME=$Env:JAVA_HOME"
$copyright = "(C) $CopyrightStartYear - $((Get-Date).Year) $Vendor"
# compile
&mvn -B -f $buildDir/../../pom.xml clean package -DskipTests -Pwin
&mvn -B -f $buildDir/../../pom.xml clean package -DskipTests -Pwin "-Djavafx.platform=win"
Copy-Item "$buildDir\..\..\target\$MainJarGlob.jar" -Destination "$buildDir\..\..\target\mods"
# add runtime
@@ -51,22 +51,23 @@ if ($clean -and (Test-Path -Path $runtimeImagePath)) {
}
## download jfx jmods
$jmodsVersion='21.0.1'
$jmodsUrl = "https://download2.gluonhq.com/openjfx/${jmodsVersion}/openjfx-${jmodsVersion}_windows-x64_bin-jmods.zip"
$jfxJmodsChecksum = 'daf8acae631c016c24cfe23f88469400274d3441dd890615a42dfb501f3eb94a'
$jfxJmodsZip = '.\resources\jfxJmods.zip'
if( !(Test-Path -Path $jfxJmodsZip) ) {
Write-Output "Downloading ${jmodsUrl}..."
Invoke-WebRequest $jmodsUrl -OutFile $jfxJmodsZip # redirects are followed by default
$javaFxVersion='23.0.2'
$javaFxJmodsUrl = "https://download2.gluonhq.com/openjfx/${javaFxVersion}/openjfx-${javaFxVersion}_windows-x64_bin-jmods.zip"
$javaFxJmodsSHA256 = 'ee176dcee3bd78bde7910735bd67f67c792882f5b89626796ae06f7a1c0119d3'
$javaFxJmods = '.\resources\jfxJmods.zip'
if( !(Test-Path -Path $javaFxJmods) ) {
Write-Output "Downloading ${javaFxJmodsUrl}..."
Invoke-WebRequest $javaFxJmodsUrl -OutFile $javaFxJmods # redirects are followed by default
}
$jmodsChecksumActual = $(Get-FileHash -Path $jfxJmodsZip -Algorithm SHA256).Hash
if( $jmodsChecksumActual -ne $jfxJmodsChecksum ) {
Write-Error "Checksum mismatch for jfxJmods.zip. Expected: $jfxJmodsChecksum, actual: $jmodsChecksumActual"
$jmodsChecksumActual = $(Get-FileHash -Path $javaFxJmods -Algorithm SHA256).Hash.ToLower()
if( $jmodsChecksumActual -ne $javaFxJmodsSHA256 ) {
Write-Error "Checksum mismatch for jfxJmods.zip. Expected: $javaFxJmodsSHA256
, actual: $jmodsChecksumActual"
exit 1;
}
Expand-Archive -Path $jfxJmodsZip -Force -DestinationPath ".\resources\"
Remove-Item -Recurse -Force -Path ".\resources\javafx-jmods"
Expand-Archive -Path $javaFxJmods -Force -DestinationPath ".\resources\"
Remove-Item -Recurse -Force -Path ".\resources\javafx-jmods" -ErrorAction Ignore
Move-Item -Force -Path ".\resources\javafx-jmods-*" -Destination ".\resources\javafx-jmods" -ErrorAction Stop
## create custom runtime
@@ -74,7 +75,7 @@ Move-Item -Force -Path ".\resources\javafx-jmods-*" -Destination ".\resources\ja
--verbose `
--output runtime `
--module-path "$Env:JAVA_HOME/jmods;$buildDir/resources/javafx-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,javafx.base,javafx.graphics,javafx.controls,javafx.fxml `
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.accessibility,jdk.management.jfr,jdk.crypto.mscapi,java.compiler,javafx.base,javafx.graphics,javafx.controls,javafx.fxml `
--strip-native-commands `
--no-header-files `
--no-man-pages `
@@ -99,7 +100,7 @@ if ($clean -and (Test-Path -Path $appPath)) {
--vendor $Vendor `
--copyright $copyright `
--java-options "--enable-preview" `
--java-options "--enable-native-access=org.cryptomator.jfuse.win" `
--java-options "--enable-native-access=org.cryptomator.jfuse.win,org.cryptomator.integrations.win" `
--java-options "-Xss5m" `
--java-options "-Xmx256m" `
--java-options "-Dcryptomator.appVersion=`"$semVerNo`"" `
@@ -121,7 +122,7 @@ if ($clean -and (Test-Path -Path $appPath)) {
--icon resources/$AppName.ico
#Create RTF license for msi
&mvn -B -f $buildDir/../../pom.xml license:add-third-party `
&mvn -B -f $buildDir/../../pom.xml license:add-third-party "-Djavafx.platform=win" `
"-Dlicense.thirdPartyFilename=license.rtf" `
"-Dlicense.fileTemplate=$buildDir\resources\licenseTemplate.ftl" `
"-Dlicense.outputDirectory=$buildDir\resources\" `
@@ -166,7 +167,7 @@ $Env:JP_WIXHELPER_DIR = "."
--file-associations resources/FAvaultFile.properties
#Create RTF license for bundle
&mvn -B -f $buildDir/../../pom.xml license:add-third-party `
&mvn -B -f $buildDir/../../pom.xml license:add-third-party "-Djavafx.platform=win" `
"-Dlicense.thirdPartyFilename=license.rtf" `
"-Dlicense.fileTemplate=$buildDir\bundle\resources\licenseTemplate.ftl" `
"-Dlicense.outputDirectory=$buildDir\bundle\resources\" `
@@ -181,7 +182,7 @@ Write-Output "Downloading ${winfspMsiUrl}..."
Invoke-WebRequest $winfspMsiUrl -OutFile ".\bundle\resources\winfsp.msi" # redirects are followed by default
# download legacy-winfsp uninstaller
$winfspUninstaller= 'https://github.com/cryptomator/winfsp-uninstaller/releases/download/1.0.0/winfsp-uninstaller.exe'
$winfspUninstaller= 'https://github.com/cryptomator/winfsp-uninstaller/releases/latest/download/winfsp-uninstaller.exe'
Write-Output "Downloading ${winfspUninstaller}..."
Invoke-WebRequest $winfspUninstaller -OutFile ".\bundle\resources\winfsp-uninstaller.exe" # redirects are followed by default

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 2024 Skymatic GmbH \b0\par
\b\'a9 2016 \'96 2025 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

Binary file not shown.

View File

@@ -1,5 +0,0 @@
@echo off
:: see comments in file ./version170-migrate-settings.ps1
cd %~dp0
powershell -NoLogo -NoProfile -NonInteractive -ExecutionPolicy RemoteSigned -Command .\version170-migrate-settings.ps1

View File

@@ -1,35 +0,0 @@
# 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
}
}

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 2024 Skymatic GmbH \b0\par
\b\'a9 2016 \'96 2025 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

View File

@@ -139,11 +139,6 @@
Sequence="execute" Before="PatchWebDAV" />
<CustomAction Id="PatchWebDAV" BinaryKey="WixCA" DllEntry="WixQuietExec64" Execute="deferred" Return="ignore" Impersonate="no"/>
<!-- Special Settings migration for 1.7.0,. Should be removed eventually, for more info, see ../contrib/version170-migrate-settings.ps1-->
<SetProperty Id="V170MigrateSettings" Value="&quot;[INSTALLDIR]version170-migrate-settings.bat&quot;"
Sequence="execute" Before="V170MigrateSettings" />
<CustomAction Id="V170MigrateSettings" BinaryKey="WixCA" DllEntry="WixQuietExec64" Execute="deferred" Return="ignore" Impersonate="no"/>
<!-- Running App detection and exit -->
<Property Id="FOUNDRUNNINGAPP" Admin="yes"/>
<util:CloseApplication
@@ -195,7 +190,6 @@
<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>

153
pom.xml
View File

@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.cryptomator</groupId>
<artifactId>cryptomator</artifactId>
<version>1.12.0</version>
<version>1.16.2</version>
<name>Cryptomator Desktop App</name>
<organization>
@@ -26,56 +26,73 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.jdk.version>21</project.jdk.version>
<project.jdk.version>23</project.jdk.version>
<!-- Group IDs of jars that need to stay on the class path for now -->
<!-- remove them, as soon they got modularized or support is dropped (i.e., WebDAV) -->
<nonModularGroupIds>org.ow2.asm,org.apache.jackrabbit,org.apache.httpcomponents</nonModularGroupIds>
<!-- cryptomator dependencies -->
<cryptomator.cryptofs.version>2.6.8</cryptomator.cryptofs.version>
<cryptomator.integrations.version>1.3.0</cryptomator.integrations.version>
<cryptomator.integrations.win.version>1.2.5</cryptomator.integrations.win.version>
<cryptomator.integrations.mac.version>1.2.3</cryptomator.integrations.mac.version>
<cryptomator.integrations.linux.version>1.4.2</cryptomator.integrations.linux.version>
<cryptomator.fuse.version>4.0.0</cryptomator.fuse.version>
<cryptomator.dokany.version>2.0.0</cryptomator.dokany.version>
<cryptomator.webdav.version>2.0.6</cryptomator.webdav.version>
<cryptomator.cryptofs.version>2.9.0</cryptomator.cryptofs.version>
<cryptomator.integrations.version>1.5.1</cryptomator.integrations.version>
<cryptomator.integrations.win.version>1.3.0</cryptomator.integrations.win.version>
<cryptomator.integrations.mac.version>1.3.2</cryptomator.integrations.mac.version>
<cryptomator.integrations.linux.version>1.5.3</cryptomator.integrations.linux.version>
<cryptomator.fuse.version>5.0.5</cryptomator.fuse.version>
<cryptomator.webdav.version>2.0.10</cryptomator.webdav.version>
<!-- 3rd party dependencies -->
<commons-lang3.version>3.14.0</commons-lang3.version>
<dagger.version>2.50</dagger.version>
<commons-lang3.version>3.17.0</commons-lang3.version>
<dagger.version>2.56.1</dagger.version>
<easybind.version>2.2</easybind.version>
<guava.version>33.0.0-jre</guava.version>
<jackson.version>2.16.1</jackson.version>
<javafx.version>21.0.1</javafx.version>
<jwt.version>4.4.0</jwt.version>
<jackson.version>2.18.3</jackson.version>
<javafx.version>23.0.2</javafx.version>
<jwt.version>4.5.0</jwt.version>
<nimbus-jose.version>9.37.3</nimbus-jose.version>
<logback.version>1.4.14</logback.version>
<slf4j.version>2.0.11</slf4j.version>
<tinyoauth2.version>0.8.0</tinyoauth2.version>
<zxcvbn.version>1.8.2</zxcvbn.version>
<logback.version>1.5.18</logback.version>
<slf4j.version>2.0.17</slf4j.version>
<tinyoauth2.version>0.8.1</tinyoauth2.version>
<zxcvbn.version>1.9.0</zxcvbn.version>
<!-- test dependencies -->
<junit.jupiter.version>5.10.2</junit.jupiter.version>
<mockito.version>5.10.0</mockito.version>
<hamcrest.version>2.2</hamcrest.version>
<junit.jupiter.version>5.12.2</junit.jupiter.version>
<mockito.version>5.17.0</mockito.version>
<hamcrest.version>3.0</hamcrest.version>
<!-- build-time dependencies -->
<jetbrains.annotations.version>24.1.0</jetbrains.annotations.version>
<dependency-check.version>9.0.9</dependency-check.version>
<jacoco.version>0.8.11</jacoco.version>
<license-generator.version>2.4.0</license-generator.version>
<junit-tree-reporter.version>1.2.1</junit-tree-reporter.version>
<mvn-compiler.version>3.12.1</mvn-compiler.version>
<jetbrains.annotations.version>26.0.2</jetbrains.annotations.version>
<dependency-check.version>12.1.1</dependency-check.version>
<jacoco.version>0.8.13</jacoco.version>
<license-generator.version>2.5.0</license-generator.version>
<junit-tree-reporter.version>1.4.0</junit-tree-reporter.version>
<mvn-compiler.version>3.14.0</mvn-compiler.version>
<mvn-resources.version>3.3.1</mvn-resources.version>
<mvn-dependency.version>3.6.1</mvn-dependency.version>
<mvn-surefire.version>3.2.5</mvn-surefire.version>
<mvn-jar.version>3.3.0</mvn-jar.version>
<mvn-dependency.version>3.8.1</mvn-dependency.version>
<mvn-surefire.version>3.5.3</mvn-surefire.version>
<mvn-jar.version>3.4.2</mvn-jar.version>
<!-- Property used by surefire to determine jacoco engine -->
<surefire.jacoco.args></surefire.jacoco.args>
</properties>
<!-- TODO: Remove once webdav version 2.0.11 is released -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.cryptomator</groupId>
<artifactId>webdav-nio-adapter-servlet</artifactId>
<version>1.2.9</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Cryptomator Libs -->
<dependency>
<groupId>org.cryptomator</groupId>
<artifactId>cryptolib</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.cryptomator</groupId>
<artifactId>cryptofs</artifactId>
@@ -86,11 +103,6 @@
<artifactId>fuse-nio-adapter</artifactId>
<version>${cryptomator.fuse.version}</version>
</dependency>
<dependency>
<groupId>org.cryptomator</groupId>
<artifactId>dokany-nio-adapter</artifactId>
<version>${cryptomator.dokany.version}</version>
</dependency>
<dependency>
<groupId>org.cryptomator</groupId>
<artifactId>webdav-nio-adapter</artifactId>
@@ -158,17 +170,30 @@
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>${jwt.version}</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>${nimbus-jose.version}</version>
</dependency>
<!-- Jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- EasyBind -->
<dependency>
@@ -185,40 +210,23 @@
</dependency>
<!-- Google -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
<exclusions>
<!-- see https://github.com/google/guava/wiki/UseGuavaInYourBuild#what-about-guavas-own-dependencies -->
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>listenablefuture</artifactId>
</exclusion>
<exclusion>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
</exclusion>
<exclusion>
<groupId>org.checkerframework</groupId>
<artifactId>checker-qual</artifactId>
</exclusion>
<exclusion>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_annotations</artifactId>
</exclusion>
<exclusion>
<groupId>com.google.j2objc</groupId>
<artifactId>j2objc-annotations</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.dagger</groupId>
<artifactId>dagger</artifactId>
<version>${dagger.version}</version>
</dependency>
<dependency>
<groupId>jakarta.inject</groupId>
<artifactId>jakarta.inject-api</artifactId>
<version>2.0.1</version>
</dependency>
<!-- Caffeine -->
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>3.2.0</version>
</dependency>
<!-- JUnit / Mockito / Hamcrest -->
<dependency>
<groupId>org.junit.jupiter</groupId>
@@ -320,7 +328,6 @@
<compilerArgs>
<arg>-Adagger.fastInit=enabled</arg>
<arg>-Adagger.formatGeneratedSource=enabled</arg>
<arg>--enable-preview</arg>
</compilerArgs>
</configuration>
</plugin>
@@ -347,11 +354,11 @@
</dependency>
</dependencies>
<configuration>
<argLine>--enable-preview</argLine>
<reportFormat>plain</reportFormat>
<consoleOutputReporter>
<disable>true</disable>
</consoleOutputReporter>
<argLine>@{surefire.jacoco.args} -javaagent:${org.mockito:mockito-core:jar}</argLine>
<statelessTestsetInfoReporter
implementation="org.apache.maven.plugin.surefire.extensions.junit5.JUnit5StatelessTestsetInfoTreeReporter">
</statelessTestsetInfoReporter>
@@ -361,6 +368,13 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>jar-paths-to-properties</id>
<phase>validate</phase>
<goals>
<goal>properties</goal>
</goals>
</execution>
<!-- sort jars into two buckets (classpath and modulepath). exclude openjfx, which gets jlinked separately -->
<execution>
<id>copy-mods</id>
@@ -433,6 +447,9 @@
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<propertyName>surefire.jacoco.args</propertyName>
</configuration>
</execution>
<execution>
<id>report</id>
@@ -465,7 +482,7 @@
<skipTestScope>true</skipTestScope>
<detail>true</detail>
<suppressionFile>suppression.xml</suppressionFile>
<nvdApiKey>${env.NVD_API_KEY}</nvdApiKey>
<nvdApiKeyEnvironmentVariable>NVD_API_KEY</nvdApiKeyEnvironmentVariable>
</configuration>
<executions>
<execution>

View File

@@ -1,8 +1,10 @@
import ch.qos.logback.classic.spi.Configurator;
import org.cryptomator.networking.SSLContextWithPKCS12TrustStore;
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.GoogleDriveMacLocationPresetsProvider;
import org.cryptomator.common.locationpresets.GoogleDriveWindowsLocationPresetsProvider;
import org.cryptomator.common.locationpresets.ICloudMacLocationPresetsProvider;
import org.cryptomator.common.locationpresets.ICloudWindowsLocationPresetsProvider;
import org.cryptomator.common.locationpresets.LeitzcloudLocationPresetsProvider;
@@ -12,6 +14,9 @@ import org.cryptomator.common.locationpresets.OneDriveLinuxLocationPresetsProvid
import org.cryptomator.common.locationpresets.OneDriveMacLocationPresetsProvider;
import org.cryptomator.common.locationpresets.OneDriveWindowsLocationPresetsProvider;
import org.cryptomator.common.locationpresets.PCloudLocationPresetsProvider;
import org.cryptomator.networking.SSLContextWithMacKeychain;
import org.cryptomator.networking.SSLContextProvider;
import org.cryptomator.networking.SSLContextWithWindowsCertStore;
import org.cryptomator.integrations.tray.TrayMenuController;
import org.cryptomator.logging.LogbackConfiguratorFactory;
import org.cryptomator.ui.traymenu.AwtTrayMenuController;
@@ -21,7 +26,6 @@ open module org.cryptomator.desktop {
requires org.cryptomator.cryptolib;
requires org.cryptomator.cryptofs;
requires org.cryptomator.frontend.dokany;
requires org.cryptomator.frontend.fuse;
requires org.cryptomator.frontend.webdav;
requires org.cryptomator.integrations.api;
@@ -32,13 +36,13 @@ open module org.cryptomator.desktop {
requires javafx.graphics;
requires javafx.controls;
requires javafx.fxml;
requires jdk.crypto.ec;
// 3rd party:
requires ch.qos.logback.classic;
requires ch.qos.logback.core;
requires com.auth0.jwt;
requires com.google.common;
requires com.fasterxml.jackson.databind;
requires com.fasterxml.jackson.datatype.jsr310;
requires com.nimbusds.jose.jwt;
requires com.nulabinc.zxcvbn;
requires com.tobiasdiez.easybind;
@@ -47,16 +51,22 @@ open module org.cryptomator.desktop {
requires org.slf4j;
requires org.apache.commons.lang3;
/* TODO: filename-based modules: */
requires static javax.inject; /* ugly dagger/guava crap */
/* dagger bs */
requires jakarta.inject;
requires static javax.inject;
requires java.compiler;
requires com.github.benmanes.caffeine;
uses org.cryptomator.common.locationpresets.LocationPresetsProvider;
uses SSLContextProvider;
uses org.cryptomator.event.NotificationHandler;
provides TrayMenuController with AwtTrayMenuController;
provides Configurator with LogbackConfiguratorFactory;
provides SSLContextProvider with SSLContextWithWindowsCertStore, SSLContextWithMacKeychain, SSLContextWithPKCS12TrustStore;
provides LocationPresetsProvider with //
DropboxWindowsLocationPresetsProvider, DropboxMacLocationPresetsProvider, DropboxLinuxLocationPresetsProvider, //
GoogleDriveLocationPresetsProvider, //
GoogleDriveMacLocationPresetsProvider, GoogleDriveWindowsLocationPresetsProvider, //
ICloudWindowsLocationPresetsProvider, ICloudMacLocationPresetsProvider, //
LeitzcloudLocationPresetsProvider, //
MegaLocationPresetsProvider, //

View File

@@ -0,0 +1,22 @@
package org.cryptomator;
import javafx.application.Platform;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class JavaFXUtil {
private JavaFXUtil() {}
public static boolean startPlatform() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
try {
Platform.startup(latch::countDown);
} catch (IllegalStateException e) {
//already initialized
latch.countDown();
}
return latch.await(5, TimeUnit.SECONDS);
}
}

View File

@@ -0,0 +1,160 @@
package org.cryptomator.common;
import org.cryptomator.cryptofs.event.BrokenDirFileEvent;
import org.cryptomator.cryptofs.event.BrokenFileNodeEvent;
import org.cryptomator.cryptofs.event.ConflictResolutionFailedEvent;
import org.cryptomator.cryptofs.event.ConflictResolvedEvent;
import org.cryptomator.cryptofs.event.DecryptionFailedEvent;
import org.cryptomator.cryptofs.event.FilesystemEvent;
import org.cryptomator.event.VaultEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.inject.Inject;
import javax.inject.Singleton;
import javafx.beans.InvalidationListener;
import javafx.collections.FXCollections;
import javafx.collections.MapChangeListener;
import javafx.collections.ObservableMap;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Comparator;
import java.util.Map;
import java.util.Set;
/**
* Map containing {@link VaultEvent}s.
* The map is keyed by the ciphertext path of the affected resource _and_ the {@link FilesystemEvent}s class in order to group same events
* <p>
* Use {@link EventMap#put(VaultEvent)} to add an element and {@link EventMap#remove(VaultEvent)} to remove it.
* <p>
* The map is size restricted to {@value MAX_SIZE} elements. If a _new_ element (i.e. not already present) is added, the least recently added is removed.
*/
@Singleton
public class EventMap implements ObservableMap<EventMap.EventKey, VaultEvent> {
private static final int MAX_SIZE = 300;
public record EventKey(Path ciphertextPath, Class<? extends FilesystemEvent> c) {}
private final ObservableMap<EventMap.EventKey, VaultEvent> delegate;
@Inject
public EventMap() {
delegate = FXCollections.observableHashMap();
}
@Override
public void addListener(MapChangeListener<? super EventKey, ? super VaultEvent> mapChangeListener) {
delegate.addListener(mapChangeListener);
}
@Override
public void removeListener(MapChangeListener<? super EventKey, ? super VaultEvent> mapChangeListener) {
delegate.removeListener(mapChangeListener);
}
@Override
public int size() {
return delegate.size();
}
@Override
public boolean isEmpty() {
return delegate.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return delegate.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return delegate.containsValue(value);
}
@Override
public VaultEvent get(Object key) {
return delegate.get(key);
}
@Override
public @Nullable VaultEvent put(EventKey key, VaultEvent value) {
return delegate.put(key, value);
}
@Override
public VaultEvent remove(Object key) {
return delegate.remove(key);
}
@Override
public void putAll(@NotNull Map<? extends EventKey, ? extends VaultEvent> m) {
delegate.putAll(m);
}
@Override
public void clear() {
delegate.clear();
}
@Override
public @NotNull Set<EventKey> keySet() {
return delegate.keySet();
}
@Override
public @NotNull Collection<VaultEvent> values() {
return delegate.values();
}
@Override
public @NotNull Set<Entry<EventKey, VaultEvent>> entrySet() {
return delegate.entrySet();
}
@Override
public void addListener(InvalidationListener invalidationListener) {
delegate.addListener(invalidationListener);
}
@Override
public void removeListener(InvalidationListener invalidationListener) {
delegate.removeListener(invalidationListener);
}
public synchronized void put(VaultEvent e) {
//compute key
var key = computeKey(e.actualEvent());
//if-else
var nullOrEntry = delegate.get(key);
if (nullOrEntry == null) {
if (size() == MAX_SIZE) {
delegate.entrySet().stream() //
.min(Comparator.comparing(entry -> entry.getValue().actualEvent().getTimestamp())) //
.ifPresent(oldestEntry -> delegate.remove(oldestEntry.getKey()));
}
delegate.put(key, e);
} else {
delegate.put(key, nullOrEntry.incrementCount(e.actualEvent()));
}
}
public synchronized VaultEvent remove(VaultEvent similar) {
//compute key
var key = computeKey(similar.actualEvent());
return this.remove(key);
}
private EventKey computeKey(FilesystemEvent e) {
var p = switch (e) {
case DecryptionFailedEvent(_, Path ciphertextPath, _) -> ciphertextPath;
case ConflictResolvedEvent(_, _, _, _, Path resolvedCiphertext) -> resolvedCiphertext;
case ConflictResolutionFailedEvent(_, _, Path conflictingCiphertext, _) -> conflictingCiphertext;
case BrokenDirFileEvent(_, Path ciphertext) -> ciphertext;
case BrokenFileNodeEvent(_, _, Path ciphertext) -> ciphertext;
};
return new EventKey(p, e.getClass());
}
}

View File

@@ -5,6 +5,7 @@ import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SubstitutingProperties extends PropertiesDecorator {
@@ -58,7 +59,7 @@ public class SubstitutingProperties extends PropertiesDecorator {
LoggerFactory.getLogger(SubstitutingProperties.class).warn("Variable {} used for substitution not found in {}. Replaced with empty string.", key, src);
return "";
} else {
return val.replace("\\", "\\\\");
return Matcher.quoteReplacement(val);
}
}

View File

@@ -1,8 +1,8 @@
package org.cryptomator.common.keychain;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import org.cryptomator.common.Passphrase;
import org.cryptomator.integrations.keychain.KeychainAccessException;
import org.cryptomator.integrations.keychain.KeychainAccessProvider;
@@ -14,20 +14,24 @@ import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@Singleton
public class KeychainManager implements KeychainAccessProvider {
private final ObjectExpression<KeychainAccessProvider> keychain;
private final LoadingCache<String, BooleanProperty> passphraseStoredProperties;
private final ReentrantReadWriteLock lock;
@Inject
KeychainManager(ObjectExpression<KeychainAccessProvider> selectedKeychain) {
this.keychain = selectedKeychain;
this.passphraseStoredProperties = CacheBuilder.newBuilder() //
.weakValues() //
.build(CacheLoader.from(this::createStoredPassphraseProperty));
this.passphraseStoredProperties = Caffeine.newBuilder() //
.softValues() //
.build(this::createStoredPassphraseProperty);
keychain.addListener(ignored -> passphraseStoredProperties.invalidateAll());
this.lock = new ReentrantReadWriteLock(false);
}
private KeychainAccessProvider getKeychainOrFail() throws KeychainAccessException {
@@ -45,27 +49,57 @@ public class KeychainManager implements KeychainAccessProvider {
@Override
public void storePassphrase(String key, String displayName, CharSequence passphrase) throws KeychainAccessException {
getKeychainOrFail().storePassphrase(key, displayName, passphrase);
storePassphrase(key, displayName, passphrase, true);
}
//TODO: remove ignored parameter once the API is fixed
@Override
public void storePassphrase(String key, String displayName, CharSequence passphrase, boolean ignored) throws KeychainAccessException {
try {
lock.writeLock().lock();
var kc = getKeychainOrFail();
//this is the only keychain actually using the parameter
var usesOSAuth = (kc.getClass().getName().equals("org.cryptomator.macos.keychain.TouchIdKeychainAccess"));
kc.storePassphrase(key, displayName, passphrase, usesOSAuth);
} finally {
lock.writeLock().unlock();
}
setPassphraseStored(key, true);
}
@Override
public char[] loadPassphrase(String key) throws KeychainAccessException {
char[] passphrase = getKeychainOrFail().loadPassphrase(key);
char[] passphrase = null;
try {
lock.readLock().lock();
passphrase = getKeychainOrFail().loadPassphrase(key);
} finally {
lock.readLock().unlock();
}
setPassphraseStored(key, passphrase != null);
return passphrase;
}
@Override
public void deletePassphrase(String key) throws KeychainAccessException {
getKeychainOrFail().deletePassphrase(key);
try {
lock.writeLock().lock();
getKeychainOrFail().deletePassphrase(key);
} finally {
lock.writeLock().unlock();
}
setPassphraseStored(key, false);
}
@Override
public void changePassphrase(String key, String displayName, CharSequence passphrase) throws KeychainAccessException {
if (isPassphraseStored(key)) {
getKeychainOrFail().changePassphrase(key, displayName, passphrase);
try {
lock.writeLock().lock();
getKeychainOrFail().changePassphrase(key, displayName, passphrase);
} finally {
lock.writeLock().unlock();
}
setPassphraseStored(key, true);
}
}
@@ -102,13 +136,11 @@ public class KeychainManager implements KeychainAccessProvider {
}
private void setPassphraseStored(String key, boolean value) {
BooleanProperty property = passphraseStoredProperties.getIfPresent(key);
if (property != null) {
if (Platform.isFxApplicationThread()) {
property.set(value);
} else {
Platform.runLater(() -> property.set(value));
}
BooleanProperty property = passphraseStoredProperties.get(key, _ -> new SimpleBooleanProperty(value));
if (Platform.isFxApplicationThread()) {
property.set(value);
} else {
Platform.runLater(() -> property.set(value));
}
}
@@ -124,7 +156,7 @@ public class KeychainManager implements KeychainAccessProvider {
* @see #isPassphraseStored(String)
*/
public ReadOnlyBooleanProperty getPassphraseStoredProperty(String key) {
return passphraseStoredProperties.getUnchecked(key);
return passphraseStoredProperties.get(key);
}
private BooleanProperty createStoredPassphraseProperty(String key) {
@@ -135,4 +167,22 @@ public class KeychainManager implements KeychainAccessProvider {
}
}
public ObjectExpression<KeychainAccessProvider> getKeychainImplementation() {
return this.keychain;
}
public static void migrate(KeychainAccessProvider oldProvider, KeychainAccessProvider newProvider, Map<String, String> idsAndNames) throws KeychainAccessException {
if (oldProvider instanceof KeychainManager || newProvider instanceof KeychainManager) {
throw new IllegalArgumentException("KeychainManger must not be the source or target of migration");
}
for (var entry : idsAndNames.entrySet()) {
var passphrase = oldProvider.loadPassphrase(entry.getKey());
if (passphrase != null) {
var wrapper = new Passphrase(passphrase);
oldProvider.deletePassphrase(entry.getKey()); //we cannot apply "first-write-then-delete" pattern here, since we can potentially write to the same passphrase store (e.g., touchID and regular keychain)
newProvider.storePassphrase(entry.getKey(), entry.getValue(), wrapper);
wrapper.destroy();
}
}
}
}

View File

@@ -0,0 +1,144 @@
package org.cryptomator.common.locationpresets;
import org.cryptomator.integrations.common.CheckAvailability;
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.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
@OperatingSystem(MAC)
@CheckAvailability
public final class GoogleDriveMacLocationPresetsProvider implements LocationPresetsProvider {
private static final Path ROOT_LOCATION = LocationPresetsProvider.resolveLocation("~/Library/CloudStorage/").toAbsolutePath();
private static final Predicate<String> PATTERN = Pattern.compile("^GoogleDrive-[^/]+$").asMatchPredicate();
private static final List<Path> FALLBACK_LOCATIONS = List.of( //
LocationPresetsProvider.resolveLocation("~/GoogleDrive/My Drive"), //
LocationPresetsProvider.resolveLocation("~/Google Drive/My Drive"), //
LocationPresetsProvider.resolveLocation("~/GoogleDrive"), //
LocationPresetsProvider.resolveLocation("~/Google Drive") //
);
@Override
public Stream<LocationPreset> getLocations() {
List<LocationPreset> cloudStorageDirLocations = getCloudStorageDirLocations();
return cloudStorageDirLocations.isEmpty() ? getFallbackLocation().stream() : cloudStorageDirLocations.stream();
}
@CheckAvailability
public static boolean isPresent() {
return isRootLocationPresent() || FALLBACK_LOCATIONS.stream().anyMatch(Files::isDirectory);
}
/**
* Checks if a root location directory is present that matches the specified pattern.
* <p>
* This method scans the {@code ROOT_LOCATION} directory for subdirectories and tests each one against a pre-defined pattern ({@code PATTERN}).
*
* @return {@code true} if a matching root location is present, otherwise {@code false}.
*/
public static boolean isRootLocationPresent() {
try (var dirStream = Files.list(ROOT_LOCATION)) {
return dirStream.anyMatch(path -> Files.isDirectory(path) && PATTERN.test(path.getFileName().toString()));
} catch (IOException | UncheckedIOException e) {
return false;
}
}
/**
* Returns Google Drive preset String.
*
* @param accountPath The path to the Google Drive account directory (e.g. {@code ~/Library/CloudStorage/GoogleDrive-username})
* @return {@code String}. For example: "Google Drive - username"
*/
private String getDriveLocationString(Path accountPath) {
String accountName = accountPath.getFileName().toString().replace("GoogleDrive-", "");
return "Google Drive - " + accountName;
}
/**
* Retrieves a list of cloud storage directory locations based on the {@code ROOT_LOCATION}.
* <p>
* This method lists all directories in the {@code ROOT_LOCATION}, filters them based on whether their names match
* a predefined pattern ({@code PATTERN}), and then extracts presets using {@code getPresetsFromAccountPath(Path)}.
* <p>
*
* @return a list of {@code LocationPreset} objects representing valid cloud storage directory locations.
*/
private List<LocationPreset> getCloudStorageDirLocations() {
try (var dirStream = Files.list(ROOT_LOCATION)) {
return dirStream.filter(path -> Files.isDirectory(path) && PATTERN.test(path.getFileName().toString()))
.flatMap(this::getPresetsFromAccountPath)
.toList();
} catch (IOException | UncheckedIOException e) {
return List.of();
}
}
/**
* Retrieves a stream of {@code LocationPreset} objects from a given Google Drive account path.
* <p>
* This method lists all directories within the provided {@code accountPath} and filters them
* to identify folders whose names match any of the translations defined in {@code MY_DRIVE_TRANSLATIONS}.
*
* @param accountPath the root path of the Google Drive account to scan.
* @return a stream of {@code LocationPreset} objects representing matching directories.
*/
private Stream<LocationPreset> getPresetsFromAccountPath(Path accountPath) {
try (var driveStream = Files.list(accountPath)) {
return driveStream
.filter(preset -> MY_DRIVE_TRANSLATIONS
.contains(preset.getFileName().toString()))
.map(drivePath -> new LocationPreset(
getDriveLocationString(accountPath),
drivePath
)).toList().stream();
} catch (IOException e) {
return Stream.empty();
}
}
/**
* Returns a list containing a fallback location preset for Google Drive.
* <p>
* This method iterates through the predefined fallback locations, checks if any of them is a directory,
* and creates a {@code LocationPreset} object for the first matching directory found.
*
* @return a list containing a single fallback location preset if a valid directory is found, otherwise an empty list.
* @deprecated This method is intended for legacy support and may be removed in future releases.
*/
@Deprecated
private List<LocationPreset> getFallbackLocation() {
return FALLBACK_LOCATIONS.stream()
.filter(Files::isDirectory)
.map(location -> new LocationPreset("Google Drive", location))
.findFirst()
.stream()
.toList();
}
/**
* Set of translations for "My Drive" in various languages.
* <p>
* This constant is used to identify different language-specific labels for "My Drive" in Google Drive.
* <p>
* The translations were originally extracted from the Chromium projects Chrome OS translation files.
* <p>
* Source: `ui/chromeos/translations` directory in the Chromium repository.
*/
private static final Set<String> MY_DRIVE_TRANSLATIONS = Set.of("My Drive", "የእኔ Drive", "ملفاتي", "মোৰ ড্ৰাইভ", "Diskim", "Мой Дыск", "Моят диск", "আমার ড্রাইভ", "Moj disk", "La meva unitat", "Můj disk", "Mit drev", "Meine Ablage", "Το Drive μου", "Mi unidad", "Minu ketas", "Nire unitatea", "Aking Drive", "Oma Drive", "Mon disque", "Mon Drive", "A miña unidade", "મારી ડ્રાઇવ", "मेरी ड्राइव", "Saját meghajtó", "Իմ դրայվը", "Drive Saya", "Drifið mitt", "I miei file", "האחסון שלי", "マイドライブ", "ჩემი Drive", "Менің Drive дискім", "ដ្រាយរបស់ខ្ញុំ", "ನನ್ನ ಡ್ರೈವ್", "내 드라이브", "Менин Drive'ым", "Mano Diskas", "Mans disks", "Мојот Drive", "എന്റെ ഡ്രൈവ്", "Миний Драйв", "माझा ड्राइव्ह", "मेरो ड्राइभ", "Mijn Drive", "Min disk", "ମୋ ଡ୍ରାଇଭ୍", "Mój dysk", "Meu Drive", "O meu disco", "Contul meu Drive", "Мой диск", "මගේ Drive", "Môj disk", "Disku im", "Мој диск", "Min enhet", "Hifadhi Yangu", "எனது இயக்ககம்", "నా డ్రైవ్‌", "ไดรฟ์ของฉัน", "Drive'ım", "Мій диск", "میری ڈرائیو", "Drive của tôi", "我的云端硬盘", "我的雲端硬碟", "IDrayivu yami");
}

View File

@@ -9,13 +9,11 @@ import java.util.Arrays;
import java.util.List;
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 {
public final class GoogleDriveWindowsLocationPresetsProvider implements LocationPresetsProvider {
private static final List<Path> LOCATIONS = Arrays.asList( //
LocationPresetsProvider.resolveLocation("~/GoogleDrive/My Drive"), //
@@ -37,5 +35,4 @@ public final class GoogleDriveLocationPresetsProvider implements LocationPresets
.findFirst() //
.stream();
}
}

View File

@@ -7,6 +7,8 @@ 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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Named;
@@ -28,6 +30,8 @@ import static org.cryptomator.integrations.mount.MountCapability.UNMOUNT_FORCED;
@Singleton
public class Mounter {
private static final Logger LOG = LoggerFactory.getLogger(Mounter.class);
// mount providers (key) can not be used if any of the conflicting mount providers (values) are already in use
private static final Map<String, Set<String>> CONFLICTING_MOUNT_SERVICES = Map.of(
"org.cryptomator.frontend.fuse.mount.MacFuseMountProvider", Set.of("org.cryptomator.frontend.fuse.mount.FuseTMountProvider"),
@@ -127,9 +131,7 @@ public class Mounter {
}
} else if (canMountToParent && !canMountToDir) {
MountWithinParentUtil.prepareParentNoMountPoint(userChosenMountPoint);
cleanup = () -> {
MountWithinParentUtil.cleanup(userChosenMountPoint);
};
cleanup = () -> MountWithinParentUtil.cleanup(userChosenMountPoint);
}
try {
builder.setMountpoint(userChosenMountPoint);
@@ -158,7 +160,7 @@ public class Mounter {
var mountService = mountProviders.stream().filter(s -> s.getClass().getName().equals(vaultSettings.mountService.getValue())).findFirst().orElse(defaultMountService.getValue());
if (isConflictingMountService(mountService)) {
var msg = STR."\{mountService.getClass()} unavailable due to conflict with either of \{CONFLICTING_MOUNT_SERVICES.get(mountService.getClass().getName())}";
var msg = mountService.getClass() + " unavailable due to conflict with either of " + CONFLICTING_MOUNT_SERVICES.get(mountService.getClass().getName());
throw new ConflictingMountServiceException(msg);
}

View File

@@ -25,30 +25,33 @@ import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.NodeOrientation;
import java.time.Instant;
import java.util.function.Consumer;
public class Settings {
private static final Logger LOG = LoggerFactory.getLogger(Settings.class);
static final boolean DEFAULT_ASKED_FOR_UPDATE_CHECK = false;
static final boolean DEFAULT_CHECK_FOR_UPDATES = false;
static final boolean DEFAULT_START_HIDDEN = false;
static final boolean DEFAULT_AUTO_CLOSE_VAULTS = false;
static final boolean DEFAULT_USE_KEYCHAIN = true;
static final boolean DEFAULT_USE_QUICKACCESS = true;
static final int DEFAULT_PORT = 42427;
static final int DEFAULT_NUM_TRAY_NOTIFICATIONS = 3;
static final boolean DEFAULT_DEBUG_MODE = false;
static final UiTheme DEFAULT_THEME = UiTheme.LIGHT;
@Deprecated // to be changed to "whatever is available" eventually
static final String DEFAULT_KEYCHAIN_PROVIDER = SystemUtils.IS_OS_WINDOWS ? "org.cryptomator.windows.keychain.WindowsProtectedKeychainAccess" : SystemUtils.IS_OS_MAC ? "org.cryptomator.macos.keychain.MacSystemKeychainAccess" : "org.cryptomator.linux.keychain.SecretServiceKeychainAccess";
static final String DEFAULT_KEYCHAIN_PROVIDER = SystemUtils.IS_OS_WINDOWS ? "org.cryptomator.windows.keychain.WindowsProtectedKeychainAccess" : //
SystemUtils.IS_OS_MAC ? "org.cryptomator.macos.keychain.MacSystemKeychainAccess" : //
"org.cryptomator.linux.keychain.SecretServiceKeychainAccess";
static final String DEFAULT_QUICKACCESS_SERVICE = SystemUtils.IS_OS_WINDOWS ? "org.cryptomator.windows.quickaccess.ExplorerQuickAccessService" : //
SystemUtils.IS_OS_LINUX ? "org.cryptomator.linux.quickaccess.NautilusBookmarks" : null;
static final String DEFAULT_USER_INTERFACE_ORIENTATION = NodeOrientation.LEFT_TO_RIGHT.name();
static final boolean DEFAULT_SHOW_MINIMIZE_BUTTON = false;
static final String DEFAULT_LAST_UPDATE_CHECK = "2000-01-01";
public static final Instant DEFAULT_TIMESTAMP = Instant.parse("2000-01-01T00:00:00Z");
public final ObservableList<VaultSettings> directories;
public final BooleanProperty askedForUpdateCheck;
public final BooleanProperty checkForUpdates;
public final BooleanProperty startHidden;
public final BooleanProperty autoCloseVaults;
public final BooleanProperty useKeychain;
@@ -57,17 +60,21 @@ public class Settings {
public final BooleanProperty debugMode;
public final ObjectProperty<UiTheme> theme;
public final StringProperty keychainProvider;
public final BooleanProperty useQuickAccess;
public final StringProperty quickAccessService;
public final ObjectProperty<NodeOrientation> userInterfaceOrientation;
public final StringProperty licenseKey;
public final BooleanProperty showMinimizeButton;
public final BooleanProperty showTrayIcon;
public final BooleanProperty compactMode;
public final IntegerProperty windowXPosition;
public final IntegerProperty windowYPosition;
public final IntegerProperty windowWidth;
public final IntegerProperty windowHeight;
public final StringProperty language;
public final StringProperty mountService;
public final StringProperty lastUpdateCheck;
public final BooleanProperty checkForUpdates;
public final ObjectProperty<Instant> lastUpdateCheckReminder;
public final ObjectProperty<Instant> lastSuccessfulUpdateCheck;
private Consumer<Settings> saveCmd;
@@ -84,11 +91,10 @@ public class Settings {
*/
Settings(SettingsJson json) {
this.directories = FXCollections.observableArrayList(VaultSettings::observables);
this.askedForUpdateCheck = new SimpleBooleanProperty(this, "askedForUpdateCheck", json.askedForUpdateCheck);
this.checkForUpdates = new SimpleBooleanProperty(this, "checkForUpdates", json.checkForUpdatesEnabled);
this.startHidden = new SimpleBooleanProperty(this, "startHidden", json.startHidden);
this.autoCloseVaults = new SimpleBooleanProperty(this, "autoCloseVaults", json.autoCloseVaults);
this.useKeychain = new SimpleBooleanProperty(this, "useKeychain", json.useKeychain);
this.useQuickAccess = new SimpleBooleanProperty(this, "addToQuickAccess", json.useQuickAccess);
this.port = new SimpleIntegerProperty(this, "webDavPort", json.port);
this.numTrayNotifications = new SimpleIntegerProperty(this, "numTrayNotifications", json.numTrayNotifications);
this.debugMode = new SimpleBooleanProperty(this, "debugMode", json.debugMode);
@@ -96,26 +102,28 @@ public class Settings {
this.keychainProvider = new SimpleStringProperty(this, "keychainProvider", json.keychainProvider);
this.userInterfaceOrientation = new SimpleObjectProperty<>(this, "userInterfaceOrientation", parseEnum(json.uiOrientation, NodeOrientation.class, NodeOrientation.LEFT_TO_RIGHT));
this.licenseKey = new SimpleStringProperty(this, "licenseKey", json.licenseKey);
this.showMinimizeButton = new SimpleBooleanProperty(this, "showMinimizeButton", json.showMinimizeButton);
this.showTrayIcon = new SimpleBooleanProperty(this, "showTrayIcon", json.showTrayIcon);
this.compactMode = new SimpleBooleanProperty(this, "compactMode", json.compactMode);
this.windowXPosition = new SimpleIntegerProperty(this, "windowXPosition", json.windowXPosition);
this.windowYPosition = new SimpleIntegerProperty(this, "windowYPosition", json.windowYPosition);
this.windowWidth = new SimpleIntegerProperty(this, "windowWidth", json.windowWidth);
this.windowHeight = new SimpleIntegerProperty(this, "windowHeight", json.windowHeight);
this.language = new SimpleStringProperty(this, "language", json.language);
this.mountService = new SimpleStringProperty(this, "mountService", json.mountService);
this.lastUpdateCheck = new SimpleStringProperty(this, "lastUpdateCheck", json.lastUpdateCheck);
this.quickAccessService = new SimpleStringProperty(this, "quickAccessService", json.quickAccessService);
this.checkForUpdates = new SimpleBooleanProperty(this, "checkForUpdates", json.checkForUpdatesEnabled);
this.lastUpdateCheckReminder = new SimpleObjectProperty<>(this, "lastUpdateCheckReminder", json.lastReminderForUpdateCheck);
this.lastSuccessfulUpdateCheck = new SimpleObjectProperty<>(this, "lastSuccessfulUpdateCheck", json.lastSuccessfulUpdateCheck);
this.directories.addAll(json.directories.stream().map(VaultSettings::new).toList());
migrateLegacySettings(json);
directories.addListener(this::somethingChanged);
askedForUpdateCheck.addListener(this::somethingChanged);
checkForUpdates.addListener(this::somethingChanged);
startHidden.addListener(this::somethingChanged);
autoCloseVaults.addListener(this::somethingChanged);
useKeychain.addListener(this::somethingChanged);
useQuickAccess.addListener(this::somethingChanged);
port.addListener(this::somethingChanged);
numTrayNotifications.addListener(this::somethingChanged);
debugMode.addListener(this::somethingChanged);
@@ -123,15 +131,18 @@ public class Settings {
keychainProvider.addListener(this::somethingChanged);
userInterfaceOrientation.addListener(this::somethingChanged);
licenseKey.addListener(this::somethingChanged);
showMinimizeButton.addListener(this::somethingChanged);
showTrayIcon.addListener(this::somethingChanged);
compactMode.addListener(this::somethingChanged);
windowXPosition.addListener(this::somethingChanged);
windowYPosition.addListener(this::somethingChanged);
windowWidth.addListener(this::somethingChanged);
windowHeight.addListener(this::somethingChanged);
language.addListener(this::somethingChanged);
mountService.addListener(this::somethingChanged);
lastUpdateCheck.addListener(this::somethingChanged);
quickAccessService.addListener(this::somethingChanged);
checkForUpdates.addListener(this::somethingChanged);
lastUpdateCheckReminder.addListener(this::somethingChanged);
lastSuccessfulUpdateCheck.addListener(this::somethingChanged);
}
@SuppressWarnings("deprecation")
@@ -165,11 +176,10 @@ public class Settings {
SettingsJson serialized() {
var json = new SettingsJson();
json.directories = directories.stream().map(VaultSettings::serialized).toList();
json.askedForUpdateCheck = askedForUpdateCheck.get();
json.checkForUpdatesEnabled = checkForUpdates.get();
json.startHidden = startHidden.get();
json.autoCloseVaults = autoCloseVaults.get();
json.useKeychain = useKeychain.get();
json.useQuickAccess = useQuickAccess.get();
json.port = port.get();
json.numTrayNotifications = numTrayNotifications.get();
json.debugMode = debugMode.get();
@@ -177,15 +187,18 @@ public class Settings {
json.keychainProvider = keychainProvider.get();
json.uiOrientation = userInterfaceOrientation.get().name();
json.licenseKey = licenseKey.get();
json.showMinimizeButton = showMinimizeButton.get();
json.showTrayIcon = showTrayIcon.get();
json.compactMode = compactMode.get();
json.windowXPosition = windowXPosition.get();
json.windowYPosition = windowYPosition.get();
json.windowWidth = windowWidth.get();
json.windowHeight = windowHeight.get();
json.language = language.get();
json.mountService = mountService.get();
json.lastUpdateCheck = lastUpdateCheck.get();
json.quickAccessService = quickAccessService.get();
json.checkForUpdatesEnabled = checkForUpdates.get();
json.lastReminderForUpdateCheck = lastUpdateCheckReminder.get();
json.lastSuccessfulUpdateCheck = lastSuccessfulUpdateCheck.get();
return json;
}

View File

@@ -1,9 +1,11 @@
package org.cryptomator.common.settings;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.time.Instant;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
@@ -16,15 +18,9 @@ class SettingsJson {
@JsonProperty("writtenByVersion")
String writtenByVersion;
@JsonProperty("askedForUpdateCheck")
boolean askedForUpdateCheck = Settings.DEFAULT_ASKED_FOR_UPDATE_CHECK;
@JsonProperty("autoCloseVaults")
boolean autoCloseVaults = Settings.DEFAULT_AUTO_CLOSE_VAULTS;
@JsonProperty("checkForUpdatesEnabled")
boolean checkForUpdatesEnabled = Settings.DEFAULT_CHECK_FOR_UPDATES;
@JsonProperty("debugMode")
boolean debugMode = Settings.DEFAULT_DEBUG_MODE;
@@ -49,12 +45,12 @@ class SettingsJson {
@JsonProperty("port")
int port = Settings.DEFAULT_PORT;
@JsonProperty("showMinimizeButton")
boolean showMinimizeButton = Settings.DEFAULT_SHOW_MINIMIZE_BUTTON;
@JsonProperty("showTrayIcon")
boolean showTrayIcon;
@JsonProperty("compactMode")
boolean compactMode;
@JsonProperty("startHidden")
boolean startHidden = Settings.DEFAULT_START_HIDDEN;
@@ -80,7 +76,20 @@ class SettingsJson {
@JsonProperty(value = "preferredVolumeImpl", access = JsonProperty.Access.WRITE_ONLY) // WRITE_ONLY means value is "written" into the java object during deserialization. Upvote this: https://github.com/FasterXML/jackson-annotations/issues/233
String preferredVolumeImpl;
@JsonProperty("lastUpdateCheck")
String lastUpdateCheck = Settings.DEFAULT_LAST_UPDATE_CHECK;
@JsonProperty("checkForUpdatesEnabled")
boolean checkForUpdatesEnabled = Settings.DEFAULT_CHECK_FOR_UPDATES;
@JsonProperty("lastReminderForUpdateCheck")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'", timezone = "UTC")
Instant lastReminderForUpdateCheck = Settings.DEFAULT_TIMESTAMP;
@JsonProperty("lastSuccessfulUpdateCheck")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'", timezone = "UTC")
Instant lastSuccessfulUpdateCheck = Settings.DEFAULT_TIMESTAMP;
@JsonProperty("useQuickAccess")
boolean useQuickAccess = Settings.DEFAULT_USE_QUICKACCESS;
@JsonProperty("quickAccessService")
String quickAccessService = Settings.DEFAULT_QUICKACCESS_SERVICE;
}

View File

@@ -10,6 +10,7 @@ package org.cryptomator.common.settings;
import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.google.common.base.Suppliers;
import org.cryptomator.common.Environment;
import org.slf4j.Logger;
@@ -36,7 +37,7 @@ import java.util.stream.Stream;
@Singleton
public class SettingsProvider implements Supplier<Settings> {
private static final ObjectMapper JSON = new ObjectMapper().setDefaultLeniency(true);
private static final ObjectMapper JSON = new ObjectMapper().setDefaultLeniency(true).registerModule(new JavaTimeModule());
private static final Logger LOG = LoggerFactory.getLogger(SettingsProvider.class);
private static final long SAVE_DELAY_MS = 1000;
@@ -57,7 +58,10 @@ public class SettingsProvider implements Supplier<Settings> {
}
private Settings load() {
Settings settings = env.getSettingsPath().flatMap(this::tryLoad).findFirst().orElseGet(() -> Settings.create(env));
Settings settings = env.getSettingsPath() //
.flatMap(this::tryLoad) //
.findFirst() //
.orElseGet(() -> Settings.create(env));
settings.setSaveCmd(this::scheduleSave);
return settings;
}

View File

@@ -58,6 +58,7 @@ public class VaultSettings {
public final StringExpression mountName;
public final StringProperty mountService;
public final IntegerProperty port;
public final StringProperty lastKnownKeyLoader;
VaultSettings(VaultSettingsJson json) {
this.id = json.id;
@@ -74,6 +75,7 @@ public class VaultSettings {
this.mountPoint = new SimpleObjectProperty<>(this, "mountPoint", json.mountPoint == null ? null : Path.of(json.mountPoint));
this.mountService = new SimpleStringProperty(this, "mountService", json.mountService);
this.port = new SimpleIntegerProperty(this, "port", json.port);
this.lastKnownKeyLoader = new SimpleStringProperty(this, "lastKnownKeyLoader", json.lastKnownKeyLoader);
// mount name is no longer an explicit setting, see https://github.com/cryptomator/cryptomator/pull/1318
this.mountName = StringExpression.stringExpression(Bindings.createStringBinding(() -> {
final String name;
@@ -99,7 +101,7 @@ public class VaultSettings {
}
Observable[] observables() {
return new Observable[]{actionAfterUnlock, autoLockIdleSeconds, autoLockWhenIdle, displayName, maxCleartextFilenameLength, mountFlags, mountPoint, path, revealAfterMount, unlockAfterStartup, usesReadOnlyMode, port, mountService};
return new Observable[]{actionAfterUnlock, autoLockIdleSeconds, autoLockWhenIdle, displayName, maxCleartextFilenameLength, mountFlags, mountPoint, path, revealAfterMount, unlockAfterStartup, usesReadOnlyMode, port, mountService, lastKnownKeyLoader};
}
public static VaultSettings withRandomId() {
@@ -130,6 +132,7 @@ public class VaultSettings {
json.mountPoint = mountPoint.map(Path::toString).getValue();
json.mountService = mountService.get();
json.port = port.get();
json.lastKnownKeyLoader = lastKnownKeyLoader.get();
return json;
}

View File

@@ -48,6 +48,9 @@ class VaultSettingsJson {
@JsonProperty("mountService")
String mountService;
@JsonProperty("lastKnownKeyLoader")
String lastKnownKeyLoader;
@JsonProperty("port")
int port = VaultSettings.DEFAULT_PORT;

View File

@@ -10,24 +10,32 @@ package org.cryptomator.common.vaults;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.common.Constants;
import org.cryptomator.event.FileSystemEventAggregator;
import org.cryptomator.common.mount.Mounter;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.settings.VaultSettings;
import org.cryptomator.cryptofs.CryptoFileSystem;
import org.cryptomator.cryptofs.CryptoFileSystemProperties;
import org.cryptomator.cryptofs.CryptoFileSystemProperties.FileSystemFlags;
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
import org.cryptomator.cryptofs.common.FileSystemCapabilityChecker;
import org.cryptomator.cryptofs.event.FilesystemEvent;
import org.cryptomator.cryptolib.api.CryptoException;
import org.cryptomator.cryptolib.api.MasterkeyLoader;
import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
import org.cryptomator.event.VaultEvent;
import org.cryptomator.integrations.mount.MountFailedException;
import org.cryptomator.integrations.mount.Mountpoint;
import org.cryptomator.integrations.mount.UnmountFailedException;
import org.cryptomator.integrations.quickaccess.QuickAccessService;
import org.cryptomator.integrations.quickaccess.QuickAccessServiceException;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Named;
import javafx.application.Platform;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
@@ -40,6 +48,7 @@ import javafx.beans.property.SimpleBooleanProperty;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.ReadOnlyFileSystemException;
import java.util.EnumSet;
import java.util.Objects;
import java.util.Set;
@@ -54,6 +63,7 @@ public class Vault {
private final VaultSettings vaultSettings;
private final AtomicReference<CryptoFileSystem> cryptoFileSystem;
private final AtomicReference<QuickAccessService.QuickAccessEntry> quickAccessEntry;
private final VaultState state;
private final ObjectProperty<Exception> lastKnownException;
private final VaultConfigCache configCache;
@@ -67,6 +77,8 @@ public class Vault {
private final BooleanBinding unknownError;
private final ObjectBinding<Mountpoint> mountPoint;
private final Mounter mounter;
private final Settings settings;
private final FileSystemEventAggregator fileSystemEventAggregator;
private final BooleanProperty showingStats;
private final AtomicReference<Mounter.MountHandle> mountHandle = new AtomicReference<>(null);
@@ -78,7 +90,8 @@ public class Vault {
VaultState state, //
@Named("lastKnownException") ObjectProperty<Exception> lastKnownException, //
VaultStats stats, //
Mounter mounter) {
Mounter mounter, Settings settings, //
FileSystemEventAggregator fileSystemEventAggregator) {
this.vaultSettings = vaultSettings;
this.configCache = configCache;
this.cryptoFileSystem = cryptoFileSystem;
@@ -94,7 +107,10 @@ public class Vault {
this.unknownError = Bindings.createBooleanBinding(this::isUnknownError, state);
this.mountPoint = Bindings.createObjectBinding(this::getMountPoint, state);
this.mounter = mounter;
this.settings = settings;
this.fileSystemEventAggregator = fileSystemEventAggregator;
this.showingStats = new SimpleBooleanProperty(false);
this.quickAccessEntry = new AtomicReference<>(null);
}
// ******************************************************************************
@@ -103,15 +119,22 @@ public class Vault {
private CryptoFileSystem createCryptoFileSystem(MasterkeyLoader keyLoader) throws IOException, MasterkeyLoadingFailedException {
Set<FileSystemFlags> flags = EnumSet.noneOf(FileSystemFlags.class);
if (vaultSettings.usesReadOnlyMode.get()) {
var createReadOnly = vaultSettings.usesReadOnlyMode.get();
try {
FileSystemCapabilityChecker.assertWriteAccess(getPath());
} catch (FileSystemCapabilityChecker.MissingCapabilityException e) {
if (!createReadOnly) {
throw new ReadOnlyFileSystemException();
}
}
if (createReadOnly) {
flags.add(FileSystemFlags.READONLY);
} else if (vaultSettings.maxCleartextFilenameLength.get() == -1) {
LOG.debug("Determining cleartext filename length limitations...");
var checker = new FileSystemCapabilityChecker();
int shorteningThreshold = configCache.get().allegedShorteningThreshold();
int ciphertextLimit = checker.determineSupportedCiphertextFileNameLength(getPath());
int ciphertextLimit = FileSystemCapabilityChecker.determineSupportedCiphertextFileNameLength(getPath());
if (ciphertextLimit < shorteningThreshold) {
int cleartextLimit = checker.determineSupportedCleartextFileNameLength(getPath());
int cleartextLimit = FileSystemCapabilityChecker.determineSupportedCleartextFileNameLength(getPath());
vaultSettings.maxCleartextFilenameLength.set(cleartextLimit);
} else {
vaultSettings.maxCleartextFilenameLength.setValue(UNLIMITED_FILENAME_LENGTH);
@@ -127,6 +150,7 @@ public class Vault {
.withFlags(flags) //
.withMaxCleartextNameLength(vaultSettings.maxCleartextFilenameLength.get()) //
.withVaultConfigFilename(Constants.VAULTCONFIG_FILENAME) //
.withFilesystemEventConsumer(this::consumeVaultEvent) //
.build();
return CryptoFileSystemProvider.newFileSystem(getPath(), fsProps);
}
@@ -154,6 +178,9 @@ public class Vault {
var rootPath = fs.getRootDirectories().iterator().next();
var mountHandle = mounter.mount(vaultSettings, rootPath);
success = this.mountHandle.compareAndSet(null, mountHandle);
if (settings.useQuickAccess.getValue()) {
addToQuickAccess();
}
} finally {
if (!success) {
destroyCryptoFileSystem();
@@ -178,6 +205,7 @@ public class Vault {
mountHandle.mountObj().close();
mountHandle.specialCleanup().run();
} finally {
removeFromQuickAccess();
destroyCryptoFileSystem();
}
@@ -185,6 +213,57 @@ public class Vault {
LOG.info("Locked vault '{}'", getDisplayName());
}
private synchronized void addToQuickAccess() {
if (quickAccessEntry.get() != null) {
//we don't throw an exception since we don't wanna block unlocking
LOG.warn("Vault already added to quick access area. Will be removed on next lock operation.");
return;
}
QuickAccessService.get() //
.filter(s -> s.getClass().getName().equals(settings.quickAccessService.getValue())) //
.findFirst() //
.ifPresentOrElse( //
this::addToQuickAccessInternal, //
() -> LOG.warn("Unable to add Vault to quick access area: Desired implementation not available.") //
);
}
private void addToQuickAccessInternal(@NotNull QuickAccessService s) {
if (getMountPoint() instanceof Mountpoint.WithPath mp) {
try {
var entry = s.add(mp.path(), getDisplayName());
quickAccessEntry.set(entry);
} catch (QuickAccessServiceException e) {
LOG.error("Adding vault to quick access area failed", e);
}
} else {
LOG.warn("Unable to add vault to quick access area: Vault is not mounted to local system path.");
}
}
private synchronized void removeFromQuickAccess() {
if (quickAccessEntry.get() == null) {
LOG.debug("Removing vault from quick access area: Entry not found, nothing to do.");
return;
}
removeFromQuickAccessInternal();
}
private void removeFromQuickAccessInternal() {
try {
quickAccessEntry.get().remove();
quickAccessEntry.set(null);
} catch (QuickAccessServiceException e) {
LOG.error("Removing vault from quick access area failed", e);
}
}
private void consumeVaultEvent(FilesystemEvent e) {
fileSystemEventAggregator.put(this, e);
}
// ******************************************************************************
// Observable Properties
// *******************************************************************************
@@ -346,6 +425,17 @@ public class Vault {
}
}
/**
* Gets the cleartext name from a given path to an encrypted vault file
*/
public String getCleartextName(Path ciphertextPath) throws IOException {
if (!state.getValue().equals(VaultState.Value.UNLOCKED)) {
throw new IllegalStateException("Vault is not unlocked");
}
var fs = cryptoFileSystem.get();
return fs.getCleartextName(ciphertextPath);
}
public VaultConfigCache getVaultConfigCache() {
return configCache;
}

View File

@@ -8,11 +8,13 @@
*******************************************************************************/
package org.cryptomator.common.vaults;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.settings.VaultSettings;
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
import org.cryptomator.cryptofs.DirStructure;
import org.cryptomator.cryptofs.migration.Migrators;
import org.cryptomator.integrations.mount.MountService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -24,6 +26,8 @@ import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.ResourceBundle;
@@ -38,14 +42,21 @@ public class VaultListManager {
private static final Logger LOG = LoggerFactory.getLogger(VaultListManager.class);
private final AutoLocker autoLocker;
private final List<MountService> mountServices;
private final VaultComponent.Factory vaultComponentFactory;
private final ObservableList<Vault> vaultList;
private final String defaultVaultName;
@Inject
public VaultListManager(ObservableList<Vault> vaultList, AutoLocker autoLocker, VaultComponent.Factory vaultComponentFactory, ResourceBundle resourceBundle, Settings settings) {
public VaultListManager(ObservableList<Vault> vaultList, //
AutoLocker autoLocker, //
List<MountService> mountServices, //
VaultComponent.Factory vaultComponentFactory, //
ResourceBundle resourceBundle, //
Settings settings) {
this.vaultList = vaultList;
this.autoLocker = autoLocker;
this.mountServices = mountServices;
this.vaultComponentFactory = vaultComponentFactory;
this.defaultVaultName = resourceBundle.getString("defaults.vault.vaultName");
@@ -76,6 +87,15 @@ public class VaultListManager {
} else {
vaultSettings.displayName.set(defaultVaultName);
}
//due to https://github.com/cryptomator/cryptomator/issues/2880#issuecomment-1680313498
var nameOfWinfspLocalMounter = "org.cryptomator.frontend.fuse.mount.WinFspMountProvider";
if (SystemUtils.IS_OS_WINDOWS //
&& vaultSettings.path.get().toString().contains("Dropbox") //
&& mountServices.stream().anyMatch(s -> s.getClass().getName().equals(nameOfWinfspLocalMounter))) {
vaultSettings.mountService.setValue(nameOfWinfspLocalMounter);
}
return vaultSettings;
}
@@ -95,6 +115,10 @@ public class VaultListManager {
private Vault create(VaultSettings vaultSettings) {
var wrapper = new VaultConfigCache(vaultSettings);
try {
if (Objects.isNull(vaultSettings.lastKnownKeyLoader.get())) {
var keyIdScheme = wrapper.get().getKeyId().getScheme();
vaultSettings.lastKnownKeyLoader.set(keyIdScheme);
}
var vaultState = determineVaultState(vaultSettings.path.get());
if (vaultState == LOCKED) { //for legacy reasons: pre v8 vault do not have a config, but they are in the NEEDS_MIGRATION state
wrapper.reloadConfig();

View File

@@ -0,0 +1,14 @@
package org.cryptomator.event;
public sealed interface Answer permits Answer.DoNothing, Answer.DoSomething {
record DoNothing() implements Answer {}
record DoSomething(Runnable action) implements Answer {
void run() {
action.run();
}
}
}

View File

@@ -0,0 +1,8 @@
package org.cryptomator.event;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.cryptofs.event.FilesystemEvent;
import java.nio.file.Path;
public record FSEventBucket(Vault vault, Path idPath, Class<? extends FilesystemEvent> c) {}

View File

@@ -0,0 +1,5 @@
package org.cryptomator.event;
import org.cryptomator.cryptofs.event.FilesystemEvent;
public record FSEventBucketContent(FilesystemEvent mostRecentEvent, int count) {}

View File

@@ -0,0 +1,107 @@
package org.cryptomator.event;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.cryptofs.event.BrokenDirFileEvent;
import org.cryptomator.cryptofs.event.BrokenFileNodeEvent;
import org.cryptomator.cryptofs.event.ConflictResolutionFailedEvent;
import org.cryptomator.cryptofs.event.ConflictResolvedEvent;
import org.cryptomator.cryptofs.event.DecryptionFailedEvent;
import org.cryptomator.cryptofs.event.FilesystemEvent;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Aggregator for {@link FilesystemEvent}s.
* <p>
* The aggregator groups filesystem events by the vault where the event occurred, an identifying path (clear- or ciphertext) and the event class (aka type).
* A group is called an {@link FSEventBucket}, its {@link FSEventBucketContent} is the most recent event object and a count of how often the event already occurred.
*/
@Singleton
public class FileSystemEventAggregator {
private final ConcurrentHashMap<FSEventBucket, FSEventBucketContent> map;
private final AtomicBoolean hasUpdates;
@Inject
public FileSystemEventAggregator() {
this.map = new ConcurrentHashMap<>();
this.hasUpdates = new AtomicBoolean(false);
}
/**
* Adds the given event to the map. If a bucket for this event already exists, only the count is updated and the event set as the most recent one.
*
* @param v Vault where the event occurred
* @param e Actual {@link FilesystemEvent}
*/
public void put(Vault v, FilesystemEvent e) {
var key = computeKey(v, e);
map.compute(key, (k, val) -> {
if (val == null) {
return new FSEventBucketContent(e, 1);
} else {
return new FSEventBucketContent(e, val.count() + 1);
}
});
hasUpdates.set(true);
}
/**
* Removes an event bucket from the map.
*/
public FSEventBucketContent remove(FSEventBucket key) {
var content = map.remove(key);
hasUpdates.set(true);
return content;
}
/**
* Clears the event map.
*/
public void clear() {
map.clear();
hasUpdates.set(true);
}
public boolean hasMaybeUpdates() {
return hasUpdates.get();
}
/**
* Clones the map entries into a collection.
* <p>
* The collection is first cleared, then all map entries are added in one bulk operation. Cleans the hasUpdates status.
*
* @param target collection which is first cleared and then the EntrySet copied to.
*/
public void cloneTo(Collection<Map.Entry<FSEventBucket, FSEventBucketContent>> target) {
hasUpdates.set(false);
target.clear();
target.addAll(map.entrySet());
}
/**
* Method to compute the identifying key for a given filesystem event
*
* @param v Vault where the event occurred
* @param event Actual {@link FilesystemEvent}
* @return a {@link FSEventBucket} used in the map and lru cache
*/
private static FSEventBucket computeKey(Vault v, FilesystemEvent event) {
var p = switch (event) {
case DecryptionFailedEvent(_, Path ciphertextPath, _) -> ciphertextPath;
case ConflictResolvedEvent(_, _, _, _, Path resolvedCiphertext) -> resolvedCiphertext;
case ConflictResolutionFailedEvent(_, _, Path conflictingCiphertext, _) -> conflictingCiphertext;
case BrokenDirFileEvent(_, Path ciphertext) -> ciphertext;
case BrokenFileNodeEvent(_, _, Path ciphertext) -> ciphertext;
};
return new FSEventBucket(v, p, event.getClass());
}
}

View File

@@ -0,0 +1,15 @@
package org.cryptomator.event;
import org.cryptomator.integrations.common.IntegrationsLoader;
import java.util.ServiceLoader;
import java.util.stream.Stream;
public interface NotificationHandler {
Answer handle(VaultEvent e);
static Stream<NotificationHandler> loadAll() {
return IntegrationsLoader.loadAll(ServiceLoader.load(NotificationHandler.class), NotificationHandler.class);
}
}

View File

@@ -0,0 +1,27 @@
package org.cryptomator.event;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.cryptofs.event.FilesystemEvent;
import java.time.Instant;
public record VaultEvent(Vault v, FilesystemEvent actualEvent, int count) implements Comparable<VaultEvent> {
public VaultEvent(Vault v, FilesystemEvent actualEvent) {
this(v, actualEvent, 1);
}
@Override
public int compareTo(VaultEvent other) {
var timeResult = actualEvent.getTimestamp().compareTo(other.actualEvent().getTimestamp());
if(timeResult != 0) {
return timeResult;
} else {
return this.equals(other) ? 0 : this.actualEvent.getClass().getName().compareTo(other.actualEvent.getClass().getName());
}
}
public VaultEvent incrementCount(FilesystemEvent update) {
return new VaultEvent(v, update, count+1);
}
}

View File

@@ -9,8 +9,9 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder;
import dagger.Lazy;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.common.Environment;
import org.cryptomator.common.SubstitutingProperties;
import org.cryptomator.common.ShutdownHook;
import org.cryptomator.common.SubstitutingProperties;
import org.cryptomator.networking.SSLContextProvider;
import org.cryptomator.ipc.IpcCommunicator;
import org.cryptomator.logging.DebugMode;
import org.cryptomator.ui.fxapp.FxApplicationComponent;
@@ -19,8 +20,10 @@ import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.net.ssl.SSLContext;
import javafx.application.Application;
import javafx.stage.Stage;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
@@ -48,14 +51,16 @@ public class Cryptomator {
private final Environment env;
private final Lazy<IpcMessageHandler> ipcMessageHandler;
private final ShutdownHook shutdownHook;
private final SecureRandom csprng;
@Inject
Cryptomator(DebugMode debugMode, SupportedLanguages supportedLanguages, Environment env, Lazy<IpcMessageHandler> ipcMessageHandler, ShutdownHook shutdownHook) {
Cryptomator(DebugMode debugMode, SupportedLanguages supportedLanguages, Environment env, Lazy<IpcMessageHandler> ipcMessageHandler, ShutdownHook shutdownHook, SecureRandom csprng) {
this.debugMode = debugMode;
this.supportedLanguages = supportedLanguages;
this.env = env;
this.ipcMessageHandler = ipcMessageHandler;
this.shutdownHook = shutdownHook;
this.csprng = csprng;
}
public static void main(String[] args) {
@@ -89,7 +94,7 @@ public class Cryptomator {
LOG.info("Starting Cryptomator {} on {} {} ({})", env.getAppVersion(), SystemUtils.OS_NAME, SystemUtils.OS_VERSION, SystemUtils.OS_ARCH);
debugMode.initialize();
supportedLanguages.applyPreferred();
changeDefaultSSLContext();
/*
* Attempts to create an IPC connection to a running Cryptomator instance and sends it the given args.
* If no external process could be reached, the args will be handled by the loopback IPC endpoint.
@@ -115,6 +120,17 @@ public class Cryptomator {
}
}
private void changeDefaultSSLContext() {
SSLContextProvider.loadAll().findFirst().ifPresent(p -> {
try {
var context = p.getContext(csprng);
SSLContext.setDefault(context);
} catch (SSLContextProvider.SSLContextBuildException e) {
LOG.warn("Failed to change default SSL context with provider {}", p.getClass().getName(), e);
}
});
}
/**
* Launches the JavaFX application, blocking the main thread until shuts down.
*

View File

@@ -20,7 +20,7 @@ public class SupportedLanguages {
// "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");
"ta", "th", "tr", "ug", "uk", "vi", "zh", "zh-HK", "zh-TW");
public static final String ENGLISH = "en";
private final List<String> sortedLanguageTags;

View File

@@ -0,0 +1,185 @@
package org.cryptomator.networking;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.KeyStoreSpi;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.concurrent.atomic.AtomicInteger;
public class CombinedKeyStoreSpi extends KeyStoreSpi {
private final KeyStore primary;
private final KeyStore fallback;
public static CombinedKeyStoreSpi create(KeyStore primary, KeyStore fallback) {
checkIfLoaded(primary);
checkIfLoaded(fallback);
return new CombinedKeyStoreSpi(primary, fallback);
}
private static void checkIfLoaded(KeyStore s) {
try {
s.aliases();
} catch (KeyStoreException e) {
throw new IllegalArgumentException("Keystore %s is not loaded.".formatted(s.getType()));
}
}
private CombinedKeyStoreSpi(KeyStore primary, KeyStore fallback) {
this.primary = primary;
this.fallback = fallback;
}
@Override
public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException, UnrecoverableKeyException {
try {
Key key = primary.getKey(alias, password);
if (key == null) {
key = fallback.getKey(alias, password);
}
return key;
} catch (KeyStoreException e) {
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
}
}
@Override
public Certificate[] engineGetCertificateChain(String alias) {
try {
Certificate[] chain = primary.getCertificateChain(alias);
if (chain == null) {
chain = fallback.getCertificateChain(alias);
}
return chain;
} catch (KeyStoreException e) {
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
}
}
@Override
public Certificate engineGetCertificate(String alias) {
try {
Certificate cert = primary.getCertificate(alias);
if (cert == null) {
cert = fallback.getCertificate(alias);
}
return cert;
} catch (KeyStoreException e) {
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
}
}
@Override
public Date engineGetCreationDate(String alias) {
try {
Date date = primary.getCreationDate(alias);
if (date == null) {
date = fallback.getCreationDate(alias);
}
return date;
} catch (KeyStoreException e) {
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
}
}
@Override
public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain) throws KeyStoreException {
throw new UnsupportedOperationException("Read-only KeyStore");
}
@Override
public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) throws KeyStoreException {
throw new UnsupportedOperationException("Read-only KeyStore");
}
@Override
public void engineSetCertificateEntry(String alias, Certificate cert) throws KeyStoreException {
throw new UnsupportedOperationException("Read-only KeyStore");
}
@Override
public void engineDeleteEntry(String alias) throws KeyStoreException {
throw new UnsupportedOperationException("Read-only KeyStore");
}
@Override
public Enumeration<String> engineAliases() {
var aliases = new LinkedHashSet<String>();
try {
primary.aliases().asIterator().forEachRemaining(aliases::add);
fallback.aliases().asIterator().forEachRemaining(aliases::add);
return Collections.enumeration(aliases);
} catch (KeyStoreException e) {
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
}
}
@Override
public boolean engineContainsAlias(String alias) {
try {
return primary.containsAlias(alias) || fallback.containsAlias(alias);
} catch (KeyStoreException e) {
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
}
}
@Override
public int engineSize() {
var aliases = engineAliases();
var i = new AtomicInteger(0);
aliases.asIterator().forEachRemaining(_ -> i.incrementAndGet());
return i.get();
}
@Override
public boolean engineIsKeyEntry(String alias) {
try {
return primary.isKeyEntry(alias) || fallback.isKeyEntry(alias);
} catch (KeyStoreException e) {
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
}
}
@Override
public boolean engineIsCertificateEntry(String alias) {
try {
return primary.isCertificateEntry(alias) || fallback.isCertificateEntry(alias);
} catch (KeyStoreException e) {
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
}
}
@Override
public String engineGetCertificateAlias(Certificate cert) {
try {
String alias = primary.getCertificateAlias(cert);
if (alias == null) {
alias = fallback.getCertificateAlias(cert);
}
return alias;
} catch (KeyStoreException e) {
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
}
}
@Override
public void engineStore(OutputStream stream, char[] password) throws IOException, NoSuchAlgorithmException, CertificateException {
throw new UnsupportedOperationException("Read-only KeyStore");
}
@Override
public void engineLoad(InputStream stream, char[] password) throws IOException, NoSuchAlgorithmException, CertificateException {
// Nothing to do; the real keystores are already loaded.
}
}

View File

@@ -0,0 +1,33 @@
package org.cryptomator.networking;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
abstract class SSLContextDifferentTrustStoreBase implements SSLContextProvider {
abstract KeyStore getTruststore() throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException;
@Override
public SSLContext getContext(SecureRandom csprng) throws SSLContextBuildException {
try {
KeyStore truststore = getTruststore();
truststore.load(null, null);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(truststore);
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), csprng);
return context;
} catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | KeyManagementException | IOException e) {
throw new SSLContextBuildException(e);
}
}
}

View File

@@ -0,0 +1,24 @@
package org.cryptomator.networking;
import org.cryptomator.integrations.common.IntegrationsLoader;
import javax.net.ssl.SSLContext;
import java.security.SecureRandom;
import java.util.ServiceLoader;
import java.util.stream.Stream;
public interface SSLContextProvider {
SSLContext getContext(SecureRandom csprng) throws SSLContextBuildException;
class SSLContextBuildException extends Exception {
SSLContextBuildException(Throwable t) {
super(t);
}
}
static Stream<SSLContextProvider> loadAll() {
return IntegrationsLoader.loadAll(ServiceLoader.load(SSLContextProvider.class), SSLContextProvider.class);
}
}

View File

@@ -0,0 +1,32 @@
package org.cryptomator.networking;
import org.cryptomator.integrations.common.OperatingSystem;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.cert.CertificateException;
/**
* SSLContextProvider for macOS using the macOS Keychain as truststore
*/
@OperatingSystem(OperatingSystem.Value.MAC)
public class SSLContextWithMacKeychain extends SSLContextDifferentTrustStoreBase implements SSLContextProvider {
@Override
KeyStore getTruststore() throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException {
var userKeyStore = KeyStore.getInstance("KeychainStore");
var systemRootKeyStore = KeyStore.getInstance("KeychainStore-ROOT");
userKeyStore.load(null);
systemRootKeyStore.load(null);
try {
CombinedKeyStoreSpi spi = CombinedKeyStoreSpi.create(userKeyStore, systemRootKeyStore);
Provider dummyProvider = new Provider("CombinedKeyStoreProvider", "1.0", "Provides a combined, read-only KeyStore") {};
return new KeyStore(spi, dummyProvider, "CombinedKeyStoreProvider") {};
} catch (IllegalArgumentException e) {
throw new KeyStoreException(e);
}
}
}

View File

@@ -0,0 +1,42 @@
package org.cryptomator.networking;
import org.cryptomator.integrations.common.CheckAvailability;
import org.cryptomator.integrations.common.OperatingSystem;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.Optional;
/**
* SSLContextProvider for Linux using a PKCS#12 file as trust store
*/
@OperatingSystem(OperatingSystem.Value.LINUX)
@CheckAvailability
public class SSLContextWithPKCS12TrustStore extends SSLContextDifferentTrustStoreBase implements SSLContextProvider {
private static final String CERT_FILE_LOCATION_PROPERTY = "cryptomator.networking.truststore.p12Path";
@Override
KeyStore getTruststore() throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException {
var pkcs12FilePath = Path.of(System.getProperty(CERT_FILE_LOCATION_PROPERTY));
try {
return KeyStore.getInstance(pkcs12FilePath.toFile(), new char[]{});
} catch (IllegalArgumentException e) {
throw new NoSuchFileException(pkcs12FilePath.toString());
}
}
@CheckAvailability
public static boolean isSupported() {
var pkcs12Path = System.getProperty(CERT_FILE_LOCATION_PROPERTY);
return Optional.ofNullable(pkcs12Path) //
.map(Path::of) //
.map(Files::exists).orElse(false);
}
}

View File

@@ -0,0 +1,21 @@
package org.cryptomator.networking;
import org.cryptomator.integrations.common.OperatingSystem;
import java.security.KeyStore;
import java.security.KeyStoreException;
/**
* SSLContextProvider for Windows using the Windows certificate store as trust store
* <p>
* In order to work, the jdk.crypto.mscapi jmod is needed
*/
@OperatingSystem(OperatingSystem.Value.WINDOWS)
public class SSLContextWithWindowsCertStore extends SSLContextDifferentTrustStoreBase implements SSLContextProvider {
@Override
KeyStore getTruststore() throws KeyStoreException {
return KeyStore.getInstance("WINDOWS-ROOT");
}
}

View File

@@ -26,7 +26,7 @@ public class CreateNewVaultExpertSettingsController implements FxController {
public static final int MAX_SHORTENING_THRESHOLD = 220;
public static final int MIN_SHORTENING_THRESHOLD = 36;
private static final String DOCS_NAME_SHORTENING_URL = "https://docs.cryptomator.org/en/1.7/security/architecture/#name-shortening";
private static final String DOCS_NAME_SHORTENING_URL = "https://docs.cryptomator.org/security/architecture/#name-shortening";
private final Stage window;
private final Lazy<Application> application;

View File

@@ -13,55 +13,64 @@ import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Named;
import javafx.application.Platform;
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.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
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.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import java.io.File;
import java.io.IOException;
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;
import java.util.concurrent.ExecutorService;
@AddVaultWizardScoped
public class CreateNewVaultLocationController implements FxController {
private static final Logger LOG = LoggerFactory.getLogger(CreateNewVaultLocationController.class);
private static final Path DEFAULT_CUSTOM_VAULT_PATH = Paths.get(System.getProperty("user.home"));
private static final String TEMP_FILE_FORMAT = ".locationTest.cryptomator.tmp";
private static final String TEMP_FILE_PREFIX = ".locationTest.cryptomator";
private final Stage window;
private final Lazy<Scene> chooseNameScene;
private final Lazy<Scene> chooseExpertSettingsScene;
private final List<RadioButton> locationPresetBtns;
private final ObjectProperty<Path> vaultPath;
private final StringProperty vaultName;
private final ExecutorService backgroundExecutor;
private final ResourceBundle resourceBundle;
private final ObservableValue<VaultPathStatus> vaultPathStatus;
private final ObservableValue<Boolean> validVaultPath;
private final BooleanProperty usePresetPath;
private final BooleanProperty loadingPresetLocations = new SimpleBooleanProperty(false);
private final ObservableList<Node> radioButtons;
private final ObservableList<Node> sortedRadioButtons;
private Path customVaultPath = DEFAULT_CUSTOM_VAULT_PATH;
//FXML
public ToggleGroup locationPresetsToggler;
public VBox radioButtonVBox;
public HBox customLocationRadioBtn;
public RadioButton customRadioButton;
public Label locationStatusLabel;
public FontAwesome5IconView goodLocation;
@@ -73,25 +82,20 @@ public class CreateNewVaultLocationController implements FxController {
@FxmlScene(FxmlFile.ADDVAULT_NEW_EXPERT_SETTINGS) Lazy<Scene> chooseExpertSettingsScene, //
ObjectProperty<Path> vaultPath, //
@Named("vaultName") StringProperty vaultName, //
ResourceBundle resourceBundle) {
ExecutorService backgroundExecutor, ResourceBundle resourceBundle) {
this.window = window;
this.chooseNameScene = chooseNameScene;
this.chooseExpertSettingsScene = chooseExpertSettingsScene;
this.vaultPath = vaultPath;
this.vaultName = vaultName;
this.backgroundExecutor = backgroundExecutor;
this.resourceBundle = resourceBundle;
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.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();
this.radioButtons = FXCollections.observableArrayList();
this.sortedRadioButtons = radioButtons.sorted(this::compareLocationPresets);
}
private VaultPathStatus validatePath(Path p) throws NullPointerException {
@@ -121,28 +125,64 @@ public class CreateNewVaultLocationController implements FxController {
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)) {
Path tmpDir = null;
try {
tmpDir = Files.createTempDirectory(p, TEMP_FILE_PREFIX );
return true;
} catch (IOException e) {
return false;
} finally {
try {
Files.deleteIfExists(tmpFile);
} catch (IOException e) {
LOG.warn("Unable to delete temporary file {}. Needs to be deleted manually.", tmpFile);
if (tmpDir != null) {
try {
Files.deleteIfExists(tmpDir);
} catch (IOException e) {
LOG.warn("Unable to delete temporary directory {}. Needs to be deleted manually.", tmpDir);
}
}
}
}
@FXML
public void initialize() {
radioButtonVBox.getChildren().addAll(1, locationPresetBtns); //first item is the list header
locationPresetsToggler.getToggles().addAll(locationPresetBtns);
var task = backgroundExecutor.submit(this::loadLocationPresets);
window.addEventHandler(WindowEvent.WINDOW_HIDING, _ -> task.cancel(true));
locationPresetsToggler.selectedToggleProperty().addListener(this::togglePredefinedLocation);
usePresetPath.bind(locationPresetsToggler.selectedToggleProperty().isNotEqualTo(customRadioButton));
radioButtons.add(customLocationRadioBtn);
Bindings.bindContent(radioButtonVBox.getChildren(), sortedRadioButtons); //to prevent garbage collection of the binding, we bind explicitly to the sorted list
}
private void loadLocationPresets() {
Platform.runLater(() -> loadingPresetLocations.set(true));
try {
LocationPresetsProvider.loadAll(LocationPresetsProvider.class) //
.flatMap(LocationPresetsProvider::getLocations) //we do not use sorted(), because it evaluates the stream elements, blocking until all elements are gathered
.forEach(this::createRadioButtonFor);
} finally {
Platform.runLater(() -> loadingPresetLocations.set(false));
}
}
private void createRadioButtonFor(LocationPreset preset) {
Platform.runLater(() -> {
var btn = new RadioButton(preset.name());
btn.setUserData(preset.path());
radioButtons.add(btn);
locationPresetsToggler.getToggles().add(btn);
});
}
private int compareLocationPresets(Node left, Node right) {
if (customLocationRadioBtn.getId().equals(left.getId())) {
return 1;
} else if (customLocationRadioBtn.getId().equals(right.getId())) {
return -1;
} else {
return ((RadioButton) left).getText().compareToIgnoreCase(((RadioButton) right).getText());
}
}
private void togglePredefinedLocation(@SuppressWarnings("unused") ObservableValue<? extends Toggle> observable, @SuppressWarnings("unused") Toggle oldValue, Toggle newValue) {
var storagePath = Optional.ofNullable((Path) newValue.getUserData()).orElse(customVaultPath);
vaultPath.set(storagePath.resolve(vaultName.get()));
@@ -197,7 +237,15 @@ public class CreateNewVaultLocationController implements FxController {
}
public boolean isValidVaultPath() {
return validVaultPath.getValue();
return Boolean.TRUE.equals(validVaultPath.getValue());
}
public boolean isLoadingPresetLocations() {
return loadingPresetLocations.getValue();
}
public BooleanProperty loadingPresetLocationsProperty() {
return loadingPresetLocations;
}
public BooleanProperty usePresetPathProperty() {

View File

@@ -76,8 +76,10 @@ public class ReadmeGenerator {
input.chars().forEachOrdered(c -> {
if (c < 128) {
sb.append((char) c);
} else if (c <= 0xFF) {
sb.append("\\'").append(String.format("%02X", c));
} else if (c < 0xFFFF) {
sb.append("\\u").append(c);
sb.append("\\uc1\\u").append(c);
}
});
}

View File

@@ -12,7 +12,9 @@ public enum FxmlFile {
CONVERTVAULT_HUBTOPASSWORD_START("/fxml/convertvault_hubtopassword_start.fxml"), //
CONVERTVAULT_HUBTOPASSWORD_CONVERT("/fxml/convertvault_hubtopassword_convert.fxml"), //
CONVERTVAULT_HUBTOPASSWORD_SUCCESS("/fxml/convertvault_hubtopassword_success.fxml"), //
DECRYPTNAMES("/fxml/decryptnames.fxml"), //
ERROR("/fxml/error.fxml"), //
EVENT_VIEW("/fxml/eventview.fxml"), //
FORGET_PASSWORD("/fxml/forget_password.fxml"), //
HEALTH_START("/fxml/health_start.fxml"), //
HEALTH_CHECK_LIST("/fxml/health_check_list.fxml"), //
@@ -44,8 +46,8 @@ public enum FxmlFile {
RECOVERYKEY_RESET_PASSWORD("/fxml/recoverykey_reset_password.fxml"), //
RECOVERYKEY_RESET_PASSWORD_SUCCESS("/fxml/recoverykey_reset_password_success.fxml"), //
RECOVERYKEY_SUCCESS("/fxml/recoverykey_success.fxml"), //
REMOVE_VAULT("/fxml/remove_vault.fxml"), //
SHARE_VAULT("/fxml/share_vault.fxml"), //
SIMPLE_DIALOG("/fxml/simple_dialog.fxml"), //
UPDATE_REMINDER("/fxml/update_reminder.fxml"), //
UNLOCK_ENTER_PASSWORD("/fxml/unlock_enter_password.fxml"),
UNLOCK_REQUIRES_RESTART("/fxml/unlock_requires_restart.fxml"), //

View File

@@ -7,6 +7,7 @@ public enum FontAwesome5Icon {
ANCHOR("\uF13D"), //
ARROW_UP("\uF062"), //
BAN("\uF05E"), //
BELL("\uF0F3"), //
BUG("\uF188"), //
CARET_DOWN("\uF0D7"), //
CARET_RIGHT("\uF0Da"), //
@@ -15,9 +16,12 @@ public enum FontAwesome5Icon {
CLIPBOARD("\uF328"), //
COG("\uF013"), //
COGS("\uF085"), //
COMPRESS_ALT("\uF422"), //
COPY("\uF0C5"), //
CROWN("\uF521"), //
DONATE("\uF4B9"), //
EDIT("\uF044"), //
ELLIPSIS_V("\uF142"), //
EXCHANGE_ALT("\uF362"), //
EXCLAMATION("\uF12A"), //
EXCLAMATION_CIRCLE("\uF06A"), //
@@ -49,6 +53,7 @@ public enum FontAwesome5Icon {
SEARCH("\uF002"), //
SHARE("\uF064"), //
SPINNER("\uF110"), //
SPONSORS("\uF2B5"), //
STETHOSCOPE("\uF0f1"), //
SYNC("\uF021"), //
TIMES("\uF00D"), //

View File

@@ -0,0 +1,96 @@
package org.cryptomator.ui.controls;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.fxml.FXML;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
public class NotificationBar extends HBox {
@FXML
private Label notificationLabel;
private final BooleanProperty dismissable = new SimpleBooleanProperty();
private final BooleanProperty notify = new SimpleBooleanProperty();
public NotificationBar() {
setAlignment(Pos.CENTER);
setStyle("-fx-alignment: center;");
Region spacer = new Region();
spacer.setMinWidth(40);
Region leftRegion = new Region();
HBox.setHgrow(leftRegion, javafx.scene.layout.Priority.ALWAYS);
Region rightRegion = new Region();
HBox.setHgrow(rightRegion, javafx.scene.layout.Priority.ALWAYS);
VBox vbox = new VBox();
vbox.setAlignment(Pos.CENTER);
HBox.setHgrow(vbox, javafx.scene.layout.Priority.ALWAYS);
notificationLabel = new Label();
notificationLabel.getStyleClass().add("notification-label");
notificationLabel.setStyle("-fx-alignment: center;");
vbox.getChildren().add(notificationLabel);
Button closeButton = new Button("X");
closeButton.setMinWidth(40);
closeButton.setStyle("-fx-background-color: transparent; -fx-text-fill: white; -fx-font-weight: bold;");
closeButton.visibleProperty().bind(dismissable);
closeButton.setOnAction(_ -> {
visibleProperty().unbind();
managedProperty().unbind();
visibleProperty().set(false);
managedProperty().set(false);
});
closeButton.visibleProperty().bind(dismissable);
getChildren().addAll(spacer, leftRegion, vbox, rightRegion, closeButton);
visibleProperty().bind(notifyProperty());
managedProperty().bind(notifyProperty());
}
public String getText() {
return notificationLabel.getText();
}
public void setText(String text) {
notificationLabel.setText(text);
}
public void setStyleClass(String styleClass) {
getStyleClass().clear();
getStyleClass().add(styleClass);
}
public boolean isDismissable() {
return dismissable.get();
}
public void setDismissable(boolean value) {
dismissable.set(value);
}
public boolean getNotify() {
return notify.get();
}
public void setNotify(boolean value) {
notify.set(value);
}
public BooleanProperty notifyProperty() {
return notify;
}
}

View File

@@ -15,6 +15,7 @@ import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.fxapp.FxApplicationWindows;
import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingStrategy;
import org.cryptomator.ui.recoverykey.RecoveryKeyFactory;
import org.jetbrains.annotations.VisibleForTesting;
import org.slf4j.Logger;
@@ -108,6 +109,7 @@ public class HubToPasswordConvertController implements FxController {
.thenRunAsync(this::convertInternal, backgroundExecutorService) //
.whenCompleteAsync((result, exception) -> {
if (exception == null) {
vault.getVaultSettings().lastKnownKeyLoader.set(MasterkeyFileLoadingStrategy.SCHEME);
LOG.info("Conversion of vault {} succeeded.", vault.getPath());
window.setScene(successScene.get());
} else {

View File

@@ -0,0 +1,25 @@
package org.cryptomator.ui.decryptname;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.value.ObservableValue;
import java.nio.file.Path;
public record CipherAndCleartext(Path ciphertext, String cleartextName) {
public String getCiphertextFilename() {
return ciphertext.getFileName().toString();
}
public ObservableValue<String> ciphertextFilenameProperty() {
return new ReadOnlyStringWrapper(getCiphertextFilename());
}
public String getCleartextName() {
return cleartextName;
}
public ObservableValue<String> cleartextNameProperty() {
return new ReadOnlyStringWrapper(getCleartextName());
}
}

View File

@@ -0,0 +1,233 @@
package org.cryptomator.ui.decryptname;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.cryptofs.common.Constants;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.controls.FontAwesome5Icon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javafx.application.Platform;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ListProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.Clipboard;
import javafx.scene.input.DataFormat;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.TransferMode;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@DecryptNameScoped
public class DecryptFileNamesViewController implements FxController {
private static final Logger LOG = LoggerFactory.getLogger(DecryptFileNamesViewController.class);
private static final KeyCodeCombination COPY_TO_CLIPBOARD_SHORTCUT = new KeyCodeCombination(KeyCode.C, KeyCodeCombination.SHORTCUT_DOWN);
private static final String COPY_TO_CLIPBOARD_SHORTCUT_STRING_WIN = "CTRL+C";
private static final String COPY_TO_CLIPBOARD_SHORTCUT_STRING_MAC = "⌘C";
private static final String COPY_TO_CLIPBOARD_SHORTCUT_STRING_LINUX = "CTRL+C";
private final ListProperty<CipherAndCleartext> mapping;
private final StringProperty dropZoneText = new SimpleStringProperty();
private final ObjectProperty<FontAwesome5Icon> dropZoneIcon = new SimpleObjectProperty<>();
private final BooleanProperty wrongFilesSelected = new SimpleBooleanProperty(false);
private final Stage window;
private final Vault vault;
private final ResourceBundle resourceBundle;
private final List<Path> initialList;
@FXML
public TableColumn<CipherAndCleartext, String> ciphertextColumn;
@FXML
public TableColumn<CipherAndCleartext, String> cleartextColumn;
@FXML
public TableView<CipherAndCleartext> cipherToCleartextTable;
@Inject
public DecryptFileNamesViewController(@DecryptNameWindow Stage window, @DecryptNameWindow Vault vault, @DecryptNameWindow List<Path> pathsToDecrypt, ResourceBundle resourceBundle) {
this.window = window;
this.vault = vault;
this.resourceBundle = resourceBundle;
this.mapping = new SimpleListProperty<>(FXCollections.observableArrayList());
this.initialList = pathsToDecrypt;
}
@FXML
public void initialize() {
cipherToCleartextTable.setItems(mapping);
cipherToCleartextTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY_ALL_COLUMNS);
//DragNDrop
cipherToCleartextTable.setOnDragEntered(event -> {
if (event.getGestureSource() == null && event.getDragboard().hasFiles()) {
cipherToCleartextTable.setItems(FXCollections.emptyObservableList());
}
});
cipherToCleartextTable.setOnDragOver(event -> {
if (event.getGestureSource() == null && event.getDragboard().hasFiles()) {
if (SystemUtils.IS_OS_WINDOWS || SystemUtils.IS_OS_MAC) {
event.acceptTransferModes(TransferMode.LINK);
} else {
event.acceptTransferModes(TransferMode.ANY);
}
}
});
cipherToCleartextTable.setOnDragDropped(event -> {
if (event.getGestureSource() == null && event.getDragboard().hasFiles()) {
checkAndDecrypt(event.getDragboard().getFiles().stream().map(File::toPath).toList());
cipherToCleartextTable.setItems(mapping);
}
});
cipherToCleartextTable.setOnDragExited(_ -> cipherToCleartextTable.setItems(mapping));
//selectionModel and copy-to-clipboard action
cipherToCleartextTable.getSelectionModel().setCellSelectionEnabled(true);
cipherToCleartextTable.setOnKeyPressed(keyEvent -> {
if (COPY_TO_CLIPBOARD_SHORTCUT.match(keyEvent)) {
copySingleCelltoClipboard();
}
});
ciphertextColumn.setCellValueFactory(new PropertyValueFactory<>("ciphertextFilename"));
cleartextColumn.setCellValueFactory(new PropertyValueFactory<>("cleartextName"));
dropZoneText.setValue(resourceBundle.getString("decryptNames.dropZone.message"));
dropZoneIcon.setValue(FontAwesome5Icon.FILE_IMPORT);
wrongFilesSelected.addListener((_, _, areWrongFiles) -> {
if (areWrongFiles) {
CompletableFuture.delayedExecutor(5, TimeUnit.SECONDS, Platform::runLater).execute(() -> {
dropZoneText.setValue(resourceBundle.getString("decryptNames.dropZone.message"));
dropZoneIcon.setValue(FontAwesome5Icon.FILE_IMPORT);
wrongFilesSelected.setValue(false);
});
}
});
if (!initialList.isEmpty()) {
checkAndDecrypt(initialList);
}
}
private void copySingleCelltoClipboard() {
cipherToCleartextTable.getSelectionModel().getSelectedCells().stream().findFirst().ifPresent(tablePosition -> {
var selectedItem = cipherToCleartextTable.getSelectionModel().getSelectedItem();
//TODO: give user feedback, if content is copied -> must be done via a custom cell factory to access the actual table cell!
if (tablePosition.getTableColumn().equals(ciphertextColumn)) {
Clipboard.getSystemClipboard().setContent(Map.of(DataFormat.PLAIN_TEXT, selectedItem.ciphertext().toString()));
} else {
Clipboard.getSystemClipboard().setContent(Map.of(DataFormat.PLAIN_TEXT, selectedItem.cleartextName()));
}
});
}
@FXML
public void selectFiles() {
var fileChooser = new FileChooser();
fileChooser.setTitle(resourceBundle.getString("decryptNames.filePicker.title"));
fileChooser.setSelectedExtensionFilter(new FileChooser.ExtensionFilter(resourceBundle.getString("decryptNames.filePicker.extensionDescription"), List.of("*.c9r")));
fileChooser.setInitialDirectory(vault.getPath().toFile());
var ciphertextNodes = fileChooser.showOpenMultipleDialog(window);
if (ciphertextNodes != null) {
checkAndDecrypt(ciphertextNodes.stream().map(File::toPath).toList());
}
}
private void checkAndDecrypt(List<Path> pathsToDecrypt) {
mapping.clear();
//Assumption: All files are in the same directory
var testPath = pathsToDecrypt.getFirst();
if (!testPath.startsWith(vault.getPath())) {
setDropZoneError(resourceBundle.getString("decryptNames.dropZone.error.foreignFiles").formatted(vault.getDisplayName()));
return;
}
if (pathsToDecrypt.size() == 1 && testPath.endsWith(Constants.DIR_ID_BACKUP_FILE_NAME)) {
setDropZoneError(resourceBundle.getString("decryptNames.dropZone.error.vaultInternalFiles"));
return;
}
try {
var newMapping = pathsToDecrypt.stream().filter(p -> !p.endsWith(Constants.DIR_ID_BACKUP_FILE_NAME)).map(this::getCleartextName).toList();
mapping.addAll(newMapping);
} catch (UncheckedIOException e) {
setDropZoneError(resourceBundle.getString("decryptNames.dropZone.error.generic"));
LOG.info("Failed to decrypt filenames for directory {}", testPath.getParent(), e);
} catch (IllegalArgumentException e) {
setDropZoneError(resourceBundle.getString("decryptNames.dropZone.error.vaultInternalFiles"));
} catch (UnsupportedOperationException e) {
setDropZoneError(resourceBundle.getString("decryptNames.dropZone.error.noDirIdBackup"));
}
}
private void setDropZoneError(String text) {
dropZoneIcon.setValue(FontAwesome5Icon.TIMES);
dropZoneText.setValue(text);
wrongFilesSelected.setValue(true);
}
private CipherAndCleartext getCleartextName(Path ciphertextNode) {
try {
var cleartextName = vault.getCleartextName(ciphertextNode);
return new CipherAndCleartext(ciphertextNode, cleartextName);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
//obvservable getter
public ObservableValue<String> dropZoneTextProperty() {
return dropZoneText;
}
public String getDropZoneText() {
return dropZoneText.get();
}
public ObservableValue<FontAwesome5Icon> dropZoneIconProperty() {
return dropZoneIcon;
}
public FontAwesome5Icon getDropZoneIcon() {
return dropZoneIcon.get();
}
public void clearTable() {
mapping.clear();
}
public void copyTableToClipboard() {
var csv = mapping.stream().map(cipherAndClear -> "\"" + cipherAndClear.ciphertext() + "\", \"" + cipherAndClear.cleartextName() + "\"").collect(Collectors.joining("\n"));
Clipboard.getSystemClipboard().setContent(Map.of(DataFormat.PLAIN_TEXT, csv));
}
public String getCopyToClipboardShortcutString() {
if (SystemUtils.IS_OS_WINDOWS) {
return COPY_TO_CLIPBOARD_SHORTCUT_STRING_WIN;
} else if (SystemUtils.IS_OS_MAC) {
return COPY_TO_CLIPBOARD_SHORTCUT_STRING_MAC;
} else {
return COPY_TO_CLIPBOARD_SHORTCUT_STRING_LINUX;
}
}
}

View File

@@ -0,0 +1,50 @@
package org.cryptomator.ui.decryptname;
import dagger.BindsInstance;
import dagger.Lazy;
import dagger.Subcomponent;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Named;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.nio.file.Path;
import java.util.List;
@DecryptNameScoped
@Subcomponent(modules = DecryptNameModule.class)
public interface DecryptNameComponent {
Logger LOG = LoggerFactory.getLogger(DecryptNameComponent.class);
@DecryptNameWindow
Stage window();
@FxmlScene(FxmlFile.DECRYPTNAMES)
Lazy<Scene> decryptNamesView();
@DecryptNameWindow
Vault vault();
default void showDecryptFileNameWindow() {
Stage s = window();
s.setScene(decryptNamesView().get());
s.sizeToScene();
if (vault().isUnlocked()) {
s.show();
} else {
LOG.error("Aborted showing DecryptFileName window: vault state is not {}, but {}.", VaultState.Value.UNLOCKED, vault().getState());
}
}
@Subcomponent.Factory
interface Factory {
DecryptNameComponent create(@BindsInstance @DecryptNameWindow Vault vault, @BindsInstance @Named("windowOwner") Stage owner, @BindsInstance @DecryptNameWindow List<Path> pathsToDecrypt);
}
}

View File

@@ -1,4 +1,4 @@
package org.cryptomator.ui.removevault;
package org.cryptomator.ui.decryptname;
import dagger.Binds;
import dagger.Module;
@@ -12,8 +12,8 @@ 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.fxapp.PrimaryStage;
import javax.inject.Named;
import javax.inject.Provider;
import javafx.scene.Scene;
import javafx.stage.Modality;
@@ -22,38 +22,38 @@ import java.util.Map;
import java.util.ResourceBundle;
@Module
abstract class RemoveVaultModule {
public abstract class DecryptNameModule {
@Provides
@RemoveVaultWindow
@RemoveVaultScoped
@DecryptNameScoped
@DecryptNameWindow
static Stage provideStage(StageFactory factory, @Named("windowOwner") Stage owner, @DecryptNameWindow Vault vault, ResourceBundle resourceBundle) {
Stage stage = factory.create();
stage.setResizable(true);
stage.initModality(Modality.WINDOW_MODAL);
stage.initOwner(owner);
stage.setTitle(resourceBundle.getString("decryptNames.title"));
vault.stateProperty().addListener(((_, _, _) -> stage.close())); //as soon as the state changes from unlocked, close the window
return stage;
}
@Provides
@DecryptNameScoped
@DecryptNameWindow
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
}
@Provides
@RemoveVaultWindow
@RemoveVaultScoped
static Stage provideStage(StageFactory factory, @PrimaryStage Stage primaryStage, @RemoveVaultWindow Vault vault, ResourceBundle resourceBundle) {
Stage stage = factory.create();
stage.setTitle(String.format(resourceBundle.getString("removeVault.title"), vault.getDisplayName()));
stage.setResizable(false);
stage.initModality(Modality.WINDOW_MODAL);
stage.initOwner(primaryStage);
return stage;
@FxmlScene(FxmlFile.DECRYPTNAMES)
@DecryptNameScoped
static Scene provideDecryptNamesViewScene(@DecryptNameWindow FxmlLoaderFactory fxmlLoaders) {
return fxmlLoaders.createScene(FxmlFile.DECRYPTNAMES);
}
@Provides
@FxmlScene(FxmlFile.REMOVE_VAULT)
@RemoveVaultScoped
static Scene provideRemoveVaultScene(@RemoveVaultWindow FxmlLoaderFactory fxmlLoaders) {
return fxmlLoaders.createScene(FxmlFile.REMOVE_VAULT);
}
// ------------------
@Binds
@IntoMap
@FxControllerKey(RemoveVaultController.class)
abstract FxController bindRemoveVaultController(RemoveVaultController controller);
@FxControllerKey(DecryptFileNamesViewController.class)
abstract FxController bindDecryptNamesViewController(DecryptFileNamesViewController controller);
}

View File

@@ -0,0 +1,11 @@
package org.cryptomator.ui.decryptname;
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 DecryptNameScoped {}

View File

@@ -0,0 +1,12 @@
package org.cryptomator.ui.decryptname;
import javax.inject.Qualifier;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Qualifier
@Documented
@Retention(RUNTIME)
@interface DecryptNameWindow {}

View File

@@ -0,0 +1,90 @@
package org.cryptomator.ui.dialogs;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.StageFactory;
import org.cryptomator.ui.controls.FontAwesome5Icon;
import org.cryptomator.ui.fxapp.FxApplicationScoped;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javafx.collections.ObservableList;
import javafx.stage.Stage;
import java.util.ResourceBundle;
import java.util.function.Consumer;
@FxApplicationScoped
public class Dialogs {
private final ResourceBundle resourceBundle;
private final StageFactory stageFactory;
@Inject
public Dialogs(ResourceBundle resourceBundle, StageFactory stageFactory) {
this.resourceBundle = resourceBundle;
this.stageFactory = stageFactory;
}
private static final Logger LOG = LoggerFactory.getLogger(Dialogs.class);
private SimpleDialog.Builder createDialogBuilder() {
return new SimpleDialog.Builder(resourceBundle, stageFactory);
}
public SimpleDialog.Builder prepareRemoveVaultDialog(Stage window, Vault vault, ObservableList<Vault> vaults) {
return createDialogBuilder().setOwner(window) //
.setTitleKey("removeVault.title", vault.getDisplayName()) //
.setMessageKey("removeVault.message") //
.setDescriptionKey("removeVault.description") //
.setIcon(FontAwesome5Icon.QUESTION) //
.setOkButtonKey("generic.button.remove") //
.setCancelButtonKey("generic.button.cancel") //
.setOkAction(stage -> {
LOG.debug("Removing vault {}.", vault.getDisplayName());
vaults.remove(vault);
stage.close();
});
}
public SimpleDialog.Builder prepareRemoveCertDialog(Stage window, Settings settings) {
return createDialogBuilder() //
.setOwner(window) //
.setTitleKey("removeCert.title") //
.setMessageKey("removeCert.message") //
.setDescriptionKey("removeCert.description") //
.setIcon(FontAwesome5Icon.QUESTION) //
.setOkButtonKey("generic.button.remove") //
.setCancelButtonKey("generic.button.cancel") //
.setOkAction(stage -> {
settings.licenseKey.set(null);
stage.close();
});
}
public SimpleDialog.Builder prepareDokanySupportEndDialog(Stage window, Consumer<Stage> cancelAction) {
return createDialogBuilder() //
.setOwner(window) //
.setTitleKey("dokanySupportEnd.title") //
.setMessageKey("dokanySupportEnd.message") //
.setDescriptionKey("dokanySupportEnd.description") //
.setIcon(FontAwesome5Icon.EXCLAMATION) //
.setOkButtonKey("generic.button.close") //
.setCancelButtonKey("dokanySupportEnd.preferencesBtn") //
.setOkAction(Stage::close) //
.setCancelAction(cancelAction);
}
public SimpleDialog.Builder prepareRetryIfReadonlyDialog(Stage window, Consumer<Stage> okAction) {
return createDialogBuilder() //
.setOwner(window) //
.setTitleKey("retryIfReadonly.title") //
.setMessageKey("retryIfReadonly.message") //
.setDescriptionKey("retryIfReadonly.description") //
.setIcon(FontAwesome5Icon.EXCLAMATION) //
.setOkButtonKey("retryIfReadonly.retry") //
.setCancelButtonKey("generic.button.close") //
.setOkAction(okAction) //
.setCancelAction(Stage::close);
}
}

View File

@@ -0,0 +1,139 @@
package org.cryptomator.ui.dialogs;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlLoaderFactory;
import org.cryptomator.ui.common.StageFactory;
import org.cryptomator.ui.controls.FontAwesome5Icon;
import javafx.scene.Scene;
import javafx.stage.Modality;
import javafx.stage.Stage;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.IllegalFormatException;
import java.util.Objects;
import java.util.ResourceBundle;
import java.util.function.Consumer;
public class SimpleDialog {
private final ResourceBundle resourceBundle;
private final Stage dialogStage;
SimpleDialog(Builder builder) throws IOException {
this.resourceBundle = builder.resourceBundle;
dialogStage = builder.stageFactory.create();
dialogStage.initOwner(builder.owner);
dialogStage.initModality(Modality.WINDOW_MODAL);
dialogStage.setTitle(resolveText(builder.titleKey, builder.titleArgs));
dialogStage.setResizable(false);
FxmlLoaderFactory loaderFactory = FxmlLoaderFactory.forController( //
new SimpleDialogController(resolveText(builder.messageKey, null), //
resolveText(builder.descriptionKey, null), //
builder.icon, //
resolveText(builder.okButtonKey, null), //
builder.cancelButtonKey != null ? resolveText(builder.cancelButtonKey, null) : null, //
() -> builder.okAction.accept(dialogStage), //
() -> builder.cancelAction.accept(dialogStage)), //
Scene::new, builder.resourceBundle);
dialogStage.setScene(new Scene(loaderFactory.load(FxmlFile.SIMPLE_DIALOG.getRessourcePathString()).getRoot()));
}
public void showAndWait() {
dialogStage.showAndWait();
}
private String resolveText(String key, String[] args) {
if (key == null || key.isEmpty() || !resourceBundle.containsKey(key)) {
throw new IllegalArgumentException(String.format("Invalid key: '%s'. Key not found in ResourceBundle.", key));
}
String text = resourceBundle.getString(key);
try {
return args != null && args.length > 0 ? String.format(text, (Object[]) args) : text;
} catch (IllegalFormatException e) {
throw new IllegalArgumentException("Formatting error: Check if arguments match placeholders in the text.", e);
}
}
public static class Builder {
private Stage owner;
private final ResourceBundle resourceBundle;
private final StageFactory stageFactory;
private String titleKey;
private String[] titleArgs;
private String messageKey;
private String descriptionKey;
private String okButtonKey;
private String cancelButtonKey;
private FontAwesome5Icon icon;
private Consumer<Stage> okAction = Stage::close;
private Consumer<Stage> cancelAction = Stage::close;
public Builder(ResourceBundle resourceBundle, StageFactory stageFactory) {
this.resourceBundle = resourceBundle;
this.stageFactory = stageFactory;
}
public Builder setOwner(Stage owner) {
this.owner = owner;
return this;
}
public Builder setTitleKey(String titleKey, String... args) {
this.titleKey = titleKey;
this.titleArgs = args;
return this;
}
public Builder setMessageKey(String messageKey) {
this.messageKey = messageKey;
return this;
}
public Builder setDescriptionKey(String descriptionKey) {
this.descriptionKey = descriptionKey;
return this;
}
public Builder setIcon(FontAwesome5Icon icon) {
this.icon = icon;
return this;
}
public Builder setOkButtonKey(String okButtonKey) {
this.okButtonKey = okButtonKey;
return this;
}
public Builder setCancelButtonKey(String cancelButtonKey) {
this.cancelButtonKey = cancelButtonKey;
return this;
}
public Builder setOkAction(Consumer<Stage> okAction) {
this.okAction = okAction;
return this;
}
public Builder setCancelAction(Consumer<Stage> cancelAction) {
this.cancelAction = cancelAction;
return this;
}
public SimpleDialog build() {
Objects.requireNonNull(titleKey, "SimpleDialog titleKey must be set.");
Objects.requireNonNull(messageKey, "SimpleDialog messageKey must be set.");
Objects.requireNonNull(descriptionKey, "SimpleDialog descriptionKey must be set.");
Objects.requireNonNull(okButtonKey, "SimpleDialog okButtonKey must be set.");
try {
return new SimpleDialog(this);
} catch (IOException e) {
throw new UncheckedIOException("Failed to create SimpleDialog.", e);
}
}
}
}

View File

@@ -0,0 +1,67 @@
package org.cryptomator.ui.dialogs;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.controls.FontAwesome5Icon;
import javafx.fxml.FXML;
public class SimpleDialogController implements FxController {
private final String message;
private final String description;
private final FontAwesome5Icon icon;
private final String okButtonText;
private final String cancelButtonText;
private final Runnable okAction;
private final Runnable cancelAction;
private final boolean cancelButtonVisible;
public SimpleDialogController(String message, String description, FontAwesome5Icon icon, String okButtonText, String cancelButtonText, Runnable okAction, Runnable cancelAction) {
this.message = message;
this.description = description;
this.icon = icon;
this.okButtonText = okButtonText;
this.cancelButtonText = cancelButtonText;
this.okAction = okAction;
this.cancelAction = cancelAction;
this.cancelButtonVisible = cancelButtonText != null && !cancelButtonText.isEmpty();
}
public boolean isCancelButtonVisible() {
return cancelButtonVisible;
}
public String getMessage() {
return message;
}
public String getDescription() {
return description;
}
public FontAwesome5Icon getIcon() {
return icon;
}
public String getOkButtonText() {
return okButtonText;
}
public String getCancelButtonText() {
return cancelButtonText;
}
@FXML
private void handleOk() {
if (okAction != null) {
okAction.run();
}
}
@FXML
private void handleCancel() {
if (cancelAction != null) {
cancelAction.run();
}
}
}

View File

@@ -20,6 +20,8 @@ public interface ErrorComponent {
default Stage show() {
Stage stage = window();
stage.setScene(scene());
stage.setMinWidth(420);
stage.setMinHeight(300);
stage.show();
return stage;
}

View File

@@ -75,6 +75,7 @@ public class ErrorController implements FxController {
private final BooleanExpression errorSolutionFound = matchingErrorDiscussion.isNotNull();
private final BooleanProperty isLoadingHttpResponse = new SimpleBooleanProperty();
private final BooleanProperty askedForLookupDatabasePermission = new SimpleBooleanProperty();
private final boolean formerSceneWasResizable;
@Inject
ErrorController(Application application, @Named("stackTrace") String stackTrace, ErrorCode errorCode, @Nullable Scene previousScene, Stage window, Environment environment, ExecutorService executorService) {
@@ -85,12 +86,14 @@ public class ErrorController implements FxController {
this.window = window;
this.environment = environment;
this.executorService = executorService;
this.formerSceneWasResizable = window.isResizable();
}
@FXML
public void back() {
if (previousScene != null) {
window.setScene(previousScene);
window.setResizable(formerSceneWasResizable);
}
}

View File

@@ -0,0 +1,329 @@
package org.cryptomator.ui.eventview;
import org.cryptomator.event.FSEventBucket;
import org.cryptomator.event.FSEventBucketContent;
import org.cryptomator.event.FileSystemEventAggregator;
import org.cryptomator.common.Nullable;
import org.cryptomator.common.ObservableUtil;
import org.cryptomator.cryptofs.CryptoPath;
import org.cryptomator.cryptofs.event.BrokenDirFileEvent;
import org.cryptomator.cryptofs.event.BrokenFileNodeEvent;
import org.cryptomator.cryptofs.event.ConflictResolutionFailedEvent;
import org.cryptomator.cryptofs.event.ConflictResolvedEvent;
import org.cryptomator.cryptofs.event.DecryptionFailedEvent;
import org.cryptomator.integrations.revealpath.RevealFailedException;
import org.cryptomator.integrations.revealpath.RevealPathService;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.controls.FontAwesome5Icon;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javafx.beans.binding.Bindings;
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.geometry.Side;
import javafx.scene.control.Button;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.Tooltip;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.layout.HBox;
import javafx.util.Duration;
import java.nio.file.Path;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Map;
import java.util.Optional;
import java.util.ResourceBundle;
import java.util.function.Function;
public class EventListCellController implements FxController {
private static final Logger LOG = LoggerFactory.getLogger(EventListCellController.class);
private static final DateTimeFormatter LOCAL_DATE_FORMATTER = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).withZone(ZoneId.systemDefault());
private static final DateTimeFormatter LOCAL_TIME_FORMATTER = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).withZone(ZoneId.systemDefault());
private final FileSystemEventAggregator fileSystemEventAggregator;
@Nullable
private final RevealPathService revealService;
private final ResourceBundle resourceBundle;
private final ObjectProperty<Map.Entry<FSEventBucket, FSEventBucketContent>> eventEntry;
private final StringProperty eventMessage;
private final StringProperty eventDescription;
private final ObjectProperty<FontAwesome5Icon> eventIcon;
private final ObservableValue<String> eventCount;
private final ObservableValue<Boolean> vaultUnlocked;
private final ObservableValue<String> readableTime;
private final ObservableValue<String> readableDate;
private final ObservableValue<String> message;
private final ObservableValue<String> description;
private final ObservableValue<FontAwesome5Icon> icon;
private final BooleanProperty actionsButtonVisible;
private final Tooltip eventTooltip;
@FXML
HBox root;
@FXML
ContextMenu eventActionsMenu;
@FXML
Button eventActionsButton;
@Inject
public EventListCellController(FileSystemEventAggregator fileSystemEventAggregator, Optional<RevealPathService> revealService, ResourceBundle resourceBundle) {
this.fileSystemEventAggregator = fileSystemEventAggregator;
this.revealService = revealService.orElseGet(() -> null);
this.resourceBundle = resourceBundle;
this.eventEntry = new SimpleObjectProperty<>(null);
this.eventMessage = new SimpleStringProperty();
this.eventDescription = new SimpleStringProperty();
this.eventIcon = new SimpleObjectProperty<>();
this.eventCount = ObservableUtil.mapWithDefault(eventEntry, e -> e.getValue().count() == 1? "" : "("+ e.getValue().count() +")", "");
this.vaultUnlocked = ObservableUtil.mapWithDefault(eventEntry.flatMap(e -> e.getKey().vault().unlockedProperty()), Function.identity(), false);
this.readableTime = ObservableUtil.mapWithDefault(eventEntry, e -> LOCAL_TIME_FORMATTER.format(e.getValue().mostRecentEvent().getTimestamp()), "");
this.readableDate = ObservableUtil.mapWithDefault(eventEntry, e -> LOCAL_DATE_FORMATTER.format(e.getValue().mostRecentEvent().getTimestamp()), "");
this.message = Bindings.createStringBinding(this::selectMessage, vaultUnlocked, eventMessage);
this.description = Bindings.createStringBinding(this::selectDescription, vaultUnlocked, eventDescription);
this.icon = Bindings.createObjectBinding(this::selectIcon, vaultUnlocked, eventIcon);
this.actionsButtonVisible = new SimpleBooleanProperty();
this.eventTooltip = new Tooltip();
eventTooltip.setShowDelay(Duration.millis(500.0));
}
@FXML
public void initialize() {
actionsButtonVisible.bind(Bindings.createBooleanBinding(this::determineActionsButtonVisibility, root.hoverProperty(), eventActionsMenu.showingProperty(), vaultUnlocked));
vaultUnlocked.addListener((_, _, newValue) -> eventActionsMenu.hide());
Tooltip.install(root, eventTooltip);
}
private boolean determineActionsButtonVisibility() {
return vaultUnlocked.getValue() && (eventActionsMenu.isShowing() || root.isHover());
}
public void setEventEntry(@NotNull Map.Entry<FSEventBucket, FSEventBucketContent> item) {
eventEntry.set(item);
eventActionsMenu.hide();
eventActionsMenu.getItems().clear();
eventTooltip.setText(item.getKey().vault().getDisplayName());
addAction("generic.action.dismiss", () -> {
fileSystemEventAggregator.remove(item.getKey());
});
switch (item.getValue().mostRecentEvent()) {
case ConflictResolvedEvent fse -> this.adjustToConflictResolvedEvent(fse);
case ConflictResolutionFailedEvent fse -> this.adjustToConflictEvent(fse);
case DecryptionFailedEvent fse -> this.adjustToDecryptionFailedEvent(fse);
case BrokenDirFileEvent fse -> this.adjustToBrokenDirFileEvent(fse);
case BrokenFileNodeEvent fse -> this.adjustToBrokenFileNodeEvent(fse);
}
}
private void adjustToBrokenFileNodeEvent(BrokenFileNodeEvent bfe) {
eventIcon.setValue(FontAwesome5Icon.TIMES);
eventMessage.setValue(resourceBundle.getString("eventView.entry.brokenFileNode.message"));
eventDescription.setValue(bfe.ciphertextPath().getFileName().toString());
if (revealService != null) {
addAction("eventView.entry.brokenFileNode.showEncrypted", () -> reveal(revealService, convertVaultPathToSystemPath(bfe.ciphertextPath())));
} else {
addAction("eventView.entry.brokenFileNode.copyEncrypted", () -> copyToClipboard(convertVaultPathToSystemPath(bfe.ciphertextPath()).toString()));
}
addAction("eventView.entry.brokenFileNode.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(bfe.cleartextPath()).toString()));
}
private void adjustToConflictResolvedEvent(ConflictResolvedEvent cre) {
eventIcon.setValue(FontAwesome5Icon.CHECK);
eventMessage.setValue(resourceBundle.getString("eventView.entry.conflictResolved.message"));
eventDescription.setValue(cre.resolvedCiphertextPath().getFileName().toString());
if (revealService != null) {
addAction("eventView.entry.conflictResolved.showDecrypted", () -> reveal(revealService, convertVaultPathToSystemPath(cre.resolvedCleartextPath())));
} else {
addAction("eventView.entry.conflictResolved.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(cre.resolvedCleartextPath()).toString()));
}
}
private void adjustToConflictEvent(ConflictResolutionFailedEvent cfe) {
eventIcon.setValue(FontAwesome5Icon.COMPRESS_ALT);
eventMessage.setValue(resourceBundle.getString("eventView.entry.conflict.message"));
eventDescription.setValue(cfe.conflictingCiphertextPath().getFileName().toString());
if (revealService != null) {
addAction("eventView.entry.conflict.showDecrypted", () -> reveal(revealService, convertVaultPathToSystemPath(cfe.canonicalCleartextPath())));
addAction("eventView.entry.conflict.showEncrypted", () -> reveal(revealService, cfe.conflictingCiphertextPath()));
} else {
addAction("eventView.entry.conflict.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(cfe.canonicalCleartextPath()).toString()));
addAction("eventView.entry.conflict.copyEncrypted", () -> copyToClipboard(cfe.conflictingCiphertextPath().toString()));
}
}
private void adjustToDecryptionFailedEvent(DecryptionFailedEvent dfe) {
eventIcon.setValue(FontAwesome5Icon.BAN);
eventMessage.setValue(resourceBundle.getString("eventView.entry.decryptionFailed.message"));
eventDescription.setValue(dfe.ciphertextPath().getFileName().toString());
if (revealService != null) {
addAction("eventView.entry.decryptionFailed.showEncrypted", () -> reveal(revealService, dfe.ciphertextPath()));
} else {
addAction("eventView.entry.decryptionFailed.copyEncrypted", () -> copyToClipboard(dfe.ciphertextPath().toString()));
}
}
private void adjustToBrokenDirFileEvent(BrokenDirFileEvent bde) {
eventIcon.setValue(FontAwesome5Icon.TIMES);
eventMessage.setValue(resourceBundle.getString("eventView.entry.brokenDirFile.message"));
eventDescription.setValue(bde.ciphertextPath().getParent().getFileName().toString());
if (revealService != null) {
addAction("eventView.entry.brokenDirFile.showEncrypted", () -> reveal(revealService, bde.ciphertextPath()));
} else {
addAction("eventView.entry.brokenDirFile.copyEncrypted", () -> copyToClipboard(bde.ciphertextPath().toString()));
}
}
private void addAction(String localizationKey, Runnable action) {
var entry = new MenuItem(resourceBundle.getString(localizationKey));
entry.getStyleClass().addLast("dropdown-button-context-menu-item");
entry.setOnAction(_ -> action.run());
eventActionsMenu.getItems().addLast(entry);
}
private FontAwesome5Icon selectIcon() {
if (vaultUnlocked.getValue()) {
return eventIcon.getValue();
} else {
return FontAwesome5Icon.LOCK;
}
}
private String selectMessage() {
if (vaultUnlocked.getValue()) {
return eventMessage.getValue();
} else {
return "***********";
}
}
private String selectDescription() {
if (vaultUnlocked.getValue()) {
return eventDescription.getValue();
} else if (eventEntry.getValue() != null) {
var e = eventEntry.getValue().getKey();
return resourceBundle.getString("eventView.entry.vaultLocked.description").formatted(e != null ? e.vault().getDisplayName() : "");
} else {
return "";
}
}
@FXML
public void toggleEventActionsMenu() {
var e = eventEntry.get();
if (e != null) {
if (eventActionsMenu.isShowing()) {
eventActionsMenu.hide();
} else {
eventActionsMenu.show(eventActionsButton, Side.BOTTOM, 0.0, 0.0);
}
}
}
private Path convertVaultPathToSystemPath(Path p) {
if (!(p instanceof CryptoPath)) {
throw new IllegalArgumentException("Path " + p + " is not a vault path");
}
var v = eventEntry.getValue().getKey().vault();
if (!v.isUnlocked()) {
return Path.of(System.getProperty("user.home"));
}
var mountUri = v.getMountPoint().uri();
var internalPath = p.toString().substring(1);
return Path.of(mountUri.getPath().concat(internalPath).substring(1));
}
private void reveal(RevealPathService s, Path p) {
try {
s.reveal(p);
} catch (RevealFailedException e) {
LOG.warn("Failed to show path {}", p, e);
}
}
private void copyToClipboard(String s) {
var content = new ClipboardContent();
content.putString(s);
Clipboard.getSystemClipboard().setContent(content);
}
//-- property accessors --
public ObservableValue<String> messageProperty() {
return message;
}
public String getMessage() {
return message.getValue();
}
public ObservableValue<String> countProperty() {
return eventCount;
}
public String getCount() {
return eventCount.getValue();
}
public ObservableValue<String> descriptionProperty() {
return description;
}
public String getDescription() {
return description.getValue();
}
public ObservableValue<FontAwesome5Icon> iconProperty() {
return icon;
}
public FontAwesome5Icon getIcon() {
return icon.getValue();
}
public ObservableValue<Boolean> actionsButtonVisibleProperty() {
return actionsButtonVisible;
}
public boolean isActionsButtonVisible() {
return actionsButtonVisible.getValue();
}
public ObservableValue<String> eventLocalTimeProperty() {
return readableTime;
}
public String getEventLocalTime() {
return readableTime.getValue();
}
public ObservableValue<String> eventLocalDateProperty() {
return readableDate;
}
public String getEventLocalDate() {
return readableDate.getValue();
}
public ObservableValue<Boolean> vaultUnlockedProperty() {
return vaultUnlocked;
}
public boolean isVaultUnlocked() {
return vaultUnlocked.getValue();
}
}

View File

@@ -0,0 +1,66 @@
package org.cryptomator.ui.eventview;
import org.cryptomator.event.FSEventBucket;
import org.cryptomator.event.FSEventBucketContent;
import org.cryptomator.ui.common.FxmlLoaderFactory;
import javax.inject.Inject;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.util.Callback;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Map;
@EventViewScoped
public class EventListCellFactory implements Callback<ListView<Map.Entry<FSEventBucket, FSEventBucketContent>>, ListCell<Map.Entry<FSEventBucket, FSEventBucketContent>>> {
private static final String FXML_PATH = "/fxml/eventview_cell.fxml";
private final FxmlLoaderFactory fxmlLoaders;
@Inject
EventListCellFactory(@EventViewWindow FxmlLoaderFactory fxmlLoaders) {
this.fxmlLoaders = fxmlLoaders;
}
@Override
public ListCell<Map.Entry<FSEventBucket, FSEventBucketContent>> call(ListView<Map.Entry<FSEventBucket, FSEventBucketContent>> eventListView) {
try {
FXMLLoader fxmlLoader = fxmlLoaders.load(FXML_PATH);
return new Cell(fxmlLoader.getRoot(), fxmlLoader.getController());
} catch (IOException e) {
throw new UncheckedIOException("Failed to load %s.".formatted(FXML_PATH), e);
}
}
private static class Cell extends ListCell<Map.Entry<FSEventBucket, FSEventBucketContent>> {
private final Parent root;
private final EventListCellController controller;
public Cell(Parent root, EventListCellController controller) {
this.root = root;
this.controller = controller;
}
@Override
protected void updateItem(Map.Entry<FSEventBucket, FSEventBucketContent> item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setGraphic(null);
this.getStyleClass().remove("list-cell");
} else {
this.getStyleClass().addLast("list-cell");
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
setGraphic(root);
controller.setEventEntry(item);
}
}
}
}

View File

@@ -0,0 +1,35 @@
package org.cryptomator.ui.eventview;
import dagger.Lazy;
import dagger.Subcomponent;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import javafx.scene.Scene;
import javafx.stage.Stage;
@EventViewScoped
@Subcomponent(modules = {EventViewModule.class})
public interface EventViewComponent {
@EventViewWindow
Stage window();
@FxmlScene(FxmlFile.EVENT_VIEW)
Lazy<Scene> scene();
default Stage showEventViewerWindow() {
Stage stage = window();
stage.setScene(scene().get());
stage.sizeToScene();
stage.show();
stage.requestFocus();
return stage;
}
@Subcomponent.Factory
interface Factory {
EventViewComponent create();
}
}

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