Compare commits

...

317 Commits

Author SHA1 Message Date
Armin Schrenk
390bdc33e0 Merge branch 'hotfix/1.19.2' 2026-03-20 08:14:04 +01:00
Armin Schrenk
2284d1fcee Update Changelog 2026-03-20 08:13:37 +01:00
Sebastian Stenzel
62a439e10e CHANGELOG.md: moved security fixes to subsection
[ci skip]
2026-03-20 08:02:58 +01:00
Sebastian Stenzel
ddad663489 add release to metainfo file 2026-03-19 16:41:17 +01:00
Sebastian Stenzel
f08e7d9b92 bump version to 1.19.2 2026-03-19 16:34:42 +01:00
Sebastian Stenzel
6c2865a09d simplify port/scheme check 2026-03-19 16:27:09 +01:00
Armin Schrenk
4be327608a Merge branch 'release/1.19.1' 2026-03-12 14:35:20 +01:00
Armin Schrenk
929ef37ded finalize release 2026-03-12 14:12:41 +01:00
Armin Schrenk
6fce1807f0 prepare 1.19.1 2026-03-12 14:08:50 +01:00
Armin Schrenk
c1d72650cc [skip ci] update changelog 2026-03-12 14:06:30 +01:00
Armin Schrenk
dab368e44b Update org.cryptomator.integrations-api to 1.8.0
closes #4176
2026-03-12 14:00:06 +01:00
Armin Schrenk
7548174e4f Update org.cryptomator.integrations-linux to 1.7.0
closes #4175
2026-03-12 13:46:04 +01:00
Armin Schrenk
b513060744 Update dependency org.cryptomator.integrations-mac from 1.5.0-beta3 to 1.5.0
closes #4177
2026-03-12 13:40:18 +01:00
Armin Schrenk
311a9ef70b [skip ci] update changelog 2026-03-12 13:36:56 +01:00
Armin Schrenk
7331144f9d Set cryptomator.hub.enableTrustOnFirstUse (#4182)
in installers/package containers
2026-03-12 13:13:49 +01:00
Cryptobot
d576b36f7b New Crowdin updates (#4172)
New translations strings.properties:
Danish; Korean; Portuguese, Brazilian; Chinese Traditional
2026-03-12 12:43:14 +01:00
Armin Schrenk
7a6340aac6 Merge pull request #4181 from cryptomator/feature/pin-appimagetool
pin appimagetool
2026-03-12 12:31:37 +01:00
Sebastian Stenzel
6b82abcd80 Merge pull request #4179 from cryptomator/feature/admin-config-allowlist
Hub: Trust on first use
2026-03-12 12:26:59 +01:00
Armin Schrenk
97bde05422 adjust wording
use singular because in most cases hub and auth are on either pre-trusted or on the same domain
2026-03-12 12:23:30 +01:00
Armin Schrenk
3bc50eee47 add checksum of appimage tool 2026-03-12 12:16:46 +01:00
Armin Schrenk
b95a220de7 Adjust wording 2026-03-12 12:08:27 +01:00
Armin Schrenk
2896e18429 Adjust dialog message to show current status
checking vs user interaction
2026-03-12 11:42:44 +01:00
Armin Schrenk
29db91f976 fix javafx display issue
do not change scene in initialize() method
2026-03-12 11:28:38 +01:00
Sebastian Stenzel
1e3dfe3de1 Merge pull request #4180 from cryptomator/feature/patched-masterkey-loading
don't load masterkey from arbitrary paths
2026-03-12 10:23:43 +01:00
Sebastian Stenzel
dcb1f5e80f pin appimagetool 2026-03-12 10:21:12 +01:00
Sebastian Stenzel
5c75eeab27 reuse existing constant 2026-03-12 10:18:19 +01:00
Sebastian Stenzel
8e4bff8c19 don't load masterkey from arbitrary paths 2026-03-12 09:58:52 +01:00
Sebastian Stenzel
e066f155b2 filter out "" 2026-03-12 09:21:55 +01:00
Sebastian Stenzel
c3c7a23ccd added test 2026-03-12 09:14:27 +01:00
Sebastian Stenzel
c816411644 deserialize null as empty 2026-03-12 09:13:40 +01:00
Sebastian Stenzel
f752490624 default to mutable collections 2026-03-12 09:12:09 +01:00
Sebastian Stenzel
d196b66b4e refined rules 2026-03-12 09:02:19 +01:00
Sebastian Stenzel
d803a1d71e apply suggestions from code review 2026-03-11 23:17:16 +01:00
Sebastian Stenzel
c75430cde2 only trust subdomains of .cryptomator.cloud
not `notcryptomator.cloud`
2026-03-11 23:13:50 +01:00
Sebastian Stenzel
f44c3531c7 devicesResourceUrl: optional consistency check 2026-03-11 23:12:13 +01:00
Sebastian Stenzel
596829bc77 dedup 2026-03-11 23:09:04 +01:00
Sebastian Stenzel
096aeb0c54 renamed var
[ci skip]
2026-03-11 22:49:28 +01:00
Sebastian Stenzel
1a12684557 fix test 2026-03-11 22:42:25 +01:00
Sebastian Stenzel
998664acc3 distrust http (except for localhost) 2026-03-11 22:01:21 +01:00
Sebastian Stenzel
c52b3fc4ad change scene without lag 2026-03-11 22:01:14 +01:00
Sebastian Stenzel
1fde3650ca renamed classes 2026-03-11 21:47:33 +01:00
Sebastian Stenzel
57614f59e4 trust *.cryptomator.cloud 2026-03-11 21:38:51 +01:00
Sebastian Stenzel
a95883f98b renamed system properties 2026-03-11 21:32:51 +01:00
Sebastian Stenzel
6cf18c33a1 simplify sorting 2026-03-11 21:12:47 +01:00
Sebastian Stenzel
232e6fbf71 add tests 2026-03-11 21:05:14 +01:00
Sebastian Stenzel
d15731d5a4 add plural label 2026-03-11 20:30:00 +01:00
Sebastian Stenzel
45d7421e4f add "reset trusted hosts" button to general preferences 2026-03-11 20:24:56 +01:00
Sebastian Stenzel
4d0aabfe6e cleanup 2026-03-11 20:12:16 +01:00
Sebastian Stenzel
db0e266fde clean up dialog 2026-03-11 19:48:37 +01:00
Sebastian Stenzel
6281561ab4 add -Dcryptomator.allowUnknownHubHosts=true 2026-03-11 18:53:14 +01:00
Sebastian Stenzel
b981f0dc19 moved logic to separate controller 2026-03-11 18:52:36 +01:00
Armin Schrenk
bc41429982 Use environment for cryptomator system properties 2026-03-11 17:59:58 +01:00
Armin Schrenk
a31621cfde validate hub config and check allowed hosts file 2026-03-11 17:35:22 +01:00
Armin Schrenk
aa68224d63 Add new properties to admin config
* allowUnknownHubHosts
* allowedHubHosts
2026-03-11 16:49:48 +01:00
Armin Schrenk
b8413a21a3 update appstream info 2026-03-09 17:01:46 +01:00
Armin Schrenk
af59196f19 [skip ci] Merge branch 'main' into develop 2026-03-09 09:32:54 +01:00
Armin Schrenk
3a58f560fc Merge branch 'release/1.19.0' 2026-03-09 09:27:31 +01:00
Armin Schrenk
a2cca0b624 finalize release 2026-03-08 23:53:07 +01:00
Armin Schrenk
0c4ba94f10 Merge branch 'develop' into release/1.19.0 2026-03-08 23:47:36 +01:00
Cryptobot
0f8b6a8f51 New Crowdin updates (#4170)
* New translations strings.properties (Korean)
[ci skip]
2026-03-08 23:45:59 +01:00
Armin Schrenk
8ca6946fe6 Suppress CVE-2025-11143
Jetty is used only locally
2026-03-08 18:08:23 +01:00
Armin Schrenk
e583b70931 use correct filename for admin config on Windows 2026-03-07 12:06:13 +01:00
Armin Schrenk
6f6d0d8771 Update wording in release draft 2026-03-06 12:58:17 +01:00
Armin Schrenk
9d3d67b605 Update changelog 2026-03-05 23:12:58 +01:00
Armin Schrenk
8da27e36d6 Merge branch 'develop' into release/1.19.0 2026-03-05 23:10:11 +01:00
dependabot[bot]
1123fa28a3 Bump org.apache.maven.plugins:maven-resources-plugin (#4167)
Bumps the maven-build-plugins group with 1 update: [org.apache.maven.plugins:maven-resources-plugin](https://github.com/apache/maven-resources-plugin).


Updates `org.apache.maven.plugins:maven-resources-plugin` from 3.4.0 to 3.5.0
- [Release notes](https://github.com/apache/maven-resources-plugin/releases)
- [Commits](https://github.com/apache/maven-resources-plugin/compare/v3.4.0...maven-resources-plugin-3.5.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-resources-plugin
  dependency-version: 3.5.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: maven-build-plugins
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-05 23:09:12 +01:00
Armin Schrenk
be3ecc536a Update to cryptofs 2.10.0 2026-03-05 17:47:52 +01:00
Armin Schrenk
94c8dd911b [skip ci] update changelog 2026-03-05 17:45:14 +01:00
Armin Schrenk
7e888b0e3b ensure logging for Substituting properties 2026-03-05 17:44:47 +01:00
dependabot[bot]
a066afe37d Bump the java-production-dependencies group with 8 updates (#4152)
* Bump the java-production-dependencies group with 8 updates

Bumps the java-production-dependencies group with 8 updates:

| Package | From | To |
| --- | --- | --- |
| [ch.qos.logback:logback-core](https://github.com/qos-ch/logback) | `1.5.31` | `1.5.32` |
| [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) | `1.5.31` | `1.5.32` |
| [com.auth0:java-jwt](https://github.com/auth0/java-jwt) | `4.5.0` | `4.5.1` |
| [com.fasterxml.jackson.core:jackson-databind](https://github.com/FasterXML/jackson) | `2.21.0` | `2.21.1` |
| com.fasterxml.jackson.datatype:jackson-datatype-jsr310 | `2.21.0` | `2.21.1` |
| [com.google.dagger:dagger](https://github.com/google/dagger) | `2.59.1` | `2.59.2` |
| [com.google.dagger:dagger-compiler](https://github.com/google/dagger) | `2.59.1` | `2.59.2` |
| [org.jetbrains:annotations](https://github.com/JetBrains/java-annotations) | `26.0.2-1` | `26.1.0` |


Updates `ch.qos.logback:logback-core` from 1.5.31 to 1.5.32
- [Release notes](https://github.com/qos-ch/logback/releases)
- [Commits](https://github.com/qos-ch/logback/compare/v_1.5.31...v_1.5.32)

Updates `ch.qos.logback:logback-classic` from 1.5.31 to 1.5.32
- [Release notes](https://github.com/qos-ch/logback/releases)
- [Commits](https://github.com/qos-ch/logback/compare/v_1.5.31...v_1.5.32)

Updates `ch.qos.logback:logback-classic` from 1.5.31 to 1.5.32
- [Release notes](https://github.com/qos-ch/logback/releases)
- [Commits](https://github.com/qos-ch/logback/compare/v_1.5.31...v_1.5.32)

Updates `com.auth0:java-jwt` from 4.5.0 to 4.5.1
- [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.5.0...4.5.1)

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

Updates `com.fasterxml.jackson.datatype:jackson-datatype-jsr310` from 2.21.0 to 2.21.1

Updates `com.fasterxml.jackson.datatype:jackson-datatype-jsr310` from 2.21.0 to 2.21.1

Updates `com.google.dagger:dagger` from 2.59.1 to 2.59.2
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.59.1...dagger-2.59.2)

Updates `com.google.dagger:dagger-compiler` from 2.59.1 to 2.59.2
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.59.1...dagger-2.59.2)

Updates `org.jetbrains:annotations` from 26.0.2-1 to 26.1.0
- [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.2-1...26.1.0)

Updates `com.google.dagger:dagger-compiler` from 2.59.1 to 2.59.2
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.59.1...dagger-2.59.2)

---
updated-dependencies:
- dependency-name: ch.qos.logback:logback-core
  dependency-version: 1.5.32
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: ch.qos.logback:logback-classic
  dependency-version: 1.5.32
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: ch.qos.logback:logback-classic
  dependency-version: 1.5.32
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: com.auth0:java-jwt
  dependency-version: 4.5.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: com.fasterxml.jackson.core:jackson-databind
  dependency-version: 2.21.1
  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-version: 2.21.1
  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-version: 2.21.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: com.google.dagger:dagger
  dependency-version: 2.59.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: com.google.dagger:dagger-compiler
  dependency-version: 2.59.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: org.jetbrains:annotations
  dependency-version: 26.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: java-production-dependencies
- dependency-name: com.google.dagger:dagger-compiler
  dependency-version: 2.59.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>

* [skip ci] update changelog

---------

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>
2026-03-05 17:29:09 +01:00
Cryptobot
21c8cbf709 New Crowdin updates (#4148)
New translations strings.properties

Arabic; Bulgarian; Chinese Simplified; Chinese Traditional; Danish; Dutch; Finnish; French; German; Greek; Italian; Japanese; Korean; Latvian; Polish; Portuguese; Portuguese, Brazilian; Punjabi; Russian; Slovak; Spanish; Swedish; Turkish; Ukrainian; Vietnamese; 

[ci skip]
2026-03-05 17:28:41 +01:00
dependabot[bot]
ea236d45a3 Bump the java-test-dependencies group across 1 directory with 2 updates (#4079)
Bumps the java-test-dependencies group with 2 updates in the / directory: [org.junit.jupiter:junit-jupiter](https://github.com/junit-team/junit-framework) and [org.mockito:mockito-core](https://github.com/mockito/mockito).


Updates `org.junit.jupiter:junit-jupiter` from 5.13.4 to 6.0.1
- [Release notes](https://github.com/junit-team/junit-framework/releases)
- [Commits](https://github.com/junit-team/junit-framework/compare/r5.13.4...r6.0.1)

Updates `org.mockito:mockito-core` from 5.20.0 to 5.21.0
- [Release notes](https://github.com/mockito/mockito/releases)
- [Commits](https://github.com/mockito/mockito/compare/v5.20.0...v5.21.0)

---
updated-dependencies:
- dependency-name: org.junit.jupiter:junit-jupiter
  dependency-version: 6.0.1
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: java-test-dependencies
- dependency-name: org.mockito:mockito-core
  dependency-version: 5.21.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: java-test-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-05 17:27:42 +01:00
dependabot[bot]
fab5ac3726 Bump the maven-build-plugins group across 1 directory with 8 updates (#4151)
* Bump the maven-build-plugins group across 1 directory with 8 updates

Bumps the maven-build-plugins group with 8 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [me.fabriciorby:maven-surefire-junit5-tree-reporter](https://github.com/fabriciorby/maven-surefire-junit5-tree-reporter) | `1.4.0` | `1.5.1` |
| [org.apache.maven.plugins:maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) | `3.14.1` | `3.15.0` |
| [org.apache.maven.plugins:maven-resources-plugin](https://github.com/apache/maven-resources-plugin) | `3.3.1` | `3.4.0` |
| [org.apache.maven.plugins:maven-dependency-plugin](https://github.com/apache/maven-dependency-plugin) | `3.8.1` | `3.10.0` |
| [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) | `3.5.4` | `3.5.5` |
| [org.codehaus.mojo:license-maven-plugin](https://github.com/mojohaus/license-maven-plugin) | `2.7.0` | `2.7.1` |
| [org.apache.maven.plugins:maven-jar-plugin](https://github.com/apache/maven-jar-plugin) | `3.4.2` | `3.5.0` |
| [org.owasp:dependency-check-maven](https://github.com/dependency-check/DependencyCheck) | `12.1.5` | `12.2.0` |



Updates `me.fabriciorby:maven-surefire-junit5-tree-reporter` from 1.4.0 to 1.5.1
- [Release notes](https://github.com/fabriciorby/maven-surefire-junit5-tree-reporter/releases)
- [Commits](https://github.com/fabriciorby/maven-surefire-junit5-tree-reporter/compare/v1.4.0...v1.5.1)

Updates `org.apache.maven.plugins:maven-compiler-plugin` from 3.14.1 to 3.15.0
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.14.1...maven-compiler-plugin-3.15.0)

Updates `org.apache.maven.plugins:maven-resources-plugin` from 3.3.1 to 3.4.0
- [Release notes](https://github.com/apache/maven-resources-plugin/releases)
- [Commits](https://github.com/apache/maven-resources-plugin/compare/maven-resources-plugin-3.3.1...v3.4.0)

Updates `org.apache.maven.plugins:maven-dependency-plugin` from 3.8.1 to 3.10.0
- [Release notes](https://github.com/apache/maven-dependency-plugin/releases)
- [Commits](https://github.com/apache/maven-dependency-plugin/compare/maven-dependency-plugin-3.8.1...maven-dependency-plugin-3.10.0)

Updates `org.apache.maven.plugins:maven-surefire-plugin` from 3.5.4 to 3.5.5
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.5.4...surefire-3.5.5)

Updates `org.codehaus.mojo:license-maven-plugin` from 2.7.0 to 2.7.1
- [Release notes](https://github.com/mojohaus/license-maven-plugin/releases)
- [Commits](https://github.com/mojohaus/license-maven-plugin/compare/2.7.0...2.7.1)

Updates `org.apache.maven.plugins:maven-jar-plugin` from 3.4.2 to 3.5.0
- [Release notes](https://github.com/apache/maven-jar-plugin/releases)
- [Commits](https://github.com/apache/maven-jar-plugin/compare/maven-jar-plugin-3.4.2...maven-jar-plugin-3.5.0)

Updates `org.owasp:dependency-check-maven` from 12.1.5 to 12.2.0
- [Release notes](https://github.com/dependency-check/DependencyCheck/releases)
- [Changelog](https://github.com/dependency-check/DependencyCheck/blob/main/CHANGELOG.md)
- [Commits](https://github.com/dependency-check/DependencyCheck/compare/v12.1.5...v12.2.0)

---
updated-dependencies:
- dependency-name: me.fabriciorby:maven-surefire-junit5-tree-reporter
  dependency-version: 1.5.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: maven-build-plugins
- dependency-name: org.apache.maven.plugins:maven-compiler-plugin
  dependency-version: 3.15.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: maven-build-plugins
- dependency-name: org.apache.maven.plugins:maven-resources-plugin
  dependency-version: 3.4.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: maven-build-plugins
- dependency-name: org.apache.maven.plugins:maven-dependency-plugin
  dependency-version: 3.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: maven-build-plugins
- dependency-name: org.apache.maven.plugins:maven-surefire-plugin
  dependency-version: 3.5.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: maven-build-plugins
- dependency-name: org.codehaus.mojo:license-maven-plugin
  dependency-version: 2.7.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: maven-build-plugins
- dependency-name: org.apache.maven.plugins:maven-jar-plugin
  dependency-version: 3.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: maven-build-plugins
- dependency-name: org.owasp:dependency-check-maven
  dependency-version: 12.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: maven-build-plugins
...

Signed-off-by: dependabot[bot] <support@github.com>

* downgrade maven surefire

---------

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>
2026-03-05 17:23:36 +01:00
dependabot[bot]
57666a620c Bump the github-actions group with 3 updates (#4162)
Bumps the github-actions group with 3 updates: [actions/upload-artifact](https://github.com/actions/upload-artifact), [actions/download-artifact](https://github.com/actions/download-artifact) and [actions/stale](https://github.com/actions/stale).


Updates `actions/upload-artifact` from 6.0.0 to 7.0.0
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](b7c566a772...bbbca2ddaa)

Updates `actions/download-artifact` from 7.0.0 to 8.0.0
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](37930b1c2a...70fc10c6e5)

Updates `actions/stale` from 10.1.1 to 10.2.0
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](997185467f...b5d41d4e1d)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/download-artifact
  dependency-version: 8.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/stale
  dependency-version: 10.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-05 17:12:30 +01:00
Armin Schrenk
e49fe23b35 Explicitly define webdav-nio-adapter-servlet dependency
and update changelog
2026-03-03 18:22:57 +01:00
Armin Schrenk
254a7696c8 [skip ci] update changelog 2026-03-03 18:13:54 +01:00
Armin Schrenk
62bd43ef9b Update fuse-nio-adapter from 6.0.0 to 6.0.1
closes #4121
2026-03-03 18:12:49 +01:00
Tobias Hagemann
b73510ec0f Merge pull request #4166 from cryptomator/feature/liquid-glass-icon
Add Liquid Glass icon for macOS 26 and remove DockTilePlugin workaround
2026-03-03 14:31:23 +01:00
Tobias Hagemann
3fba62ef72 revert icns to legacy icon and recompile Assets.car without fallback bitmaps 2026-03-03 14:16:22 +01:00
Armin Schrenk
7daca70a15 Feature: Replace JavaFX host services with RevealPathService impls (#4165)
when a OS path need to be shown in the OS file browser.
2026-03-03 11:25:29 +01:00
Tobias Hagemann
90228a1d5c add Liquid Glass icon and remove DockTilePlugin workaround 2026-03-03 06:55:24 +01:00
Armin Schrenk
4090413290 increase slightly notify window heigth 2026-02-27 15:52:30 +01:00
Armin Schrenk
29bfbdc524 Adjust wording for in use feature 2026-02-27 15:08:32 +01:00
Armin Schrenk
688090095e harden curl downloads on CI (#4158) 2026-02-26 17:49:38 +01:00
Armin Schrenk
98db9649c3 Merge branch 'main' into develop
# Conflicts:
#	pom.xml
2026-02-26 16:58:00 +01:00
Armin Schrenk
7a4c8f113e Merge branch 'hotfix/1.18.1' 2026-02-26 16:57:10 +01:00
Armin Schrenk
50f6a87788 [skip metadata check] fix release check workflow 2026-02-26 16:53:21 +01:00
Armin Schrenk
d601088948 [skip metadata check] update workflow for hotfix 2026-02-26 16:44:50 +01:00
Armin Schrenk
4d62f2303d prepare version 1.18.1 2026-02-26 16:27:57 +01:00
Armin Schrenk
792734b486 add unit tests 2026-02-26 16:20:34 +01:00
Armin Schrenk
f884861373 skip fallback if failing to load 2026-02-26 15:48:35 +01:00
Armin Schrenk
da3c5e901f fixes #4156
for Windows fallback on JDK shipped cacert file if well-known CA are not present
2026-02-26 15:15:48 +01:00
Armin Schrenk
f7ccc326de drain eventual logger events after debug Mode is enabled 2026-02-25 12:27:06 +01:00
Armin Schrenk
246eb19c3c CI: Build cryptomator-bin package before creating PR. (#4149)
use arch container to build cryptomator-bin package
2026-02-23 11:48:38 +01:00
Armin Schrenk
c073b26d8f fix slack notification for makepkg flow 2026-02-23 11:39:46 +01:00
Armin Schrenk
227a3258ec Update slack webhook in post-publish flow 2026-02-20 18:56:42 +01:00
Armin Schrenk
3279df68c7 Update appimage workflow
* use env variables in action generated/generated input
* use cryptobot as actor for PR
* update slack webhook
2026-02-20 17:33:36 +01:00
Armin Schrenk
bf6598302b add correct info in PR description 2026-02-20 17:18:17 +01:00
Armin Schrenk
dccb4ef072 disable gits safe directory 2026-02-20 17:03:00 +01:00
Armin Schrenk
cbae2413ae use correct github expression varaible
in create-pr step
2026-02-20 16:45:43 +01:00
Armin Schrenk
113ab66a49 Merge pull request #4139 from cryptomator/feature/aur-build
CI: Build arch package
2026-02-20 16:40:05 +01:00
Armin Schrenk
34eb336e5f only commit PKGBUILD and SRCINFO 2026-02-20 16:30:22 +01:00
Armin Schrenk
2cab0c59a1 update javafx to version 25.0.2 2026-02-20 16:23:21 +01:00
Armin Schrenk
3822136e69 update year 2026-02-20 16:23:10 +01:00
Armin Schrenk
1fa4d42d27 use yml multiline syntax 2026-02-20 16:22:55 +01:00
Armin Schrenk
d5bc0914f4 fix description text for PR 2026-02-20 16:17:08 +01:00
Armin Schrenk
ee5165320d Update Git user email for automation commits 2026-02-19 12:04:36 +01:00
Armin Schrenk
1dab85d265 Merge branch 'develop' into release/1.19.0 2026-02-18 16:25:04 +01:00
Armin Schrenk
423752e720 [skip ci] update changelog 2026-02-18 16:22:31 +01:00
Cryptobot
4efcec7e93 New Crowdin updates (#4041)
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]
2026-02-18 15:56:30 +01:00
Armin Schrenk
619d981ded [skip ci] Update README 2026-02-18 15:46:47 +01:00
mindmonk
72d93e943b fix text wrapping in ResetPasswordDialog (#4123) 2026-02-18 15:43:50 +01:00
Armin Schrenk
f07523267d Bump javafx to version 25.0.2 (#4145) 2026-02-18 15:42:51 +01:00
Armin Schrenk
5409470750 update wix 2026-02-18 15:27:36 +01:00
Armin Schrenk
70b7f39bcc revert 5ab12c1b1a for windows build 2026-02-18 15:16:39 +01:00
Armin Schrenk
5ab12c1b1a Update to latest JDK 25 2026-02-18 11:49:13 +01:00
Armin Schrenk
0ac63e7aba Closes #4136 2026-02-18 11:26:42 +01:00
Armin Schrenk
ac6f34fe17 reorder changelog 2026-02-18 11:15:46 +01:00
Armin Schrenk
dba3de230b Update dependencies
* org.cryptomator:integrations-win from 1.5.1 to 1.6.0
* org.cryptomator:webdav-nio-adapter from 3.0.0 to 3.0.1
2026-02-18 11:15:00 +01:00
Armin Schrenk
e11d42bb07 update IDE file 2026-02-18 11:07:18 +01:00
Jan-Peter Klein
171d5d5a4c Fixes #4141 2026-02-18 10:55:49 +01:00
Armin Schrenk
b86d8ca790 [skip ci] update changelog 2026-02-17 15:30:20 +01:00
Armin Schrenk
74fc77ab8d fix pom inconsistency 2026-02-17 15:21:16 +01:00
Armin Schrenk
044dbcb11f Update cryptofs to version 2.10.0-beta3 2026-02-17 15:13:46 +01:00
Armin Schrenk
1b243bb725 suppress logging of expected exception 2026-02-17 15:12:25 +01:00
Armin Schrenk
f21cb90e7d Merge pull request #4025 from purejava/new-secret-service
New keychain backend SecretService for Linux
2026-02-17 13:16:06 +01:00
Armin Schrenk
1e8f272f6a Merge pull request #4143 from cryptomator/dependabot/maven/java-production-dependencies-d98826387a
Bump the java-production-dependencies group across 1 directory with 11 updates
2026-02-17 13:15:07 +01:00
Armin Schrenk
5c1f8e7576 update IDE file 2026-02-17 12:46:19 +01:00
Armin Schrenk
bc0bb38e4c remove dagger formatting due to compile error 2026-02-17 12:45:46 +01:00
Armin Schrenk
b9b02acbe5 Merge pull request #4134 from cryptomator/feature/javafx-color-scheme-change
Feature: Use JavaFX built ins to adapt to OS color scheme
2026-02-17 10:36:23 +01:00
Armin Schrenk
e53598cfce update azure signing to stable version 2026-02-16 17:06:00 +01:00
Armin Schrenk
3fb0e9328f ensure curl only uses https 2026-02-16 17:01:52 +01:00
Armin Schrenk
eb369ba5bd use envsubst also in create-pr job 2026-02-16 16:53:25 +01:00
Armin Schrenk
738bd56270 ensure curl is installed in container 2026-02-16 16:53:07 +01:00
Armin Schrenk
5e29f08d2b make pr-creation condition more explicit 2026-02-16 16:52:27 +01:00
Armin Schrenk
b3a5265b98 add adminConfig path as property 2026-02-16 16:29:01 +01:00
Armin Schrenk
d7d439947d Merge branch 'develop' into feature/aur-build 2026-02-16 16:17:09 +01:00
Armin Schrenk
a79fd63634 [skip ci] update changelog 2026-02-16 16:15:05 +01:00
Armin Schrenk
f753ddc9be Apply suggestions from code review
Co-authored-by: Sebastian Stenzel <overheadhunter@users.noreply.github.com>
2026-02-16 16:05:26 +01:00
Armin Schrenk
2eda795219 create cryptomator dir in opt before copy 2026-02-16 16:01:32 +01:00
Armin Schrenk
158b454b0d fix NPE in EventualLogger 2026-02-16 12:45:57 +01:00
Armin Schrenk
9e6bd913cb refactor FxApplicationStyle
use pattern (removeOldListeners, addNewListerner, applyTheme)
2026-02-16 12:37:46 +01:00
Armin Schrenk
83ef9d06d9 simplify JfxUiAppearanceProvider
and move loading of appearance service into the fx app
2026-02-16 11:55:03 +01:00
Armin Schrenk
cf0052b4f5 revert lambda processing 2026-02-16 11:07:04 +01:00
Armin Schrenk
18ce7d333d fix build
* use JDK 25
* first install git, then checkout
2026-02-16 11:01:43 +01:00
Armin Schrenk
0b4d86768a Closes #4088 2026-02-16 10:13:21 +01:00
Armin Schrenk
f32d0c463f use $GITHUB_WORKSPACE
instead of github.workspace; bug in GitHubs CI system
2026-02-16 10:03:23 +01:00
dependabot[bot]
a77e90738a Bump the java-production-dependencies group across 1 directory with 11 updates
Bumps the java-production-dependencies group with 11 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [org.cryptomator:cryptolib](https://github.com/cryptomator/cryptolib) | `2.2.1` | `2.2.2` |
| [org.cryptomator:fuse-nio-adapter](https://github.com/cryptomator/fuse-nio-adapter) | `5.1.0` | `6.0.0` |
| [ch.qos.logback:logback-core](https://github.com/qos-ch/logback) | `1.5.19` | `1.5.31` |
| [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) | `1.5.19` | `1.5.31` |
| org.apache.commons:commons-lang3 | `3.19.0` | `3.20.0` |
| [com.fasterxml.jackson.core:jackson-databind](https://github.com/FasterXML/jackson) | `2.20.0` | `2.21.0` |
| com.fasterxml.jackson.datatype:jackson-datatype-jsr310 | `2.20.0` | `2.21.0` |
| [com.google.dagger:dagger](https://github.com/google/dagger) | `2.57.2` | `2.59.1` |
| [com.google.dagger:dagger-compiler](https://github.com/google/dagger) | `2.57.2` | `2.59.1` |
| [com.github.ben-manes.caffeine:caffeine](https://github.com/ben-manes/caffeine) | `3.2.2` | `3.2.3` |
| [org.cryptomator:integrations-linux](https://github.com/cryptomator/integrations-linux) | `1.7.0-beta3` | `1.7.0-beta4` |



Updates `org.cryptomator:cryptolib` from 2.2.1 to 2.2.2
- [Release notes](https://github.com/cryptomator/cryptolib/releases)
- [Changelog](https://github.com/cryptomator/cryptolib/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/cryptomator/cryptolib/compare/2.2.1...2.2.2)

Updates `org.cryptomator:fuse-nio-adapter` from 5.1.0 to 6.0.0
- [Release notes](https://github.com/cryptomator/fuse-nio-adapter/releases)
- [Changelog](https://github.com/cryptomator/fuse-nio-adapter/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/cryptomator/fuse-nio-adapter/compare/5.1.0...6.0.0)

Updates `ch.qos.logback:logback-core` from 1.5.19 to 1.5.31
- [Release notes](https://github.com/qos-ch/logback/releases)
- [Commits](https://github.com/qos-ch/logback/compare/v_1.5.19...v_1.5.31)

Updates `ch.qos.logback:logback-classic` from 1.5.19 to 1.5.31
- [Release notes](https://github.com/qos-ch/logback/releases)
- [Commits](https://github.com/qos-ch/logback/compare/v_1.5.19...v_1.5.31)

Updates `ch.qos.logback:logback-classic` from 1.5.19 to 1.5.31
- [Release notes](https://github.com/qos-ch/logback/releases)
- [Commits](https://github.com/qos-ch/logback/compare/v_1.5.19...v_1.5.31)

Updates `org.apache.commons:commons-lang3` from 3.19.0 to 3.20.0

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

Updates `com.fasterxml.jackson.datatype:jackson-datatype-jsr310` from 2.20.0 to 2.21.0

Updates `com.fasterxml.jackson.datatype:jackson-datatype-jsr310` from 2.20.0 to 2.21.0

Updates `com.google.dagger:dagger` from 2.57.2 to 2.59.1
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.57.2...dagger-2.59.1)

Updates `com.google.dagger:dagger-compiler` from 2.57.2 to 2.59.1
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.57.2...dagger-2.59.1)

Updates `com.github.ben-manes.caffeine:caffeine` from 3.2.2 to 3.2.3
- [Release notes](https://github.com/ben-manes/caffeine/releases)
- [Commits](https://github.com/ben-manes/caffeine/compare/v3.2.2...v3.2.3)

Updates `com.google.dagger:dagger-compiler` from 2.57.2 to 2.59.1
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.57.2...dagger-2.59.1)

Updates `org.cryptomator:integrations-linux` from 1.7.0-beta3 to 1.7.0-beta4
- [Release notes](https://github.com/cryptomator/integrations-linux/releases)
- [Changelog](https://github.com/cryptomator/integrations-linux/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/cryptomator/integrations-linux/compare/1.7.0-beta3...1.7.0-beta4)

---
updated-dependencies:
- dependency-name: org.cryptomator:cryptolib
  dependency-version: 2.2.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: org.cryptomator:fuse-nio-adapter
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: java-production-dependencies
- dependency-name: ch.qos.logback:logback-core
  dependency-version: 1.5.31
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: ch.qos.logback:logback-classic
  dependency-version: 1.5.31
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: ch.qos.logback:logback-classic
  dependency-version: 1.5.31
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: org.apache.commons:commons-lang3
  dependency-version: 3.20.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: java-production-dependencies
- dependency-name: com.fasterxml.jackson.core:jackson-databind
  dependency-version: 2.21.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: java-production-dependencies
- dependency-name: com.fasterxml.jackson.datatype:jackson-datatype-jsr310
  dependency-version: 2.21.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: java-production-dependencies
- dependency-name: com.fasterxml.jackson.datatype:jackson-datatype-jsr310
  dependency-version: 2.21.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: java-production-dependencies
- dependency-name: com.google.dagger:dagger
  dependency-version: 2.59.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: java-production-dependencies
- dependency-name: com.google.dagger:dagger-compiler
  dependency-version: 2.59.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: java-production-dependencies
- dependency-name: com.github.ben-manes.caffeine:caffeine
  dependency-version: 3.2.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
- dependency-name: com.google.dagger:dagger-compiler
  dependency-version: 2.59.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: java-production-dependencies
- dependency-name: org.cryptomator:integrations-linux
  dependency-version: 1.7.0-beta4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: java-production-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-16 06:06:54 +00:00
Armin Schrenk
7275ec9a61 fix envsubst command 2026-02-13 18:17:14 +01:00
Armin Schrenk
0fa34dba33 replace PKGBUILD with PKGBUILD.template
use envsubst to create actual PKGBUILD
2026-02-13 17:49:45 +01:00
Armin Schrenk
49f070977a use proper quotes 2026-02-13 13:59:11 +01:00
Armin Schrenk
35f39a9eaf minor fixes 2026-02-13 13:58:04 +01:00
Armin Schrenk
b9d21b1b7a replace hypens with underscore in pkgbuild version 2026-02-13 13:55:56 +01:00
Armin Schrenk
2e698317e5 Indirect github action inputs with env vars 2026-02-13 13:50:39 +01:00
Armin Schrenk
9c88fbab5e merge tarball job into pr creation job 2026-02-13 13:41:54 +01:00
Armin Schrenk
1a51642eb1 fix workflow 2026-02-13 13:30:47 +01:00
Armin Schrenk
fdaf5d1c36 rename 'aur' dir to ' makepkg'
mention the format rather a specific repository
2026-02-13 13:29:38 +01:00
Armin Schrenk
00e824a1ba fix workflow 2026-02-13 13:24:04 +01:00
Armin Schrenk
9c5ab7e311 build arch package on CLI 2026-02-13 13:18:34 +01:00
mindmonk
0bec741c2b Merge pull request #4120 from cryptomator/feature/disable-password-tab-if-masterkey-missing
Disable recovery key actions in Vault Password options when masterkey is missing
2026-02-12 18:08:52 +01:00
Armin Schrenk
af43aeca15 Merge branch 'develop' into feature/javafx-color-scheme-change 2026-02-12 10:18:32 +01:00
Armin Schrenk
1629eae5d3 [skip ci] update changelog 2026-02-11 15:55:34 +01:00
Armin Schrenk
99898b74fb minor cleanup 2026-02-11 15:55:19 +01:00
Armin Schrenk
327d6065e9 Merge pull request #4105 from cryptomator/feature/admin-properties
Feature: Admin Config
2026-02-11 15:25:31 +01:00
Armin Schrenk
2a5ef5d999 log inconsistent state 2026-02-11 15:21:55 +01:00
Armin Schrenk
34e5d19a04 prevent resource leak 2026-02-11 15:16:11 +01:00
Armin Schrenk
33851a8559 Refactor admin props
* rename class to AdminPropertiesFactory
* rename factory method to "create"
* remove side effects from methods
* returned properties default to system properties
2026-02-11 15:12:52 +01:00
Armin Schrenk
fb54d96997 fix wrong method delegation 2026-02-11 14:49:56 +01:00
Armin Schrenk
cff47b1c73 wrap system properties instead of direct modification 2026-02-11 14:36:55 +01:00
Armin Schrenk
5db05d8bc7 Apply suggestions from codereview 2026-02-11 14:33:01 +01:00
Armin Schrenk
b85780eae9 Disable JavaFX based UiAppearanceProvider for macOS 2026-02-11 12:22:22 +01:00
Ralph Plawetzki
bdfd22c483 Partially reverts dd1af8cd78
Not needed anymore, see https://github.com/cryptomator/integrations-linux/pull/125#issuecomment-3876060158
2026-02-11 06:07:01 +01:00
Armin Schrenk
e3433cb312 Refactor FxApplicationStyle class 2026-02-10 18:17:09 +01:00
Armin Schrenk
46d1d605ad refactor JfxUiAppearanceProvider class
* use delegate pattern for initialization
* add logging
2026-02-10 18:01:36 +01:00
Armin Schrenk
a4eadd4817 remove theme change restrictions 2026-02-10 17:58:29 +01:00
Armin Schrenk
c6717bd4e1 Rely on javafx to change color theme 2026-02-09 17:48:23 +01:00
Armin Schrenk
53f368108a Rename jvm property and actual config file 2026-02-09 16:54:04 +01:00
Armin Schrenk
5e52811c74 Remove hard coded default locations for admin config 2026-02-09 16:49:12 +01:00
Armin Schrenk
cad7b45808 Refactor to first check system property cryptomator.adminConfig for config path 2026-02-09 16:16:26 +01:00
Armin Schrenk
a057bf6f70 Merge branch 'develop' into feature/admin-properties 2026-02-09 15:03:06 +01:00
Armin Schrenk
4cf11cf293 [skip ci] update changelog 2026-02-09 14:56:37 +01:00
Armin Schrenk
2523609996 disable loading of user defined config for windows msi (#4132) 2026-02-09 14:49:07 +01:00
dependabot[bot]
80276ee992 Bump the github-actions group across 1 directory with 8 updates (#4124)
Bumps the github-actions group with 8 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [actions/checkout](https://github.com/actions/checkout) | `6.0.1` | `6.0.2` |
| [actions/setup-java](https://github.com/actions/setup-java) | `5.1.0` | `5.2.0` |
| [actions/upload-artifact](https://github.com/actions/upload-artifact) | `5.0.0` | `6.0.0` |
| [actions/download-artifact](https://github.com/actions/download-artifact) | `6.0.0` | `7.0.0` |
| [actions/cache](https://github.com/actions/cache) | `4.3.0` | `5.0.3` |
| [skymatic/workflows/.github/workflows/run-dependency-check.yml](https://github.com/skymatic/workflows) | `3.0.1` | `3.0.2` |
| [fjogeleit/http-request-action](https://github.com/fjogeleit/http-request-action) | `1.16.6` | `2.0.0` |
| [skymatic/workflows](https://github.com/skymatic/workflows) | `3.0.1` | `3.0.2` |



Updates `actions/checkout` from 6.0.1 to 6.0.2
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](8e8c483db8...de0fac2e45)

Updates `actions/setup-java` from 5.1.0 to 5.2.0
- [Release notes](https://github.com/actions/setup-java/releases)
- [Commits](f2beeb24e1...be666c2fcd)

Updates `actions/upload-artifact` from 5.0.0 to 6.0.0
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](330a01c490...b7c566a772)

Updates `actions/download-artifact` from 6.0.0 to 7.0.0
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](018cc2cf5b...37930b1c2a)

Updates `actions/cache` from 4.3.0 to 5.0.3
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](0057852bfa...cdf6c1fa76)

Updates `skymatic/workflows/.github/workflows/run-dependency-check.yml` from 3.0.1 to 3.0.2
- [Release notes](https://github.com/skymatic/workflows/releases)
- [Commits](1074588008...2d0c27a7b0)

Updates `fjogeleit/http-request-action` from 1.16.6 to 2.0.0
- [Release notes](https://github.com/fjogeleit/http-request-action/releases)
- [Changelog](https://github.com/fjogeleit/http-request-action/blob/main/RELEASE.md)
- [Commits](c0b95d02a0...551353b829)

Updates `skymatic/workflows` from 3.0.1 to 3.0.2
- [Release notes](https://github.com/skymatic/workflows/releases)
- [Commits](1074588008...2d0c27a7b0)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 6.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: actions/setup-java
  dependency-version: 5.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: actions/upload-artifact
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/download-artifact
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/cache
  dependency-version: 5.0.3
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: skymatic/workflows/.github/workflows/run-dependency-check.yml
  dependency-version: 3.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: fjogeleit/http-request-action
  dependency-version: 2.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: skymatic/workflows
  dependency-version: 3.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-09 09:27:49 +01:00
Ralph Plawetzki
561432bc98 Revert "Make SecretServiceKeychainAccess the default selection"
This reverts commit 9a74194391.
Users decide when to migrate.
2026-02-05 08:15:10 +01:00
Ralph Plawetzki
cd0a640a36 Enable migrating KeychainEntries on Linux as well 2026-02-05 07:09:38 +01:00
Armin Schrenk
a7b8541912 Update Slack webhook URL secret in workflow 2026-01-30 15:27:31 +01:00
Jan-Peter Klein
d4382f3130 remove docTooltip 2026-01-28 18:40:56 +01:00
Jan-Peter Klein
2983745be5 remove docs link 2026-01-28 18:20:18 +01:00
Armin Schrenk
77983fe00a simplify EventualLogger init 2026-01-28 17:44:48 +01:00
Armin Schrenk
a4836f6528 cleanup 2026-01-28 17:36:52 +01:00
Armin Schrenk
e9b3b505a8 apply suggestions from code review 2026-01-28 17:35:34 +01:00
Armin Schrenk
19c9eada9d check first the filesize before opening a Reader to the config file 2026-01-28 17:32:10 +01:00
Jan-Peter Klein
2a5bce2c5c disable password tab when masterkey.file is missing 2026-01-27 17:42:04 +01:00
mindmonk
9ee81a0e35 Merge pull request #4106 from cryptomator/feature/move-recover-io-tasks-to-background
Move recovery I/O to background thread
2026-01-26 13:30:39 +01:00
Jan-Peter Klein
8b05ae0a54 dedup createTask 2026-01-23 16:09:06 +01:00
Jan-Peter Klein
aa898c634f refactor recovery restore to sync logic with async task wrapper for testability 2026-01-23 13:57:38 +01:00
Armin Schrenk
efbd107fb5 increase null safety 2026-01-21 18:09:26 +01:00
Armin Schrenk
300cac5441 don't forget log markers 2026-01-21 16:36:56 +01:00
Armin Schrenk
b651b9ac26 config file can be exactly the max size 2026-01-21 16:08:00 +01:00
Armin Schrenk
29e76e7f93 keep throwables in EventualLogger 2026-01-21 16:07:17 +01:00
Armin Schrenk
5cac6b8114 also adjust distribution 2026-01-21 15:55:04 +01:00
Armin Schrenk
35c2141fd6 cleanup 2026-01-21 15:34:34 +01:00
Armin Schrenk
b00c81c20a use "cryptomator.config" for config file 2026-01-21 15:34:24 +01:00
Armin Schrenk
7ee0606306 adjust unit tests 2026-01-21 15:34:08 +01:00
Armin Schrenk
046372f95b refactored BufferedLog
* rename to EventualLogger
* adhere to slf4j API
* ensure single instance
2026-01-21 15:33:26 +01:00
Armin Schrenk
c198adaf3f switch back to properties 2026-01-21 11:53:31 +01:00
Armin Schrenk
d53f0880ca add test for AdminPropertiesSetter 2026-01-15 18:06:24 +01:00
Armin Schrenk
088b177c0e Ensure that null map is also logged 2026-01-15 15:11:46 +01:00
Armin Schrenk
287ab4e792 [skip ci] Update changelog 2026-01-15 15:11:12 +01:00
Armin Schrenk
0e9cad5b09 Merge pull request #4103 from cryptomator/feature/basic-accessibility
Feature: Improve accessibility for core functionality
2026-01-15 10:44:16 +01:00
Armin Schrenk
a0c9caeb21 [skip ci] update changelog 2026-01-14 17:57:24 +01:00
Armin Schrenk
f620c6685a apply suggestions from AI review 2026-01-14 17:53:07 +01:00
Armin Schrenk
61be8c449c fixed flush does not clear BufferedLog 2026-01-14 17:39:49 +01:00
Armin Schrenk
43343b9954 fix wrong Linux path 2026-01-14 17:36:07 +01:00
Armin Schrenk
460b7e6225 [skip ci] update changelog 2026-01-14 17:33:45 +01:00
Armin Schrenk
e2430bfb22 add null check 2026-01-14 17:29:56 +01:00
Armin Schrenk
ac7c9c2165 use a bracket to "describe" the vault state 2026-01-14 17:28:20 +01:00
Jan-Peter Klein
efd73e0d3e move recovery IO operations to background 2026-01-14 17:14:23 +01:00
Armin Schrenk
b441803462 also adjust wix installer to new config format 2026-01-14 16:28:48 +01:00
Armin Schrenk
42b06aa556 Switch to JSON as config format
Java Properties require ISO 8859-1 character encoding, leading to manual edits of file.
2026-01-14 14:12:28 +01:00
Armin Schrenk
b1c21501a6 Add dummy admin properties file in Windows installer 2026-01-13 18:40:53 +01:00
Armin Schrenk
45633837e0 only allow overwriting a subset of JVM properties 2026-01-13 17:26:48 +01:00
Armin Schrenk
b23bd0b27a Implement logic to overwrite system properties set in app internal config file 2026-01-13 13:14:40 +01:00
Armin Schrenk
b3f3faf4ee add DIALOG role to more dialogs 2026-01-13 11:02:01 +01:00
Armin Schrenk
33f26bf804 Refactor notificationbar
* rename to InfoBar
* replace closeButton text with graphic and add accessibilityText
* use common base class for styling and use CSS lookup for variants
2026-01-12 23:31:37 +01:00
Armin Schrenk
a06accb80f add accessibletext to vault storage location 2026-01-12 23:15:40 +01:00
Armin Schrenk
a50e372f05 add correct accessible role to dialogs 2026-01-12 23:14:09 +01:00
Armin Schrenk
06726303fb add proper accessibility text for vault list 2026-01-12 23:13:15 +01:00
Armin Schrenk
11c86f7287 impl idea 2026-01-12 11:59:17 +01:00
mindmonk
8e68a62ab0 Merge pull request #4081 from cryptomator/feature/hub-vault-archived-dialog
Feature: Show dedicated “Archived Vault” screen on unlock when Hub returns 410
2026-01-06 11:20:29 +01:00
Jan-Peter Klein
787d0b8e12 code cleanup 2026-01-05 14:00:20 +01:00
Jan-Peter Klein
ba765f7a69 code cleanup 2026-01-05 13:31:45 +01:00
Jan-Peter Klein
e9d7e631c7 fix typo 2026-01-05 13:27:50 +01:00
Jan-Peter Klein
88acbc8ed7 fix typo 2026-01-05 13:22:01 +01:00
Jan-Peter Klein
e84a73b9c3 use SimpleDialog 2026-01-05 13:17:10 +01:00
Jan-Peter Klein
2324ddad8b update changelog 2026-01-05 11:53:51 +01:00
Jan-Peter Klein
04da2504de Merge branch 'develop' into feature/hub-vault-archived-dialog 2026-01-05 11:28:08 +01:00
Armin Schrenk
ad240eb18b Merge branch 'develop' into release/1.19.0
# Conflicts:
#	pom.xml
2025-12-30 12:40:06 +01:00
Armin Schrenk
8105dbc236 Closes #4058 2025-12-30 12:31:45 +01:00
Armin Schrenk
ceed70c314 [skip ci] update changelog 2025-12-29 16:59:01 +01:00
Armin Schrenk
eddf586b81 Merge pull request #4078 from cryptomator/feature/files-in-use
Feature: Files in use
2025-12-29 16:00:36 +01:00
Armin Schrenk
0d7ddd3189 [skip ci] Update changelog 2025-12-29 15:55:49 +01:00
Armin Schrenk
491cd5e550 install/remove the encrypted mime type on install/uninstall 2025-12-29 15:22:26 +01:00
Armin Schrenk
93d95ecd93 make message more clear
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-21 12:42:11 +01:00
Armin Schrenk
05a41a625c reset selection index everytime window is shown
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-21 12:32:35 +01:00
Armin Schrenk
2aff02a186 cleanup
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-21 12:27:07 +01:00
Armin Schrenk
4b7de11750 dedup css
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-21 12:26:08 +01:00
Armin Schrenk
aaf921afcf Adjust notification dialog
* add scrollbar to description content
* move filename to own visual element
* move vaultName above message

Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-21 11:40:02 +01:00
Armin Schrenk
7718445f7c rename method
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-21 11:00:01 +01:00
Armin Schrenk
0fa27f66c9 Use proper icon for in-use event 2025-12-19 13:54:47 +01:00
Armin Schrenk
111c5ae2de correctly convert URI path to system path 2025-12-19 13:25:42 +01:00
Armin Schrenk
8841bb1c6a add c9u as file extension 2025-12-18 17:55:43 +01:00
Armin Schrenk
8ca7e34d8f minor fixes 2025-12-18 16:47:45 +01:00
Armin Schrenk
0fa6f0d915 only close notification window on index error 2025-12-18 16:20:58 +01:00
Armin Schrenk
4ffd8f4467 add localization for file-is-in-use-event in event view 2025-12-18 16:19:42 +01:00
Armin Schrenk
bb0c1b54c1 Add log message to get used mount service 2025-12-18 15:39:56 +01:00
Armin Schrenk
8eb91f6471 Change design of files-in-use-notification
* add timestamp of event occurance
* move filename into message section
* remove translations
2025-12-18 13:28:04 +01:00
Armin Schrenk
eb20fd7278 add device name to filesystemowner and display device name in notification 2025-12-17 16:55:42 +01:00
Armin Schrenk
d836798361 only one instance of notification window 2025-12-17 16:27:10 +01:00
Jan-Peter Klein
760e260eba show archived vault dialog on unlock when Hub returns 410 2025-12-17 09:56:56 +01:00
Armin Schrenk
0cd6eb8b5e use Path api to concat (string) paths for events
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-16 12:52:35 +01:00
Armin Schrenk
0b2107309b guard the notification window from theoretical thread races
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-16 12:33:25 +01:00
dependabot[bot]
309881b339 Bump the github-actions group across 1 directory with 8 updates (#4073)
Bumps the github-actions group with 8 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [actions/checkout](https://github.com/actions/checkout) | `5.0.0` | `6.0.1` |
| [actions/setup-java](https://github.com/actions/setup-java) | `5.0.0` | `5.1.0` |
| [actions/upload-artifact](https://github.com/actions/upload-artifact) | `4.6.2` | `5.0.0` |
| [softprops/action-gh-release](https://github.com/softprops/action-gh-release) | `2.4.1` | `2.5.0` |
| [actions/download-artifact](https://github.com/actions/download-artifact) | `5.0.0` | `6.0.0` |
| [fjogeleit/http-request-action](https://github.com/fjogeleit/http-request-action) | `1.16.5` | `1.16.6` |
| [actions/stale](https://github.com/actions/stale) | `10.1.0` | `10.1.1` |
| [skymatic/workflows](https://github.com/skymatic/workflows) | `450e322ff2214d0be0b079b63343c894f3ef735f` | `1074588008ae3326a2221ea451783280518f0366` |



Updates `actions/checkout` from 5.0.0 to 6.0.1
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](08c6903cd8...8e8c483db8)

Updates `actions/setup-java` from 5.0.0 to 5.1.0
- [Release notes](https://github.com/actions/setup-java/releases)
- [Commits](dded088883...f2beeb24e1)

Updates `actions/upload-artifact` from 4.6.2 to 5.0.0
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](ea165f8d65...330a01c490)

Updates `softprops/action-gh-release` from 2.4.1 to 2.5.0
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](6da8fa9354...a06a81a03e)

Updates `actions/download-artifact` from 5.0.0 to 6.0.0
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](634f93cb29...018cc2cf5b)

Updates `fjogeleit/http-request-action` from 1.16.5 to 1.16.6
- [Release notes](https://github.com/fjogeleit/http-request-action/releases)
- [Commits](1297c6fc63...c0b95d02a0)

Updates `actions/stale` from 10.1.0 to 10.1.1
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](5f858e3efb...997185467f)

Updates `skymatic/workflows` from 450e322ff2214d0be0b079b63343c894f3ef735f to 1074588008ae3326a2221ea451783280518f0366
- [Release notes](https://github.com/skymatic/workflows/releases)
- [Commits](450e322ff2...1074588008)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 6.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: actions/setup-java
  dependency-version: 5.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: actions/upload-artifact
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: softprops/action-gh-release
  dependency-version: 2.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: actions/download-artifact
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: fjogeleit/http-request-action
  dependency-version: 1.16.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: actions/stale
  dependency-version: 10.1.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: skymatic/workflows
  dependency-version: 1074588008ae3326a2221ea451783280518f0366
  dependency-type: direct:production
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-16 09:54:39 +01:00
Armin Schrenk
532cdf30ac Fix typos 2025-12-12 17:41:29 +01:00
Armin Schrenk
d746e9e215 add translation to event 2025-12-12 16:55:15 +01:00
Armin Schrenk
408c80744a Show notification for fileIsInUseEvent 2025-12-12 13:29:46 +01:00
Armin Schrenk
bf890d2165 Merge pull request #4069 from cryptomator/feature/notify-fallback
Feature: Notification Window with JavaFX
2025-12-12 12:42:37 +01:00
Armin Schrenk
eb90a7fb33 Merge branch 'feature/files-in-use' into feature/notify-fallback
# Conflicts:
#	src/main/java/org/cryptomator/common/EventMap.java
#	src/main/java/org/cryptomator/common/vaults/Vault.java
2025-12-12 12:31:08 +01:00
Armin Schrenk
a47814f38c cleanup 2025-12-12 12:26:46 +01:00
Armin Schrenk
8b157fd935 add dark theme 2025-12-12 12:25:47 +01:00
Armin Schrenk
5e582f666c add accessibleText 2025-12-12 11:37:42 +01:00
Armin Schrenk
bebe3064ee hide paging if there is only one event 2025-12-12 11:21:39 +01:00
Armin Schrenk
bbf8e1d1e5 Ensure that keyloader is not reused between vaults 2025-12-11 14:35:23 +01:00
Armin Schrenk
98d2442deb For hub vaults set filesystem owner 2025-12-11 14:34:45 +01:00
Armin Schrenk
cac5c86dab Merge branch 'develop' into feature/files-in-use
# Conflicts:
#	pom.xml
2025-12-10 13:04:34 +01:00
Armin Schrenk
5a0145800d Redesign notifcation dialog
* add Cryptomator title
* include vault name in message
* remove bottom section and move button to current message area
2025-12-10 13:01:07 +01:00
Armin Schrenk
f4b56e5e51 rename variable 2025-12-10 12:34:33 +01:00
Armin Schrenk
7cfb63ed48 cleanup in NotificationController 2025-12-10 12:34:09 +01:00
Armin Schrenk
2521cd2bfb cleanup
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-09 18:13:04 +01:00
Armin Schrenk
1e861ac187 fix av-whitelist workflow 2025-12-09 09:34:25 +01:00
Tobias Hagemann
a4c85be61c Add accessible text to form controls and table columns (#4066) 2025-12-06 07:41:39 +01:00
Armin Schrenk
5b9e70da33 implement code suggestions
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-05 17:32:24 +01:00
Armin Schrenk
b83a3c27c6 [skip ci] remove unused import
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-05 16:52:04 +01:00
Armin Schrenk
5c2954de03 guard controller from NPE
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-05 16:43:39 +01:00
Armin Schrenk
8a834fe71c fix window placement
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-05 16:38:37 +01:00
Armin Schrenk
4ff2905723 regularly poll for notification updates
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-05 16:37:31 +01:00
Armin Schrenk
538e01b1e5 consider location of system bar when placing notification window
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-05 15:54:05 +01:00
Armin Schrenk
3135be9178 fix logic in notificationManager
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-05 12:14:07 +01:00
Armin Schrenk
2c456f5323 fix more issues
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-05 11:58:16 +01:00
Armin Schrenk
9d464e3a4f fix threading issue in notification manager
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-05 11:53:43 +01:00
Armin Schrenk
83199eb1de use VaultEvent for notification to also show affected vault
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-05 11:35:54 +01:00
Armin Schrenk
5772ffec17 activate notifications by consuming vault events
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-05 11:27:01 +01:00
Armin Schrenk
f3415277d7 cleanup
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-05 11:23:52 +01:00
Armin Schrenk
8e9a001fde clean up
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-05 10:50:48 +01:00
Armin Schrenk
5e229395f1 remove test code
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-05 10:50:32 +01:00
Armin Schrenk
18dd9770f2 add second fake event
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-04 17:03:47 +01:00
Armin Schrenk
185c5a4f5d implement more ui logic
and reduce css

Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-04 17:03:36 +01:00
Armin Schrenk
285ddac219 ai thoughts
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-04 16:20:49 +01:00
Armin Schrenk
9e631a78f2 Pimp notification dialog
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-12-04 15:35:05 +01:00
Tobias Hagemann
7fe9049266 Improve accessibility for icon-only controls and input labels (#4064) 2025-12-01 22:06:57 +01:00
Tobias Hagemann
39ab9ad63f Merge pull request #4055 from tamaracha/fix_a11y_buttons
Fix a11y for no-graphics buttons in main window
2025-12-01 16:13:10 +01:00
Armin Schrenk
b4528f825e [skip ci] drop interface approach and just add fx window 2025-11-29 18:03:55 +01:00
Armin Schrenk
3d679c73e7 [skip ci] impl draft
Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
2025-11-28 14:31:04 +01:00
Sebastian Stenzel
04bdb2d8c4 fix mocked update check 2025-11-24 20:58:57 +01:00
Sebastian Stenzel
f32d24c1c0 Merge branch 'develop' into release/1.19.0 2025-11-24 20:58:25 +01:00
Sebastian Stenzel
f4f093bb42 update GitHub Releases Template
[ci skip]
2025-11-24 19:57:24 +01:00
Tamara Cook
b6d0823c24 Add accessible text and tooltips to no-graphics buttons in main window 2025-11-23 22:24:31 +01:00
Tamara Cook
7f4776a995 Make buttons clickable by any input device 2025-11-23 19:26:55 +01:00
Armin Schrenk
9d2b31cd56 Merge branch 'develop' into feature/files-in-use 2025-11-21 10:15:24 +01:00
Armin Schrenk
cee22e34db adjust display text 2025-10-31 14:18:07 +01:00
Ralph Plawetzki
9a74194391 Make SecretServiceKeychainAccess the default selection 2025-10-27 05:33:35 +01:00
Armin Schrenk
18300ee67f [skip ci] adjust to changed API 2025-10-21 15:36:51 +02:00
Armin Schrenk
5797108dfe Merge branch 'develop' into feature/files-in-use 2025-10-16 12:33:14 +02:00
Armin Schrenk
e1ff552f08 [skip ci] pick a distinguishable name for fs owner 2025-10-15 17:27:12 +02:00
Armin Schrenk
f3d4494d91 [skip ci] Adjust event view to new API 2025-10-15 17:21:20 +02:00
Armin Schrenk
bdc1cc3f05 Merge branch 'develop' into feature/files-in-use
# Conflicts:
#	pom.xml
2025-10-15 17:20:37 +02:00
Armin Schrenk
f5bd23de51 test impl 2025-09-02 09:58:52 +02:00
253 changed files with 5420 additions and 1988 deletions

View File

@@ -48,7 +48,7 @@ runs:
echo "client-secret=${{ inputs.client-secret }}" >> "$GITHUB_OUTPUT"
shell: bash
- name: Sign DLLs with Azure Trusted Signing
uses: azure/trusted-signing-action@fc390cf8ed0f14e248a542af1d838388a47c7a7c # v0.5.10
uses: azure/artifact-signing-action@87c2e83e6868da99d3380aa309851b32ed9a8346 # v1.1.0
with:
files-folder: ${{ inputs.base-dir }}
files-folder-filter: ${{ inputs.file-extensions }}
@@ -59,7 +59,7 @@ runs:
azure-tenant-id: ${{ steps.set-secrets.outputs.tenant-id }}
azure-client-id: ${{ steps.set-secrets.outputs.client-id }}
azure-client-secret: ${{ steps.set-secrets.outputs.client-secret }}
trusted-signing-account-name: cryptomatorSigning
signing-account-name: cryptomatorSigning
certificate-profile-name: production
endpoint: https://weu.codesigning.azure.net/
timestamp-rfc3161: http://timestamp.acs.microsoft.com

View File

@@ -14,6 +14,9 @@ updates:
versions: ["2.0.1.MR"]
- dependency-name: "org.openjfx:*"
update-types: ["version-update:semver-major"]
# due to https://github.com/fabriciorby/maven-surefire-junit5-tree-reporter/issues/68
- dependency-name: "org.apache.maven.plugins:maven-surefire-plugin"
versions: [ "3.5.4", "3.5.5" ]
groups:
java-test-dependencies:
patterns:

View File

@@ -8,6 +8,10 @@ on:
version:
description: 'Version'
required: false
create-pr:
description: 'Create a PR for aur-bin repo'
type: boolean
default: false
push:
branches-ignore:
- 'dependabot/**'
@@ -19,7 +23,7 @@ on:
env:
JAVA_DIST: 'temurin'
JAVA_VERSION: '25.0.1+8.0.LTS'
JAVA_VERSION: '25.0.2+10.0.LTS'
jobs:
get-version:
@@ -31,22 +35,28 @@ jobs:
name: Build AppImage
runs-on: ${{ matrix.os }}
needs: [get-version]
env:
SEMVER_STR: ${{ needs.get-version.outputs.semVerStr }}
SEMVER_NUM: ${{ needs.get-version.outputs.semVerNum }}
REV_NUM: ${{ needs.get-version.outputs.revNum }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
appimage-suffix: x86_64
openjfx-url: 'https://download2.gluonhq.com/openjfx/25/openjfx-25_linux-x64_bin-jmods.zip'
openjfx-sha: '96e520f48610d8ffb94ca30face1f11ffe8a977ddc1c4ff80b1a9e9f048bd94e'
arch: x86_64
openjfx-url: 'https://download2.gluonhq.com/openjfx/25.0.2/openjfx-25.0.2_linux-x64_bin-jmods.zip'
openjfx-sha: 'e0a9c29d8cf3af9b8b48848b43f87b5785bc107c53a951b19668ce05842bba1b'
appimagetool-sha: 'ed4ce84f0d9caff66f50bcca6ff6f35aae54ce8135408b3fa33abfc3cb384eb0'
- os: ubuntu-24.04-arm
appimage-suffix: aarch64
openjfx-url: 'https://download2.gluonhq.com/openjfx/25/openjfx-25_linux-aarch64_bin-jmods.zip'
openjfx-sha: '9ad4ca7b769ca4ee6419f1e99143dd6ff812f8be4fddb46a7d7cacbeea148af4'
arch: aarch64
openjfx-url: 'https://download2.gluonhq.com/openjfx/25.0.2/openjfx-25.0.2_linux-aarch64_bin-jmods.zip'
openjfx-sha: 'c3408f818693cce09e59829a8e862a82c7695fdfcd585c41cfd527f5fc3fe646'
appimagetool-sha: 'f0837e7448a0c1e4e650a93bb3e85802546e60654ef287576f46c71c126a9158'
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Java
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
distribution: ${{ env.JAVA_DIST }}
java-version: ${{ env.JAVA_VERSION }}
@@ -55,7 +65,7 @@ jobs:
- name: Download OpenJFX jmods
id: download-jmods
run: |
curl -L ${{ matrix.openjfx-url }} -o openjfx-jmods.zip
curl --silent --fail-with-body --proto "=https" -L ${{ matrix.openjfx-url }} -o openjfx-jmods.zip
echo "${{ matrix.openjfx-sha }} 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
@@ -73,7 +83,7 @@ jobs:
exit 1
fi
- name: Set version
run : mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }}
run : mvn versions:set -DnewVersion="$SEMVER_STR"
- name: Run maven
run: mvn -B clean package -Plinux -DskipTests
- name: Patch target dir
@@ -94,13 +104,15 @@ jobs:
${JAVA_HOME}/bin/jlink
--verbose
--output runtime
--module-path "${{ steps.jep-493-check.outputs.jmod_paths }}"
--module-path "${JMOD_PATHS}"
--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.cryptoki,jdk.crypto.ec,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
env:
JMOD_PATHS: ${{ steps.jep-493-check.outputs.jmod_paths }}
- name: Run jpackage
run: >
${JAVA_HOME}/bin/jpackage
@@ -114,24 +126,25 @@ jobs:
--name Cryptomator
--vendor "Skymatic GmbH"
--copyright "(C) 2016 - 2025 Skymatic GmbH"
--app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}"
--app-version "${SEMVER_NUM}.${REV_NUM}"
--java-options "--enable-preview"
--java-options "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator"
--java-options "-Xss5m"
--java-options "-Xmx256m"
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
--java-options "-Dcryptomator.appVersion=\"${SEMVER_STR}\""
--java-options "-Dfile.encoding=\"utf-8\""
--java-options "-Djava.net.useSystemProxies=true"
--java-options "-Dcryptomator.adminConfigPath=\"/etc/cryptomator/config.properties\""
--java-options "-Dcryptomator.logDir=\"@{userhome}/.local/share/Cryptomator/logs\""
--java-options "-Dcryptomator.pluginDir=\"@{userhome}/.local/share/Cryptomator/plugins\""
--java-options "-Dcryptomator.settingsPath=\"@{userhome}/.config/Cryptomator/settings.json:@{userhome}/.Cryptomator/settings.json\""
--java-options "-Dcryptomator.p12Path=\"@{userhome}/.config/Cryptomator/key.p12\""
--java-options "-Dcryptomator.ipcSocketPath=\"@{userhome}/.config/Cryptomator/ipc.socket\""
--java-options "-Dcryptomator.mountPointsDir=\"@{userhome}/.local/share/Cryptomator/mnt\""
--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 }}\""
--java-options "-Dcryptomator.buildNumber=\"appimage-${REV_NUM}\""
--java-options "-Dcryptomator.networking.truststore.p12Path=\"/etc/cryptomator/certs.p12\""
--java-options "-Dcryptomator.hub.enableTrustOnFirstUse=true"
--java-options "-XX:ErrorFile=/cryptomator/cryptomator_crash.log"
--resource-dir dist/linux/resources
- name: Patch Cryptomator.AppDir
@@ -155,7 +168,8 @@ jobs:
ln -s bin/cryptomator.sh Cryptomator.AppDir/AppRun
- name: Download AppImageKit
run: |
curl -L https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-${{ matrix.appimage-suffix }}.AppImage -o appimagetool.AppImage
curl --silent --fail-with-body --proto "=https" -L "https://github.com/AppImage/appimagetool/releases/download/1.9.1/appimagetool-${{ matrix.arch }}.AppImage" -o appimagetool.AppImage
echo "${{ matrix.appimagetool-sha }} appimagetool.AppImage" | shasum -a256 --check
chmod +x appimagetool.AppImage
./appimagetool.AppImage --appimage-extract
- name: Prepare GPG-Agent for signing with key 615D449FE6E6A235
@@ -167,17 +181,17 @@ jobs:
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
- name: Build AppImage
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"
./squashfs-root/AppRun Cryptomator.AppDir cryptomator-${SEMVER_STR}-${{ matrix.arch }}.AppImage
-u "gh-releases-zsync|cryptomator|cryptomator|latest|cryptomator-*-${{ matrix.arch }}.AppImage.zsync"
--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
gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator-*.AppImage.zsync
- name: Upload artifacts
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: appimage-${{ matrix.appimage-suffix }}
name: appimage-${{ matrix.arch }}
path: |
cryptomator-*.AppImage
cryptomator-*.AppImage.zsync
@@ -185,7 +199,7 @@ jobs:
if-no-files-found: error
- name: Publish AppImage on GitHub Releases
if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published'
uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090 # v2.4.1
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
with:
fail_on_unmatched_files: true
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
@@ -196,65 +210,77 @@ jobs:
create-aur-bin-pr:
name: Create PR for aur-bin repo
needs: [build, get-version]
if: github.event_name == 'workflow_dispatch' && inputs.create-pr || github.event_name == 'release' && needs.get-version.outputs.versionType == 'stable'
runs-on: ubuntu-latest
if: github.event_name == 'release' && needs.get-version.outputs.versionType == 'stable'
needs: [build, get-version]
container:
image: archlinux:base-devel
env:
SEMVER_STR: ${{ needs.get-version.outputs.semVerStr }}
PKGDEST: ${{ github.workspace }}/pkgdest
SRCDEST: ${{ github.workspace }}/srcdest
steps:
- name: Download AppImages
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
path: downloads/
merge-multiple: true
- name: Compute sha256 hash of AppImages
id: checksums
- name: Prepare pacman
run: |
X64_SHA256=$(sha256sum downloads/cryptomator-*-x86_64.AppImage | cut -d ' ' -f1)
echo "x64-sha256sum=${X64_SHA256}" >> "$GITHUB_OUTPUT"
AARCH64_SHA256=$(sha256sum downloads/cryptomator-*-aarch64.AppImage | cut -d ' ' -f1)
echo "aarch64-sha256sum=${AARCH64_SHA256}" >> "$GITHUB_OUTPUT"
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
pacman-key --init
pacman-key --populate archlinux
pacman -Syu --noconfirm --needed git base-devel sudo gnupg maven unzip github-cli curl pacman-contrib
- name: Checkout cryptomator/aur-bin
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: 'cryptomator/aur-bin'
token: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
- name: Install dependencies
- name: Create build user
run: |
sudo apt-get update
sudo apt-get -y install makepkg pacman-package-manager
useradd -m builder
echo 'builder ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers.d/builder
chown -R builder:builder "$GITHUB_WORKSPACE"
install -d -m 0755 -o builder -g builder "$PKGDEST" "$SRCDEST"
- name: Import Cryptomator release signing key
# try first ubuntu. on failure try openpgp keyservers
run: >
sudo -u builder gpg --batch --keyserver hkps://keyserver.ubuntu.com --recv-keys 58117AFA1F85B3EEC154677D615D449FE6E6A235
|| sudo -u builder gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys 58117AFA1F85B3EEC154677D615D449FE6E6A235
- name: Checkout release branch
run: |
git checkout -b release/${{ needs.get-version.outputs.semVerStr }}
git config --global safe.directory '*'
git checkout -b "release/${SEMVER_STR}"
- name: Update build file
run: |
sed -i -e 's|^pkgver=.*$|pkgver=${{ needs.get-version.outputs.semVerStr }}|' PKGBUILD
sed -i -e "s|^pkgver=.*$|pkgver=${SEMVER_STR}|" PKGBUILD
sed -i -e 's|^pkgrel=.*$|pkgrel=1|' PKGBUILD
sed -i -e "s|^sha256sums_x86_64=.*$|sha256sums_x86_64=('${{ steps.checksums.outputs.x64-sha256sum }}'|" PKGBUILD
sed -i -e "s|^sha256sums_aarch64=.*$|sha256sums_aarch64=('${{ steps.checksums.outputs.aarch64-sha256sum}}'|" PKGBUILD
makepkg --printsrcinfo > .SRCINFO
sudo -u builder updpkgsums
sudo -u builder makepkg --printsrcinfo > .SRCINFO
- name: Build package with makepkg
run: >
sudo -u builder
env PKGDEST="$PKGDEST" SRCDEST="$SRCDEST"
makepkg --syncdeps --cleanbuild --noconfirm --log
- 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 user.name "cryptobot"
git config user.email "cryptobot@users.noreply.github.com"
git config push.autoSetupRemote true
git stage .
git commit -m "Prepare release ${{needs.get-version.outputs.semVerStr}}"
git stage PKGBUILD .SRCINFO
git commit -m "Prepare release ${SEMVER_STR}"
git push
- name: Create pull request
id: create-pr
run: |
printf "> [!IMPORTANT]\n> Todos:\n> - [ ] Update build instructions\n> - [ ] Check for JDK update\n> - [ ] Check for JFX update" > pr_body.md
URL=$(gh pr create --title "Release ${{ needs.get-version.outputs.semVerStr }}" --body-file pr_body.md)
echo "PR_URL=$URL" >> "$GITHUB_OUTPUT"
printf "Created by $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" > pr_body.md
PR_URL=$(gh pr create --title "Release ${SEMVER_STR}" --body-file pr_body.md)
echo "url=$PR_URL" >> "$GITHUB_OUTPUT"
env:
GH_TOKEN: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
- name: Slack Notification
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }}
SLACK_USERNAME: 'Cryptobot'
SLACK_ICON: false
SLACK_ICON_EMOJI: ':bot:'
SLACK_CHANNEL: 'cryptomator-desktop'
SLACK_TITLE: "AUR-bin release PR for ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} created."
SLACK_MESSAGE: "See <${{ steps.create-pr.outputs.PR_URL }}|PR> on how to proceed."
SLACK_TITLE: "AUR-bin release PR for ${{ github.event.repository.name }} ${{ needs.get-version.outputs.semVerStr }} created."
SLACK_MESSAGE: "See <${{ steps.create-pr.outputs.url }}|PR> on how to proceed."
SLACK_FOOTER: false
MSG_MINIMAL: true

View File

@@ -1,95 +0,0 @@
name: Create PR for AUR
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'
env:
INPUT_TAG: ${{ inputs.tag }}
outputs:
url: ${{ steps.url.outputs.url}}
sha256: ${{ steps.sha256.outputs.sha256}}
steps:
- name: Determine tarball url
id: url
run: |
URL="";
if [[ -n "${INPUT_TAG}" ]]; then
URL="https://github.com/cryptomator/cryptomator/archive/refs/tags/${INPUT_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: sha256
run: |
curl --silent --fail-with-body -L -H "Accept: application/vnd.github+json" ${{ steps.url.outputs.url }} --output cryptomator.tar.gz
TARBALL_SHA256=$(sha256sum cryptomator.tar.gz | cut -d ' ' -f1)
echo "sha256=${TARBALL_SHA256}" >> "$GITHUB_OUTPUT"
aur:
name: Create PR for AUR
runs-on: ubuntu-latest
needs: [tarball, get-version]
env:
AUR_PR_URL: tbd
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
repository: 'cryptomator/aur'
token: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install makepkg pacman-package-manager
- name: Checkout release branch
run: |
git checkout -b release/${{ needs.get-version.outputs.semVerStr }}
- name: Update build file
run: |
sed -i -e 's|^pkgver=.*$|pkgver=${{ needs.get-version.outputs.semVerStr }}|' PKGBUILD
sed -i -e 's|^pkgrel=.*$|pkgrel=1|' PKGBUILD
sed -i -e "s|^sha256sums=.*$|sha256sums=('${{ needs.tarball.outputs.sha256 }}'|" PKGBUILD
makepkg --printsrcinfo > .SRCINFO
- 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 build instructions\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 "AUR_PR_URL=$PR_URL" >> "$GITHUB_ENV"
env:
GH_TOKEN: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
- name: Slack Notification
if: github.event_name == 'release'
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_USERNAME: 'Cryptobot'
SLACK_ICON: false
SLACK_ICON_EMOJI: ':bot:'
SLACK_CHANNEL: 'cryptomator-desktop'
SLACK_TITLE: "AUR release PR created for ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} created."
SLACK_MESSAGE: "See <${{ env.AUR_PR_URL }}|PR> on how to proceed."
SLACK_FOOTER: false
MSG_MINIMAL: true

View File

@@ -7,6 +7,16 @@ on:
description: "Url to the file to upload"
required: true
type: string
avast:
description: "Upload to Avast"
required: false
type: boolean
default: true
kaspersky:
description: "Upload to Kaspersky"
required: false
type: boolean
default: true
workflow_dispatch:
inputs:
url:
@@ -39,9 +49,9 @@ jobs:
url="${INPUT_URL}"
echo "fileName=${url##*/}" >> $GITHUB_OUTPUT
- name: Download file
run: curl --remote-name ${INPUT_URL} -L -o ${{steps.extractName.outputs.fileName}}
run: curl --silent --fail-with-body --proto "=https" -L "${INPUT_URL}" -o "${{steps.extractName.outputs.fileName}}"
- name: Upload artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: ${{ steps.extractName.outputs.fileName }}
path: ${{ steps.extractName.outputs.fileName }}
@@ -50,10 +60,10 @@ jobs:
name: Anti Virus Allowlisting Kaspersky
runs-on: ubuntu-latest
needs: download-file
if: github.event_name == 'workflow_call' || inputs.kaspersky
if: inputs.kaspersky
steps:
- name: Download artifact
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
with:
name: ${{ needs.download-file.outputs.fileName }}
path: upload
@@ -70,10 +80,10 @@ jobs:
name: Anti Virus Allowlisting Avast
runs-on: ubuntu-latest
needs: download-file
if: github.event_name == 'workflow_call' || inputs.avast
if: inputs.avast
steps:
- name: Download artifact
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
with:
name: ${{ needs.download-file.outputs.fileName }}
path: upload

View File

@@ -22,14 +22,14 @@ jobs:
name: Compile and Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
distribution: ${{ env.JAVA_DIST }}
java-version: ${{ env.JAVA_VERSION }}
cache: 'maven'
- name: Cache SonarCloud packages
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
@@ -49,29 +49,28 @@ jobs:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- name: Draft a release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090 # v2.4.1
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
with:
draft: true
discussion_category_name: releases
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
generate_release_notes: true
body: |-
:construction: Work in Progress
> [!NOTE]
> 🚧 Work in Progress 🚧
>
> Please be patient, the [builds are still running](https://github.com/cryptomator/cryptomator/actions). Binary packages can be found here in a few moments.
<!--REPLACE with auto-generated release notes (see below)
### What's New 🎉
### Bugfixes 🐛
### Other Changes 📎
END REPLACE-->
For a comprehensive view of changes, read the [CHANGELOG](https://github.com/cryptomator/cryptomator/blob/develop/CHANGELOG.md).
---
### Full Changelog
See [CHANGELOG.md](https://github.com/cryptomator/cryptomator/blob/develop/CHANGELOG.md).
📜 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:
@@ -79,4 +78,9 @@ jobs:
```
-->
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).
> [!TIP]
> You can verify the GPG signature of all assets using our public key: [`5811 7AFA 1F85 B3EE C154 677D 615D 449F E6E6 A235`](https://gist.github.com/cryptobot/211111cf092037490275f39d408f461a).
<!-- Auto-Generated Release Notes: -->

View File

@@ -26,7 +26,7 @@ jobs:
run: echo 'JDK_MAJOR_VERSION=${{ env.JDK_VERSION }}'.substring(0,2) >> "$env:GITHUB_ENV"
shell: pwsh
- name: Checkout latest JDK ${{ env.JDK_MAJOR_VERSION }}
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
java-version: ${{ env.JDK_MAJOR_VERSION}}
distribution: ${{ env.JDK_VENDOR }}

View File

@@ -23,12 +23,12 @@ on:
env:
JAVA_DIST: 'temurin'
JAVA_VERSION: '25.0.1+8.0.LTS'
JAVA_VERSION: '25.0.2+10.0.LTS'
DEB_BUILD_DEPENDS: 'debhelper (>=10), openjdk-25-jdk (>= 25+36), libgtk-3-0 (>= 3.20.0), libxxf86vm1, libgl1'
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/25/openjfx-25_linux-x64_bin-jmods.zip'
OPENJFX_JMODS_AMD64_HASH: '96e520f48610d8ffb94ca30face1f11ffe8a977ddc1c4ff80b1a9e9f048bd94e'
OPENJFX_JMODS_AARCH64: 'https://download2.gluonhq.com/openjfx/25/openjfx-25_linux-aarch64_bin-jmods.zip'
OPENJFX_JMODS_AARCH64_HASH: '9ad4ca7b769ca4ee6419f1e99143dd6ff812f8be4fddb46a7d7cacbeea148af4'
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/25.0.2/openjfx-25.0.2_linux-x64_bin-jmods.zip'
OPENJFX_JMODS_AMD64_HASH: 'e0a9c29d8cf3af9b8b48848b43f87b5785bc107c53a951b19668ce05842bba1b'
OPENJFX_JMODS_AARCH64: 'https://download2.gluonhq.com/openjfx/25.0.2/openjfx-25.0.2_linux-aarch64_bin-jmods.zip'
OPENJFX_JMODS_AARCH64_HASH: 'c3408f818693cce09e59829a8e862a82c7695fdfcd585c41cfd527f5fc3fe646'
jobs:
get-version:
@@ -43,7 +43,7 @@ jobs:
env:
INPUT_PPAVER: ${{ inputs.ppaver }}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- id: deb-version
name: Determine deb-version
run: |
@@ -60,7 +60,7 @@ jobs:
env:
DEB_BUILD_DEPENDS: ${{ env.DEB_BUILD_DEPENDS }}
- name: Setup Java
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
distribution: ${{ env.JAVA_DIST }}
java-version: ${{ env.JAVA_VERSION }}
@@ -71,11 +71,11 @@ jobs:
- name: Download OpenJFX jmods
id: download-jmods
run: |
curl -L ${{ env.OPENJFX_JMODS_AMD64 }} -o openjfx-amd64.zip
curl --silent --fail-with-body --proto "=https" -L ${{ env.OPENJFX_JMODS_AMD64 }} -o openjfx-amd64.zip
echo "${{ env.OPENJFX_JMODS_AMD64_HASH }} openjfx-amd64.zip" | shasum -a256 --check
mkdir -p jmods/amd64
unzip -j openjfx-amd64.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d jmods/amd64
curl -L ${{ env.OPENJFX_JMODS_AARCH64 }} -o openjfx-aarch64.zip
curl --silent --fail-with-body --proto "=https" -L ${{ env.OPENJFX_JMODS_AARCH64 }} -o openjfx-aarch64.zip
echo "${{ env.OPENJFX_JMODS_AARCH64_HASH }} openjfx-aarch64.zip" | shasum -a256 --check
mkdir -p jmods/aarch64
unzip -j openjfx-aarch64.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d jmods/aarch64
@@ -143,7 +143,7 @@ jobs:
run: |
gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator_*_amd64.deb
- name: Upload artifacts
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: linux-deb-package
path: |

View File

@@ -7,7 +7,7 @@ on:
jobs:
check-dependencies:
uses: skymatic/workflows/.github/workflows/run-dependency-check.yml@1074588008ae3326a2221ea451783280518f0366 # v3.0.1
uses: skymatic/workflows/.github/workflows/run-dependency-check.yml@957d3c2c08c56855fdac41e5afb9a7aca8c30dd9 # v3.0.3
with:
runner-os: 'ubuntu-latest'
java-distribution: 'temurin'
@@ -16,4 +16,4 @@ jobs:
nvd-api-key: ${{ secrets.NVD_API_KEY }}
ossindex-username: ${{ secrets.OSSINDEX_USERNAME }}
ossindex-token: ${{ secrets.OSSINDEX_API_TOKEN }}
slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }}

View File

@@ -53,7 +53,7 @@ jobs:
INTERVAL: 900
JSON_DATA: ${{ steps.get-stats.outputs.result }}
- name: Upload Results
uses: fjogeleit/http-request-action@1297c6fc63a79b147d1676540a3fd9d2e37817c5 # v1.16.5
uses: fjogeleit/http-request-action@551353b829c3646756b2ec2b3694f819d7957495 # v2.0.0
with:
url: 'https://graphite-us-central1.grafana.net/metrics'
method: 'POST'

View File

@@ -33,7 +33,7 @@ jobs:
- 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
curl --silent --fail-with-body --proto "=https" -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:
@@ -43,7 +43,7 @@ jobs:
env:
FLATHUB_PR_URL: tbd
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: 'flathub/org.cryptomator.Cryptomator'
token: ${{ secrets.CRYPTOBOT_PR_TOKEN }}

View File

@@ -35,11 +35,11 @@ jobs:
revNum: ${{ steps.versions.outputs.revNum }}
type: ${{ steps.versions.outputs.type}}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- name: Setup Java
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
distribution: ${{ env.JAVA_DIST }}
java-version: ${{ env.JAVA_VERSION }}

200
.github/workflows/linux-makepkg.yml vendored Normal file
View File

@@ -0,0 +1,200 @@
name: Build Arch package
on:
release:
types: [published]
workflow_dispatch:
inputs:
version:
description: 'Version'
required: false
create-pr:
description: 'Create a PR for aur repo'
type: boolean
default: false
push:
branches-ignore:
- 'dependabot/**'
paths:
- '.github/workflows/linux-makepkg.yml'
- 'dist/linux/makepkg/**'
- 'dist/linux/common/**'
- 'dist/linux/resources/**'
jobs:
get-version:
uses: ./.github/workflows/get-version.yml
with:
version: ${{ inputs.version }}
makepkg:
name: Build with makepkg
needs: [get-version]
runs-on: ubuntu-latest
container:
image: archlinux:base-devel
env:
PKGDEST: ${{ github.workspace }}/pkgdest
SRCDEST: ${{ github.workspace }}/srcdest
steps:
- name: Prepare pacman
run: |
pacman-key --init
pacman-key --populate archlinux
pacman -Syu --noconfirm --needed git base-devel sudo gnupg maven unzip
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
path: cryptomator
- name: Create build user
run: |
useradd -m builder
echo 'builder ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers.d/builder
chown -R builder:builder "$GITHUB_WORKSPACE"
install -d -m 0755 -o builder -g builder "$PKGDEST" "$SRCDEST"
- name: Prepare PKGBUILD
# cannot use github.workspace due to https://github.com/actions/runner/issues/2058
run: |
export SOURCES="${SOURCES_1}${GITHUB_WORKSPACE}${SOURCES_2}"
envsubst '$PKG_VERSION $PKG_RELEASE $SOURCES $SOURCES_SHA' < cryptomator/dist/linux/makepkg/PKGBUILD.template > PKGBUILD
env:
PKG_VERSION: ${{ needs.get-version.outputs.semVerNum }}
PKG_RELEASE: 1
SOURCES_1: '"${_src_app_dir}::git+file://'
SOURCES_2: '/cryptomator"'
SOURCES_SHA: "'SKIP'"
- name: Build package with makepkg
run: >
sudo -u builder
env PKGDEST="$PKGDEST" SRCDEST="$SRCDEST"
makepkg --syncdeps --cleanbuild --noconfirm --log
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: arch-package
if-no-files-found: error
path: |
${{ env.PKGDEST }}/*.pkg.tar.zst
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: pkgbuild-file
if-no-files-found: error
path: |
cryptomator/dist/linux/makepkg/PKGBUILD.template
create-pr:
name: Create PR for aur repo
if: github.event_name == 'workflow_dispatch' && inputs.create-pr || github.event_name == 'release' && needs.get-version.outputs.versionType == 'stable'
runs-on: ubuntu-latest
needs: [get-version, makepkg]
container:
image: archlinux:base-devel
env:
PKGDEST: ${{ github.workspace }}/pkgdest
SRCDEST: ${{ github.workspace }}/srcdest
steps:
- name: Prepare pacman
run: |
pacman-key --init
pacman-key --populate archlinux
pacman -Syu --noconfirm --needed git base-devel sudo gnupg maven unzip github-cli curl
- name: Download source tarball and compute checksum
id: sha256
run: |
URL="https://github.com/cryptomator/cryptomator/archive/refs/tags/${TAG}.tar.gz"
curl --silent --fail-with-body --proto "=https" -L -H "Accept: application/vnd.github+json" ${URL} --output cryptomator.tar.gz
TARBALL_SHA256=$(sha256sum cryptomator.tar.gz | cut -d ' ' -f1)
echo "value=${TARBALL_SHA256}" >> "$GITHUB_OUTPUT"
env:
TAG: ${{ needs.get-version.outputs.semVerStr || github.event.release.tag_name }}
- name: Checkout cryptomator/aur repo
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: 'cryptomator/aur'
token: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
- name: Create build user
run: |
useradd -m builder
echo 'builder ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers.d/builder
chown -R builder:builder "$GITHUB_WORKSPACE"
install -d -m 0755 -o builder -g builder "$PKGDEST" "$SRCDEST"
- name: Import Cryptomator release signing key
# try first ubuntu. on failure try openpgp keyservers
run: >
sudo -u builder gpg --batch --keyserver hkps://keyserver.ubuntu.com --recv-keys 58117AFA1F85B3EEC154677D615D449FE6E6A235
|| sudo -u builder gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys 58117AFA1F85B3EEC154677D615D449FE6E6A235
- name: Checkout release branch
run: |
git config --global safe.directory '*'
git checkout -b release/${VERSION}
env:
VERSION: ${{ needs.get-version.outputs.semVerStr }}
- name: Determine pkgrel
id: pkgrel
run: |
TARGET_VERSION='${{ needs.get-version.outputs.semVerStr }}'
CURRENT_VERSION="$(sed -nE 's/^pkgver=(.*)$/\1/p' PKGBUILD | head -n1)"
CURRENT_REL="$(sed -nE 's/^pkgrel=([0-9]+).*$/\1/p' PKGBUILD | head -n1)"
if [[ "$CURRENT_VERSION" == "$TARGET_VERSION" && "$CURRENT_REL" =~ ^[0-9]+$ ]]; then
NEXT_REL=$((CURRENT_REL + 1))
else
NEXT_REL=1
fi
echo "value=${NEXT_REL}" >> "$GITHUB_OUTPUT"
echo "dist-version=${VERSION}-${NEXT_REL}" >> "$GITHUB_OUTPUT"
env:
VERSION: ${{ needs.get-version.outputs.semVerStr }}
- name: Download PKGBUILD template
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
with:
name: pkgbuild-file
- name: Prepare PKGBUILD
run: |
envsubst '$PKG_VERSION $PKG_RELEASE $SOURCES $SOURCES_SHA' < PKGBUILD.template > PKGBUILD
sudo -u builder makepkg --printsrcinfo > .SRCINFO
env:
PKG_VERSION: ${{ needs.get-version.outputs.semVerNum }}
PKG_RELEASE: ${{ steps.pkgrel.outputs.value }}
SOURCES: |-
"cryptomator-${pkgver//_/-}.tar.gz::https://github.com/cryptomator/cryptomator/archive/refs/tags/${pkgver//_/-}.tar.gz"
"cryptomator-${pkgver//_/-}.tar.gz.asc::https://github.com/cryptomator/cryptomator/releases/download/${pkgver//_/-}/cryptomator-${pkgver//_/-}.tar.gz.asc"
SOURCES_SHA: |-
'${{steps.sha256.outputs.value}}'
'SKIP'
- name: Build package with makepkg
run: >
sudo -u builder
env PKGDEST="$PKGDEST" SRCDEST="$SRCDEST"
makepkg --syncdeps --cleanbuild --noconfirm --log
- name: Commit and push
run: |
git config user.name "cryptobot"
git config user.email "cryptobot@users.noreply.github.com"
git config push.autoSetupRemote true
git stage PKGBUILD .SRCINFO
git commit -m "Prepare release ${DIST_VERSION}"
git push
env:
DIST_VERSION: ${{ steps.pkgrel.outputs.dist-version }}
- name: Create pull request
id: create-pr
run: |
printf "Created by $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" > pr_body.md
PR_URL=$(gh pr create --title "Release $DIST_VERSION" --body-file pr_body.md)
echo "url=$PR_URL" >> "$GITHUB_OUTPUT"
env:
DIST_VERSION: ${{ steps.pkgrel.outputs.dist-version }}
GH_TOKEN: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
- name: Slack Notification
if: github.event_name == 'release'
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }}
SLACK_USERNAME: 'Cryptobot'
SLACK_ICON: false
SLACK_ICON_EMOJI: ':bot:'
SLACK_CHANNEL: 'cryptomator-desktop'
SLACK_TITLE: "AUR release PR created for ${{ github.event.repository.name }} ${{ steps.pkgrel.outputs.dist-version }} ."
SLACK_MESSAGE: "See <${{ steps.create-pr.outputs.url }}|PR> on how to proceed."
SLACK_FOOTER: false
MSG_MINIMAL: true

View File

@@ -24,7 +24,7 @@ on:
env:
JAVA_DIST: 'temurin'
JAVA_VERSION: '25.0.1+8.0.LTS'
JAVA_VERSION: '25.0.2+10.0.LTS'
jobs:
get-version:
@@ -44,12 +44,12 @@ jobs:
architecture: x64
output-suffix: x64
fuse-lib: macFUSE
openjfx-url: 'https://download2.gluonhq.com/openjfx/25/openjfx-25_osx-x64_bin-jmods.zip'
openjfx-sha: '0eba73fb28a24c845175d16fa2f8c081c936ce6de1be9b79eb6119fa32e53d52'
openjfx-url: 'https://download2.gluonhq.com/openjfx/25.0.2/openjfx-25.0.2_osx-x64_bin-jmods.zip'
openjfx-sha: '0b4d8463f03901b7425d94628e4116b7078abb8dd540fbec415266fac20bda5c'
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Java
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
distribution: ${{ env.JAVA_DIST }}
java-version: ${{ env.JAVA_VERSION }}
@@ -59,7 +59,7 @@ jobs:
- name: Download OpenJFX jmods
id: download-jmods
run: |
curl -L ${{ matrix.openjfx-url }} -o openjfx-jmods.zip
curl --silent --fail-with-body --proto "=https" -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
@@ -128,8 +128,8 @@ jobs:
--java-options "-Dapple.awt.enableTemplateImages=true"
--java-options "-Dsun.java2d.metal=true"
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
--java-options "-Dcryptomator.adminConfigPath=\"/Library/Application Support/Cryptomator/config.properties\""
--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\""
@@ -138,12 +138,14 @@ jobs:
--java-options "-Dcryptomator.showTrayIcon=true"
--java-options "-Dcryptomator.updateMechanism=org.cryptomator.macos.update.DmgUpdateMechanism"
--java-options "-Dcryptomator.buildNumber=\"dmg-${{ needs.get-version.outputs.revNum }}\""
--java-options "-Dcryptomator.hub.enableTrustOnFirstUse=true"
--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/
cp dist/mac/resources/Assets.car 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
@@ -151,20 +153,6 @@ jobs:
VERSION_NO: ${{ needs.get-version.outputs.semVerNum }}
REVISION_NO: ${{ needs.get-version.outputs.revNum }}
PROVISIONING_PROFILE_BASE64: ${{ secrets.MACOS_PROVISIONING_PROFILE_BASE64 }}
- name: Build and install DockTilePlugin
env:
DERIVED_DATA_PATH: dist/mac/DockTilePlugin/build
run: |
xcodebuild -project dist/mac/DockTilePlugin/DockTilePlugin.xcodeproj \
-scheme DockTilePlugin \
-configuration Release \
-destination "platform=macOS,arch=x86_64" \
-derivedDataPath ${DERIVED_DATA_PATH} \
-quiet \
clean build
mkdir -p Cryptomator.app/Contents/PlugIns
cp -R ${DERIVED_DATA_PATH}/Build/Products/Release/Cryptomator.docktileplugin Cryptomator.app/Contents/PlugIns/
rm -rf ${DERIVED_DATA_PATH}
- name: Generate license for dmg
run: >
mvn -B license:add-third-party
@@ -283,7 +271,7 @@ jobs:
run: security delete-keychain $RUNNER_TEMP/codesign.keychain-db
continue-on-error: true
- name: Upload artifacts
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: dmg-${{ matrix.output-suffix }}
path: |
@@ -292,7 +280,7 @@ jobs:
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@6da8fa9354ddfdc4aeace5fc48d7f679b5214090 # v2.4.1
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
with:
fail_on_unmatched_files: true
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}

View File

@@ -22,7 +22,7 @@ on:
env:
JAVA_DIST: 'temurin'
JAVA_VERSION: '25.0.1+8.0.LTS'
JAVA_VERSION: '25.0.2+10.0.LTS'
jobs:
get-version:
@@ -42,12 +42,12 @@ jobs:
architecture: aarch64
output-suffix: arm64
fuse-lib: FUSE-T
openjfx-url: 'https://download2.gluonhq.com/openjfx/25/openjfx-25_osx-aarch64_bin-jmods.zip'
openjfx-sha: '13f8c0513c40c95881479fbcf0465a29a60217393fb0656f5e4eab78a9442fba'
openjfx-url: 'https://download2.gluonhq.com/openjfx/25.0.2/openjfx-25.0.2_osx-aarch64_bin-jmods.zip'
openjfx-sha: '4cd258001c75af7047005c5c891e2400ed11d24fbb09412324c0cbaf8b503c5a'
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Java
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
distribution: ${{ env.JAVA_DIST }}
java-version: ${{ env.JAVA_VERSION }}
@@ -57,7 +57,7 @@ jobs:
- name: Download OpenJFX jmods
id: download-jmods
run: |
curl -L ${{ matrix.openjfx-url }} -o openjfx-jmods.zip
curl --silent --fail-with-body --proto "=https" -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
@@ -126,8 +126,8 @@ jobs:
--java-options "-Dapple.awt.enableTemplateImages=true"
--java-options "-Dsun.java2d.metal=true"
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
--java-options "-Dcryptomator.adminConfigPath=\"/Library/Application Support/Cryptomator/config.properties\""
--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\""
@@ -137,12 +137,14 @@ jobs:
--java-options "-Dcryptomator.updateMechanism=org.cryptomator.macos.update.DmgUpdateMechanism"
--java-options "-Dcryptomator.buildNumber=\"dmg-${{ needs.get-version.outputs.revNum }}\""
--java-options "-XX:ErrorFile=/cryptomator/cryptomator_crash.log"
--java-options "-Dcryptomator.hub.enableTrustOnFirstUse=true"
--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/
cp dist/mac/resources/Assets.car 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
@@ -150,20 +152,6 @@ jobs:
VERSION_NO: ${{ needs.get-version.outputs.semVerNum }}
REVISION_NO: ${{ needs.get-version.outputs.revNum }}
PROVISIONING_PROFILE_BASE64: ${{ secrets.MACOS_PROVISIONING_PROFILE_BASE64 }}
- name: Build and install DockTilePlugin
env:
DERIVED_DATA_PATH: dist/mac/DockTilePlugin/build
run: |
xcodebuild -project dist/mac/DockTilePlugin/DockTilePlugin.xcodeproj \
-scheme DockTilePlugin \
-configuration Release \
-destination "platform=macOS,arch=arm64" \
-derivedDataPath ${DERIVED_DATA_PATH} \
-quiet \
clean build
mkdir -p Cryptomator.app/Contents/PlugIns
cp -R ${DERIVED_DATA_PATH}/Build/Products/Release/Cryptomator.docktileplugin Cryptomator.app/Contents/PlugIns/
rm -rf ${DERIVED_DATA_PATH}
- name: Generate license for dmg
run: >
mvn -B license:add-third-party
@@ -282,7 +270,7 @@ jobs:
run: security delete-keychain $RUNNER_TEMP/codesign.keychain-db
continue-on-error: true
- name: Upload artifacts
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: dmg-${{ matrix.output-suffix }}
path: |
@@ -291,7 +279,7 @@ jobs:
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@6da8fa9354ddfdc4aeace5fc48d7f679b5214090 # v2.4.1
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
with:
fail_on_unmatched_files: true
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}

View File

@@ -12,7 +12,7 @@ jobs:
issues: write
pull-requests: write
steps:
- uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10.1.0
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0
with:
days-before-stale: 14
days-before-close: 0

View File

@@ -10,7 +10,7 @@ jobs:
steps:
- name: Download source tarball
run: |
curl -L -H "Accept: application/vnd.github+json" https://github.com/cryptomator/cryptomator/archive/refs/tags/${{ github.event.release.tag_name }}.tar.gz --output cryptomator-${{ github.event.release.tag_name }}.tar.gz
curl --silent --fail-with-body --proto "=https" -L -H "Accept: application/vnd.github+json" https://github.com/cryptomator/cryptomator/archive/refs/tags/${{ github.event.release.tag_name }}.tar.gz --output cryptomator-${{ github.event.release.tag_name }}.tar.gz
- name: Sign source tarball with key 615D449FE6E6A235
run: |
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
@@ -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@6da8fa9354ddfdc4aeace5fc48d7f679b5214090 # v2.4.1
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
with:
fail_on_unmatched_files: true
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
@@ -28,7 +28,7 @@ jobs:
- name: Slack Notification
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }}
SLACK_USERNAME: 'Cryptobot'
SLACK_ICON: false
SLACK_ICON_EMOJI: ':bot:'

View File

@@ -16,8 +16,8 @@ jobs:
name: Compile and Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
distribution: ${{ env.JAVA_DIST }}
java-version: ${{ env.JAVA_VERSION }}

View File

@@ -19,9 +19,9 @@ jobs:
name: Validate commits pushed to release/hotfix branch to fulfill release requirements
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Java
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
distribution: ${{ env.JAVA_DIST }}
java-version: ${{ env.JAVA_VERSION }}
@@ -43,13 +43,14 @@ jobs:
exit 1
fi
- name: Validate release in org.cryptomator.Cryptomator.metainfo.xml file
if: ${{ ! (contains(github.event.head_commit.message, '[skip metadata check]') || contains(github.event.head_commit.message, '[metadata check skip]')) }}
run: |
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
- name: Cache NVD DB
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
with:
path: ~/.m2/repository/org/owasp/dependency-check-data/
key: dependency-check-${{ github.run_id }}

View File

@@ -12,7 +12,7 @@ jobs:
issues: write
pull-requests: write
steps:
- uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10.1.0
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0
with:
days-before-stale: 365
days-before-close: 90

View File

@@ -22,11 +22,12 @@ on:
env:
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/25/openjfx-25_windows-x64_bin-jmods.zip'
OPENJFX_JMODS_AMD64_HASH: 'c8eb9fd039b00e0020cf6c3db8ed7876bf3ee4d27860aa697a247b83b8296ae7'
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/25.0.2/openjfx-25.0.2_windows-x64_bin-jmods.zip'
OPENJFX_JMODS_AMD64_HASH: '33d878dfac85590c4d77c518ed413e512d34a8479d90132b230a7ddd173576b3'
WINFSP_MSI: 'https://github.com/winfsp/winfsp/releases/download/v2.1/winfsp-2.1.25156.msi'
WINFSP_MSI_HASH: '073a70e00f77423e34bed98b86e600def93393ba5822204fac57a29324db9f7a'
WINFSP_UNINSTALLER: 'https://github.com/cryptomator/winfsp-uninstaller/releases/latest/download/winfsp-uninstaller.exe'
WIX_VERSION: '6.0.2'
defaults:
run:
@@ -51,9 +52,9 @@ jobs:
java-version: '25.0.1+8'
java-package: 'jdk'
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Java
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
distribution: ${{ matrix.java-dist }}
java-version: ${{ matrix.java-version }}
@@ -62,14 +63,16 @@ jobs:
cache: 'maven'
- name: Install wix and extensions
run: |
dotnet tool install --global wix --version 6.0.0
wix.exe extension add WixToolset.UI.wixext/6.0.0 --global
wix.exe extension add WixToolset.Util.wixext/6.0.0 --global
dotnet tool install --global wix --version ${WIX_VERSION}
wix.exe extension add --global WixToolset.UI.wixext/${WIX_VERSION}
wix.exe extension add --global WixToolset.Util.wixext/${WIX_VERSION}
env:
WIX_VERSION: ${{ env.WIX_VERSION }}
- name: Download and extract JavaFX jmods from Gluon
if: matrix.arch == 'x64'
#In the last step we move all jmods files a dir level up because jmods are placed inside a directory in the zip
run: |
curl --output openjfx-jmods.zip -L "${{ env.OPENJFX_JMODS_AMD64 }}"
curl --silent --fail-with-body --proto "=https" -L "${{ env.OPENJFX_JMODS_AMD64 }}" --output openjfx-jmods.zip
if(!(Get-FileHash -Path openjfx-jmods.zip -Algorithm SHA256).Hash.ToLower().equals("${{ env.OPENJFX_JMODS_AMD64_HASH }}")) {
throw "Wrong checksum of JMOD archive downloaded from ${{ env.OPENJFX_JMODS_AMD64 }}.";
}
@@ -140,8 +143,8 @@ jobs:
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
--java-options "-Dfile.encoding=\"utf-8\""
--java-options "-Djava.net.useSystemProxies=true"
--java-options "-Dcryptomator.adminConfigPath=\"C:/ProgramData/Cryptomator/config.properties\""
--java-options "-Dcryptomator.logDir=\"@{localappdata}/Cryptomator\""
--java-options "-Dcryptomator.pluginDir=\"@{appdata}/Cryptomator/Plugins\""
--java-options "-Dcryptomator.settingsPath=\"@{appdata}/Cryptomator/settings.json;@{userhome}/AppData/Roaming/Cryptomator/settings.json\""
--java-options "-Dcryptomator.p12Path=\"@{appdata}/Cryptomator/key.p12;@{userhome}/AppData/Roaming/Cryptomator/key.p12\""
--java-options "-Dcryptomator.ipcSocketPath=\"@{localappdata}/Cryptomator/ipc.socket\""
@@ -154,6 +157,7 @@ jobs:
--java-options "-Dcryptomator.integrationsWin.windowsHelloKeychainPaths=\"@{appdata}/Cryptomator/windowsHelloKeychain.json\""
--java-options "-Dcryptomator.disableUpdateCheck=false"
--java-options "-XX:ErrorFile=C:/cryptomator/cryptomator_crash.log"
--java-options "-Dcryptomator.hub.enableTrustOnFirstUse=true"
--resource-dir dist/win/resources
--icon dist/win/resources/Cryptomator.ico
--add-launcher "Cryptomator (Debug)=dist/win/debug-launcher.properties"
@@ -200,7 +204,7 @@ jobs:
client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
- name: Sign DLLs with Actalis CodeSigner
if: inputs.sign || github.event_name == 'release'
uses: skymatic/workflows/.github/actions/win-sign-action@450e322ff2214d0be0b079b63343c894f3ef735f # no specific version
uses: skymatic/workflows/.github/actions/win-sign-action@957d3c2c08c56855fdac41e5afb9a7aca8c30dd9 # no specific version
with:
base-dir: 'appdir'
file-extensions: 'dll,exe,ps1'
@@ -277,7 +281,7 @@ jobs:
GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }}
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
- name: Upload artifacts
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: msi-${{ matrix.arch }}
path: |
@@ -299,21 +303,23 @@ jobs:
java-version: '24.0.1+9'
java-package: 'jdk'
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Install wix and extensions
run: |
dotnet tool install --global wix --version 6.0.0
wix.exe extension add WixToolset.BootstrapperApplications.wixext/6.0.0 --global
wix.exe extension add WixToolset.Util.wixext/6.0.0 --global
dotnet tool install --global wix --version ${WIX_VERSION}
wix.exe extension add --global WixToolset.BootstrapperApplications.wixext/${WIX_VERSION}
wix.exe extension add --global WixToolset.Util.wixext/${WIX_VERSION}
env:
WIX_VERSION: ${{ env.WIX_VERSION }}
- name: Download .msi
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
with:
name: msi-${{ matrix.arch }}
path: dist/win/bundle/resources
- name: Strip version info from msi file name
run: mv dist/win/bundle/resources/Cryptomator*.msi dist/win/bundle/resources/Cryptomator.msi
- name: Setup Java
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
distribution: ${{ matrix.java-dist }}
java-version: ${{ matrix.java-version }}
@@ -333,7 +339,7 @@ jobs:
shell: pwsh
- name: Download WinFsp
run: |
curl --output $env:WINFSP_PATH -L ${{ env.WINFSP_MSI }}
curl --silent --fail-with-body --proto "=https" -L ${{ env.WINFSP_MSI }} --output $env:WINFSP_PATH
$computedHash = (Get-FileHash -Path $env:WINFSP_PATH -Algorithm SHA256).Hash.ToLower()
if ($computedHash -ne "${{ env.WINFSP_MSI_HASH }}") {
throw "Checksum mismatch for $env:WINFSP_PATH (expected ${{ env.WINFSP_MSI_HASH }}, got $computedHash)."
@@ -343,7 +349,7 @@ jobs:
shell: pwsh
- name: Download Legacy-WinFsp uninstaller
run: |
curl --output dist/win/bundle/resources/winfsp-uninstaller.exe -L ${{ env.WINFSP_UNINSTALLER }}
curl --silent --fail-with-body --proto "=https" -L ${{ env.WINFSP_UNINSTALLER }} --output dist/win/bundle/resources/winfsp-uninstaller.exe
shell: pwsh
- name: Create Wix Burn bundle
working-directory: dist/win
@@ -376,7 +382,7 @@ jobs:
client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
- name: Sign burn engine with Actalis CodeSigner
if: inputs.sign || github.event_name == 'release'
uses: skymatic/workflows/.github/actions/win-sign-action@450e322ff2214d0be0b079b63343c894f3ef735f # no specific version
uses: skymatic/workflows/.github/actions/win-sign-action@957d3c2c08c56855fdac41e5afb9a7aca8c30dd9 # no specific version
with:
base-dir: 'tmp'
file-extensions: 'exe'
@@ -400,7 +406,7 @@ jobs:
client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
- name: Sign installer with Actalis CodeSigner
if: inputs.sign || github.event_name == 'release'
uses: skymatic/workflows/.github/actions/win-sign-action@450e322ff2214d0be0b079b63343c894f3ef735f # no specific version
uses: skymatic/workflows/.github/actions/win-sign-action@957d3c2c08c56855fdac41e5afb9a7aca8c30dd9 # no specific version
with:
base-dir: 'installer'
file-extensions: 'exe'
@@ -418,7 +424,7 @@ jobs:
GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }}
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
- name: Upload artifacts
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: exe-${{ matrix.executable-suffix }}
path: |
@@ -436,12 +442,12 @@ jobs:
download-url-exe-x64: ${{ fromJSON(steps.publish.outputs.assets)[2].browser_download_url }}
steps:
- name: Download installers
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
with:
merge-multiple: true
- name: Publish installers on GitHub Releases
id: publish
uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090 # v2.4.1
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
with:
fail_on_unmatched_files: true
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}

43
.idea/compiler.xml generated
View File

@@ -12,17 +12,15 @@
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<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.57.2/dagger-compiler-2.57.2.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger/2.57.2/dagger-2.57.2.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-compiler/2.59.1/dagger-compiler-2.59.1.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger/2.59.1/dagger-2.59.1.jar" />
<entry name="$MAVEN_REPOSITORY$/jakarta/inject/jakarta.inject-api/2.0.1/jakarta.inject-api-2.0.1.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.57.2/dagger-spi-2.57.2.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-spi/2.59.1/dagger-spi-2.59.1.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/devtools/ksp/symbol-processing-api/2.1.21-2.0.2/symbol-processing-api-2.1.21-2.0.2.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/googlejavaformat/google-java-format/1.5/google-java-format-1.5.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/errorprone/javac-shaded/9-dev-r4023-3/javac-shaded-9-dev-r4023-3.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/devtools/ksp/symbol-processing-api/2.2.20-2.0.3/symbol-processing-api-2.2.20-2.0.3.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/googlejavaformat/google-java-format/1.33.0/google-java-format-1.33.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" />
@@ -37,8 +35,33 @@
<entry name="$MAVEN_REPOSITORY$/javax/inject/javax.inject/1/javax.inject-1.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.3/checker-compat-qual-2.5.3.jar" />
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-metadata-jvm/2.1.21/kotlin-metadata-jvm-2.1.21.jar" />
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.1.21/kotlin-stdlib-2.1.21.jar" />
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-metadata-jvm/2.2.20/kotlin-metadata-jvm-2.2.20.jar" />
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.2.20/kotlin-stdlib-2.2.20.jar" />
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-compiler/2.59.1/dagger-compiler-2.59.1.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger/2.59.1/dagger-2.59.1.jar" />
<entry name="$MAVEN_REPOSITORY$/jakarta/inject/jakarta.inject-api/2.0.1/jakarta.inject-api-2.0.1.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.59.1/dagger-spi-2.59.1.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/devtools/ksp/symbol-processing-api/2.2.20-2.0.3/symbol-processing-api-2.2.20-2.0.3.jar" />
<entry name="$MAVEN_REPOSITORY$/com/google/googlejavaformat/google-java-format/1.33.0/google-java-format-1.33.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/squareup/kotlinpoet/1.11.0/kotlinpoet-1.11.0.jar" />
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.6.10/kotlin-stdlib-jdk8-1.6.10.jar" />
<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$/javax/inject/javax.inject/1/javax.inject-1.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.3/checker-compat-qual-2.5.3.jar" />
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-metadata-jvm/2.2.20/kotlin-metadata-jvm-2.2.20.jar" />
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.2.20/kotlin-stdlib-2.2.20.jar" />
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar" />
</processorPath>
<module name="cryptomator" />
@@ -47,7 +70,7 @@
</component>
<component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
<module name="cryptomator" options="-Adagger.fastInit=enabled -Adagger.formatGeneratedSource=enabled" />
<module name="cryptomator" options="-Adagger.fastInit=enabled" />
</option>
</component>
</project>

View File

@@ -2,7 +2,7 @@
<configuration default="false" name="Cryptomator Linux" 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;@{userhome}/.config/Cryptomator/settings.json&quot; -Dcryptomator.p12Path=&quot;@{userhome}/.config/Cryptomator/key.p12&quot; -Dcryptomator.ipcSocketPath=&quot;@{userhome}/.config/Cryptomator/ipc.socket&quot; -Dcryptomator.logDir=&quot;@{userhome}/.local/share/Cryptomator/logs&quot; -Dcryptomator.pluginDir=&quot;@{userhome}/.local/share/Cryptomator/plugins&quot; -Dcryptomator.mountPointsDir=&quot;@{userhome}/.local/share/Cryptomator/mnt&quot; -Dcryptomator.showTrayIcon=true -Xss20m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator,javafx.graphics" />
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath=&quot;@{userhome}/.config/Cryptomator/settings.json&quot; -Dcryptomator.p12Path=&quot;@{userhome}/.config/Cryptomator/key.p12&quot; -Dcryptomator.ipcSocketPath=&quot;@{userhome}/.config/Cryptomator/ipc.socket&quot; -Dcryptomator.logDir=&quot;@{userhome}/.local/share/Cryptomator/logs&quot; -Dcryptomator.pluginDir=&quot;@{userhome}/.local/share/Cryptomator/plugins&quot; -Dcryptomator.mountPointsDir=&quot;@{userhome}/.local/share/Cryptomator/mnt&quot; -Dcryptomator.showTrayIcon=true -Dcryptomator.hub.enableTrustOnFirstUse=true -Xss20m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator,javafx.graphics" />
<method v="2">
<option name="Make" enabled="true" />
</method>

View File

@@ -2,7 +2,7 @@
<configuration default="false" name="Cryptomator Linux 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;@{userhome}/.config/Cryptomator-Dev/settings.json&quot; -Dcryptomator.p12Path=&quot;@{userhome}/.config/Cryptomator-Dev/key.p12&quot; -Dcryptomator.ipcSocketPath=&quot;@{userhome}/.config/Cryptomator-Dev/ipc.socket&quot; -Dcryptomator.logDir=&quot;@{userhome}/.local/share/Cryptomator-Dev/logs&quot; -Dcryptomator.pluginDir=&quot;@{userhome}/.local/share/Cryptomator-Dev/plugins&quot; -Dcryptomator.mountPointsDir=&quot;@{userhome}/.local/share/Cryptomator-Dev/mnt&quot; -Dcryptomator.showTrayIcon=true -Dfuse.experimental=&quot;true&quot; -Xss20m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator,javafx.graphics" />
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath=&quot;@{userhome}/.config/Cryptomator-Dev/settings.json&quot; -Dcryptomator.p12Path=&quot;@{userhome}/.config/Cryptomator-Dev/key.p12&quot; -Dcryptomator.ipcSocketPath=&quot;@{userhome}/.config/Cryptomator-Dev/ipc.socket&quot; -Dcryptomator.logDir=&quot;@{userhome}/.local/share/Cryptomator-Dev/logs&quot; -Dcryptomator.pluginDir=&quot;@{userhome}/.local/share/Cryptomator-Dev/plugins&quot; -Dcryptomator.mountPointsDir=&quot;@{userhome}/.local/share/Cryptomator-Dev/mnt&quot; -Dcryptomator.showTrayIcon=true -Dcryptomator.hub.enableTrustOnFirstUse=true -Dfuse.experimental=&quot;true&quot; -Xss20m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator,javafx.graphics" />
<method v="2">
<option name="Make" enabled="true" />
</method>

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.integrationsWin.windowsHelloKeychainPaths=&quot;@{appdata}/Cryptomator/windowsHelloKeychain.json;@{userhome}/AppData/Roaming/Cryptomator/windowsHelloKeychain.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,javafx.graphics" />
<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.integrationsWin.windowsHelloKeychainPaths=&quot;@{appdata}/Cryptomator/windowsHelloKeychain.json;@{userhome}/AppData/Roaming/Cryptomator/windowsHelloKeychain.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 -Dcryptomator.hub.enableTrustOnFirstUse=true -Xss2m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.win,org.cryptomator.integrations.win,javafx.graphics" />
<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.integrationsWin.windowsHelloKeychainPaths=&quot;@{appdata}/Cryptomator-Dev/windowsHelloKeychain.json;@{userhome}/AppData/Roaming/Cryptomator-Dev/windowsHelloKeychain.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,javafx.graphics" />
<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.integrationsWin.windowsHelloKeychainPaths=&quot;@{appdata}/Cryptomator-Dev/windowsHelloKeychain.json;@{userhome}/AppData/Roaming/Cryptomator-Dev/windowsHelloKeychain.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 -Dcryptomator.hub.enableTrustOnFirstUse=true -Xss2m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.win,org.cryptomator.integrations.win,javafx.graphics" />
<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/settings.json&quot; -Dcryptomator.p12Path=&quot;@{userhome}/Library/Application Support/Cryptomator/key.p12&quot; -Dcryptomator.ipcSocketPath=&quot;@{userhome}/Library/Application Support/Cryptomator/ipc.socket&quot; -Dcryptomator.logDir=&quot;@{userhome}/Library/Logs/Cryptomator&quot; -Dcryptomator.pluginDir=&quot;@{userhome}/Library/Application Support/Cryptomator/Plugins&quot; -Dcryptomator.mountPointsDir=&quot;@{userhome}/Cryptomator&quot; -Dcryptomator.showTrayIcon=true -Dcryptomator.integrationsMac.keychainServiceName=Cryptomator -Dcryptomator.updateMechanism=org.cryptomator.macos.update.DmgUpdateMechanism -Xss2m -Xmx512m -ea --enable-preview --enable-native-access=org.cryptomator.jfuse.mac,javafx.graphics" />
<option name="VM_PARAMETERS" value="-Dapple.awt.enableTemplateImages=true -Dcryptomator.settingsPath=&quot;@{userhome}/Library/Application Support/Cryptomator/settings.json&quot; -Dcryptomator.p12Path=&quot;@{userhome}/Library/Application Support/Cryptomator/key.p12&quot; -Dcryptomator.ipcSocketPath=&quot;@{userhome}/Library/Application Support/Cryptomator/ipc.socket&quot; -Dcryptomator.logDir=&quot;@{userhome}/Library/Logs/Cryptomator&quot; -Dcryptomator.pluginDir=&quot;@{userhome}/Library/Application Support/Cryptomator/Plugins&quot; -Dcryptomator.mountPointsDir=&quot;@{userhome}/Cryptomator&quot; -Dcryptomator.showTrayIcon=true -Dcryptomator.integrationsMac.keychainServiceName=Cryptomator -Dcryptomator.updateMechanism=org.cryptomator.macos.update.DmgUpdateMechanism -Dcryptomator.hub.enableTrustOnFirstUse=true -Xss2m -Xmx512m -ea --enable-preview --enable-native-access=org.cryptomator.jfuse.mac,javafx.graphics" />
<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}/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,javafx.graphics" />
<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 -Dcryptomator.hub.enableTrustOnFirstUse=true -Xss2m -Xmx512m -ea --enable-preview --enable-native-access=org.cryptomator.jfuse.mac,javafx.graphics" />
<method v="2">
<option name="Make" enabled="true" />
</method>

View File

@@ -7,10 +7,77 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
The changelog starts with version 1.19.0.
Changes to prior versions can be found on the [Github release page](https://github.com/cryptomator/cryptomator/releases).
## [Unreleased](https://github.com/cryptomator/cryptomator/compare/1.18.0...HEAD)
## [1.19.2](https://github.com/cryptomator/cryptomator/releases/1.19.2) - 2026-03-20
### Security
* Cryptomamtor Hub Vaults: Additional patch for (#4179, [GHSA-34rf-rwr3-7g43](https://github.com/cryptomator/cryptomator/security/advisories/GHSA-34rf-rwr3-7g43))
## [1.19.1](https://github.com/cryptomator/cryptomator/releases/1.19.1) - 2026-03-12
### Security
* Cryptomamtor Hub Vaults: Fixed possible man-in-the-middle attack with tampered vault config (#4179, [GHSA-34rf-rwr3-7g43](https://github.com/cryptomator/cryptomator/security/advisories/GHSA-34rf-rwr3-7g43))
* Disallow unencrypted http connections to hub by default ([CVE-2026-32309](https://github.com/cryptomator/cryptomator/security/advisories/GHSA-vv33-h7qx-c264))
* Disallow loading of masterkey file from arbitrary paths (#4180, [CVE-2026-32310](https://github.com/cryptomator/cryptomator/security/advisories/GHSA-5phc-5pfx-hr52))
* Fixed not-configured plugin directory does not disable plugin search ([#4176](https://github.com/cryptomator/cryptomator/pull/4176))
### Added
* New Self-Update Mechanism (initially for .dmg and Flatpak packages) (#3948)
* Trust on first use, adding new config properties `cryptomator.hub.allowedHosts` and `cryptomator.hub.enableTrustOnFirstUse` (#4179)
### Fixed
* Fixed Finder window opens twice when revealing vault on macOS ([#4177](https://github.com/cryptomator/cryptomator/pull/4177))
* Fixed app does not start due to secret service detection failure on Linux ([#4175](https://github.com/cryptomator/cryptomator/pull/4175))
### Changed
* Built using JDK 25 (#4031)
* Pin version of appimagetool([#4181](https://github.com/cryptomator/cryptomator/pull/4181))
* Updated translations
* Updated dependencies:
* `org.cryptomator:integrations-api` from 1.8.0-beta1 to 1.8.0
* `org.cryptomator:integrations-linux` from 1.7.0-beta4 to 1.7.0
* `org.cryptomator:integrations-mac` from 1.5.0-beta3 to 1.5.0
## [1.19.0](https://github.com/cryptomator/cryptomator/releases/tag/1.19.0) - 2026-03-09
### Added
* Self-Update Mechanism ([#3948](https://github.com/cryptomator/cryptomator/pull/3948))
* Implemented `.dmg` update mechanism
* Implemented Flatpak update mechanism
* App notifications ([#4069](https://github.com/cryptomator/cryptomator/pull/4069))
* Mark files in-use for Hub vaults ([#4078](https://github.com/cryptomator/cryptomator/pull/4078))
* Accessibility: Adjust app to be used with a screen reader ([#547](https://github.com/cryptomator/cryptomator/issues/547))
* Show Archived Vault Dialog on unlock when Hub returns 410 ([#4081](https://github.com/cryptomator/cryptomator/pull/4081))
* Support automatic app theme selection according to OS theme on Linux ([#4027](https://github.com/cryptomator/cryptomator/issues/4027))
* Admin configuration: Allow overwriting certain app properties by external config file ([#4105](https://github.com/cryptomator/cryptomator/pull/4105))
* New keychain backend using [secret service API](https://specifications.freedesktop.org/secret-service/0.2) for Linux ([#4025](https://github.com/cryptomator/cryptomator/pull/4025))
* Liquid Glass icon for macOS ([#4166](https://github.com/cryptomator/cryptomator/pull/4166))
### Fixed
* Fixed password reset/show recovery possible for vaults without masterkey file ([#4120](https://github.com/cryptomator/cryptomator/pull/4120))
* Fixed restore vault config failed due to selecting a directory instead of file ([#4141](https://github.com/cryptomator/cryptomator/issues/4141))
* Fixed leaking of cleartext paths into application log ([GHSA-j83j-mwhc-rcgw](https://github.com/cryptomator/cryptomator/security/advisories/GHSA-j83j-mwhc-rcgw))
### Changed
* Disable user defined app start config on Windows ([#4132](https://github.com/cryptomator/cryptomator/issues/4132))
* Disable plugin loading by default ([#4136](https://github.com/cryptomator/cryptomator/4136))
* Use JDK 25 ([#4031](https://github.com/cryptomator/cryptomator/pull/4031))
* Update JavaFX to 25.0.2 ([#4145](https://github.com/cryptomator/cryptomator/pull/4145))
* Updated translations
* Updated dependencies
* `ch.qos.logback:*` from 1.5.19 to 1.5.32
* `com.fasterxml.jackson.core:jackson-databind` from 2.20.0 to 2.21.1
* `com.fasterxml.jackson.datatype:jackson-datatype-jsr310` from 2.20.0 to 2.21.1
* `com.github.ben-manes.caffeine:caffeine` from 3.2.2 to 3.2.3
* `com.google.dagger:*` from 2.57.2 to 2.59.2
* `org.apache.commons:commons-lang3` from 3.19.0 to 3.20.0
* `org.cryptomator:cryptofs` from 2.9.0 to 2.10.0
* `org.cryptomator:cryptolib` from 2.2.1 to 2.2.2
* `org.cryptomator:fuse-nio-adapter` from 5.1.0 to 6.0.1
* `org.cryptomator:integrations-api` from 1.7.0 to 1.8.0-beta1
* `org.cryptomator:integrations-linux` from 1.6.1 to 1.7.0-beta4
* `org.cryptomator:integrations-mac` from 1.4.1 to 1.5.0-beta3
* `org.cryptomator:integrations-win` from 1.5.1 to 1.6.0
* `org.cryptomator:webdav-nio-adapter` from 3.0.0 to 3.0.1
* `org.cryptomator:webdav-nio-adapter-servlet` to 1.2.12

View File

@@ -78,7 +78,7 @@ For more information on the security details visit [cryptomator.org](https://doc
### Dependencies
* JDK 24 (e.g. temurin, zulu)
* JDK 25 (e.g. temurin, zulu)
* Maven 3
### Run Maven

8
dist/common/config.properties vendored Normal file
View File

@@ -0,0 +1,8 @@
# This is the Cryptomator administrative configuration file.
# It is a simple key-value pair file.
# Lines starting with '#' are comments and will be ignored.
# For more info, read the docs at https://docs.cryptomator.org/desktop/advanced-settings/
#
# Example:
# Sets the plugin directory and enables plugin loading
# cryptomator.pluginDir=@{userhome}/Cryptomator/Plugins

View File

@@ -23,12 +23,12 @@ mvn -B -f ../../../pom.xml clean package -Plinux -DskipTests
cp ../../../LICENSE.txt ../../../target
cp ../../../target/cryptomator-*.jar ../../../target/mods
JAVAFX_VERSION=25
JAVAFX_VERSION=25.0.2
JAVAFX_ARCH="x64"
JAVAFX_JMODS_SHA256='96e520f48610d8ffb94ca30face1f11ffe8a977ddc1c4ff80b1a9e9f048bd94e'
JAVAFX_JMODS_SHA256='e0a9c29d8cf3af9b8b48848b43f87b5785bc107c53a951b19668ce05842bba1b'
if [ "${CPU_ARCH}" = "aarch64" ]; then
JAVAFX_ARCH="aarch64"
JAVAFX_JMODS_SHA256='951c52481af0ec5885b06f1ebaa8a10da7e8ea23c5e1ef3e2f6f11fa1b3a7ce1'
JAVAFX_JMODS_SHA256='c3408f818693cce09e59829a8e862a82c7695fdfcd585c41cfd527f5fc3fe646'
fi
# download javaFX jmods
@@ -88,8 +88,8 @@ ${JAVA_HOME}/bin/jpackage \
--app-version "${VERSION}.${REVISION_NO}" \
--java-options "-Dfile.encoding=\"utf-8\"" \
--java-options "-Djava.net.useSystemProxies=true" \
--java-options "-Dcryptomator.adminConfigPath=\"/etc/cryptomator/config.properties\"" \
--java-options "-Dcryptomator.logDir=\"@{userhome}/.local/share/Cryptomator/logs\"" \
--java-options "-Dcryptomator.pluginDir=\"@{userhome}/.local/share/Cryptomator/plugins\"" \
--java-options "-Dcryptomator.settingsPath=\"@{userhome}/.config/Cryptomator/settings.json:@{userhome}/.Cryptomator/settings.json\"" \
--java-options "-Dcryptomator.p12Path=\"@{userhome}/.config/Cryptomator/key.p12\"" \
--java-options "-Dcryptomator.ipcSocketPath=\"@{userhome}/.config/Cryptomator/ipc.socket\"" \
@@ -99,6 +99,7 @@ ${JAVA_HOME}/bin/jpackage \
--java-options "-Dcryptomator.buildNumber=\"appimage-${REVISION_NO}\"" \
--java-options "-Dcryptomator.networking.truststore.p12Path=\"/etc/cryptomator/certs.p12\"" \
--java-options "-XX:ErrorFile=/cryptomator/cryptomator_crash.log" \
--java-options "-Dcryptomator.hub.enableTrustOnFirstUse=true" \
--resource-dir ../resources
# transform AppDir
@@ -115,6 +116,7 @@ cp ../common/org.cryptomator.Cryptomator.tray-unlocked.svg Cryptomator.AppDir/us
cp ../common/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/usr/share/applications/org.cryptomator.Cryptomator.desktop
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
cp ../common/application-vnd.cryptomator.encrypted.xml Cryptomator.AppDir/usr/share/mime/packages/application-vnd.cryptomator.encrypted.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/.DirIcon
ln -s usr/share/applications/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/org.cryptomator.Cryptomator.desktop
@@ -122,7 +124,7 @@ ln -s org.cryptomator.Cryptomator.metainfo.xml Cryptomator.AppDir/usr/share/meta
ln -s bin/cryptomator.sh Cryptomator.AppDir/AppRun
# load AppImageTool
curl -L https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-${CPU_ARCH}.AppImage -o /tmp/appimagetool.AppImage
curl -L https://github.com/AppImage/appimagetool/releases/download/1.9.1/appimagetool-${CPU_ARCH}.AppImage -o /tmp/appimagetool.AppImage
chmod +x /tmp/appimagetool.AppImage
# create AppImage

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="application/vnd.cryptomator.encrypted">
<comment>Cryptomator Encrypted Data</comment>
<glob pattern="*.c9r"/>
<glob pattern="*.c9s"/>
<glob pattern="*.c9u"/>
</mime-type>
</mime-info>

View File

@@ -73,6 +73,7 @@
<url type="faq">https://community.cryptomator.org/c/kb/faq</url>
<url type="help">https://docs.cryptomator.org/</url>
<url type="translate">https://translate.cryptomator.org</url>
<url type="vcs-browser">https://github.com/cryptomator/cryptomator</url>
<developer id="de.skymatic">
<name>Skymatic GmbH</name>
@@ -83,6 +84,15 @@
</content_rating>
<releases>
<release date="2026-03-20" version="1.19.2">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.19.2</url>
</release>
<release date="2026-03-12" version="1.19.1">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.19.1</url>
</release>
<release date="2026-03-09" version="1.19.0">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.19.0</url>
</release>
<release date="2025-11-12" version="1.18.0">
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.18.0</url>
</release>

View File

@@ -6,4 +6,5 @@ common/org.cryptomator.Cryptomator.tray-unlocked.svg usr/share/icons/hicolor/sca
common/org.cryptomator.Cryptomator256.png usr/share/icons/hicolor/256x256/apps
common/org.cryptomator.Cryptomator512.png usr/share/icons/hicolor/512x512/apps
common/org.cryptomator.Cryptomator.metainfo.xml usr/share/metainfo
common/application-vnd.cryptomator.vault.xml usr/share/mime/packages
common/application-vnd.cryptomator.vault.xml usr/share/mime/packages
common/application-vnd.cryptomator.encrypted.xml usr/share/mime/packages

View File

@@ -25,6 +25,7 @@ case "$1" in
fi
xdg-desktop-menu install --novendor /usr/share/applications/org.cryptomator.Cryptomator.desktop
xdg-mime install /usr/share/mime/packages/application-vnd.cryptomator.vault.xml
xdg-mime install /usr/share/mime/packages/application-vnd.cryptomator.encrypted.xml
;;
abort-upgrade|abort-remove|abort-deconfigure)

View File

@@ -23,6 +23,7 @@ case "$1" in
xdg-desktop-menu uninstall --novendor /usr/share/applications/org.cryptomator.Cryptomator.desktop
xdg-mime uninstall /usr/share/mime/packages/application-vnd.cryptomator.vault.xml
xdg-mime uninstall /usr/share/mime/packages/application-vnd.cryptomator.encrypted.xml
;;
failed-upgrade)

View File

@@ -51,8 +51,8 @@ override_dh_auto_build:
--java-options "-Xmx256m" \
--java-options "-Dfile.encoding=\"utf-8\"" \
--java-options "-Djava.net.useSystemProxies=true" \
--java-options "-Dcryptomator.adminConfigPath=\"/etc/cryptomator/config.properties\"" \
--java-options "-Dcryptomator.logDir=\"@{userhome}/.local/share/Cryptomator/logs\"" \
--java-options "-Dcryptomator.pluginDir=\"@{userhome}/.local/share/Cryptomator/plugins\"" \
--java-options "-Dcryptomator.settingsPath=\"@{userhome}/.config/Cryptomator/settings.json:@{userhome}/.Cryptomator/settings.json\"" \
--java-options "-Dcryptomator.p12Path=\"@{userhome}/.config/Cryptomator/key.p12\"" \
--java-options "-Dcryptomator.ipcSocketPath=\"@{userhome}/.config/Cryptomator/ipc.socket\"" \
@@ -64,6 +64,7 @@ override_dh_auto_build:
--java-options "-Dcryptomator.disableUpdateCheck=\"${DISABLE_UPDATE_CHECK}\"" \
--java-options "-Dcryptomator.integrationsLinux.autoStartCmd=\"cryptomator\"" \
--java-options "-Dcryptomator.networking.truststore.p12Path=\"/etc/cryptomator/certs.p12\"" \
--java-options "-Dcryptomator.hub.enableTrustOnFirstUse=true" \
--app-version "${VERSION_NUM}.${REVISION_NUM}" \
--resource-dir resources \
--verbose

119
dist/linux/makepkg/PKGBUILD.template vendored Normal file
View File

@@ -0,0 +1,119 @@
# Maintainer: Aaron Graves <linux@ajgraves.com>
# Contributor: Julian Raufelder <arch@raufelder.com>
# Contributor: Morten Linderud <morten@linderud.pw>
# Contributor: Sebastian Stenzel <sebastian.stenzel@gmail.com>
# Contributor: Armin Schrenk <armin.schrenk@skymatic.de>
pkgname=cryptomator
pkgver=$PKG_VERSION
pkgrel=$PKG_RELEASE
pkgdesc="Multiplatform transparent client-side encryption of your files in the cloud."
arch=('any')
url="https://cryptomator.org/"
license=('GPL3')
depends=('fuse3' 'alsa-lib' 'hicolor-icon-theme' 'libxtst' 'libnet' 'libxrender')
makedepends=('maven' 'unzip')
optdepends=('keepassxc-cryptomator: Use KeePassXC to store vault passwords' 'ttf-hanazono: Install this font when using Japanese system language')
_jdkver=25.0.2+10
_jfxver=25.0.2
_src_app_dir=cryptomator-${pkgver//_/-}
source=($SOURCES);
source_x86_64=("jdk-${_jdkver}.tar.gz::https://github.com/adoptium/temurin${_jdkver:0:2}-binaries/releases/download/jdk-${_jdkver//\+/%2B}/OpenJDK${_jdkver:0:2}U-jdk_x64_linux_hotspot_${_jdkver//\+/_}.tar.gz"
"openjfx-${_jfxver}.zip::https://download2.gluonhq.com/openjfx/${_jfxver}/openjfx-${_jfxver}_linux-x64_bin-jmods.zip")
source_aarch64=("jdk-${_jdkver}.tar.gz::https://github.com/adoptium/temurin${_jdkver:0:2}-binaries/releases/download/jdk-${_jdkver//\+/%2B}/OpenJDK${_jdkver:0:2}U-jdk_aarch64_linux_hotspot_${_jdkver//\+/_}.tar.gz"
"openjfx-${_jfxver}.zip::https://download2.gluonhq.com/openjfx/${_jfxver}/openjfx-${_jfxver}_linux-aarch64_bin-jmods.zip")
noextract=("jdk-${_jdkver}.tar.gz" "openjfx-${_jfxver}.zip")
sha256sums=($SOURCES_SHA)
sha256sums_x86_64=('987387933b64b9833846dee373b640440d3e1fd48a04804ec01a6dbf718e8ab8'
'e0a9c29d8cf3af9b8b48848b43f87b5785bc107c53a951b19668ce05842bba1b')
sha256sums_aarch64=('a9d73e711d967dc44896d4f430f73a68fd33590dabc29a7f2fb9f593425b854c'
'c3408f818693cce09e59829a8e862a82c7695fdfcd585c41cfd527f5fc3fe646')
options=('!strip')
validpgpkeys=('58117AFA1F85B3EEC154677D615D449FE6E6A235')
build() {
export JAVA_HOME="${srcdir}/jdk-${_jdkver}"
JMODS_PATH="${srcdir}/openjfx-${_jfxver}-jmods"
#JEP 493
if ! $(${JAVA_HOME}/bin/jlink --help | grep -q "Linking from run-time image enabled"); then
JMODS_PATH="${JMODS_PATH}:${JAVA_HOME}/jmods:"
fi
tar xfz "jdk-${_jdkver}.tar.gz"
mkdir "openjfx-${_jfxver}-jmods"
unzip -j "openjfx-${_jfxver}.zip" \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d "openjfx-${_jfxver}-jmods"
cd "${srcdir}/${_src_app_dir}"
mvn -B clean package -DskipTests -Plinux
cp LICENSE.txt target
cp target/cryptomator-*.jar target/mods
cd target
"$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.crypto.ec,jdk.crypto.cryptoki,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
##Note: jpackage does not allow -beta suffixes, have to strip those
"$JAVA_HOME/bin/jpackage" \
--type app-image \
--runtime-image runtime \
--input libs \
--module-path mods \
--module org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator \
--dest . \
--name cryptomator \
--vendor "Skymatic GmbH" \
--copyright "(C) 2016 - 2026 Skymatic GmbH" \
--java-options "--enable-preview" \
--java-options '--enable-native-access=javafx.graphics,org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator' \
--java-options "-Xss5m" \
--java-options "-Xmx256m" \
--java-options "-Dfile.encoding=\"utf-8\"" \
--java-options "-Djava.net.useSystemProxies=true" \
--java-options "-Dcryptomator.adminConfigPath=\"/etc/cryptomator/config.properties\"" \
--java-options "-Dcryptomator.appVersion=\"${pkgver//_/-}\"" \
--java-options "-Dcryptomator.buildNumber=\"aur-${pkgrel}\"" \
--java-options "-Dcryptomator.disableUpdateCheck=true" \
--java-options "-Dcryptomator.integrationsLinux.autoStartCmd=\"cryptomator\"" \
--java-options "-Dcryptomator.ipcSocketPath=\"@{userhome}/.config/Cryptomator/ipc.socket\"" \
--java-options "-Dcryptomator.logDir=\"@{userhome}/.local/share/Cryptomator/logs\"" \
--java-options "-Dcryptomator.mountPointsDir=\"@{userhome}/.local/share/Cryptomator/mnt\"" \
--java-options "-Dcryptomator.networking.truststore.p12Path=\"/etc/cryptomator/certs.p12\"" \
--java-options "-Dcryptomator.pluginDir=\"@{userhome}/.local/share/Cryptomator/plugins\"" \
--java-options "-Dcryptomator.p12Path=\"@{userhome}/.config/Cryptomator/key.p12\"" \
--java-options "-Dcryptomator.settingsPath=\"@{userhome}/.config/Cryptomator/settings.json:~/.Cryptomator/settings.json\"" \
--java-options "-Dcryptomator.showTrayIcon=true" \
--java-options "-Dcryptomator.hub.enableTrustOnFirstUse=true" \
--app-version "${pkgver//_*/}" \
--verbose
}
package() {
install -Dm644 "${srcdir}/${_src_app_dir}/dist/linux/common/application-vnd.cryptomator.vault.xml" "${pkgdir}/usr/share/mime/packages/cryptomator-vault.xml"
install -Dm644 "${srcdir}/${_src_app_dir}/dist/linux/common/org.cryptomator.Cryptomator.desktop" "${pkgdir}/usr/share/applications/org.cryptomator.Cryptomator.desktop"
install -Dm644 "${srcdir}/${_src_app_dir}/dist/linux/common/org.cryptomator.Cryptomator256.png" "${pkgdir}/usr/share/icons/hicolor/256x256/apps/org.cryptomator.Cryptomator.png"
install -Dm644 "${srcdir}/${_src_app_dir}/dist/linux/common/org.cryptomator.Cryptomator512.png" "${pkgdir}/usr/share/icons/hicolor/512x512/apps/org.cryptomator.Cryptomator.png"
install -Dm644 "${srcdir}/${_src_app_dir}/dist/linux/common/org.cryptomator.Cryptomator.svg" "${pkgdir}/usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg"
install -Dm644 "${srcdir}/${_src_app_dir}/dist/linux/common/org.cryptomator.Cryptomator.tray.svg" "${pkgdir}/usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.tray.svg"
install -Dm644 "${srcdir}/${_src_app_dir}/dist/linux/common/org.cryptomator.Cryptomator.tray-unlocked.svg" "${pkgdir}/usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.tray-unlocked.svg"
install -Dm644 "${srcdir}/${_src_app_dir}/dist/linux/common/org.cryptomator.Cryptomator.tray.svg" "${pkgdir}/usr/share/icons/hicolor/symbolic/apps/org.cryptomator.Cryptomator.tray-symbolic.svg"
install -Dm644 "${srcdir}/${_src_app_dir}/dist/linux/common/org.cryptomator.Cryptomator.tray-unlocked.svg" "${pkgdir}/usr/share/icons/hicolor/symbolic/apps/org.cryptomator.Cryptomator.tray-unlocked-symbolic.svg"
mkdir -p "${pkgdir}/opt/cryptomator/"
cp -R "${srcdir}/${_src_app_dir}/target/cryptomator" "${pkgdir}/opt/"
install -Dm644 "${srcdir}/${_src_app_dir}/target/LICENSE.txt" -t "${pkgdir}/usr/share/licenses/${pkgname}"
mkdir -p "${pkgdir}/usr/bin"
ln -s "/opt/cryptomator/bin/cryptomator" "${pkgdir}/usr/bin/cryptomator"
}

1
dist/mac/.gitignore vendored
View File

@@ -1,2 +1 @@
embedded.provisionprofile
xcuserdata/

View File

@@ -1,19 +0,0 @@
//
// CryptomatorDockTilePlugin.swift
// Integrations
//
// Created by Tobias Hagemann on 22.09.25.
// Copyright © 2025 Cryptomator. All rights reserved.
//
import AppKit
class CryptomatorDockTilePlugin: NSObject, NSDockTilePlugIn {
func setDockTile(_ dockTile: NSDockTile?) {
guard let dockTile = dockTile, let image = Bundle(for: Self.self).image(forResource: "Cryptomator") else {
return
}
dockTile.contentView = NSImageView(image: image)
dockTile.display()
}
}

View File

@@ -1,314 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 77;
objects = {
/* Begin PBXBuildFile section */
74E08DE12E8584DE007E665C /* CryptomatorDockTilePlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74E08DE02E85847E007E665C /* CryptomatorDockTilePlugin.swift */; };
74E08DED2E858532007E665C /* Cryptomator.icns in Resources */ = {isa = PBXBuildFile; fileRef = 74E08DEC2E858532007E665C /* Cryptomator.icns */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
74E08DD92E858467007E665C /* Cryptomator.docktileplugin */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Cryptomator.docktileplugin; sourceTree = BUILT_PRODUCTS_DIR; };
74E08DE02E85847E007E665C /* CryptomatorDockTilePlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CryptomatorDockTilePlugin.swift; sourceTree = "<group>"; };
74E08DEC2E858532007E665C /* Cryptomator.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = Cryptomator.icns; path = ../resources/Cryptomator.icns; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
74E08DD62E858467007E665C /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
74E08DD02E858467007E665C = {
isa = PBXGroup;
children = (
74E08DE02E85847E007E665C /* CryptomatorDockTilePlugin.swift */,
74E08DEC2E858532007E665C /* Cryptomator.icns */,
74E08DDA2E858467007E665C /* Products */,
);
sourceTree = "<group>";
};
74E08DDA2E858467007E665C /* Products */ = {
isa = PBXGroup;
children = (
74E08DD92E858467007E665C /* Cryptomator.docktileplugin */,
);
name = Products;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
74E08DD82E858467007E665C /* DockTilePlugin */ = {
isa = PBXNativeTarget;
buildConfigurationList = 74E08DDD2E858467007E665C /* Build configuration list for PBXNativeTarget "DockTilePlugin" */;
buildPhases = (
74E08DD52E858467007E665C /* Sources */,
74E08DD62E858467007E665C /* Frameworks */,
74E08DD72E858467007E665C /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = DockTilePlugin;
packageProductDependencies = (
);
productName = DockTilePlugin;
productReference = 74E08DD92E858467007E665C /* Cryptomator.docktileplugin */;
productType = "com.apple.product-type.bundle";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
74E08DD12E858467007E665C /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = 1;
LastUpgradeCheck = 2600;
ORGANIZATIONNAME = Cryptomator;
TargetAttributes = {
74E08DD82E858467007E665C = {
CreatedOnToolsVersion = 26.0.1;
};
};
};
buildConfigurationList = 74E08DD42E858467007E665C /* Build configuration list for PBXProject "DockTilePlugin" */;
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 74E08DD02E858467007E665C;
minimizedProjectReferenceProxies = 1;
preferredProjectObjectVersion = 77;
productRefGroup = 74E08DDA2E858467007E665C /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
74E08DD82E858467007E665C /* DockTilePlugin */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
74E08DD72E858467007E665C /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74E08DED2E858532007E665C /* Cryptomator.icns in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
74E08DD52E858467007E665C /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74E08DE12E8584DE007E665C /* CryptomatorDockTilePlugin.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
74E08DDB2E858467007E665C /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = YZQJQUHA3L;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 11.5;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_VERSION = 5.0;
};
name = Debug;
};
74E08DDC2E858467007E665C /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = YZQJQUHA3L;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 11.5;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
SWIFT_VERSION = 5.0;
};
name = Release;
};
74E08DDE2E858467007E665C /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "";
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 Cryptomator. All rights reserved.";
INFOPLIST_KEY_NSPrincipalClass = CryptomatorDockTilePlugin;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles";
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = org.cryptomator.DockTilePlugin;
PRODUCT_NAME = Cryptomator;
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
WRAPPER_EXTENSION = docktileplugin;
};
name = Debug;
};
74E08DDF2E858467007E665C /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "";
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2025 Cryptomator. All rights reserved.";
INFOPLIST_KEY_NSPrincipalClass = CryptomatorDockTilePlugin;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles";
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = org.cryptomator.DockTilePlugin;
PRODUCT_NAME = Cryptomator;
PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES;
STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
WRAPPER_EXTENSION = docktileplugin;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
74E08DD42E858467007E665C /* Build configuration list for PBXProject "DockTilePlugin" */ = {
isa = XCConfigurationList;
buildConfigurations = (
74E08DDB2E858467007E665C /* Debug */,
74E08DDC2E858467007E665C /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
74E08DDD2E858467007E665C /* Build configuration list for PBXNativeTarget "DockTilePlugin" */ = {
isa = XCConfigurationList;
buildConfigurations = (
74E08DDE2E858467007E665C /* Debug */,
74E08DDF2E858467007E665C /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 74E08DD12E858467007E665C /* Project object */;
}

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View File

@@ -1,67 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "2600"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "74E08DD82E858467007E665C"
BuildableName = "Cryptomator.docktileplugin"
BlueprintName = "DockTilePlugin"
ReferencedContainer = "container:DockTilePlugin.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "74E08DD82E858467007E665C"
BuildableName = "Cryptomator.docktileplugin"
BlueprintName = "DockTilePlugin"
ReferencedContainer = "container:DockTilePlugin.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

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

@@ -32,15 +32,15 @@ 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"
JAVAFX_VERSION=25
JAVAFX_VERSION=25.0.2
JAVAFX_ARCH="undefined"
JAVAFX_JMODS_SHA256="undefined"
if [ "$(machine)" = "arm64e" ]; then
JAVAFX_ARCH="aarch64"
JAVAFX_JMODS_SHA256="13f8c0513c40c95881479fbcf0465a29a60217393fb0656f5e4eab78a9442fba"
JAVAFX_JMODS_SHA256="4cd258001c75af7047005c5c891e2400ed11d24fbb09412324c0cbaf8b503c5a"
else
JAVAFX_ARCH="x64"
JAVAFX_JMODS_SHA256="0eba73fb28a24c845175d16fa2f8c081c936ce6de1be9b79eb6119fa32e53d52"
JAVAFX_JMODS_SHA256="0b4d8463f03901b7425d94628e4116b7078abb8dd540fbec415266fac20bda5c"
fi
JAVAFX_JMODS_URL="https://download2.gluonhq.com/openjfx/${JAVAFX_VERSION}/openjfx-${JAVAFX_VERSION}_osx-${JAVAFX_ARCH}_bin-jmods.zip"
@@ -114,9 +114,9 @@ ${JAVA_HOME}/bin/jpackage \
--java-options "-Dapple.awt.enableTemplateImages=true" \
--java-options "-Dsun.java2d.metal=true" \
--java-options "-Dcryptomator.appVersion=\"${VERSION_NO}\"" \
--java-options "-Dcryptomator.adminConfigPath=\"/Library/Application Support/Cryptomator/config.properties\"" \
--java-options "-Dcryptomator.logDir=\"@{userhome}/Library/Logs/${APP_NAME}\"" \
--java-options "-XX:ErrorFile=/cryptomator/cryptomator_crash.log" \
--java-options "-Dcryptomator.pluginDir=\"@{userhome}/Library/Application Support/${APP_NAME}/Plugins\"" \
--java-options "-Dcryptomator.settingsPath=\"@{userhome}/Library/Application Support/${APP_NAME}/settings.json\"" \
--java-options "-Dcryptomator.ipcSocketPath=\"@{userhome}/Library/Application Support/${APP_NAME}/ipc.socket\"" \
--java-options "-Dcryptomator.p12Path=\"@{userhome}/Library/Application Support/${APP_NAME}/key.p12\"" \
@@ -125,28 +125,17 @@ ${JAVA_HOME}/bin/jpackage \
--java-options "-Dcryptomator.showTrayIcon=true" \
--java-options "-Dcryptomator.updateMechanism=org.cryptomator.macos.update.DmgUpdateMechanism" \
--java-options "-Dcryptomator.buildNumber=\"dmg-${REVISION_NO}\"" \
--java-options "-Dcryptomator.hub.enableTrustOnFirstUse=true" \
--mac-package-identifier ${PACKAGE_IDENTIFIER} \
--resource-dir ../resources
# transform app dir
cp ../resources/${APP_NAME}-Vault.icns ${APP_NAME}.app/Contents/Resources/
cp ../resources/Assets.car ${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/
# build and install dock tile plugin
echo "Building and installing Cryptomator.docktileplugin..."
DERIVED_DATA_PATH=../DockTilePlugin/build
xcodebuild -project ../DockTilePlugin/DockTilePlugin.xcodeproj \
-scheme DockTilePlugin \
-configuration Release \
-derivedDataPath ${DERIVED_DATA_PATH} \
-quiet \
clean build
mkdir -p ${APP_NAME}.app/Contents/PlugIns
cp -R ${DERIVED_DATA_PATH}/Build/Products/Release/Cryptomator.docktileplugin ${APP_NAME}.app/Contents/PlugIns/
rm -rf ${DERIVED_DATA_PATH}
# generate license
mvn -B -f../../../pom.xml license:add-third-party \
-Dlicense.thirdPartyFilename=license.rtf \

BIN
dist/mac/resources/Assets.car vendored Normal file

Binary file not shown.

View File

@@ -12,6 +12,8 @@
<string>Cryptomator</string>
<key>CFBundleIconFile</key>
<string>Cryptomator.icns</string>
<key>CFBundleIconName</key>
<string>Cryptomator</string>
<key>CFBundleIdentifier</key>
<string>org.cryptomator</string>
<key>CFBundleInfoDictionaryVersion</key>
@@ -105,6 +107,7 @@
<array>
<string>c9r</string>
<string>c9s</string>
<string>c9u</string>
</array>
<key>public.mime-type</key>
<array>
@@ -116,8 +119,5 @@
<!-- allow utilization of integrated GPU, see https://developer.apple.com/library/mac/qa/qa1734/_index.html -->
<key>NSSupportsAutomaticGraphicsSwitching</key>
<true/>
<!-- register dock tile plugin -->
<key>NSDockTilePlugIn</key>
<string>Cryptomator.docktileplugin</string>
</dict>
</plist>

15
dist/win/build.ps1 vendored
View File

@@ -34,20 +34,20 @@ if ((Get-Command "mvn" -ErrorAction SilentlyContinue) -eq $null)
}
if ((Get-Command 'wix' -ErrorAction SilentlyContinue) -eq $null)
{
Write-Error 'Unable to find wix in your PATH (try: dotnet tool install --global wix --version 6.0.0)'
Write-Error 'Unable to find wix in your PATH (try: dotnet tool install --global wix --version 6.0.2)'
exit 1
}
$wixExtensions = & wix.exe extension list --global | Out-String
if ($wixExtensions -notmatch 'WixToolset.UI.wixext') {
Write-Error 'Wix UI extension missing. Please install it with: wix.exe extension add WixToolset.UI.wixext/6.0.0 --global)'
Write-Error 'Wix UI extension missing. Please install it with: wix.exe extension add WixToolset.UI.wixext/6.0.2 --global)'
exit 1
}
if ($wixExtensions -notmatch 'WixToolset.Util.wixext') {
Write-Error 'Wix Util extension missing. Please install it with: wix.exe extension add WixToolset.Util.wixext/6.0.0 --global)'
Write-Error 'Wix Util extension missing. Please install it with: wix.exe extension add WixToolset.Util.wixext/6.0.2 --global)'
exit 1
}
if ($wixExtensions -notmatch 'WixToolset.BootstrapperApplications.wixext') {
Write-Error 'Wix Bootstrapper extension missing. Please install it with: wix.exe extension add WixToolset.BootstrapperApplications.wixext/6.0.0 --global)'
Write-Error 'Wix Bootstrapper extension missing. Please install it with: wix.exe extension add WixToolset.BootstrapperApplications.wixext/6.0.2 --global)'
exit 1
}
@@ -93,9 +93,9 @@ switch ($archName) {
$jmodPaths = "$Env:JAVA_HOME/jmods"
}
'x64' {
$javaFxVersion='25'
$javaFxVersion='25.0.2'
$javaFxJmodsUrl = "https://download2.gluonhq.com/openjfx/${javaFxVersion}/openjfx-${javaFxVersion}_windows-x64_bin-jmods.zip"
$javaFxJmodsSHA256 = 'c8eb9fd039b00e0020cf6c3db8ed7876bf3ee4d27860aa697a247b83b8296ae7'
$javaFxJmodsSHA256 = '33d878dfac85590c4d77c518ed413e512d34a8479d90132b230a7ddd173576b3'
$javaFxJmods = '.\resources\jfxJmods.zip'
if( !(Test-Path -Path $javaFxJmods) ) {
@@ -155,7 +155,7 @@ $javaOptions = @(
"--java-options", "-Djava.net.useSystemProxies=true"
"--java-options", "-Dcryptomator.logDir=`"@{localappdata}/$AppName`""
"--java-options", "-XX:ErrorFile=`"C:/cryptomator/cryptomator_crash.log`""
"--java-options", "-Dcryptomator.pluginDir=`"@{appdata}/$AppName/Plugins`""
"--java-options", "-Dcryptomator.adminConfigPath=`"C:/ProgramData/$AppName/config.properties`""
"--java-options", "-Dcryptomator.settingsPath=`"@{appdata}/$AppName/settings.json;@{userhome}/AppData/Roaming/$AppName/settings.json`""
"--java-options", "-Dcryptomator.ipcSocketPath=`"@{localappdata}/$AppName/ipc.socket`""
"--java-options", "-Dcryptomator.p12Path=`"@{appdata}/$AppName/key.p12;@{userhome}/AppData/Roaming/$AppName/key.p12`""
@@ -167,6 +167,7 @@ $javaOptions = @(
"--java-options", "-Dcryptomator.showTrayIcon=true"
"--java-options", "-Dcryptomator.buildNumber=`"msi-$revisionNo`""
"--java-options", "-Dcryptomator.disableUpdateCheck=false"
"--java-options", "-Dcryptomator.hub.enableTrustOnFirstUse=true"
)

12
dist/win/contrib/disableUserConfig.bat vendored Normal file
View File

@@ -0,0 +1,12 @@
@echo off
:: Batch wrapper for PowerShell script to disable user configuration in Cryptomator
:: This is executed as a Custom Action during MSI installation
:: This file must be located in the INSTALLDIR
:: Change to INSTALLDIR
cd %~dp0
:: Execute the PowerShell script
powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy RemoteSigned -File ".\disableUserConfig.ps1"
:: Return the exit code from PowerShell
exit /b %ERRORLEVEL%

24
dist/win/contrib/disableUserConfig.ps1 vendored Normal file
View File

@@ -0,0 +1,24 @@
# PowerShell script to disable user configuration
# This script is executed as a Custom Action during MSI installation
# It deletes the file .package, effectively disabling user specific jpackage configuration.
# NOTE: This file must be located in the same directory as set in the MSI property INSTALLDIR
try {
# Determine file path
$packageFile = Join-Path $PSScriptRoot 'app\.package'
#check if file exists
if (Test-Path -Path $packageFile) {
Write-Host "Deleting file: $packageFile"
Remove-Item -Path $packageFile -Force -ErrorAction Stop
} else {
Write-Host "File not found: $packageFile. Skipping deletion."
}
exit 0
}
catch {
Write-Error "Error deleting package file: $_"
exit 1
}

View File

@@ -87,17 +87,37 @@
<!-- Non-Opening ProgID -->
<ns0:DirectoryRef Id="INSTALLDIR">
<ns0:Component Bitness="always64" Id="nonStartingProgID" >
<ns0:Component Bitness="always64" Id="nonStartingProgID">
<ns0:File Id="IconFileForEncryptedData" KeyPath="yes" Source="$(env.JP_WIXWIZARD_RESOURCES)\$(var.IconFileEncryptedData)" Name="$(var.IconFileEncryptedData)"/>
<ns0:ProgId Id="$(var.JpAppName).Encrypted.1" Description="$(var.JpAppName) Encrypted Data" Icon="IconFileForEncryptedData" IconIndex="0">
<ns0:Extension Id="c9r" Advertise="no" ContentType="$(var.ProgIdContentType)">
<ns0:MIME ContentType="$(var.ProgIdContentType)" Default="yes"/>
</ns0:Extension>
<ns0:Extension Id="c9s" Advertise="no" ContentType="$(var.ProgIdContentType)"/>
<ns0:Extension Id="c9u" Advertise="no" ContentType="$(var.ProgIdContentType)"/>
</ns0:ProgId>
</ns0:Component>
</ns0:DirectoryRef>
<ns0:StandardDirectory Id="CommonAppDataFolder">
<ns0:Directory Id="CryptomatorDesktopProgramData" Name="Cryptomator">
<ns0:Component Id="AdminConfigDir" Guid="c078b7da-ba6e-4069-a5ab-5c0f0f9856a0">
<ns0:CreateFolder>
<util:PermissionEx User="SYSTEM" GenericAll="yes"/>
<util:PermissionEx User="Administrators" GenericAll="yes"/>
<util:PermissionEx User="Users" GenericRead="yes" GenericExecute="yes"/>
</ns0:CreateFolder>
</ns0:Component>
<ns0:Component Id="AdminConfigFile" NeverOverwrite="yes" Permanent="yes">
<ns0:File Id="EmptyAdminConfig" Source="$(env.JP_WIXWIZARD_RESOURCES)\..\..\common\config.properties" Name="config.properties" KeyPath="yes">
<util:PermissionEx User="SYSTEM" GenericAll="yes"/>
<util:PermissionEx User="Administrators" GenericAll="yes"/>
<util:PermissionEx User="Users" GenericRead="yes" GenericExecute="yes"/>
</ns0:File>
</ns0:Component>
</ns0:Directory>
</ns0:StandardDirectory>
<!-- Standard required root -->
<ns0:Feature Id="DefaultFeature" Title="!(loc.MainFeatureTitle)" Level="1">
@@ -105,7 +125,9 @@
<ns0:ComponentGroupRef Id="Files"/>
<ns0:ComponentGroupRef Id="FileAssociations"/>
<!-- Ref to additional ProgIDs -->
<ns0:ComponentRef Id="nonStartingProgID" />
<ns0:ComponentRef Id="nonStartingProgID"/>
<ns0:ComponentRef Id="AdminConfigDir"/>
<ns0:ComponentRef Id="AdminConfigFile"/>
</ns0:Feature>
<ns0:CustomAction Id="JpSetARPINSTALLLOCATION" Property="ARPINSTALLLOCATION" Value="[INSTALLDIR]" />
@@ -131,6 +153,10 @@
<!-- Property for controlling update check behavior (can be set via command line) -->
<ns0:Property Id="DISABLEUPDATECHECK" Secure="yes" />
<!-- Disable user config -->
<ns0:SetProperty Id="DisableUserConfig" Value="&quot;[INSTALLDIR]disableUserConfig.bat&quot;" Sequence="execute" Before="DisableUserConfig" />
<ns0:CustomAction Id="DisableUserConfig" BinaryRef="Wix4UtilCA_$(sys.BUILDARCHSHORT)" DllEntry="WixQuietExec" Execute="deferred" Return="ignore" Impersonate="no"/>
<!-- WebDAV patches -->
<ns0:SetProperty Id="PatchWebDAV" Value="&quot;[INSTALLDIR]patchWebDAV.bat&quot; &quot;$(var.LoopbackAlias)&quot;" Sequence="execute" Before="PatchWebDAV" />
<ns0:CustomAction Id="PatchWebDAV" BinaryRef="Wix4UtilCA_$(sys.BUILDARCHSHORT)" DllEntry="WixQuietExec" Execute="deferred" Return="ignore" Impersonate="no"/>
@@ -187,9 +213,10 @@
<ns0:Custom Action="FailOnRunningApp" After="Wix4CloseApplications_$(sys.BUILDARCHSHORT)" Condition="FOUNDRUNNINGAPP" />
<ns0:RemoveExistingProducts After="InstallValidate"/> <!-- Moved from CostInitialize, due to Wix4CloseApplications_* -->
<ns0:Custom Action="DisableUserConfig" After="InstallFiles" Condition="NOT (Installed AND (NOT REINSTALL) AND (NOT UPGRADINGPRODUCTCODE) AND REMOVE)"/>
<!-- Skip action on uninstall -->
<!-- TODO: don't skip action, but remove cryptomator alias from hosts file -->
<ns0:Custom Action="PatchWebDAV" After="InstallFiles" Condition="NOT (Installed AND (NOT REINSTALL) AND (NOT UPGRADINGPRODUCTCODE) AND REMOVE)"/>
<ns0:Custom Action="PatchWebDAV" After="DisableUserConfig" Condition="NOT (Installed AND (NOT REINSTALL) AND (NOT UPGRADINGPRODUCTCODE) AND REMOVE)"/>
<!-- Configure update check setting if property is provided -->
<ns0:Custom Action="PatchUpdateCheck" After="PatchWebDAV" Condition="DISABLEUPDATECHECK AND NOT (Installed AND (NOT REINSTALL) AND (NOT UPGRADINGPRODUCTCODE) AND REMOVE)"/>
</ns0:InstallExecuteSequence>

63
pom.xml
View File

@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.cryptomator</groupId>
<artifactId>cryptomator</artifactId>
<version>1.19.0</version>
<version>1.19.2</version>
<name>Cryptomator Desktop App</name>
<organization>
@@ -33,43 +33,46 @@
<nonModularGroupIds>org.ow2.asm,org.apache.jackrabbit,org.apache.httpcomponents</nonModularGroupIds>
<!-- cryptomator dependencies -->
<cryptomator.cryptofs.version>2.9.0</cryptomator.cryptofs.version>
<cryptomator.integrations.version>1.8.0-beta1</cryptomator.integrations.version>
<cryptomator.integrations.win.version>1.5.1</cryptomator.integrations.win.version>
<cryptomator.integrations.mac.version>1.5.0-beta1</cryptomator.integrations.mac.version>
<cryptomator.integrations.linux.version>1.7.0-beta1</cryptomator.integrations.linux.version>
<cryptomator.fuse.version>5.1.0</cryptomator.fuse.version>
<cryptomator.webdav.version>3.0.0</cryptomator.webdav.version>
<cryptomator.cryptofs.version>2.10.0</cryptomator.cryptofs.version>
<cryptomator.cryptolib.version>2.2.2</cryptomator.cryptolib.version>
<cryptomator.integrations.version>1.8.0</cryptomator.integrations.version>
<cryptomator.integrations.win.version>1.6.0</cryptomator.integrations.win.version>
<cryptomator.integrations.mac.version>1.5.0</cryptomator.integrations.mac.version>
<cryptomator.integrations.linux.version>1.7.0</cryptomator.integrations.linux.version>
<cryptomator.fuse.version>6.0.1</cryptomator.fuse.version>
<cryptomator.webdav.version>3.0.1</cryptomator.webdav.version>
<cryptomator.webdav-servlet.version>1.2.12</cryptomator.webdav-servlet.version>
<!-- 3rd party dependencies -->
<commons-lang3.version>3.19.0</commons-lang3.version>
<dagger.version>2.57.2</dagger.version>
<caffeine.version>3.2.3</caffeine.version>
<commons-lang3.version>3.20.0</commons-lang3.version>
<dagger.version>2.59.2</dagger.version>
<easybind.version>2.2</easybind.version>
<jackson.version>2.20.0</jackson.version>
<javafx.version>25</javafx.version>
<jwt.version>4.5.0</jwt.version>
<jackson.version>2.21.1</jackson.version>
<javafx.version>25.0.2</javafx.version>
<jwt.version>4.5.1</jwt.version>
<nimbus-jose.version>10.5</nimbus-jose.version>
<logback.version>1.5.19</logback.version>
<logback.version>1.5.32</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.13.4</junit.jupiter.version>
<mockito.version>5.20.0</mockito.version>
<junit.jupiter.version>6.0.3</junit.jupiter.version>
<mockito.version>5.22.0</mockito.version>
<hamcrest.version>3.0</hamcrest.version>
<!-- build-time dependencies -->
<jetbrains.annotations.version>26.0.2-1</jetbrains.annotations.version>
<dependency-check.version>12.1.5</dependency-check.version>
<jetbrains.annotations.version>26.1.0</jetbrains.annotations.version>
<dependency-check.version>12.2.0</dependency-check.version>
<jacoco.version>0.8.14</jacoco.version>
<license-generator.version>2.7.0</license-generator.version>
<junit-tree-reporter.version>1.4.0</junit-tree-reporter.version>
<mvn-compiler.version>3.14.1</mvn-compiler.version>
<mvn-resources.version>3.3.1</mvn-resources.version>
<mvn-dependency.version>3.8.1</mvn-dependency.version>
<mvn-surefire.version>3.5.4</mvn-surefire.version>
<mvn-jar.version>3.4.2</mvn-jar.version>
<license-generator.version>2.7.1</license-generator.version>
<junit-tree-reporter.version>1.5.1</junit-tree-reporter.version>
<mvn-compiler.version>3.15.0</mvn-compiler.version>
<mvn-resources.version>3.5.0</mvn-resources.version>
<mvn-dependency.version>3.10.0</mvn-dependency.version>
<mvn-surefire.version>3.5.3</mvn-surefire.version>
<mvn-jar.version>3.5.0</mvn-jar.version>
<!-- Property used by surefire to determine jacoco engine -->
<surefire.jacoco.args></surefire.jacoco.args>
@@ -91,10 +94,15 @@
<dependencies>
<!-- Cryptomator Libs -->
<dependency>
<groupId>org.cryptomator</groupId>
<artifactId>webdav-nio-adapter-servlet</artifactId>
<version>${cryptomator.webdav-servlet.version}</version>
</dependency>
<dependency>
<groupId>org.cryptomator</groupId>
<artifactId>cryptolib</artifactId>
<version>2.2.1</version>
<version>${cryptomator.cryptolib.version}</version>
</dependency>
<dependency>
<groupId>org.cryptomator</groupId>
@@ -228,7 +236,7 @@
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>3.2.2</version>
<version>${caffeine.version}</version>
</dependency>
<!-- JUnit / Mockito / Hamcrest -->
<dependency>
@@ -330,7 +338,6 @@
</annotationProcessorPaths>
<compilerArgs>
<arg>-Adagger.fastInit=enabled</arg>
<arg>-Adagger.formatGeneratedSource=enabled</arg>
</compilerArgs>
</configuration>
</plugin>

View File

@@ -1,5 +1,4 @@
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;
@@ -14,11 +13,16 @@ 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.revealpath.RevealPathService;
import org.cryptomator.integrations.tray.TrayMenuController;
import org.cryptomator.integrations.uiappearance.UiAppearanceProvider;
import org.cryptomator.logging.LogbackConfiguratorFactory;
import org.cryptomator.networking.SSLContextProvider;
import org.cryptomator.networking.SSLContextWithMacKeychain;
import org.cryptomator.networking.SSLContextWithPKCS12TrustStore;
import org.cryptomator.networking.SSLContextWithWindowsCertStore;
import org.cryptomator.ui.fxapp.JfxRevealPathService;
import org.cryptomator.ui.fxapp.JfxUiAppearanceProvider;
import org.cryptomator.ui.traymenu.AwtTrayMenuController;
open module org.cryptomator.desktop {
@@ -61,6 +65,8 @@ open module org.cryptomator.desktop {
uses SSLContextProvider;
uses org.cryptomator.event.NotificationHandler;
provides UiAppearanceProvider with JfxUiAppearanceProvider;
provides RevealPathService with JfxRevealPathService;
provides TrayMenuController with AwtTrayMenuController;
provides Configurator with LogbackConfiguratorFactory;
provides SSLContextProvider with SSLContextWithWindowsCertStore, SSLContextWithMacKeychain, SSLContextWithPKCS12TrustStore;

View File

@@ -22,8 +22,6 @@ import javax.inject.Named;
import javax.inject.Singleton;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Comparator;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.SynchronousQueue;
@@ -76,8 +74,8 @@ public abstract class CommonsModule {
@Provides
@Singleton
static Optional<RevealPathService> provideRevealPathService() {
return RevealPathService.get().findFirst();
static RevealPathService provideRevealPathService() {
return RevealPathService.get().findFirst().orElseThrow();
}

View File

@@ -13,5 +13,7 @@ public interface Constants {
String CRYPTOMATOR_FILENAME_GLOB = "*.cryptomator";
URI DEFAULT_KEY_ID = URI.create(MasterkeyFileLoadingStrategy.SCHEME + ":" + MASTERKEY_FILENAME);
byte[] PEPPER = new byte[0];
// Separator used to concatenate Hub username and device name in the filesystem owner identifier.
String HUB_USER_DEVICE_SEPARATOR = "&";
}

View File

@@ -9,10 +9,13 @@ import org.slf4j.LoggerFactory;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Optional;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
@@ -20,20 +23,22 @@ public class Environment {
private static final Logger LOG = LoggerFactory.getLogger(Environment.class);
private static final int DEFAULT_MIN_PW_LENGTH = 8;
private static final String SETTINGS_PATH_PROP_NAME = "cryptomator.settingsPath";
private static final String IPC_SOCKET_PATH_PROP_NAME = "cryptomator.ipcSocketPath";
private static final String KEYCHAIN_PATHS_PROP_NAME = "cryptomator.integrationsWin.keychainPaths";
private static final String WINDOWS_HELLO_KEYCHAIN_PATHS_PROP_NAME = "cryptomator.integrationsWin.windowsHelloKeychainPaths";
private static final String P12_PATH_PROP_NAME = "cryptomator.p12Path";
private static final String LOG_DIR_PROP_NAME = "cryptomator.logDir";
private static final String LOOPBACK_ALIAS_PROP_NAME = "cryptomator.loopbackAlias";
private static final String MOUNTPOINT_DIR_PROP_NAME = "cryptomator.mountPointsDir";
private static final String MIN_PW_LENGTH_PROP_NAME = "cryptomator.minPwLength";
private static final String APP_VERSION_PROP_NAME = "cryptomator.appVersion";
private static final String BUILD_NUMBER_PROP_NAME = "cryptomator.buildNumber";
private static final String PLUGIN_DIR_PROP_NAME = "cryptomator.pluginDir";
private static final String TRAY_ICON_PROP_NAME = "cryptomator.showTrayIcon";
private static final String DISABLE_UPDATE_CHECK_PROP_NAME = "cryptomator.disableUpdateCheck";
public static final String SETTINGS_PATH_PROP_NAME = "cryptomator.settingsPath";
public static final String IPC_SOCKET_PATH_PROP_NAME = "cryptomator.ipcSocketPath";
public static final String KEYCHAIN_PATHS_PROP_NAME = "cryptomator.integrationsWin.keychainPaths";
public static final String WINDOWS_HELLO_KEYCHAIN_PATHS_PROP_NAME = "cryptomator.integrationsWin.windowsHelloKeychainPaths";
public static final String P12_PATH_PROP_NAME = "cryptomator.p12Path";
public static final String LOG_DIR_PROP_NAME = "cryptomator.logDir";
public static final String LOOPBACK_ALIAS_PROP_NAME = "cryptomator.loopbackAlias";
public static final String MOUNTPOINT_DIR_PROP_NAME = "cryptomator.mountPointsDir";
public static final String MIN_PW_LENGTH_PROP_NAME = "cryptomator.minPwLength";
public static final String APP_VERSION_PROP_NAME = "cryptomator.appVersion";
public static final String BUILD_NUMBER_PROP_NAME = "cryptomator.buildNumber";
public static final String PLUGIN_DIR_PROP_NAME = "cryptomator.pluginDir";
public static final String TRAY_ICON_PROP_NAME = "cryptomator.showTrayIcon";
public static final String DISABLE_UPDATE_CHECK_PROP_NAME = "cryptomator.disableUpdateCheck";
public static final String HUB_ALLOWED_HOSTS_PROP_NAME = "cryptomator.hub.allowedHosts";
public static final String HUB_TOFU_PROP_NAME = "cryptomator.hub.enableTrustOnFirstUse";
private Environment() {}
@@ -57,6 +62,8 @@ public class Environment {
logCryptomatorSystemProperty(PLUGIN_DIR_PROP_NAME);
logCryptomatorSystemProperty(TRAY_ICON_PROP_NAME);
logCryptomatorSystemProperty(DISABLE_UPDATE_CHECK_PROP_NAME);
logCryptomatorSystemProperty(HUB_ALLOWED_HOSTS_PROP_NAME);
logCryptomatorSystemProperty(HUB_TOFU_PROP_NAME);
}
public static Environment getInstance() {
@@ -145,6 +152,18 @@ public class Environment {
return Boolean.getBoolean(DISABLE_UPDATE_CHECK_PROP_NAME);
}
public Set<String> hubAllowedHosts() {
var allowedHubHostsString = System.getProperty(HUB_ALLOWED_HOSTS_PROP_NAME, "");
return Arrays.stream(allowedHubHostsString.split(","))
.map(String::trim)
.filter(Predicate.not(String::isEmpty))
.collect(Collectors.toUnmodifiableSet());
}
public boolean hubTrustOnFirstUse() {
return Boolean.getBoolean(HUB_TOFU_PROP_NAME);
}
private Optional<Path> getPath(String propertyName) {
String value = System.getProperty(propertyName);
return Optional.ofNullable(value).map(Paths::get);

View File

@@ -1,160 +0,0 @@
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

@@ -0,0 +1,18 @@
package org.cryptomator.common;
import java.util.function.Supplier;
/**
* Interface marking a class to be used in {@link org.cryptomator.cryptofs.CryptoFileSystemProperties.Builder#withOwnerGetter(Supplier)}.
*/
@FunctionalInterface
public interface FilesystemOwnerSupplier {
/**
* Get the filesystem owner.
*
* @return the filesystem owner
*/
String getOwner();
}

View File

@@ -1,7 +1,7 @@
package org.cryptomator.common;
import org.jetbrains.annotations.VisibleForTesting;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import java.util.Map;
import java.util.Properties;
@@ -13,10 +13,12 @@ public class SubstitutingProperties extends PropertiesDecorator {
private static final Pattern TEMPLATE = Pattern.compile("@\\{(\\w+)}");
private final Map<String, String> env;
private final Logger logger;
public SubstitutingProperties(Properties props, Map<String, String> systemEnvironment) {
public SubstitutingProperties(Properties props, Map<String, String> systemEnvironment, Logger logger) {
super(props);
this.env = systemEnvironment;
this.logger = logger;
}
@Override
@@ -44,7 +46,7 @@ public class SubstitutingProperties extends PropertiesDecorator {
case "localappdata" -> resolveFrom("LOCALAPPDATA", Source.ENV);
case "userhome" -> resolveFrom("user.home", Source.PROPS);
default -> {
LoggerFactory.getLogger(SubstitutingProperties.class).warn("Unknown variable {} in property value {}.", match.group(), value);
logger.warn("Unknown variable {} in property value {}.", match.group(), value);
yield match.group();
}
});
@@ -56,7 +58,7 @@ public class SubstitutingProperties extends PropertiesDecorator {
case PROPS -> delegate.getProperty(key);
};
if (val == null) {
LoggerFactory.getLogger(SubstitutingProperties.class).warn("Variable {} used for substitution not found in {}. Replaced with empty string.", key, src);
logger.warn("Variable {} used for substitution not found in {}. Replaced with empty string.", key, src);
return "";
} else {
return Matcher.quoteReplacement(val);

View File

@@ -167,6 +167,7 @@ public class Mounter {
usedMountServices.add(mountService);
var builder = mountService.forFileSystem(cryptoFsRoot);
LOG.debug("Using mount service {} for mounting vault {}", mountService.getClass().getName(), vaultSettings.displayName);
var internal = new SettledMounter(mountService, builder, vaultSettings); // FIXME: no need for an inner class
var cleanup = internal.prepare();
return new MountHandle(builder.mount(), mountService.hasCapability(UNMOUNT_FORCED), cleanup);

View File

@@ -61,6 +61,7 @@ public final class MasterkeyService {
Optional<Path> c9rFile = paths //
.filter(p -> p.toString().endsWith(".c9r")) //
.filter(p -> !p.endsWith("dir.c9r")) //
.filter(Files::isRegularFile) //
.findFirst();
if (c9rFile.isEmpty()) {
LOG.info("Unable to detect Crypto scheme: No *.c9r file found in {}", vaultPath);

View File

@@ -24,9 +24,12 @@ import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.ObservableSet;
import javafx.geometry.NodeOrientation;
import java.nio.file.Path;
import java.time.Instant;
import java.util.HashSet;
import java.util.Set;
public class Settings {
@@ -78,6 +81,7 @@ public class Settings {
public final ObjectProperty<Instant> lastSuccessfulUpdateCheck;
public final ObjectProperty<Path> previouslyUsedVaultDirectory;
public final StringProperty lastUpdateAttemptedByVersion;
public final ObservableSet<String> trustedHosts;
public static Settings create(SettingsProvider provider, Environment env) {
var defaults = new SettingsJson();
@@ -118,6 +122,7 @@ public class Settings {
this.lastSuccessfulUpdateCheck = new SimpleObjectProperty<>(this, "lastSuccessfulUpdateCheck", json.lastSuccessfulUpdateCheck);
this.previouslyUsedVaultDirectory = new SimpleObjectProperty<>(this, "previouslyUsedVaultDirectory", json.previouslyUsedVaultDirectory);
this.lastUpdateAttemptedByVersion = new SimpleStringProperty(this, "lastUpdateAttemptedByVersion", json.lastUpdateAttemptedByVersion);
this.trustedHosts = FXCollections.observableSet(json.trustedHosts);
this.directories.addAll(json.directories.stream().map(VaultSettings::new).toList());
@@ -149,15 +154,11 @@ public class Settings {
lastSuccessfulUpdateCheck.addListener(this::somethingChanged);
previouslyUsedVaultDirectory.addListener(this::somethingChanged);
lastUpdateAttemptedByVersion.addListener(this::somethingChanged);
trustedHosts.addListener(this::somethingChanged);
}
@SuppressWarnings("deprecation")
private void migrateLegacySettings(SettingsJson json) {
// migrate renamed keychainAccess
if(this.keychainProvider.getValueSafe().equals("org.cryptomator.linux.keychain.SecretServiceKeychainAccess")) {
this.keychainProvider.setValue("org.cryptomator.linux.keychain.GnomeKeyringKeychainAccess");
}
// implicit migration of 1.6.x legacy setting "preferredVolumeImpl":
if (this.mountService.get() == null && json.preferredVolumeImpl != null) {
this.mountService.set(switch (json.preferredVolumeImpl) {
@@ -212,6 +213,7 @@ public class Settings {
json.lastSuccessfulUpdateCheck = lastSuccessfulUpdateCheck.get();
json.previouslyUsedVaultDirectory = previouslyUsedVaultDirectory.get();
json.lastUpdateAttemptedByVersion = lastUpdateAttemptedByVersion.get();
json.trustedHosts = Set.copyOf(trustedHosts);
return json;
}

View File

@@ -4,17 +4,23 @@ 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 com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.Nulls;
import java.nio.file.Path;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
class SettingsJson {
@JsonProperty("directories")
List<VaultSettingsJson> directories = List.of();
@JsonSetter(nulls = Nulls.AS_EMPTY)
List<VaultSettingsJson> directories = new ArrayList<>();
@JsonProperty("writtenByVersion")
String writtenByVersion;
@@ -99,4 +105,8 @@ class SettingsJson {
@JsonProperty("lastUpdateAttemptedByVersion")
String lastUpdateAttemptedByVersion;
@JsonProperty("trustedHosts")
@JsonSetter(nulls = Nulls.AS_EMPTY)
Set<String> trustedHosts = new HashSet<>();
}

View File

@@ -10,14 +10,6 @@ public enum UiTheme {
DARK("preferences.interface.theme.dark"), //
AUTOMATIC("preferences.interface.theme.automatic");
public static UiTheme[] applicableValues() {
if (SystemUtils.IS_OS_MAC || SystemUtils.IS_OS_WINDOWS) {
return values();
} else {
return new UiTheme[]{LIGHT, DARK};
}
}
private final String displayName;
UiTheme(String displayName) {

View File

@@ -10,7 +10,7 @@ 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.FilesystemOwnerSupplier;
import org.cryptomator.common.mount.Mounter;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.settings.VaultSettings;
@@ -23,6 +23,8 @@ 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.FileSystemEventAggregator;
import org.cryptomator.event.NotificationManager;
import org.cryptomator.integrations.mount.MountFailedException;
import org.cryptomator.integrations.mount.Mountpoint;
import org.cryptomator.integrations.mount.UnmountFailedException;
@@ -78,6 +80,7 @@ public class Vault {
private final Mounter mounter;
private final Settings settings;
private final FileSystemEventAggregator fileSystemEventAggregator;
private final NotificationManager notificationManager;
private final BooleanProperty showingStats;
private final AtomicReference<Mounter.MountHandle> mountHandle = new AtomicReference<>(null);
@@ -90,7 +93,8 @@ public class Vault {
@Named("lastKnownException") ObjectProperty<Exception> lastKnownException, //
VaultStats stats, //
Mounter mounter, Settings settings, //
FileSystemEventAggregator fileSystemEventAggregator) {
FileSystemEventAggregator fileSystemEventAggregator, //
NotificationManager notificationManager) {
this.vaultSettings = vaultSettings;
this.configCache = configCache;
this.cryptoFileSystem = cryptoFileSystem;
@@ -109,6 +113,7 @@ public class Vault {
this.mounter = mounter;
this.settings = settings;
this.fileSystemEventAggregator = fileSystemEventAggregator;
this.notificationManager = notificationManager;
this.showingStats = new SimpleBooleanProperty(false);
this.quickAccessEntry = new AtomicReference<>(null);
}
@@ -145,14 +150,17 @@ public class Vault {
LOG.warn("Limiting cleartext filename length on this device to {}.", vaultSettings.maxCleartextFilenameLength.get());
}
CryptoFileSystemProperties fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties() //
var fsPropsBuilder = CryptoFileSystemProperties.cryptoFileSystemProperties() //
.withKeyLoader(keyLoader) //
.withFlags(flags) //
.withMaxCleartextNameLength(vaultSettings.maxCleartextFilenameLength.get()) //
.withVaultConfigFilename(Constants.VAULTCONFIG_FILENAME) //
.withFilesystemEventConsumer(this::consumeVaultEvent) //
.build();
return CryptoFileSystemProvider.newFileSystem(getPath(), fsProps);
.withFilesystemEventConsumer(this::consumeVaultEvent);
if (keyLoader instanceof FilesystemOwnerSupplier oo) {
fsPropsBuilder.withOwnerGetter(oo::getOwner);
}
return CryptoFileSystemProvider.newFileSystem(getPath(), fsPropsBuilder.build());
}
private void destroyCryptoFileSystem() {
@@ -262,6 +270,7 @@ public class Vault {
private void consumeVaultEvent(FilesystemEvent e) {
fileSystemEventAggregator.put(this, e);
notificationManager.offer(this, e);
}
// ******************************************************************************

View File

@@ -6,6 +6,7 @@ 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.FileIsInUseEvent;
import org.cryptomator.cryptofs.event.FilesystemEvent;
import javax.inject.Inject;
@@ -101,6 +102,7 @@ public class FileSystemEventAggregator {
case ConflictResolutionFailedEvent(_, _, Path conflictingCiphertext, _) -> conflictingCiphertext;
case BrokenDirFileEvent(_, Path ciphertext) -> ciphertext;
case BrokenFileNodeEvent(_, _, Path ciphertext) -> ciphertext;
case FileIsInUseEvent(_, _, Path ciphertext, _, _, _) -> ciphertext;
};
return new FSEventBucket(v, p, event.getClass());
}

View File

@@ -0,0 +1,85 @@
package org.cryptomator.event;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.cryptofs.event.FileIsInUseEvent;
import org.cryptomator.cryptofs.event.FilesystemEvent;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.nio.file.Path;
import java.time.Duration;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Manager for notifications.
* <p>
* To add (filesystem) events, use method {@link #offer(Vault, FilesystemEvent)}. If the input event is eligible, it is added to an internal queue.
* An event is eligible, if
* <ul>
* <li>the event should trigger a notification and</li>
* <li>it is not added within the last {@value DEBOUNCE_THRESHOLD_SECONDS} seconds</li>
* </ul>
*
* @see org.cryptomator.ui.fxapp.FxNotificationManager
*/
@Singleton
public class NotificationManager {
private static final int DEBOUNCE_THRESHOLD_SECONDS = 5;
private final Cache<FSEventBucket, FilesystemEvent> debounceCache;
private final ConcurrentLinkedQueue<VaultEvent> pendingEvents;
@Inject
public NotificationManager() {
debounceCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofSeconds(DEBOUNCE_THRESHOLD_SECONDS)).build();
pendingEvents = new ConcurrentLinkedQueue<>();
}
/**
* Offers the given filesystem event to the notification manager.
*
* @param v The vault where the filesystem event happened
* @param e the actual filesystem event
* @return {@code true} if the filesystem event is accepted, otherwise {@code false}.
*/
public boolean offer(Vault v, FilesystemEvent e) {
return switch (e) {
case FileIsInUseEvent fiiue -> addEvent(v, fiiue.ciphertextPath(), fiiue);
default -> false;
};
}
boolean addEvent(Vault v, Path keyPath, FilesystemEvent e) {
var key = new FSEventBucket(v, keyPath, e.getClass());
var isAdded = new AtomicBoolean(false);
debounceCache.asMap().computeIfAbsent(key, _ -> {
synchronized (this) {
pendingEvents.add(new VaultEvent(v, e));
isAdded.set(true);
}
return e;
});
return isAdded.get();
}
/**
* Adds all events to the target list and clears afterward the pending-event-queue
*
* @param target list where the filesystem events are copied to
* @return {@code true}, if elements were copied
*/
public boolean appendToAndClear(List<VaultEvent> target) {
//it is not clear, if addAll iterates thread-safe over the pendingEvents
//hence we synchronize moving (copy then clear) and adding-single-element operations
synchronized (this) {
var result = target.addAll(pendingEvents);
pendingEvents.clear();
return result;
}
}
}

View File

@@ -3,25 +3,6 @@ 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) {
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

@@ -0,0 +1,101 @@
package org.cryptomator.launcher;
import org.slf4j.Logger;
import java.io.IOException;
import java.io.Reader;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Properties;
import java.util.Set;
/**
* Factory to generate admin properties.
*
* <p>
* Admin properties are {@link Properties} using system properties as defaults, but allow overwriting a specific set of properties with an external config file.
* Those properties are created by calling {@link #create()}. The method first reads system property {@value #ADMIN_PROP_FILE_KEY}. If it contains a path to a valid properties file, all overridable properties from the file are loaded into the returned admin properties.
* <p>
* The overridable properties are:
* <ul>
* <li>cryptomator.logDir</li>
* <li>cryptomator.pluginDir</li>
* <li>cryptomator.p12Path</li>
* <li>cryptomator.mountPointsDir</li>
* <li>cryptomator.disableUpdateCheck</li>
* <li>cryptomator.hub.allowedHosts</li>
* <li>cryptomator.hub.enableTrustOnFirstUse</li>
* </ul>
*
* @see Properties
* @see System#getProperties()
*/
class AdminPropertiesFactory {
private static final Logger LOG = EventualLogger.INSTANCE;
private static final long MAX_CONFIG_SIZE_BYTES = 8192;
private static final String ADMIN_PROP_FILE_KEY = "cryptomator.adminConfigPath";
private static final Set<String> ALLOWED_OVERRIDES = Set.of( //
"cryptomator.logDir", //
"cryptomator.pluginDir", //
"cryptomator.p12Path", //
"cryptomator.mountPointsDir", //
"cryptomator.disableUpdateCheck", //
"cryptomator.hub.allowedHosts", //
"cryptomator.hub.enableTrustOnFirstUse");
/**
* Creates new {@link Properties} containing overridable properties from the admin config.
* <p>
* The returned properties object uses as default the {@link System} properties.
* For a list of overridable properties, see {@link AdminPropertiesFactory}
*
* @return {@link Properties} containing overridable properties from the admin config and defaulting to system properties.
*/
static Properties create() {
var systemProps = System.getProperties();
var adminProps = new Properties(systemProps);
final String adminCfgPath = System.getProperty(ADMIN_PROP_FILE_KEY);
if (adminCfgPath == null) {
LOG.debug("Admin config property is not defined. Skipping.");
return adminProps;
}
var propsFromFile = loadPropertiesFromFile(Path.of(adminCfgPath));
for (var key : propsFromFile.stringPropertyNames()) {
if (ALLOWED_OVERRIDES.contains(key)) {
var value = propsFromFile.getProperty(key);
LOG.info("Overwriting {} with value {} from admin config.", key, value);
adminProps.setProperty(key, value);
} else {
LOG.debug("Property {} in admin config is not supported for override.", key);
}
}
return adminProps;
}
//visible for testing
static Properties loadPropertiesFromFile(Path adminPropertiesPath) {
var adminProps = new Properties();
try (FileChannel ch = FileChannel.open(adminPropertiesPath, StandardOpenOption.READ); //
Reader reader = Channels.newReader(ch, StandardCharsets.UTF_8)) {
if (ch.size() > MAX_CONFIG_SIZE_BYTES) {
throw new IOException("Config file %s exceeds maximum size of %d".formatted(adminPropertiesPath, MAX_CONFIG_SIZE_BYTES));
}
adminProps.load(reader);
} catch (NoSuchFileException _) {
//NO-OP
LOG.debug("No admin properties found at {}.", adminPropertiesPath);
} catch (IOException | IllegalArgumentException e) {
LOG.warn("Failed to read administrative properties from {}. Returning empty properties.", adminPropertiesPath, e);
}
return adminProps;
}
}

View File

@@ -11,9 +11,9 @@ import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.common.Environment;
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.networking.SSLContextProvider;
import org.cryptomator.ui.fxapp.FxApplicationComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -35,7 +35,8 @@ public class Cryptomator {
private static final long STARTUP_TIME = System.currentTimeMillis();
static {
var lazyProcessedProps = new SubstitutingProperties(System.getProperties(), System.getenv());
var adminProps = AdminPropertiesFactory.create();
var lazyProcessedProps = new SubstitutingProperties(adminProps, System.getenv(), EventualLogger.INSTANCE);
System.setProperties(lazyProcessedProps);
CRYPTOMATOR_COMPONENT = DaggerCryptomatorComponent.factory().create(STARTUP_TIME);
LOG = LoggerFactory.getLogger(Cryptomator.class);
@@ -89,10 +90,11 @@ public class Cryptomator {
* @return Nonzero exit code in case of an error.
*/
private int run(String[] args) {
debugMode.initialize();
EventualLogger.INSTANCE.drainTo(LOG);
env.log();
LOG.debug("Dagger graph initialized after {}ms", System.currentTimeMillis() - STARTUP_TIME);
LOG.info("Starting Cryptomator {} on {} {} ({})", env.getAppVersion(), SystemUtils.OS_NAME, SystemUtils.OS_VERSION, SystemUtils.OS_ARCH);
debugMode.initialize();
supportedLanguages.applyPreferred();
changeDefaultSSLContext();
/*

View File

@@ -4,7 +4,6 @@ import dagger.Module;
import dagger.Provides;
import org.cryptomator.integrations.autostart.AutoStartProvider;
import org.cryptomator.integrations.tray.TrayIntegrationProvider;
import org.cryptomator.integrations.uiappearance.UiAppearanceProvider;
import org.cryptomator.ui.fxapp.FxApplicationComponent;
import javax.inject.Named;
@@ -30,11 +29,6 @@ class CryptomatorModule {
return new ArrayBlockingQueue<>(10);
}
@Provides
@Singleton
static Optional<UiAppearanceProvider> provideAppearanceProvider() {
return UiAppearanceProvider.get();
}
@Provides
@Singleton

View File

@@ -0,0 +1,106 @@
package org.cryptomator.launcher;
import org.slf4j.Logger;
import org.slf4j.Marker;
import org.slf4j.event.DefaultLoggingEvent;
import org.slf4j.event.Level;
import org.slf4j.event.LoggingEvent;
import org.slf4j.helpers.AbstractLogger;
import java.util.ArrayDeque;
import java.util.List;
import java.util.Objects;
import java.util.Queue;
class EventualLogger extends AbstractLogger {
static final EventualLogger INSTANCE = new EventualLogger();
private final Queue<LoggingEvent> bufferedEvents = new ArrayDeque<>();
private EventualLogger() {
}
synchronized void drainTo(Logger gutter) {
for (var event : bufferedEvents) {
var builder = gutter.atLevel(event.getLevel()) //
.setCause(event.getThrowable()) //
.setMessage(event.getMessage());
Objects.requireNonNullElse(event.getArguments(), List.of()).forEach(builder::addArgument);
Objects.requireNonNullElse(event.getMarkers(), List.<Marker>of()).forEach(builder::addMarker);
builder.log();
}
bufferedEvents.clear();
}
@Override
protected synchronized void handleNormalizedLoggingCall(Level level, Marker marker, String messagePattern, Object[] arguments, Throwable throwable) {
var event = new DefaultLoggingEvent(level, this);
if (marker != null) {
event.addMarker(marker);
}
event.setMessage(messagePattern);
for (var arg : Objects.requireNonNullElse(arguments, new Object[]{})) {
event.addArgument(arg);
}
event.setThrowable(throwable);
bufferedEvents.add(event);
}
//Unclear, unused and undocumented method of slf4j, see also https://github.com/qos-ch/slf4j/discussions/348
@Override
protected String getFullyQualifiedCallerName() {
return getClass().getCanonicalName();
}
@Override
public boolean isTraceEnabled() {
return true;
}
@Override
public boolean isTraceEnabled(Marker marker) {
return true;
}
@Override
public boolean isDebugEnabled() {
return true;
}
@Override
public boolean isDebugEnabled(Marker marker) {
return true;
}
@Override
public boolean isInfoEnabled() {
return true;
}
@Override
public boolean isInfoEnabled(Marker marker) {
return true;
}
@Override
public boolean isWarnEnabled() {
return true;
}
@Override
public boolean isWarnEnabled(Marker marker) {
return true;
}
@Override
public boolean isErrorEnabled() {
return true;
}
@Override
public boolean isErrorEnabled(Marker marker) {
return true;
}
}

View File

@@ -18,7 +18,7 @@ abstract class SSLContextDifferentTrustStoreBase implements SSLContextProvider {
public SSLContext getContext(SecureRandom csprng) throws SSLContextBuildException {
try {
KeyStore truststore = getTruststore();
truststore.load(null, null);
ensureLoaded(truststore);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(truststore);
@@ -30,4 +30,13 @@ abstract class SSLContextDifferentTrustStoreBase implements SSLContextProvider {
throw new SSLContextBuildException(e);
}
}
static void ensureLoaded(KeyStore truststore) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
try {
truststore.aliases();
} catch (KeyStoreException e) {
// Not initialized yet (e.g. custom KeyStore SPI); initialize without replacing preloaded stores.
truststore.load(null, null);
}
}
}

View File

@@ -1,21 +1,73 @@
package org.cryptomator.networking;
import org.cryptomator.common.Nullable;
import org.cryptomator.integrations.common.OperatingSystem;
import org.jetbrains.annotations.VisibleForTesting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.cert.CertificateException;
import java.util.List;
import java.util.Properties;
/**
* SSLContextProvider for Windows using the Windows certificate store as trust store
* SSLContextProvider for Windows using the Windows certificate store as trust store and the bundled JDK cacerts as fallback
* <p>
* In order to work, the jdk.crypto.mscapi jmod is needed
*/
@OperatingSystem(OperatingSystem.Value.WINDOWS)
public class SSLContextWithWindowsCertStore extends SSLContextDifferentTrustStoreBase implements SSLContextProvider {
private static final Logger LOG = LoggerFactory.getLogger(SSLContextWithWindowsCertStore.class);
private static final String DEFAULT_TRUSTSTORE_PASSWORD = "changeit"; //default JDK cacerts password
@Override
KeyStore getTruststore() throws KeyStoreException {
return KeyStore.getInstance("WINDOWS-ROOT");
KeyStore getTruststore() throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
var windowsKeyStore = KeyStore.getInstance("WINDOWS-ROOT");
var jdkKeyStore = getShippedCaCertsStore();
if (jdkKeyStore == null) {
return windowsKeyStore;
}
ensureLoaded(windowsKeyStore);
ensureLoaded(jdkKeyStore);
try {
CombinedKeyStoreSpi spi = CombinedKeyStoreSpi.create(windowsKeyStore, jdkKeyStore);
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);
}
}
@Nullable
KeyStore getShippedCaCertsStore() {
return getCaCertsStoreByProperties(System.getProperties());
}
//for testability
@VisibleForTesting
@Nullable
KeyStore getCaCertsStoreByProperties(Properties props) {
var javaHome = Path.of(props.getProperty("java.home"));
var trustStorePassword = props.getProperty("javax.net.ssl.trustStorePassword", DEFAULT_TRUSTSTORE_PASSWORD).toCharArray();
for (var candidate : List.of(javaHome.resolve("lib/security/cacerts"), javaHome.resolve("conf/security/cacerts"))) {
try {
if (Files.isRegularFile(candidate)) {
return KeyStore.getInstance(candidate.toFile(), trustStorePassword);
}
} catch (CertificateException | KeyStoreException | IOException | NoSuchAlgorithmException e) {
LOG.info("Unable to load fallback cacerts {} file. Skipping fallback.", candidate, e);
}
}
return null;
}
}

View File

@@ -59,7 +59,7 @@ public class ChooseExistingVaultController implements FxController {
this.vault = vault;
this.vaultListManager = vaultListManager;
this.resourceBundle = resourceBundle;
this.screenshot = applicationStyle.appliedThemeProperty().map(this::selectScreenshot);
this.screenshot = applicationStyle.appliedAppThemeProperty().map(this::selectScreenshot);
}
private Image selectScreenshot(Theme theme) {

View File

@@ -19,6 +19,7 @@ public enum FxmlFile {
HEALTH_START("/fxml/health_start.fxml"), //
HEALTH_CHECK_LIST("/fxml/health_check_list.fxml"), //
HUB_NO_KEYCHAIN("/fxml/hub_no_keychain.fxml"), //
HUB_CHECK_HOST_TRUST("/fxml/hub_check_host_trust.fxml"), //
HUB_AUTH_FLOW("/fxml/hub_auth_flow.fxml"), //
HUB_INVALID_LICENSE("/fxml/hub_invalid_license.fxml"), //
HUB_RECEIVE_KEY("/fxml/hub_receive_key.fxml"), //
@@ -29,6 +30,7 @@ public enum FxmlFile {
HUB_REGISTER_FAILED("/fxml/hub_register_failed.fxml"), //
HUB_REGISTER_DEVICE("/fxml/hub_register_device.fxml"), //
HUB_UNAUTHORIZED_DEVICE("/fxml/hub_unauthorized_device.fxml"), //
HUB_UNTRUSTED_HOST("/fxml/hub_untrusted_host.fxml"), //
HUB_REQUIRE_ACCOUNT_INIT("/fxml/hub_require_account_init.fxml"), //
LOCK_FORCED("/fxml/lock_forced.fxml"), //
LOCK_FAILED("/fxml/lock_failed.fxml"), //
@@ -38,6 +40,7 @@ public enum FxmlFile {
MIGRATION_RUN("/fxml/migration_run.fxml"), //
MIGRATION_START("/fxml/migration_start.fxml"), //
MIGRATION_SUCCESS("/fxml/migration_success.fxml"), //
NOTIFICATION("/fxml/notification.fxml"), //
PREFERENCES("/fxml/preferences.fxml"), //
QUIT("/fxml/quit.fxml"), //
QUIT_FORCED("/fxml/quit_forced.fxml"), //
@@ -59,6 +62,7 @@ public enum FxmlFile {
VAULT_STATISTICS("/fxml/stats.fxml"), //
WRONGFILEALERT("/fxml/wrongfilealert.fxml");
private final String ressourcePathString;
FxmlFile(String ressourcePathString) {

View File

@@ -0,0 +1,56 @@
package org.cryptomator.ui.common;
import javafx.stage.Screen;
/**
* Utility class providing methods regarding the OS bar.
*/
public class SystemBarUtil {
public enum Placement {
/**
* OS Bar placed at the left screen edge
*/
LEFT,
/**
* OS Bar placed at the top screen edge
*/
TOP,
/**
* OS Bar placed at the right screen edge
*/
RIGHT,
/**
* OS Bar placed at the bottom screen edge
*/
BOTTOM;
}
/**
* Determines the placement of the OS bar on the given screen.
* <p>
* <b>Assuming the OS bar fills one screen edge completely</b>,
* this method determines that screen edge by comparing the actual screen bounds with the visual ones.
* <p>
* If the screen does not have a system bar, the bottom placement is returned.
* If the screen does have multiple system bars, the first in following priority is returned:
* LEFT, TOP, RIGHT, BOTTOM.
*
* @param screen a {@link Screen} where an OS bar exists
* @return {@link Placement} indicating the screen edge.
*/
public static Placement getPlacementOfSystembar(Screen screen) {
var bounds = screen.getBounds();
var vBounds = screen.getVisualBounds();
//assumption: the system bar fills a whole screen side
if (bounds.getMinX() != vBounds.getMinX()) {
return Placement.LEFT;
} else if (bounds.getMinY() != vBounds.getMinY()) {
return Placement.TOP;
} else if (bounds.getMaxX() != vBounds.getMaxX()) {
return Placement.RIGHT;
} else {
return Placement.BOTTOM;
}
}
}

View File

@@ -1,17 +1,16 @@
package org.cryptomator.ui.common;
import dagger.Lazy;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.integrations.mount.Mountpoint;
import org.cryptomator.integrations.mount.UnmountFailedException;
import org.cryptomator.integrations.revealpath.RevealFailedException;
import org.cryptomator.integrations.revealpath.RevealPathService;
import org.cryptomator.ui.fxapp.FxApplicationScoped;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javafx.application.Application;
import javafx.application.HostServices;
import javafx.concurrent.Task;
import javafx.stage.Stage;
import java.io.IOException;
@@ -28,12 +27,12 @@ public class VaultService {
private static final Logger LOG = LoggerFactory.getLogger(VaultService.class);
private final Lazy<Application> application;
private final RevealPathService revealPathService;
private final ExecutorService executorService;
@Inject
public VaultService(Lazy<Application> application, ExecutorService executorService) {
this.application = application;
public VaultService(RevealPathService revealPathService, ExecutorService executorService) {
this.revealPathService = revealPathService;
this.executorService = executorService;
}
@@ -47,9 +46,9 @@ public class VaultService {
* @param vault The vault to reveal
*/
public Task<Vault> createRevealTask(Vault vault) {
Task<Vault> task = new RevealVaultTask(vault, application.get().getHostServices());
task.setOnSucceeded(evt -> LOG.info("Revealed {}", vault.getDisplayName()));
task.setOnFailed(evt -> LOG.error("Failed to reveal " + vault.getDisplayName(), evt.getSource().getException()));
Task<Vault> task = new RevealVaultTask(vault, revealPathService);
task.setOnSucceeded(_ -> LOG.info("Revealed {}", vault.getDisplayName()));
task.setOnFailed(evt -> LOG.warn("Failed to reveal {}", vault.getDisplayName(), evt.getSource().getException()));
return task;
}
@@ -110,19 +109,18 @@ public class VaultService {
private static class RevealVaultTask extends Task<Vault> {
private final Vault vault;
private final HostServices hostServices;
private final RevealPathService rs;
public RevealVaultTask(Vault vault, HostServices hostServices) {
public RevealVaultTask(Vault vault, RevealPathService revealPathService) {
this.vault = vault;
this.hostServices = hostServices;
setOnFailed(evt -> LOG.error("Failed to reveal " + vault.getDisplayName(), getException()));
this.rs = revealPathService;
}
@Override
protected Vault call() {
protected Vault call() throws RevealFailedException {
switch (vault.getMountPoint()) {
case null -> LOG.warn("Not currently mounted");
case Mountpoint.WithPath m -> hostServices.showDocument(m.uri().toString());
case Mountpoint.WithPath m -> rs.reveal(m.path());
case Mountpoint.WithUri m -> LOG.info("Vault mounted at {}", m.uri()); // TODO show in UI?
}
return vault;

View File

@@ -12,6 +12,8 @@ public enum FontAwesome5Icon {
CARET_DOWN("\uF0D7"), //
CARET_RIGHT("\uF0Da"), //
CHECK("\uF00C"), //
CHEVRON_LEFT("\uF053"), //
CHEVRON_RIGHT("\uF054"), //
CLOCK("\uF017"), //
CLIPBOARD("\uF328"), //
COG("\uF013"), //
@@ -60,6 +62,7 @@ public enum FontAwesome5Icon {
TRASH("\uF1F8"), //
UNLINK("\uf127"), //
USER_COG("\uf4fe"), //
USER_LOCK("\uf502"), //
WRENCH("\uF0AD"), //
WINDOW_MINIMIZE("\uF2D1"), //
;

View File

@@ -4,24 +4,27 @@ import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.fxml.FXML;
import javafx.geometry.Pos;
import javafx.scene.AccessibleRole;
import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import java.util.ResourceBundle;
public class NotificationBar extends HBox {
public class InfoBar extends HBox {
@FXML
private Label notificationLabel;
private Label infoMessage;
private final BooleanProperty dismissable = new SimpleBooleanProperty();
private final BooleanProperty notify = new SimpleBooleanProperty();
public NotificationBar() {
public InfoBar() {
setAlignment(Pos.CENTER);
setStyle("-fx-alignment: center;");
getStyleClass().addAll("info-bar");
Region spacer = new Region();
spacer.setMinWidth(40);
@@ -36,14 +39,21 @@ public class NotificationBar extends HBox {
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);
infoMessage = new Label();
infoMessage.setFocusTraversable(true);
infoMessage.setAccessibleRole(AccessibleRole.BUTTON);
vbox.getChildren().add(infoMessage);
Button closeButton = new Button("X");
var closeGraphic = new FontAwesome5IconView();
closeGraphic.setGlyph(FontAwesome5Icon.TIMES);
closeGraphic.setGlyphSize(12);
closeGraphic.getStyleClass().add("glyph");
Button closeButton = new Button();
closeButton.setGraphic(closeGraphic);
closeButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
closeButton.setAccessibleText(ResourceBundle.getBundle("i18n.strings").getString("main.notification.closeButton.tooltip"));
closeButton.setMinWidth(40);
closeButton.setStyle("-fx-background-color: transparent; -fx-text-fill: white; -fx-font-weight: bold;");
closeButton.visibleProperty().bind(dismissable);
closeButton.setOnAction(_ -> {
@@ -61,11 +71,11 @@ public class NotificationBar extends HBox {
}
public String getText() {
return notificationLabel.getText();
return infoMessage.getText();
}
public void setText(String text) {
notificationLabel.setText(text);
infoMessage.setText(text);
}
public void setStyleClass(String styleClass) {

View File

@@ -61,6 +61,15 @@ public class Dialogs {
.setOkButtonKey(BUTTON_KEY_CLOSE);
}
public SimpleDialog.Builder prepareHubVaultArchived(Stage window, Vault vault) {
return createDialogBuilder().setOwner(window) //
.setTitleKey("unlock.title", vault.getDisplayName()) //
.setMessageKey("hub.archived.message") //
.setDescriptionKey("hub.archived.description") //
.setIcon(FontAwesome5Icon.BAN)//
.setOkButtonKey(BUTTON_KEY_CLOSE);
}
public SimpleDialog.Builder prepareRecoveryVaultAdded(Stage window, String displayName) {
return createDialogBuilder().setOwner(window) //
.setTitleKey("recover.existing.title") //

View File

@@ -1,16 +1,18 @@
package org.cryptomator.ui.eventview;
import org.cryptomator.event.FSEventBucket;
import org.cryptomator.event.FSEventBucketContent;
import org.cryptomator.event.FileSystemEventAggregator;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.common.Constants;
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.cryptofs.event.FileIsInUseEvent;
import org.cryptomator.event.FSEventBucket;
import org.cryptomator.event.FSEventBucketContent;
import org.cryptomator.event.FileSystemEventAggregator;
import org.cryptomator.integrations.revealpath.RevealFailedException;
import org.cryptomator.integrations.revealpath.RevealPathService;
import org.cryptomator.ui.common.FxController;
@@ -43,7 +45,6 @@ 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;
@@ -54,7 +55,6 @@ public class EventListCellController implements FxController {
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;
@@ -79,15 +79,17 @@ public class EventListCellController implements FxController {
Button eventActionsButton;
@Inject
public EventListCellController(FileSystemEventAggregator fileSystemEventAggregator, Optional<RevealPathService> revealService, ResourceBundle resourceBundle) {
public EventListCellController(FileSystemEventAggregator fileSystemEventAggregator,
RevealPathService revealService,
ResourceBundle resourceBundle) {
this.fileSystemEventAggregator = fileSystemEventAggregator;
this.revealService = revealService.orElseGet(() -> null);
this.revealService = revealService;
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.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()), "");
@@ -115,7 +117,7 @@ public class EventListCellController implements FxController {
eventActionsMenu.hide();
eventActionsMenu.getItems().clear();
eventTooltip.setText(item.getKey().vault().getDisplayName());
addAction("generic.action.dismiss", () -> {
addLocalizedAction("generic.action.dismiss", () -> {
fileSystemEventAggregator.remove(item.getKey());
});
switch (item.getValue().mostRecentEvent()) {
@@ -124,70 +126,70 @@ public class EventListCellController implements FxController {
case DecryptionFailedEvent fse -> this.adjustToDecryptionFailedEvent(fse);
case BrokenDirFileEvent fse -> this.adjustToBrokenDirFileEvent(fse);
case BrokenFileNodeEvent fse -> this.adjustToBrokenFileNodeEvent(fse);
case FileIsInUseEvent fse -> this.adjustToFileInUseEvent(fse);
}
}
private void adjustToFileInUseEvent(FileIsInUseEvent fiiue) {
eventIcon.setValue(FontAwesome5Icon.USER_LOCK);
eventMessage.setValue(resourceBundle.getString("eventView.entry.inUse.message"));
var indexFileName = fiiue.cleartextPath().lastIndexOf("/");
eventDescription.setValue(fiiue.cleartextPath().substring(indexFileName + 1));
addLocalizedAction("eventView.entry.inUse.showDecrypted", () -> reveal(revealService, convertVaultPathToSystemPath(fiiue.cleartextPath())));
addLocalizedAction("eventView.entry.inUse.showEncrypted", () -> reveal(revealService, fiiue.ciphertextPath()));
var userAndDevice = fiiue.owner().split(Constants.HUB_USER_DEVICE_SEPARATOR);
var user = userAndDevice[0];
var device = userAndDevice.length == 1 ? userAndDevice[0] : userAndDevice[1];
addLocalizedAction("eventView.entry.inUse.copyUserAndDevice", () -> copyToClipboard(user + ", " + device));
addLocalizedAction("eventView.entry.inUse.ignoreLock", fiiue.ignoreMethod());
}
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, bfe.ciphertextPath()));
} else {
addAction("eventView.entry.brokenFileNode.copyEncrypted", () -> copyToClipboard(bfe.ciphertextPath().toString()));
}
addAction("eventView.entry.brokenFileNode.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(bfe.cleartextPath()).toString()));
addLocalizedAction("eventView.entry.brokenFileNode.showEncrypted", () -> reveal(revealService, bfe.ciphertextPath()));
addLocalizedAction("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()));
}
addLocalizedAction("eventView.entry.conflictResolved.showDecrypted", () -> reveal(revealService, convertVaultPathToSystemPath(cre.resolvedCleartextPath())));
}
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()));
}
addLocalizedAction("eventView.entry.conflict.showDecrypted", () -> reveal(revealService, convertVaultPathToSystemPath(cfe.canonicalCleartextPath())));
addLocalizedAction("eventView.entry.conflict.showEncrypted", () -> reveal(revealService, cfe.conflictingCiphertextPath()));
}
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()));
}
addLocalizedAction("eventView.entry.decryptionFailed.showEncrypted", () -> reveal(revealService, dfe.ciphertextPath()));
}
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()));
}
addLocalizedAction("eventView.entry.brokenDirFile.showEncrypted", () -> reveal(revealService, bde.ciphertextPath()));
}
private void addAction(String localizationKey, Runnable action) {
var entry = new MenuItem(resourceBundle.getString(localizationKey));
private void addLocalizedAction(String localizationKey, Runnable action) {
var entryText = resourceBundle.getString(localizationKey);
addAction(entryText, action);
}
private void addAction(String entryText, Runnable action) {
var entry = new MenuItem(entryText);
entry.getStyleClass().addLast("dropdown-button-context-menu-item");
entry.setOnAction(_ -> action.run());
eventActionsMenu.getItems().addLast(entry);
@@ -234,18 +236,17 @@ public class EventListCellController implements FxController {
}
}
private Path convertVaultPathToSystemPath(Path p) {
if (!(p instanceof CryptoPath)) {
throw new IllegalArgumentException("Path " + p + " is not a vault path");
}
private Path convertVaultPathToSystemPath(String vaultInternalPath) {
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));
var mountPoint = v.getMountPoint().uri().getPath();
if (SystemUtils.IS_OS_WINDOWS) {
mountPoint = mountPoint.substring(1); //strip away any leading "/", otherwise there are errors
}
return Path.of(mountPoint, vaultInternalPath.substring(1)); //vaultPaths are always absolute
}
private void reveal(RevealPathService s, Path p) {

View File

@@ -10,16 +10,20 @@ import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Named;
import javafx.application.Application;
import javafx.application.Platform;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
@FxApplicationScoped
public class FxApplication {
private static final Logger LOG = LoggerFactory.getLogger(FxApplication.class);
static final AtomicReference<Application> INSTANCE = new AtomicReference<>();
private final long startupTime;
private final Environment environment;
private final Settings settings;
@@ -30,9 +34,21 @@ public class FxApplication {
private final FxApplicationTerminator applicationTerminator;
private final AutoUnlocker autoUnlocker;
private final FxFSEventList fxFSEventList;
private final FxNotificationManager notificationManager;
@Inject
FxApplication(@Named("startupTime") long startupTime, Environment environment, Settings settings, AppLaunchEventHandler launchEventHandler, Lazy<TrayMenuComponent> trayMenu, FxApplicationWindows appWindows, FxApplicationStyle applicationStyle, FxApplicationTerminator applicationTerminator, AutoUnlocker autoUnlocker, FxFSEventList fxFSEventList) {
FxApplication(Application fxApp,
@Named("startupTime") long startupTime, //
Environment environment, //
Settings settings, //
AppLaunchEventHandler launchEventHandler, //
Lazy<TrayMenuComponent> trayMenu, //
FxApplicationWindows appWindows, //
FxApplicationStyle applicationStyle, //
FxApplicationTerminator applicationTerminator, //
AutoUnlocker autoUnlocker, //
FxFSEventList fxFSEventList, //
FxNotificationManager notificationManager) {
this.startupTime = startupTime;
this.environment = environment;
this.settings = settings;
@@ -43,6 +59,9 @@ public class FxApplication {
this.applicationTerminator = applicationTerminator;
this.autoUnlocker = autoUnlocker;
this.fxFSEventList = fxFSEventList;
this.notificationManager = notificationManager;
INSTANCE.set(fxApp);
}
public void start() {
@@ -88,6 +107,7 @@ public class FxApplication {
launchEventHandler.startHandlingLaunchEvents();
fxFSEventList.schedulePollForUpdates();
notificationManager.schedulePollForUpdates();
autoUnlocker.tryUnlockForTimespan(2, TimeUnit.MINUTES);
}

View File

@@ -7,12 +7,14 @@ package org.cryptomator.ui.fxapp;
import dagger.Module;
import dagger.Provides;
import org.cryptomator.integrations.uiappearance.UiAppearanceProvider;
import org.cryptomator.ui.decryptname.DecryptNameComponent;
import org.cryptomator.ui.error.ErrorComponent;
import org.cryptomator.ui.eventview.EventViewComponent;
import org.cryptomator.ui.health.HealthCheckComponent;
import org.cryptomator.ui.lock.LockComponent;
import org.cryptomator.ui.mainwindow.MainWindowComponent;
import org.cryptomator.ui.notification.NotificationComponent;
import org.cryptomator.ui.preferences.PreferencesComponent;
import org.cryptomator.ui.quit.QuitComponent;
import org.cryptomator.ui.recoverykey.RecoveryKeyComponent;
@@ -25,6 +27,7 @@ import org.cryptomator.ui.vaultoptions.VaultOptionsComponent;
import javafx.scene.image.Image;
import java.io.IOException;
import java.io.InputStream;
import java.util.Optional;
@Module(subcomponents = {TrayMenuComponent.class, //
DecryptNameComponent.class, //
@@ -39,7 +42,8 @@ import java.io.InputStream;
UpdateReminderComponent.class, //
ShareVaultComponent.class, //
EventViewComponent.class, //
RecoveryKeyComponent.class})
RecoveryKeyComponent.class, //
NotificationComponent.class})
abstract class FxApplicationModule {
private static Image createImageFromResource(String resourceName) throws IOException {
@@ -48,6 +52,12 @@ abstract class FxApplicationModule {
}
}
@Provides
@FxApplicationScoped
static Optional<UiAppearanceProvider> provideAppearanceProvider() {
return UiAppearanceProvider.get();
}
@Provides
@FxApplicationScoped
static TrayMenuComponent provideTrayMenuComponent(TrayMenuComponent.Builder builder) {
@@ -78,4 +88,10 @@ abstract class FxApplicationModule {
return factory.create();
}
@Provides
@FxApplicationScoped
static NotificationComponent provideNotificationComponent(NotificationComponent.Factory factory) {
return factory.create();
}
}

View File

@@ -36,82 +36,91 @@ public class FxApplicationStyle {
}
public void initialize() {
var uiTheme = settings.theme.get();
if (uiTheme == UiTheme.AUTOMATIC) {
registerOsThemeListener();
}
applyTheme(uiTheme);
settings.theme.addListener(this::appThemeChanged);
loadSelectedStyleSheet(settings.theme.get());
}
private void appThemeChanged(@SuppressWarnings("unused") ObservableValue<? extends UiTheme> observable, @SuppressWarnings("unused") UiTheme oldValue, UiTheme newValue) {
if (appearanceProvider.isPresent() && oldValue == UiTheme.AUTOMATIC && newValue != UiTheme.AUTOMATIC) {
private void appThemeChanged(@SuppressWarnings("unused") ObservableValue<? extends UiTheme> observable, UiTheme oldValue, UiTheme newValue) {
if (oldValue == newValue) {
// no-op
} else if (newValue == UiTheme.AUTOMATIC) {
registerOsThemeListener();
} else if (oldValue == UiTheme.AUTOMATIC) {
removeOsThemeListener();
}
applyTheme(newValue);
}
private void removeOsThemeListener() {
if (appearanceProvider.isPresent()) {
try {
appearanceProvider.get().removeListener(systemInterfaceThemeListener);
} catch (UiAppearanceException e) {
LOG.error("Failed to disable automatic theme switching.");
}
}
loadSelectedStyleSheet(newValue);
}
private void loadSelectedStyleSheet(UiTheme desiredTheme) {
UiTheme theme = licenseHolder.isValidLicense() ? desiredTheme : UiTheme.LIGHT;
switch (theme) {
case LIGHT -> applyLightTheme();
case DARK -> applyDarkTheme();
case AUTOMATIC -> {
appearanceProvider.ifPresent(provider -> {
try {
provider.addListener(systemInterfaceThemeListener);
} catch (UiAppearanceException e) {
LOG.error("Failed to enable automatic theme switching.");
}
});
applySystemTheme();
LOG.warn("Failed to disable automatic theme switching.", e);
}
} else {
LOG.debug("Unable to remove listener os theme changes: No supported UiAppearanceProvider present");
}
}
private void systemInterfaceThemeChanged(Theme theme) {
switch (theme) {
case LIGHT -> applyLightTheme();
case DARK -> applyDarkTheme();
}
}
private void applySystemTheme() {
private void registerOsThemeListener() {
if (appearanceProvider.isPresent()) {
systemInterfaceThemeChanged(appearanceProvider.get().getSystemTheme());
try {
appearanceProvider.get().addListener(systemInterfaceThemeListener);
} catch (UiAppearanceException e) {
LOG.warn("Failed to enable automatic theme switching.", e);
}
} else {
LOG.warn("No UiAppearanceProvider present, assuming LIGHT theme...");
applyLightTheme();
LOG.warn("Unable to register for os theme changes: No supported UiAppearanceProvider present");
}
}
private void applyLightTheme() {
var stylesheet = Optional //
.ofNullable(getClass().getResource("/css/light_theme.bss")) //
.orElse(getClass().getResource("/css/light_theme.css"));
private void applyTheme(UiTheme uiTheme) {
if (!licenseHolder.isValidLicense()) {
loadAndApplyLightTheme();
} else {
switch (uiTheme) {
case AUTOMATIC -> {
var osTheme = appearanceProvider.map(UiAppearanceProvider::getSystemTheme).orElse(Theme.LIGHT);
systemInterfaceThemeChanged(osTheme);
}
case LIGHT -> loadAndApplyLightTheme();
case DARK -> loadAndApplyDarkTheme();
}
}
}
private void systemInterfaceThemeChanged(Theme osTheme) {
switch (osTheme) {
case LIGHT -> loadAndApplyLightTheme();
case DARK -> loadAndApplyDarkTheme();
}
}
private void loadAndApplyLightTheme() {
loadAndApplyTheme(Theme.LIGHT, "/css/light_theme.css");
}
private void loadAndApplyDarkTheme() {
loadAndApplyTheme(Theme.DARK, "/css/dark_theme.css");
}
private void loadAndApplyTheme(Theme appTheme, String cssFile) {
var stylesheet = getClass().getResource(cssFile);
if (stylesheet == null) {
LOG.warn("Failed to load light_theme stylesheet");
} else {
Application.setUserAgentStylesheet(stylesheet.toString());
appearanceProvider.ifPresent(provider -> provider.adjustToTheme(Theme.LIGHT));
appliedTheme.set(Theme.LIGHT);
throw new IllegalStateException("Cannot find resource %s".formatted(cssFile));
}
Application.setUserAgentStylesheet(stylesheet.toString());
appearanceProvider.ifPresent(provider -> provider.adjustToTheme(appTheme));
appliedTheme.set(appTheme);
}
private void applyDarkTheme() {
var stylesheet = Optional //
.ofNullable(getClass().getResource("/css/dark_theme.bss")) //
.orElse(getClass().getResource("/css/dark_theme.css"));
if (stylesheet == null) {
LOG.warn("Failed to load dark_theme stylesheet");
} else {
Application.setUserAgentStylesheet(stylesheet.toString());
appearanceProvider.ifPresent(provider -> provider.adjustToTheme(Theme.DARK));
appliedTheme.set(Theme.DARK);
}
}
public ObjectProperty<Theme> appliedThemeProperty() {
public ObjectProperty<Theme> appliedAppThemeProperty() {
return appliedTheme;
}
}

View File

@@ -11,6 +11,7 @@ import org.cryptomator.ui.error.ErrorComponent;
import org.cryptomator.ui.eventview.EventViewComponent;
import org.cryptomator.ui.lock.LockComponent;
import org.cryptomator.ui.mainwindow.MainWindowComponent;
import org.cryptomator.ui.notification.NotificationComponent;
import org.cryptomator.ui.preferences.PreferencesComponent;
import org.cryptomator.ui.preferences.SelectedPreferencesTab;
import org.cryptomator.ui.quit.QuitComponent;
@@ -54,6 +55,7 @@ public class FxApplicationWindows {
private final LockComponent.Factory lockWorkflowFactory;
private final ErrorComponent.Factory errorWindowFactory;
private final Lazy<EventViewComponent> eventViewWindow;
private final Lazy<NotificationComponent> notificationWindow;
private final ExecutorService executor;
private final VaultOptionsComponent.Factory vaultOptionsWindow;
private final ShareVaultComponent.Factory shareVaultWindow;
@@ -73,6 +75,7 @@ public class FxApplicationWindows {
VaultOptionsComponent.Factory vaultOptionsWindow, //
ShareVaultComponent.Factory shareVaultWindow, //
Lazy<EventViewComponent> eventViewWindow, //
Lazy<NotificationComponent> notificationWindow,
ExecutorService executor, //
Dialogs dialogs) {
this.primaryStage = primaryStage;
@@ -85,6 +88,7 @@ public class FxApplicationWindows {
this.lockWorkflowFactory = lockWorkflowFactory;
this.errorWindowFactory = errorWindowFactory;
this.eventViewWindow = eventViewWindow;
this.notificationWindow = notificationWindow;
this.executor = executor;
this.vaultOptionsWindow = vaultOptionsWindow;
this.shareVaultWindow = shareVaultWindow;
@@ -193,6 +197,10 @@ public class FxApplicationWindows {
return CompletableFuture.supplyAsync(() -> eventViewWindow.get().showEventViewerWindow(), Platform::runLater).whenComplete(this::reportErrors);
}
public CompletionStage<Stage> showNotification() {
return CompletableFuture.supplyAsync(() -> notificationWindow.get().showNotification(), Platform::runLater).whenComplete(this::reportErrors);
}
/**
* Displays the generic error scene in the given window.
*

View File

@@ -3,6 +3,8 @@ package org.cryptomator.ui.fxapp;
import org.cryptomator.event.FSEventBucket;
import org.cryptomator.event.FSEventBucketContent;
import org.cryptomator.event.FileSystemEventAggregator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javafx.application.Platform;
@@ -11,6 +13,7 @@ import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import java.util.Map;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -23,6 +26,8 @@ import java.util.concurrent.TimeUnit;
@FxApplicationScoped
public class FxFSEventList {
private static final Logger LOG = LoggerFactory.getLogger(FxFSEventList.class);
private final ObservableList<Map.Entry<FSEventBucket, FSEventBucketContent>> events;
private final FileSystemEventAggregator eventAggregator;
private final ScheduledExecutorService scheduler;
@@ -37,7 +42,13 @@ public class FxFSEventList {
}
public void schedulePollForUpdates() {
scheduler.schedule(this::checkForEventUpdates, 1000, TimeUnit.MILLISECONDS);
try {
scheduler.schedule(this::checkForEventUpdates, 1000, TimeUnit.MILLISECONDS);
} catch ( RejectedExecutionException e) {
if(!scheduler.isShutdown()) {
LOG.warn("Failed to poll for filesystem events", e);
}
}
}
/**

View File

@@ -0,0 +1,57 @@
package org.cryptomator.ui.fxapp;
import org.cryptomator.event.NotificationManager;
import org.cryptomator.event.VaultEvent;
import javax.inject.Inject;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Notification manager inside the UI domain.
* <p>
* Polls the {@link NotificationManager} for pending events every {@value POLL_INTERVAL_SECONDS } seconds and
* triggers the notification window display when events are available.
* Returns an observable list of events requiring a user notification with {@link #getEventsRequiringNotification()}.
*
* @see NotificationManager
*/
@FxApplicationScoped
public class FxNotificationManager {
private static final int POLL_INTERVAL_SECONDS = 1;
private final NotificationManager notificationManager;
private final ScheduledExecutorService scheduler;
private final FxApplicationWindows applicationWindows;
private final ObservableList<VaultEvent> eventsRequiringNotification;
@Inject
public FxNotificationManager(NotificationManager notificationManager, ScheduledExecutorService scheduler, FxApplicationWindows applicationWindows) {
this.notificationManager = notificationManager;
this.scheduler = scheduler;
this.applicationWindows = applicationWindows;
this.eventsRequiringNotification = FXCollections.observableArrayList();
}
public void schedulePollForUpdates() {
scheduler.scheduleAtFixedRate(this::checkForPendingNotifications, 0, POLL_INTERVAL_SECONDS, TimeUnit.SECONDS);
}
private void checkForPendingNotifications() {
Platform.runLater(() -> {
if (notificationManager.appendToAndClear(eventsRequiringNotification)) {
applicationWindows.showNotification();
}
});
}
public ObservableList<VaultEvent> getEventsRequiringNotification() {
return eventsRequiringNotification;
}
}

View File

@@ -0,0 +1,37 @@
package org.cryptomator.ui.fxapp;
import org.cryptomator.integrations.common.DisplayName;
import org.cryptomator.integrations.common.OperatingSystem;
import org.cryptomator.integrations.common.Priority;
import org.cryptomator.integrations.revealpath.RevealFailedException;
import org.cryptomator.integrations.revealpath.RevealPathService;
import java.nio.file.Path;
/**
* A {@link RevealPathService} service implementation using the JavaFX {@link javafx.application.HostServices#showDocument(String)} to reveal documents.
* <p>
* Internally the HostServices class uses GTK on Linux.
*
* @implNote {@link #reveal(Path)} only succeeds when the class {@link FxApplication} is initialized.
*/
@DisplayName("JavaFX HostServices (GTK)")
@OperatingSystem(OperatingSystem.Value.LINUX)
@Priority(10)
public class JfxRevealPathService implements RevealPathService {
@Override
public void reveal(Path p) throws RevealFailedException {
var fxApp = FxApplication.INSTANCE.get();
if (fxApp != null) {
fxApp.getHostServices().showDocument(p.toUri().toString());
} else {
throw new RevealFailedException("JavaFX Application not initialized");
}
}
@Override
public boolean isSupported() {
return true;
}
}

View File

@@ -0,0 +1,68 @@
package org.cryptomator.ui.fxapp;
import org.cryptomator.integrations.common.DisplayName;
import org.cryptomator.integrations.common.OperatingSystem;
import org.cryptomator.integrations.common.Priority;
import org.cryptomator.integrations.uiappearance.Theme;
import org.cryptomator.integrations.uiappearance.UiAppearanceException;
import org.cryptomator.integrations.uiappearance.UiAppearanceListener;
import org.cryptomator.integrations.uiappearance.UiAppearanceProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javafx.application.ColorScheme;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import java.util.concurrent.ConcurrentHashMap;
@DisplayName("JavaFX Color Scheme switcher")
@OperatingSystem(OperatingSystem.Value.LINUX)
@OperatingSystem(OperatingSystem.Value.WINDOWS)
@Priority(1050)
public class JfxUiAppearanceProvider implements UiAppearanceProvider {
private static final Logger LOG = LoggerFactory.getLogger(JfxUiAppearanceProvider.class);
private final ConcurrentHashMap<UiAppearanceListener, ChangeListener<ColorScheme>> uiAppearanceListeners = new ConcurrentHashMap<>();
private final Platform.Preferences preferences = Platform.getPreferences(); //Note: this service impl MUST be loaded in the fx application thread
@Override
public Theme getSystemTheme() {
return switch (preferences.getColorScheme()) {
case DARK -> Theme.DARK;
case LIGHT -> Theme.LIGHT;
};
}
@Override
public void adjustToTheme(Theme theme) {
//no-op
}
@Override
public void addListener(UiAppearanceListener uiAppearanceListener) throws UiAppearanceException {
var fxChangeListener = (ChangeListener<ColorScheme>) (_, _, newScheme) -> {
var newTheme = switch (newScheme) {
case DARK -> Theme.DARK;
case LIGHT -> Theme.LIGHT;
};
uiAppearanceListener.systemAppearanceChanged(newTheme);
};
LOG.debug("Register listener for OS theme changes");
uiAppearanceListeners.computeIfAbsent(uiAppearanceListener, k -> {
Platform.runLater(() -> preferences.colorSchemeProperty().addListener(fxChangeListener));
return fxChangeListener;
});
}
@Override
public void removeListener(UiAppearanceListener uiAppearanceListener) throws UiAppearanceException {
var fxChangeListener = uiAppearanceListeners.remove(uiAppearanceListener);
if (fxChangeListener != null) {
LOG.debug("Removing listener for OS theme changes");
Platform.runLater(() -> preferences.colorSchemeProperty().removeListener(fxChangeListener));
}
}
}

View File

@@ -63,8 +63,8 @@ abstract class HealthCheckModule {
@Provides
@HealthCheckWindow
@HealthCheckScoped
static KeyLoadingStrategy provideKeyLoadingStrategy(KeyLoadingComponent.Builder compBuilder, @HealthCheckWindow Vault vault, @Named("unlockWindow") Stage window ) {
return compBuilder.vault(vault).window(window).build().keyloadingStrategy();
static KeyLoadingStrategy provideKeyLoadingStrategy(KeyLoadingComponent.Factory compFactory, @HealthCheckWindow Vault vault, @Named("unlockWindow") Stage window ) {
return compFactory.create(vault, window).keyloadingStrategy();
}
@Provides

View File

@@ -4,9 +4,12 @@ import com.google.common.base.Throwables;
import org.cryptomator.common.Environment;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.cryptofs.VaultConfig;
import org.cryptomator.integrations.revealpath.RevealFailedException;
import org.cryptomator.integrations.revealpath.RevealPathService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javafx.application.Application;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
@@ -25,6 +28,7 @@ import java.util.stream.Collectors;
@HealthCheckScoped
public class ReportWriter {
private static final Logger LOG = LoggerFactory.getLogger(ReportWriter.class);
private static final String REPORT_HEADER = """
*******************************************
* Cryptomator Vault Health Report *
@@ -43,14 +47,14 @@ public class ReportWriter {
private final Vault vault;
private final VaultConfig vaultConfig;
private final Application application;
private final RevealPathService revealPathService;
private final Path exportDestination;
@Inject
public ReportWriter(@HealthCheckWindow Vault vault, AtomicReference<VaultConfig> vaultConfigRef, Application application, Environment env) {
public ReportWriter(@HealthCheckWindow Vault vault, AtomicReference<VaultConfig> vaultConfigRef, RevealPathService revealPathService, Environment env) {
this.vault = vault;
this.vaultConfig = Objects.requireNonNull(vaultConfigRef.get());
this.application = application;
this.revealPathService = revealPathService;
this.exportDestination = env.getLogDir().orElse(Path.of(System.getProperty("user.home"))).resolve("healthReport_" + vault.getDisplayName() + "_" + TIME_STAMP.format(Instant.now()) + ".log");
}
@@ -92,7 +96,11 @@ public class ReportWriter {
}
private void reveal() {
application.getHostServices().showDocument(exportDestination.getParent().toUri().toString());
try {
revealPathService.reveal(exportDestination.getParent());
} catch (RevealFailedException e) {
LOG.warn("Failed to reveal export destination location of report", e);
}
}
}

View File

@@ -3,11 +3,8 @@ package org.cryptomator.ui.keyloading;
import dagger.BindsInstance;
import dagger.Subcomponent;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.cryptolib.api.MasterkeyLoader;
import javafx.stage.Stage;
import java.util.Map;
import java.util.function.Supplier;
@KeyLoadingScoped
@Subcomponent(modules = {KeyLoadingModule.class})
@@ -16,16 +13,10 @@ public interface KeyLoadingComponent {
@KeyLoading
KeyLoadingStrategy keyloadingStrategy();
@Subcomponent.Builder
interface Builder {
@Subcomponent.Factory
interface Factory {
@BindsInstance
Builder vault(@KeyLoading Vault vault);
@BindsInstance
Builder window(@KeyLoading Stage window);
KeyLoadingComponent build();
KeyLoadingComponent create(@BindsInstance @KeyLoading Vault vault, @KeyLoading @BindsInstance Stage window);
}
}

View File

@@ -1,6 +1,5 @@
package org.cryptomator.ui.keyloading.hub;
import com.nimbusds.jose.JWEObject;
import dagger.Lazy;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxmlFile;
@@ -12,8 +11,6 @@ import javax.inject.Inject;
import javax.inject.Named;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.StringBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.concurrent.WorkerStateEvent;

View File

@@ -0,0 +1,179 @@
package org.cryptomator.ui.keyloading.hub;
import dagger.Lazy;
import org.cryptomator.common.Environment;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.keyloading.KeyLoading;
import org.cryptomator.ui.keyloading.KeyLoadingScoped;
import org.jetbrains.annotations.VisibleForTesting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
import javafx.stage.Stage;
import java.net.URI;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.CompletableFuture;
@KeyLoadingScoped
public class CheckHostTrustController implements FxController {
private static final Logger LOG = LoggerFactory.getLogger(CheckHostTrustController.class);
private static final String CHECK_KEY = "hub.checkHostTrust.message.check";
private static final String ASK_SINGULAR_KEY = "hub.checkHostTrust.message.ask";
private static final String ASK_PLURAL_KEY = "hub.checkHostTrust.message.ask.plural";
private static final String TRUSTED_CRYPTOMATOR_CLOUD_DOMAIN = ".cryptomator.cloud";
private final Stage window;
private final HubConfig hubConfig;
private final URI canonicalHubUri;
private final URI canonicalAuthUri;
private final Lazy<Scene> authFlowScene;
private final Lazy<Scene> untrustedHostScene;
private final CompletableFuture<ReceivedKey> result;
private final Settings settings;
private final Environment env;
private final ResourceBundle resourceBundle;
private final SortedSet<String> hostnames;
private final StringProperty messageLabel;
@FXML
private TextFlow hostnamesFlow;
@Inject
public CheckHostTrustController(@KeyLoading Stage window, //
HubConfig hubConfig, //
@FxmlScene(FxmlFile.HUB_AUTH_FLOW) Lazy<Scene> authFlowScene, //
@FxmlScene(FxmlFile.HUB_UNTRUSTED_HOST) Lazy<Scene> untrustedHostScene, //
CompletableFuture<ReceivedKey> result, //
Settings settings, //
Environment env, //
ResourceBundle resourceBundle) {
this.window = window;
this.hubConfig = hubConfig;
this.canonicalHubUri = hubConfig.getApiBaseUrl();
this.canonicalAuthUri = URI.create(hubConfig.authEndpoint);
this.authFlowScene = authFlowScene;
this.untrustedHostScene = untrustedHostScene;
this.result = result;
this.settings = settings;
this.env = env;
this.resourceBundle = resourceBundle;
this.hostnames = new TreeSet<>();
this.messageLabel = new SimpleStringProperty(resourceBundle.getString(CHECK_KEY));
}
@FXML
public void initialize() {
if (!isConsistentHubConfig()) {
LOG.warn("Inconsistent hub config detected. Denying access to protect the user.");
deny();
} else if (isAllCryptomatorCloud() && !isAnyHttpHost()) {
trust(); // trust *.cryptomator.cloud by default, domain is owned by Cryptomator maintainers
} else if (containsAllowedHosts(env.hubAllowedHosts())) {
trust(); // trust hosts explicitly allowlisted via system property
} else if (isAnyHttpHost() && !isAllLocalhost()) {
LOG.warn("Denying attempt to connect to hub instance via unencrypted HTTP.");
deny(); // never trust http hosts except for local testing
} else if (env.hubTrustOnFirstUse() && containsAllowedHosts(settings.trustedHosts)) {
trust(); // trust hosts previously allowlisted by the user
} else if (env.hubTrustOnFirstUse()) {
hostnames.add(getAuthority(canonicalHubUri));
hostnames.add(getAuthority(canonicalAuthUri));
renderHostnames(); // ask user whether to trust these hosts
} else {
LOG.warn("Cryptomator is not allowed to connect to {}. Check your {} config.", getAuthority(canonicalHubUri), Environment.HUB_ALLOWED_HOSTS_PROP_NAME);
deny();
}
}
@FXML
public void trust() {
settings.trustedHosts.addAll(hostnames);
Platform.runLater(() -> {
window.setScene(authFlowScene.get());
});
}
@FXML
public void deny() {
result.cancel(true);
Platform.runLater(() -> {
window.setScene(untrustedHostScene.get());
});
}
private void renderHostnames() {
hostnamesFlow.getChildren().clear();
for (var hostname : hostnames) {
hostnamesFlow.getChildren().add(new Text(hostname + System.lineSeparator()));
}
var messageKey = hostnames.size() > 1 ? ASK_PLURAL_KEY : ASK_SINGULAR_KEY;
messageLabel.set(resourceBundle.getString(messageKey));
}
private boolean isConsistentHubConfig() {
var canonicalHubAuthority = getAuthority(canonicalHubUri);
var canonicalAuthAuthority = getAuthority(canonicalAuthUri);
// apiBaseURL.host == deviceUrl.host == authSuccessUrl.host == authErrorUrl.host
return (hubConfig.apiBaseUrl == null || getAuthority(hubConfig.apiBaseUrl).equals(canonicalHubAuthority)) //
&& (hubConfig.devicesResourceUrl == null || getAuthority(hubConfig.devicesResourceUrl).equals(canonicalHubAuthority)) //
&& getAuthority(hubConfig.authSuccessUrl).equals(canonicalHubAuthority) //
&& getAuthority(hubConfig.authErrorUrl).equals(canonicalHubAuthority) //
// authUrl.host == tokenUrl.host:
&& getAuthority(hubConfig.tokenEndpoint).equals(canonicalAuthAuthority);
}
private boolean isAllCryptomatorCloud() {
return canonicalHubUri.getHost().endsWith(TRUSTED_CRYPTOMATOR_CLOUD_DOMAIN) && canonicalAuthUri.getHost().endsWith(TRUSTED_CRYPTOMATOR_CLOUD_DOMAIN);
}
private boolean isAnyHttpHost() {
return "http".equalsIgnoreCase(canonicalHubUri.getScheme()) || "http".equalsIgnoreCase(canonicalAuthUri.getScheme());
}
private boolean isAllLocalhost() {
return "localhost".equalsIgnoreCase(canonicalHubUri.getHost()) && "localhost".equalsIgnoreCase(canonicalAuthUri.getHost());
}
@VisibleForTesting
boolean containsAllowedHosts(Set<String> allowedHubHosts) {
return allowedHubHosts.contains(getAuthority(canonicalHubUri)) && allowedHubHosts.contains(getAuthority(canonicalAuthUri));
}
public static String getAuthority(String string) {
return getAuthority(URI.create(string));
}
public static String getAuthority(URI uri) {
if (uri.getPort() == -1) {
return "%s://%s".formatted(uri.getScheme(), uri.getHost());
} else {
return "%s://%s:%s".formatted(uri.getScheme(), uri.getHost(), uri.getPort());
}
}
//--- JavaFX property getter & setter
public StringProperty messageLabelProperty() {
return messageLabel;
}
public String getMessageLabel() {
return messageLabel.get();
}
}

View File

@@ -66,6 +66,13 @@ public abstract class HubKeyLoadingModule {
return new AtomicReference<>();
}
@Provides
@Named("filesystemOwnerId")
@KeyLoadingScoped
static AtomicReference<String> provideFilesystemOwnerIdRef() {
return new AtomicReference<>();
}
@Provides
@KeyLoadingScoped
static CompletableFuture<ReceivedKey> provideResult() {
@@ -91,6 +98,13 @@ public abstract class HubKeyLoadingModule {
return fxmlLoaders.createScene(FxmlFile.HUB_NO_KEYCHAIN);
}
@Provides
@FxmlScene(FxmlFile.HUB_CHECK_HOST_TRUST)
@KeyLoadingScoped
static Scene provideHubCheckHostTrustScene(@KeyLoading FxmlLoaderFactory fxmlLoaders) {
return fxmlLoaders.createScene(FxmlFile.HUB_CHECK_HOST_TRUST);
}
@Provides
@FxmlScene(FxmlFile.HUB_AUTH_FLOW)
@KeyLoadingScoped
@@ -161,6 +175,13 @@ public abstract class HubKeyLoadingModule {
return fxmlLoaders.createScene(FxmlFile.HUB_UNAUTHORIZED_DEVICE);
}
@Provides
@FxmlScene(FxmlFile.HUB_UNTRUSTED_HOST)
@KeyLoadingScoped
static Scene provideHubUntrustedHostScene(@KeyLoading FxmlLoaderFactory fxmlLoaders) {
return fxmlLoaders.createScene(FxmlFile.HUB_UNTRUSTED_HOST);
}
@Provides
@FxmlScene(FxmlFile.HUB_REQUIRE_ACCOUNT_INIT)
@KeyLoadingScoped
@@ -173,6 +194,11 @@ public abstract class HubKeyLoadingModule {
@FxControllerKey(NoKeychainController.class)
abstract FxController bindNoKeychainController(NoKeychainController controller);
@Binds
@IntoMap
@FxControllerKey(CheckHostTrustController.class)
abstract FxController bindCheckHostAuthenticityController(CheckHostTrustController controller);
@Binds
@IntoMap
@FxControllerKey(AuthFlowController.class)
@@ -218,6 +244,11 @@ public abstract class HubKeyLoadingModule {
@FxControllerKey(UnauthorizedDeviceController.class)
abstract FxController bindUnauthorizedDeviceController(UnauthorizedDeviceController controller);
@Binds
@IntoMap
@FxControllerKey(UntrustedHostController.class)
abstract FxController bindUnauthorizedHostController(UntrustedHostController controller);
@Binds
@IntoMap
@FxControllerKey(RequireAccountInitController.class)

View File

@@ -2,6 +2,7 @@ package org.cryptomator.ui.keyloading.hub;
import com.google.common.base.Preconditions;
import dagger.Lazy;
import org.cryptomator.common.FilesystemOwnerSupplier;
import org.cryptomator.common.keychain.KeychainManager;
import org.cryptomator.common.keychain.NoKeychainAccessProviderException;
import org.cryptomator.common.settings.DeviceKey;
@@ -23,28 +24,31 @@ import java.net.URI;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicReference;
@KeyLoading
public class HubKeyLoadingStrategy implements KeyLoadingStrategy {
public class HubKeyLoadingStrategy implements KeyLoadingStrategy, FilesystemOwnerSupplier {
private static final String SCHEME_PREFIX = "hub+";
public static final String SCHEME_PREFIX = "hub+";
public static final String SCHEME_HUB_HTTP = SCHEME_PREFIX + "http";
public static final String SCHEME_HUB_HTTPS = SCHEME_PREFIX + "https";
private final Stage window;
private final KeychainManager keychainManager;
private final Lazy<Scene> authFlowScene;
private final AtomicReference<String> fsOwnerId;
private final Lazy<Scene> checkHostTrustScene;
private final Lazy<Scene> noKeychainScene;
private final CompletableFuture<ReceivedKey> result;
private final DeviceKey deviceKey;
@Inject
public HubKeyLoadingStrategy(@KeyLoading Stage window, @FxmlScene(FxmlFile.HUB_AUTH_FLOW) Lazy<Scene> authFlowScene, @FxmlScene(FxmlFile.HUB_NO_KEYCHAIN) Lazy<Scene> noKeychainScene, CompletableFuture<ReceivedKey> result, DeviceKey deviceKey, KeychainManager keychainManager, @Named("windowTitle") String windowTitle) {
public HubKeyLoadingStrategy(@KeyLoading Stage window, @FxmlScene(FxmlFile.HUB_CHECK_HOST_TRUST) Lazy<Scene> checkHostTrustScene, @FxmlScene(FxmlFile.HUB_NO_KEYCHAIN) Lazy<Scene> noKeychainScene, CompletableFuture<ReceivedKey> result, DeviceKey deviceKey, KeychainManager keychainManager, @Named("windowTitle") String windowTitle, @Named("filesystemOwnerId") AtomicReference<String> fsOwnerId) {
this.window = window;
this.keychainManager = keychainManager;
this.fsOwnerId = fsOwnerId;
window.setTitle(windowTitle);
window.setOnCloseRequest(_ -> result.cancel(true));
this.authFlowScene = authFlowScene;
this.checkHostTrustScene = checkHostTrustScene;
this.noKeychainScene = noKeychainScene;
this.result = result;
this.deviceKey = deviceKey;
@@ -58,7 +62,7 @@ public class HubKeyLoadingStrategy implements KeyLoadingStrategy {
throw new NoKeychainAccessProviderException();
}
var keypair = deviceKey.get();
showWindow(authFlowScene);
showWindow(checkHostTrustScene);
var jwe = result.get();
return jwe.decryptMasterkey(keypair.getPrivate());
} catch (NoKeychainAccessProviderException e) {
@@ -90,4 +94,13 @@ public class HubKeyLoadingStrategy implements KeyLoadingStrategy {
});
}
@Override
public String getOwner() {
var name = fsOwnerId.get();
if (name == null) {
throw new IllegalStateException("Owner is not yet determined");
}
return name;
}
}

View File

@@ -6,10 +6,12 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Preconditions;
import com.nimbusds.jose.JWEObject;
import dagger.Lazy;
import org.cryptomator.common.Constants;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.dialogs.Dialogs;
import org.cryptomator.ui.keyloading.KeyLoading;
import org.cryptomator.ui.keyloading.KeyLoadingScoped;
import org.slf4j.Logger;
@@ -41,7 +43,6 @@ import java.util.concurrent.atomic.AtomicReference;
public class ReceiveKeyController implements FxController {
private static final Logger LOG = LoggerFactory.getLogger(ReceiveKeyController.class);
private static final String SCHEME_PREFIX = "hub+";
private static final ObjectMapper JSON = new ObjectMapper().setDefaultLeniency(true);
private static final Duration REQ_TIMEOUT = Duration.ofSeconds(10);
@@ -50,6 +51,7 @@ public class ReceiveKeyController implements FxController {
private final String vaultId;
private final String deviceId;
private final String bearerToken;
private final AtomicReference<String> fsOwnerId;
private final CompletableFuture<ReceivedKey> result;
private final Lazy<Scene> registerDeviceScene;
private final Lazy<Scene> legacyRegisterDeviceScene;
@@ -57,14 +59,30 @@ public class ReceiveKeyController implements FxController {
private final Lazy<Scene> accountInitializationScene;
private final Lazy<Scene> invalidLicenseScene;
private final HttpClient httpClient;
private final Dialogs dialogs;
private final Vault vault;
@Inject
public ReceiveKeyController(@KeyLoading Vault vault, ExecutorService executor, @KeyLoading Stage window, HubConfig hubConfig, @Named("deviceId") String deviceId, @Named("bearerToken") AtomicReference<String> tokenRef, CompletableFuture<ReceivedKey> result, @FxmlScene(FxmlFile.HUB_REGISTER_DEVICE) Lazy<Scene> registerDeviceScene, @FxmlScene(FxmlFile.HUB_LEGACY_REGISTER_DEVICE) Lazy<Scene> legacyRegisterDeviceScene, @FxmlScene(FxmlFile.HUB_UNAUTHORIZED_DEVICE) Lazy<Scene> unauthorizedScene, @FxmlScene(FxmlFile.HUB_REQUIRE_ACCOUNT_INIT) Lazy<Scene> accountInitializationScene, @FxmlScene(FxmlFile.HUB_INVALID_LICENSE) Lazy<Scene> invalidLicenseScene) {
public ReceiveKeyController(@KeyLoading Vault vault, //
ExecutorService executor, //
@KeyLoading Stage window, //
HubConfig hubConfig, //
@Named("deviceId") String deviceId, //
@Named("bearerToken") AtomicReference<String> tokenRef, //
@Named("filesystemOwnerId") AtomicReference<String> fsOwnerId, //
CompletableFuture<ReceivedKey> result, //
@FxmlScene(FxmlFile.HUB_REGISTER_DEVICE) Lazy<Scene> registerDeviceScene, //
@FxmlScene(FxmlFile.HUB_LEGACY_REGISTER_DEVICE) Lazy<Scene> legacyRegisterDeviceScene, //
@FxmlScene(FxmlFile.HUB_UNAUTHORIZED_DEVICE) Lazy<Scene> unauthorizedScene, //
@FxmlScene(FxmlFile.HUB_REQUIRE_ACCOUNT_INIT) Lazy<Scene> accountInitializationScene, //
@FxmlScene(FxmlFile.HUB_INVALID_LICENSE) Lazy<Scene> invalidLicenseScene, //
Dialogs dialogs) {
this.window = window;
this.hubConfig = hubConfig;
this.vaultId = extractVaultId(vault.getVaultConfigCache().getUnchecked().getKeyId()); // TODO: access vault config's JTI directly (requires changes in cryptofs)
this.deviceId = deviceId;
this.bearerToken = Objects.requireNonNull(tokenRef.get());
this.fsOwnerId = fsOwnerId;
this.result = result;
this.registerDeviceScene = registerDeviceScene;
this.legacyRegisterDeviceScene = legacyRegisterDeviceScene;
@@ -73,6 +91,8 @@ public class ReceiveKeyController implements FxController {
this.invalidLicenseScene = invalidLicenseScene;
this.window.addEventHandler(WindowEvent.WINDOW_HIDING, this::windowClosed);
this.httpClient = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).executor(executor).build();
this.dialogs = dialogs;
this.vault = vault;
}
@FXML
@@ -81,7 +101,34 @@ public class ReceiveKeyController implements FxController {
}
public void receiveKey() {
requestApiConfig();
requestUserData();
}
private void requestUserData() {
var userUri = hubConfig.URIs.API.resolve("users/me?withDevices=false");
var request = HttpRequest.newBuilder(userUri) //
.header("Authorization", "Bearer " + bearerToken) //
.GET() //
.timeout(REQ_TIMEOUT) //
.build();
httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)) //
.thenAcceptAsync(this::receivedUserData) //
.exceptionally(this::retrievalFailed);
}
private void receivedUserData(HttpResponse<String> response) {
LOG.debug("GET {} -> Status Code {}", response.request().uri(), response.statusCode());
try {
if (response.statusCode() == 200) {
var user = JSON.reader().readValue(response.body(), UserDto.class);
fsOwnerId.set(user.name);
requestApiConfig();
} else {
throw new IllegalStateException("Unexpected response " + response.statusCode());
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
/**
@@ -144,6 +191,7 @@ public class ReceiveKeyController implements FxController {
switch (response.statusCode()) {
case 200 -> {
var device = JSON.reader().readValue(response.body(), DeviceDto.class);
fsOwnerId.accumulateAndGet(device.name, (s1, s2) -> s1 + Constants.HUB_USER_DEVICE_SEPARATOR + s2);
requestVaultMasterkey(device.userPrivateKey);
}
case 404 -> Platform.runLater(this::needsDeviceRegistration);
@@ -184,7 +232,8 @@ public class ReceiveKeyController implements FxController {
switch (response.statusCode()) {
case 200 -> receivedBothEncryptedKeys(response.body(), encryptedUserKey);
case 402 -> licenseExceeded();
case 403, 410 -> accessNotGranted(); // or vault has been archived, effectively disallowing access - TODO: add specific dialog?
case 403 -> accessNotGranted();
case 410 -> accessGoneVaultArchived();
case 449 -> accountInitializationRequired();
default -> throw new IllegalStateException("Unexpected response " + response.statusCode());
}
@@ -228,7 +277,8 @@ public class ReceiveKeyController implements FxController {
switch (response.statusCode()) {
case 200 -> receivedLegacyAccessTokenSuccess(response.body());
case 402 -> licenseExceeded();
case 403, 410 -> accessNotGranted(); // or vault has been archived, effectively disallowing access
case 403 -> accessNotGranted();
case 410 -> accessGoneVaultArchived();
case 404 -> needsLegacyDeviceRegistration();
default -> throw new IOException("Unexpected response " + response.statusCode());
}
@@ -261,6 +311,11 @@ public class ReceiveKeyController implements FxController {
window.setScene(unauthorizedScene.get());
}
private void accessGoneVaultArchived() {
window.close();
dialogs.prepareHubVaultArchived((Stage)window.getOwner(), vault).build().showAndWait();
}
private void accountInitializationRequired() {
window.setScene(accountInitializationScene.get());
}
@@ -289,13 +344,16 @@ public class ReceiveKeyController implements FxController {
}
private static String extractVaultId(URI vaultKeyUri) {
assert vaultKeyUri.getScheme().startsWith(SCHEME_PREFIX);
assert vaultKeyUri.getScheme().startsWith(HubKeyLoadingStrategy.SCHEME_PREFIX);
var path = vaultKeyUri.getPath();
return path.substring(path.lastIndexOf('/') + 1);
}
@JsonIgnoreProperties(ignoreUnknown = true)
private record DeviceDto(@JsonProperty(value = "userPrivateKey", required = true) String userPrivateKey) {}
private record UserDto(@JsonProperty(value = "name", required = true) String name) {}
@JsonIgnoreProperties(ignoreUnknown = true)
private record DeviceDto(@JsonProperty(value = "name", required = true) String name, @JsonProperty(value = "userPrivateKey", required = true) String userPrivateKey) {}
@JsonIgnoreProperties(ignoreUnknown = true)
private record ConfigDto(@JsonProperty(value = "apiLevel") int apiLevel) {}

View File

@@ -0,0 +1,34 @@
package org.cryptomator.ui.keyloading.hub;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.keyloading.KeyLoading;
import org.cryptomator.ui.keyloading.KeyLoadingScoped;
import javax.inject.Inject;
import javafx.fxml.FXML;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import java.util.concurrent.CompletableFuture;
@KeyLoadingScoped
public class UntrustedHostController implements FxController {
private final Stage window;
private final CompletableFuture<ReceivedKey> result;
@Inject
public UntrustedHostController(@KeyLoading Stage window, CompletableFuture<ReceivedKey> result) {
this.window = window;
this.result = result;
this.window.addEventHandler(WindowEvent.WINDOW_HIDING, this::windowClosed);
}
@FXML
public void close() {
window.close();
}
private void windowClosed(WindowEvent windowEvent) {
result.cancel(true);
}
}

View File

@@ -1,6 +1,7 @@
package org.cryptomator.ui.keyloading.masterkeyfile;
import com.google.common.base.Preconditions;
import org.cryptomator.common.Constants;
import org.cryptomator.common.Passphrase;
import org.cryptomator.common.keychain.KeychainManager;
import org.cryptomator.common.vaults.Vault;
@@ -63,16 +64,21 @@ public class MasterkeyFileLoadingStrategy implements KeyLoadingStrategy {
public Masterkey loadKey(URI keyId) throws MasterkeyLoadingFailedException {
window.setTitle(resourceBundle.getString("unlock.title").formatted(vault.getDisplayName()));
Preconditions.checkArgument(SCHEME.equalsIgnoreCase(keyId.getScheme()), "Only supports keys with scheme " + SCHEME);
if (!Constants.MASTERKEY_FILENAME.equals(keyId.getSchemeSpecificPart())) {
LOG.warn("unsupported masterkey path found in vault.cryptomator: {}", keyId.getSchemeSpecificPart());
}
try {
Path filePath = vault.getPath().resolve(keyId.getSchemeSpecificPart());
// determine masterkey file path:
Path filePath = vault.getPath().resolve(Constants.MASTERKEY_FILENAME);
if (!Files.exists(filePath)) {
filePath = askUserForMasterkeyFilePath();
}
// unlock:
if (passphrase == null) {
askForPassphrase();
}
var masterkey = masterkeyFileAccess.load(filePath, passphrase);
//backup
// backup on successful unlock:
if (filePath.startsWith(vault.getPath())) {
try {
BackupHelper.attemptBackup(filePath);

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