mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-09-21 23:44:42 +00:00
Compare commits
290
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2cd9c5a5d | ||
|
|
995ece19ae | ||
|
|
99182674ef | ||
|
|
94eb1e365b | ||
|
|
414ccad8fb | ||
|
|
e57e5358c4 | ||
|
|
e24719ed19 | ||
|
|
e21525ce2e | ||
|
|
9a14cfc674 | ||
|
|
9af9362a7b | ||
|
|
c05ff5d9ec | ||
|
|
7bc231023f | ||
|
|
4d4a93746d | ||
|
|
cb6b77318d | ||
|
|
3244b66c1c | ||
|
|
b72982edd8 | ||
|
|
a1db1272a9 | ||
|
|
feb9fb689e | ||
|
|
0178ca4080 | ||
|
|
79f2863f24 | ||
|
|
f1ef506e2b | ||
|
|
fbeeaa4c93 | ||
|
|
00f5d433da | ||
|
|
115a4216ee | ||
|
|
403d469dff | ||
|
|
ddf112bdfa | ||
|
|
2ade07da75 | ||
|
|
e6a0339878 | ||
|
|
2b0c2cf90a | ||
|
|
2afd8d0988 | ||
|
|
f2bda6b5f9 | ||
|
|
0bb1bf81ec | ||
|
|
bf8d5ed09f | ||
|
|
e9f6854df8 | ||
|
|
354225bf1e | ||
|
|
0d4f373311 | ||
|
|
1da535e89c | ||
|
|
941b4e3652 | ||
|
|
dd1af8cd78 | ||
|
|
27ea29ab9d | ||
|
|
a699a794a9 | ||
|
|
cd6b1cf129 | ||
|
|
7d2c4992af | ||
|
|
e67f235887 | ||
|
|
6a21d24687 | ||
|
|
cba6ed9875 | ||
|
|
72fdc8f536 | ||
|
|
41336cca13 | ||
|
|
322907bbcd | ||
|
|
1f8df6fead | ||
|
|
6e085b783d | ||
|
|
59dddd3f4c | ||
|
|
d6bbcfbbc1 | ||
|
|
7260d7f9f8 | ||
|
|
c39c4be1cd | ||
|
|
565ab4a09b | ||
|
|
f797491a17 | ||
|
|
cff83b6ac6 | ||
|
|
6f9b3e31e7 | ||
|
|
0a0dde3f47 | ||
|
|
e27e303c01 | ||
|
|
ef54b685f6 | ||
|
|
0370fd5848 | ||
|
|
119d18d699 | ||
|
|
8322633b14 | ||
|
|
2f32fc5c16 | ||
|
|
7c44c4f194 | ||
|
|
bbb663f9d2 | ||
|
|
fdb4a2fb5c | ||
|
|
0a4684133d | ||
|
|
0d5e518af3 | ||
|
|
d47ab43fcf | ||
|
|
19a711d12b | ||
|
|
bf2db55d00 | ||
|
|
885975e099 | ||
|
|
85c2901484 | ||
|
|
434030b139 | ||
|
|
e43bb37758 | ||
|
|
2eb9f0fca8 | ||
|
|
9503feb9c4 | ||
|
|
08e9f130e4 | ||
|
|
4e39eaa1f1 | ||
|
|
eaca95e8dc | ||
|
|
cf32e794c8 | ||
|
|
b5b221a5c7 | ||
|
|
d7cb99a12d | ||
|
|
b1893c63d4 | ||
|
|
79b3274074 | ||
|
|
7c86e5e39a | ||
|
|
b50cc703b6 | ||
|
|
9dc4a1dc5a | ||
|
|
f1a63a1679 | ||
|
|
d53d4e3452 | ||
|
|
b7fa1ae6d8 | ||
|
|
3f192a587c | ||
|
|
3a1b0b17d6 | ||
|
|
5d2a243c55 | ||
|
|
008a2a3301 | ||
|
|
0680437004 | ||
|
|
db6cf5459e | ||
|
|
1d8466a9e3 | ||
|
|
dcbcd692e7 | ||
|
|
87fd6c712a | ||
|
|
958505559f | ||
|
|
4736e5e7e7 | ||
|
|
55d217887a | ||
|
|
34ccd3ff73 | ||
|
|
989c349331 | ||
|
|
b9df56a6de | ||
|
|
38dbefff0b | ||
|
|
4cbe45919b | ||
|
|
b7ccf7986d | ||
|
|
40d632a489 | ||
|
|
800aca5207 | ||
|
|
6a26d95c15 | ||
|
|
439d3d7529 | ||
|
|
7476e192a3 | ||
|
|
c6193bc259 | ||
|
|
7446c69cd8 | ||
|
|
43c352e0d2 | ||
|
|
61ec3bc465 | ||
|
|
36dd98127d | ||
|
|
30862146b0 | ||
|
|
c19734da6f | ||
|
|
ba8fb273c7 | ||
|
|
5204a8e356 | ||
|
|
43b341860b | ||
|
|
ad02e43daf | ||
|
|
4942bcb52b | ||
|
|
6b2e718e04 | ||
|
|
a1323b5e81 | ||
|
|
ab4f487de1 | ||
|
|
d506e7472d | ||
|
|
2d33d02b46 | ||
|
|
06ddec4b70 | ||
|
|
24e31553fd | ||
|
|
eaa6b31de8 | ||
|
|
060ae588a2 | ||
|
|
262f84e8db | ||
|
|
6d55331ef2 | ||
|
|
42269a6057 | ||
|
|
181e45a596 | ||
|
|
3c8e506805 | ||
|
|
401b0afe9f | ||
|
|
42ec41b991 | ||
|
|
7ec3c5d04f | ||
|
|
f0a7379575 | ||
|
|
0d12b11c48 | ||
|
|
14a025f769 | ||
|
|
598fc9bbc8 | ||
|
|
fbab2df00f | ||
|
|
fb56b61a75 | ||
|
|
c5c3d55658 | ||
|
|
48c2d49c86 | ||
|
|
00d68393f6 | ||
|
|
7a50ba0b43 | ||
|
|
b2bee99286 | ||
|
|
88d384afdf | ||
|
|
7af82b831f | ||
|
|
a86f42fa44 | ||
|
|
70b0413777 | ||
|
|
577a77af38 | ||
|
|
3ba7e9ba00 | ||
|
|
b2250e8ce0 | ||
|
|
f2a480c7a0 | ||
|
|
bda38096e1 | ||
|
|
7e66a61294 | ||
|
|
3aa627a467 | ||
|
|
ae1b5fc925 | ||
|
|
b1076f9c86 | ||
|
|
ede1c72595 | ||
|
|
d2fcd5b64f | ||
|
|
6d9704ffa2 | ||
|
|
40df3d015a | ||
|
|
4e22706d92 | ||
|
|
341710f724 | ||
|
|
8386183f7a | ||
|
|
b76a7d6895 | ||
|
|
4a397a8151 | ||
|
|
2239a3e6a3 | ||
|
|
5318368879 | ||
|
|
41a279da9d | ||
|
|
478c69f82c | ||
|
|
eb0e630a44 | ||
|
|
0bcbf9a13a | ||
|
|
e3073a3613 | ||
|
|
3333dc7f22 | ||
|
|
12ec6fbec8 | ||
|
|
43fc976ad7 | ||
|
|
034278c0a0 | ||
|
|
92b3a9e1bd | ||
|
|
fc7169f2a0 | ||
|
|
c39710ede0 | ||
|
|
cc0b6aed15 | ||
|
|
f8a83c9cc8 | ||
|
|
43ce64f01e | ||
|
|
d585a03f76 | ||
|
|
f953be6237 | ||
|
|
e81bbe197b | ||
|
|
738fa4da12 | ||
|
|
9a08dcc46d | ||
|
|
74ef8d915d | ||
|
|
025a7a5582 | ||
|
|
3b2ddcf98d | ||
|
|
c10fc0ee5b | ||
|
|
aaa37e2c7a | ||
|
|
7af7c920e3 | ||
|
|
a4f79fb98a | ||
|
|
f429f2d3e7 | ||
|
|
4f6e091c13 | ||
|
|
2df779f7ab | ||
|
|
5b9d9150c5 | ||
|
|
f0aaec2058 | ||
|
|
4adc4a9175 | ||
|
|
5a97060fac | ||
|
|
db96074119 | ||
|
|
7ecc10bc79 | ||
|
|
44fe4a6f8a | ||
|
|
76a4ef50cb | ||
|
|
ca2f80024a | ||
|
|
dcd7077b08 | ||
|
|
31482d7d18 | ||
|
|
5ef666154e | ||
|
|
a810eff797 | ||
|
|
664158eb84 | ||
|
|
6b43881909 | ||
|
|
126004b1f8 | ||
|
|
ba34cfa9d5 | ||
|
|
03b4ad85ef | ||
|
|
1abfcd495f | ||
|
|
69964a80f1 | ||
|
|
aa8306ea4a | ||
|
|
3fecde37f4 | ||
|
|
2fc5fd99fb | ||
|
|
7edacfea70 | ||
|
|
7020fa49d9 | ||
|
|
7cea0bb33c | ||
|
|
3d622b18dc | ||
|
|
62cd506588 | ||
|
|
cd830f27a0 | ||
|
|
3f75018369 | ||
|
|
270a4c594d | ||
|
|
a5fdc5755b | ||
|
|
0a5a554714 | ||
|
|
976f22c27a | ||
|
|
8267574697 | ||
|
|
9077c964b3 | ||
|
|
f80467a3a4 | ||
|
|
8c462c4cb7 | ||
|
|
b25b5bd5a3 | ||
|
|
6365c22297 | ||
|
|
d7dd24b94e | ||
|
|
aee8844558 | ||
|
|
c536149c62 | ||
|
|
ca1ae8181b | ||
|
|
2b19c9757b | ||
|
|
d6871e3d82 | ||
|
|
0432a64537 | ||
|
|
06988b06c7 | ||
|
|
9b72eb8219 | ||
|
|
ea188f6176 | ||
|
|
cf67d022c8 | ||
|
|
7ba6e12799 | ||
|
|
b512518ccc | ||
|
|
93dfd35627 | ||
|
|
50b92f9510 | ||
|
|
7cca8922d8 | ||
|
|
c00889b1c4 | ||
|
|
b6224f355d | ||
|
|
9a8f96d432 | ||
|
|
3cc199227b | ||
|
|
3d0647bce3 | ||
|
|
192f35a9dd | ||
|
|
f2b4c9a35b | ||
|
|
3b8fec4c5a | ||
|
|
60b74a018d | ||
|
|
be69e04f51 | ||
|
|
194f6009df | ||
|
|
910a2eace8 | ||
|
|
3c95618eec | ||
|
|
fc709eb700 | ||
|
|
a6c60ac5d0 | ||
|
|
b88b9c8f92 | ||
|
|
2b8cd36b7b | ||
|
|
3d23deb744 | ||
|
|
641066ea07 | ||
|
|
9f035b7d37 | ||
|
|
92b512b719 | ||
|
|
1102f73680 | ||
|
|
cf9663fc26 |
@@ -16,6 +16,10 @@
|
|||||||
|
|
||||||
- Suggest your change by [submitting a new issue](https://github.com/cryptomator/cryptomator/issues/new/choose) and start writing code.
|
- Suggest your change by [submitting a new issue](https://github.com/cryptomator/cryptomator/issues/new/choose) and start writing code.
|
||||||
|
|
||||||
|
## Do you intend to add a new translation or change an existing one?
|
||||||
|
|
||||||
|
Translations are not managed directly in this repository. Instead, we use [Crowdin](https://translate.cryptomator.org/), which automatically synchronizes translations with this repository. If you want to help us with translations, please visit our translation project on Crowdin.
|
||||||
|
|
||||||
## Code of Conduct
|
## Code of Conduct
|
||||||
|
|
||||||
Help us keep Cryptomator open and inclusive. Please read and follow our [Code of Conduct](https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md).
|
Help us keep Cryptomator open and inclusive. Please read and follow our [Code of Conduct](https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md).
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
name: Bug Report
|
name: Bug Report
|
||||||
description: Create a report to help us improve
|
description: Create a report to help us improve
|
||||||
labels: ["type:bug"]
|
type: "Bug"
|
||||||
body:
|
body:
|
||||||
|
- type: input
|
||||||
|
id: summary
|
||||||
|
attributes:
|
||||||
|
label: Summary
|
||||||
|
placeholder: Please summarize your problem.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
- type: checkboxes
|
- type: checkboxes
|
||||||
id: terms
|
id: terms
|
||||||
attributes:
|
attributes:
|
||||||
@@ -11,13 +18,6 @@ body:
|
|||||||
required: true
|
required: true
|
||||||
- label: I agree to follow this project's [Code of Conduct](https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md)
|
- label: I agree to follow this project's [Code of Conduct](https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md)
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
|
||||||
id: summary
|
|
||||||
attributes:
|
|
||||||
label: Summary
|
|
||||||
placeholder: Please summarize your problem.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: software-versions
|
id: software-versions
|
||||||
attributes:
|
attributes:
|
||||||
@@ -97,4 +97,4 @@ body:
|
|||||||
id: further-info
|
id: further-info
|
||||||
attributes:
|
attributes:
|
||||||
label: Anything else?
|
label: Anything else?
|
||||||
description: Links? References? Screenshots? Configurations? Any data that might be necessary to reproduce the issue?
|
description: Links? References? Screenshots? Configurations? Any data that might be necessary to reproduce the issue?
|
||||||
@@ -1,7 +1,14 @@
|
|||||||
name: Feature Request
|
name: Feature Request
|
||||||
description: Suggest an idea for this project
|
description: Suggest an idea for this project
|
||||||
labels: ["type:feature-request"]
|
type: "Feature"
|
||||||
body:
|
body:
|
||||||
|
- type: input
|
||||||
|
id: summary
|
||||||
|
attributes:
|
||||||
|
label: Summary
|
||||||
|
placeholder: Please summarize your feature request.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
- type: checkboxes
|
- type: checkboxes
|
||||||
id: terms
|
id: terms
|
||||||
attributes:
|
attributes:
|
||||||
@@ -11,13 +18,6 @@ body:
|
|||||||
required: true
|
required: true
|
||||||
- label: I agree to follow this project's [Code of Conduct](https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md)
|
- label: I agree to follow this project's [Code of Conduct](https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md)
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
|
||||||
id: summary
|
|
||||||
attributes:
|
|
||||||
label: Summary
|
|
||||||
placeholder: Please summarize your feature request.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: motivation
|
id: motivation
|
||||||
attributes:
|
attributes:
|
||||||
|
|||||||
@@ -53,6 +53,4 @@ updates:
|
|||||||
groups:
|
groups:
|
||||||
github-actions:
|
github-actions:
|
||||||
patterns:
|
patterns:
|
||||||
- "*"
|
- "*"
|
||||||
labels:
|
|
||||||
- "misc:ci"
|
|
||||||
+101
-19
@@ -8,16 +8,24 @@ on:
|
|||||||
version:
|
version:
|
||||||
description: 'Version'
|
description: 'Version'
|
||||||
required: false
|
required: false
|
||||||
|
push:
|
||||||
|
branches-ignore:
|
||||||
|
- 'dependabot/**'
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/appimage.yml'
|
||||||
|
- 'dist/linux/appimage/**'
|
||||||
|
- 'dist/linux/common/**'
|
||||||
|
- 'dist/linux/resources/**'
|
||||||
|
|
||||||
env:
|
env:
|
||||||
JAVA_DIST: 'zulu'
|
JAVA_DIST: 'temurin'
|
||||||
JAVA_VERSION: '23.0.1+11'
|
JAVA_VERSION: '24.0.1+9'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
get-version:
|
get-version:
|
||||||
uses: ./.github/workflows/get-version.yml
|
uses: ./.github/workflows/get-version.yml
|
||||||
with:
|
with:
|
||||||
version: ${{ inputs.version }}
|
version: ${{ inputs.version }} #okay if not defined
|
||||||
|
|
||||||
build:
|
build:
|
||||||
name: Build AppImage
|
name: Build AppImage
|
||||||
@@ -29,12 +37,12 @@ jobs:
|
|||||||
include:
|
include:
|
||||||
- os: ubuntu-latest
|
- os: ubuntu-latest
|
||||||
appimage-suffix: x86_64
|
appimage-suffix: x86_64
|
||||||
openjfx-url: 'https://download2.gluonhq.com/openjfx/22.0.2/openjfx-22.0.2_linux-x64_bin-jmods.zip'
|
openjfx-url: 'https://download2.gluonhq.com/openjfx/24.0.1/openjfx-24.0.1_linux-x64_bin-jmods.zip'
|
||||||
openjfx-sha: 'd44bff3b94d5668fdee18a938d7b1269026d663d44765f02d29a9bdfd3fa1eb0'
|
openjfx-sha: '425fac742b9fbd095b2ce868cff82d1024620f747c94a7144d0a4879e756146c'
|
||||||
- os: [self-hosted, Linux, ARM64]
|
- os: ubuntu-24.04-arm
|
||||||
appimage-suffix: aarch64
|
appimage-suffix: aarch64
|
||||||
openjfx-url: 'https://download2.gluonhq.com/openjfx/22.0.2/openjfx-22.0.2_linux-aarch64_bin-jmods.zip'
|
openjfx-url: 'https://download2.gluonhq.com/openjfx/24.0.1/openjfx-24.0.1_linux-aarch64_bin-jmods.zip'
|
||||||
openjfx-sha: '3d5457136690c4f5bb9522d38b45218e045bdac13c24aa4c808c7c8d17d039c7'
|
openjfx-sha: '7e02edd0f4ee5527a27c94b0bbba66fcaaff41009119e45d0eca0f96ddfb6e7b'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Setup Java
|
- name: Setup Java
|
||||||
@@ -44,7 +52,6 @@ jobs:
|
|||||||
java-version: ${{ env.JAVA_VERSION }}
|
java-version: ${{ env.JAVA_VERSION }}
|
||||||
check-latest: true
|
check-latest: true
|
||||||
cache: 'maven'
|
cache: 'maven'
|
||||||
|
|
||||||
- name: Download OpenJFX jmods
|
- name: Download OpenJFX jmods
|
||||||
id: download-jmods
|
id: download-jmods
|
||||||
run: |
|
run: |
|
||||||
@@ -61,7 +68,7 @@ jobs:
|
|||||||
POM_JFX_VERSION=${POM_JFX_VERSION#*@}
|
POM_JFX_VERSION=${POM_JFX_VERSION#*@}
|
||||||
POM_JFX_VERSION=${POM_JFX_VERSION%%.*}
|
POM_JFX_VERSION=${POM_JFX_VERSION%%.*}
|
||||||
|
|
||||||
if [ $POM_JFX_VERSION -ne $JMOD_VERSION_AMD64 ]; then
|
if [ $POM_JFX_VERSION -ne $JMOD_VERSION ]; then
|
||||||
>&2 echo "Major JavaFX version in pom.xml (${POM_JFX_VERSION}) != amd64 jmod version (${JMOD_VERSION})"
|
>&2 echo "Major JavaFX version in pom.xml (${POM_JFX_VERSION}) != amd64 jmod version (${JMOD_VERSION})"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@@ -73,13 +80,21 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cp LICENSE.txt target
|
cp LICENSE.txt target
|
||||||
cp target/cryptomator-*.jar target/mods
|
cp target/cryptomator-*.jar target/mods
|
||||||
|
- name: Run jlink with help option
|
||||||
|
id: jep-493-check
|
||||||
|
run: |
|
||||||
|
JMOD_PATHS="openjfx-jmods"
|
||||||
|
if ! ${JAVA_HOME}/bin/jlink --help | grep -q "Linking from run-time image enabled"; then
|
||||||
|
JMOD_PATHS="${JAVA_HOME}/jmods:${JMOD_PATHS}"
|
||||||
|
fi
|
||||||
|
echo "jmod_paths=${JMOD_PATHS}" >> "$GITHUB_OUTPUT"
|
||||||
- name: Run jlink
|
- name: Run jlink
|
||||||
#Remark: no compression is applied for improved build compression later (here appimage)
|
#Remark: no compression is applied for improved build compression later (here appimage)
|
||||||
run: >
|
run: >
|
||||||
${JAVA_HOME}/bin/jlink
|
${JAVA_HOME}/bin/jlink
|
||||||
--verbose
|
--verbose
|
||||||
--output runtime
|
--output runtime
|
||||||
--module-path "${JAVA_HOME}/jmods:openjfx-jmods"
|
--module-path "${{ steps.jep-493-check.outputs.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.unsupported,jdk.security.auth,jdk.accessibility,jdk.management.jfr,jdk.net,java.compiler
|
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.security.auth,jdk.accessibility,jdk.management.jfr,jdk.net,java.compiler
|
||||||
--strip-native-commands
|
--strip-native-commands
|
||||||
--no-header-files
|
--no-header-files
|
||||||
@@ -98,10 +113,11 @@ jobs:
|
|||||||
--dest appdir
|
--dest appdir
|
||||||
--name Cryptomator
|
--name Cryptomator
|
||||||
--vendor "Skymatic GmbH"
|
--vendor "Skymatic GmbH"
|
||||||
--copyright "(C) 2016 - 2024 Skymatic GmbH"
|
--copyright "(C) 2016 - 2025 Skymatic GmbH"
|
||||||
--app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}"
|
--app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}"
|
||||||
--java-options "--enable-preview"
|
--java-options "--enable-preview"
|
||||||
--java-options "--enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator"
|
--java-options "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator"
|
||||||
|
--java-options "--sun-misc-unsafe-memory-access=allow"
|
||||||
--java-options "-Xss5m"
|
--java-options "-Xss5m"
|
||||||
--java-options "-Xmx256m"
|
--java-options "-Xmx256m"
|
||||||
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
|
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
|
||||||
@@ -116,6 +132,7 @@ jobs:
|
|||||||
--java-options "-Dcryptomator.showTrayIcon=true"
|
--java-options "-Dcryptomator.showTrayIcon=true"
|
||||||
--java-options "-Dcryptomator.integrationsLinux.trayIconsDir=\"@{appdir}/usr/share/icons/hicolor/symbolic/apps\""
|
--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-${{ needs.get-version.outputs.revNum }}\""
|
||||||
|
--java-options "-Dcryptomator.networking.truststore.p12Path=\"/etc/cryptomator/certs.p12\""
|
||||||
--resource-dir dist/linux/resources
|
--resource-dir dist/linux/resources
|
||||||
- name: Patch Cryptomator.AppDir
|
- name: Patch Cryptomator.AppDir
|
||||||
run: |
|
run: |
|
||||||
@@ -132,13 +149,13 @@ jobs:
|
|||||||
cp dist/linux/common/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/usr/share/applications/org.cryptomator.Cryptomator.desktop
|
cp dist/linux/common/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/usr/share/applications/org.cryptomator.Cryptomator.desktop
|
||||||
cp dist/linux/common/application-vnd.cryptomator.vault.xml Cryptomator.AppDir/usr/share/mime/packages/application-vnd.cryptomator.vault.xml
|
cp dist/linux/common/application-vnd.cryptomator.vault.xml Cryptomator.AppDir/usr/share/mime/packages/application-vnd.cryptomator.vault.xml
|
||||||
ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/org.cryptomator.Cryptomator.svg
|
ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/org.cryptomator.Cryptomator.svg
|
||||||
ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/Cryptomator.svg
|
|
||||||
ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/.DirIcon
|
ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/.DirIcon
|
||||||
ln -s usr/share/applications/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/Cryptomator.desktop
|
ln -s usr/share/applications/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/org.cryptomator.Cryptomator.desktop
|
||||||
|
ln -s org.cryptomator.Cryptomator.metainfo.xml Cryptomator.AppDir/usr/share/metainfo/org.cryptomator.Cryptomator.appdata.xml
|
||||||
ln -s bin/cryptomator.sh Cryptomator.AppDir/AppRun
|
ln -s bin/cryptomator.sh Cryptomator.AppDir/AppRun
|
||||||
- name: Download AppImageKit
|
- name: Download AppImageKit
|
||||||
run: |
|
run: |
|
||||||
curl -L https://github.com/AppImage/AppImageKit/releases/download/13/appimagetool-${{ matrix.appimage-suffix }}.AppImage -o appimagetool.AppImage
|
curl -L https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-${{ matrix.appimage-suffix }}.AppImage -o appimagetool.AppImage
|
||||||
chmod +x appimagetool.AppImage
|
chmod +x appimagetool.AppImage
|
||||||
./appimagetool.AppImage --appimage-extract
|
./appimagetool.AppImage --appimage-extract
|
||||||
- name: Prepare GPG-Agent for signing with key 615D449FE6E6A235
|
- name: Prepare GPG-Agent for signing with key 615D449FE6E6A235
|
||||||
@@ -151,8 +168,8 @@ jobs:
|
|||||||
- name: Build AppImage
|
- name: Build AppImage
|
||||||
run: >
|
run: >
|
||||||
./squashfs-root/AppRun Cryptomator.AppDir cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.appimage-suffix }}.AppImage
|
./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'
|
-u "gh-releases-zsync|cryptomator|cryptomator|latest|cryptomator-*-${{ matrix.appimage-suffix }}.AppImage.zsync"
|
||||||
--sign --sign-key=615D449FE6E6A235 --sign-args="--batch --pinentry-mode loopback"
|
--sign --sign-key=615D449FE6E6A235
|
||||||
- name: Create detached GPG signatures
|
- name: Create detached GPG signatures
|
||||||
run: |
|
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
|
||||||
@@ -175,4 +192,69 @@ jobs:
|
|||||||
files: |
|
files: |
|
||||||
cryptomator-*.AppImage
|
cryptomator-*.AppImage
|
||||||
cryptomator-*.zsync
|
cryptomator-*.zsync
|
||||||
cryptomator-*.asc
|
cryptomator-*.asc
|
||||||
|
|
||||||
|
create-aur-bin-pr:
|
||||||
|
name: Create PR for aur-bin repo
|
||||||
|
needs: [build, get-version]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event_name == 'release'
|
||||||
|
steps:
|
||||||
|
- name: Download AppImages
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: downloads/
|
||||||
|
merge-multiple: true
|
||||||
|
- name: Compute sha256 hash of AppImages
|
||||||
|
id: checksums
|
||||||
|
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@v4
|
||||||
|
with:
|
||||||
|
repository: 'cryptomator/aur-bin'
|
||||||
|
token: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get -y 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_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
|
||||||
|
- 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
|
||||||
|
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"
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
|
||||||
|
- name: Slack Notification
|
||||||
|
uses: rtCamp/action-slack-notify@v2
|
||||||
|
env:
|
||||||
|
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||||
|
SLACK_USERNAME: 'Cryptobot'
|
||||||
|
SLACK_ICON: false
|
||||||
|
SLACK_ICON_EMOJI: ':bot:'
|
||||||
|
SLACK_CHANNEL: 'cryptomator-desktop'
|
||||||
|
SLACK_TITLE: "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_FOOTER: false
|
||||||
|
MSG_MINIMAL: true
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
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'
|
||||||
|
outputs:
|
||||||
|
url: ${{ steps.url.outputs.url}}
|
||||||
|
sha256: ${{ steps.sha256.outputs.sha256}}
|
||||||
|
steps:
|
||||||
|
- name: Determine tarball url
|
||||||
|
id: url
|
||||||
|
run: |
|
||||||
|
URL="";
|
||||||
|
if [[ -n "${{ inputs.tag }}" ]]; then
|
||||||
|
URL="https://github.com/cryptomator/cryptomator/archive/refs/tags/${{ inputs.tag }}.tar.gz"
|
||||||
|
else
|
||||||
|
URL="https://github.com/cryptomator/cryptomator/archive/refs/tags/${{ github.event.release.tag_name }}.tar.gz"
|
||||||
|
fi
|
||||||
|
echo "url=${URL}" >> "$GITHUB_OUTPUT"
|
||||||
|
- name: Download source tarball and compute checksum
|
||||||
|
id: 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@v4
|
||||||
|
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
|
||||||
|
uses: rtCamp/action-slack-notify@v2
|
||||||
|
if: github.event_name == 'release'
|
||||||
|
env:
|
||||||
|
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||||
|
SLACK_USERNAME: 'Cryptobot'
|
||||||
|
SLACK_ICON: false
|
||||||
|
SLACK_ICON_EMOJI: ':bot:'
|
||||||
|
SLACK_CHANNEL: 'cryptomator-desktop'
|
||||||
|
SLACK_TITLE: "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
|
||||||
@@ -13,15 +13,48 @@ on:
|
|||||||
description: "Url to the file to upload"
|
description: "Url to the file to upload"
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
avast:
|
||||||
|
description: "Upload to Avast"
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
kaspersky:
|
||||||
|
description: "Upload to Kaspersky"
|
||||||
|
required: false
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
allowlist:
|
download-file:
|
||||||
name: Anti Virus Allowlisting
|
name: Downloads the file into the VM
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
fileName: ${{ steps.extractName.outputs.fileName}}
|
||||||
steps:
|
steps:
|
||||||
- name: Download file
|
- name: Extract file name
|
||||||
|
id: extractName
|
||||||
run: |
|
run: |
|
||||||
curl --remote-name ${{ inputs.url }} -L
|
url="${{ inputs.url }}"
|
||||||
|
echo "fileName=${url##*/}" >> $GITHUB_OUTPUT
|
||||||
|
- name: Download file
|
||||||
|
run: curl --remote-name ${{ inputs.url }} -L -o ${{steps.extractName.outputs.fileName}}
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ steps.extractName.outputs.fileName }}
|
||||||
|
path: ${{ steps.extractName.outputs.fileName }}
|
||||||
|
if-no-files-found: error
|
||||||
|
allowlist-kaspersky:
|
||||||
|
name: Anti Virus Allowlisting Kaspersky
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: download-file
|
||||||
|
if: github.event_name == 'workflow_call' || inputs.kaspersky
|
||||||
|
steps:
|
||||||
|
- name: Download artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ needs.download-file.outputs.fileName }}
|
||||||
|
path: upload
|
||||||
- name: Upload to Kaspersky
|
- name: Upload to Kaspersky
|
||||||
uses: SamKirkland/FTP-Deploy-Action@v4.3.5
|
uses: SamKirkland/FTP-Deploy-Action@v4.3.5
|
||||||
with:
|
with:
|
||||||
@@ -30,11 +63,26 @@ jobs:
|
|||||||
port: 990
|
port: 990
|
||||||
username: ${{ secrets.ALLOWLIST_KASPERSKY_USERNAME }}
|
username: ${{ secrets.ALLOWLIST_KASPERSKY_USERNAME }}
|
||||||
password: ${{ secrets.ALLOWLIST_KASPERSKY_PASSWORD }}
|
password: ${{ secrets.ALLOWLIST_KASPERSKY_PASSWORD }}
|
||||||
- name: Upload to Avast
|
local-dir: ./upload/
|
||||||
uses: SamKirkland/FTP-Deploy-Action@v4.3.5
|
allowlist-avast:
|
||||||
|
name: Anti Virus Allowlisting Avast
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: download-file
|
||||||
|
if: github.event_name == 'workflow_call' || inputs.avast
|
||||||
|
steps:
|
||||||
|
- name: Download artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ${{ needs.download-file.outputs.fileName }}
|
||||||
|
path: upload
|
||||||
|
- name: Upload to Avast
|
||||||
|
uses: wlixcc/SFTP-Deploy-Action@v1.2.6
|
||||||
with:
|
with:
|
||||||
protocol: ftp
|
|
||||||
server: whitelisting.avast.com
|
server: whitelisting.avast.com
|
||||||
port: 21
|
port: 22
|
||||||
username: ${{ secrets.ALLOWLIST_AVAST_USERNAME }}
|
username: ${{ secrets.ALLOWLIST_AVAST_USERNAME }}
|
||||||
password: ${{ secrets.ALLOWLIST_AVAST_PASSWORD }}
|
password: ${{ secrets.ALLOWLIST_AVAST_PASSWORD }}
|
||||||
|
ssh_private_key: ''
|
||||||
|
sftp_only: true
|
||||||
|
local_path: './upload/*'
|
||||||
|
remote_path: '/data'
|
||||||
@@ -2,12 +2,16 @@ name: Build
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/build.yml'
|
||||||
|
- 'pom.xml'
|
||||||
|
- 'src/**'
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
types: [labeled]
|
types: [labeled]
|
||||||
|
|
||||||
env:
|
env:
|
||||||
JAVA_DIST: 'zulu'
|
JAVA_DIST: 'temurin'
|
||||||
JAVA_VERSION: 23
|
JAVA_VERSION: 24
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
JDK_VERSION: '23.0.1+11'
|
JDK_VERSION: '24.0.1+9'
|
||||||
JDK_VENDOR: zulu
|
JDK_VENDOR: temurin
|
||||||
RUNTIME_VERSION_HELPER: >
|
RUNTIME_VERSION_HELPER: >
|
||||||
public class Test {
|
public class Test {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|||||||
@@ -5,41 +5,52 @@ on:
|
|||||||
inputs:
|
inputs:
|
||||||
semver:
|
semver:
|
||||||
description: 'SemVer String (e.g. 1.7.0-beta1)'
|
description: 'SemVer String (e.g. 1.7.0-beta1)'
|
||||||
required: true
|
|
||||||
ppaver:
|
ppaver:
|
||||||
description: 'Base PPA Version String (e.g. 1.6.16+1.7.0~beta1) without -0ppa1'
|
description: 'Base PPA Version String (e.g. 1.6.16+1.7.0~beta1) without -0ppa1'
|
||||||
required: true
|
|
||||||
dput:
|
dput:
|
||||||
description: 'Upload to PPA'
|
description: 'Upload to PPA'
|
||||||
required: true
|
required: true
|
||||||
default: false
|
default: false
|
||||||
type: boolean
|
type: boolean
|
||||||
|
push:
|
||||||
|
branches-ignore:
|
||||||
|
- 'dependabot/**'
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/debian.yml'
|
||||||
|
- 'dist/linux/debian/**'
|
||||||
|
- 'dist/linux/common/**'
|
||||||
|
- 'dist/linux/resources/**'
|
||||||
|
|
||||||
env:
|
env:
|
||||||
JAVA_DIST: 'zulu'
|
JAVA_DIST: 'temurin'
|
||||||
JAVA_VERSION: '23.0.1+11'
|
JAVA_VERSION: '24.0.1+9'
|
||||||
COFFEELIBS_JDK: 23
|
COFFEELIBS_JDK: 24
|
||||||
COFFEELIBS_JDK_VERSION: '23.0.1+11-0ppa1'
|
COFFEELIBS_JDK_VERSION: '24.0.1+9-0ppa3'
|
||||||
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/22.0.2/openjfx-22.0.2_linux-x64_bin-jmods.zip'
|
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/24.0.1/openjfx-24.0.1_linux-x64_bin-jmods.zip'
|
||||||
OPENJFX_JMODS_AMD64_HASH: 'd44bff3b94d5668fdee18a938d7b1269026d663d44765f02d29a9bdfd3fa1eb0'
|
OPENJFX_JMODS_AMD64_HASH: '425fac742b9fbd095b2ce868cff82d1024620f747c94a7144d0a4879e756146c'
|
||||||
OPENJFX_JMODS_AARCH64: 'https://download2.gluonhq.com/openjfx/22.0.2/openjfx-22.0.2_linux-aarch64_bin-jmods.zip'
|
OPENJFX_JMODS_AARCH64: 'https://download2.gluonhq.com/openjfx/24.0.1/openjfx-24.0.1_linux-aarch64_bin-jmods.zip'
|
||||||
OPENJFX_JMODS_AARCH64_HASH: '3d5457136690c4f5bb9522d38b45218e045bdac13c24aa4c808c7c8d17d039c7'
|
OPENJFX_JMODS_AARCH64_HASH: '7e02edd0f4ee5527a27c94b0bbba66fcaaff41009119e45d0eca0f96ddfb6e7b'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
get-version:
|
||||||
|
uses: ./.github/workflows/get-version.yml
|
||||||
|
with:
|
||||||
|
version: ${{ inputs.semver }} #okay if not defined
|
||||||
|
|
||||||
build:
|
build:
|
||||||
name: Build Debian Package
|
name: Build Debian Package
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
|
needs: [get-version]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- id: versions
|
- id: deb-version
|
||||||
name: Get version information
|
name: Determine deb-version
|
||||||
run: |
|
run: |
|
||||||
SEM_VER_STR="${{ inputs.semver }}"
|
if [ -n "${{inputs.ppaver}}" ]; then
|
||||||
SEM_VER_NUM=`echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/'`
|
echo "debVersion=${{inputs.ppaver }}" >> "$GITHUB_OUTPUT"
|
||||||
REVCOUNT=`git rev-list --count HEAD`
|
else
|
||||||
echo "semVerStr=${SEM_VER_STR}" >> $GITHUB_OUTPUT
|
echo "debVersion=${{needs.get-version.outputs.semVerStr}}" >> "$GITHUB_OUTPUT"
|
||||||
echo "semVerNum=${SEM_VER_NUM}" >> $GITHUB_OUTPUT
|
fi
|
||||||
echo "revNum=${REVCOUNT}" >> $GITHUB_OUTPUT
|
|
||||||
- name: Install build tools
|
- name: Install build tools
|
||||||
run: |
|
run: |
|
||||||
sudo add-apt-repository ppa:coffeelibs/openjdk
|
sudo add-apt-repository ppa:coffeelibs/openjdk
|
||||||
@@ -94,7 +105,7 @@ jobs:
|
|||||||
cp -r jmods pkgdir
|
cp -r jmods pkgdir
|
||||||
cp -r dist/linux/common/ pkgdir
|
cp -r dist/linux/common/ pkgdir
|
||||||
cp target/cryptomator-*.jar pkgdir/mods
|
cp target/cryptomator-*.jar pkgdir/mods
|
||||||
tar -cJf cryptomator_${{ inputs.ppaver }}.orig.tar.xz -C pkgdir .
|
tar -cJf cryptomator_${{ steps.deb-version.outputs.debVersion }}.orig.tar.xz -C pkgdir .
|
||||||
- name: Patch and rename pkgdir
|
- name: Patch and rename pkgdir
|
||||||
run: |
|
run: |
|
||||||
cp -r dist/linux/debian/ pkgdir
|
cp -r dist/linux/debian/ pkgdir
|
||||||
@@ -103,12 +114,12 @@ jobs:
|
|||||||
envsubst '${SEMVER_STR} ${VERSION_NUM} ${REVISION_NUM} ${DISABLE_UPDATE_CHECK}' < dist/linux/debian/rules > pkgdir/debian/rules
|
envsubst '${SEMVER_STR} ${VERSION_NUM} ${REVISION_NUM} ${DISABLE_UPDATE_CHECK}' < dist/linux/debian/rules > pkgdir/debian/rules
|
||||||
envsubst '${PPA_VERSION} ${RFC2822_TIMESTAMP}' < dist/linux/debian/changelog > pkgdir/debian/changelog
|
envsubst '${PPA_VERSION} ${RFC2822_TIMESTAMP}' < dist/linux/debian/changelog > pkgdir/debian/changelog
|
||||||
find . -name "*.jar" >> pkgdir/debian/source/include-binaries
|
find . -name "*.jar" >> pkgdir/debian/source/include-binaries
|
||||||
mv pkgdir cryptomator_${{ inputs.ppaver }}
|
mv pkgdir cryptomator_${{ steps.deb-version.outputs.debVersion }}
|
||||||
env:
|
env:
|
||||||
SEMVER_STR: ${{ steps.versions.outputs.semVerStr }}
|
SEMVER_STR: ${{ needs.get-version.outputs.semVerStr }}
|
||||||
VERSION_NUM: ${{ steps.versions.outputs.semVerNum }}
|
VERSION_NUM: ${{ needs.get-version.outputs.semVerNum }}
|
||||||
REVISION_NUM: ${{ steps.versions.outputs.revNum }}
|
REVISION_NUM: ${{ needs.get-version.outputs.revNum }}
|
||||||
PPA_VERSION: ${{ inputs.ppaver }}-0ppa1
|
PPA_VERSION: ${{ steps.deb-version.outputs.debVersion }}-0ppa1
|
||||||
- name: Prepare GPG-Agent for signing with key 615D449FE6E6A235
|
- name: Prepare GPG-Agent for signing with key 615D449FE6E6A235
|
||||||
run: |
|
run: |
|
||||||
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
|
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
|
||||||
@@ -118,12 +129,13 @@ jobs:
|
|||||||
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
|
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
|
||||||
- name: debuild
|
- name: debuild
|
||||||
run: |
|
run: |
|
||||||
|
(sleep 8m; gpg --batch --quiet --pinentry-mode loopback -u 615D449FE6E6A235 --dry-run --sign README.md) &
|
||||||
debuild -S -sa -d
|
debuild -S -sa -d
|
||||||
debuild -b -sa -d
|
debuild -b -sa -d
|
||||||
env:
|
env:
|
||||||
DEBSIGN_PROGRAM: gpg --batch --pinentry-mode loopback
|
DEBSIGN_PROGRAM: gpg --batch --pinentry-mode loopback
|
||||||
DEBSIGN_KEYID: 615D449FE6E6A235
|
DEBSIGN_KEYID: 615D449FE6E6A235
|
||||||
working-directory: cryptomator_${{ inputs.ppaver }}
|
working-directory: cryptomator_${{ steps.deb-version.outputs.debVersion }}
|
||||||
- name: Create detached GPG signatures
|
- name: Create detached GPG signatures
|
||||||
run: |
|
run: |
|
||||||
gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator_*_amd64.deb
|
gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator_*_amd64.deb
|
||||||
@@ -140,7 +152,7 @@ jobs:
|
|||||||
cryptomator_*_amd64.deb
|
cryptomator_*_amd64.deb
|
||||||
cryptomator_*.asc
|
cryptomator_*.asc
|
||||||
- name: Publish on PPA
|
- name: Publish on PPA
|
||||||
if: inputs.dput
|
if: inputs.dput && inputs.ppaver != ''
|
||||||
run: dput ppa:sebastian-stenzel/cryptomator-beta cryptomator_*_source.changes
|
run: dput ppa:sebastian-stenzel/cryptomator-beta cryptomator_*_source.changes
|
||||||
# If ref is a tag, also upload to GitHub Releases:
|
# If ref is a tag, also upload to GitHub Releases:
|
||||||
- name: Publish Debian package on GitHub Releases
|
- name: Publish Debian package on GitHub Releases
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
runner-os: 'ubuntu-latest'
|
runner-os: 'ubuntu-latest'
|
||||||
java-distribution: 'temurin'
|
java-distribution: 'temurin'
|
||||||
java-version: 23
|
java-version: 24
|
||||||
check-command: 'mvn -B validate -Pdependency-check -Djavafx.platform=linux'
|
check-command: 'mvn -B validate -Pdependency-check -Djavafx.platform=linux'
|
||||||
secrets:
|
secrets:
|
||||||
nvd-api-key: ${{ secrets.NVD_API_KEY }}
|
nvd-api-key: ${{ secrets.NVD_API_KEY }}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: 'flathub/org.cryptomator.Cryptomator'
|
repository: 'flathub/org.cryptomator.Cryptomator'
|
||||||
token: ${{ secrets.CRYPTOBOT_WINGET_TOKEN }}
|
token: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
|
||||||
- name: Checkout release branch
|
- name: Checkout release branch
|
||||||
run: |
|
run: |
|
||||||
git checkout -b release/${{ needs.get-version.outputs.semVerStr }}
|
git checkout -b release/${{ needs.get-version.outputs.semVerStr }}
|
||||||
@@ -72,7 +72,7 @@ jobs:
|
|||||||
PR_URL=$(gh pr create --title "Release ${{ needs.get-version.outputs.semVerStr }}" --body-file pr_body.md)
|
PR_URL=$(gh pr create --title "Release ${{ needs.get-version.outputs.semVerStr }}" --body-file pr_body.md)
|
||||||
echo "FLATHUB_PR_URL=$PR_URL" >> "$GITHUB_ENV"
|
echo "FLATHUB_PR_URL=$PR_URL" >> "$GITHUB_ENV"
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.CRYPTOBOT_WINGET_TOKEN }}
|
GH_TOKEN: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
|
||||||
- name: Slack Notification
|
- name: Slack Notification
|
||||||
uses: rtCamp/action-slack-notify@v2
|
uses: rtCamp/action-slack-notify@v2
|
||||||
if: github.event_name == 'release'
|
if: github.event_name == 'release'
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ on:
|
|||||||
value: ${{ jobs.determine-version.outputs.type }}
|
value: ${{ jobs.determine-version.outputs.type }}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
JAVA_DIST: 'zulu'
|
JAVA_DIST: 'temurin'
|
||||||
JAVA_VERSION: 23
|
JAVA_VERSION: 24
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
determine-version:
|
determine-version:
|
||||||
|
|||||||
@@ -2,20 +2,29 @@ name: Build macOS .dmg for x64
|
|||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# STOP! DO NOT EDIT THIS FILE!
|
# STOP! DO NOT EDIT THIS FILE!
|
||||||
#
|
#
|
||||||
# It is a copy of mac-dmg.yml with tiny adjustements (mainly lines 42 to 47)
|
# It is a copy of mac-dmg.yml with tiny adjustements (mainly lines 42 to 47)
|
||||||
# It was made necessary, since Github does not offer free macos intel runners for macos 15 and above.
|
# It was made necessary, since Github does not offer free macos intel runners for macos 15 and above.
|
||||||
# This workflow can only be triggered by a release.
|
#
|
||||||
#
|
|
||||||
#######################################
|
#######################################
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
types: [published]
|
types: [published]
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
description: 'Version'
|
||||||
|
required: false
|
||||||
|
notarize:
|
||||||
|
description: 'Notarize'
|
||||||
|
required: true
|
||||||
|
default: false
|
||||||
|
type: boolean
|
||||||
|
|
||||||
env:
|
env:
|
||||||
JAVA_DIST: 'zulu'
|
JAVA_DIST: 'temurin'
|
||||||
JAVA_VERSION: '23.0.1+11'
|
JAVA_VERSION: '24.0.1+9'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
get-version:
|
get-version:
|
||||||
@@ -35,8 +44,8 @@ jobs:
|
|||||||
architecture: x64
|
architecture: x64
|
||||||
output-suffix: x64
|
output-suffix: x64
|
||||||
fuse-lib: macFUSE
|
fuse-lib: macFUSE
|
||||||
openjfx-url: 'https://download2.gluonhq.com/openjfx/22.0.2/openjfx-22.0.2_osx-x64_bin-jmods.zip'
|
openjfx-url: 'https://download2.gluonhq.com/openjfx/24.0.1/openjfx-24.0.1_osx-x64_bin-jmods.zip'
|
||||||
openjfx-sha: '115cb08bb59d880cfff6e51e0bf0dcc45785ed9d456b8b8425597b04da6ab3d4'
|
openjfx-sha: '6e62a426d43c168a488521f904a523f3dd6ee2cf103e08136f2fd465c828a105'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Setup Java
|
- name: Setup Java
|
||||||
@@ -75,13 +84,21 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cp LICENSE.txt target
|
cp LICENSE.txt target
|
||||||
cp target/cryptomator-*.jar target/mods
|
cp target/cryptomator-*.jar target/mods
|
||||||
|
- name: Run jlink with help option
|
||||||
|
id: jep-493-check
|
||||||
|
run: |
|
||||||
|
JMOD_PATHS="openjfx-jmods"
|
||||||
|
if ! ${JAVA_HOME}/bin/jlink --help | grep -q "Linking from run-time image enabled"; then
|
||||||
|
JMOD_PATHS="${JAVA_HOME}/jmods:${JMOD_PATHS}"
|
||||||
|
fi
|
||||||
|
echo "jmod_paths=${JMOD_PATHS}" >> "$GITHUB_OUTPUT"
|
||||||
- name: Run jlink
|
- name: Run jlink
|
||||||
#Remark: no compression is applied for improved build compression later (here dmg)
|
#Remark: no compression is applied for improved build compression later (here dmg)
|
||||||
run: >
|
run: >
|
||||||
${JAVA_HOME}/bin/jlink
|
${JAVA_HOME}/bin/jlink
|
||||||
--verbose
|
--verbose
|
||||||
--output runtime
|
--output runtime
|
||||||
--module-path "${JAVA_HOME}/jmods:openjfx-jmods"
|
--module-path "${{ steps.jep-493-check.outputs.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.unsupported,jdk.accessibility,jdk.management.jfr,java.compiler
|
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.accessibility,jdk.management.jfr,java.compiler
|
||||||
--strip-native-commands
|
--strip-native-commands
|
||||||
--no-header-files
|
--no-header-files
|
||||||
@@ -100,10 +117,11 @@ jobs:
|
|||||||
--dest appdir
|
--dest appdir
|
||||||
--name Cryptomator
|
--name Cryptomator
|
||||||
--vendor "Skymatic GmbH"
|
--vendor "Skymatic GmbH"
|
||||||
--copyright "(C) 2016 - 2024 Skymatic GmbH"
|
--copyright "(C) 2016 - 2025 Skymatic GmbH"
|
||||||
--app-version "${{ needs.get-version.outputs.semVerNum }}"
|
--app-version "${{ needs.get-version.outputs.semVerNum }}"
|
||||||
--java-options "--enable-preview"
|
--java-options "--enable-preview"
|
||||||
--java-options "--enable-native-access=org.cryptomator.jfuse.mac"
|
--java-options "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.mac"
|
||||||
|
--java-options "--sun-misc-unsafe-memory-access=allow"
|
||||||
--java-options "-Xss5m"
|
--java-options "-Xss5m"
|
||||||
--java-options "-Xmx256m"
|
--java-options "-Xmx256m"
|
||||||
--java-options "-Dfile.encoding=\"utf-8\""
|
--java-options "-Dfile.encoding=\"utf-8\""
|
||||||
@@ -223,6 +241,11 @@ jobs:
|
|||||||
Cryptomator-${VERSION_NO}-${{ matrix.output-suffix }}.dmg dmg
|
Cryptomator-${VERSION_NO}-${{ matrix.output-suffix }}.dmg dmg
|
||||||
env:
|
env:
|
||||||
VERSION_NO: ${{ needs.get-version.outputs.semVerNum }}
|
VERSION_NO: ${{ needs.get-version.outputs.semVerNum }}
|
||||||
|
- name: Codesign .dmg
|
||||||
|
run: |
|
||||||
|
codesign -s ${CODESIGN_IDENTITY} --timestamp Cryptomator-*.dmg
|
||||||
|
env:
|
||||||
|
CODESIGN_IDENTITY: ${{ secrets.MACOS_CODESIGN_IDENTITY }}
|
||||||
- name: Notarize .dmg
|
- name: Notarize .dmg
|
||||||
if: startsWith(github.ref, 'refs/tags/') || inputs.notarize
|
if: startsWith(github.ref, 'refs/tags/') || inputs.notarize
|
||||||
uses: cocoalibs/xcode-notarization-action@v1
|
uses: cocoalibs/xcode-notarization-action@v1
|
||||||
|
|||||||
@@ -13,10 +13,16 @@ on:
|
|||||||
required: true
|
required: true
|
||||||
default: false
|
default: false
|
||||||
type: boolean
|
type: boolean
|
||||||
|
push:
|
||||||
|
branches-ignore:
|
||||||
|
- 'dependabot/**'
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/mac-dmg.yml'
|
||||||
|
- 'dist/mac/**'
|
||||||
|
|
||||||
env:
|
env:
|
||||||
JAVA_DIST: 'zulu'
|
JAVA_DIST: 'temurin'
|
||||||
JAVA_VERSION: '23.0.1+11'
|
JAVA_VERSION: '24.0.1+9'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
get-version:
|
get-version:
|
||||||
@@ -36,8 +42,8 @@ jobs:
|
|||||||
architecture: aarch64
|
architecture: aarch64
|
||||||
output-suffix: arm64
|
output-suffix: arm64
|
||||||
fuse-lib: FUSE-T
|
fuse-lib: FUSE-T
|
||||||
openjfx-url: 'https://download2.gluonhq.com/openjfx/22.0.2/openjfx-22.0.2_osx-aarch64_bin-jmods.zip'
|
openjfx-url: 'https://download2.gluonhq.com/openjfx/24.0.1/openjfx-24.0.1_osx-aarch64_bin-jmods.zip'
|
||||||
openjfx-sha: '813c6748f7c99cb7a579d48b48a087b4682b1fad1fc1a4fe5f9b21cf872b15a7'
|
openjfx-sha: 'b5a94a13077507003fa852512bfa33f4fb680bc8076d8002e4227a84c85171d4'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Setup Java
|
- name: Setup Java
|
||||||
@@ -76,13 +82,21 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cp LICENSE.txt target
|
cp LICENSE.txt target
|
||||||
cp target/cryptomator-*.jar target/mods
|
cp target/cryptomator-*.jar target/mods
|
||||||
|
- name: Run jlink with help option
|
||||||
|
id: jep-493-check
|
||||||
|
run: |
|
||||||
|
JMOD_PATHS="openjfx-jmods"
|
||||||
|
if ! ${JAVA_HOME}/bin/jlink --help | grep -q "Linking from run-time image enabled"; then
|
||||||
|
JMOD_PATHS="${JAVA_HOME}/jmods:${JMOD_PATHS}"
|
||||||
|
fi
|
||||||
|
echo "jmod_paths=${JMOD_PATHS}" >> "$GITHUB_OUTPUT"
|
||||||
- name: Run jlink
|
- name: Run jlink
|
||||||
#Remark: no compression is applied for improved build compression later (here dmg)
|
#Remark: no compression is applied for improved build compression later (here dmg)
|
||||||
run: >
|
run: >
|
||||||
${JAVA_HOME}/bin/jlink
|
${JAVA_HOME}/bin/jlink
|
||||||
--verbose
|
--verbose
|
||||||
--output runtime
|
--output runtime
|
||||||
--module-path "${JAVA_HOME}/jmods:openjfx-jmods"
|
--module-path "${{ steps.jep-493-check.outputs.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.unsupported,jdk.accessibility,jdk.management.jfr,java.compiler
|
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.accessibility,jdk.management.jfr,java.compiler
|
||||||
--strip-native-commands
|
--strip-native-commands
|
||||||
--no-header-files
|
--no-header-files
|
||||||
@@ -101,10 +115,11 @@ jobs:
|
|||||||
--dest appdir
|
--dest appdir
|
||||||
--name Cryptomator
|
--name Cryptomator
|
||||||
--vendor "Skymatic GmbH"
|
--vendor "Skymatic GmbH"
|
||||||
--copyright "(C) 2016 - 2024 Skymatic GmbH"
|
--copyright "(C) 2016 - 2025 Skymatic GmbH"
|
||||||
--app-version "${{ needs.get-version.outputs.semVerNum }}"
|
--app-version "${{ needs.get-version.outputs.semVerNum }}"
|
||||||
--java-options "--enable-preview"
|
--java-options "--enable-preview"
|
||||||
--java-options "--enable-native-access=org.cryptomator.jfuse.mac"
|
--java-options "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.mac"
|
||||||
|
--java-options "--sun-misc-unsafe-memory-access=allow"
|
||||||
--java-options "-Xss5m"
|
--java-options "-Xss5m"
|
||||||
--java-options "-Xmx256m"
|
--java-options "-Xmx256m"
|
||||||
--java-options "-Dfile.encoding=\"utf-8\""
|
--java-options "-Dfile.encoding=\"utf-8\""
|
||||||
@@ -224,6 +239,11 @@ jobs:
|
|||||||
Cryptomator-${VERSION_NO}-${{ matrix.output-suffix }}.dmg dmg
|
Cryptomator-${VERSION_NO}-${{ matrix.output-suffix }}.dmg dmg
|
||||||
env:
|
env:
|
||||||
VERSION_NO: ${{ needs.get-version.outputs.semVerNum }}
|
VERSION_NO: ${{ needs.get-version.outputs.semVerNum }}
|
||||||
|
- name: Codesign .dmg
|
||||||
|
run: |
|
||||||
|
codesign -s ${CODESIGN_IDENTITY} --timestamp Cryptomator-*.dmg
|
||||||
|
env:
|
||||||
|
CODESIGN_IDENTITY: ${{ secrets.MACOS_CODESIGN_IDENTITY }}
|
||||||
- name: Notarize .dmg
|
- name: Notarize .dmg
|
||||||
if: startsWith(github.ref, 'refs/tags/') || inputs.notarize
|
if: startsWith(github.ref, 'refs/tags/') || inputs.notarize
|
||||||
uses: cocoalibs/xcode-notarization-action@v1
|
uses: cocoalibs/xcode-notarization-action@v1
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
JAVA_DIST: 'zulu'
|
JAVA_DIST: 'temurin'
|
||||||
JAVA_VERSION: 23
|
JAVA_VERSION: 24
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
@@ -15,7 +15,6 @@ jobs:
|
|||||||
test:
|
test:
|
||||||
name: Compile and Test
|
name: Compile and Test
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]')"
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-java@v4
|
- uses: actions/setup-java@v4
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ defaults:
|
|||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
env:
|
env:
|
||||||
JAVA_DIST: 'zulu'
|
JAVA_DIST: 'temurin'
|
||||||
JAVA_VERSION: 23
|
JAVA_VERSION: 23
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|||||||
+151
-81
@@ -12,14 +12,19 @@ on:
|
|||||||
description: 'Build debug version with console output'
|
description: 'Build debug version with console output'
|
||||||
type: boolean
|
type: boolean
|
||||||
default: false
|
default: false
|
||||||
|
push:
|
||||||
|
branches-ignore:
|
||||||
|
- 'dependabot/**'
|
||||||
|
paths:
|
||||||
|
- '.github/workflows/win-exe.yml'
|
||||||
|
- 'dist/win/**'
|
||||||
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
JAVA_DIST: 'zulu'
|
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/24.0.1/openjfx-24.0.1_windows-x64_bin-jmods.zip'
|
||||||
JAVA_VERSION: '23.0.1+11'
|
OPENJFX_JMODS_AMD64_HASH: 'f13d17c7caf88654fc835f1b4e75a9b0f34a888eb8abef381796c0002e63b03f'
|
||||||
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/22.0.2/openjfx-22.0.2_windows-x64_bin-jmods.zip'
|
WINFSP_MSI: 'https://github.com/winfsp/winfsp/releases/download/v2.1/winfsp-2.1.25156.msi'
|
||||||
OPENJFX_JMODS_AMD64_HASH: 'f9376d200f5c5b85327d575c1ec1482e6455f19916577f7e2fc9be2f48bb29b6'
|
WINFSP_MSI_HASH: '073a70e00f77423e34bed98b86e600def93393ba5822204fac57a29324db9f7a'
|
||||||
WINFSP_MSI: 'https://github.com/winfsp/winfsp/releases/download/v2.0/winfsp-2.0.23075.msi'
|
|
||||||
WINFSP_UNINSTALLER: 'https://github.com/cryptomator/winfsp-uninstaller/releases/latest/download/winfsp-uninstaller.exe'
|
WINFSP_UNINSTALLER: 'https://github.com/cryptomator/winfsp-uninstaller/releases/latest/download/winfsp-uninstaller.exe'
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
@@ -34,36 +39,54 @@ jobs:
|
|||||||
|
|
||||||
build-msi:
|
build-msi:
|
||||||
name: Build .msi Installer
|
name: Build .msi Installer
|
||||||
runs-on: windows-latest
|
runs-on: ${{ matrix.os }}
|
||||||
needs: [get-version]
|
needs: [ get-version ]
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- arch: x64
|
||||||
|
os: windows-latest
|
||||||
|
java-dist: 'zulu'
|
||||||
|
java-version: '24.0.1+9'
|
||||||
|
java-package: 'jdk'
|
||||||
|
- arch: arm64
|
||||||
|
os: windows-11-arm
|
||||||
|
java-dist: 'liberica'
|
||||||
|
java-version: '24.0.1+11'
|
||||||
|
java-package: 'jdk+fx' #This is needed, as liberica contains JFX 24 Jmods for Windows ARM64
|
||||||
env:
|
env:
|
||||||
LOOPBACK_ALIAS: 'cryptomator-vault'
|
LOOPBACK_ALIAS: 'cryptomator-vault'
|
||||||
WIN_CONSOLE_FLAG: ''
|
WIN_CONSOLE_FLAG: ''
|
||||||
steps:
|
steps:
|
||||||
- name: Upgrade WIX to latest version
|
|
||||||
run: choco install wixtoolset --version 3.14.1
|
|
||||||
shell: pwsh
|
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Setup Java
|
- name: Setup Java
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: ${{ env.JAVA_DIST }}
|
distribution: ${{ matrix.java-dist }}
|
||||||
java-version: ${{ env.JAVA_VERSION }}
|
java-version: ${{ matrix.java-version }}
|
||||||
|
java-package: ${{ matrix.java-package }}
|
||||||
check-latest: true
|
check-latest: true
|
||||||
cache: 'maven'
|
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
|
||||||
- name: Download and extract JavaFX jmods from Gluon
|
- 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
|
#In the last step we move all jmods files a dir level up because jmods are placed inside a directory in the zip
|
||||||
run: |
|
run: |
|
||||||
curl --output jfxjmods.zip -L "${{ env.OPENJFX_JMODS_AMD64 }}"
|
curl --output openjfx-jmods.zip -L "${{ env.OPENJFX_JMODS_AMD64 }}"
|
||||||
if(!(Get-FileHash -Path jfxjmods.zip -Algorithm SHA256).Hash.ToLower().equals("${{ env.OPENJFX_JMODS_AMD64_HASH }}")) {
|
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 }}.";
|
throw "Wrong checksum of JMOD archive downloaded from ${{ env.OPENJFX_JMODS_AMD64 }}.";
|
||||||
}
|
}
|
||||||
Expand-Archive -Path jfxjmods.zip -DestinationPath jfxjmods
|
Expand-Archive -Path openjfx-jmods.zip -DestinationPath openjfx-jmods
|
||||||
Get-ChildItem -Path jfxjmods -Recurse -Filter "*.jmod" | ForEach-Object { Move-Item -Path $_ -Destination $_.Directory.Parent}
|
Get-ChildItem -Path openjfx-jmods -Recurse -Filter "*.jmod" | ForEach-Object { Move-Item -Path $_ -Destination $_.Directory.Parent}
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
- name: Ensure major jfx version in pom and in jmods is the same
|
- name: Ensure major jfx version in pom and in jmods is the same
|
||||||
|
if: matrix.arch == 'x64'
|
||||||
run: |
|
run: |
|
||||||
JMOD_VERSION_AMD64=$(jmod describe jfxjmods/javafx.base.jmod | head -1)
|
JMOD_VERSION_AMD64=$(jmod describe openjfx-jmods/javafx.base.jmod | head -1)
|
||||||
JMOD_VERSION_AMD64=${JMOD_VERSION_AMD64#*@}
|
JMOD_VERSION_AMD64=${JMOD_VERSION_AMD64#*@}
|
||||||
JMOD_VERSION_AMD64=${JMOD_VERSION_AMD64%%.*}
|
JMOD_VERSION_AMD64=${JMOD_VERSION_AMD64%%.*}
|
||||||
POM_JFX_VERSION=$(mvn help:evaluate "-Dexpression=javafx.version" -q -DforceStdout)
|
POM_JFX_VERSION=$(mvn help:evaluate "-Dexpression=javafx.version" -q -DforceStdout)
|
||||||
@@ -75,29 +98,34 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
- name: Set version
|
- name: Set version
|
||||||
run : mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }}
|
run: mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }}
|
||||||
- name: Run maven
|
- name: Run maven
|
||||||
run: mvn -B clean package -Pwin -DskipTests -Djavafx.platform=win
|
run: mvn -B clean package -Pwin -DskipTests -Djavafx.platform=win
|
||||||
- name: Patch target dir
|
- name: Patch target dir
|
||||||
run: |
|
run: |
|
||||||
cp LICENSE.txt target
|
cp LICENSE.txt target
|
||||||
cp target/cryptomator-*.jar target/mods
|
cp target/cryptomator-*.jar target/mods
|
||||||
|
- name: Run jlink with help option
|
||||||
|
id: jep-493-check
|
||||||
|
run: |
|
||||||
|
JMOD_PATHS="openjfx-jmods"
|
||||||
|
if ! $(${JAVA_HOME}/bin/jlink --help | grep -q "Linking from run-time image enabled"); then
|
||||||
|
JMOD_PATHS="${JAVA_HOME}/jmods;${JMOD_PATHS}"
|
||||||
|
fi
|
||||||
|
echo "jmod_paths=${JMOD_PATHS}" >> "$GITHUB_OUTPUT"
|
||||||
- name: Run jlink
|
- name: Run jlink
|
||||||
#Remark: no compression is applied for improved build compression later (here msi)
|
# Remark: no compression is applied for improved build compression later (here msi)
|
||||||
run: >
|
run: >
|
||||||
${JAVA_HOME}/bin/jlink
|
${JAVA_HOME}/bin/jlink
|
||||||
--verbose
|
--verbose
|
||||||
--output runtime
|
--output runtime
|
||||||
--module-path "jfxjmods;${JAVA_HOME}/jmods"
|
--module-path "${{ steps.jep-493-check.outputs.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.unsupported,jdk.accessibility,jdk.management.jfr,java.compiler
|
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.crypto.mscapi,jdk.unsupported,jdk.accessibility,jdk.management.jfr,java.compiler
|
||||||
--strip-native-commands
|
--strip-native-commands
|
||||||
--no-header-files
|
--no-header-files
|
||||||
--no-man-pages
|
--no-man-pages
|
||||||
--strip-debug
|
--strip-debug
|
||||||
--compress zip-0
|
--compress zip-0
|
||||||
- name: Change win-console flag if debug is active
|
|
||||||
if: ${{ inputs.isDebug }}
|
|
||||||
run: echo "WIN_CONSOLE_FLAG=--win-console" >> $GITHUB_ENV
|
|
||||||
- name: Run jpackage
|
- name: Run jpackage
|
||||||
run: >
|
run: >
|
||||||
${JAVA_HOME}/bin/jpackage
|
${JAVA_HOME}/bin/jpackage
|
||||||
@@ -110,10 +138,11 @@ jobs:
|
|||||||
--dest appdir
|
--dest appdir
|
||||||
--name Cryptomator
|
--name Cryptomator
|
||||||
--vendor "Skymatic GmbH"
|
--vendor "Skymatic GmbH"
|
||||||
--copyright "(C) 2016 - 2024 Skymatic GmbH"
|
--copyright "(C) 2016 - 2025 Skymatic GmbH"
|
||||||
--app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}"
|
--app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}"
|
||||||
--java-options "--enable-preview"
|
--java-options "--enable-preview"
|
||||||
--java-options "--enable-native-access=org.cryptomator.jfuse.win,org.cryptomator.integrations.win"
|
--java-options "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.win,org.cryptomator.integrations.win"
|
||||||
|
--java-options "--sun-misc-unsafe-memory-access=allow"
|
||||||
--java-options "-Xss5m"
|
--java-options "-Xss5m"
|
||||||
--java-options "-Xmx256m"
|
--java-options "-Xmx256m"
|
||||||
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
|
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
|
||||||
@@ -130,11 +159,11 @@ jobs:
|
|||||||
--java-options "-Dcryptomator.buildNumber=\"msi-${{ needs.get-version.outputs.revNum }}\""
|
--java-options "-Dcryptomator.buildNumber=\"msi-${{ needs.get-version.outputs.revNum }}\""
|
||||||
--java-options "-Dcryptomator.integrationsWin.autoStartShellLinkName=\"Cryptomator\""
|
--java-options "-Dcryptomator.integrationsWin.autoStartShellLinkName=\"Cryptomator\""
|
||||||
--java-options "-Dcryptomator.integrationsWin.keychainPaths=\"@{appdata}/Cryptomator/keychain.json;@{userhome}/AppData/Roaming/Cryptomator/keychain.json\""
|
--java-options "-Dcryptomator.integrationsWin.keychainPaths=\"@{appdata}/Cryptomator/keychain.json;@{userhome}/AppData/Roaming/Cryptomator/keychain.json\""
|
||||||
--java-options "-Dcryptomator.integrationsWin.windowsHelloKeychainPaths=\"@{appdata}/Cryptomator/windowsHelloKeychain.json;@{userhome}/AppData/Roaming/Cryptomator/windowsHelloKeychain.json\""
|
--java-options "-Dcryptomator.integrationsWin.windowsHelloKeychainPaths=\"@{appdata}/Cryptomator/windowsHelloKeychain.json\""
|
||||||
--java-options "-Djavafx.verbose=${{ inputs.isDebug }}"
|
--java-options "-Djavafx.verbose=${{ inputs.isDebug }}"
|
||||||
--resource-dir dist/win/resources
|
--resource-dir dist/win/resources
|
||||||
--icon dist/win/resources/Cryptomator.ico
|
--icon dist/win/resources/Cryptomator.ico
|
||||||
${WIN_CONSOLE_FLAG}
|
--add-launcher "Debug_Cryptomator=dist/win/debug-launcher.properties"
|
||||||
- name: Patch Application Directory
|
- name: Patch Application Directory
|
||||||
run: |
|
run: |
|
||||||
cp dist/win/contrib/* appdir/Cryptomator
|
cp dist/win/contrib/* appdir/Cryptomator
|
||||||
@@ -149,7 +178,9 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
- name: Fix permissions
|
- name: Fix permissions
|
||||||
run: attrib -r appdir/Cryptomator/Cryptomator.exe
|
run: |
|
||||||
|
attrib -r appdir/Cryptomator/Cryptomator.exe
|
||||||
|
attrib -r appdir/Cryptomator/Debug_Cryptomator.exe
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
- name: Extract jars with DLLs for Codesigning
|
- name: Extract jars with DLLs for Codesigning
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
@@ -219,7 +250,7 @@ jobs:
|
|||||||
--dest installer
|
--dest installer
|
||||||
--name Cryptomator
|
--name Cryptomator
|
||||||
--vendor "Skymatic GmbH"
|
--vendor "Skymatic GmbH"
|
||||||
--copyright "(C) 2016 - 2024 Skymatic GmbH"
|
--copyright "(C) 2016 - 2025 Skymatic GmbH"
|
||||||
--app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum}}"
|
--app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum}}"
|
||||||
--win-menu
|
--win-menu
|
||||||
--win-dir-chooser
|
--win-dir-chooser
|
||||||
@@ -241,8 +272,8 @@ jobs:
|
|||||||
description: Cryptomator Installer
|
description: Cryptomator Installer
|
||||||
timestampUrl: 'http://timestamp.digicert.com'
|
timestampUrl: 'http://timestamp.digicert.com'
|
||||||
folder: installer
|
folder: installer
|
||||||
- name: Add possible alpha/beta tags to installer name
|
- name: Add possible alpha/beta tags and architecture to installer name
|
||||||
run: mv installer/Cryptomator-*.msi Cryptomator-${{ needs.get-version.outputs.semVerStr }}-x64.msi
|
run: mv installer/Cryptomator-*.msi Cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.arch }}.msi
|
||||||
- name: Create detached GPG signature with key 615D449FE6E6A235
|
- name: Create detached GPG signature with key 615D449FE6E6A235
|
||||||
run: |
|
run: |
|
||||||
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
|
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
|
||||||
@@ -253,7 +284,7 @@ jobs:
|
|||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: msi
|
name: msi-${{ matrix.arch }}
|
||||||
path: |
|
path: |
|
||||||
Cryptomator-*.msi
|
Cryptomator-*.msi
|
||||||
Cryptomator-*.asc
|
Cryptomator-*.asc
|
||||||
@@ -261,21 +292,43 @@ jobs:
|
|||||||
|
|
||||||
build-exe:
|
build-exe:
|
||||||
name: Build .exe installer
|
name: Build .exe installer
|
||||||
runs-on: windows-latest
|
runs-on: ${{ matrix.os }}
|
||||||
needs: [get-version, build-msi]
|
needs: [ get-version, build-msi ]
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- arch: x64
|
||||||
|
os: windows-latest
|
||||||
|
executable-suffix: x64
|
||||||
|
java-dist: 'zulu'
|
||||||
|
java-version: '24.0.1+9'
|
||||||
|
java-package: 'jdk'
|
||||||
|
- arch: arm64
|
||||||
|
os: windows-11-arm
|
||||||
|
executable-suffix: arm64
|
||||||
|
java-dist: 'liberica'
|
||||||
|
java-version: '24.0.1+11'
|
||||||
|
java-package: 'jdk+fx' #This is needed, as liberica contains JFX 24 Jmods for Windows ARM64
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
- 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
|
||||||
- name: Download .msi
|
- name: Download .msi
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: msi
|
name: msi-${{ matrix.arch }}
|
||||||
path: dist/win/bundle/resources
|
path: dist/win/bundle/resources
|
||||||
- name: Strip version info from msi file name
|
- name: Strip version info from msi file name
|
||||||
run: mv dist/win/bundle/resources/Cryptomator*.msi dist/win/bundle/resources/Cryptomator.msi
|
run: mv dist/win/bundle/resources/Cryptomator*.msi dist/win/bundle/resources/Cryptomator.msi
|
||||||
- uses: actions/setup-java@v4
|
- name: Setup Java
|
||||||
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: ${{ env.JAVA_DIST }}
|
distribution: ${{ matrix.java-dist }}
|
||||||
java-version: ${{ env.JAVA_VERSION }}
|
java-version: ${{ matrix.java-version }}
|
||||||
|
java-package: ${{ matrix.java-package }}
|
||||||
check-latest: true
|
check-latest: true
|
||||||
cache: 'maven'
|
cache: 'maven'
|
||||||
- name: Generate license for exe
|
- name: Generate license for exe
|
||||||
@@ -291,35 +344,36 @@ jobs:
|
|||||||
shell: pwsh
|
shell: pwsh
|
||||||
- name: Download WinFsp
|
- name: Download WinFsp
|
||||||
run: |
|
run: |
|
||||||
curl --output dist/win/bundle/resources/winfsp.msi -L ${{ env.WINFSP_MSI }}
|
curl --output $env:WINFSP_PATH -L ${{ env.WINFSP_MSI }}
|
||||||
|
$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)."
|
||||||
|
}
|
||||||
|
env:
|
||||||
|
WINFSP_PATH: 'dist/win/bundle/resources/winfsp.msi'
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
- name: Download Legacy-WinFsp uninstaller
|
- name: Download Legacy-WinFsp uninstaller
|
||||||
run: |
|
run: |
|
||||||
curl --output dist/win/bundle/resources/winfsp-uninstaller.exe -L ${{ env.WINFSP_UNINSTALLER }}
|
curl --output dist/win/bundle/resources/winfsp-uninstaller.exe -L ${{ env.WINFSP_UNINSTALLER }}
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
- name: Compile to wixObj file
|
- name: Create Wix Burn bundle
|
||||||
|
working-directory: dist/win
|
||||||
run: >
|
run: >
|
||||||
"${WIX}/bin/candle.exe" dist/win/bundle/bundleWithWinfsp.wxs
|
wix build
|
||||||
-ext WixBalExtension
|
-define BundleName="Cryptomator"
|
||||||
-ext WixUtilExtension
|
-define BundleVersion="${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum}}"
|
||||||
-out dist/win/bundle/
|
-define BundleVendor="Skymatic GmbH"
|
||||||
-dBundleVersion="${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}"
|
-define BundleCopyright="(C) 2016 - 2025 Skymatic GmbH"
|
||||||
-dBundleVendor="Skymatic GmbH"
|
-define AboutUrl="https://cryptomator.org"
|
||||||
-dBundleCopyright="(C) 2016 - 2024 Skymatic GmbH"
|
-define HelpUrl="https://cryptomator.org/contact"
|
||||||
-dAboutUrl="https://cryptomator.org"
|
-define UpdateUrl="https://cryptomator.org/downloads/"
|
||||||
-dHelpUrl="https://cryptomator.org/contact"
|
-ext "WixToolset.Util.wixext"
|
||||||
-dUpdateUrl="https://cryptomator.org/downloads/"
|
-ext "WixToolset.BootstrapperApplications.wixext"
|
||||||
- name: Create executable with linker
|
./bundle/bundleWithWinfsp.wxs
|
||||||
run: >
|
-out "../../installer/unsigned/Cryptomator-Installer.exe"
|
||||||
"${WIX}/bin/light.exe" -b dist/win/ dist/win/bundle/bundleWithWinfsp.wixobj
|
|
||||||
-ext WixBalExtension
|
|
||||||
-ext WixUtilExtension
|
|
||||||
-out installer/unsigned/Cryptomator-Installer.exe
|
|
||||||
- name: Detach burn engine in preparation to sign
|
- name: Detach burn engine in preparation to sign
|
||||||
run: >
|
run: >
|
||||||
"${WIX}/bin/insignia.exe"
|
wix burn detach installer/unsigned/Cryptomator-Installer.exe -engine tmp/engine.exe
|
||||||
-ib installer/unsigned/Cryptomator-Installer.exe
|
|
||||||
-o tmp/engine.exe
|
|
||||||
- name: Codesign burn engine
|
- name: Codesign burn engine
|
||||||
uses: skymatic/code-sign-action@v3
|
uses: skymatic/code-sign-action@v3
|
||||||
with:
|
with:
|
||||||
@@ -330,10 +384,8 @@ jobs:
|
|||||||
timestampUrl: 'http://timestamp.digicert.com'
|
timestampUrl: 'http://timestamp.digicert.com'
|
||||||
folder: tmp
|
folder: tmp
|
||||||
- name: Reattach signed burn engine to installer
|
- name: Reattach signed burn engine to installer
|
||||||
run : >
|
run: >
|
||||||
"${WIX}/bin/insignia.exe"
|
wix burn reattach installer/unsigned/Cryptomator-Installer.exe -engine tmp/engine.exe -o installer/Cryptomator-Installer.exe
|
||||||
-ab tmp/engine.exe installer/unsigned/Cryptomator-Installer.exe
|
|
||||||
-o installer/Cryptomator-Installer.exe
|
|
||||||
- name: Codesign EXE
|
- name: Codesign EXE
|
||||||
uses: skymatic/code-sign-action@v3
|
uses: skymatic/code-sign-action@v3
|
||||||
with:
|
with:
|
||||||
@@ -344,7 +396,7 @@ jobs:
|
|||||||
timestampUrl: 'http://timestamp.digicert.com'
|
timestampUrl: 'http://timestamp.digicert.com'
|
||||||
folder: installer
|
folder: installer
|
||||||
- name: Add possible alpha/beta tags to installer name
|
- name: Add possible alpha/beta tags to installer name
|
||||||
run: mv installer/Cryptomator-Installer.exe Cryptomator-${{ needs.get-version.outputs.semVerStr }}-x64.exe
|
run: mv installer/Cryptomator-Installer.exe Cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.executable-suffix }}.exe
|
||||||
- name: Create detached GPG signature with key 615D449FE6E6A235
|
- name: Create detached GPG signature with key 615D449FE6E6A235
|
||||||
run: |
|
run: |
|
||||||
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
|
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
|
||||||
@@ -355,7 +407,7 @@ jobs:
|
|||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: exe
|
name: exe-${{ matrix.executable-suffix }}
|
||||||
path: |
|
path: |
|
||||||
Cryptomator-*.exe
|
Cryptomator-*.exe
|
||||||
Cryptomator-*.asc
|
Cryptomator-*.asc
|
||||||
@@ -365,16 +417,18 @@ jobs:
|
|||||||
name: Publish installers to the github release
|
name: Publish installers to the github release
|
||||||
if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published'
|
if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [build-msi, build-exe]
|
needs: [ build-msi, build-exe ]
|
||||||
outputs:
|
outputs:
|
||||||
download-url-msi: ${{ fromJSON(steps.publish.outputs.assets)[0].browser_download_url }}
|
download-url-msi-x64: ${{ fromJSON(steps.publish.outputs.assets)[0].browser_download_url }}
|
||||||
download-url-exe: ${{ fromJSON(steps.publish.outputs.assets)[1].browser_download_url }}
|
download-url-msi-arm64: ${{ fromJSON(steps.publish.outputs.assets)[1].browser_download_url }}
|
||||||
|
download-url-exe-x64: ${{ fromJSON(steps.publish.outputs.assets)[2].browser_download_url }}
|
||||||
|
download-url-exe-arm64: ${{ fromJSON(steps.publish.outputs.assets)[3].browser_download_url }}
|
||||||
steps:
|
steps:
|
||||||
- name: Download installers
|
- name: Download installers
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
merge-multiple: true
|
merge-multiple: true
|
||||||
- name: Publish .msi on GitHub Releases
|
- name: Publish installers on GitHub Releases
|
||||||
id: publish
|
id: publish
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
@@ -382,22 +436,38 @@ jobs:
|
|||||||
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
|
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
|
||||||
# do not change ordering of filelist, required for correct job output
|
# do not change ordering of filelist, required for correct job output
|
||||||
files: |
|
files: |
|
||||||
*.msi
|
*x64.msi
|
||||||
*.exe
|
*arm64.msi
|
||||||
|
*x64.exe
|
||||||
|
*arm64.exe
|
||||||
*.asc
|
*.asc
|
||||||
|
|
||||||
allowlist-msi:
|
allowlist-msi-x64:
|
||||||
uses: ./.github/workflows/av-whitelist.yml
|
uses: ./.github/workflows/av-whitelist.yml
|
||||||
needs: [publish]
|
needs: [ publish ]
|
||||||
with:
|
with:
|
||||||
url: ${{ needs.publish.outputs.download-url-msi }}
|
url: ${{ needs.publish.outputs.download-url-msi-x64 }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
allowlist-exe:
|
allowlist-msi-arm64:
|
||||||
uses: ./.github/workflows/av-whitelist.yml
|
uses: ./.github/workflows/av-whitelist.yml
|
||||||
needs: [publish]
|
needs: [ publish ]
|
||||||
with:
|
with:
|
||||||
url: ${{ needs.publish.outputs.download-url-exe }}
|
url: ${{ needs.publish.outputs.download-url-msi-arm64 }}
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
allowlist-exe-x64:
|
||||||
|
uses: ./.github/workflows/av-whitelist.yml
|
||||||
|
needs: [ publish, allowlist-msi-x64 ]
|
||||||
|
with:
|
||||||
|
url: ${{ needs.publish.outputs.download-url-exe-x64 }}
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
allowlist-exe-arm64:
|
||||||
|
uses: ./.github/workflows/av-whitelist.yml
|
||||||
|
needs: [ publish, allowlist-msi-arm64 ]
|
||||||
|
with:
|
||||||
|
url: ${{ needs.publish.outputs.download-url-exe-arm64 }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
notify-winget:
|
notify-winget:
|
||||||
@@ -414,7 +484,7 @@ jobs:
|
|||||||
SLACK_ICON: false
|
SLACK_ICON: false
|
||||||
SLACK_ICON_EMOJI: ':bot:'
|
SLACK_ICON_EMOJI: ':bot:'
|
||||||
SLACK_CHANNEL: 'cryptomator-desktop'
|
SLACK_CHANNEL: 'cryptomator-desktop'
|
||||||
SLACK_TITLE: "MSI of ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} published."
|
SLACK_TITLE: "MSI packages of ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} published."
|
||||||
SLACK_MESSAGE: "Ready to <https://github.com/${{ github.repository }}/actions/workflows/winget.yml| release to winget>."
|
SLACK_MESSAGE: "Ready to <https://github.com/${{ github.repository }}/actions/workflows/winget.yml| release them to winget>."
|
||||||
SLACK_FOOTER: false
|
SLACK_FOOTER: false
|
||||||
MSG_MINIMAL: true
|
MSG_MINIMAL: true
|
||||||
|
|||||||
@@ -16,12 +16,12 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
gh repo sync cryptomator/winget-pkgs -b master --force
|
gh repo sync cryptomator/winget-pkgs -b master --force
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.CRYPTOBOT_WINGET_TOKEN }}
|
GH_TOKEN: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
|
||||||
- name: Submit package
|
- name: Submit package
|
||||||
uses: vedantmgoyal2009/winget-releaser@main
|
uses: vedantmgoyal2009/winget-releaser@main
|
||||||
with:
|
with:
|
||||||
identifier: Cryptomator.Cryptomator
|
identifier: Cryptomator.Cryptomator
|
||||||
version: ${{ inputs.tag }}
|
version: ${{ inputs.tag }}
|
||||||
release-tag: ${{ inputs.tag }}
|
release-tag: ${{ inputs.tag }}
|
||||||
installers-regex: '\.msi$'
|
installers-regex: '-x64\.msi$'
|
||||||
token: ${{ secrets.CRYPTOBOT_WINGET_TOKEN }}
|
token: ${{ secrets.CRYPTOBOT_PR_TOKEN }}
|
||||||
Generated
+9
-8
@@ -14,17 +14,16 @@
|
|||||||
<option name="dagger.fastInit" value="enabled" />
|
<option name="dagger.fastInit" value="enabled" />
|
||||||
<option name="dagger.formatGeneratedSource" value="enabled" />
|
<option name="dagger.formatGeneratedSource" value="enabled" />
|
||||||
<processorPath useClasspath="false">
|
<processorPath useClasspath="false">
|
||||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-compiler/2.52/dagger-compiler-2.52.jar" />
|
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-compiler/2.55/dagger-compiler-2.55.jar" />
|
||||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger/2.52/dagger-2.52.jar" />
|
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger/2.55/dagger-2.55.jar" />
|
||||||
<entry name="$MAVEN_REPOSITORY$/jakarta/inject/jakarta.inject-api/2.0.1/jakarta.inject-api-2.0.1.jar" />
|
<entry name="$MAVEN_REPOSITORY$/jakarta/inject/jakarta.inject-api/2.0.1/jakarta.inject-api-2.0.1.jar" />
|
||||||
<entry name="$MAVEN_REPOSITORY$/javax/inject/javax.inject/1/javax.inject-1.jar" />
|
<entry name="$MAVEN_REPOSITORY$/javax/inject/javax.inject/1/javax.inject-1.jar" />
|
||||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-spi/2.52/dagger-spi-2.52.jar" />
|
<entry name="$MAVEN_REPOSITORY$/org/jspecify/jspecify/1.0.0/jspecify-1.0.0.jar" />
|
||||||
|
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-spi/2.55/dagger-spi-2.55.jar" />
|
||||||
<entry name="$MAVEN_REPOSITORY$/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar" />
|
<entry name="$MAVEN_REPOSITORY$/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar" />
|
||||||
<entry name="$MAVEN_REPOSITORY$/com/google/devtools/ksp/symbol-processing-api/1.9.24-1.0.20/symbol-processing-api-1.9.24-1.0.20.jar" />
|
<entry name="$MAVEN_REPOSITORY$/com/google/devtools/ksp/symbol-processing-api/2.0.21-1.0.28/symbol-processing-api-2.0.21-1.0.28.jar" />
|
||||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.9.0/kotlin-stdlib-jdk8-1.9.0.jar" />
|
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.0.21/kotlin-stdlib-2.0.21.jar" />
|
||||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.24/kotlin-stdlib-1.9.24.jar" />
|
|
||||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar" />
|
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar" />
|
||||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.9.0/kotlin-stdlib-jdk7-1.9.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/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/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$/com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar" />
|
||||||
@@ -35,6 +34,8 @@
|
|||||||
<entry name="$MAVEN_REPOSITORY$/com/google/googlejavaformat/google-java-format/1.5/google-java-format-1.5.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/errorprone/javac-shaded/9-dev-r4023-3/javac-shaded-9-dev-r4023-3.jar" />
|
||||||
<entry name="$MAVEN_REPOSITORY$/com/squareup/kotlinpoet/1.11.0/kotlinpoet-1.11.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$/org/jetbrains/kotlin/kotlin-reflect/1.6.10/kotlin-reflect-1.6.10.jar" />
|
||||||
<entry name="$MAVEN_REPOSITORY$/net/ltgt/gradle/incap/incap/0.2/incap-0.2.jar" />
|
<entry name="$MAVEN_REPOSITORY$/net/ltgt/gradle/incap/incap/0.2/incap-0.2.jar" />
|
||||||
<entry name="$MAVEN_REPOSITORY$/org/checkerframework/checker-compat-qual/2.5.5/checker-compat-qual-2.5.5.jar" />
|
<entry name="$MAVEN_REPOSITORY$/org/checkerframework/checker-compat-qual/2.5.5/checker-compat-qual-2.5.5.jar" />
|
||||||
@@ -45,7 +46,7 @@
|
|||||||
</component>
|
</component>
|
||||||
<component name="JavacSettings">
|
<component name="JavacSettings">
|
||||||
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
|
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
|
||||||
<module name="cryptomator" options="-Adagger.fastInit=enabled -Adagger.formatGeneratedSource=enabled --enable-preview" />
|
<module name="cryptomator" options="-Adagger.fastInit=enabled -Adagger.formatGeneratedSource=enabled" />
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
Generated
+1
-1
@@ -8,7 +8,7 @@
|
|||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_23" project-jdk-name="23" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_24" project-jdk-name="24" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
<configuration default="false" name="Cryptomator Linux" type="Application" factoryName="Application">
|
<configuration default="false" name="Cryptomator Linux" type="Application" factoryName="Application">
|
||||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||||
<module name="cryptomator" />
|
<module name="cryptomator" />
|
||||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="@{userhome}/.config/Cryptomator/settings.json" -Dcryptomator.p12Path="@{userhome}/.config/Cryptomator/key.p12" -Dcryptomator.ipcSocketPath="@{userhome}/.config/Cryptomator/ipc.socket" -Dcryptomator.logDir="@{userhome}/.local/share/Cryptomator/logs" -Dcryptomator.pluginDir="@{userhome}/.local/share/Cryptomator/plugins" -Dcryptomator.mountPointsDir="@{userhome}/.local/share/Cryptomator/mnt" -Dcryptomator.showTrayIcon=true -Xss20m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator" />
|
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="@{userhome}/.config/Cryptomator/settings.json" -Dcryptomator.p12Path="@{userhome}/.config/Cryptomator/key.p12" -Dcryptomator.ipcSocketPath="@{userhome}/.config/Cryptomator/ipc.socket" -Dcryptomator.logDir="@{userhome}/.local/share/Cryptomator/logs" -Dcryptomator.pluginDir="@{userhome}/.local/share/Cryptomator/plugins" -Dcryptomator.mountPointsDir="@{userhome}/.local/share/Cryptomator/mnt" -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" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
<configuration default="false" name="Cryptomator Linux Dev" type="Application" factoryName="Application">
|
<configuration default="false" name="Cryptomator Linux Dev" type="Application" factoryName="Application">
|
||||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||||
<module name="cryptomator" />
|
<module name="cryptomator" />
|
||||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="@{userhome}/.config/Cryptomator-Dev/settings.json" -Dcryptomator.p12Path="@{userhome}/.config/Cryptomator-Dev/key.p12" -Dcryptomator.ipcSocketPath="@{userhome}/.config/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="@{userhome}/.local/share/Cryptomator-Dev/logs" -Dcryptomator.pluginDir="@{userhome}/.local/share/Cryptomator-Dev/plugins" -Dcryptomator.mountPointsDir="@{userhome}/.local/share/Cryptomator-Dev/mnt" -Dcryptomator.showTrayIcon=true -Dfuse.experimental="true" -Xss20m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator" />
|
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="@{userhome}/.config/Cryptomator-Dev/settings.json" -Dcryptomator.p12Path="@{userhome}/.config/Cryptomator-Dev/key.p12" -Dcryptomator.ipcSocketPath="@{userhome}/.config/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="@{userhome}/.local/share/Cryptomator-Dev/logs" -Dcryptomator.pluginDir="@{userhome}/.local/share/Cryptomator-Dev/plugins" -Dcryptomator.mountPointsDir="@{userhome}/.local/share/Cryptomator-Dev/mnt" -Dcryptomator.showTrayIcon=true -Dfuse.experimental="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">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
<configuration default="false" name="Cryptomator Windows" type="Application" factoryName="Application">
|
<configuration default="false" name="Cryptomator Windows" type="Application" factoryName="Application">
|
||||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||||
<module name="cryptomator" />
|
<module name="cryptomator" />
|
||||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="@{appdata}/Cryptomator/settings.json;@{userhome}/AppData/Roaming/Cryptomator/settings.json" -Dcryptomator.ipcSocketPath="@{localappdata}/Cryptomator/ipc.socket" -Dcryptomator.logDir="@{localappdata}/Cryptomator" -Dcryptomator.pluginDir="@{appdata}/Cryptomator/Plugins" -Dcryptomator.integrationsWin.keychainPaths="@{appdata}/Cryptomator/keychain.json;@{userhome}/AppData/Roaming/Cryptomator/keychain.json" -Dcryptomator.integrationsWin.windowsHelloKeychainPaths="@{appdata}/Cryptomator/windowsHelloKeychain.json;@{userhome}/AppData/Roaming/Cryptomator/windowsHelloKeychain.json" -Dcryptomator.p12Path="@{appdata}/Cryptomator/key.p12;@{userhome}/AppData/Roaming/Cryptomator/key.p12" -Dcryptomator.mountPointsDir="@{userhome}/Cryptomator" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.win,org.cryptomator.integrations.win" />
|
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="@{appdata}/Cryptomator/settings.json;@{userhome}/AppData/Roaming/Cryptomator/settings.json" -Dcryptomator.ipcSocketPath="@{localappdata}/Cryptomator/ipc.socket" -Dcryptomator.logDir="@{localappdata}/Cryptomator" -Dcryptomator.pluginDir="@{appdata}/Cryptomator/Plugins" -Dcryptomator.integrationsWin.keychainPaths="@{appdata}/Cryptomator/keychain.json;@{userhome}/AppData/Roaming/Cryptomator/keychain.json" -Dcryptomator.integrationsWin.windowsHelloKeychainPaths="@{appdata}/Cryptomator/windowsHelloKeychain.json;@{userhome}/AppData/Roaming/Cryptomator/windowsHelloKeychain.json" -Dcryptomator.p12Path="@{appdata}/Cryptomator/key.p12;@{userhome}/AppData/Roaming/Cryptomator/key.p12" -Dcryptomator.mountPointsDir="@{userhome}/Cryptomator" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.win,org.cryptomator.integrations.win,javafx.graphics" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
<configuration default="false" name="Cryptomator Windows Dev" type="Application" factoryName="Application">
|
<configuration default="false" name="Cryptomator Windows Dev" type="Application" factoryName="Application">
|
||||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||||
<module name="cryptomator" />
|
<module name="cryptomator" />
|
||||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="@{appdata}/Cryptomator-Dev/settings.json;@{userhome}/AppData/Roaming/Cryptomator-Dev/settings.json" -Dcryptomator.ipcSocketPath="@{localappdata}/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="@{localappdata}/Cryptomator-Dev" -Dcryptomator.pluginDir="@{appdata}/Cryptomator-Dev/Plugins" -Dcryptomator.integrationsWin.keychainPaths="@{appdata}/Cryptomator-Dev/keychain.json;@{userhome}/AppData/Roaming/Cryptomator-Dev/keychain.json" -Dcryptomator.integrationsWin.windowsHelloKeychainPaths="@{appdata}/Cryptomator-Dev/windowsHelloKeychain.json;@{userhome}/AppData/Roaming/Cryptomator-Dev/windowsHelloKeychain.json" -Dcryptomator.p12Path="@{appdata}/Cryptomator-Dev/key.p12;@{userhome}/AppData/Roaming/Cryptomator-Dev/key.p12" -Dcryptomator.mountPointsDir="@{userhome}/Cryptomator-Dev" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.win,org.cryptomator.integrations.win" />
|
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="@{appdata}/Cryptomator-Dev/settings.json;@{userhome}/AppData/Roaming/Cryptomator-Dev/settings.json" -Dcryptomator.ipcSocketPath="@{localappdata}/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="@{localappdata}/Cryptomator-Dev" -Dcryptomator.pluginDir="@{appdata}/Cryptomator-Dev/Plugins" -Dcryptomator.integrationsWin.keychainPaths="@{appdata}/Cryptomator-Dev/keychain.json;@{userhome}/AppData/Roaming/Cryptomator-Dev/keychain.json" -Dcryptomator.integrationsWin.windowsHelloKeychainPaths="@{appdata}/Cryptomator-Dev/windowsHelloKeychain.json;@{userhome}/AppData/Roaming/Cryptomator-Dev/windowsHelloKeychain.json" -Dcryptomator.p12Path="@{appdata}/Cryptomator-Dev/key.p12;@{userhome}/AppData/Roaming/Cryptomator-Dev/key.p12" -Dcryptomator.mountPointsDir="@{userhome}/Cryptomator-Dev" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.win,org.cryptomator.integrations.win,javafx.graphics" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
</envs>
|
</envs>
|
||||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||||
<module name="cryptomator" />
|
<module name="cryptomator" />
|
||||||
<option name="VM_PARAMETERS" value="-Dapple.awt.enableTemplateImages=true -Dcryptomator.settingsPath="@{userhome}/Library/Application Support/Cryptomator/settings.json" -Dcryptomator.p12Path="@{userhome}/Library/Application Support/Cryptomator/key.p12" -Dcryptomator.ipcSocketPath="@{userhome}/Library/Application Support/Cryptomator/ipc.socket" -Dcryptomator.logDir="@{userhome}/Library/Logs/Cryptomator" -Dcryptomator.pluginDir="@{userhome}/Library/Application Support/Cryptomator/Plugins" -Dcryptomator.mountPointsDir="@{userhome}/Cryptomator" -Dcryptomator.showTrayIcon=true -Dcryptomator.integrationsMac.keychainServiceName=Cryptomator -Xss2m -Xmx512m -ea --enable-preview --enable-native-access=org.cryptomator.jfuse.mac" />
|
<option name="VM_PARAMETERS" value="-Dapple.awt.enableTemplateImages=true -Dcryptomator.settingsPath="@{userhome}/Library/Application Support/Cryptomator/settings.json" -Dcryptomator.p12Path="@{userhome}/Library/Application Support/Cryptomator/key.p12" -Dcryptomator.ipcSocketPath="@{userhome}/Library/Application Support/Cryptomator/ipc.socket" -Dcryptomator.logDir="@{userhome}/Library/Logs/Cryptomator" -Dcryptomator.pluginDir="@{userhome}/Library/Application Support/Cryptomator/Plugins" -Dcryptomator.mountPointsDir="@{userhome}/Cryptomator" -Dcryptomator.showTrayIcon=true -Dcryptomator.integrationsMac.keychainServiceName=Cryptomator -Xss2m -Xmx512m -ea --enable-preview --enable-native-access=org.cryptomator.jfuse.mac,javafx.graphics" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
</envs>
|
</envs>
|
||||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||||
<module name="cryptomator" />
|
<module name="cryptomator" />
|
||||||
<option name="VM_PARAMETERS" value="-Dapple.awt.enableTemplateImages=true -Dcryptomator.settingsPath="@{userhome}/Library/Application Support/Cryptomator-Dev/settings.json" -Dcryptomator.p12Path="@{userhome}/Library/Application Support/Cryptomator-Dev/key.p12" -Dcryptomator.ipcSocketPath="@{userhome}/Library/Application Support/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="@{userhome}/Library/Logs/Cryptomator-Dev" -Dcryptomator.pluginDir="@{userhome}/Library/Application Support/Cryptomator-Dev/Plugins" -Dcryptomator.mountPointsDir="@{userhome}/Library/Application Support/Cryptomator-Dev/mnt" -Dcryptomator.showTrayIcon=true -Dcryptomator.integrationsMac.keychainServiceName=Cryptomator -Xss2m -Xmx512m -ea --enable-preview --enable-native-access=org.cryptomator.jfuse.mac" />
|
<option name="VM_PARAMETERS" value="-Dapple.awt.enableTemplateImages=true -Dcryptomator.settingsPath="@{userhome}/Library/Application Support/Cryptomator-Dev/settings.json" -Dcryptomator.p12Path="@{userhome}/Library/Application Support/Cryptomator-Dev/key.p12" -Dcryptomator.ipcSocketPath="@{userhome}/Library/Application Support/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="@{userhome}/Library/Logs/Cryptomator-Dev" -Dcryptomator.pluginDir="@{userhome}/Library/Application Support/Cryptomator-Dev/Plugins" -Dcryptomator.mountPointsDir="@{userhome}/Library/Application Support/Cryptomator-Dev/mnt" -Dcryptomator.showTrayIcon=true -Dcryptomator.integrationsMac.keychainServiceName=Cryptomator -Xss2m -Xmx512m -ea --enable-preview --enable-native-access=org.cryptomator.jfuse.mac,javafx.graphics" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Make" enabled="true" />
|
<option name="Make" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
[](https://cryptomator.org/)
|
[](https://cryptomator.org/)
|
||||||
|
|
||||||
[](https://github.com/cryptomator/cryptomator/actions?query=workflow%3ABuild)
|
[](https://github.com/cryptomator/cryptomator/actions/workflows/build.yml?query=branch%3Adevelop)
|
||||||
[](https://snyk.io/test/github/cryptomator/cryptomator)
|
[](https://snyk.io/test/github/cryptomator/cryptomator)
|
||||||
[](https://sonarcloud.io/dashboard?id=cryptomator_cryptomator)
|
[](https://sonarcloud.io/dashboard?id=cryptomator_cryptomator)
|
||||||
[](http://twitter.com/Cryptomator)
|
[](https://mastodon.online/@cryptomator)
|
||||||
[](https://translate.cryptomator.org/)
|
[](https://translate.cryptomator.org/)
|
||||||
[](https://github.com/cryptomator/cryptomator/releases/latest)
|
[](https://github.com/cryptomator/cryptomator/releases/latest)
|
||||||
[](https://community.cryptomator.org)
|
[](https://community.cryptomator.org)
|
||||||
@@ -32,9 +32,9 @@ Become our Gold Sponsor and showcase your brand to a targeted audience! Please c
|
|||||||
|
|
||||||
### Special Shoutout
|
### Special Shoutout
|
||||||
|
|
||||||
Continuous integration hosting for ARM64 builds is provided by [MacStadium](https://www.macstadium.com/opensource).
|
Continuous integration hosting for ARM64 builds is provided by [MacStadium](https://www.macstadium.com/company/opensource).
|
||||||
|
|
||||||
<a href="https://www.macstadium.com/opensource"><img src="https://uploads-ssl.webflow.com/5ac3c046c82724970fc60918/5c019d917bba312af7553b49_MacStadium-developerlogo.png" alt="MacStadium" height="100"></a>
|
<a href="https://www.macstadium.com/company/opensource"><img src="https://uploads-ssl.webflow.com/5ac3c046c82724970fc60918/5c019d917bba312af7553b49_MacStadium-developerlogo.png" alt="MacStadium" height="100"></a>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ Download native binaries of Cryptomator on [cryptomator.org](https://cryptomator
|
|||||||
- File names get encrypted
|
- File names get encrypted
|
||||||
- Folder structure gets obfuscated
|
- Folder structure gets obfuscated
|
||||||
- Use as many vaults in your Dropbox as you want, each having individual passwords
|
- Use as many vaults in your Dropbox as you want, each having individual passwords
|
||||||
- Four thousand commits for the security of your data!! :tada:
|
- More than Five thousand commits for the security of your data!! :tada:
|
||||||
|
|
||||||
### Privacy
|
### Privacy
|
||||||
|
|
||||||
@@ -72,13 +72,13 @@ Download native binaries of Cryptomator on [cryptomator.org](https://cryptomator
|
|||||||
|
|
||||||
### Security Architecture
|
### Security Architecture
|
||||||
|
|
||||||
For more information on the security details visit [cryptomator.org](https://docs.cryptomator.org/en/latest/security/architecture/).
|
For more information on the security details visit [cryptomator.org](https://docs.cryptomator.org/security/architecture/).
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
|
|
||||||
* JDK 22 (e.g. temurin, zulu)
|
* JDK 24 (e.g. temurin, zulu)
|
||||||
* Maven 3
|
* Maven 3
|
||||||
|
|
||||||
### Run Maven
|
### Run Maven
|
||||||
|
|||||||
Vendored
+19
-12
@@ -12,7 +12,7 @@ command -v unzip >/dev/null 2>&1 || { echo >&2 "unzip not found."; exit 1; }
|
|||||||
|
|
||||||
VERSION=$(mvn -f ../../../pom.xml help:evaluate -Dexpression=project.version -q -DforceStdout)
|
VERSION=$(mvn -f ../../../pom.xml help:evaluate -Dexpression=project.version -q -DforceStdout)
|
||||||
SEMVER_STR=${VERSION}
|
SEMVER_STR=${VERSION}
|
||||||
CPU_ARCH=$(uname -p)
|
CPU_ARCH=$(uname -m)
|
||||||
|
|
||||||
if [[ ! "${CPU_ARCH}" =~ x86_64|aarch64 ]]; then echo "Platform ${CPU_ARCH} not supported"; exit 1; fi
|
if [[ ! "${CPU_ARCH}" =~ x86_64|aarch64 ]]; then echo "Platform ${CPU_ARCH} not supported"; exit 1; fi
|
||||||
|
|
||||||
@@ -23,12 +23,12 @@ mvn -B -f ../../../pom.xml clean package -Plinux -DskipTests -Djavafx.platform=l
|
|||||||
cp ../../../LICENSE.txt ../../../target
|
cp ../../../LICENSE.txt ../../../target
|
||||||
cp ../../../target/cryptomator-*.jar ../../../target/mods
|
cp ../../../target/cryptomator-*.jar ../../../target/mods
|
||||||
|
|
||||||
JAVAFX_VERSION=22.0.2
|
JAVAFX_VERSION=24.0.1
|
||||||
JAVAFX_ARCH="x64"
|
JAVAFX_ARCH="x64"
|
||||||
JAVAFX_JMODS_SHA256='d44bff3b94d5668fdee18a938d7b1269026d663d44765f02d29a9bdfd3fa1eb0'
|
JAVAFX_JMODS_SHA256='425fac742b9fbd095b2ce868cff82d1024620f747c94a7144d0a4879e756146c'
|
||||||
if [ "${CPU_ARCH}" = "aarch64" ]; then
|
if [ "${CPU_ARCH}" = "aarch64" ]; then
|
||||||
JAVAFX_ARCH="aarch64"
|
JAVAFX_ARCH="aarch64"
|
||||||
JAVAFX_JMODS_SHA256='3d5457136690c4f5bb9522d38b45218e045bdac13c24aa4c808c7c8d17d039c7'
|
JAVAFX_JMODS_SHA256='7e02edd0f4ee5527a27c94b0bbba66fcaaff41009119e45d0eca0f96ddfb6e7b'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# download javaFX jmods
|
# download javaFX jmods
|
||||||
@@ -51,11 +51,17 @@ if [ $POM_JFX_VERSION -ne $JMOD_VERSION ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
# add runtime
|
# create runtime
|
||||||
|
## check for JEP 493
|
||||||
|
JMOD_PATHS="openjfx-jmods"
|
||||||
|
if ! ${JAVA_HOME}/bin/jlink --help | grep -q "Linking from run-time image enabled"; then
|
||||||
|
JMOD_PATHS="${JAVA_HOME}/jmods:${JMOD_PATHS}"
|
||||||
|
fi
|
||||||
|
## create runtime image
|
||||||
${JAVA_HOME}/bin/jlink \
|
${JAVA_HOME}/bin/jlink \
|
||||||
--verbose \
|
--verbose \
|
||||||
--output runtime \
|
--output runtime \
|
||||||
--module-path "${JAVA_HOME}/jmods:openjfx-jmods" \
|
--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.unsupported,jdk.security.auth,jdk.accessibility,jdk.management.jfr,jdk.net,java.compiler \
|
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.security.auth,jdk.accessibility,jdk.management.jfr,jdk.net,java.compiler \
|
||||||
--strip-native-commands \
|
--strip-native-commands \
|
||||||
--no-header-files \
|
--no-header-files \
|
||||||
@@ -75,8 +81,8 @@ ${JAVA_HOME}/bin/jpackage \
|
|||||||
--name Cryptomator \
|
--name Cryptomator \
|
||||||
--vendor "Skymatic GmbH" \
|
--vendor "Skymatic GmbH" \
|
||||||
--java-options "--enable-preview" \
|
--java-options "--enable-preview" \
|
||||||
--java-options "--enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator" \
|
--java-options "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator" \
|
||||||
--copyright "(C) 2016 - 2024 Skymatic GmbH" \
|
--copyright "(C) 2016 - 2025 Skymatic GmbH" \
|
||||||
--java-options "-Xss5m" \
|
--java-options "-Xss5m" \
|
||||||
--java-options "-Xmx256m" \
|
--java-options "-Xmx256m" \
|
||||||
--app-version "${VERSION}.${REVISION_NO}" \
|
--app-version "${VERSION}.${REVISION_NO}" \
|
||||||
@@ -91,6 +97,7 @@ ${JAVA_HOME}/bin/jpackage \
|
|||||||
--java-options "-Dcryptomator.showTrayIcon=true" \
|
--java-options "-Dcryptomator.showTrayIcon=true" \
|
||||||
--java-options "-Dcryptomator.integrationsLinux.trayIconsDir=\"@{appdir}/usr/share/icons/hicolor/symbolic/apps\"" \
|
--java-options "-Dcryptomator.integrationsLinux.trayIconsDir=\"@{appdir}/usr/share/icons/hicolor/symbolic/apps\"" \
|
||||||
--java-options "-Dcryptomator.buildNumber=\"appimage-${REVISION_NO}\"" \
|
--java-options "-Dcryptomator.buildNumber=\"appimage-${REVISION_NO}\"" \
|
||||||
|
--java-options "-Dcryptomator.networking.truststore.p12Path=\"/etc/cryptomator/certs.p12\"" \
|
||||||
--resource-dir ../resources
|
--resource-dir ../resources
|
||||||
|
|
||||||
# transform AppDir
|
# transform AppDir
|
||||||
@@ -108,20 +115,20 @@ cp ../common/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/usr/share/ap
|
|||||||
cp ../common/org.cryptomator.Cryptomator.metainfo.xml Cryptomator.AppDir/usr/share/metainfo/org.cryptomator.Cryptomator.metainfo.xml
|
cp ../common/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.vault.xml Cryptomator.AppDir/usr/share/mime/packages/application-vnd.cryptomator.vault.xml
|
||||||
ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/org.cryptomator.Cryptomator.svg
|
ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/org.cryptomator.Cryptomator.svg
|
||||||
ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/Cryptomator.svg
|
|
||||||
ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/.DirIcon
|
ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/.DirIcon
|
||||||
ln -s usr/share/applications/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/Cryptomator.desktop
|
ln -s usr/share/applications/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/org.cryptomator.Cryptomator.desktop
|
||||||
|
ln -s org.cryptomator.Cryptomator.metainfo.xml Cryptomator.AppDir/usr/share/metainfo/org.cryptomator.Cryptomator.appdata.xml
|
||||||
ln -s bin/cryptomator.sh Cryptomator.AppDir/AppRun
|
ln -s bin/cryptomator.sh Cryptomator.AppDir/AppRun
|
||||||
|
|
||||||
# load AppImageTool
|
# load AppImageTool
|
||||||
curl -L https://github.com/AppImage/AppImageKit/releases/download/13/appimagetool-${CPU_ARCH}.AppImage -o /tmp/appimagetool.AppImage
|
curl -L https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-${CPU_ARCH}.AppImage -o /tmp/appimagetool.AppImage
|
||||||
chmod +x /tmp/appimagetool.AppImage
|
chmod +x /tmp/appimagetool.AppImage
|
||||||
|
|
||||||
# create AppImage
|
# create AppImage
|
||||||
/tmp/appimagetool.AppImage \
|
/tmp/appimagetool.AppImage \
|
||||||
Cryptomator.AppDir \
|
Cryptomator.AppDir \
|
||||||
cryptomator-${SEMVER_STR}-${CPU_ARCH}.AppImage \
|
cryptomator-${SEMVER_STR}-${CPU_ARCH}.AppImage \
|
||||||
-u 'gh-releases-zsync|cryptomator|cryptomator|latest|cryptomator-*-${CPU_ARCH}.AppImage.zsync'
|
-u "gh-releases-zsync|cryptomator|cryptomator|latest|cryptomator-*-${CPU_ARCH}.AppImage.zsync"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Done. AppImage successfully created: cryptomator-${SEMVER_STR}-${CPU_ARCH}.AppImage"
|
echo "Done. AppImage successfully created: cryptomator-${SEMVER_STR}-${CPU_ARCH}.AppImage"
|
||||||
|
|||||||
+39
-6
@@ -1,11 +1,16 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!-- Copyright 2018 Armin Schrenk <armin.schrenk@zoho.eu> -->
|
|
||||||
<component type="desktop-application">
|
<component type="desktop-application">
|
||||||
<id>org.cryptomator.Cryptomator</id>
|
<id>org.cryptomator.Cryptomator</id>
|
||||||
<metadata_license>FSFAP</metadata_license>
|
<metadata_license>FSFAP</metadata_license>
|
||||||
<project_license>GPL-3.0-or-later</project_license>
|
<project_license>GPL-3.0-or-later</project_license>
|
||||||
<name>Cryptomator</name>
|
<name>Cryptomator</name>
|
||||||
<summary>Encryption made easy and optimized for the cloud</summary>
|
<summary>Encryption for your cloud made easy</summary>
|
||||||
|
|
||||||
|
<keywords>
|
||||||
|
<keyword>encryption</keyword>
|
||||||
|
<keyword>security</keyword>
|
||||||
|
<keyword>privacy</keyword>
|
||||||
|
</keywords>
|
||||||
|
|
||||||
<description>
|
<description>
|
||||||
<p>
|
<p>
|
||||||
@@ -44,12 +49,16 @@
|
|||||||
|
|
||||||
<screenshots>
|
<screenshots>
|
||||||
<screenshot type="default">
|
<screenshot type="default">
|
||||||
<caption>Light theme</caption>
|
<caption>Encrypts your data, protects your privacy</caption>
|
||||||
<image>https://user-images.githubusercontent.com/11858409/156986109-6e58f59c-8b8c-4501-b33b-bb1e33007cea.png</image>
|
<image>https://static.cryptomator.org/desktop/flathubScreenshots/MainWindowUnlockDialog_light.png</image>
|
||||||
</screenshot>
|
</screenshot>
|
||||||
<screenshot>
|
<screenshot>
|
||||||
<caption>Dark theme</caption>
|
<caption>Dark theme available</caption>
|
||||||
<image>https://user-images.githubusercontent.com/11858409/156986113-6c5d7801-86e0-4643-bc2f-aff9d95d3ce0.png</image>
|
<image>https://static.cryptomator.org/desktop/flathubScreenshots/MainWindowUnlocked_dark.png</image>
|
||||||
|
</screenshot>
|
||||||
|
<screenshot>
|
||||||
|
<caption>Easy to use - work on encrypted files as if they were not</caption>
|
||||||
|
<image>https://static.cryptomator.org/desktop/flathubScreenshots/MainWindowUnlocked_light.png</image>
|
||||||
</screenshot>
|
</screenshot>
|
||||||
</screenshots>
|
</screenshots>
|
||||||
|
|
||||||
@@ -74,6 +83,30 @@
|
|||||||
</content_rating>
|
</content_rating>
|
||||||
|
|
||||||
<releases>
|
<releases>
|
||||||
|
<release date="2025-06-24" version="1.17.0">
|
||||||
|
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.17.0</url>
|
||||||
|
</release>
|
||||||
|
<release date="2025-05-15" version="1.16.2">
|
||||||
|
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.16.2</url>
|
||||||
|
</release>
|
||||||
|
<release date="2025-04-30" version="1.16.1">
|
||||||
|
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.16.1</url>
|
||||||
|
</release>
|
||||||
|
<release date="2025-04-29" version="1.16.0">
|
||||||
|
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.16.0</url>
|
||||||
|
</release>
|
||||||
|
<release date="2025-04-09" version="1.15.3">
|
||||||
|
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.15.3</url>
|
||||||
|
</release>
|
||||||
|
<release date="2025-04-04" version="1.15.2">
|
||||||
|
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.15.2</url>
|
||||||
|
</release>
|
||||||
|
<release date="2025-02-05" version="1.15.1">
|
||||||
|
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.15.1</url>
|
||||||
|
</release>
|
||||||
|
<release date="2025-02-03" version="1.15.0">
|
||||||
|
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.15.0</url>
|
||||||
|
</release>
|
||||||
<release date="2024-11-19" version="1.14.2">
|
<release date="2024-11-19" version="1.14.2">
|
||||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.14.2</url>
|
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.14.2</url>
|
||||||
</release>
|
</release>
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
<svg height="16" viewBox="0 0 42 42" width="16" xmlns="http://www.w3.org/2000/svg">
|
<svg height="16" viewBox="0 0 42 42" width="16" xmlns="http://www.w3.org/2000/svg">
|
||||||
<style
|
<defs>
|
||||||
id="current-color-scheme" type="text/css">
|
<style id="current-color-scheme" type="text/css">
|
||||||
.ColorScheme-Text {
|
.ColorScheme-Text {
|
||||||
color:#232629;
|
color:#222222;
|
||||||
}
|
}
|
||||||
</style>
|
.ColorScheme-Highlight {
|
||||||
<g fill-rule="evenodd" style="fill:#f2f2f2;fill-opacity:1" class="ColorScheme-Text" fill="currentColor">
|
color:#49B04A;
|
||||||
<path d="m15.591 35.824c-.019.009-.936.775-1.458 1.208a.418.418 0 0 1 -.627-.111 9.322 9.322 0 0 1 -.3-5.974 15.843 15.843 0 0 0 2.894 2.043c.051 1.03-.161 2.644-.509 2.834zm6.409-6.824h-2l.5-5a2 2 0 1 1 1 0zm-14.544-3.241.744-1.366a1.579 1.579 0 0 0 -.019-1.557l.653-1.2c.2.014-.03-.113.165-.14.051-.217-.051-.336 0-.5a3.269 3.269 0 0 0 0-1.5 7.151 7.151 0 0 1 0-3 2.366 2.366 0 0 0 -2.378 1.448 2.409 2.409 0 0 0 .229 2.661l-.7 1.278a1.779 1.779 0 0 0 -1.317.891l-.741 1.372a1.577 1.577 0 0 0 -.019 1.487 3.028 3.028 0 0 0 -2.746 1.525 2.648 2.648 0 0 0 .044 2.631.748.748 0 0 0 .981.266.656.656 0 0 0 .284-.92 1.37 1.37 0 0 1 -.023-1.361 1.6 1.6 0 0 1 2.079-.63 1.408 1.408 0 0 1 .672 1.95 1.546 1.546 0 0 1 -1.2.78.688.688 0 0 0 -.636.749.707.707 0 0 0 .717.6.789.789 0 0 0 .082 0 2.989 2.989 0 0 0 2.322-1.513 2.669 2.669 0 0 0 -.377-3.084 1.767 1.767 0 0 0 1.184-.867zm13.544-10.759a13.013 13.013 0 0 1 5-1 21.6 21.6 0 0 1 4.5.5 9.312 9.312 0 0 0 -9.5-8.5c-5.794 0-9.176 4-9.5 8.5a21.858 21.858 0 0 1 4.5-.5 12.819 12.819 0 0 1 5 1zm3.5-5c1.209 0 2.5.866 2.5 2h-5c0-1.134 1.291-2 2.5-2zm-7 0c1.209 0 2.5.866 2.5 2h-5c0-1.134 1.291-2 2.5-2zm14.473 6a8.067 8.067 0 0 0 -8.08 8v2.141a3.891 3.891 0 0 0 -2.893 3.734v5.125a23.166 23.166 0 0 1 -4.174-1.623 7.857 7.857 0 0 1 -.027.878 3.263 3.263 0 0 1 -.729 2.074l-1.794 1.483a.379.379 0 0 1 -.276.188h-4c-1.324 0-2.346-1.336-2.653-3.343a7.058 7.058 0 0 1 .234-3.18 3.477 3.477 0 0 1 1.636-2.157 1.868 1.868 0 0 1 .783-.32h1.5a8.035 8.035 0 0 1 -1.5-5 11.1 11.1 0 0 1 .5-3 2.519 2.519 0 0 0 0-1.5 13.272 13.272 0 0 1 -.5-3.5c6.687-1.936 11 0 11 0s4.319-1.955 11 0"/>
|
}
|
||||||
<path d="m39 28h-10v-4a3.13 3.13 0 0 1 3-3 3.087 3.087 0 0 1 3 3v1a1.034 1.034 0 0 0 1 1h1a1.034 1.034 0 0 0 1-1v-1a6 6 0 0 0 -12 0v4h-1a2.073 2.073 0 0 0 -2 2v6a2.073 2.073 0 0 0 2 2h14a2.073 2.073 0 0 0 2-2v-6a2.073 2.073 0 0 0 -2-2zm-5.391 5.94a1.609 1.609 0 0 1 -3.217 0v-1.876a1.609 1.609 0 0 1 3.217 0z"/>
|
</style>
|
||||||
|
</defs>
|
||||||
|
<g fill-rule="evenodd">
|
||||||
|
<path d="m15.591 35.824c-.019.009-.936.775-1.458 1.208a.418.418 0 0 1 -.627-.111 9.322 9.322 0 0 1 -.3-5.974 15.843 15.843 0 0 0 2.894 2.043c.051 1.03-.161 2.644-.509 2.834zm6.409-6.824h-2l.5-5a2 2 0 1 1 1 0zm-14.544-3.241.744-1.366a1.579 1.579 0 0 0 -.019-1.557l.653-1.2c.2.014-.03-.113.165-.14.051-.217-.051-.336 0-.5a3.269 3.269 0 0 0 0-1.5 7.151 7.151 0 0 1 0-3 2.366 2.366 0 0 0 -2.378 1.448 2.409 2.409 0 0 0 .229 2.661l-.7 1.278a1.779 1.779 0 0 0 -1.317.891l-.741 1.372a1.577 1.577 0 0 0 -.019 1.487 3.028 3.028 0 0 0 -2.746 1.525 2.648 2.648 0 0 0 .044 2.631.748.748 0 0 0 .981.266.656.656 0 0 0 .284-.92 1.37 1.37 0 0 1 -.023-1.361 1.6 1.6 0 0 1 2.079-.63 1.408 1.408 0 0 1 .672 1.95 1.546 1.546 0 0 1 -1.2.78.688.688 0 0 0 -.636.749.707.707 0 0 0 .717.6.789.789 0 0 0 .082 0 2.989 2.989 0 0 0 2.322-1.513 2.669 2.669 0 0 0 -.377-3.084 1.767 1.767 0 0 0 1.184-.867zm13.544-10.759a13.013 13.013 0 0 1 5-1 21.6 21.6 0 0 1 4.5.5 9.312 9.312 0 0 0 -9.5-8.5c-5.794 0-9.176 4-9.5 8.5a21.858 21.858 0 0 1 4.5-.5 12.819 12.819 0 0 1 5 1zm3.5-5c1.209 0 2.5.866 2.5 2h-5c0-1.134 1.291-2 2.5-2zm-7 0c1.209 0 2.5.866 2.5 2h-5c0-1.134 1.291-2 2.5-2zm14.473 6a8.067 8.067 0 0 0 -8.08 8v2.141a3.891 3.891 0 0 0 -2.893 3.734v5.125a23.166 23.166 0 0 1 -4.174-1.623 7.857 7.857 0 0 1 -.027.878 3.263 3.263 0 0 1 -.729 2.074l-1.794 1.483a.379.379 0 0 1 -.276.188h-4c-1.324 0-2.346-1.336-2.653-3.343a7.058 7.058 0 0 1 .234-3.18 3.477 3.477 0 0 1 1.636-2.157 1.868 1.868 0 0 1 .783-.32h1.5a8.035 8.035 0 0 1 -1.5-5 11.1 11.1 0 0 1 .5-3 2.519 2.519 0 0 0 0-1.5 13.272 13.272 0 0 1 -.5-3.5c6.687-1.936 11 0 11 0s4.319-1.955 11 0" class="ColorScheme-Text" fill="currentColor"/>
|
||||||
|
<path d="m39 28h-10v-4a3.13 3.13 0 0 1 3-3 3.087 3.087 0 0 1 3 3v1a1.034 1.034 0 0 0 1 1h1a1.034 1.034 0 0 0 1-1v-1a6 6 0 0 0 -12 0v4h-1a2.073 2.073 0 0 0 -2 2v6a2.073 2.073 0 0 0 2 2h14a2.073 2.073 0 0 0 2-2v-6a2.073 2.073 0 0 0 -2-2zm-5.391 5.94a1.609 1.609 0 0 1 -3.217 0v-1.876a1.609 1.609 0 0 1 3.217 0z" class="ColorScheme-Highlight" fill="currentColor"/>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.3 KiB |
+8
-6
@@ -1,8 +1,10 @@
|
|||||||
<svg height="16" viewBox="0 0 42 42" width="16" xmlns="http://www.w3.org/2000/svg">
|
<svg height="16" viewBox="0 0 42 42" width="16" xmlns="http://www.w3.org/2000/svg">
|
||||||
<style id="current-color-scheme" type="text/css">
|
<defs>
|
||||||
.ColorScheme-Text {
|
<style id="current-color-scheme" type="text/css">
|
||||||
color:#232629;
|
.ColorScheme-Text {
|
||||||
}
|
color:#222222;
|
||||||
</style>
|
}
|
||||||
<path d="m32.66 29.319a1.432 1.432 0 0 0 -.66-.319h-1.5a8.125 8.125 0 0 0 1.5-5 11.027 11.027 0 0 0 -.5-3 2.519 2.519 0 0 1 0-1.5 12.987 12.987 0 0 0 .5-3.5c-6.681-1.955-11 0-11 0s-4.313-1.936-11 0a13.272 13.272 0 0 0 .5 3.5 2.519 2.519 0 0 1 0 1.5 11.1 11.1 0 0 0 -.5 3 8.035 8.035 0 0 0 1.5 5h-1.5a1.868 1.868 0 0 0 -.783.319 3.477 3.477 0 0 0 -1.636 2.157 7.058 7.058 0 0 0 -.234 3.18c.307 2.008 1.329 3.344 2.653 3.344h4a.379.379 0 0 0 .277-.187l1.793-1.483a3.263 3.263 0 0 0 .729-2.074 7.857 7.857 0 0 0 .027-.878 23.166 23.166 0 0 0 4.174 1.622 24.4 24.4 0 0 0 4.051-1.614 7.848 7.848 0 0 0 .027.869 3.263 3.263 0 0 0 .729 2.074l1.793 1.484a.61.61 0 0 0 .4.187h4c1.324 0 2.223-1.336 2.529-3.343a7.057 7.057 0 0 0 -.234-3.18 3.477 3.477 0 0 0 -1.635-2.158zm-17.069 6.5c-.019.009-.936.775-1.458 1.208a.418.418 0 0 1 -.627-.111 9.322 9.322 0 0 1 -.3-5.974 15.843 15.843 0 0 0 2.894 2.048c.051 1.03-.161 2.644-.509 2.834zm6.409-6.819h-2l.5-5a2 2 0 1 1 1 0zm6.38 7.921a.418.418 0 0 1 -.627.111c-.522-.433-1.439-1.2-1.458-1.208-.348-.189-.56-1.8-.505-2.828a15.84 15.84 0 0 0 2.9-2.037 9.322 9.322 0 0 1 -.31 5.962zm-20.924-11.162.744-1.366a1.579 1.579 0 0 0 -.019-1.557l.653-1.2c.2.014-.03-.113.165-.14.051-.217-.051-.336 0-.5a3.269 3.269 0 0 0 0-1.5 7.151 7.151 0 0 1 0-3 2.366 2.366 0 0 0 -2.378 1.448 2.409 2.409 0 0 0 .229 2.661l-.7 1.278a1.779 1.779 0 0 0 -1.317.891l-.741 1.372a1.577 1.577 0 0 0 -.019 1.487 3.028 3.028 0 0 0 -2.746 1.525 2.648 2.648 0 0 0 .044 2.631.748.748 0 0 0 .981.266.656.656 0 0 0 .284-.92 1.37 1.37 0 0 1 -.023-1.361 1.6 1.6 0 0 1 2.079-.63 1.408 1.408 0 0 1 .672 1.95 1.546 1.546 0 0 1 -1.2.78.688.688 0 0 0 -.636.749.707.707 0 0 0 .717.6.789.789 0 0 0 .082 0 2.989 2.989 0 0 0 2.322-1.513 2.669 2.669 0 0 0 -.377-3.084 1.767 1.767 0 0 0 1.184-.867zm33.217 1.2a3.021 3.021 0 0 0 -2.658-1.525 1.574 1.574 0 0 0 -.107-1.283l-.745-1.367a1.779 1.779 0 0 0 -1.317-.891l-.7-1.278a2.409 2.409 0 0 0 .229-2.661 2.283 2.283 0 0 0 -2.375-1.454 7.039 7.039 0 0 1 0 3 3.272 3.272 0 0 0 0 1.5c.047.152-.047.3 0 .5.227.04-.069.156.165.14l.653 1.2a1.579 1.579 0 0 0 -.019 1.557l.745 1.367a1.753 1.753 0 0 0 1.045.832 2.66 2.66 0 0 0 -.238 2.916 2.989 2.989 0 0 0 2.326 1.509.79.79 0 0 0 .082 0 .707.707 0 0 0 .717-.6.688.688 0 0 0 -.636-.749 1.546 1.546 0 0 1 -1.2-.78 1.408 1.408 0 0 1 .672-1.95 1.628 1.628 0 0 1 1.179-.089 1.512 1.512 0 0 1 .9.719 1.37 1.37 0 0 1 -.023 1.361.656.656 0 0 0 .284.92.748.748 0 0 0 .981-.266 2.648 2.648 0 0 0 .04-2.633zm-19.673-11.959a13.013 13.013 0 0 1 5-1 21.6 21.6 0 0 1 4.5.5 9.312 9.312 0 0 0 -9.5-8.5c-5.794 0-9.176 4-9.5 8.5a21.858 21.858 0 0 1 4.5-.5 12.819 12.819 0 0 1 5 1zm3.5-5c1.209 0 2.5.866 2.5 2h-5c0-1.134 1.291-2 2.5-2zm-7 0c1.209 0 2.5.866 2.5 2h-5c0-1.134 1.291-2 2.5-2z" fill-rule="evenodd" style="fill:#f2f2f2;fill-opacity:1" class="ColorScheme-Text" fill="currentColor"/>
|
</style>
|
||||||
|
</defs>
|
||||||
|
<path d="m32.66 29.319a1.432 1.432 0 0 0 -.66-.319h-1.5a8.125 8.125 0 0 0 1.5-5 11.027 11.027 0 0 0 -.5-3 2.519 2.519 0 0 1 0-1.5 12.987 12.987 0 0 0 .5-3.5c-6.681-1.955-11 0-11 0s-4.313-1.936-11 0a13.272 13.272 0 0 0 .5 3.5 2.519 2.519 0 0 1 0 1.5 11.1 11.1 0 0 0 -.5 3 8.035 8.035 0 0 0 1.5 5h-1.5a1.868 1.868 0 0 0 -.783.319 3.477 3.477 0 0 0 -1.636 2.157 7.058 7.058 0 0 0 -.234 3.18c.307 2.008 1.329 3.344 2.653 3.344h4a.379.379 0 0 0 .277-.187l1.793-1.483a3.263 3.263 0 0 0 .729-2.074 7.857 7.857 0 0 0 .027-.878 23.166 23.166 0 0 0 4.174 1.622 24.4 24.4 0 0 0 4.051-1.614 7.848 7.848 0 0 0 .027.869 3.263 3.263 0 0 0 .729 2.074l1.793 1.484a.61.61 0 0 0 .4.187h4c1.324 0 2.223-1.336 2.529-3.343a7.057 7.057 0 0 0 -.234-3.18 3.477 3.477 0 0 0 -1.635-2.158zm-17.069 6.5c-.019.009-.936.775-1.458 1.208a.418.418 0 0 1 -.627-.111 9.322 9.322 0 0 1 -.3-5.974 15.843 15.843 0 0 0 2.894 2.048c.051 1.03-.161 2.644-.509 2.834zm6.409-6.819h-2l.5-5a2 2 0 1 1 1 0zm6.38 7.921a.418.418 0 0 1 -.627.111c-.522-.433-1.439-1.2-1.458-1.208-.348-.189-.56-1.8-.505-2.828a15.84 15.84 0 0 0 2.9-2.037 9.322 9.322 0 0 1 -.31 5.962zm-20.924-11.162.744-1.366a1.579 1.579 0 0 0 -.019-1.557l.653-1.2c.2.014-.03-.113.165-.14.051-.217-.051-.336 0-.5a3.269 3.269 0 0 0 0-1.5 7.151 7.151 0 0 1 0-3 2.366 2.366 0 0 0 -2.378 1.448 2.409 2.409 0 0 0 .229 2.661l-.7 1.278a1.779 1.779 0 0 0 -1.317.891l-.741 1.372a1.577 1.577 0 0 0 -.019 1.487 3.028 3.028 0 0 0 -2.746 1.525 2.648 2.648 0 0 0 .044 2.631.748.748 0 0 0 .981.266.656.656 0 0 0 .284-.92 1.37 1.37 0 0 1 -.023-1.361 1.6 1.6 0 0 1 2.079-.63 1.408 1.408 0 0 1 .672 1.95 1.546 1.546 0 0 1 -1.2.78.688.688 0 0 0 -.636.749.707.707 0 0 0 .717.6.789.789 0 0 0 .082 0 2.989 2.989 0 0 0 2.322-1.513 2.669 2.669 0 0 0 -.377-3.084 1.767 1.767 0 0 0 1.184-.867zm33.217 1.2a3.021 3.021 0 0 0 -2.658-1.525 1.574 1.574 0 0 0 -.107-1.283l-.745-1.367a1.779 1.779 0 0 0 -1.317-.891l-.7-1.278a2.409 2.409 0 0 0 .229-2.661 2.283 2.283 0 0 0 -2.375-1.454 7.039 7.039 0 0 1 0 3 3.272 3.272 0 0 0 0 1.5c.047.152-.047.3 0 .5.227.04-.069.156.165.14l.653 1.2a1.579 1.579 0 0 0 -.019 1.557l.745 1.367a1.753 1.753 0 0 0 1.045.832 2.66 2.66 0 0 0 -.238 2.916 2.989 2.989 0 0 0 2.326 1.509.79.79 0 0 0 .082 0 .707.707 0 0 0 .717-.6.688.688 0 0 0 -.636-.749 1.546 1.546 0 0 1 -1.2-.78 1.408 1.408 0 0 1 .672-1.95 1.628 1.628 0 0 1 1.179-.089 1.512 1.512 0 0 1 .9.719 1.37 1.37 0 0 1 -.023 1.361.656.656 0 0 0 .284.92.748.748 0 0 0 .981-.266 2.648 2.648 0 0 0 .04-2.633zm-19.673-11.959a13.013 13.013 0 0 1 5-1 21.6 21.6 0 0 1 4.5.5 9.312 9.312 0 0 0 -9.5-8.5c-5.794 0-9.176 4-9.5 8.5a21.858 21.858 0 0 1 4.5-.5 12.819 12.819 0 0 1 5 1zm3.5-5c1.209 0 2.5.866 2.5 2h-5c0-1.134 1.291-2 2.5-2zm-7 0c1.209 0 2.5.866 2.5 2h-5c0-1.134 1.291-2 2.5-2z" fill-rule="evenodd" class="ColorScheme-Text" fill="currentColor"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
cryptomator (${PPA_VERSION}) focal; urgency=low
|
cryptomator (${PPA_VERSION}) jammy; urgency=low
|
||||||
|
|
||||||
* Full changelog can be found on https://github.com/cryptomator/cryptomator/releases
|
* Full changelog can be found on https://github.com/cryptomator/cryptomator/releases
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -2,7 +2,7 @@ Source: cryptomator
|
|||||||
Maintainer: Cryptobot <releases@cryptomator.org>
|
Maintainer: Cryptobot <releases@cryptomator.org>
|
||||||
Section: utils
|
Section: utils
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Build-Depends: debhelper (>=10), coffeelibs-jdk-22 (>= 22.0.1+8-0ppa1), libgtk-3-0, libxxf86vm1, libgl1
|
Build-Depends: debhelper (>=10), coffeelibs-jdk-24 (>= 24.0.1+9-0ppa3), libgtk-3-0, libxxf86vm1, libgl1
|
||||||
Standards-Version: 4.5.0
|
Standards-Version: 4.5.0
|
||||||
Homepage: https://cryptomator.org
|
Homepage: https://cryptomator.org
|
||||||
Vcs-Git: https://github.com/cryptomator/cryptomator.git
|
Vcs-Git: https://github.com/cryptomator/cryptomator.git
|
||||||
|
|||||||
Vendored
+2
-2
@@ -4,11 +4,11 @@ Upstream-Contact: Cryptomator <info@cryptomator.org>
|
|||||||
Source: https://cryptomator.org
|
Source: https://cryptomator.org
|
||||||
|
|
||||||
Files: *
|
Files: *
|
||||||
Copyright: 2016-2024 Skymatic GmbH
|
Copyright: 2016-2025 Skymatic GmbH
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: debian/org.cryptomator.Cryptomator.appdata.xml
|
Files: debian/org.cryptomator.Cryptomator.appdata.xml
|
||||||
Copyright: 2016-2024 Skymatic GmbH
|
Copyright: 2016-2025 Skymatic GmbH
|
||||||
License: FSFAP
|
License: FSFAP
|
||||||
|
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|||||||
Vendored
+5
-3
@@ -4,7 +4,7 @@
|
|||||||
# Uncomment this to turn on verbose mode.
|
# Uncomment this to turn on verbose mode.
|
||||||
#export DH_VERBOSE=1
|
#export DH_VERBOSE=1
|
||||||
|
|
||||||
JAVA_HOME = /usr/lib/jvm/java-23-coffeelibs
|
JAVA_HOME = /usr/lib/jvm/java-24-coffeelibs
|
||||||
DEB_BUILD_ARCH ?= $(shell dpkg-architecture -qDEB_BUILD_ARCH)
|
DEB_BUILD_ARCH ?= $(shell dpkg-architecture -qDEB_BUILD_ARCH)
|
||||||
ifeq ($(DEB_BUILD_ARCH),amd64)
|
ifeq ($(DEB_BUILD_ARCH),amd64)
|
||||||
JMODS_PATH = jmods/amd64:${JAVA_HOME}/jmods
|
JMODS_PATH = jmods/amd64:${JAVA_HOME}/jmods
|
||||||
@@ -44,8 +44,9 @@ override_dh_auto_build:
|
|||||||
--name cryptomator \
|
--name cryptomator \
|
||||||
--vendor "Skymatic GmbH" \
|
--vendor "Skymatic GmbH" \
|
||||||
--java-options "--enable-preview" \
|
--java-options "--enable-preview" \
|
||||||
--java-options "--enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator" \
|
--java-options "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator" \
|
||||||
--copyright "(C) 2016 - 2024 Skymatic GmbH" \
|
--java-options "--sun-misc-unsafe-memory-access=allow" \
|
||||||
|
--copyright "(C) 2016 - 2025 Skymatic GmbH" \
|
||||||
--java-options "-Xss5m" \
|
--java-options "-Xss5m" \
|
||||||
--java-options "-Xmx256m" \
|
--java-options "-Xmx256m" \
|
||||||
--java-options "-Dfile.encoding=\"utf-8\"" \
|
--java-options "-Dfile.encoding=\"utf-8\"" \
|
||||||
@@ -62,6 +63,7 @@ override_dh_auto_build:
|
|||||||
--java-options "-Dcryptomator.appVersion=\"${SEMVER_STR}\"" \
|
--java-options "-Dcryptomator.appVersion=\"${SEMVER_STR}\"" \
|
||||||
--java-options "-Dcryptomator.disableUpdateCheck=\"${DISABLE_UPDATE_CHECK}\"" \
|
--java-options "-Dcryptomator.disableUpdateCheck=\"${DISABLE_UPDATE_CHECK}\"" \
|
||||||
--java-options "-Dcryptomator.integrationsLinux.autoStartCmd=\"cryptomator\"" \
|
--java-options "-Dcryptomator.integrationsLinux.autoStartCmd=\"cryptomator\"" \
|
||||||
|
--java-options "-Dcryptomator.networking.truststore.p12Path=\"/etc/cryptomator/certs.p12\"" \
|
||||||
--app-version "${VERSION_NUM}.${REVISION_NUM}" \
|
--app-version "${VERSION_NUM}.${REVISION_NUM}" \
|
||||||
--resource-dir resources \
|
--resource-dir resources \
|
||||||
--verbose
|
--verbose
|
||||||
|
|||||||
Vendored
+13
-7
@@ -24,7 +24,7 @@ rm -rf runtime dmg *.app *.dmg
|
|||||||
# set variables
|
# set variables
|
||||||
APP_NAME="Cryptomator"
|
APP_NAME="Cryptomator"
|
||||||
VENDOR="Skymatic GmbH"
|
VENDOR="Skymatic GmbH"
|
||||||
COPYRIGHT_YEARS="2016 - 2024"
|
COPYRIGHT_YEARS="2016 - 2025"
|
||||||
PACKAGE_IDENTIFIER="org.cryptomator"
|
PACKAGE_IDENTIFIER="org.cryptomator"
|
||||||
MAIN_JAR_GLOB="cryptomator-*.jar"
|
MAIN_JAR_GLOB="cryptomator-*.jar"
|
||||||
MODULE_AND_MAIN_CLASS="org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator"
|
MODULE_AND_MAIN_CLASS="org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator"
|
||||||
@@ -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'`
|
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"
|
FUSE_LIB="FUSE-T"
|
||||||
|
|
||||||
JAVAFX_VERSION=22.0.2
|
JAVAFX_VERSION=24.0.1
|
||||||
JAVAFX_ARCH="undefined"
|
JAVAFX_ARCH="undefined"
|
||||||
JAVAFX_JMODS_SHA256="undefined"
|
JAVAFX_JMODS_SHA256="undefined"
|
||||||
if [ "$(machine)" = "arm64e" ]; then
|
if [ "$(machine)" = "arm64e" ]; then
|
||||||
JAVAFX_ARCH="aarch64"
|
JAVAFX_ARCH="aarch64"
|
||||||
JAVAFX_JMODS_SHA256="813c6748f7c99cb7a579d48b48a087b4682b1fad1fc1a4fe5f9b21cf872b15a7"
|
JAVAFX_JMODS_SHA256="b5a94a13077507003fa852512bfa33f4fb680bc8076d8002e4227a84c85171d4"
|
||||||
else
|
else
|
||||||
JAVAFX_ARCH="x64"
|
JAVAFX_ARCH="x64"
|
||||||
JAVAFX_JMODS_SHA256="115cb08bb59d880cfff6e51e0bf0dcc45785ed9d456b8b8425597b04da6ab3d4"
|
JAVAFX_JMODS_SHA256="6e62a426d43c168a488521f904a523f3dd6ee2cf103e08136f2fd465c828a105"
|
||||||
fi
|
fi
|
||||||
JAVAFX_JMODS_URL="https://download2.gluonhq.com/openjfx/${JAVAFX_VERSION}/openjfx-${JAVAFX_VERSION}_osx-${JAVAFX_ARCH}_bin-jmods.zip"
|
JAVAFX_JMODS_URL="https://download2.gluonhq.com/openjfx/${JAVAFX_VERSION}/openjfx-${JAVAFX_VERSION}_osx-${JAVAFX_ARCH}_bin-jmods.zip"
|
||||||
|
|
||||||
@@ -75,10 +75,16 @@ mvn -B -Djavafx.platform=mac -f../../../pom.xml clean package -DskipTests -Pmac
|
|||||||
cp ../../../LICENSE.txt ../../../target
|
cp ../../../LICENSE.txt ../../../target
|
||||||
cp ../../../target/${MAIN_JAR_GLOB} ../../../target/mods
|
cp ../../../target/${MAIN_JAR_GLOB} ../../../target/mods
|
||||||
|
|
||||||
# add runtime
|
# create runtime
|
||||||
|
## check for JEP 493
|
||||||
|
JMOD_PATHS="openjfx-jmods"
|
||||||
|
if ! ${JAVA_HOME}/bin/jlink --help | grep -q "Linking from run-time image enabled"; then
|
||||||
|
JMOD_PATHS="${JAVA_HOME}/jmods:${JMOD_PATHS}"
|
||||||
|
fi
|
||||||
|
## create custom runtime
|
||||||
${JAVA_HOME}/bin/jlink \
|
${JAVA_HOME}/bin/jlink \
|
||||||
--output runtime \
|
--output runtime \
|
||||||
--module-path "${JAVA_HOME}/jmods:openjfx-jmods" \
|
--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.unsupported,jdk.security.auth,jdk.accessibility,jdk.management.jfr,java.compiler \
|
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.security.auth,jdk.accessibility,jdk.management.jfr,java.compiler \
|
||||||
--strip-native-commands \
|
--strip-native-commands \
|
||||||
--no-header-files \
|
--no-header-files \
|
||||||
@@ -100,7 +106,7 @@ ${JAVA_HOME}/bin/jpackage \
|
|||||||
--copyright "(C) ${COPYRIGHT_YEARS} ${VENDOR}" \
|
--copyright "(C) ${COPYRIGHT_YEARS} ${VENDOR}" \
|
||||||
--app-version "${VERSION_NO}" \
|
--app-version "${VERSION_NO}" \
|
||||||
--java-options "--enable-preview" \
|
--java-options "--enable-preview" \
|
||||||
--java-options "--enable-native-access=org.cryptomator.jfuse.mac" \
|
--java-options "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.mac" \
|
||||||
--java-options "-Xss5m" \
|
--java-options "-Xss5m" \
|
||||||
--java-options "-Xmx256m" \
|
--java-options "-Xmx256m" \
|
||||||
--java-options "-Dfile.encoding=\"utf-8\"" \
|
--java-options "-Dfile.encoding=\"utf-8\"" \
|
||||||
|
|||||||
+1
-1
@@ -17,7 +17,7 @@
|
|||||||
\f1\b0 \
|
\f1\b0 \
|
||||||
\
|
\
|
||||||
|
|
||||||
\f0\b \'a9 2016 \'96 2024 Skymatic GmbH
|
\f0\b \'a9 2016 \'96 2025 Skymatic GmbH
|
||||||
\f1\b0 \
|
\f1\b0 \
|
||||||
\
|
\
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\
|
||||||
|
|||||||
+2
-1
@@ -4,7 +4,8 @@ installer
|
|||||||
*.wixobj
|
*.wixobj
|
||||||
*.pdb
|
*.pdb
|
||||||
*.msi
|
*.msi
|
||||||
|
*Debug.properties
|
||||||
*.exe
|
*.exe
|
||||||
*.jmod
|
*.jmod
|
||||||
resources/jfxJmods.zip
|
resources/jfxJmods.zip
|
||||||
license.rtf
|
license.rtf
|
||||||
|
|||||||
Vendored
+1
-1
@@ -11,7 +11,7 @@ SET HELP_URL="https://cryptomator.org/contact/"
|
|||||||
SET MODULE_AND_MAIN_CLASS="org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator"
|
SET MODULE_AND_MAIN_CLASS="org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator"
|
||||||
SET LOOPBACK_ALIAS="cryptomator-vault"
|
SET LOOPBACK_ALIAS="cryptomator-vault"
|
||||||
|
|
||||||
powershell -NoLogo -NoProfile -ExecutionPolicy Unrestricted -Command .\build.ps1^
|
pwsh -NoLogo -NoProfile -ExecutionPolicy Unrestricted -Command .\build.ps1^
|
||||||
-AppName %APPNAME%^
|
-AppName %APPNAME%^
|
||||||
-MainJarGlob "%MAIN_JAR_GLOB%"^
|
-MainJarGlob "%MAIN_JAR_GLOB%"^
|
||||||
-ModuleAndMainClass "%MODULE_AND_MAIN_CLASS%"^
|
-ModuleAndMainClass "%MODULE_AND_MAIN_CLASS%"^
|
||||||
|
|||||||
Vendored
+184
-50
@@ -18,19 +18,38 @@ $ProgressPreference = 'SilentlyContinue' # disables Invoke-WebRequest's progress
|
|||||||
# check preconditions
|
# check preconditions
|
||||||
if ((Get-Command "git" -ErrorAction SilentlyContinue) -eq $null)
|
if ((Get-Command "git" -ErrorAction SilentlyContinue) -eq $null)
|
||||||
{
|
{
|
||||||
Write-Host "Unable to find git.exe in your PATH (try: choco install git)"
|
Write-Error "Unable to find git.exe in your PATH (try: choco install git)"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
if ((Get-Command "mvn" -ErrorAction SilentlyContinue) -eq $null)
|
if ((Get-Command "mvn" -ErrorAction SilentlyContinue) -eq $null)
|
||||||
{
|
{
|
||||||
Write-Host "Unable to find mvn.cmd in your PATH (try: choco install maven)"
|
Write-Error "Unable to find mvn.cmd in your PATH (try: choco install maven)"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
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)'
|
||||||
|
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)'
|
||||||
|
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)'
|
||||||
|
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)'
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
$buildDir = Split-Path -Parent $PSCommandPath
|
$buildDir = Split-Path -Parent $PSCommandPath
|
||||||
$version = $(mvn -f $buildDir/../../pom.xml help:evaluate -Dexpression="project.version" -q -DforceStdout)
|
$version = $(mvn -f $buildDir/../../pom.xml help:evaluate -Dexpression="project.version" -q -DforceStdout)
|
||||||
$semVerNo = $version -replace '(\d+\.\d+\.\d+).*','$1'
|
$semVerNo = $version -replace '(\d+\.\d+\.\d+).*','$1'
|
||||||
$revisionNo = $(git rev-list --count HEAD)
|
$revisionNo = $(git rev-list --count HEAD)
|
||||||
|
$signingCertThumbprint = "TODO"
|
||||||
|
|
||||||
Write-Output "`$version=$version"
|
Write-Output "`$version=$version"
|
||||||
Write-Output "`$semVerNo=$semVerNo"
|
Write-Output "`$semVerNo=$semVerNo"
|
||||||
@@ -50,43 +69,100 @@ if ($clean -and (Test-Path -Path $runtimeImagePath)) {
|
|||||||
Remove-Item -Path $runtimeImagePath -Force -Recurse
|
Remove-Item -Path $runtimeImagePath -Force -Recurse
|
||||||
}
|
}
|
||||||
|
|
||||||
## download jfx jmods
|
## download jfx jmods for X64, while they are part of the Arm64 JDK
|
||||||
$javaFxVersion='22.0.2'
|
$archCode = (Get-CimInstance Win32_Processor).Architecture
|
||||||
$javaFxJmodsUrl = "https://download2.gluonhq.com/openjfx/${javaFxVersion}/openjfx-${javaFxVersion}_windows-x64_bin-jmods.zip"
|
$archName = switch ($archCode) {
|
||||||
$javaFxJmodsSHA256 = 'f9376d200f5c5b85327d575c1ec1482e6455f19916577f7e2fc9be2f48bb29b6'
|
9 { "x64 (AMD64)" }
|
||||||
$javaFxJmods = '.\resources\jfxJmods.zip'
|
12 { "ARM64" }
|
||||||
if( !(Test-Path -Path $javaFxJmods) ) {
|
default { "WMI Win32_Processor.Architecture code ($archCode)" }
|
||||||
Write-Output "Downloading ${javaFxJmodsUrl}..."
|
|
||||||
Invoke-WebRequest $javaFxJmodsUrl -OutFile $javaFxJmods # redirects are followed by default
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$jmodsChecksumActual = $(Get-FileHash -Path $javaFxJmods -Algorithm SHA256).Hash
|
switch ($archName) {
|
||||||
if( $jmodsChecksumActual -ne $javaFxJmodsSHA256 ) {
|
'ARM64' {
|
||||||
Write-Error "Checksum mismatch for jfxJmods.zip. Expected: $javaFxJmodsSHA256
|
$javafxBaseJmod = Join-Path $Env:JAVA_HOME "jmods\javafx.base.jmod"
|
||||||
, actual: $jmodsChecksumActual"
|
if (!(Test-Path $javafxBaseJmod)) {
|
||||||
exit 1;
|
Write-Error "JavaFX module not found in JDK. Please ensure full JDK (including jmods) is installed."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
$jmodPaths = "$Env:JAVA_HOME/jmods"
|
||||||
|
}
|
||||||
|
'x64 (AMD64)' {
|
||||||
|
$javaFxVersion='24.0.1'
|
||||||
|
$javaFxJmodsUrl = "https://download2.gluonhq.com/openjfx/${javaFxVersion}/openjfx-${javaFxVersion}_windows-x64_bin-jmods.zip"
|
||||||
|
$javaFxJmodsSHA256 = 'f13d17c7caf88654fc835f1b4e75a9b0f34a888eb8abef381796c0002e63b03f'
|
||||||
|
$javaFxJmods = '.\resources\jfxJmods.zip'
|
||||||
|
|
||||||
|
if( !(Test-Path -Path $javaFxJmods) ) {
|
||||||
|
Write-Output "Downloading ${javaFxJmodsUrl}..."
|
||||||
|
Invoke-WebRequest $javaFxJmodsUrl -OutFile $javaFxJmods # redirects are followed by default
|
||||||
|
}
|
||||||
|
|
||||||
|
$jmodsChecksumActual = $(Get-FileHash -Path $javaFxJmods -Algorithm SHA256).Hash.ToLower()
|
||||||
|
if( $jmodsChecksumActual -ne $javaFxJmodsSHA256 ) {
|
||||||
|
Write-Error "Checksum mismatch for jfxJmods.zip. Expected: $javaFxJmodsSHA256
|
||||||
|
, actual: $jmodsChecksumActual"
|
||||||
|
exit 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expand-Archive -Path $javaFxJmods -Force -DestinationPath ".\resources\"
|
||||||
|
Remove-Item -Recurse -Force -Path ".\resources\javafx-jmods" -ErrorAction Ignore
|
||||||
|
Move-Item -Force -Path ".\resources\javafx-jmods-*" -Destination ".\resources\javafx-jmods" -ErrorAction Stop
|
||||||
|
|
||||||
|
$jmodPaths="$buildDir/resources/javafx-jmods";
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
Write-Error "Unsupported architecture: $arch"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Expand-Archive -Path $javaFxJmods -Force -DestinationPath ".\resources\"
|
|
||||||
Remove-Item -Recurse -Force -Path ".\resources\javafx-jmods"
|
|
||||||
Move-Item -Force -Path ".\resources\javafx-jmods-*" -Destination ".\resources\javafx-jmods" -ErrorAction Stop
|
|
||||||
|
|
||||||
## create custom runtime
|
## create custom runtime
|
||||||
|
### adjust for JEP 493
|
||||||
|
if ((& "$Env:JAVA_HOME\bin\jlink" --help | Select-String -Pattern "Linking from run-time image enabled" -SimpleMatch | Measure-Object).Count -eq 0 ) {
|
||||||
|
$jmodPaths="$Env:JAVA_HOME/jmods;" + $jmodPaths;
|
||||||
|
}
|
||||||
|
|
||||||
|
### create runtime
|
||||||
& "$Env:JAVA_HOME\bin\jlink" `
|
& "$Env:JAVA_HOME\bin\jlink" `
|
||||||
--verbose `
|
--verbose `
|
||||||
--output runtime `
|
--output runtime `
|
||||||
--module-path "$Env:JAVA_HOME/jmods;$buildDir/resources/javafx-jmods" `
|
--module-path $jmodPaths `
|
||||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.accessibility,jdk.management.jfr,java.compiler,javafx.base,javafx.graphics,javafx.controls,javafx.fxml `
|
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.accessibility,jdk.management.jfr,jdk.crypto.mscapi,java.compiler,javafx.base,javafx.graphics,javafx.controls,javafx.fxml `
|
||||||
--strip-native-commands `
|
--strip-native-commands `
|
||||||
--no-header-files `
|
--no-header-files `
|
||||||
--no-man-pages `
|
--no-man-pages `
|
||||||
--strip-debug `
|
--strip-debug `
|
||||||
--compress "zip-0" #do not compress to have improved msi compression
|
--compress "zip-0" #do not compress and use msi compression
|
||||||
|
|
||||||
$appPath = ".\$AppName"
|
$appPath = ".\$AppName"
|
||||||
if ($clean -and (Test-Path -Path $appPath)) {
|
if ($clean -and (Test-Path -Path $appPath)) {
|
||||||
Remove-Item -Path $appPath -Force -Recurse
|
Remove-Item -Path $appPath -Force -Recurse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$javaOptions = @(
|
||||||
|
"--java-options", "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.win,org.cryptomator.integrations.win"
|
||||||
|
"--java-options", "-Xss5m"
|
||||||
|
"--java-options", "-Xmx256m"
|
||||||
|
"--java-options", "-Dcryptomator.appVersion=`"$semVerNo`""
|
||||||
|
"--java-options", "-Dfile.encoding=`"utf-8`""
|
||||||
|
"--java-options", "-Djava.net.useSystemProxies=true"
|
||||||
|
"--java-options", "-Dcryptomator.logDir=`"@{localappdata}/$AppName`""
|
||||||
|
"--java-options", "-Dcryptomator.pluginDir=`"@{appdata}/$AppName/Plugins`""
|
||||||
|
"--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`""
|
||||||
|
"--java-options", "-Dcryptomator.mountPointsDir=`"@{userhome}/$AppName`""
|
||||||
|
"--java-options", "-Dcryptomator.loopbackAlias=`"$LoopbackAlias`""
|
||||||
|
"--java-options", "-Dcryptomator.integrationsWin.autoStartShellLinkName=`"$AppName`""
|
||||||
|
"--java-options", "-Dcryptomator.integrationsWin.keychainPaths=`"@{appdata}/$AppName/keychain.json;@{userhome}/AppData/Roaming/$AppName/keychain.json`""
|
||||||
|
"--java-options", "-Dcryptomator.integrationsWin.windowsHelloKeychainPaths=`"@{appdata}/$AppName/windowsHelloKeychain.json`""
|
||||||
|
"--java-options", "-Dcryptomator.showTrayIcon=true"
|
||||||
|
"--java-options", "-Dcryptomator.buildNumber=`"msi-$revisionNo`""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# create app dir
|
# create app dir
|
||||||
& "$Env:JAVA_HOME\bin\jpackage" `
|
& "$Env:JAVA_HOME\bin\jpackage" `
|
||||||
--verbose `
|
--verbose `
|
||||||
@@ -99,27 +175,16 @@ if ($clean -and (Test-Path -Path $appPath)) {
|
|||||||
--name $AppName `
|
--name $AppName `
|
||||||
--vendor $Vendor `
|
--vendor $Vendor `
|
||||||
--copyright $copyright `
|
--copyright $copyright `
|
||||||
--java-options "--enable-preview" `
|
|
||||||
--java-options "--enable-native-access=org.cryptomator.jfuse.win,org.cryptomator.integrations.win" `
|
|
||||||
--java-options "-Xss5m" `
|
|
||||||
--java-options "-Xmx256m" `
|
|
||||||
--java-options "-Dcryptomator.appVersion=`"$semVerNo`"" `
|
|
||||||
--app-version "$semVerNo.$revisionNo" `
|
--app-version "$semVerNo.$revisionNo" `
|
||||||
--java-options "-Dfile.encoding=`"utf-8`"" `
|
|
||||||
--java-options "-Djava.net.useSystemProxies=true" `
|
|
||||||
--java-options "-Dcryptomator.logDir=`"@{localappdata}/$AppName`"" `
|
|
||||||
--java-options "-Dcryptomator.pluginDir=`"@{appdata}/$AppName/Plugins`"" `
|
|
||||||
--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`"" `
|
|
||||||
--java-options "-Dcryptomator.mountPointsDir=`"@{userhome}/$AppName`"" `
|
|
||||||
--java-options "-Dcryptomator.loopbackAlias=`"$LoopbackAlias`"" `
|
|
||||||
--java-options "-Dcryptomator.integrationsWin.autoStartShellLinkName=`"$AppName`"" `
|
|
||||||
--java-options "-Dcryptomator.integrationsWin.keychainPaths=`"@{appdata}/$AppName/keychain.json;@{userhome}/AppData/Roaming/$AppName/keychain.json`"" `
|
|
||||||
--java-options "-Dcryptomator.showTrayIcon=true" `
|
|
||||||
--java-options "-Dcryptomator.buildNumber=`"msi-$revisionNo`"" `
|
|
||||||
--resource-dir resources `
|
--resource-dir resources `
|
||||||
--icon resources/$AppName.ico
|
--icon resources/$AppName.ico `
|
||||||
|
--add-launcher "Debug_${AppName}=$buildDir\debug-launcher.properties" `
|
||||||
|
@javaOptions
|
||||||
|
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Write-Error "jpackage Appimage failed with exit code $LASTEXITCODE"
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
#Create RTF license for msi
|
#Create RTF license for msi
|
||||||
&mvn -B -f $buildDir/../../pom.xml license:add-third-party "-Djavafx.platform=win" `
|
&mvn -B -f $buildDir/../../pom.xml license:add-third-party "-Djavafx.platform=win" `
|
||||||
@@ -134,6 +199,7 @@ if ($clean -and (Test-Path -Path $appPath)) {
|
|||||||
# patch app dir
|
# patch app dir
|
||||||
Copy-Item "contrib\*" -Destination "$AppName"
|
Copy-Item "contrib\*" -Destination "$AppName"
|
||||||
attrib -r "$AppName\$AppName.exe"
|
attrib -r "$AppName\$AppName.exe"
|
||||||
|
attrib -r "$AppName\Debug_${AppName}.exe"
|
||||||
# patch batch script to set hostfile
|
# patch batch script to set hostfile
|
||||||
$webDAVPatcher = "$AppName\patchWebDAV.bat"
|
$webDAVPatcher = "$AppName\patchWebDAV.bat"
|
||||||
try {
|
try {
|
||||||
@@ -143,6 +209,53 @@ try {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# sign app dir
|
||||||
|
## extract
|
||||||
|
Add-Type -AssemblyName "System.io.compression.filesystem"
|
||||||
|
$jarFolder = Resolve-Path "$AppName\app\mods"
|
||||||
|
$jarExtractDir = New-Item -Path "$AppName\jar-extract" -ItemType Directory
|
||||||
|
Get-ChildItem -Path $jarFolder -Filter "*.jar" | ForEach-Object {
|
||||||
|
$jar = [Io.compression.zipfile]::OpenRead($_.FullName)
|
||||||
|
if (@($jar.Entries | Where-Object {
|
||||||
|
$_.Name.ToString().EndsWith(".dll")} | Select-Object -First 1).Count -gt 0) {
|
||||||
|
#jars containing dlls extract
|
||||||
|
Set-Location $jarExtractDir
|
||||||
|
Expand-Archive -Path $_.FullName
|
||||||
|
|
||||||
|
}
|
||||||
|
$jar.Dispose()
|
||||||
|
}
|
||||||
|
Set-Location $buildDir
|
||||||
|
## Extract wixhelper.dll for Codesigning #see https://github.com/cryptomator/cryptomator/issues/3130
|
||||||
|
if($jmodPaths -like "${env:JAVA_HOME}\jmods") {
|
||||||
|
$wixHelperDir = New-Item -Path ${AppName}/jpackage-jmod -ItemType Directory
|
||||||
|
& ${env:JAVA_HOME}\bin\jmod.exe extract --dir $wixHelperDir "${env:JAVA_HOME}\jmods\jdk.jpackage.jmod"
|
||||||
|
Get-ChildItem -Recurse -Path "$wixHelperDir" -File wixhelper.dll | Select-Object -Last 1 | Copy-Item -Destination "${AppName}/"
|
||||||
|
}
|
||||||
|
|
||||||
|
## prepare signtool
|
||||||
|
Write-Output "Signing files in app dir $AppName..."
|
||||||
|
$signTool = Get-ChildItem -Path "${Env:ProgramFiles(x86)}\Windows Kits\10\bin\" -Recurse -Filter "signtool.exe" | Where-Object FullName -like "*${archName}*" | Sort-Object LastWriteTime -Descending | Select-Object -First 1
|
||||||
|
if ($null -eq $signTool) {
|
||||||
|
Write-Error "Unable to find signtool.exe in ${Env:ProgramFiles(x86)}\Windows Kits\10\bin\. Please ensure Windows SDK is installed."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Write-Output "Using signtool: $($signTool.FullName)"
|
||||||
|
Write-Output "Using signing certificate with thumbprint: $signingCertThumbprint"
|
||||||
|
## sign files inside app dir
|
||||||
|
$filesToSign = Get-ChildItem -Path $AppName -Recurse -File -Include "*.exe","*.dll","*.sys"
|
||||||
|
|
||||||
|
foreach ($file in $filesToSign) {
|
||||||
|
& $signTool sign /as /sha1 $signingCertThumbprint /tr "http://timestamp.digicert.com" /td SHA256 /fd SHA256 /d "Cryptomator" $file.FullName
|
||||||
|
if( $? -eq $false) {
|
||||||
|
Write-Error "Failed to sign file: $($file.FullName)"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#TODO: Sign wixhelper.dll with signtool.exe
|
||||||
|
#TODO: patch jar files with signed dlls
|
||||||
|
|
||||||
# create .msi
|
# create .msi
|
||||||
$Env:JP_WIXWIZARD_RESOURCES = "$buildDir\resources"
|
$Env:JP_WIXWIZARD_RESOURCES = "$buildDir\resources"
|
||||||
$Env:JP_WIXHELPER_DIR = "."
|
$Env:JP_WIXHELPER_DIR = "."
|
||||||
@@ -166,6 +279,11 @@ $Env:JP_WIXHELPER_DIR = "."
|
|||||||
--about-url $AboutUrl `
|
--about-url $AboutUrl `
|
||||||
--file-associations resources/FAvaultFile.properties
|
--file-associations resources/FAvaultFile.properties
|
||||||
|
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Write-Error "jpackage MSI failed with exit code $LASTEXITCODE"
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
#Create RTF license for bundle
|
#Create RTF license for bundle
|
||||||
&mvn -B -f $buildDir/../../pom.xml license:add-third-party "-Djavafx.platform=win" `
|
&mvn -B -f $buildDir/../../pom.xml license:add-third-party "-Djavafx.platform=win" `
|
||||||
"-Dlicense.thirdPartyFilename=license.rtf" `
|
"-Dlicense.thirdPartyFilename=license.rtf" `
|
||||||
@@ -177,9 +295,19 @@ $Env:JP_WIXHELPER_DIR = "."
|
|||||||
"-Dlicense.licenseMergesUrl=file:///$buildDir/../../license/merges"
|
"-Dlicense.licenseMergesUrl=file:///$buildDir/../../license/merges"
|
||||||
|
|
||||||
# download Winfsp
|
# download Winfsp
|
||||||
$winfspMsiUrl= 'https://github.com/winfsp/winfsp/releases/download/v2.0/winfsp-2.0.23075.msi'
|
$winfspMsiUrl= 'https://github.com/winfsp/winfsp/releases/download/v2.1/winfsp-2.1.25156.msi'
|
||||||
|
$winfspMsiHash = '073A70E00F77423E34BED98B86E600DEF93393BA5822204FAC57A29324DB9F7A'
|
||||||
Write-Output "Downloading ${winfspMsiUrl}..."
|
Write-Output "Downloading ${winfspMsiUrl}..."
|
||||||
Invoke-WebRequest $winfspMsiUrl -OutFile ".\bundle\resources\winfsp.msi" # redirects are followed by default
|
Invoke-WebRequest $winfspMsiUrl -OutFile ".\bundle\resources\winfsp.msi" # redirects are followed by default
|
||||||
|
$computedHash = $(Get-FileHash -Path '.\bundle\resources\winfsp.msi' -Algorithm SHA256).Hash
|
||||||
|
if (! $computedHash.Equals($winfspMsiHash)) {
|
||||||
|
Write-Error -Category InvalidData -CategoryActivity "Data integrity check failed" -Message @"
|
||||||
|
Downloaded Winfsp Installer does not match stored SHA256 checksum.
|
||||||
|
Expected: $winfspMsiHash
|
||||||
|
Actual: $computedHash
|
||||||
|
"@
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
# download legacy-winfsp uninstaller
|
# download legacy-winfsp uninstaller
|
||||||
$winfspUninstaller= 'https://github.com/cryptomator/winfsp-uninstaller/releases/latest/download/winfsp-uninstaller.exe'
|
$winfspUninstaller= 'https://github.com/cryptomator/winfsp-uninstaller/releases/latest/download/winfsp-uninstaller.exe'
|
||||||
@@ -187,14 +315,20 @@ Write-Output "Downloading ${winfspUninstaller}..."
|
|||||||
Invoke-WebRequest $winfspUninstaller -OutFile ".\bundle\resources\winfsp-uninstaller.exe" # redirects are followed by default
|
Invoke-WebRequest $winfspUninstaller -OutFile ".\bundle\resources\winfsp-uninstaller.exe" # redirects are followed by default
|
||||||
|
|
||||||
# copy MSI to bundle resources
|
# copy MSI to bundle resources
|
||||||
Copy-Item ".\installer\$AppName-*.msi" -Destination ".\bundle\resources\$AppName.msi"
|
Copy-Item ".\installer\$AppName-*.msi" -Destination ".\bundle\resources\$AppName.msi" -Force
|
||||||
|
|
||||||
# create bundle including winfsp
|
# create bundle including winfsp
|
||||||
& "$env:WIX\bin\candle.exe" .\bundle\bundleWithWinfsp.wxs -ext WixBalExtension -ext WixUtilextension -out bundle\ `
|
& wix build `
|
||||||
-dBundleVersion="$semVerNo.$revisionNo" `
|
-define BundleName="$AppName" `
|
||||||
-dBundleVendor="$Vendor" `
|
-define BundleVersion="$semVerNo.$revisionNo" `
|
||||||
-dBundleCopyright="$copyright" `
|
-define BundleVendor="$Vendor" `
|
||||||
-dAboutUrl="$AboutUrl" `
|
-define BundleCopyright="$copyright" `
|
||||||
-dHelpUrl="$HelpUrl" `
|
-define AboutUrl="$AboutUrl" `
|
||||||
-dUpdateUrl="$UpdateUrl"
|
-define HelpUrl="$HelpUrl" `
|
||||||
& "$env:WIX\bin\light.exe" -b . .\bundle\BundlewithWinfsp.wixobj -ext WixBalExtension -ext WixUtilextension -out installer\$AppName-Installer.exe
|
-define UpdateUrl="$UpdateUrl" `
|
||||||
|
-ext "WixToolset.Util.wixext" `
|
||||||
|
-ext "WixToolset.BootstrapperApplications.wixext" `
|
||||||
|
.\bundle\bundleWithWinfsp.wxs `
|
||||||
|
-out "installer\$AppName-Installer.exe"
|
||||||
|
|
||||||
|
Write-Output "Created EXE installer .\installer\$AppName-Installer.exe"
|
||||||
|
|||||||
Vendored
+41
-59
@@ -1,66 +1,48 @@
|
|||||||
<?xml version="1.0"?>
|
<!-- For Built in variables, see https://wixtoolset.org/docs/tools/burn/builtin-variables/-->
|
||||||
|
<ns0:Wix xmlns:ns0="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
|
||||||
<!-- For Built in variables, see https://wixtoolset.org/docs/tools/burn/builtin-variables/-->
|
<ns0:Bundle Name="$(var.BundleName)"
|
||||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:bal="http://schemas.microsoft.com/wix/BalExtension" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
|
UpgradeCode="29eea626-2e5b-4449-b5f8-4602925ddf7b"
|
||||||
<!-- see https://wixtoolset.org/documentation/manual/v3/xsd/wix/bundle.html-->
|
Version="$(var.BundleVersion)"
|
||||||
<!-- Attributes explicitly not used:
|
Manufacturer="$(var.BundleVendor)"
|
||||||
Condition - the single msi files have their own install conditions, no need to copy them here
|
AboutUrl="$(var.AboutUrl)"
|
||||||
-->
|
HelpUrl="$(var.HelpUrl)"
|
||||||
|
UpdateUrl="$(var.UpdateUrl)"
|
||||||
<Bundle Name="Cryptomator" UpgradeCode="29eea626-2e5b-4449-b5f8-4602925ddf7b" Version="$(var.BundleVersion)" Manufacturer="$(var.BundleVendor)"
|
Copyright="$(var.BundleCopyright)"
|
||||||
AboutUrl="$(var.AboutUrl)" HelpUrl="$(var.HelpUrl)" UpdateUrl="$(var.UpdateUrl)" Copyright="$(var.BundleCopyright)" IconSourceFile="bundle\resources\Cryptomator.ico">
|
IconSourceFile="bundle\resources\Cryptomator.ico">
|
||||||
|
|
||||||
<!-- detect outdated WinFsp installations -->
|
<!-- detect outdated WinFsp installations -->
|
||||||
<util:ProductSearch
|
<util:ProductSearch Variable="InstalledLegacyWinFspVersion" Result="version" UpgradeCode="82F812D9-4083-4EF1-8BC8-0F1EDA05B46B" />
|
||||||
Variable="InstalledLegacyWinFspVersion"
|
|
||||||
Result="version"
|
|
||||||
UpgradeCode="82F812D9-4083-4EF1-8BC8-0F1EDA05B46B"/>
|
|
||||||
|
|
||||||
<!-- for definition of the standard themes, see https://github.com/wixtoolset/wix3/blob/master/src/ext/BalExtension/wixstdba/Resources/-->
|
<ns0:BootstrapperApplication>
|
||||||
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLargeLicense">
|
<bal:WixStandardBootstrapperApplication LicenseFile="bundle\resources\license.rtf" ShowVersion="yes"
|
||||||
<!-- see https://wixtoolset.org/documentation/manual/v3/xsd/bal/wixstandardbootstrapperapplication.html -->
|
SuppressOptionsUI="yes"
|
||||||
<!-- Possible Attributes: LaunchTarget -->
|
Theme="rtfLargeLicense"
|
||||||
<bal:WixStandardBootstrapperApplication
|
ThemeFile="bundle\resources\customBootstrapperTheme.xml"
|
||||||
LicenseFile="bundle\resources\license.rtf"
|
LocalizationFile="bundle\resources\customBootstrapperTheme.wxl"
|
||||||
ShowVersion="yes"
|
LogoSideFile="bundle\resources\logoSide.png"
|
||||||
SuppressOptionsUI="yes"
|
LogoFile="bundle\resources\logo.png"
|
||||||
ThemeFile="bundle\customBootstrapperTheme.xml"
|
LaunchTarget="[ProgramFiles64Folder]\$(var.BundleName)\$(var.BundleName).exe" />
|
||||||
LocalizationFile="bundle\customBootstrapperTheme.wxl"
|
<ns0:Payload SourceFile="bundle\resources\logoSide.png"/>
|
||||||
LogoFile="bundle\resources\logo.png"/>
|
<!-- Required due to https://github.com/wixtoolset/issues/issues/8104 -->
|
||||||
<Payload SourceFile="bundle\resources\logoSide.png" />
|
<ns0:Payload Name="Cryptobot.ico" SourceFile="bundle\resources\Cryptomator.ico"/>
|
||||||
</BootstrapperApplicationRef>
|
</ns0:BootstrapperApplication>
|
||||||
|
|
||||||
<Chain>
|
<ns0:Chain>
|
||||||
<ExePackage Cache="yes" PerMachine="yes" Permanent="no"
|
<ns0:ExePackage Cache="keep" PerMachine="yes" Permanent="no" SourceFile="bundle\resources\winfsp-uninstaller.exe" DisplayName="Removing outdated WinFsp Driver" Description="Executable to remove old winfsp" DetectCondition="false" InstallCondition="(InstalledLegacyWinFspVersion <> v0.0.0.0) AND ((WixBundleAction = 7) OR (WixBundleAction = 5))" UninstallArguments="">
|
||||||
SourceFile="resources\winfsp-uninstaller.exe"
|
<ns0:CommandLine Condition="WixBundleUILevel <= 3" InstallArgument="-q -l "[WixBundleLog].winfsp-uninstaller.log"" RepairArgument="-q" UninstallArgument="-s" />
|
||||||
DisplayName="Removing outdated WinFsp Driver"
|
|
||||||
Description="Executable to remove old winfsp"
|
|
||||||
DetectCondition="false"
|
|
||||||
InstallCondition="(InstalledLegacyWinFspVersion <> v0.0.0.0) AND ((WixBundleAction = 7) OR (WixBundleAction = 5))">
|
|
||||||
<CommandLine Condition="WixBundleUILevel <= 3" InstallArgument="-q -l "[WixBundleLog].winfsp-uninstaller.log"" RepairArgument="-q" UninstallArgument="-s" />
|
|
||||||
<!-- XML allows line breaks in attributes, hence keep the line breaks here -->
|
<!-- XML allows line breaks in attributes, hence keep the line breaks here -->
|
||||||
<CommandLine Condition="WixBundleUILevel > 3" InstallArgument="-l "[WixBundleLog].winfsp-uninstaller.log" -t "Cryptomator Installer" -m "Cryptomator requires a newer version of the WinFsp driver. The installer will now uninstall WinFsp, possibly reboot, and afterwards proceed with the installation.
|
<ns0:CommandLine Condition="WixBundleUILevel > 3" InstallArgument="-l "[WixBundleLog].winfsp-uninstaller.log" -t "Cryptomator Installer" -m "Cryptomator requires a newer version of the WinFsp driver. The installer will now uninstall WinFsp, possibly reboot, and afterwards proceed with the installation.
|
||||||
|
|
||||||
Do you want to continue?"" RepairArgument="-q" UninstallArgument="-s" />
|
Do you want to continue?"" RepairArgument="-q" UninstallArgument="-s" />
|
||||||
<ExitCode Behavior="success" Value="0"/>
|
<ns0:ExitCode Behavior="success" Value="0" />
|
||||||
<ExitCode Behavior="success" Value="1"/>
|
<ns0:ExitCode Behavior="success" Value="1" />
|
||||||
<ExitCode Behavior="error" Value="2"/>
|
<ns0:ExitCode Behavior="error" Value="2" />
|
||||||
<ExitCode Behavior="error" Value="3"/>
|
<ns0:ExitCode Behavior="error" Value="3" />
|
||||||
<ExitCode Behavior="forceReboot" Value="4"/>
|
<ns0:ExitCode Behavior="forceReboot" Value="4" />
|
||||||
<ExitCode Behavior="success" Value="5"/>
|
<ns0:ExitCode Behavior="success" Value="5" />
|
||||||
</ExePackage>
|
</ns0:ExePackage>
|
||||||
<!-- see https://wixtoolset.org/documentation/manual/v3/xsd/wix/msipackage.html-->
|
<ns0:MsiPackage SourceFile="bundle\resources\Cryptomator.msi" CacheId="cryptomator-bundle-cryptomator" Visible="no" />
|
||||||
<MsiPackage
|
<ns0:MsiPackage SourceFile="bundle\resources\winfsp.msi" CacheId="cryptomator-bundle-winfsp" Visible="yes" Permanent="yes" />
|
||||||
SourceFile="resources\Cryptomator.msi"
|
</ns0:Chain>
|
||||||
CacheId="cryptomator-bundle-cryptomator"
|
</ns0:Bundle>
|
||||||
DisplayInternalUI="no"
|
</ns0:Wix>
|
||||||
Visible="no"/>
|
|
||||||
<MsiPackage
|
|
||||||
SourceFile="resources\winfsp.msi"
|
|
||||||
CacheId="cryptomator-bundle-winfsp"
|
|
||||||
Visible="yes"
|
|
||||||
DisplayInternalUI="no"
|
|
||||||
Permanent="yes"/>
|
|
||||||
</Chain>
|
|
||||||
</Bundle>
|
|
||||||
</Wix>
|
|
||||||
-64
@@ -1,64 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
|
|
||||||
|
|
||||||
|
|
||||||
<WixLocalization Culture="en-us" Language="1033" xmlns="http://schemas.microsoft.com/wix/2006/localization">
|
|
||||||
<String Id="Caption">[WixBundleName] Setup</String>
|
|
||||||
<String Id="Title">[WixBundleName]</String>
|
|
||||||
<String Id="InstallHeader">Welcome</String>
|
|
||||||
<String Id="InstallMessage">This Setup will install [WixBundleName] and additional dependencies on your computer.</String>
|
|
||||||
<String Id="InstallVersion">Version [WixBundleVersion]</String>
|
|
||||||
<String Id="ConfirmCancelMessage">Are you sure you want to cancel?</String>
|
|
||||||
<String Id="ExecuteUpgradeRelatedBundleMessage">Previous version</String>
|
|
||||||
<String Id="HelpHeader">Setup Help</String>
|
|
||||||
<String Id="HelpText">/install | /repair | /uninstall | /layout [directory] - installs, repairs, uninstalls or
|
|
||||||
creates a complete local copy of the bundle in directory. Install is the default.
|
|
||||||
|
|
||||||
/passive | /quiet - displays minimal UI with no prompts or displays no UI and
|
|
||||||
no prompts. By default UI and all prompts are displayed.
|
|
||||||
|
|
||||||
/norestart - suppress any attempts to restart. By default UI will prompt before restart.
|
|
||||||
/log log.txt - logs to a specific file. By default a log file is created in %TEMP%.</String>
|
|
||||||
<String Id="HelpCloseButton">&Close</String>
|
|
||||||
<String Id="InstallLicenseLinkText">[WixBundleName] <a href="#">license terms</a>.</String>
|
|
||||||
<String Id="InstallAcceptCheckbox">I &agree to the license terms and conditions</String>
|
|
||||||
<String Id="InstallOptionsButton">&Options</String>
|
|
||||||
<String Id="InstallInstallButton">&Install</String>
|
|
||||||
<String Id="InstallCloseButton">&Close</String>
|
|
||||||
<String Id="OptionsHeader">Setup Options</String>
|
|
||||||
<String Id="OptionsLocationLabel">Install location:</String>
|
|
||||||
<String Id="OptionsBrowseButton">&Browse</String>
|
|
||||||
<String Id="OptionsOkButton">&OK</String>
|
|
||||||
<String Id="OptionsCancelButton">&Cancel</String>
|
|
||||||
<String Id="ProgressHeader">Setup Progress</String>
|
|
||||||
<String Id="ProgressLabel">Processing:</String>
|
|
||||||
<String Id="OverallProgressPackageText">Initializing...</String>
|
|
||||||
<String Id="ProgressCancelButton">&Cancel</String>
|
|
||||||
<String Id="ModifyHeader">Modify Setup</String>
|
|
||||||
<String Id="ModifyRepairButton">&Repair</String>
|
|
||||||
<String Id="ModifyUninstallButton">&Uninstall</String>
|
|
||||||
<String Id="ModifyCloseButton">&Close</String>
|
|
||||||
<String Id="SuccessRepairHeader">Repair Successfully Completed</String>
|
|
||||||
<String Id="SuccessUninstallHeader">Uninstall Successfully Completed</String>
|
|
||||||
<String Id="SuccessInstallHeader">Installation Successfully Completed</String>
|
|
||||||
<String Id="SuccessHeader">Setup Successful</String>
|
|
||||||
<String Id="SuccessLaunchButton">&Launch</String>
|
|
||||||
<String Id="SuccessRestartText">You must restart your computer before you can use the software.</String>
|
|
||||||
<String Id="SuccessRestartButton">&Restart</String>
|
|
||||||
<String Id="SuccessCloseButton">&Close</String>
|
|
||||||
<String Id="FailureHeader">Setup Failed</String>
|
|
||||||
<String Id="FailureInstallHeader">Setup Failed</String>
|
|
||||||
<String Id="FailureUninstallHeader">Uninstall Failed</String>
|
|
||||||
<String Id="FailureRepairHeader">Repair Failed</String>
|
|
||||||
<String Id="FailureHyperlinkLogText">One or more issues caused the setup to fail. Please fix the issues and then retry setup. For more information see the <a href="#">log file</a>.</String>
|
|
||||||
<String Id="FailureRestartText">You must restart your computer to complete the rollback of the software.</String>
|
|
||||||
<String Id="FailureRestartButton">&Restart</String>
|
|
||||||
<String Id="FailureCloseButton">&Close</String>
|
|
||||||
<String Id="FilesInUseHeader">Files In Use</String>
|
|
||||||
<String Id="FilesInUseLabel">The following applications are using files that need to be updated:</String>
|
|
||||||
<String Id="FilesInUseCloseRadioButton">Close the &applications and attempt to restart them.</String>
|
|
||||||
<String Id="FilesInUseDontCloseRadioButton">&Do not close applications. A reboot will be required.</String>
|
|
||||||
<String Id="FilesInUseOkButton">&OK</String>
|
|
||||||
<String Id="FilesInUseCancelButton">&Cancel</String>
|
|
||||||
<String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
|
|
||||||
</WixLocalization>
|
|
||||||
-91
@@ -1,91 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
|
|
||||||
<!-- adjusted theme based on https://github.com/wixtoolset/wix3/blob/master/src/ext/BalExtension/wixstdba/Resources/HyperlinkSidebarTheme.xml -->
|
|
||||||
|
|
||||||
|
|
||||||
<Theme xmlns="http://wixtoolset.org/schemas/thmutil/2010">
|
|
||||||
<Window Width="600" Height="450" HexStyle="100a0000" FontId="0">#(loc.Caption)</Window>
|
|
||||||
<Font Id="0" Height="-12" Weight="500" Foreground="000000" Background="FFFFFF">Segoe UI</Font>
|
|
||||||
<Font Id="1" Height="-24" Weight="500" Foreground="000000">Segoe UI</Font>
|
|
||||||
<Font Id="2" Height="-22" Weight="500" Foreground="666666">Segoe UI</Font>
|
|
||||||
<Font Id="3" Height="-12" Weight="500" Foreground="000000" Background="FFFFFF">Segoe UI</Font>
|
|
||||||
<Font Id="4" Height="-12" Weight="500" Foreground="ff0000" Background="FFFFFF" Underline="yes">Segoe UI</Font>
|
|
||||||
<Font Id="5" Height="-12" Weight="700" Foreground="000000" Background="FFFFFF">Segoe UI</Font>
|
|
||||||
|
|
||||||
<Image X="11" Y="11" Width="64" Height="64" ImageFile="logo.png" />
|
|
||||||
<Text X="80" Y="11" Width="-11" Height="64" FontId="1" DisablePrefix="yes">#(loc.Title)</Text>
|
|
||||||
|
|
||||||
<Page Name="Help">
|
|
||||||
<Image X="11" Y="11" Width="64" Height="64" ImageFile="logo.png" />
|
|
||||||
<Text X="80" Y="11" Width="-11" Height="64" FontId="1" DisablePrefix="yes">#(loc.Title)</Text>
|
|
||||||
<Text X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.HelpHeader)</Text>
|
|
||||||
<Text X="11" Y="112" Width="-11" Height="-35" FontId="3" DisablePrefix="yes">#(loc.HelpText)</Text>
|
|
||||||
<Button Name="HelpCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.HelpCloseButton)</Button>
|
|
||||||
</Page>
|
|
||||||
<Page Name="Install">
|
|
||||||
<Text X="185" Y="11" Width="-11" Height="32" FontId="1" DisablePrefix="yes">#(loc.Title)</Text>
|
|
||||||
<Image X="11" Y="11" Width="165" Height="400" ImageFile="logoside.png"/>
|
|
||||||
<Text X="185" Y="50" Width="-11" Height="32" FontId="2" DisablePrefix="yes">#(loc.InstallHeader)</Text>
|
|
||||||
<Text X="185" Y="91" Width="-11" Height="64" FontId="3" DisablePrefix="yes">#(loc.InstallMessage)</Text>
|
|
||||||
<Richedit Name="EulaRichedit" X="185" Y="131" Width="-12" Height="-65" HexStyle="0x00800000" TabStop="yes" FontId="0" />
|
|
||||||
<Checkbox Name="EulaAcceptCheckbox" X="185" Y="-46" Width="-11" Height="17" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.InstallAcceptCheckbox)</Checkbox>
|
|
||||||
<Text Name="InstallVersion" X="185" Y="-11" Width="-11" Height="17" FontId="3" DisablePrefix="yes" HideWhenDisabled="yes">#(loc.InstallVersion)</Text>
|
|
||||||
<Button Name="InstallButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.InstallInstallButton)</Button>
|
|
||||||
<Button Name="WelcomeCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.InstallCloseButton)</Button>
|
|
||||||
</Page>
|
|
||||||
<Page Name="FilesInUse">
|
|
||||||
<Image X="11" Y="11" Width="64" Height="64" ImageFile="logo.png" />
|
|
||||||
<Text X="80" Y="11" Width="-11" Height="64" FontId="1" DisablePrefix="yes">#(loc.Title)</Text>
|
|
||||||
<Text X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.FilesInUseHeader)</Text>
|
|
||||||
<Text X="11" Y="121" Width="-11" Height="34" FontId="3" DisablePrefix="yes">#(loc.FilesInUseLabel)</Text>
|
|
||||||
<Text Name="FilesInUseText" X="11" Y="150" Width="-11" Height="-86" FontId="3" DisablePrefix="yes" HexStyle="0x0000000C">A</Text>
|
|
||||||
|
|
||||||
<Button Name="FilesInUseCloseRadioButton" X="11" Y="-60" Width="-11" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes" HexStyle="0x000009">#(loc.FilesInUseCloseRadioButton)</Button>
|
|
||||||
<Button Name="FilesInUseDontCloseRadioButton" X="11" Y="-40" Width="-11" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes" HexStyle="0x000009">#(loc.FilesInUseDontCloseRadioButton)</Button>
|
|
||||||
|
|
||||||
<Button Name="FilesInUseOkButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.FilesInUseOkButton)</Button>
|
|
||||||
<Button Name="FilesInUseCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.FilesInUseCancelButton)</Button>
|
|
||||||
</Page>
|
|
||||||
<Page Name="Progress">
|
|
||||||
<Text X="80" Y="11" Width="-11" Height="32" FontId="1" DisablePrefix="yes">#(loc.Title)</Text>
|
|
||||||
<Image X="11" Y="11" Width="64" Height="64" ImageFile="logo.png"/>
|
|
||||||
<Text X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.ProgressHeader)</Text>
|
|
||||||
<Text X="11" Y="141" Width="70" Height="17" FontId="3" DisablePrefix="yes">#(loc.ProgressLabel)</Text>
|
|
||||||
<Text Name="OverallProgressPackageText" X="85" Y="141" Width="-11" Height="17" FontId="3" DisablePrefix="yes">#(loc.OverallProgressPackageText)</Text>
|
|
||||||
<Progressbar Name="OverallCalculatedProgressbar" X="11" Y="163" Width="-11" Height="20" />
|
|
||||||
<Button Name="ProgressCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ProgressCancelButton)</Button>
|
|
||||||
</Page>
|
|
||||||
<Page Name="Modify">
|
|
||||||
<Image X="11" Y="11" Width="64" Height="64" ImageFile="logo.png" />
|
|
||||||
<Text X="80" Y="11" Width="-11" Height="64" FontId="1" DisablePrefix="yes">#(loc.Title)</Text>
|
|
||||||
<Text X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.ModifyHeader)</Text>
|
|
||||||
<Button Name="RepairButton" X="-171" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.ModifyRepairButton)</Button>
|
|
||||||
<Button Name="UninstallButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ModifyUninstallButton)</Button>
|
|
||||||
<Button Name="ModifyCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ModifyCloseButton)</Button>
|
|
||||||
</Page>
|
|
||||||
<Page Name="Success">
|
|
||||||
<Text X="185" Y="11" Width="-11" Height="32" FontId="1" DisablePrefix="yes">#(loc.Title)</Text>
|
|
||||||
<Image X="11" Y="11" Width="165" Height="400" ImageFile="logoside.png"/>
|
|
||||||
<Text Name="SuccessHeader" X="185" Y="50" Width="-11" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.SuccessHeader)</Text>
|
|
||||||
<Text Name="SuccessInstallHeader" X="185" Y="50" Width="-11" Height="100" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.SuccessInstallHeader)</Text>
|
|
||||||
<Text Name="SuccessRepairHeader" X="185" Y="50" Width="-11" Height="100" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.SuccessRepairHeader)</Text>
|
|
||||||
<Text Name="SuccessUninstallHeader" X="185" Y="50" Width="-11" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.SuccessUninstallHeader)</Text>
|
|
||||||
<Button Name="LaunchButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessLaunchButton)</Button>
|
|
||||||
<Text Name="SuccessRestartText" X="185" Y="-51" Width="400" Height="34" FontId="3" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.SuccessRestartText)</Text>
|
|
||||||
<Button Name="SuccessRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessRestartButton)</Button>
|
|
||||||
<Button Name="SuccessCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.SuccessCloseButton)</Button>
|
|
||||||
</Page>
|
|
||||||
<Page Name="Failure">
|
|
||||||
<Text X="185" Y="11" Width="-11" Height="32" FontId="1" DisablePrefix="yes">#(loc.Title)</Text>
|
|
||||||
<Image X="11" Y="11" Width="165" Height="400" ImageFile="logoside.png"/>
|
|
||||||
<Text Name="FailureHeader" X="185" Y="50" Width="-11" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureHeader)</Text>
|
|
||||||
<Text Name="FailureInstallHeader" X="185" Y="50" Width="-11" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureInstallHeader)</Text>
|
|
||||||
<Text Name="FailureUninstallHeader" X="185" Y="50" Width="-11" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureUninstallHeader)</Text>
|
|
||||||
<Text Name="FailureRepairHeader" X="185" Y="50" Width="-11" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureRepairHeader)</Text>
|
|
||||||
<Hypertext Name="FailureLogFileLink" X="185" Y="121" Width="-11" Height="68" FontId="3" TabStop="yes" HideWhenDisabled="yes">#(loc.FailureHyperlinkLogText)</Hypertext>
|
|
||||||
<Hypertext Name="FailureMessageText" X="185" Y="-80" Width="-11" Height="140" FontId="5" TabStop="yes" HideWhenDisabled="yes" />
|
|
||||||
<Text Name="FailureRestartText" X="185" Y="-57" Width="-11" Height="80" FontId="3" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureRestartText)</Text>
|
|
||||||
<Button Name="FailureRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.FailureRestartButton)</Button>
|
|
||||||
<Button Name="FailureCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.FailureCloseButton)</Button>
|
|
||||||
</Page>
|
|
||||||
</Theme>
|
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
|
||||||
|
|
||||||
|
|
||||||
|
<WixLocalization Culture="en-us" Language="1033" xmlns="http://wixtoolset.org/schemas/v4/wxl">
|
||||||
|
<String Id="Caption" Value="[WixBundleName] Setup" />
|
||||||
|
<String Id="Title" Value="[WixBundleName]" />
|
||||||
|
<String Id="InstallHeader" Value="Welcome" />
|
||||||
|
<String Id="InstallMessage" Value="Setup will install [WixBundleName] on your computer." />
|
||||||
|
<String Id="InstallVersion" Value="Version [WixBundleVersion]" />
|
||||||
|
<String Id="CheckingForUpdatesLabel" Value="Checking for updates" />
|
||||||
|
<String Id="UpdateButton" Value="&Update to version [WixStdBAUpdateAvailable]" />
|
||||||
|
<String Id="InstallVersion" Value="Version [WixBundleVersion]" />
|
||||||
|
<String Id="ConfirmCancelMessage" Value="Are you sure you want to cancel?" />
|
||||||
|
<String Id="ExecuteUpgradeRelatedBundleMessage" Value="Previous version" />
|
||||||
|
<String Id="HelpHeader" Value="Setup Help" />
|
||||||
|
<String Id="HelpText" Value="/install | /repair | /uninstall | /layout [directory] - installs, repairs, uninstalls or
 creates a complete local copy of the bundle in directory. Install is the default.

/passive | /quiet - displays minimal UI with no prompts or displays no UI and
 no prompts. By default UI and all prompts are displayed.

/norestart - suppress any attempts to restart. By default UI will prompt before restart.
/log log.txt - logs to a specific file. By default a log file is created in %TEMP%." />
|
||||||
|
<String Id="HelpCloseButton" Value="&Close" />
|
||||||
|
<String Id="InstallAcceptCheckbox" Value="I &agree to the license terms and conditions" />
|
||||||
|
<String Id="InstallOptionsButton" Value="&Options" />
|
||||||
|
<String Id="InstallInstallButton" Value="&Install" />
|
||||||
|
<String Id="InstallCancelButton" Value="&Cancel" />
|
||||||
|
<String Id="OptionsHeader" Value="Setup Options" />
|
||||||
|
<String Id="OptionsLocationLabel" Value="Install location:" />
|
||||||
|
<String Id="OptionsBrowseButton" Value="&Browse" />
|
||||||
|
<String Id="OptionsOkButton" Value="&OK" />
|
||||||
|
<String Id="OptionsCancelButton" Value="&Cancel" />
|
||||||
|
<String Id="ProgressHeader" Value="Setup Progress" />
|
||||||
|
<String Id="ProgressLabel" Value="Processing:" />
|
||||||
|
<String Id="OverallProgressPackageText" Value="Initializing..." />
|
||||||
|
<String Id="ProgressCancelButton" Value="&Cancel" />
|
||||||
|
<String Id="ModifyHeader" Value="Modify Setup" />
|
||||||
|
<String Id="ModifyRepairButton" Value="&Repair" />
|
||||||
|
<String Id="ModifyUninstallButton" Value="&Uninstall" />
|
||||||
|
<String Id="ModifyCancelButton" Value="&Cancel" />
|
||||||
|
<String Id="SuccessHeader" Value="Setup Successful" />
|
||||||
|
<String Id="SuccessCacheHeader" Value="Cache Successfully Completed" />
|
||||||
|
<String Id="SuccessInstallHeader" Value="Installation Successfully Completed" />
|
||||||
|
<String Id="SuccessLayoutHeader" Value="Layout Successfully Completed" />
|
||||||
|
<String Id="SuccessModifyHeader" Value="Modify Successfully Completed" />
|
||||||
|
<String Id="SuccessRepairHeader" Value="Repair Successfully Completed" />
|
||||||
|
<String Id="SuccessUninstallHeader" Value="Uninstall Successfully Completed" />
|
||||||
|
<String Id="SuccessUnsafeUninstallHeader" Value="Uninstall Successfully Completed" />
|
||||||
|
<String Id="SuccessLaunchButton" Value="&Launch" />
|
||||||
|
<String Id="SuccessRestartText" Value="You must restart your computer before you can use the software." />
|
||||||
|
<String Id="SuccessUninstallRestartText" Value="You must restart your computer to complete the removal of the software." />
|
||||||
|
<String Id="SuccessRestartButton" Value="&Restart" />
|
||||||
|
<String Id="SuccessCloseButton" Value="&Close" />
|
||||||
|
<String Id="FailureHeader" Value="Setup Failed" />
|
||||||
|
<String Id="FailureCacheHeader" Value="Cache Failed" />
|
||||||
|
<String Id="FailureInstallHeader" Value="Setup Failed" />
|
||||||
|
<String Id="FailureLayoutHeader" Value="Layout Failed" />
|
||||||
|
<String Id="FailureModifyHeader" Value="Modify Failed" />
|
||||||
|
<String Id="FailureRepairHeader" Value="Repair Failed" />
|
||||||
|
<String Id="FailureUninstallHeader" Value="Uninstall Failed" />
|
||||||
|
<String Id="FailureUnsafeUninstallHeader" Value="Uninstall Failed" />
|
||||||
|
<String Id="FailureHyperlinkLogText" Value="One or more issues caused the setup to fail. Please fix the issues and then retry setup. For more information see the <a href="#">log file</a>." />
|
||||||
|
<String Id="FailureRestartText" Value="You must restart your computer to complete the rollback of the software." />
|
||||||
|
<String Id="FailureRestartButton" Value="&Restart" />
|
||||||
|
<String Id="FailureCloseButton" Value="&Close" />
|
||||||
|
<String Id="FilesInUseTitle" Value="Files In Use" />
|
||||||
|
<String Id="FilesInUseLabel" Value="The following applications are using files that need to be updated:" />
|
||||||
|
<String Id="FilesInUseNetfxCloseRadioButton" Value="Close the &applications." />
|
||||||
|
<String Id="FilesInUseCloseRadioButton" Value="Close the &applications and attempt to restart them." />
|
||||||
|
<String Id="FilesInUseDontCloseRadioButton" Value="&Do not close applications. A reboot will be required." />
|
||||||
|
<String Id="FilesInUseRetryButton" Value="&Retry" />
|
||||||
|
<String Id="FilesInUseIgnoreButton" Value="&Ignore" />
|
||||||
|
<String Id="FilesInUseExitButton" Value="E&xit" />
|
||||||
|
</WixLocalization>
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
|
||||||
|
|
||||||
|
|
||||||
|
<Theme xmlns="http://wixtoolset.org/schemas/v4/thmutil">
|
||||||
|
<Font Id="0" Height="-12" Weight="500" Foreground="windowtext" Background="window">Segoe UI</Font>
|
||||||
|
<Font Id="1" Height="-24" Weight="500" Foreground="windowtext">Segoe UI</Font>
|
||||||
|
<Font Id="2" Height="-22" Weight="500" Foreground="graytext">Segoe UI</Font>
|
||||||
|
<Font Id="3" Height="-12" Weight="500" Foreground="windowtext" Background="window">Segoe UI</Font>
|
||||||
|
|
||||||
|
<Window Width="600" Height="450" HexStyle="100a0000" FontId="0" Caption="#(loc.Caption)" IconFile="Cryptobot.ico">
|
||||||
|
<Page Name="Help">
|
||||||
|
<Label X="80" Y="11" Width="-11" Height="32" FontId="1" DisablePrefix="yes">#(loc.Title)</Label>
|
||||||
|
<ImageControl X="11" Y="11" Width="64" Height="64" ImageFile="logo.png"/>
|
||||||
|
<Label X="11" Y="80" Width="-11" Height="32" FontId="2" DisablePrefix="yes">#(loc.HelpHeader)</Label>
|
||||||
|
<Label X="11" Y="121" Width="-11" Height="-35" FontId="3" DisablePrefix="yes">#(loc.HelpText)</Label>
|
||||||
|
<Button Name="HelpCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
|
||||||
|
<Text>#(loc.HelpCloseButton)</Text>
|
||||||
|
<CloseWindowAction />
|
||||||
|
</Button>
|
||||||
|
</Page>
|
||||||
|
<Page Name="Loading">
|
||||||
|
<Label X="185" Y="50" Width="-11" Height="30" FontId="2" DisablePrefix="yes" Visible="no" Name="CheckingForUpdatesLabel" />
|
||||||
|
</Page>
|
||||||
|
<Page Name="Install">
|
||||||
|
<ImageControl X="11" Y="11" Width="165" Height="400" ImageFile="logoside.png"/>
|
||||||
|
<Label X="185" Y="11" Width="-11" Height="32" FontId="2" DisablePrefix="yes">#(loc.InstallHeader)</Label>
|
||||||
|
<Label X="185" Y="50" Width="-11" Height="64" FontId="3" DisablePrefix="yes">
|
||||||
|
<Text Condition="WixStdBASuppressOptionsUI">#(loc.InstallMessage)</Text>
|
||||||
|
<Text Condition="NOT WixStdBASuppressOptionsUI">#(loc.InstallMessageOptions)</Text>
|
||||||
|
</Label>
|
||||||
|
<Richedit Name="EulaRichedit" X="185" Y="91" Width="-12" Height="-64" HexStyle="0x00800000" TabStop="yes" FontId="0" />
|
||||||
|
<Checkbox Name="EulaAcceptCheckbox" X="185" Y="-39" Width="-11" Height="17" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.InstallAcceptCheckbox)</Checkbox>
|
||||||
|
<Label Name="InstallVersion" X="11" Y="-11" Width="165" Height="17" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBAShowVersion">#(loc.InstallVersion)</Label>
|
||||||
|
<Button Name="InstallUpdateButton" X="11" Y="-11" Width="200" Height="23" TabStop="yes" FontId="0" EnableCondition="WixStdBAUpdateAvailable" HideWhenDisabled="yes">#(loc.UpdateButton)</Button>
|
||||||
|
<Button Name="OptionsButton" X="-171" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" VisibleCondition="NOT WixStdBASuppressOptionsUI">
|
||||||
|
<Text>#(loc.InstallOptionsButton)</Text>
|
||||||
|
<ChangePageAction Page="Options" />
|
||||||
|
</Button>
|
||||||
|
<Button Name="InstallButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.InstallInstallButton)</Button>
|
||||||
|
<Button Name="InstallCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
|
||||||
|
<Text>#(loc.InstallCancelButton)</Text>
|
||||||
|
<CloseWindowAction />
|
||||||
|
</Button>
|
||||||
|
</Page>
|
||||||
|
<Page Name="Options">
|
||||||
|
<Label X="80" Y="11" Width="-11" Height="32" FontId="1" DisablePrefix="yes">#(loc.Title)</Label>
|
||||||
|
<ImageControl X="11" Y="11" Width="64" Height="64" ImageFile="logo.png"/>
|
||||||
|
<Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.OptionsHeader)</Label>
|
||||||
|
<Label X="11" Y="121" Width="-11" Height="17" FontId="3">#(loc.OptionsLocationLabel)</Label>
|
||||||
|
<Editbox Name="InstallFolder" X="11" Y="143" Width="-91" Height="21" TabStop="yes" FontId="3" FileSystemAutoComplete="yes" />
|
||||||
|
<Button Name="BrowseButton" X="-11" Y="142" Width="75" Height="23" TabStop="yes" FontId="3">
|
||||||
|
<Text>#(loc.OptionsBrowseButton)</Text>
|
||||||
|
<BrowseDirectoryAction VariableName="InstallFolder" />
|
||||||
|
</Button>
|
||||||
|
<Button Name="OptionsOkButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
|
||||||
|
<Text>#(loc.OptionsOkButton)</Text>
|
||||||
|
<ChangePageAction Page="Install" />
|
||||||
|
</Button>
|
||||||
|
<Button Name="OptionsCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
|
||||||
|
<Text>#(loc.OptionsCancelButton)</Text>
|
||||||
|
<ChangePageAction Page="Install" Cancel="yes" />
|
||||||
|
</Button>
|
||||||
|
</Page>
|
||||||
|
<Page Name="Progress">
|
||||||
|
<Label X="80" Y="11" Width="-11" Height="32" FontId="1" DisablePrefix="yes">#(loc.Title)</Label>
|
||||||
|
<ImageControl X="11" Y="11" Width="64" Height="64" ImageFile="logo.png"/>
|
||||||
|
<Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.ProgressHeader)</Label>
|
||||||
|
<Label X="11" Y="141" Width="70" Height="17" FontId="3" DisablePrefix="yes">#(loc.ProgressLabel)</Label>
|
||||||
|
<Label Name="OverallProgressPackageText" X="85" Y="141" Width="-11" Height="17" FontId="3" DisablePrefix="yes">#(loc.OverallProgressPackageText)</Label>
|
||||||
|
<Progressbar Name="OverallCalculatedProgressbar" X="11" Y="163" Width="-11" Height="20" />
|
||||||
|
<Button Name="ProgressCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ProgressCancelButton)</Button>
|
||||||
|
</Page>
|
||||||
|
<Page Name="Modify">
|
||||||
|
<ImageControl X="11" Y="11" Width="165" Height="400" ImageFile="logoside.png"/>
|
||||||
|
<Label X="185" Y="11" Width="-11" Height="32" FontId="2" DisablePrefix="yes">#(loc.ModifyHeader)</Label>
|
||||||
|
<Label Name="InstallVersion" X="11" Y="-11" Width="-11" Height="17" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBAShowVersion">#(loc.InstallVersion)</Label>
|
||||||
|
<Button Name="ModifyUpdateButton" X="11" Y="-11" Width="200" Height="23" TabStop="yes" FontId="0" EnableCondition="WixStdBAUpdateAvailable" HideWhenDisabled="yes">#(loc.UpdateButton)</Button>
|
||||||
|
<Button Name="RepairButton" X="-171" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.ModifyRepairButton)</Button>
|
||||||
|
<Button Name="UninstallButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ModifyUninstallButton)</Button>
|
||||||
|
<Button Name="ModifyCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
|
||||||
|
<Text>#(loc.ModifyCancelButton)</Text>
|
||||||
|
<CloseWindowAction />
|
||||||
|
</Button>
|
||||||
|
</Page>
|
||||||
|
<Page Name="Success">
|
||||||
|
<ImageControl X="11" Y="11" Width="165" Height="400" ImageFile="logoside.png"/>
|
||||||
|
<Label X="185" Y="11" Width="-11" Height="32" FontId="2" DisablePrefix="yes">
|
||||||
|
<Text>#(loc.SuccessHeader)</Text>
|
||||||
|
<Text Condition="WixBundleAction = 2">#(loc.SuccessLayoutHeader)</Text>
|
||||||
|
<Text Condition="WixBundleAction = 3">#(loc.SuccessUnsafeUninstallHeader)</Text>
|
||||||
|
<Text Condition="WixBundleAction = 4">#(loc.SuccessUninstallHeader)</Text>
|
||||||
|
<Text Condition="WixBundleAction = 5">#(loc.SuccessCacheHeader)</Text>
|
||||||
|
<Text Condition="WixBundleAction = 6">#(loc.SuccessInstallHeader)</Text>
|
||||||
|
<Text Condition="WixBundleAction = 7">#(loc.SuccessModifyHeader)</Text>
|
||||||
|
<Text Condition="WixBundleAction = 8">#(loc.SuccessRepairHeader)</Text>
|
||||||
|
</Label>
|
||||||
|
<Button Name="LaunchButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessLaunchButton)</Button>
|
||||||
|
<Label X="185" Y="-51" Width="400" Height="34" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBARestartRequired">
|
||||||
|
<Text>#(loc.SuccessRestartText)</Text>
|
||||||
|
<Text Condition="WixBundleAction = 3">#(loc.SuccessUninstallRestartText)</Text>
|
||||||
|
</Label>
|
||||||
|
<Label Name="InstallVersion" X="11" Y="-11" Width="165" Height="17" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBAShowVersion">#(loc.InstallVersion)</Label>
|
||||||
|
<Button Name="SuccessRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessRestartButton)</Button>
|
||||||
|
<Button Name="SuccessCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
|
||||||
|
<Text>#(loc.SuccessCloseButton)</Text>
|
||||||
|
<CloseWindowAction />
|
||||||
|
</Button>
|
||||||
|
</Page>
|
||||||
|
<Page Name="Failure">
|
||||||
|
<ImageControl X="11" Y="11" Width="165" Height="400" ImageFile="logoside.png"/>
|
||||||
|
<Label X="185" Y="11" Width="-11" Height="32" FontId="2" DisablePrefix="yes">
|
||||||
|
<Text>#(loc.FailureHeader)</Text>
|
||||||
|
<Text Condition="WixBundleAction = 2">#(loc.FailureLayoutHeader)</Text>
|
||||||
|
<Text Condition="WixBundleAction = 3">#(loc.FailureUnsafeUninstallHeader)</Text>
|
||||||
|
<Text Condition="WixBundleAction = 4">#(loc.FailureUninstallHeader)</Text>
|
||||||
|
<Text Condition="WixBundleAction = 5">#(loc.FailureCacheHeader)</Text>
|
||||||
|
<Text Condition="WixBundleAction = 6">#(loc.FailureInstallHeader)</Text>
|
||||||
|
<Text Condition="WixBundleAction = 7">#(loc.FailureModifyHeader)</Text>
|
||||||
|
<Text Condition="WixBundleAction = 8">#(loc.FailureRepairHeader)</Text>
|
||||||
|
</Label>
|
||||||
|
<Hypertext Name="FailureLogFileLink" X="185" Y="121" Width="-11" Height="68" FontId="3" TabStop="yes" HideWhenDisabled="yes">#(loc.FailureHyperlinkLogText)</Hypertext>
|
||||||
|
<Hypertext Name="FailureMessageText" X="185" Y="-115" Width="-11" Height="80" FontId="3" TabStop="yes" HideWhenDisabled="yes" />
|
||||||
|
<Label Name="InstallVersion" X="11" Y="-11" Width="165" Height="17" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBAShowVersion">#(loc.InstallVersion)</Label>
|
||||||
|
<Label X="185" Y="-57" Width="-11" Height="80" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBARestartRequired">#(loc.FailureRestartText)</Label>
|
||||||
|
<Button Name="FailureRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.FailureRestartButton)</Button>
|
||||||
|
<Button Name="FailureCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
|
||||||
|
<Text>#(loc.FailureCloseButton)</Text>
|
||||||
|
<CloseWindowAction />
|
||||||
|
</Button>
|
||||||
|
</Page>
|
||||||
|
</Window>
|
||||||
|
</Theme>
|
||||||
+1
-1
@@ -10,7 +10,7 @@
|
|||||||
\vieww12000\viewh15840\viewkind0
|
\vieww12000\viewh15840\viewkind0
|
||||||
\pard\tx283\tx567\tx850\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\b\fs16\lang7 Cryptomator is distributed under the GPLv3 License, found below. Please see the bottom of this document for any other license applicable to code used within Cryptomator.\b0\par
|
\pard\tx283\tx567\tx850\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\b\fs16\lang7 Cryptomator is distributed under the GPLv3 License, found below. Please see the bottom of this document for any other license applicable to code used within Cryptomator.\b0\par
|
||||||
\par
|
\par
|
||||||
\b\'a9 2016 \'96 2024 Skymatic GmbH \b0\par
|
\b\'a9 2016 \'96 2025 Skymatic GmbH \b0\par
|
||||||
\par
|
\par
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\par
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\par
|
||||||
\par
|
\par
|
||||||
|
|||||||
Vendored
BIN
Binary file not shown.
Vendored
+1
@@ -0,0 +1 @@
|
|||||||
|
win-console=true
|
||||||
Vendored
+3
-2
@@ -6,9 +6,10 @@ java ^
|
|||||||
-Dcryptomator.ipcSocketPath="~/AppData/Roaming/Cryptomator/ipc.socket" ^
|
-Dcryptomator.ipcSocketPath="~/AppData/Roaming/Cryptomator/ipc.socket" ^
|
||||||
-Dcryptomator.logDir="~/AppData/Roaming/Cryptomator" ^
|
-Dcryptomator.logDir="~/AppData/Roaming/Cryptomator" ^
|
||||||
-Dcryptomator.mountPointsDir="~/Cryptomator" ^
|
-Dcryptomator.mountPointsDir="~/Cryptomator" ^
|
||||||
-Dcryptomator.keychainPath="~/AppData/Roaming/Cryptomator/keychain.json" ^
|
-Dcryptomator.integrationsWin.keychainPaths="~/AppData/Roaming/Cryptomator/keychain.json" ^
|
||||||
|
-Dcryptomator.integrationsWin.windowsHelloKeychainPaths="~/AppData/Roaming/Cryptomator/windowsHelloKeychain.json" ^
|
||||||
-Xss20m ^
|
-Xss20m ^
|
||||||
-Xmx512m ^
|
-Xmx512m ^
|
||||||
--enable-preview `
|
--enable-preview `
|
||||||
--enable-native-access=org.cryptomator.jfuse.win `
|
--enable-native-access=org.cryptomator.jfuse.win `
|
||||||
-m org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator
|
-m org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator
|
||||||
|
|||||||
Vendored
-109
@@ -1,109 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Include>
|
|
||||||
<Fragment>
|
|
||||||
<!-- copy pasta from https://github.com/wixtoolset/wix3/blob/develop/src/ext/UIExtension/wixlib/WixUI_InstallDir.wxs with custom exit dialog-->
|
|
||||||
<UI Id="CustomWizard">
|
|
||||||
<TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8" />
|
|
||||||
<TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="12" />
|
|
||||||
<TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" />
|
|
||||||
|
|
||||||
<Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
|
|
||||||
<Property Id="WixUI_Mode" Value="InstallDir" />
|
|
||||||
|
|
||||||
<DialogRef Id="BrowseDlg" />
|
|
||||||
<DialogRef Id="DiskCostDlg" />
|
|
||||||
<DialogRef Id="ErrorDlg" />
|
|
||||||
<DialogRef Id="FilesInUse" />
|
|
||||||
<DialogRef Id="MsiRMFilesInUse" />
|
|
||||||
<DialogRef Id="PrepareDlg" />
|
|
||||||
<DialogRef Id="ProgressDlg" />
|
|
||||||
<DialogRef Id="ResumeDlg" />
|
|
||||||
<DialogRef Id="UserExit" />
|
|
||||||
|
|
||||||
<Publish Dialog="BrowseDlg" Control="OK" Event="DoAction" Value="WixUIValidatePath" Order="3">1</Publish>
|
|
||||||
<Publish Dialog="BrowseDlg" Control="OK" Event="SpawnDialog" Value="InvalidDirDlg" Order="4"><![CDATA[NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"]]></Publish>
|
|
||||||
|
|
||||||
<!-- custom end dialogs -->
|
|
||||||
<Publish Dialog="MyExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999">1</Publish>
|
|
||||||
<Publish Dialog="MyFatalErrorDlg" Control="Finish" Event="EndDialog" Value="Return" Order="998">1</Publish>
|
|
||||||
|
|
||||||
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="LicenseAgreementDlg">NOT Installed</Publish>
|
|
||||||
<Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg">Installed AND PATCH</Publish>
|
|
||||||
|
|
||||||
<Publish Dialog="LicenseAgreementDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg">1</Publish>
|
|
||||||
<Publish Dialog="LicenseAgreementDlg" Control="Next" Event="NewDialog" Value="InstallDirDlg">LicenseAccepted = "1"</Publish>
|
|
||||||
|
|
||||||
<Publish Dialog="InstallDirDlg" Control="Back" Event="NewDialog" Value="LicenseAgreementDlg">1</Publish>
|
|
||||||
<Publish Dialog="InstallDirDlg" Control="Next" Event="SetTargetPath" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
|
|
||||||
<Publish Dialog="InstallDirDlg" Control="Next" Event="DoAction" Value="WixUIValidatePath" Order="2">NOT WIXUI_DONTVALIDATEPATH</Publish>
|
|
||||||
<Publish Dialog="InstallDirDlg" Control="Next" Event="SpawnDialog" Value="InvalidDirDlg" Order="3"><![CDATA[NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"]]></Publish>
|
|
||||||
<Publish Dialog="InstallDirDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" Order="4">WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1"</Publish>
|
|
||||||
<Publish Dialog="InstallDirDlg" Control="ChangeFolder" Property="_BrowseProperty" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
|
|
||||||
<Publish Dialog="InstallDirDlg" Control="ChangeFolder" Event="SpawnDialog" Value="BrowseDlg" Order="2">1</Publish>
|
|
||||||
|
|
||||||
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="InstallDirDlg" Order="1">NOT Installed</Publish>
|
|
||||||
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg" Order="2">Installed AND NOT PATCH</Publish>
|
|
||||||
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="2">Installed AND PATCH</Publish>
|
|
||||||
|
|
||||||
<Publish Dialog="MaintenanceWelcomeDlg" Control="Next" Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish>
|
|
||||||
|
|
||||||
<Publish Dialog="MaintenanceTypeDlg" Control="RepairButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
|
|
||||||
<Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
|
|
||||||
<Publish Dialog="MaintenanceTypeDlg" Control="Back" Event="NewDialog" Value="MaintenanceWelcomeDlg">1</Publish>
|
|
||||||
|
|
||||||
<Property Id="ARPNOMODIFY" Value="1" />
|
|
||||||
|
|
||||||
<!-- copy pasta from https://github.com/wixtoolset/wix3/blob/develop/src/ext/UIExtension/wixlib/ExitDialog.wxs with adjustments-->
|
|
||||||
<Dialog Id="MyExitDialog" Width="370" Height="270" Title="!(loc.ExitDialog_Title)">
|
|
||||||
<Control Id="Finish" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Cancel="yes" Text="!(loc.WixUIFinish)" />
|
|
||||||
<Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Disabled="yes" Text="!(loc.WixUICancel)" />
|
|
||||||
<Control Id="Bitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="234" TabSkip="no" Text="!(loc.ExitDialogBitmap)" />
|
|
||||||
<Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Disabled="yes" Text="!(loc.WixUIBack)" />
|
|
||||||
<Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" />
|
|
||||||
<Control Id="Description" Type="Text" X="135" Y="70" Width="220" Height="40" Transparent="yes" NoPrefix="yes" Text="!(loc.ExitDialogDescription)" />
|
|
||||||
|
|
||||||
<Control Id="Title" Type="Text" X="135" Y="20" Width="220" Height="60" Transparent="yes" NoPrefix="yes" Text="!(loc.ExitDialogTitle)" />
|
|
||||||
<!-- TODO: localize? -->
|
|
||||||
<Control Id="Suggestion" Type="Text" X="135" Y="100" Width="220" Height="60" Transparent="yes" NoPrefix="yes">
|
|
||||||
<Text>We recommend for the best user experience to download and install the following third party Windows driver:</Text>
|
|
||||||
</Control>
|
|
||||||
<Control Id="WinFsp" Type="Hyperlink" X="140" Y="125" Width="220" Height="60" Transparent="yes">
|
|
||||||
<Text><![CDATA[WinFsp (<a href="https://winfsp.dev/">Homepage</a>)]]></Text>
|
|
||||||
</Control>
|
|
||||||
</Dialog>
|
|
||||||
|
|
||||||
<!-- copy pasta from https://github.com/wixtoolset/wix3/blob/develop/src/ext/UIExtension/wixlib/FatalError.wxs with adjustments-->
|
|
||||||
<Dialog Id="MyFatalErrorDlg" Width="370" Height="270" Title="!(loc.FatalError_Title)">
|
|
||||||
<Control Id="Finish" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Cancel="yes" Text="!(loc.WixUIFinish)">
|
|
||||||
<Publish Event="EndDialog" Value="Exit">1</Publish>
|
|
||||||
</Control>
|
|
||||||
<Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Disabled="yes" Text="!(loc.WixUICancel)" />
|
|
||||||
<Control Id="Bitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="234" TabSkip="no" Text="!(loc.FatalErrorBitmap)" />
|
|
||||||
<Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Disabled="yes" Text="!(loc.WixUIBack)" />
|
|
||||||
<Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" />
|
|
||||||
<Control Id="Title" Type="Text" X="135" Y="20" Width="220" Height="60" Transparent="yes" NoPrefix="yes" Text="!(loc.FatalErrorTitle)" />
|
|
||||||
<Control Id="Description" Type="Text" X="135" Y="70" Width="220" Height="80" Transparent="yes" NoPrefix="yes" Text="!(loc.FatalErrorDescription1) !(loc.FatalErrorDescription2)" />
|
|
||||||
<Control Id="DescriptionReason1" Type="Text" X="135" Y="160" Width="220" Height="20" Transparent="yes" NoPrefix="yes" Hidden="yes" >
|
|
||||||
<Text>Reason:</Text>
|
|
||||||
<Condition Action="show">FOUNDRUNNINGAPP</Condition>
|
|
||||||
</Control>
|
|
||||||
<Control Id="DescriptionReason2" Type="Text" X="135" Y="170" Width="220" Height="40" Transparent="yes" NoPrefix="yes" Hidden="yes" >
|
|
||||||
<Text>Application to update was still running during installation.</Text>
|
|
||||||
<Condition Action="show">FOUNDRUNNINGAPP</Condition>
|
|
||||||
</Control>
|
|
||||||
</Dialog>
|
|
||||||
|
|
||||||
<InstallUISequence>
|
|
||||||
<Show Dialog="MyExitDialog" Overridable="yes" OnExit="success"/>
|
|
||||||
<Show Dialog="MyFatalErrorDlg" Overridable="yes" OnExit="error"/>
|
|
||||||
</InstallUISequence>
|
|
||||||
<AdminUISequence>
|
|
||||||
<Show Dialog="MyExitDialog" Overridable="yes" OnExit="success"/>
|
|
||||||
<Show Dialog="MyFatalErrorDlg" Overridable="yes" OnExit="error"/>
|
|
||||||
</AdminUISequence>
|
|
||||||
|
|
||||||
</UI>
|
|
||||||
|
|
||||||
<UIRef Id="WixUI_Common" />
|
|
||||||
</Fragment>
|
|
||||||
</Include>
|
|
||||||
+1
-1
@@ -10,7 +10,7 @@
|
|||||||
\vieww12000\viewh15840\viewkind0
|
\vieww12000\viewh15840\viewkind0
|
||||||
\pard\tx283\tx567\tx850\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\b\fs16\lang7 Cryptomator is distributed under the GPLv3 License, found below. Please see the bottom of this document for any other license applicable to code used within Cryptomator.\b0\par
|
\pard\tx283\tx567\tx850\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\b\fs16\lang7 Cryptomator is distributed under the GPLv3 License, found below. Please see the bottom of this document for any other license applicable to code used within Cryptomator.\b0\par
|
||||||
\par
|
\par
|
||||||
\b\'a9 2016 \'96 2024 Skymatic GmbH \b0\par
|
\b\'a9 2016 \'96 2025 Skymatic GmbH \b0\par
|
||||||
\par
|
\par
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\par
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\par
|
||||||
\par
|
\par
|
||||||
|
|||||||
Vendored
+105
-115
@@ -1,6 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
|
<ns0:Wix xmlns:ns0="http://wixtoolset.org/schemas/v4/wxs" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util" >
|
||||||
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
|
|
||||||
|
|
||||||
<?ifdef JpIsSystemWide ?>
|
<?ifdef JpIsSystemWide ?>
|
||||||
<?define JpInstallScope="perMachine"?>
|
<?define JpInstallScope="perMachine"?>
|
||||||
@@ -30,174 +29,165 @@
|
|||||||
|
|
||||||
<?include $(var.JpConfigDir)/overrides.wxi ?>
|
<?include $(var.JpConfigDir)/overrides.wxi ?>
|
||||||
|
|
||||||
<Product
|
<ns0:Package
|
||||||
Id="$(var.JpProductCode)"
|
Name="$(var.JpAppName)"
|
||||||
Name="$(var.JpAppName)"
|
Language="$(var.JpProductLanguage)"
|
||||||
Language="$(var.JpProductLanguage)"
|
Version="$(var.JpAppVersion)"
|
||||||
Version="$(var.JpAppVersion)"
|
Manufacturer="$(var.JpAppVendor)"
|
||||||
Manufacturer="$(var.JpAppVendor)"
|
UpgradeCode="$(var.JpProductUpgradeCode)"
|
||||||
UpgradeCode="$(var.JpProductUpgradeCode)">
|
InstallerVersion="$(var.JpInstallerVersion)"
|
||||||
|
Compressed="$(var.JpCompressedMsi)"
|
||||||
|
ProductCode="$(var.JpProductCode)"
|
||||||
|
Scope="$(var.JpInstallScope)">
|
||||||
|
|
||||||
<Package
|
<ns0:SummaryInformation Manufacturer="$(var.JpAppVendor)" Description="$(var.JpAppDescription)"/>
|
||||||
Description="$(var.JpAppDescription)"
|
<ns0:Media Id="1" Cabinet="Data.cab" EmbedCab="yes" />
|
||||||
Manufacturer="$(var.JpAppVendor)"
|
|
||||||
InstallerVersion="$(var.JpInstallerVersion)"
|
|
||||||
Compressed="$(var.JpCompressedMsi)"
|
|
||||||
InstallScope="$(var.JpInstallScope)" Platform="x64"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Media Id="1" Cabinet="Data.cab" EmbedCab="yes" />
|
|
||||||
|
|
||||||
<Upgrade Id="$(var.JpProductUpgradeCode)">
|
<ns0:Upgrade Id="$(var.JpProductUpgradeCode)">
|
||||||
<UpgradeVersion
|
<ns0:UpgradeVersion
|
||||||
OnlyDetect="$(var.JpUpgradeVersionOnlyDetectUpgrade)"
|
OnlyDetect="$(var.JpUpgradeVersionOnlyDetectUpgrade)"
|
||||||
Property="JP_UPGRADABLE_FOUND"
|
Property="JP_UPGRADABLE_FOUND"
|
||||||
Maximum="$(var.JpAppVersion)"
|
Maximum="$(var.JpAppVersion)"
|
||||||
MigrateFeatures="yes"
|
MigrateFeatures="yes"
|
||||||
IncludeMaximum="yes" /> <!-- TODO: check if this needs to be set to yes-->
|
IncludeMaximum="$(var.JpUpgradeVersionOnlyDetectUpgrade)"/> <!-- TODO in earlier versions, this was set to yes-->
|
||||||
<UpgradeVersion
|
<ns0:UpgradeVersion
|
||||||
OnlyDetect="$(var.JpUpgradeVersionOnlyDetectDowngrade)"
|
OnlyDetect="$(var.JpUpgradeVersionOnlyDetectDowngrade)"
|
||||||
Property="JP_DOWNGRADABLE_FOUND"
|
Property="JP_DOWNGRADABLE_FOUND"
|
||||||
Minimum="$(var.JpAppVersion)"
|
Minimum="$(var.JpAppVersion)"
|
||||||
MigrateFeatures="yes"
|
MigrateFeatures="yes"
|
||||||
IncludeMinimum="$(var.JpUpgradeVersionOnlyDetectDowngrade)" />
|
IncludeMinimum="$(var.JpUpgradeVersionOnlyDetectDowngrade)" />
|
||||||
</Upgrade>
|
</ns0:Upgrade>
|
||||||
|
|
||||||
<?ifndef JpAllowUpgrades ?>
|
<?ifndef JpAllowUpgrades ?>
|
||||||
<CustomAction Id="JpDisallowUpgrade" Error="!(loc.DisallowUpgradeErrorMessage)" />
|
<ns0:CustomAction Id="JpDisallowUpgrade" Error="!(loc.DisallowUpgradeErrorMessage)" />
|
||||||
<?endif?>
|
<?endif?>
|
||||||
<?ifndef JpAllowDowngrades ?>
|
<?ifndef JpAllowDowngrades ?>
|
||||||
<CustomAction Id="JpDisallowDowngrade" Error="!(loc.DowngradeErrorMessage)" />
|
<ns0:CustomAction Id="JpDisallowDowngrade" Error="!(loc.DowngradeErrorMessage)" />
|
||||||
<?endif?>
|
<?endif?>
|
||||||
|
|
||||||
<Binary Id="JpCaDll" SourceFile="$(env.JP_WIXHELPER_DIR)\wixhelper.dll"/>
|
<!-- TODO: how does this work again? -->
|
||||||
<CustomAction Id="JpFindRelatedProducts" BinaryKey="JpCaDll" DllEntry="FindRelatedProductsEx" />
|
<ns0:Binary Id="JpCaDll" SourceFile="$(env.JP_WIXHELPER_DIR)\wixhelper.dll" />
|
||||||
|
<ns0:CustomAction Id="JpFindRelatedProducts" BinaryRef="JpCaDll" DllEntry="FindRelatedProductsEx" />
|
||||||
|
|
||||||
<?ifndef SkipCryptomatorLegacyCheck ?>
|
<?ifndef SkipCryptomatorLegacyCheck ?>
|
||||||
<!-- Block installation if innosetup entry of Cryptomator is found -->
|
<!-- Block installation if innosetup entry of Cryptomator is found -->
|
||||||
<Property Id="OLDEXEINSTALLER">
|
<ns0:Property Id="OLDEXEINSTALLER">
|
||||||
<RegistrySearch Id="InnoSetupInstallation" Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\Cryptomator_is1" Type="raw" Name="DisplayName" />
|
<ns0:RegistrySearch Id="InnoSetupInstallation" Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\Cryptomator_is1" Type="raw" Name="DisplayName" />
|
||||||
</Property>
|
</ns0:Property>
|
||||||
<!-- TODO: localize -->
|
<!-- TODO: localize -->
|
||||||
<Condition Message="A lower version of [ProductName] is already installed. Uninstall it first and then start the setup again. Setup will now exit.">
|
<ns0:Launch Message="A lower version of [ProductName] is already installed. Uninstall it first and then start the setup again. Setup will now exit." Condition="Installed OR NOT OLDEXEINSTALLER" />
|
||||||
<![CDATA[Installed OR NOT OLDEXEINSTALLER]]>
|
|
||||||
</Condition>
|
|
||||||
<?endif?>
|
<?endif?>
|
||||||
<!-- Cryptomator uses UNIX Sockets, which are supported starting with Windows 10 v1803-->
|
<!-- Cryptomator uses UNIX Sockets, which are supported starting with Windows 10 v1803-->
|
||||||
<Property Id="WINDOWSBUILDNUMBER" Secure="yes">
|
<ns0:Property Id="WINDOWSBUILDNUMBER" Secure="yes">
|
||||||
<RegistrySearch Id="BuildNumberSearch" Root="HKLM" Key="SOFTWARE\Microsoft\Windows NT\CurrentVersion" Name="CurrentBuildNumber" Type="raw" />
|
<ns0:RegistrySearch Id="BuildNumberSearch" Root="HKLM" Key="SOFTWARE\Microsoft\Windows NT\CurrentVersion" Name="CurrentBuildNumber" Type="raw" />
|
||||||
</Property>
|
</ns0:Property>
|
||||||
<Condition Message="This application requires Windows 10 version 1803 (build 17134) or newer.">
|
<ns0:Launch Message="This application requires Windows 10 version 1803 (build 17134) or newer." Condition="Installed OR (WINDOWSBUILDNUMBER >= 17134)" />
|
||||||
<![CDATA[Installed OR (WINDOWSBUILDNUMBER >= 17134)]]>
|
|
||||||
</Condition>
|
|
||||||
|
|
||||||
<!-- Non-Opening ProgID -->
|
<!-- Non-Opening ProgID -->
|
||||||
<DirectoryRef Id="INSTALLDIR">
|
<ns0:DirectoryRef Id="INSTALLDIR">
|
||||||
<Component Win64="yes" Id="nonStartingProgID" >
|
<ns0:Component Bitness="always64" Id="nonStartingProgID" >
|
||||||
<File Id="IconFileForEncryptedData" KeyPath="yes" Source="$(env.JP_WIXWIZARD_RESOURCES)\$(var.IconFileEncryptedData)" Name="$(var.IconFileEncryptedData)"></File>
|
<ns0:File Id="IconFileForEncryptedData" KeyPath="yes" Source="$(env.JP_WIXWIZARD_RESOURCES)\$(var.IconFileEncryptedData)" Name="$(var.IconFileEncryptedData)"/>
|
||||||
<ProgId Id="$(var.JpAppName).Encrypted.1" Description="$(var.JpAppName) Encrypted Data" Icon="IconFileForEncryptedData" IconIndex="0">
|
<ns0:ProgId Id="$(var.JpAppName).Encrypted.1" Description="$(var.JpAppName) Encrypted Data" Icon="IconFileForEncryptedData" IconIndex="0">
|
||||||
<Extension Id="c9r" Advertise="no" ContentType="$(var.ProgIdContentType)">
|
<ns0:Extension Id="c9r" Advertise="no" ContentType="$(var.ProgIdContentType)">
|
||||||
<MIME ContentType="$(var.ProgIdContentType)" Default="yes"></MIME>
|
<ns0:MIME ContentType="$(var.ProgIdContentType)" Default="yes"/>
|
||||||
</Extension>
|
</ns0:Extension>
|
||||||
<Extension Id="c9s" Advertise="no" ContentType="$(var.ProgIdContentType)"/>
|
<ns0:Extension Id="c9s" Advertise="no" ContentType="$(var.ProgIdContentType)"/>
|
||||||
</ProgId>
|
</ns0:ProgId>
|
||||||
</Component>
|
</ns0:Component>
|
||||||
</DirectoryRef>
|
</ns0:DirectoryRef>
|
||||||
|
|
||||||
<!-- Standard required root -->
|
<!-- Standard required root -->
|
||||||
<Directory Id="TARGETDIR" Name="SourceDir"/>
|
|
||||||
|
|
||||||
<Feature Id="DefaultFeature" Title="!(loc.MainFeatureTitle)" Level="1">
|
<ns0:Feature Id="DefaultFeature" Title="!(loc.MainFeatureTitle)" Level="1">
|
||||||
<ComponentGroupRef Id="Shortcuts"/>
|
<ns0:ComponentGroupRef Id="Shortcuts"/>
|
||||||
<ComponentGroupRef Id="Files"/>
|
<ns0:ComponentGroupRef Id="Files"/>
|
||||||
<ComponentGroupRef Id="FileAssociations"/>
|
<ns0:ComponentGroupRef Id="FileAssociations"/>
|
||||||
<!-- Ref to additional ProgIDs -->
|
<!-- Ref to additional ProgIDs -->
|
||||||
<ComponentRef Id="nonStartingProgID" />
|
<ns0:ComponentRef Id="nonStartingProgID" />
|
||||||
</Feature>
|
</ns0:Feature>
|
||||||
|
|
||||||
<CustomAction Id="JpSetARPINSTALLLOCATION" Property="ARPINSTALLLOCATION" Value="[INSTALLDIR]" />
|
<ns0:CustomAction Id="JpSetARPINSTALLLOCATION" Property="ARPINSTALLLOCATION" Value="[INSTALLDIR]" />
|
||||||
<CustomAction Id="JpSetARPCOMMENTS" Property="ARPCOMMENTS" Value="$(var.JpAppDescription)" />
|
<ns0:CustomAction Id="JpSetARPCOMMENTS" Property="ARPCOMMENTS" Value="$(var.JpAppDescription)" />
|
||||||
<CustomAction Id="JpSetARPCONTACT" Property="ARPCONTACT" Value="$(var.JpAppVendor)" />
|
<ns0:CustomAction Id="JpSetARPCONTACT" Property="ARPCONTACT" Value="$(var.JpAppVendor)" />
|
||||||
<CustomAction Id="JpSetARPSIZE" Property="ARPSIZE" Value="$(var.JpAppSizeKb)" />
|
<ns0:CustomAction Id="JpSetARPSIZE" Property="ARPSIZE" Value="$(var.JpAppSizeKb)" />
|
||||||
|
|
||||||
<?ifdef JpHelpURL ?>
|
<?ifdef JpHelpURL ?>
|
||||||
<CustomAction Id="JpSetARPHELPLINK" Property="ARPHELPLINK" Value="$(var.JpHelpURL)" />
|
<ns0:CustomAction Id="JpSetARPHELPLINK" Property="ARPHELPLINK" Value="$(var.JpHelpURL)" />
|
||||||
<?endif?>
|
<?endif?>
|
||||||
|
|
||||||
<?ifdef JpAboutURL ?>
|
<?ifdef JpAboutURL ?>
|
||||||
<CustomAction Id="JpSetARPURLINFOABOUT" Property="ARPURLINFOABOUT" Value="$(var.JpAboutURL)" />
|
<ns0:CustomAction Id="JpSetARPURLINFOABOUT" Property="ARPURLINFOABOUT" Value="$(var.JpAboutURL)" />
|
||||||
<?endif?>
|
<?endif?>
|
||||||
|
|
||||||
<?ifdef JpUpdateURL ?>
|
<?ifdef JpUpdateURL ?>
|
||||||
<CustomAction Id="JpSetARPURLUPDATEINFO" Property="ARPURLUPDATEINFO" Value="$(var.JpUpdateURL)" />
|
<ns0:CustomAction Id="JpSetARPURLUPDATEINFO" Property="ARPURLUPDATEINFO" Value="$(var.JpUpdateURL)" />
|
||||||
<?endif?>
|
<?endif?>
|
||||||
|
|
||||||
<Property Id="WixQuietExec64CmdTimeout" Value="20" />
|
<ns0:Property Id="WixQuietExec64CmdTimeout" Value="20" />
|
||||||
<!-- Note for custom actions: Immediate CAs run BEFORE the files are installed, hence if you depend on installed files, the CAs must be deferred.-->
|
<!-- Note for custom actions: Immediate CAs run BEFORE the files are installed, hence if you depend on installed files, the CAs must be deferred.-->
|
||||||
<!-- WebDAV patches -->
|
<!-- WebDAV patches -->
|
||||||
<SetProperty Id="PatchWebDAV" Value=""[INSTALLDIR]patchWebDAV.bat""
|
<ns0:SetProperty Id="PatchWebDAV" Value=""[INSTALLDIR]patchWebDAV.bat"" Sequence="execute" Before="PatchWebDAV" />
|
||||||
Sequence="execute" Before="PatchWebDAV" />
|
<ns0:CustomAction Id="PatchWebDAV" BinaryRef="Wix4UtilCA_$(sys.BUILDARCHSHORT)" DllEntry="WixQuietExec" Execute="deferred" Return="ignore" Impersonate="no"/>
|
||||||
<CustomAction Id="PatchWebDAV" BinaryKey="WixCA" DllEntry="WixQuietExec64" Execute="deferred" Return="ignore" Impersonate="no"/>
|
|
||||||
|
|
||||||
<!-- Running App detection and exit -->
|
<!-- Running App detection and exit -->
|
||||||
<Property Id="FOUNDRUNNINGAPP" Admin="yes"/>
|
<ns0:Property Id="FOUNDRUNNINGAPP" Admin="yes"/>
|
||||||
<util:CloseApplication
|
<util:CloseApplication
|
||||||
Target="$(var.CloseApplicationTarget)"
|
Target="$(var.CloseApplicationTarget)"
|
||||||
Id="Close$(var.JpAppName)"
|
Id="Close$(var.JpAppName)"
|
||||||
CloseMessage="no"
|
CloseMessage="no"
|
||||||
RebootPrompt="no"
|
RebootPrompt="no"
|
||||||
PromptToContinue="yes"
|
PromptToContinue="yes"
|
||||||
Description="A running instance of $(var.JpAppName) is found, using files marked for update. Please close it to continue."
|
Description="A running instance of $(var.JpAppName) is found, using files marked for update. Please close it to continue."
|
||||||
Property="FOUNDRUNNINGAPP"
|
Property="FOUNDRUNNINGAPP"
|
||||||
>
|
/>
|
||||||
</util:CloseApplication>
|
<ns0:CustomAction Id="FailOnRunningApp" Error="Installation aborted, because files marked for update are used by a running instance of $(var.JpAppName)."/>
|
||||||
<CustomAction Id="FailOnRunningApp" Error="Installation aborted, because files marked for update are used by a running instance of $(var.JpAppName)."/>
|
|
||||||
|
|
||||||
<?ifdef JpIcon ?>
|
<?ifdef JpIcon ?>
|
||||||
<Property Id="ARPPRODUCTICON" Value="JpARPPRODUCTICON"/>
|
<ns0:Property Id="ARPPRODUCTICON" Value="JpARPPRODUCTICON"/>
|
||||||
<Icon Id="JpARPPRODUCTICON" SourceFile="$(var.JpIcon)"/>
|
<ns0:Icon Id="JpARPPRODUCTICON" SourceFile="$(var.JpIcon)"/>
|
||||||
<?endif?>
|
<?endif?>
|
||||||
|
|
||||||
<UIRef Id="JpUI"/>
|
<ns0:UIRef Id="JpUI"/>
|
||||||
|
|
||||||
<InstallExecuteSequence>
|
<ns0:InstallExecuteSequence>
|
||||||
<Custom Action="JpSetARPINSTALLLOCATION" After="CostFinalize">Not Installed</Custom>
|
<ns0:Custom Action="JpSetARPINSTALLLOCATION" After="CostFinalize" Condition="Not Installed" />
|
||||||
<Custom Action="JpSetARPCOMMENTS" After="CostFinalize">Not Installed</Custom>
|
<ns0:Custom Action="JpSetARPCOMMENTS" After="CostFinalize" Condition="Not Installed" />
|
||||||
<Custom Action="JpSetARPCONTACT" After="CostFinalize">Not Installed</Custom>
|
<ns0:Custom Action="JpSetARPCONTACT" After="CostFinalize" Condition="Not Installed" />
|
||||||
<Custom Action="JpSetARPSIZE" After="CostFinalize">Not Installed</Custom>
|
<ns0:Custom Action="JpSetARPSIZE" After="CostFinalize" Condition="Not Installed" />
|
||||||
<?ifdef JpHelpURL ?>
|
<?ifdef JpHelpURL ?>
|
||||||
<Custom Action="JpSetARPHELPLINK" After="CostFinalize">Not Installed</Custom>
|
<ns0:Custom Action="JpSetARPHELPLINK" After="CostFinalize" Condition="Not Installed" />
|
||||||
<?endif?>
|
<?endif?>
|
||||||
<?ifdef JpAboutURL ?>
|
<?ifdef JpAboutURL ?>
|
||||||
<Custom Action="JpSetARPURLINFOABOUT" After="CostFinalize">Not Installed</Custom>
|
<ns0:Custom Action="JpSetARPURLINFOABOUT" After="CostFinalize" Condition="Not Installed" />
|
||||||
<?endif?>
|
<?endif?>
|
||||||
<?ifdef JpUpdateURL ?>
|
<?ifdef JpUpdateURL ?>
|
||||||
<Custom Action="JpSetARPURLUPDATEINFO" After="CostFinalize">Not Installed</Custom>
|
<ns0:Custom Action="JpSetARPURLUPDATEINFO" After="CostFinalize" Condition="Not Installed" />
|
||||||
<?endif?>
|
<?endif?>
|
||||||
|
|
||||||
<?ifndef JpAllowUpgrades ?>
|
<?ifndef JpAllowUpgrades ?>
|
||||||
<Custom Action="JpDisallowUpgrade" After="JpFindRelatedProducts">JP_UPGRADABLE_FOUND</Custom>
|
<ns0:Custom Action="JpDisallowUpgrade" After="JpFindRelatedProducts" Condition="JP_UPGRADABLE_FOUND"/>
|
||||||
<?endif?>
|
<?endif?>
|
||||||
<?ifndef JpAllowDowngrades ?>
|
<?ifndef JpAllowDowngrades ?>
|
||||||
<Custom Action="JpDisallowDowngrade" After="JpFindRelatedProducts">JP_DOWNGRADABLE_FOUND</Custom>
|
<ns0:Custom Action="JpDisallowDowngrade" After="JpFindRelatedProducts" Condition="JP_DOWNGRADABLE_FOUND" />
|
||||||
<?endif?>
|
<?endif?>
|
||||||
<Custom Action="JpFindRelatedProducts" After="FindRelatedProducts"/>
|
<ns0:Custom Action="JpFindRelatedProducts" After="FindRelatedProducts"/>
|
||||||
|
|
||||||
<!-- Check and fail if Cryptomator is running -->
|
<!-- Check and fail if Cryptomator is running -->
|
||||||
<Custom Action="WixCloseApplications" Before="InstallValidate"></Custom>
|
<ns0:Custom Action="override Wix4CloseApplications_$(sys.BUILDARCHSHORT)" Before="InstallValidate" />
|
||||||
<Custom Action="FailOnRunningApp" After="WixCloseApplications" >FOUNDRUNNINGAPP</Custom>
|
<ns0:Custom Action="FailOnRunningApp" After="Wix4CloseApplications_$(sys.BUILDARCHSHORT)" Condition="FOUNDRUNNINGAPP" />
|
||||||
|
|
||||||
<RemoveExistingProducts After="InstallValidate"/> <!-- Moved from CostInitialize, due to WixCloseApplications -->
|
<ns0:RemoveExistingProducts After="InstallValidate"/> <!-- Moved from CostInitialize, due to Wix4CloseApplications_* -->
|
||||||
|
<!-- 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:InstallExecuteSequence>
|
||||||
|
|
||||||
<Custom Action="PatchWebDAV" After="InstallFiles">NOT Installed OR REINSTALL</Custom>
|
<ns0:InstallUISequence>
|
||||||
</InstallExecuteSequence>
|
<ns0:Custom Action="JpFindRelatedProducts" After="FindRelatedProducts"/>
|
||||||
|
</ns0:InstallUISequence>
|
||||||
|
|
||||||
<InstallUISequence>
|
<ns0:WixVariable Id="WixUIBannerBmp" Value="$(env.JP_WIXWIZARD_RESOURCES)\banner.bmp" />
|
||||||
<Custom Action="JpFindRelatedProducts" After="FindRelatedProducts"/>
|
<ns0:WixVariable Id="WixUIDialogBmp" Value="$(env.JP_WIXWIZARD_RESOURCES)\background.bmp" />
|
||||||
</InstallUISequence>
|
</ns0:Package>
|
||||||
|
</ns0:Wix>
|
||||||
<WixVariable Id="WixUIBannerBmp" Value="$(env.JP_WIXWIZARD_RESOURCES)\banner.bmp" />
|
|
||||||
<WixVariable Id="WixUIDialogBmp" Value="$(env.JP_WIXWIZARD_RESOURCES)\background.bmp" />
|
|
||||||
</Product>
|
|
||||||
|
|
||||||
</Wix>
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -47,4 +47,4 @@ Legacy Installation settings:
|
|||||||
- SkipCryptomatorLegacyCheck
|
- SkipCryptomatorLegacyCheck
|
||||||
Should be defined to disable checking for the inno setup installation of Cryptomator and undefined, to enable it.
|
Should be defined to disable checking for the inno setup installation of Cryptomator and undefined, to enable it.
|
||||||
-->
|
-->
|
||||||
<Include/>
|
<ns0:Include xmlns:ns0="http://wixtoolset.org/schemas/v4/wxs"></ns0:Include>
|
||||||
|
|||||||
Vendored
-16
@@ -1,16 +0,0 @@
|
|||||||
<?xml version="1.0" ?>
|
|
||||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
|
|
||||||
<Fragment>
|
|
||||||
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR"></Property>
|
|
||||||
<WixVariable Id="WixUILicenseRtf" Value="$(var.JpLicenseRtf)"></WixVariable>
|
|
||||||
<UI Id="JpUI">
|
|
||||||
<UIRef Id="CustomWizard" />
|
|
||||||
<DialogRef Id="InstallDirNotEmptyDlg"></DialogRef>
|
|
||||||
<Publish Dialog="ShortcutPromptDlg" Control="Back" Event="NewDialog" Value="InstallDirDlg">1</Publish>
|
|
||||||
<Publish Dialog="ShortcutPromptDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
|
|
||||||
<Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="ShortcutPromptDlg" Order="6">NOT Installed</Publish>
|
|
||||||
<UIRef Id="CustomWizard" />
|
|
||||||
</UI>
|
|
||||||
</Fragment>
|
|
||||||
<?include $(env.JP_WIXWIZARD_RESOURCES)\customWizard.wxi ?>
|
|
||||||
</Wix>
|
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.cryptomator</groupId>
|
<groupId>org.cryptomator</groupId>
|
||||||
<artifactId>cryptomator</artifactId>
|
<artifactId>cryptomator</artifactId>
|
||||||
<version>1.15.0-SNAPSHOT</version>
|
<version>1.18.0-SNAPSHOT</version>
|
||||||
<name>Cryptomator Desktop App</name>
|
<name>Cryptomator Desktop App</name>
|
||||||
|
|
||||||
<organization>
|
<organization>
|
||||||
@@ -26,58 +26,72 @@
|
|||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<project.jdk.version>23</project.jdk.version>
|
<project.jdk.version>24</project.jdk.version>
|
||||||
|
|
||||||
<!-- Group IDs of jars that need to stay on the class path for now -->
|
<!-- Group IDs of jars that need to stay on the class path for now -->
|
||||||
<!-- remove them, as soon they got modularized or support is dropped (i.e., WebDAV) -->
|
<!-- remove them, as soon they got modularized or support is dropped (i.e., WebDAV) -->
|
||||||
<nonModularGroupIds>org.ow2.asm,org.apache.jackrabbit,org.apache.httpcomponents</nonModularGroupIds>
|
<nonModularGroupIds>org.ow2.asm,org.apache.jackrabbit,org.apache.httpcomponents</nonModularGroupIds>
|
||||||
|
|
||||||
<!-- cryptomator dependencies -->
|
<!-- cryptomator dependencies -->
|
||||||
<cryptomator.cryptofs.version>2.7.1</cryptomator.cryptofs.version>
|
<cryptomator.cryptofs.version>2.9.0</cryptomator.cryptofs.version>
|
||||||
<cryptomator.integrations.version>1.4.0</cryptomator.integrations.version>
|
<cryptomator.integrations.version>1.6.0</cryptomator.integrations.version>
|
||||||
<cryptomator.integrations.win.version>1.4.1</cryptomator.integrations.win.version>
|
<cryptomator.integrations.win.version>1.5.0</cryptomator.integrations.win.version>
|
||||||
<cryptomator.integrations.mac.version>1.3.0</cryptomator.integrations.mac.version>
|
<cryptomator.integrations.mac.version>1.4.0</cryptomator.integrations.mac.version>
|
||||||
<cryptomator.integrations.linux.version>1.5.1</cryptomator.integrations.linux.version>
|
<cryptomator.integrations.linux.version>1.6.0</cryptomator.integrations.linux.version>
|
||||||
<cryptomator.fuse.version>5.0.2</cryptomator.fuse.version>
|
<cryptomator.fuse.version>5.0.5</cryptomator.fuse.version>
|
||||||
<cryptomator.webdav.version>2.0.7</cryptomator.webdav.version>
|
<cryptomator.webdav.version>2.0.10</cryptomator.webdav.version>
|
||||||
|
|
||||||
<!-- 3rd party dependencies -->
|
<!-- 3rd party dependencies -->
|
||||||
<commons-lang3.version>3.17.0</commons-lang3.version>
|
<commons-lang3.version>3.17.0</commons-lang3.version>
|
||||||
<dagger.version>2.52</dagger.version>
|
<dagger.version>2.56.2</dagger.version>
|
||||||
<easybind.version>2.2</easybind.version>
|
<easybind.version>2.2</easybind.version>
|
||||||
<jackson.version>2.18.1</jackson.version>
|
<jackson.version>2.19.1</jackson.version>
|
||||||
<javafx.version>22.0.2</javafx.version>
|
<javafx.version>24.0.1</javafx.version>
|
||||||
<jwt.version>4.4.0</jwt.version>
|
<jwt.version>4.5.0</jwt.version>
|
||||||
<nimbus-jose.version>9.37.3</nimbus-jose.version>
|
<nimbus-jose.version>9.37.3</nimbus-jose.version>
|
||||||
<logback.version>1.5.12</logback.version>
|
<logback.version>1.5.18</logback.version>
|
||||||
<slf4j.version>2.0.16</slf4j.version>
|
<slf4j.version>2.0.17</slf4j.version>
|
||||||
<tinyoauth2.version>0.8.0</tinyoauth2.version>
|
<tinyoauth2.version>0.8.1</tinyoauth2.version>
|
||||||
<zxcvbn.version>1.9.0</zxcvbn.version>
|
<zxcvbn.version>1.9.0</zxcvbn.version>
|
||||||
|
|
||||||
<!-- test dependencies -->
|
<!-- test dependencies -->
|
||||||
<junit.jupiter.version>5.11.3</junit.jupiter.version>
|
<junit.jupiter.version>5.13.1</junit.jupiter.version>
|
||||||
<mockito.version>5.14.2</mockito.version>
|
<mockito.version>5.18.0</mockito.version>
|
||||||
<hamcrest.version>3.0</hamcrest.version>
|
<hamcrest.version>3.0</hamcrest.version>
|
||||||
|
|
||||||
<!-- build-time dependencies -->
|
<!-- build-time dependencies -->
|
||||||
<jetbrains.annotations.version>26.0.1</jetbrains.annotations.version>
|
<jetbrains.annotations.version>26.0.2</jetbrains.annotations.version>
|
||||||
<dependency-check.version>11.1.0</dependency-check.version>
|
<dependency-check.version>12.1.3</dependency-check.version>
|
||||||
<jacoco.version>0.8.12</jacoco.version>
|
<jacoco.version>0.8.13</jacoco.version>
|
||||||
<license-generator.version>2.4.0</license-generator.version>
|
<license-generator.version>2.5.0</license-generator.version>
|
||||||
<junit-tree-reporter.version>1.3.0</junit-tree-reporter.version>
|
<junit-tree-reporter.version>1.4.0</junit-tree-reporter.version>
|
||||||
<mvn-compiler.version>3.13.0</mvn-compiler.version>
|
<mvn-compiler.version>3.14.0</mvn-compiler.version>
|
||||||
<mvn-resources.version>3.3.1</mvn-resources.version>
|
<mvn-resources.version>3.3.1</mvn-resources.version>
|
||||||
<mvn-dependency.version>3.8.1</mvn-dependency.version>
|
<mvn-dependency.version>3.8.1</mvn-dependency.version>
|
||||||
<mvn-surefire.version>3.5.2</mvn-surefire.version>
|
<mvn-surefire.version>3.5.3</mvn-surefire.version>
|
||||||
<mvn-jar.version>3.4.2</mvn-jar.version>
|
<mvn-jar.version>3.4.2</mvn-jar.version>
|
||||||
|
|
||||||
|
<!-- Property used by surefire to determine jacoco engine -->
|
||||||
|
<surefire.jacoco.args></surefire.jacoco.args>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
<!-- TODO: Remove once webdav version 2.0.11 is released -->
|
||||||
|
<dependencyManagement>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.cryptomator</groupId>
|
||||||
|
<artifactId>webdav-nio-adapter-servlet</artifactId>
|
||||||
|
<version>1.2.9</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</dependencyManagement>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<!-- Cryptomator Libs -->
|
<!-- Cryptomator Libs -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.cryptomator</groupId>
|
<groupId>org.cryptomator</groupId>
|
||||||
<artifactId>cryptolib</artifactId>
|
<artifactId>cryptolib</artifactId>
|
||||||
<version>2.2.0</version>
|
<version>2.2.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.cryptomator</groupId>
|
<groupId>org.cryptomator</groupId>
|
||||||
@@ -156,6 +170,12 @@
|
|||||||
<groupId>com.auth0</groupId>
|
<groupId>com.auth0</groupId>
|
||||||
<artifactId>java-jwt</artifactId>
|
<artifactId>java-jwt</artifactId>
|
||||||
<version>${jwt.version}</version>
|
<version>${jwt.version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
<artifactId>jackson-core</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.nimbusds</groupId>
|
<groupId>com.nimbusds</groupId>
|
||||||
@@ -205,7 +225,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||||
<artifactId>caffeine</artifactId>
|
<artifactId>caffeine</artifactId>
|
||||||
<version>3.1.8</version>
|
<version>3.2.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- JUnit / Mockito / Hamcrest -->
|
<!-- JUnit / Mockito / Hamcrest -->
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -308,7 +328,6 @@
|
|||||||
<compilerArgs>
|
<compilerArgs>
|
||||||
<arg>-Adagger.fastInit=enabled</arg>
|
<arg>-Adagger.fastInit=enabled</arg>
|
||||||
<arg>-Adagger.formatGeneratedSource=enabled</arg>
|
<arg>-Adagger.formatGeneratedSource=enabled</arg>
|
||||||
<arg>--enable-preview</arg>
|
|
||||||
</compilerArgs>
|
</compilerArgs>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
@@ -335,11 +354,11 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<configuration>
|
<configuration>
|
||||||
<argLine>--enable-preview</argLine>
|
|
||||||
<reportFormat>plain</reportFormat>
|
<reportFormat>plain</reportFormat>
|
||||||
<consoleOutputReporter>
|
<consoleOutputReporter>
|
||||||
<disable>true</disable>
|
<disable>true</disable>
|
||||||
</consoleOutputReporter>
|
</consoleOutputReporter>
|
||||||
|
<argLine>@{surefire.jacoco.args} -javaagent:${org.mockito:mockito-core:jar} --enable-native-access=javafx.graphics</argLine>
|
||||||
<statelessTestsetInfoReporter
|
<statelessTestsetInfoReporter
|
||||||
implementation="org.apache.maven.plugin.surefire.extensions.junit5.JUnit5StatelessTestsetInfoTreeReporter">
|
implementation="org.apache.maven.plugin.surefire.extensions.junit5.JUnit5StatelessTestsetInfoTreeReporter">
|
||||||
</statelessTestsetInfoReporter>
|
</statelessTestsetInfoReporter>
|
||||||
@@ -349,6 +368,13 @@
|
|||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-dependency-plugin</artifactId>
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
<executions>
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>jar-paths-to-properties</id>
|
||||||
|
<phase>validate</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>properties</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
<!-- sort jars into two buckets (classpath and modulepath). exclude openjfx, which gets jlinked separately -->
|
<!-- sort jars into two buckets (classpath and modulepath). exclude openjfx, which gets jlinked separately -->
|
||||||
<execution>
|
<execution>
|
||||||
<id>copy-mods</id>
|
<id>copy-mods</id>
|
||||||
@@ -421,6 +447,9 @@
|
|||||||
<goals>
|
<goals>
|
||||||
<goal>prepare-agent</goal>
|
<goal>prepare-agent</goal>
|
||||||
</goals>
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<propertyName>surefire.jacoco.args</propertyName>
|
||||||
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
<execution>
|
<execution>
|
||||||
<id>report</id>
|
<id>report</id>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import ch.qos.logback.classic.spi.Configurator;
|
import ch.qos.logback.classic.spi.Configurator;
|
||||||
|
import org.cryptomator.networking.SSLContextWithPKCS12TrustStore;
|
||||||
import org.cryptomator.common.locationpresets.DropboxLinuxLocationPresetsProvider;
|
import org.cryptomator.common.locationpresets.DropboxLinuxLocationPresetsProvider;
|
||||||
import org.cryptomator.common.locationpresets.DropboxMacLocationPresetsProvider;
|
import org.cryptomator.common.locationpresets.DropboxMacLocationPresetsProvider;
|
||||||
import org.cryptomator.common.locationpresets.DropboxWindowsLocationPresetsProvider;
|
import org.cryptomator.common.locationpresets.DropboxWindowsLocationPresetsProvider;
|
||||||
@@ -13,6 +14,9 @@ import org.cryptomator.common.locationpresets.OneDriveLinuxLocationPresetsProvid
|
|||||||
import org.cryptomator.common.locationpresets.OneDriveMacLocationPresetsProvider;
|
import org.cryptomator.common.locationpresets.OneDriveMacLocationPresetsProvider;
|
||||||
import org.cryptomator.common.locationpresets.OneDriveWindowsLocationPresetsProvider;
|
import org.cryptomator.common.locationpresets.OneDriveWindowsLocationPresetsProvider;
|
||||||
import org.cryptomator.common.locationpresets.PCloudLocationPresetsProvider;
|
import org.cryptomator.common.locationpresets.PCloudLocationPresetsProvider;
|
||||||
|
import org.cryptomator.networking.SSLContextWithMacKeychain;
|
||||||
|
import org.cryptomator.networking.SSLContextProvider;
|
||||||
|
import org.cryptomator.networking.SSLContextWithWindowsCertStore;
|
||||||
import org.cryptomator.integrations.tray.TrayMenuController;
|
import org.cryptomator.integrations.tray.TrayMenuController;
|
||||||
import org.cryptomator.logging.LogbackConfiguratorFactory;
|
import org.cryptomator.logging.LogbackConfiguratorFactory;
|
||||||
import org.cryptomator.ui.traymenu.AwtTrayMenuController;
|
import org.cryptomator.ui.traymenu.AwtTrayMenuController;
|
||||||
@@ -54,9 +58,12 @@ open module org.cryptomator.desktop {
|
|||||||
requires com.github.benmanes.caffeine;
|
requires com.github.benmanes.caffeine;
|
||||||
|
|
||||||
uses org.cryptomator.common.locationpresets.LocationPresetsProvider;
|
uses org.cryptomator.common.locationpresets.LocationPresetsProvider;
|
||||||
|
uses SSLContextProvider;
|
||||||
|
uses org.cryptomator.event.NotificationHandler;
|
||||||
|
|
||||||
provides TrayMenuController with AwtTrayMenuController;
|
provides TrayMenuController with AwtTrayMenuController;
|
||||||
provides Configurator with LogbackConfiguratorFactory;
|
provides Configurator with LogbackConfiguratorFactory;
|
||||||
|
provides SSLContextProvider with SSLContextWithWindowsCertStore, SSLContextWithMacKeychain, SSLContextWithPKCS12TrustStore;
|
||||||
provides LocationPresetsProvider with //
|
provides LocationPresetsProvider with //
|
||||||
DropboxWindowsLocationPresetsProvider, DropboxMacLocationPresetsProvider, DropboxLinuxLocationPresetsProvider, //
|
DropboxWindowsLocationPresetsProvider, DropboxMacLocationPresetsProvider, DropboxLinuxLocationPresetsProvider, //
|
||||||
GoogleDriveMacLocationPresetsProvider, GoogleDriveWindowsLocationPresetsProvider, //
|
GoogleDriveMacLocationPresetsProvider, GoogleDriveWindowsLocationPresetsProvider, //
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import java.util.concurrent.TimeUnit;
|
|||||||
|
|
||||||
public class JavaFXUtil {
|
public class JavaFXUtil {
|
||||||
|
|
||||||
|
private JavaFXUtil() {}
|
||||||
|
|
||||||
public static boolean startPlatform() throws InterruptedException {
|
public static boolean startPlatform() throws InterruptedException {
|
||||||
CountDownLatch latch = new CountDownLatch(1);
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -0,0 +1,160 @@
|
|||||||
|
package org.cryptomator.common;
|
||||||
|
|
||||||
|
import org.cryptomator.cryptofs.event.BrokenDirFileEvent;
|
||||||
|
import org.cryptomator.cryptofs.event.BrokenFileNodeEvent;
|
||||||
|
import org.cryptomator.cryptofs.event.ConflictResolutionFailedEvent;
|
||||||
|
import org.cryptomator.cryptofs.event.ConflictResolvedEvent;
|
||||||
|
import org.cryptomator.cryptofs.event.DecryptionFailedEvent;
|
||||||
|
import org.cryptomator.cryptofs.event.FilesystemEvent;
|
||||||
|
import org.cryptomator.event.VaultEvent;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
import javafx.beans.InvalidationListener;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.MapChangeListener;
|
||||||
|
import javafx.collections.ObservableMap;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map containing {@link VaultEvent}s.
|
||||||
|
* The map is keyed by the ciphertext path of the affected resource _and_ the {@link FilesystemEvent}s class in order to group same events
|
||||||
|
* <p>
|
||||||
|
* Use {@link EventMap#put(VaultEvent)} to add an element and {@link EventMap#remove(VaultEvent)} to remove it.
|
||||||
|
* <p>
|
||||||
|
* The map is size restricted to {@value MAX_SIZE} elements. If a _new_ element (i.e. not already present) is added, the least recently added is removed.
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class EventMap implements ObservableMap<EventMap.EventKey, VaultEvent> {
|
||||||
|
|
||||||
|
private static final int MAX_SIZE = 300;
|
||||||
|
|
||||||
|
public record EventKey(Path ciphertextPath, Class<? extends FilesystemEvent> c) {}
|
||||||
|
|
||||||
|
private final ObservableMap<EventMap.EventKey, VaultEvent> delegate;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public EventMap() {
|
||||||
|
delegate = FXCollections.observableHashMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addListener(MapChangeListener<? super EventKey, ? super VaultEvent> mapChangeListener) {
|
||||||
|
delegate.addListener(mapChangeListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeListener(MapChangeListener<? super EventKey, ? super VaultEvent> mapChangeListener) {
|
||||||
|
delegate.removeListener(mapChangeListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return delegate.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return delegate.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean containsKey(Object key) {
|
||||||
|
return delegate.containsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean containsValue(Object value) {
|
||||||
|
return delegate.containsValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VaultEvent get(Object key) {
|
||||||
|
return delegate.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable VaultEvent put(EventKey key, VaultEvent value) {
|
||||||
|
return delegate.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VaultEvent remove(Object key) {
|
||||||
|
return delegate.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void putAll(@NotNull Map<? extends EventKey, ? extends VaultEvent> m) {
|
||||||
|
delegate.putAll(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
delegate.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Set<EventKey> keySet() {
|
||||||
|
return delegate.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Collection<VaultEvent> values() {
|
||||||
|
return delegate.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Set<Entry<EventKey, VaultEvent>> entrySet() {
|
||||||
|
return delegate.entrySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addListener(InvalidationListener invalidationListener) {
|
||||||
|
delegate.addListener(invalidationListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeListener(InvalidationListener invalidationListener) {
|
||||||
|
delegate.removeListener(invalidationListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void put(VaultEvent e) {
|
||||||
|
//compute key
|
||||||
|
var key = computeKey(e.actualEvent());
|
||||||
|
//if-else
|
||||||
|
var nullOrEntry = delegate.get(key);
|
||||||
|
if (nullOrEntry == null) {
|
||||||
|
if (size() == MAX_SIZE) {
|
||||||
|
delegate.entrySet().stream() //
|
||||||
|
.min(Comparator.comparing(entry -> entry.getValue().actualEvent().getTimestamp())) //
|
||||||
|
.ifPresent(oldestEntry -> delegate.remove(oldestEntry.getKey()));
|
||||||
|
}
|
||||||
|
delegate.put(key, e);
|
||||||
|
} else {
|
||||||
|
delegate.put(key, nullOrEntry.incrementCount(e.actualEvent()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized VaultEvent remove(VaultEvent similar) {
|
||||||
|
//compute key
|
||||||
|
var key = computeKey(similar.actualEvent());
|
||||||
|
return this.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private EventKey computeKey(FilesystemEvent e) {
|
||||||
|
var p = switch (e) {
|
||||||
|
case DecryptionFailedEvent(_, Path ciphertextPath, _) -> ciphertextPath;
|
||||||
|
case ConflictResolvedEvent(_, _, _, _, Path resolvedCiphertext) -> resolvedCiphertext;
|
||||||
|
case ConflictResolutionFailedEvent(_, _, Path conflictingCiphertext, _) -> conflictingCiphertext;
|
||||||
|
case BrokenDirFileEvent(_, Path ciphertext) -> ciphertext;
|
||||||
|
case BrokenFileNodeEvent(_, _, Path ciphertext) -> ciphertext;
|
||||||
|
};
|
||||||
|
return new EventKey(p, e.getClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package org.cryptomator.common.keychain;
|
|||||||
|
|
||||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||||
|
import org.cryptomator.common.Passphrase;
|
||||||
import org.cryptomator.integrations.keychain.KeychainAccessException;
|
import org.cryptomator.integrations.keychain.KeychainAccessException;
|
||||||
import org.cryptomator.integrations.keychain.KeychainAccessProvider;
|
import org.cryptomator.integrations.keychain.KeychainAccessProvider;
|
||||||
|
|
||||||
@@ -13,12 +14,15 @@ import javafx.beans.property.BooleanProperty;
|
|||||||
import javafx.beans.property.ReadOnlyBooleanProperty;
|
import javafx.beans.property.ReadOnlyBooleanProperty;
|
||||||
import javafx.beans.property.SimpleBooleanProperty;
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class KeychainManager implements KeychainAccessProvider {
|
public class KeychainManager implements KeychainAccessProvider {
|
||||||
|
|
||||||
private final ObjectExpression<KeychainAccessProvider> keychain;
|
private final ObjectExpression<KeychainAccessProvider> keychain;
|
||||||
private final LoadingCache<String, BooleanProperty> passphraseStoredProperties;
|
private final LoadingCache<String, BooleanProperty> passphraseStoredProperties;
|
||||||
|
private final ReentrantReadWriteLock lock;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
KeychainManager(ObjectExpression<KeychainAccessProvider> selectedKeychain) {
|
KeychainManager(ObjectExpression<KeychainAccessProvider> selectedKeychain) {
|
||||||
@@ -27,6 +31,7 @@ public class KeychainManager implements KeychainAccessProvider {
|
|||||||
.softValues() //
|
.softValues() //
|
||||||
.build(this::createStoredPassphraseProperty);
|
.build(this::createStoredPassphraseProperty);
|
||||||
keychain.addListener(ignored -> passphraseStoredProperties.invalidateAll());
|
keychain.addListener(ignored -> passphraseStoredProperties.invalidateAll());
|
||||||
|
this.lock = new ReentrantReadWriteLock(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private KeychainAccessProvider getKeychainOrFail() throws KeychainAccessException {
|
private KeychainAccessProvider getKeychainOrFail() throws KeychainAccessException {
|
||||||
@@ -37,39 +42,50 @@ public class KeychainManager implements KeychainAccessProvider {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String displayName() {
|
|
||||||
return getClass().getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void storePassphrase(String key, String displayName, CharSequence passphrase) throws KeychainAccessException {
|
public void storePassphrase(String key, String displayName, CharSequence passphrase) throws KeychainAccessException {
|
||||||
storePassphrase(key, displayName, passphrase, true); //TODO: currently only TouchID is using this parameter, so this is okayish
|
try {
|
||||||
}
|
lock.writeLock().lock();
|
||||||
|
getKeychainOrFail().storePassphrase(key, displayName, passphrase);
|
||||||
@Override
|
} finally {
|
||||||
public void storePassphrase(String key, String displayName, CharSequence passphrase, boolean requireOsAuthentication) throws KeychainAccessException {
|
lock.writeLock().unlock();
|
||||||
getKeychainOrFail().storePassphrase(key, displayName, passphrase, requireOsAuthentication);
|
}
|
||||||
setPassphraseStored(key, true);
|
setPassphraseStored(key, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public char[] loadPassphrase(String key) throws KeychainAccessException {
|
public char[] loadPassphrase(String key) throws KeychainAccessException {
|
||||||
char[] passphrase = getKeychainOrFail().loadPassphrase(key);
|
char[] passphrase = null;
|
||||||
|
try {
|
||||||
|
lock.readLock().lock();
|
||||||
|
passphrase = getKeychainOrFail().loadPassphrase(key);
|
||||||
|
} finally {
|
||||||
|
lock.readLock().unlock();
|
||||||
|
}
|
||||||
setPassphraseStored(key, passphrase != null);
|
setPassphraseStored(key, passphrase != null);
|
||||||
return passphrase;
|
return passphrase;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deletePassphrase(String key) throws KeychainAccessException {
|
public void deletePassphrase(String key) throws KeychainAccessException {
|
||||||
getKeychainOrFail().deletePassphrase(key);
|
try {
|
||||||
|
lock.writeLock().lock();
|
||||||
|
getKeychainOrFail().deletePassphrase(key);
|
||||||
|
} finally {
|
||||||
|
lock.writeLock().unlock();
|
||||||
|
}
|
||||||
setPassphraseStored(key, false);
|
setPassphraseStored(key, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void changePassphrase(String key, String displayName, CharSequence passphrase) throws KeychainAccessException {
|
public void changePassphrase(String key, String displayName, CharSequence passphrase) throws KeychainAccessException {
|
||||||
if (isPassphraseStored(key)) {
|
if (isPassphraseStored(key)) {
|
||||||
getKeychainOrFail().changePassphrase(key, displayName, passphrase);
|
try {
|
||||||
|
lock.writeLock().lock();
|
||||||
|
getKeychainOrFail().changePassphrase(key, displayName, passphrase);
|
||||||
|
} finally {
|
||||||
|
lock.writeLock().unlock();
|
||||||
|
}
|
||||||
setPassphraseStored(key, true);
|
setPassphraseStored(key, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,4 +157,18 @@ public class KeychainManager implements KeychainAccessProvider {
|
|||||||
return this.keychain;
|
return this.keychain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void migrate(KeychainAccessProvider oldProvider, KeychainAccessProvider newProvider, Map<String, String> idsAndNames) throws KeychainAccessException {
|
||||||
|
if (oldProvider instanceof KeychainManager || newProvider instanceof KeychainManager) {
|
||||||
|
throw new IllegalArgumentException("KeychainManger must not be the source or target of migration");
|
||||||
|
}
|
||||||
|
for (var entry : idsAndNames.entrySet()) {
|
||||||
|
var passphrase = oldProvider.loadPassphrase(entry.getKey());
|
||||||
|
if (passphrase != null) {
|
||||||
|
var wrapper = new Passphrase(passphrase);
|
||||||
|
oldProvider.deletePassphrase(entry.getKey()); //we cannot apply "first-write-then-delete" pattern here, since we can potentially write to the same passphrase store (e.g., touchID and regular keychain)
|
||||||
|
newProvider.storePassphrase(entry.getKey(), entry.getValue(), wrapper);
|
||||||
|
wrapper.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public class Settings {
|
|||||||
@Deprecated // to be changed to "whatever is available" eventually
|
@Deprecated // to be changed to "whatever is available" eventually
|
||||||
static final String DEFAULT_KEYCHAIN_PROVIDER = SystemUtils.IS_OS_WINDOWS ? "org.cryptomator.windows.keychain.WindowsProtectedKeychainAccess" : //
|
static final String DEFAULT_KEYCHAIN_PROVIDER = SystemUtils.IS_OS_WINDOWS ? "org.cryptomator.windows.keychain.WindowsProtectedKeychainAccess" : //
|
||||||
SystemUtils.IS_OS_MAC ? "org.cryptomator.macos.keychain.MacSystemKeychainAccess" : //
|
SystemUtils.IS_OS_MAC ? "org.cryptomator.macos.keychain.MacSystemKeychainAccess" : //
|
||||||
"org.cryptomator.linux.keychain.SecretServiceKeychainAccess";
|
"org.cryptomator.linux.keychain.GnomeKeyringKeychainAccess";
|
||||||
static final String DEFAULT_QUICKACCESS_SERVICE = SystemUtils.IS_OS_WINDOWS ? "org.cryptomator.windows.quickaccess.ExplorerQuickAccessService" : //
|
static final String DEFAULT_QUICKACCESS_SERVICE = SystemUtils.IS_OS_WINDOWS ? "org.cryptomator.windows.quickaccess.ExplorerQuickAccessService" : //
|
||||||
SystemUtils.IS_OS_LINUX ? "org.cryptomator.linux.quickaccess.NautilusBookmarks" : null;
|
SystemUtils.IS_OS_LINUX ? "org.cryptomator.linux.quickaccess.NautilusBookmarks" : null;
|
||||||
|
|
||||||
@@ -147,6 +147,11 @@ public class Settings {
|
|||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
private void migrateLegacySettings(SettingsJson json) {
|
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":
|
// implicit migration of 1.6.x legacy setting "preferredVolumeImpl":
|
||||||
if (this.mountService.get() == null && json.preferredVolumeImpl != null) {
|
if (this.mountService.get() == null && json.preferredVolumeImpl != null) {
|
||||||
this.mountService.set(switch (json.preferredVolumeImpl) {
|
this.mountService.set(switch (json.preferredVolumeImpl) {
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ public class VaultSettings {
|
|||||||
public final StringExpression mountName;
|
public final StringExpression mountName;
|
||||||
public final StringProperty mountService;
|
public final StringProperty mountService;
|
||||||
public final IntegerProperty port;
|
public final IntegerProperty port;
|
||||||
|
public final StringProperty lastKnownKeyLoader;
|
||||||
|
|
||||||
VaultSettings(VaultSettingsJson json) {
|
VaultSettings(VaultSettingsJson json) {
|
||||||
this.id = json.id;
|
this.id = json.id;
|
||||||
@@ -74,6 +75,7 @@ public class VaultSettings {
|
|||||||
this.mountPoint = new SimpleObjectProperty<>(this, "mountPoint", json.mountPoint == null ? null : Path.of(json.mountPoint));
|
this.mountPoint = new SimpleObjectProperty<>(this, "mountPoint", json.mountPoint == null ? null : Path.of(json.mountPoint));
|
||||||
this.mountService = new SimpleStringProperty(this, "mountService", json.mountService);
|
this.mountService = new SimpleStringProperty(this, "mountService", json.mountService);
|
||||||
this.port = new SimpleIntegerProperty(this, "port", json.port);
|
this.port = new SimpleIntegerProperty(this, "port", json.port);
|
||||||
|
this.lastKnownKeyLoader = new SimpleStringProperty(this, "lastKnownKeyLoader", json.lastKnownKeyLoader);
|
||||||
// mount name is no longer an explicit setting, see https://github.com/cryptomator/cryptomator/pull/1318
|
// mount name is no longer an explicit setting, see https://github.com/cryptomator/cryptomator/pull/1318
|
||||||
this.mountName = StringExpression.stringExpression(Bindings.createStringBinding(() -> {
|
this.mountName = StringExpression.stringExpression(Bindings.createStringBinding(() -> {
|
||||||
final String name;
|
final String name;
|
||||||
@@ -99,7 +101,7 @@ public class VaultSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Observable[] observables() {
|
Observable[] observables() {
|
||||||
return new Observable[]{actionAfterUnlock, autoLockIdleSeconds, autoLockWhenIdle, displayName, maxCleartextFilenameLength, mountFlags, mountPoint, path, revealAfterMount, unlockAfterStartup, usesReadOnlyMode, port, mountService};
|
return new Observable[]{actionAfterUnlock, autoLockIdleSeconds, autoLockWhenIdle, displayName, maxCleartextFilenameLength, mountFlags, mountPoint, path, revealAfterMount, unlockAfterStartup, usesReadOnlyMode, port, mountService, lastKnownKeyLoader};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static VaultSettings withRandomId() {
|
public static VaultSettings withRandomId() {
|
||||||
@@ -130,6 +132,7 @@ public class VaultSettings {
|
|||||||
json.mountPoint = mountPoint.map(Path::toString).getValue();
|
json.mountPoint = mountPoint.map(Path::toString).getValue();
|
||||||
json.mountService = mountService.get();
|
json.mountService = mountService.get();
|
||||||
json.port = port.get();
|
json.port = port.get();
|
||||||
|
json.lastKnownKeyLoader = lastKnownKeyLoader.get();
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ class VaultSettingsJson {
|
|||||||
@JsonProperty("mountService")
|
@JsonProperty("mountService")
|
||||||
String mountService;
|
String mountService;
|
||||||
|
|
||||||
|
@JsonProperty("lastKnownKeyLoader")
|
||||||
|
String lastKnownKeyLoader;
|
||||||
|
|
||||||
@JsonProperty("port")
|
@JsonProperty("port")
|
||||||
int port = VaultSettings.DEFAULT_PORT;
|
int port = VaultSettings.DEFAULT_PORT;
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ package org.cryptomator.common.vaults;
|
|||||||
|
|
||||||
import org.apache.commons.lang3.SystemUtils;
|
import org.apache.commons.lang3.SystemUtils;
|
||||||
import org.cryptomator.common.Constants;
|
import org.cryptomator.common.Constants;
|
||||||
|
import org.cryptomator.event.FileSystemEventAggregator;
|
||||||
import org.cryptomator.common.mount.Mounter;
|
import org.cryptomator.common.mount.Mounter;
|
||||||
import org.cryptomator.common.settings.Settings;
|
import org.cryptomator.common.settings.Settings;
|
||||||
import org.cryptomator.common.settings.VaultSettings;
|
import org.cryptomator.common.settings.VaultSettings;
|
||||||
@@ -18,9 +19,11 @@ import org.cryptomator.cryptofs.CryptoFileSystemProperties;
|
|||||||
import org.cryptomator.cryptofs.CryptoFileSystemProperties.FileSystemFlags;
|
import org.cryptomator.cryptofs.CryptoFileSystemProperties.FileSystemFlags;
|
||||||
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
|
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
|
||||||
import org.cryptomator.cryptofs.common.FileSystemCapabilityChecker;
|
import org.cryptomator.cryptofs.common.FileSystemCapabilityChecker;
|
||||||
|
import org.cryptomator.cryptofs.event.FilesystemEvent;
|
||||||
import org.cryptomator.cryptolib.api.CryptoException;
|
import org.cryptomator.cryptolib.api.CryptoException;
|
||||||
import org.cryptomator.cryptolib.api.MasterkeyLoader;
|
import org.cryptomator.cryptolib.api.MasterkeyLoader;
|
||||||
import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
|
import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
|
||||||
|
import org.cryptomator.event.VaultEvent;
|
||||||
import org.cryptomator.integrations.mount.MountFailedException;
|
import org.cryptomator.integrations.mount.MountFailedException;
|
||||||
import org.cryptomator.integrations.mount.Mountpoint;
|
import org.cryptomator.integrations.mount.Mountpoint;
|
||||||
import org.cryptomator.integrations.mount.UnmountFailedException;
|
import org.cryptomator.integrations.mount.UnmountFailedException;
|
||||||
@@ -32,6 +35,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.beans.Observable;
|
import javafx.beans.Observable;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.binding.BooleanBinding;
|
import javafx.beans.binding.BooleanBinding;
|
||||||
@@ -44,6 +48,7 @@ import javafx.beans.property.SimpleBooleanProperty;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.nio.file.ReadOnlyFileSystemException;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -73,6 +78,7 @@ public class Vault {
|
|||||||
private final ObjectBinding<Mountpoint> mountPoint;
|
private final ObjectBinding<Mountpoint> mountPoint;
|
||||||
private final Mounter mounter;
|
private final Mounter mounter;
|
||||||
private final Settings settings;
|
private final Settings settings;
|
||||||
|
private final FileSystemEventAggregator fileSystemEventAggregator;
|
||||||
private final BooleanProperty showingStats;
|
private final BooleanProperty showingStats;
|
||||||
|
|
||||||
private final AtomicReference<Mounter.MountHandle> mountHandle = new AtomicReference<>(null);
|
private final AtomicReference<Mounter.MountHandle> mountHandle = new AtomicReference<>(null);
|
||||||
@@ -84,7 +90,8 @@ public class Vault {
|
|||||||
VaultState state, //
|
VaultState state, //
|
||||||
@Named("lastKnownException") ObjectProperty<Exception> lastKnownException, //
|
@Named("lastKnownException") ObjectProperty<Exception> lastKnownException, //
|
||||||
VaultStats stats, //
|
VaultStats stats, //
|
||||||
Mounter mounter, Settings settings) {
|
Mounter mounter, Settings settings, //
|
||||||
|
FileSystemEventAggregator fileSystemEventAggregator) {
|
||||||
this.vaultSettings = vaultSettings;
|
this.vaultSettings = vaultSettings;
|
||||||
this.configCache = configCache;
|
this.configCache = configCache;
|
||||||
this.cryptoFileSystem = cryptoFileSystem;
|
this.cryptoFileSystem = cryptoFileSystem;
|
||||||
@@ -101,6 +108,7 @@ public class Vault {
|
|||||||
this.mountPoint = Bindings.createObjectBinding(this::getMountPoint, state);
|
this.mountPoint = Bindings.createObjectBinding(this::getMountPoint, state);
|
||||||
this.mounter = mounter;
|
this.mounter = mounter;
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
|
this.fileSystemEventAggregator = fileSystemEventAggregator;
|
||||||
this.showingStats = new SimpleBooleanProperty(false);
|
this.showingStats = new SimpleBooleanProperty(false);
|
||||||
this.quickAccessEntry = new AtomicReference<>(null);
|
this.quickAccessEntry = new AtomicReference<>(null);
|
||||||
}
|
}
|
||||||
@@ -111,15 +119,22 @@ public class Vault {
|
|||||||
|
|
||||||
private CryptoFileSystem createCryptoFileSystem(MasterkeyLoader keyLoader) throws IOException, MasterkeyLoadingFailedException {
|
private CryptoFileSystem createCryptoFileSystem(MasterkeyLoader keyLoader) throws IOException, MasterkeyLoadingFailedException {
|
||||||
Set<FileSystemFlags> flags = EnumSet.noneOf(FileSystemFlags.class);
|
Set<FileSystemFlags> flags = EnumSet.noneOf(FileSystemFlags.class);
|
||||||
if (vaultSettings.usesReadOnlyMode.get()) {
|
var createReadOnly = vaultSettings.usesReadOnlyMode.get();
|
||||||
|
try {
|
||||||
|
FileSystemCapabilityChecker.assertWriteAccess(getPath());
|
||||||
|
} catch (FileSystemCapabilityChecker.MissingCapabilityException e) {
|
||||||
|
if (!createReadOnly) {
|
||||||
|
throw new ReadOnlyFileSystemException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (createReadOnly) {
|
||||||
flags.add(FileSystemFlags.READONLY);
|
flags.add(FileSystemFlags.READONLY);
|
||||||
} else if (vaultSettings.maxCleartextFilenameLength.get() == -1) {
|
} else if (vaultSettings.maxCleartextFilenameLength.get() == -1) {
|
||||||
LOG.debug("Determining cleartext filename length limitations...");
|
LOG.debug("Determining cleartext filename length limitations...");
|
||||||
var checker = new FileSystemCapabilityChecker();
|
|
||||||
int shorteningThreshold = configCache.get().allegedShorteningThreshold();
|
int shorteningThreshold = configCache.get().allegedShorteningThreshold();
|
||||||
int ciphertextLimit = checker.determineSupportedCiphertextFileNameLength(getPath());
|
int ciphertextLimit = FileSystemCapabilityChecker.determineSupportedCiphertextFileNameLength(getPath());
|
||||||
if (ciphertextLimit < shorteningThreshold) {
|
if (ciphertextLimit < shorteningThreshold) {
|
||||||
int cleartextLimit = checker.determineSupportedCleartextFileNameLength(getPath());
|
int cleartextLimit = FileSystemCapabilityChecker.determineSupportedCleartextFileNameLength(getPath());
|
||||||
vaultSettings.maxCleartextFilenameLength.set(cleartextLimit);
|
vaultSettings.maxCleartextFilenameLength.set(cleartextLimit);
|
||||||
} else {
|
} else {
|
||||||
vaultSettings.maxCleartextFilenameLength.setValue(UNLIMITED_FILENAME_LENGTH);
|
vaultSettings.maxCleartextFilenameLength.setValue(UNLIMITED_FILENAME_LENGTH);
|
||||||
@@ -135,6 +150,7 @@ public class Vault {
|
|||||||
.withFlags(flags) //
|
.withFlags(flags) //
|
||||||
.withMaxCleartextNameLength(vaultSettings.maxCleartextFilenameLength.get()) //
|
.withMaxCleartextNameLength(vaultSettings.maxCleartextFilenameLength.get()) //
|
||||||
.withVaultConfigFilename(Constants.VAULTCONFIG_FILENAME) //
|
.withVaultConfigFilename(Constants.VAULTCONFIG_FILENAME) //
|
||||||
|
.withFilesystemEventConsumer(this::consumeVaultEvent) //
|
||||||
.build();
|
.build();
|
||||||
return CryptoFileSystemProvider.newFileSystem(getPath(), fsProps);
|
return CryptoFileSystemProvider.newFileSystem(getPath(), fsProps);
|
||||||
}
|
}
|
||||||
@@ -243,6 +259,11 @@ public class Vault {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void consumeVaultEvent(FilesystemEvent e) {
|
||||||
|
fileSystemEventAggregator.put(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
// ******************************************************************************
|
// ******************************************************************************
|
||||||
// Observable Properties
|
// Observable Properties
|
||||||
// *******************************************************************************
|
// *******************************************************************************
|
||||||
@@ -404,6 +425,17 @@ public class Vault {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the cleartext name from a given path to an encrypted vault file
|
||||||
|
*/
|
||||||
|
public String getCleartextName(Path ciphertextPath) throws IOException {
|
||||||
|
if (!state.getValue().equals(VaultState.Value.UNLOCKED)) {
|
||||||
|
throw new IllegalStateException("Vault is not unlocked");
|
||||||
|
}
|
||||||
|
var fs = cryptoFileSystem.get();
|
||||||
|
return fs.getCleartextName(ciphertextPath);
|
||||||
|
}
|
||||||
|
|
||||||
public VaultConfigCache getVaultConfigCache() {
|
public VaultConfigCache getVaultConfigCache() {
|
||||||
return configCache;
|
return configCache;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
package org.cryptomator.common.vaults;
|
package org.cryptomator.common.vaults;
|
||||||
|
|
||||||
import org.apache.commons.lang3.SystemUtils;
|
import org.apache.commons.lang3.SystemUtils;
|
||||||
|
import org.cryptomator.common.Constants;
|
||||||
import org.cryptomator.common.settings.Settings;
|
import org.cryptomator.common.settings.Settings;
|
||||||
import org.cryptomator.common.settings.VaultSettings;
|
import org.cryptomator.common.settings.VaultSettings;
|
||||||
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
|
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
|
||||||
@@ -27,6 +28,7 @@ import java.nio.file.NoSuchFileException;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
@@ -34,6 +36,7 @@ import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
|
|||||||
import static org.cryptomator.common.Constants.VAULTCONFIG_FILENAME;
|
import static org.cryptomator.common.Constants.VAULTCONFIG_FILENAME;
|
||||||
import static org.cryptomator.common.vaults.VaultState.Value.ERROR;
|
import static org.cryptomator.common.vaults.VaultState.Value.ERROR;
|
||||||
import static org.cryptomator.common.vaults.VaultState.Value.LOCKED;
|
import static org.cryptomator.common.vaults.VaultState.Value.LOCKED;
|
||||||
|
import static org.cryptomator.common.vaults.VaultState.Value.NEEDS_MIGRATION;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class VaultListManager {
|
public class VaultListManager {
|
||||||
@@ -49,9 +52,9 @@ public class VaultListManager {
|
|||||||
@Inject
|
@Inject
|
||||||
public VaultListManager(ObservableList<Vault> vaultList, //
|
public VaultListManager(ObservableList<Vault> vaultList, //
|
||||||
AutoLocker autoLocker, //
|
AutoLocker autoLocker, //
|
||||||
List<MountService> mountServices,
|
List<MountService> mountServices, //
|
||||||
VaultComponent.Factory vaultComponentFactory,
|
VaultComponent.Factory vaultComponentFactory, //
|
||||||
ResourceBundle resourceBundle,
|
ResourceBundle resourceBundle, //
|
||||||
Settings settings) {
|
Settings settings) {
|
||||||
this.vaultList = vaultList;
|
this.vaultList = vaultList;
|
||||||
this.autoLocker = autoLocker;
|
this.autoLocker = autoLocker;
|
||||||
@@ -103,7 +106,7 @@ public class VaultListManager {
|
|||||||
vaultList.addAll(vaults);
|
vaultList.addAll(vaults);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<Vault> get(Path vaultPath) {
|
public Optional<Vault> get(Path vaultPath) {
|
||||||
assert vaultPath.isAbsolute();
|
assert vaultPath.isAbsolute();
|
||||||
assert vaultPath.normalize().equals(vaultPath);
|
assert vaultPath.normalize().equals(vaultPath);
|
||||||
return vaultList.stream() //
|
return vaultList.stream() //
|
||||||
@@ -117,6 +120,12 @@ public class VaultListManager {
|
|||||||
var vaultState = determineVaultState(vaultSettings.path.get());
|
var vaultState = determineVaultState(vaultSettings.path.get());
|
||||||
if (vaultState == LOCKED) { //for legacy reasons: pre v8 vault do not have a config, but they are in the NEEDS_MIGRATION state
|
if (vaultState == LOCKED) { //for legacy reasons: pre v8 vault do not have a config, but they are in the NEEDS_MIGRATION state
|
||||||
wrapper.reloadConfig();
|
wrapper.reloadConfig();
|
||||||
|
if (Objects.isNull(vaultSettings.lastKnownKeyLoader.get())) {
|
||||||
|
var keyIdScheme = wrapper.get().getKeyId().getScheme();
|
||||||
|
vaultSettings.lastKnownKeyLoader.set(keyIdScheme);
|
||||||
|
}
|
||||||
|
} else if (vaultState == NEEDS_MIGRATION) {
|
||||||
|
vaultSettings.lastKnownKeyLoader.set(Constants.DEFAULT_KEY_ID.toString());
|
||||||
}
|
}
|
||||||
return vaultComponentFactory.create(vaultSettings, wrapper, vaultState, null).vault();
|
return vaultComponentFactory.create(vaultSettings, wrapper, vaultState, null).vault();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package org.cryptomator.event;
|
||||||
|
|
||||||
|
public sealed interface Answer permits Answer.DoNothing, Answer.DoSomething {
|
||||||
|
|
||||||
|
|
||||||
|
record DoNothing() implements Answer {}
|
||||||
|
|
||||||
|
record DoSomething(Runnable action) implements Answer {
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
action.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package org.cryptomator.event;
|
||||||
|
|
||||||
|
import org.cryptomator.common.vaults.Vault;
|
||||||
|
import org.cryptomator.cryptofs.event.FilesystemEvent;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public record FSEventBucket(Vault vault, Path idPath, Class<? extends FilesystemEvent> c) {}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package org.cryptomator.event;
|
||||||
|
|
||||||
|
import org.cryptomator.cryptofs.event.FilesystemEvent;
|
||||||
|
|
||||||
|
public record FSEventBucketContent(FilesystemEvent mostRecentEvent, int count) {}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
package org.cryptomator.event;
|
||||||
|
|
||||||
|
import org.cryptomator.common.vaults.Vault;
|
||||||
|
import org.cryptomator.cryptofs.event.BrokenDirFileEvent;
|
||||||
|
import org.cryptomator.cryptofs.event.BrokenFileNodeEvent;
|
||||||
|
import org.cryptomator.cryptofs.event.ConflictResolutionFailedEvent;
|
||||||
|
import org.cryptomator.cryptofs.event.ConflictResolvedEvent;
|
||||||
|
import org.cryptomator.cryptofs.event.DecryptionFailedEvent;
|
||||||
|
import org.cryptomator.cryptofs.event.FilesystemEvent;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aggregator for {@link FilesystemEvent}s.
|
||||||
|
* <p>
|
||||||
|
* The aggregator groups filesystem events by the vault where the event occurred, an identifying path (clear- or ciphertext) and the event class (aka type).
|
||||||
|
* A group is called an {@link FSEventBucket}, its {@link FSEventBucketContent} is the most recent event object and a count of how often the event already occurred.
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class FileSystemEventAggregator {
|
||||||
|
|
||||||
|
private final ConcurrentHashMap<FSEventBucket, FSEventBucketContent> map;
|
||||||
|
private final AtomicBoolean hasUpdates;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public FileSystemEventAggregator() {
|
||||||
|
this.map = new ConcurrentHashMap<>();
|
||||||
|
this.hasUpdates = new AtomicBoolean(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the given event to the map. If a bucket for this event already exists, only the count is updated and the event set as the most recent one.
|
||||||
|
*
|
||||||
|
* @param v Vault where the event occurred
|
||||||
|
* @param e Actual {@link FilesystemEvent}
|
||||||
|
*/
|
||||||
|
public void put(Vault v, FilesystemEvent e) {
|
||||||
|
var key = computeKey(v, e);
|
||||||
|
map.compute(key, (k, val) -> {
|
||||||
|
if (val == null) {
|
||||||
|
return new FSEventBucketContent(e, 1);
|
||||||
|
} else {
|
||||||
|
return new FSEventBucketContent(e, val.count() + 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
hasUpdates.set(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an event bucket from the map.
|
||||||
|
*/
|
||||||
|
public FSEventBucketContent remove(FSEventBucket key) {
|
||||||
|
var content = map.remove(key);
|
||||||
|
hasUpdates.set(true);
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the event map.
|
||||||
|
*/
|
||||||
|
public void clear() {
|
||||||
|
map.clear();
|
||||||
|
hasUpdates.set(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean hasMaybeUpdates() {
|
||||||
|
return hasUpdates.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clones the map entries into a collection.
|
||||||
|
* <p>
|
||||||
|
* The collection is first cleared, then all map entries are added in one bulk operation. Cleans the hasUpdates status.
|
||||||
|
*
|
||||||
|
* @param target collection which is first cleared and then the EntrySet copied to.
|
||||||
|
*/
|
||||||
|
public void cloneTo(Collection<Map.Entry<FSEventBucket, FSEventBucketContent>> target) {
|
||||||
|
hasUpdates.set(false);
|
||||||
|
target.clear();
|
||||||
|
target.addAll(map.entrySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to compute the identifying key for a given filesystem event
|
||||||
|
*
|
||||||
|
* @param v Vault where the event occurred
|
||||||
|
* @param event Actual {@link FilesystemEvent}
|
||||||
|
* @return a {@link FSEventBucket} used in the map and lru cache
|
||||||
|
*/
|
||||||
|
private static FSEventBucket computeKey(Vault v, FilesystemEvent event) {
|
||||||
|
var p = switch (event) {
|
||||||
|
case DecryptionFailedEvent(_, Path ciphertextPath, _) -> ciphertextPath;
|
||||||
|
case ConflictResolvedEvent(_, _, _, _, Path resolvedCiphertext) -> resolvedCiphertext;
|
||||||
|
case ConflictResolutionFailedEvent(_, _, Path conflictingCiphertext, _) -> conflictingCiphertext;
|
||||||
|
case BrokenDirFileEvent(_, Path ciphertext) -> ciphertext;
|
||||||
|
case BrokenFileNodeEvent(_, _, Path ciphertext) -> ciphertext;
|
||||||
|
};
|
||||||
|
return new FSEventBucket(v, p, event.getClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package org.cryptomator.event;
|
||||||
|
|
||||||
|
import org.cryptomator.integrations.common.IntegrationsLoader;
|
||||||
|
|
||||||
|
import java.util.ServiceLoader;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public interface NotificationHandler {
|
||||||
|
|
||||||
|
Answer handle(VaultEvent e);
|
||||||
|
|
||||||
|
static Stream<NotificationHandler> loadAll() {
|
||||||
|
return IntegrationsLoader.loadAll(ServiceLoader.load(NotificationHandler.class), NotificationHandler.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package org.cryptomator.event;
|
||||||
|
|
||||||
|
import org.cryptomator.common.vaults.Vault;
|
||||||
|
import org.cryptomator.cryptofs.event.FilesystemEvent;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
public record VaultEvent(Vault v, FilesystemEvent actualEvent, int count) implements Comparable<VaultEvent> {
|
||||||
|
|
||||||
|
public VaultEvent(Vault v, FilesystemEvent actualEvent) {
|
||||||
|
this(v, actualEvent, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(VaultEvent other) {
|
||||||
|
var timeResult = actualEvent.getTimestamp().compareTo(other.actualEvent().getTimestamp());
|
||||||
|
if(timeResult != 0) {
|
||||||
|
return timeResult;
|
||||||
|
} else {
|
||||||
|
return this.equals(other) ? 0 : this.actualEvent.getClass().getName().compareTo(other.actualEvent.getClass().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public VaultEvent incrementCount(FilesystemEvent update) {
|
||||||
|
return new VaultEvent(v, update, count+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,8 +9,9 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
|||||||
import dagger.Lazy;
|
import dagger.Lazy;
|
||||||
import org.apache.commons.lang3.SystemUtils;
|
import org.apache.commons.lang3.SystemUtils;
|
||||||
import org.cryptomator.common.Environment;
|
import org.cryptomator.common.Environment;
|
||||||
import org.cryptomator.common.SubstitutingProperties;
|
|
||||||
import org.cryptomator.common.ShutdownHook;
|
import org.cryptomator.common.ShutdownHook;
|
||||||
|
import org.cryptomator.common.SubstitutingProperties;
|
||||||
|
import org.cryptomator.networking.SSLContextProvider;
|
||||||
import org.cryptomator.ipc.IpcCommunicator;
|
import org.cryptomator.ipc.IpcCommunicator;
|
||||||
import org.cryptomator.logging.DebugMode;
|
import org.cryptomator.logging.DebugMode;
|
||||||
import org.cryptomator.ui.fxapp.FxApplicationComponent;
|
import org.cryptomator.ui.fxapp.FxApplicationComponent;
|
||||||
@@ -19,8 +20,10 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
import java.security.SecureRandom;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@@ -48,14 +51,16 @@ public class Cryptomator {
|
|||||||
private final Environment env;
|
private final Environment env;
|
||||||
private final Lazy<IpcMessageHandler> ipcMessageHandler;
|
private final Lazy<IpcMessageHandler> ipcMessageHandler;
|
||||||
private final ShutdownHook shutdownHook;
|
private final ShutdownHook shutdownHook;
|
||||||
|
private final SecureRandom csprng;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
Cryptomator(DebugMode debugMode, SupportedLanguages supportedLanguages, Environment env, Lazy<IpcMessageHandler> ipcMessageHandler, ShutdownHook shutdownHook) {
|
Cryptomator(DebugMode debugMode, SupportedLanguages supportedLanguages, Environment env, Lazy<IpcMessageHandler> ipcMessageHandler, ShutdownHook shutdownHook, SecureRandom csprng) {
|
||||||
this.debugMode = debugMode;
|
this.debugMode = debugMode;
|
||||||
this.supportedLanguages = supportedLanguages;
|
this.supportedLanguages = supportedLanguages;
|
||||||
this.env = env;
|
this.env = env;
|
||||||
this.ipcMessageHandler = ipcMessageHandler;
|
this.ipcMessageHandler = ipcMessageHandler;
|
||||||
this.shutdownHook = shutdownHook;
|
this.shutdownHook = shutdownHook;
|
||||||
|
this.csprng = csprng;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
@@ -89,7 +94,7 @@ public class Cryptomator {
|
|||||||
LOG.info("Starting Cryptomator {} on {} {} ({})", env.getAppVersion(), SystemUtils.OS_NAME, SystemUtils.OS_VERSION, SystemUtils.OS_ARCH);
|
LOG.info("Starting Cryptomator {} on {} {} ({})", env.getAppVersion(), SystemUtils.OS_NAME, SystemUtils.OS_VERSION, SystemUtils.OS_ARCH);
|
||||||
debugMode.initialize();
|
debugMode.initialize();
|
||||||
supportedLanguages.applyPreferred();
|
supportedLanguages.applyPreferred();
|
||||||
|
changeDefaultSSLContext();
|
||||||
/*
|
/*
|
||||||
* Attempts to create an IPC connection to a running Cryptomator instance and sends it the given args.
|
* Attempts to create an IPC connection to a running Cryptomator instance and sends it the given args.
|
||||||
* If no external process could be reached, the args will be handled by the loopback IPC endpoint.
|
* If no external process could be reached, the args will be handled by the loopback IPC endpoint.
|
||||||
@@ -115,6 +120,17 @@ public class Cryptomator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void changeDefaultSSLContext() {
|
||||||
|
SSLContextProvider.loadAll().findFirst().ifPresent(p -> {
|
||||||
|
try {
|
||||||
|
var context = p.getContext(csprng);
|
||||||
|
SSLContext.setDefault(context);
|
||||||
|
} catch (SSLContextProvider.SSLContextBuildException e) {
|
||||||
|
LOG.warn("Failed to change default SSL context with provider {}", p.getClass().getName(), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Launches the JavaFX application, blocking the main thread until shuts down.
|
* Launches the JavaFX application, blocking the main thread until shuts down.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -90,6 +90,9 @@ public class LogbackConfigurator extends ContextAwareBase implements Configurato
|
|||||||
// configure fuse file locking logger:
|
// configure fuse file locking logger:
|
||||||
Logger fuseLocking = context.getLogger("org.cryptomator.frontend.fuse.locks");
|
Logger fuseLocking = context.getLogger("org.cryptomator.frontend.fuse.locks");
|
||||||
fuseLocking.setLevel(Level.OFF);
|
fuseLocking.setLevel(Level.OFF);
|
||||||
|
//deactivate kwallet unsettling message
|
||||||
|
Logger kdeWallet = context.getLogger("org.purejava.kwallet.freedesktop.dbus.handlers");
|
||||||
|
kdeWallet.setLevel(Level.OFF);
|
||||||
}
|
}
|
||||||
return ExecutionStatus.DO_NOT_INVOKE_NEXT_IF_ANY;
|
return ExecutionStatus.DO_NOT_INVOKE_NEXT_IF_ANY;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,185 @@
|
|||||||
|
package org.cryptomator.networking;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.security.Key;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.KeyStoreSpi;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.UnrecoverableKeyException;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
public class CombinedKeyStoreSpi extends KeyStoreSpi {
|
||||||
|
|
||||||
|
private final KeyStore primary;
|
||||||
|
private final KeyStore fallback;
|
||||||
|
|
||||||
|
public static CombinedKeyStoreSpi create(KeyStore primary, KeyStore fallback) {
|
||||||
|
checkIfLoaded(primary);
|
||||||
|
checkIfLoaded(fallback);
|
||||||
|
return new CombinedKeyStoreSpi(primary, fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkIfLoaded(KeyStore s) {
|
||||||
|
try {
|
||||||
|
s.aliases();
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
throw new IllegalArgumentException("Keystore %s is not loaded.".formatted(s.getType()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CombinedKeyStoreSpi(KeyStore primary, KeyStore fallback) {
|
||||||
|
this.primary = primary;
|
||||||
|
this.fallback = fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException, UnrecoverableKeyException {
|
||||||
|
try {
|
||||||
|
Key key = primary.getKey(alias, password);
|
||||||
|
if (key == null) {
|
||||||
|
key = fallback.getKey(alias, password);
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Certificate[] engineGetCertificateChain(String alias) {
|
||||||
|
try {
|
||||||
|
Certificate[] chain = primary.getCertificateChain(alias);
|
||||||
|
if (chain == null) {
|
||||||
|
chain = fallback.getCertificateChain(alias);
|
||||||
|
}
|
||||||
|
return chain;
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Certificate engineGetCertificate(String alias) {
|
||||||
|
try {
|
||||||
|
Certificate cert = primary.getCertificate(alias);
|
||||||
|
if (cert == null) {
|
||||||
|
cert = fallback.getCertificate(alias);
|
||||||
|
}
|
||||||
|
return cert;
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date engineGetCreationDate(String alias) {
|
||||||
|
try {
|
||||||
|
Date date = primary.getCreationDate(alias);
|
||||||
|
if (date == null) {
|
||||||
|
date = fallback.getCreationDate(alias);
|
||||||
|
}
|
||||||
|
return date;
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain) throws KeyStoreException {
|
||||||
|
throw new UnsupportedOperationException("Read-only KeyStore");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) throws KeyStoreException {
|
||||||
|
throw new UnsupportedOperationException("Read-only KeyStore");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void engineSetCertificateEntry(String alias, Certificate cert) throws KeyStoreException {
|
||||||
|
throw new UnsupportedOperationException("Read-only KeyStore");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void engineDeleteEntry(String alias) throws KeyStoreException {
|
||||||
|
throw new UnsupportedOperationException("Read-only KeyStore");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Enumeration<String> engineAliases() {
|
||||||
|
var aliases = new LinkedHashSet<String>();
|
||||||
|
try {
|
||||||
|
primary.aliases().asIterator().forEachRemaining(aliases::add);
|
||||||
|
fallback.aliases().asIterator().forEachRemaining(aliases::add);
|
||||||
|
return Collections.enumeration(aliases);
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean engineContainsAlias(String alias) {
|
||||||
|
try {
|
||||||
|
return primary.containsAlias(alias) || fallback.containsAlias(alias);
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int engineSize() {
|
||||||
|
var aliases = engineAliases();
|
||||||
|
var i = new AtomicInteger(0);
|
||||||
|
aliases.asIterator().forEachRemaining(_ -> i.incrementAndGet());
|
||||||
|
return i.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean engineIsKeyEntry(String alias) {
|
||||||
|
try {
|
||||||
|
return primary.isKeyEntry(alias) || fallback.isKeyEntry(alias);
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean engineIsCertificateEntry(String alias) {
|
||||||
|
try {
|
||||||
|
return primary.isCertificateEntry(alias) || fallback.isCertificateEntry(alias);
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String engineGetCertificateAlias(Certificate cert) {
|
||||||
|
try {
|
||||||
|
String alias = primary.getCertificateAlias(cert);
|
||||||
|
if (alias == null) {
|
||||||
|
alias = fallback.getCertificateAlias(cert);
|
||||||
|
}
|
||||||
|
return alias;
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
throw new IllegalStateException("At least one keystore of [%s, %s] is not initialized.".formatted(primary.getType(), fallback.getType()), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void engineStore(OutputStream stream, char[] password) throws IOException, NoSuchAlgorithmException, CertificateException {
|
||||||
|
throw new UnsupportedOperationException("Read-only KeyStore");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void engineLoad(InputStream stream, char[] password) throws IOException, NoSuchAlgorithmException, CertificateException {
|
||||||
|
// Nothing to do; the real keystores are already loaded.
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package org.cryptomator.networking;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.KeyManagementException;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
|
||||||
|
abstract class SSLContextDifferentTrustStoreBase implements SSLContextProvider {
|
||||||
|
|
||||||
|
abstract KeyStore getTruststore() throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SSLContext getContext(SecureRandom csprng) throws SSLContextBuildException {
|
||||||
|
try {
|
||||||
|
KeyStore truststore = getTruststore();
|
||||||
|
truststore.load(null, null);
|
||||||
|
|
||||||
|
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||||
|
tmf.init(truststore);
|
||||||
|
|
||||||
|
SSLContext context = SSLContext.getInstance("TLS");
|
||||||
|
context.init(null, tmf.getTrustManagers(), csprng);
|
||||||
|
return context;
|
||||||
|
} catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | KeyManagementException | IOException e) {
|
||||||
|
throw new SSLContextBuildException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package org.cryptomator.networking;
|
||||||
|
|
||||||
|
import org.cryptomator.integrations.common.IntegrationsLoader;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.ServiceLoader;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public interface SSLContextProvider {
|
||||||
|
|
||||||
|
SSLContext getContext(SecureRandom csprng) throws SSLContextBuildException;
|
||||||
|
|
||||||
|
class SSLContextBuildException extends Exception {
|
||||||
|
|
||||||
|
SSLContextBuildException(Throwable t) {
|
||||||
|
super(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stream<SSLContextProvider> loadAll() {
|
||||||
|
return IntegrationsLoader.loadAll(ServiceLoader.load(SSLContextProvider.class), SSLContextProvider.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package org.cryptomator.networking;
|
||||||
|
|
||||||
|
import org.cryptomator.integrations.common.OperatingSystem;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.Provider;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SSLContextProvider for macOS using the macOS Keychain as truststore
|
||||||
|
*/
|
||||||
|
@OperatingSystem(OperatingSystem.Value.MAC)
|
||||||
|
public class SSLContextWithMacKeychain extends SSLContextDifferentTrustStoreBase implements SSLContextProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
KeyStore getTruststore() throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException {
|
||||||
|
var userKeyStore = KeyStore.getInstance("KeychainStore");
|
||||||
|
var systemRootKeyStore = KeyStore.getInstance("KeychainStore-ROOT");
|
||||||
|
userKeyStore.load(null);
|
||||||
|
systemRootKeyStore.load(null);
|
||||||
|
try {
|
||||||
|
CombinedKeyStoreSpi spi = CombinedKeyStoreSpi.create(userKeyStore, systemRootKeyStore);
|
||||||
|
Provider dummyProvider = new Provider("CombinedKeyStoreProvider", "1.0", "Provides a combined, read-only KeyStore") {};
|
||||||
|
return new KeyStore(spi, dummyProvider, "CombinedKeyStoreProvider") {};
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new KeyStoreException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package org.cryptomator.networking;
|
||||||
|
|
||||||
|
import org.cryptomator.integrations.common.CheckAvailability;
|
||||||
|
import org.cryptomator.integrations.common.OperatingSystem;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.NoSuchFileException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SSLContextProvider for Linux using a PKCS#12 file as trust store
|
||||||
|
*/
|
||||||
|
@OperatingSystem(OperatingSystem.Value.LINUX)
|
||||||
|
@CheckAvailability
|
||||||
|
public class SSLContextWithPKCS12TrustStore extends SSLContextDifferentTrustStoreBase implements SSLContextProvider {
|
||||||
|
|
||||||
|
private static final String CERT_FILE_LOCATION_PROPERTY = "cryptomator.networking.truststore.p12Path";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
KeyStore getTruststore() throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException {
|
||||||
|
var pkcs12FilePath = Path.of(System.getProperty(CERT_FILE_LOCATION_PROPERTY));
|
||||||
|
try {
|
||||||
|
return KeyStore.getInstance(pkcs12FilePath.toFile(), new char[]{});
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new NoSuchFileException(pkcs12FilePath.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CheckAvailability
|
||||||
|
public static boolean isSupported() {
|
||||||
|
var pkcs12Path = System.getProperty(CERT_FILE_LOCATION_PROPERTY);
|
||||||
|
return Optional.ofNullable(pkcs12Path) //
|
||||||
|
.map(Path::of) //
|
||||||
|
.map(Files::exists).orElse(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package org.cryptomator.networking;
|
||||||
|
|
||||||
|
import org.cryptomator.integrations.common.OperatingSystem;
|
||||||
|
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SSLContextProvider for Windows using the Windows certificate store as trust store
|
||||||
|
* <p>
|
||||||
|
* In order to work, the jdk.crypto.mscapi jmod is needed
|
||||||
|
*/
|
||||||
|
@OperatingSystem(OperatingSystem.Value.WINDOWS)
|
||||||
|
public class SSLContextWithWindowsCertStore extends SSLContextDifferentTrustStoreBase implements SSLContextProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
KeyStore getTruststore() throws KeyStoreException {
|
||||||
|
return KeyStore.getInstance("WINDOWS-ROOT");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+1
-1
@@ -26,7 +26,7 @@ public class CreateNewVaultExpertSettingsController implements FxController {
|
|||||||
|
|
||||||
public static final int MAX_SHORTENING_THRESHOLD = 220;
|
public static final int MAX_SHORTENING_THRESHOLD = 220;
|
||||||
public static final int MIN_SHORTENING_THRESHOLD = 36;
|
public static final int MIN_SHORTENING_THRESHOLD = 36;
|
||||||
private static final String DOCS_NAME_SHORTENING_URL = "https://docs.cryptomator.org/en/1.7/security/architecture/#name-shortening";
|
private static final String DOCS_NAME_SHORTENING_URL = "https://docs.cryptomator.org/security/architecture/#name-shortening";
|
||||||
|
|
||||||
private final Stage window;
|
private final Stage window;
|
||||||
private final Lazy<Application> application;
|
private final Lazy<Application> application;
|
||||||
|
|||||||
+10
-8
@@ -40,7 +40,6 @@ import java.io.IOException;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.StandardOpenOption;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
@@ -50,7 +49,7 @@ public class CreateNewVaultLocationController implements FxController {
|
|||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(CreateNewVaultLocationController.class);
|
private static final Logger LOG = LoggerFactory.getLogger(CreateNewVaultLocationController.class);
|
||||||
private static final Path DEFAULT_CUSTOM_VAULT_PATH = Paths.get(System.getProperty("user.home"));
|
private static final Path DEFAULT_CUSTOM_VAULT_PATH = Paths.get(System.getProperty("user.home"));
|
||||||
private static final String TEMP_FILE_FORMAT = ".locationTest.cryptomator.tmp";
|
private static final String TEMP_FILE_PREFIX = ".locationTest.cryptomator";
|
||||||
|
|
||||||
private final Stage window;
|
private final Stage window;
|
||||||
private final Lazy<Scene> chooseNameScene;
|
private final Lazy<Scene> chooseNameScene;
|
||||||
@@ -126,16 +125,19 @@ public class CreateNewVaultLocationController implements FxController {
|
|||||||
|
|
||||||
|
|
||||||
private boolean isActuallyWritable(Path p) {
|
private boolean isActuallyWritable(Path p) {
|
||||||
Path tmpFile = p.resolve(TEMP_FILE_FORMAT);
|
Path tmpDir = null;
|
||||||
try (var chan = Files.newByteChannel(tmpFile, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE, StandardOpenOption.DELETE_ON_CLOSE)) {
|
try {
|
||||||
|
tmpDir = Files.createTempDirectory(p, TEMP_FILE_PREFIX );
|
||||||
return true;
|
return true;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return false;
|
return false;
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
if (tmpDir != null) {
|
||||||
Files.deleteIfExists(tmpFile);
|
try {
|
||||||
} catch (IOException e) {
|
Files.deleteIfExists(tmpDir);
|
||||||
LOG.warn("Unable to delete temporary file {}. Needs to be deleted manually.", tmpFile);
|
} catch (IOException e) {
|
||||||
|
LOG.warn("Unable to delete temporary directory {}. Needs to be deleted manually.", tmpDir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ public class ReadmeGenerator {
|
|||||||
input.chars().forEachOrdered(c -> {
|
input.chars().forEachOrdered(c -> {
|
||||||
if (c < 128) {
|
if (c < 128) {
|
||||||
sb.append((char) c);
|
sb.append((char) c);
|
||||||
|
} else if (c <= 0xFF) {
|
||||||
|
sb.append("\\'").append(String.format("%02X", c));
|
||||||
} else if (c < 0xFFFF) {
|
} else if (c < 0xFFFF) {
|
||||||
sb.append("\\u").append(c);
|
sb.append("\\u").append(c);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ public enum FxmlFile {
|
|||||||
CONVERTVAULT_HUBTOPASSWORD_START("/fxml/convertvault_hubtopassword_start.fxml"), //
|
CONVERTVAULT_HUBTOPASSWORD_START("/fxml/convertvault_hubtopassword_start.fxml"), //
|
||||||
CONVERTVAULT_HUBTOPASSWORD_CONVERT("/fxml/convertvault_hubtopassword_convert.fxml"), //
|
CONVERTVAULT_HUBTOPASSWORD_CONVERT("/fxml/convertvault_hubtopassword_convert.fxml"), //
|
||||||
CONVERTVAULT_HUBTOPASSWORD_SUCCESS("/fxml/convertvault_hubtopassword_success.fxml"), //
|
CONVERTVAULT_HUBTOPASSWORD_SUCCESS("/fxml/convertvault_hubtopassword_success.fxml"), //
|
||||||
|
DECRYPTNAMES("/fxml/decryptnames.fxml"), //
|
||||||
ERROR("/fxml/error.fxml"), //
|
ERROR("/fxml/error.fxml"), //
|
||||||
|
EVENT_VIEW("/fxml/eventview.fxml"), //
|
||||||
FORGET_PASSWORD("/fxml/forget_password.fxml"), //
|
FORGET_PASSWORD("/fxml/forget_password.fxml"), //
|
||||||
HEALTH_START("/fxml/health_start.fxml"), //
|
HEALTH_START("/fxml/health_start.fxml"), //
|
||||||
HEALTH_CHECK_LIST("/fxml/health_check_list.fxml"), //
|
HEALTH_CHECK_LIST("/fxml/health_check_list.fxml"), //
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ public enum FontAwesome5Icon {
|
|||||||
ANCHOR("\uF13D"), //
|
ANCHOR("\uF13D"), //
|
||||||
ARROW_UP("\uF062"), //
|
ARROW_UP("\uF062"), //
|
||||||
BAN("\uF05E"), //
|
BAN("\uF05E"), //
|
||||||
|
BELL("\uF0F3"), //
|
||||||
BUG("\uF188"), //
|
BUG("\uF188"), //
|
||||||
CARET_DOWN("\uF0D7"), //
|
CARET_DOWN("\uF0D7"), //
|
||||||
CARET_RIGHT("\uF0Da"), //
|
CARET_RIGHT("\uF0Da"), //
|
||||||
@@ -15,10 +16,12 @@ public enum FontAwesome5Icon {
|
|||||||
CLIPBOARD("\uF328"), //
|
CLIPBOARD("\uF328"), //
|
||||||
COG("\uF013"), //
|
COG("\uF013"), //
|
||||||
COGS("\uF085"), //
|
COGS("\uF085"), //
|
||||||
|
COMPRESS_ALT("\uF422"), //
|
||||||
COPY("\uF0C5"), //
|
COPY("\uF0C5"), //
|
||||||
CROWN("\uF521"), //
|
CROWN("\uF521"), //
|
||||||
DONATE("\uF4B9"), //
|
DONATE("\uF4B9"), //
|
||||||
EDIT("\uF044"), //
|
EDIT("\uF044"), //
|
||||||
|
ELLIPSIS_V("\uF142"), //
|
||||||
EXCHANGE_ALT("\uF362"), //
|
EXCHANGE_ALT("\uF362"), //
|
||||||
EXCLAMATION("\uF12A"), //
|
EXCLAMATION("\uF12A"), //
|
||||||
EXCLAMATION_CIRCLE("\uF06A"), //
|
EXCLAMATION_CIRCLE("\uF06A"), //
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import org.cryptomator.ui.common.FxController;
|
|||||||
import org.cryptomator.ui.common.FxmlFile;
|
import org.cryptomator.ui.common.FxmlFile;
|
||||||
import org.cryptomator.ui.common.FxmlScene;
|
import org.cryptomator.ui.common.FxmlScene;
|
||||||
import org.cryptomator.ui.fxapp.FxApplicationWindows;
|
import org.cryptomator.ui.fxapp.FxApplicationWindows;
|
||||||
|
import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingStrategy;
|
||||||
import org.cryptomator.ui.recoverykey.RecoveryKeyFactory;
|
import org.cryptomator.ui.recoverykey.RecoveryKeyFactory;
|
||||||
import org.jetbrains.annotations.VisibleForTesting;
|
import org.jetbrains.annotations.VisibleForTesting;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -108,6 +109,7 @@ public class HubToPasswordConvertController implements FxController {
|
|||||||
.thenRunAsync(this::convertInternal, backgroundExecutorService) //
|
.thenRunAsync(this::convertInternal, backgroundExecutorService) //
|
||||||
.whenCompleteAsync((result, exception) -> {
|
.whenCompleteAsync((result, exception) -> {
|
||||||
if (exception == null) {
|
if (exception == null) {
|
||||||
|
vault.getVaultSettings().lastKnownKeyLoader.set(MasterkeyFileLoadingStrategy.SCHEME);
|
||||||
LOG.info("Conversion of vault {} succeeded.", vault.getPath());
|
LOG.info("Conversion of vault {} succeeded.", vault.getPath());
|
||||||
window.setScene(successScene.get());
|
window.setScene(successScene.get());
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package org.cryptomator.ui.decryptname;
|
||||||
|
|
||||||
|
import javafx.beans.property.ReadOnlyStringWrapper;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public record CipherAndCleartext(Path ciphertext, String cleartextName) {
|
||||||
|
|
||||||
|
public String getCiphertextFilename() {
|
||||||
|
return ciphertext.getFileName().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableValue<String> ciphertextFilenameProperty() {
|
||||||
|
return new ReadOnlyStringWrapper(getCiphertextFilename());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCleartextName() {
|
||||||
|
return cleartextName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableValue<String> cleartextNameProperty() {
|
||||||
|
return new ReadOnlyStringWrapper(getCleartextName());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,233 @@
|
|||||||
|
package org.cryptomator.ui.decryptname;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.SystemUtils;
|
||||||
|
import org.cryptomator.common.vaults.Vault;
|
||||||
|
import org.cryptomator.cryptofs.common.Constants;
|
||||||
|
import org.cryptomator.ui.common.FxController;
|
||||||
|
import org.cryptomator.ui.controls.FontAwesome5Icon;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.property.BooleanProperty;
|
||||||
|
import javafx.beans.property.ListProperty;
|
||||||
|
import javafx.beans.property.ObjectProperty;
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
|
import javafx.beans.property.SimpleListProperty;
|
||||||
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.beans.property.StringProperty;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.scene.control.TableColumn;
|
||||||
|
import javafx.scene.control.TableView;
|
||||||
|
import javafx.scene.control.cell.PropertyValueFactory;
|
||||||
|
import javafx.scene.input.Clipboard;
|
||||||
|
import javafx.scene.input.DataFormat;
|
||||||
|
import javafx.scene.input.KeyCode;
|
||||||
|
import javafx.scene.input.KeyCodeCombination;
|
||||||
|
import javafx.scene.input.TransferMode;
|
||||||
|
import javafx.stage.FileChooser;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@DecryptNameScoped
|
||||||
|
public class DecryptFileNamesViewController implements FxController {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(DecryptFileNamesViewController.class);
|
||||||
|
private static final KeyCodeCombination COPY_TO_CLIPBOARD_SHORTCUT = new KeyCodeCombination(KeyCode.C, KeyCodeCombination.SHORTCUT_DOWN);
|
||||||
|
private static final String COPY_TO_CLIPBOARD_SHORTCUT_STRING_WIN = "CTRL+C";
|
||||||
|
private static final String COPY_TO_CLIPBOARD_SHORTCUT_STRING_MAC = "⌘C";
|
||||||
|
private static final String COPY_TO_CLIPBOARD_SHORTCUT_STRING_LINUX = "CTRL+C";
|
||||||
|
|
||||||
|
private final ListProperty<CipherAndCleartext> mapping;
|
||||||
|
private final StringProperty dropZoneText = new SimpleStringProperty();
|
||||||
|
private final ObjectProperty<FontAwesome5Icon> dropZoneIcon = new SimpleObjectProperty<>();
|
||||||
|
private final BooleanProperty wrongFilesSelected = new SimpleBooleanProperty(false);
|
||||||
|
private final Stage window;
|
||||||
|
private final Vault vault;
|
||||||
|
private final ResourceBundle resourceBundle;
|
||||||
|
private final List<Path> initialList;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public TableColumn<CipherAndCleartext, String> ciphertextColumn;
|
||||||
|
@FXML
|
||||||
|
public TableColumn<CipherAndCleartext, String> cleartextColumn;
|
||||||
|
@FXML
|
||||||
|
public TableView<CipherAndCleartext> cipherToCleartextTable;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public DecryptFileNamesViewController(@DecryptNameWindow Stage window, @DecryptNameWindow Vault vault, @DecryptNameWindow List<Path> pathsToDecrypt, ResourceBundle resourceBundle) {
|
||||||
|
this.window = window;
|
||||||
|
this.vault = vault;
|
||||||
|
this.resourceBundle = resourceBundle;
|
||||||
|
this.mapping = new SimpleListProperty<>(FXCollections.observableArrayList());
|
||||||
|
this.initialList = pathsToDecrypt;
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void initialize() {
|
||||||
|
cipherToCleartextTable.setItems(mapping);
|
||||||
|
cipherToCleartextTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY_ALL_COLUMNS);
|
||||||
|
//DragNDrop
|
||||||
|
cipherToCleartextTable.setOnDragEntered(event -> {
|
||||||
|
if (event.getGestureSource() == null && event.getDragboard().hasFiles()) {
|
||||||
|
cipherToCleartextTable.setItems(FXCollections.emptyObservableList());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cipherToCleartextTable.setOnDragOver(event -> {
|
||||||
|
if (event.getGestureSource() == null && event.getDragboard().hasFiles()) {
|
||||||
|
if (SystemUtils.IS_OS_WINDOWS || SystemUtils.IS_OS_MAC) {
|
||||||
|
event.acceptTransferModes(TransferMode.LINK);
|
||||||
|
} else {
|
||||||
|
event.acceptTransferModes(TransferMode.ANY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cipherToCleartextTable.setOnDragDropped(event -> {
|
||||||
|
if (event.getGestureSource() == null && event.getDragboard().hasFiles()) {
|
||||||
|
checkAndDecrypt(event.getDragboard().getFiles().stream().map(File::toPath).toList());
|
||||||
|
cipherToCleartextTable.setItems(mapping);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cipherToCleartextTable.setOnDragExited(_ -> cipherToCleartextTable.setItems(mapping));
|
||||||
|
//selectionModel and copy-to-clipboard action
|
||||||
|
cipherToCleartextTable.getSelectionModel().setCellSelectionEnabled(true);
|
||||||
|
cipherToCleartextTable.setOnKeyPressed(keyEvent -> {
|
||||||
|
if (COPY_TO_CLIPBOARD_SHORTCUT.match(keyEvent)) {
|
||||||
|
copySingleCelltoClipboard();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ciphertextColumn.setCellValueFactory(new PropertyValueFactory<>("ciphertextFilename"));
|
||||||
|
cleartextColumn.setCellValueFactory(new PropertyValueFactory<>("cleartextName"));
|
||||||
|
|
||||||
|
dropZoneText.setValue(resourceBundle.getString("decryptNames.dropZone.message"));
|
||||||
|
dropZoneIcon.setValue(FontAwesome5Icon.FILE_IMPORT);
|
||||||
|
|
||||||
|
wrongFilesSelected.addListener((_, _, areWrongFiles) -> {
|
||||||
|
if (areWrongFiles) {
|
||||||
|
CompletableFuture.delayedExecutor(5, TimeUnit.SECONDS, Platform::runLater).execute(() -> {
|
||||||
|
dropZoneText.setValue(resourceBundle.getString("decryptNames.dropZone.message"));
|
||||||
|
dropZoneIcon.setValue(FontAwesome5Icon.FILE_IMPORT);
|
||||||
|
wrongFilesSelected.setValue(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!initialList.isEmpty()) {
|
||||||
|
checkAndDecrypt(initialList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copySingleCelltoClipboard() {
|
||||||
|
cipherToCleartextTable.getSelectionModel().getSelectedCells().stream().findFirst().ifPresent(tablePosition -> {
|
||||||
|
var selectedItem = cipherToCleartextTable.getSelectionModel().getSelectedItem();
|
||||||
|
//TODO: give user feedback, if content is copied -> must be done via a custom cell factory to access the actual table cell!
|
||||||
|
if (tablePosition.getTableColumn().equals(ciphertextColumn)) {
|
||||||
|
Clipboard.getSystemClipboard().setContent(Map.of(DataFormat.PLAIN_TEXT, selectedItem.ciphertext().toString()));
|
||||||
|
} else {
|
||||||
|
Clipboard.getSystemClipboard().setContent(Map.of(DataFormat.PLAIN_TEXT, selectedItem.cleartextName()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void selectFiles() {
|
||||||
|
var fileChooser = new FileChooser();
|
||||||
|
fileChooser.setTitle(resourceBundle.getString("decryptNames.filePicker.title"));
|
||||||
|
fileChooser.setSelectedExtensionFilter(new FileChooser.ExtensionFilter(resourceBundle.getString("decryptNames.filePicker.extensionDescription"), List.of("*.c9r")));
|
||||||
|
fileChooser.setInitialDirectory(vault.getPath().toFile());
|
||||||
|
var ciphertextNodes = fileChooser.showOpenMultipleDialog(window);
|
||||||
|
if (ciphertextNodes != null) {
|
||||||
|
checkAndDecrypt(ciphertextNodes.stream().map(File::toPath).toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkAndDecrypt(List<Path> pathsToDecrypt) {
|
||||||
|
mapping.clear();
|
||||||
|
//Assumption: All files are in the same directory
|
||||||
|
var testPath = pathsToDecrypt.getFirst();
|
||||||
|
if (!testPath.startsWith(vault.getPath())) {
|
||||||
|
setDropZoneError(resourceBundle.getString("decryptNames.dropZone.error.foreignFiles").formatted(vault.getDisplayName()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (pathsToDecrypt.size() == 1 && testPath.endsWith(Constants.DIR_ID_BACKUP_FILE_NAME)) {
|
||||||
|
setDropZoneError(resourceBundle.getString("decryptNames.dropZone.error.vaultInternalFiles"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
var newMapping = pathsToDecrypt.stream().filter(p -> !p.endsWith(Constants.DIR_ID_BACKUP_FILE_NAME)).map(this::getCleartextName).toList();
|
||||||
|
mapping.addAll(newMapping);
|
||||||
|
} catch (UncheckedIOException e) {
|
||||||
|
setDropZoneError(resourceBundle.getString("decryptNames.dropZone.error.generic"));
|
||||||
|
LOG.info("Failed to decrypt filenames for directory {}", testPath.getParent(), e);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
setDropZoneError(resourceBundle.getString("decryptNames.dropZone.error.vaultInternalFiles"));
|
||||||
|
} catch (UnsupportedOperationException e) {
|
||||||
|
setDropZoneError(resourceBundle.getString("decryptNames.dropZone.error.noDirIdBackup"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDropZoneError(String text) {
|
||||||
|
dropZoneIcon.setValue(FontAwesome5Icon.TIMES);
|
||||||
|
dropZoneText.setValue(text);
|
||||||
|
wrongFilesSelected.setValue(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CipherAndCleartext getCleartextName(Path ciphertextNode) {
|
||||||
|
try {
|
||||||
|
var cleartextName = vault.getCleartextName(ciphertextNode);
|
||||||
|
return new CipherAndCleartext(ciphertextNode, cleartextName);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new UncheckedIOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//obvservable getter
|
||||||
|
|
||||||
|
public ObservableValue<String> dropZoneTextProperty() {
|
||||||
|
return dropZoneText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDropZoneText() {
|
||||||
|
return dropZoneText.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableValue<FontAwesome5Icon> dropZoneIconProperty() {
|
||||||
|
return dropZoneIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FontAwesome5Icon getDropZoneIcon() {
|
||||||
|
return dropZoneIcon.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearTable() {
|
||||||
|
mapping.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void copyTableToClipboard() {
|
||||||
|
var csv = mapping.stream().map(cipherAndClear -> "\"" + cipherAndClear.ciphertext() + "\", \"" + cipherAndClear.cleartextName() + "\"").collect(Collectors.joining("\n"));
|
||||||
|
Clipboard.getSystemClipboard().setContent(Map.of(DataFormat.PLAIN_TEXT, csv));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCopyToClipboardShortcutString() {
|
||||||
|
if (SystemUtils.IS_OS_WINDOWS) {
|
||||||
|
return COPY_TO_CLIPBOARD_SHORTCUT_STRING_WIN;
|
||||||
|
} else if (SystemUtils.IS_OS_MAC) {
|
||||||
|
return COPY_TO_CLIPBOARD_SHORTCUT_STRING_MAC;
|
||||||
|
} else {
|
||||||
|
return COPY_TO_CLIPBOARD_SHORTCUT_STRING_LINUX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package org.cryptomator.ui.decryptname;
|
||||||
|
|
||||||
|
import dagger.BindsInstance;
|
||||||
|
import dagger.Lazy;
|
||||||
|
import dagger.Subcomponent;
|
||||||
|
import org.cryptomator.common.vaults.Vault;
|
||||||
|
import org.cryptomator.common.vaults.VaultState;
|
||||||
|
import org.cryptomator.ui.common.FxmlFile;
|
||||||
|
import org.cryptomator.ui.common.FxmlScene;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.inject.Named;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@DecryptNameScoped
|
||||||
|
@Subcomponent(modules = DecryptNameModule.class)
|
||||||
|
public interface DecryptNameComponent {
|
||||||
|
|
||||||
|
Logger LOG = LoggerFactory.getLogger(DecryptNameComponent.class);
|
||||||
|
|
||||||
|
@DecryptNameWindow
|
||||||
|
Stage window();
|
||||||
|
|
||||||
|
@FxmlScene(FxmlFile.DECRYPTNAMES)
|
||||||
|
Lazy<Scene> decryptNamesView();
|
||||||
|
|
||||||
|
@DecryptNameWindow
|
||||||
|
Vault vault();
|
||||||
|
|
||||||
|
default void showDecryptFileNameWindow() {
|
||||||
|
Stage s = window();
|
||||||
|
s.setScene(decryptNamesView().get());
|
||||||
|
s.sizeToScene();
|
||||||
|
if (vault().isUnlocked()) {
|
||||||
|
s.show();
|
||||||
|
} else {
|
||||||
|
LOG.error("Aborted showing DecryptFileName window: vault state is not {}, but {}.", VaultState.Value.UNLOCKED, vault().getState());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subcomponent.Factory
|
||||||
|
interface Factory {
|
||||||
|
|
||||||
|
DecryptNameComponent create(@BindsInstance @DecryptNameWindow Vault vault, @BindsInstance @Named("windowOwner") Stage owner, @BindsInstance @DecryptNameWindow List<Path> pathsToDecrypt);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package org.cryptomator.ui.decryptname;
|
||||||
|
|
||||||
|
import dagger.Binds;
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
import dagger.multibindings.IntoMap;
|
||||||
|
import org.cryptomator.common.vaults.Vault;
|
||||||
|
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||||
|
import org.cryptomator.ui.common.FxController;
|
||||||
|
import org.cryptomator.ui.common.FxControllerKey;
|
||||||
|
import org.cryptomator.ui.common.FxmlFile;
|
||||||
|
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||||
|
import org.cryptomator.ui.common.FxmlScene;
|
||||||
|
import org.cryptomator.ui.common.StageFactory;
|
||||||
|
|
||||||
|
import javax.inject.Named;
|
||||||
|
import javax.inject.Provider;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.stage.Modality;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public abstract class DecryptNameModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@DecryptNameScoped
|
||||||
|
@DecryptNameWindow
|
||||||
|
static Stage provideStage(StageFactory factory, @Named("windowOwner") Stage owner, @DecryptNameWindow Vault vault, ResourceBundle resourceBundle) {
|
||||||
|
Stage stage = factory.create();
|
||||||
|
stage.setResizable(true);
|
||||||
|
stage.initModality(Modality.WINDOW_MODAL);
|
||||||
|
stage.initOwner(owner);
|
||||||
|
stage.setTitle(resourceBundle.getString("decryptNames.title"));
|
||||||
|
vault.stateProperty().addListener(((_, _, _) -> stage.close())); //as soon as the state changes from unlocked, close the window
|
||||||
|
return stage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@DecryptNameScoped
|
||||||
|
@DecryptNameWindow
|
||||||
|
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||||
|
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@FxmlScene(FxmlFile.DECRYPTNAMES)
|
||||||
|
@DecryptNameScoped
|
||||||
|
static Scene provideDecryptNamesViewScene(@DecryptNameWindow FxmlLoaderFactory fxmlLoaders) {
|
||||||
|
return fxmlLoaders.createScene(FxmlFile.DECRYPTNAMES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@FxControllerKey(DecryptFileNamesViewController.class)
|
||||||
|
abstract FxController bindDecryptNamesViewController(DecryptFileNamesViewController controller);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package org.cryptomator.ui.decryptname;
|
||||||
|
|
||||||
|
import javax.inject.Scope;
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
@Scope
|
||||||
|
@Documented
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@interface DecryptNameScoped {}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package org.cryptomator.ui.decryptname;
|
||||||
|
|
||||||
|
import javax.inject.Qualifier;
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
@Qualifier
|
||||||
|
@Documented
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
@interface DecryptNameWindow {}
|
||||||
@@ -2,31 +2,34 @@ package org.cryptomator.ui.dialogs;
|
|||||||
|
|
||||||
import org.cryptomator.common.settings.Settings;
|
import org.cryptomator.common.settings.Settings;
|
||||||
import org.cryptomator.common.vaults.Vault;
|
import org.cryptomator.common.vaults.Vault;
|
||||||
|
import org.cryptomator.ui.common.StageFactory;
|
||||||
import org.cryptomator.ui.controls.FontAwesome5Icon;
|
import org.cryptomator.ui.controls.FontAwesome5Icon;
|
||||||
|
import org.cryptomator.ui.fxapp.FxApplicationScoped;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
@Singleton
|
@FxApplicationScoped
|
||||||
public class Dialogs {
|
public class Dialogs {
|
||||||
|
|
||||||
private final ResourceBundle resourceBundle;
|
private final ResourceBundle resourceBundle;
|
||||||
|
private final StageFactory stageFactory;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public Dialogs(ResourceBundle resourceBundle) {
|
public Dialogs(ResourceBundle resourceBundle, StageFactory stageFactory) {
|
||||||
this.resourceBundle = resourceBundle;
|
this.resourceBundle = resourceBundle;
|
||||||
|
this.stageFactory = stageFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(Dialogs.class);
|
private static final Logger LOG = LoggerFactory.getLogger(Dialogs.class);
|
||||||
|
|
||||||
private SimpleDialog.Builder createDialogBuilder() {
|
private SimpleDialog.Builder createDialogBuilder() {
|
||||||
return new SimpleDialog.Builder(resourceBundle);
|
return new SimpleDialog.Builder(resourceBundle, stageFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SimpleDialog.Builder prepareRemoveVaultDialog(Stage window, Vault vault, ObservableList<Vault> vaults) {
|
public SimpleDialog.Builder prepareRemoveVaultDialog(Stage window, Vault vault, ObservableList<Vault> vaults) {
|
||||||
@@ -35,7 +38,7 @@ public class Dialogs {
|
|||||||
.setMessageKey("removeVault.message") //
|
.setMessageKey("removeVault.message") //
|
||||||
.setDescriptionKey("removeVault.description") //
|
.setDescriptionKey("removeVault.description") //
|
||||||
.setIcon(FontAwesome5Icon.QUESTION) //
|
.setIcon(FontAwesome5Icon.QUESTION) //
|
||||||
.setOkButtonKey("removeVault.confirmBtn") //
|
.setOkButtonKey("generic.button.remove") //
|
||||||
.setCancelButtonKey("generic.button.cancel") //
|
.setCancelButtonKey("generic.button.cancel") //
|
||||||
.setOkAction(stage -> {
|
.setOkAction(stage -> {
|
||||||
LOG.debug("Removing vault {}.", vault.getDisplayName());
|
LOG.debug("Removing vault {}.", vault.getDisplayName());
|
||||||
@@ -51,7 +54,7 @@ public class Dialogs {
|
|||||||
.setMessageKey("removeCert.message") //
|
.setMessageKey("removeCert.message") //
|
||||||
.setDescriptionKey("removeCert.description") //
|
.setDescriptionKey("removeCert.description") //
|
||||||
.setIcon(FontAwesome5Icon.QUESTION) //
|
.setIcon(FontAwesome5Icon.QUESTION) //
|
||||||
.setOkButtonKey("removeCert.confirmBtn") //
|
.setOkButtonKey("generic.button.remove") //
|
||||||
.setCancelButtonKey("generic.button.cancel") //
|
.setCancelButtonKey("generic.button.cancel") //
|
||||||
.setOkAction(stage -> {
|
.setOkAction(stage -> {
|
||||||
settings.licenseKey.set(null);
|
settings.licenseKey.set(null);
|
||||||
@@ -65,11 +68,23 @@ public class Dialogs {
|
|||||||
.setTitleKey("dokanySupportEnd.title") //
|
.setTitleKey("dokanySupportEnd.title") //
|
||||||
.setMessageKey("dokanySupportEnd.message") //
|
.setMessageKey("dokanySupportEnd.message") //
|
||||||
.setDescriptionKey("dokanySupportEnd.description") //
|
.setDescriptionKey("dokanySupportEnd.description") //
|
||||||
.setIcon(FontAwesome5Icon.QUESTION) //
|
.setIcon(FontAwesome5Icon.EXCLAMATION) //
|
||||||
.setOkButtonKey("generic.button.close") //
|
.setOkButtonKey("generic.button.close") //
|
||||||
.setCancelButtonKey("dokanySupportEnd.preferencesBtn") //
|
.setCancelButtonKey("dokanySupportEnd.preferencesBtn") //
|
||||||
.setOkAction(Stage::close) //
|
.setOkAction(Stage::close) //
|
||||||
.setCancelAction(cancelAction);
|
.setCancelAction(cancelAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SimpleDialog.Builder prepareRetryIfReadonlyDialog(Stage window, Consumer<Stage> okAction) {
|
||||||
|
return createDialogBuilder() //
|
||||||
|
.setOwner(window) //
|
||||||
|
.setTitleKey("retryIfReadonly.title") //
|
||||||
|
.setMessageKey("retryIfReadonly.message") //
|
||||||
|
.setDescriptionKey("retryIfReadonly.description") //
|
||||||
|
.setIcon(FontAwesome5Icon.EXCLAMATION) //
|
||||||
|
.setOkButtonKey("retryIfReadonly.retry") //
|
||||||
|
.setCancelButtonKey("generic.button.close") //
|
||||||
|
.setOkAction(okAction) //
|
||||||
|
.setCancelAction(Stage::close);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.cryptomator.ui.dialogs;
|
|||||||
|
|
||||||
import org.cryptomator.ui.common.FxmlFile;
|
import org.cryptomator.ui.common.FxmlFile;
|
||||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||||
|
import org.cryptomator.ui.common.StageFactory;
|
||||||
import org.cryptomator.ui.controls.FontAwesome5Icon;
|
import org.cryptomator.ui.controls.FontAwesome5Icon;
|
||||||
|
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
@@ -17,24 +18,24 @@ import java.util.function.Consumer;
|
|||||||
public class SimpleDialog {
|
public class SimpleDialog {
|
||||||
|
|
||||||
private final ResourceBundle resourceBundle;
|
private final ResourceBundle resourceBundle;
|
||||||
|
|
||||||
private final Stage dialogStage;
|
private final Stage dialogStage;
|
||||||
|
|
||||||
SimpleDialog(Builder builder) throws IOException {
|
SimpleDialog(Builder builder) throws IOException {
|
||||||
this.resourceBundle = builder.resourceBundle;
|
this.resourceBundle = builder.resourceBundle;
|
||||||
dialogStage = new Stage();
|
dialogStage = builder.stageFactory.create();
|
||||||
dialogStage.initOwner(builder.owner);
|
dialogStage.initOwner(builder.owner);
|
||||||
dialogStage.initModality(Modality.WINDOW_MODAL);
|
dialogStage.initModality(Modality.WINDOW_MODAL);
|
||||||
dialogStage.setTitle(resolveText(builder.titleKey, builder.titleArgs));
|
dialogStage.setTitle(resolveText(builder.titleKey, builder.titleArgs));
|
||||||
dialogStage.setResizable(false);
|
dialogStage.setResizable(false);
|
||||||
|
|
||||||
FxmlLoaderFactory loaderFactory = FxmlLoaderFactory.forController(
|
FxmlLoaderFactory loaderFactory = FxmlLoaderFactory.forController( //
|
||||||
new SimpleDialogController(resolveText(builder.messageKey, null),
|
new SimpleDialogController(resolveText(builder.messageKey, null), //
|
||||||
resolveText(builder.descriptionKey, null),
|
resolveText(builder.descriptionKey, null), //
|
||||||
builder.icon,resolveText(builder.okButtonKey, null),
|
builder.icon, //
|
||||||
resolveText(builder.cancelButtonKey, null),
|
resolveText(builder.okButtonKey, null), //
|
||||||
() -> builder.okAction.accept(dialogStage),
|
builder.cancelButtonKey != null ? resolveText(builder.cancelButtonKey, null) : null, //
|
||||||
() -> builder.cancelAction.accept(dialogStage)),
|
() -> builder.okAction.accept(dialogStage), //
|
||||||
|
() -> builder.cancelAction.accept(dialogStage)), //
|
||||||
Scene::new, builder.resourceBundle);
|
Scene::new, builder.resourceBundle);
|
||||||
|
|
||||||
dialogStage.setScene(new Scene(loaderFactory.load(FxmlFile.SIMPLE_DIALOG.getRessourcePathString()).getRoot()));
|
dialogStage.setScene(new Scene(loaderFactory.load(FxmlFile.SIMPLE_DIALOG.getRessourcePathString()).getRoot()));
|
||||||
@@ -60,19 +61,20 @@ public class SimpleDialog {
|
|||||||
|
|
||||||
private Stage owner;
|
private Stage owner;
|
||||||
private final ResourceBundle resourceBundle;
|
private final ResourceBundle resourceBundle;
|
||||||
|
private final StageFactory stageFactory;
|
||||||
private String titleKey;
|
private String titleKey;
|
||||||
private String[] titleArgs;
|
private String[] titleArgs;
|
||||||
private String messageKey;
|
private String messageKey;
|
||||||
private String descriptionKey;
|
private String descriptionKey;
|
||||||
private String okButtonKey;
|
private String okButtonKey;
|
||||||
private String cancelButtonKey;
|
private String cancelButtonKey;
|
||||||
|
|
||||||
private FontAwesome5Icon icon;
|
private FontAwesome5Icon icon;
|
||||||
private Consumer<Stage> okAction = Stage::close;
|
private Consumer<Stage> okAction = Stage::close;
|
||||||
private Consumer<Stage> cancelAction = Stage::close;
|
private Consumer<Stage> cancelAction = Stage::close;
|
||||||
|
|
||||||
public Builder(ResourceBundle resourceBundle) {
|
public Builder(ResourceBundle resourceBundle, StageFactory stageFactory) {
|
||||||
this.resourceBundle = resourceBundle;
|
this.resourceBundle = resourceBundle;
|
||||||
|
this.stageFactory = stageFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setOwner(Stage owner) {
|
public Builder setOwner(Stage owner) {
|
||||||
@@ -122,11 +124,10 @@ public class SimpleDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SimpleDialog build() {
|
public SimpleDialog build() {
|
||||||
Objects.requireNonNull(titleKey,"SimpleDialog titleKey must be set.");
|
Objects.requireNonNull(titleKey, "SimpleDialog titleKey must be set.");
|
||||||
Objects.requireNonNull(messageKey,"SimpleDialog messageKey must be set.");
|
Objects.requireNonNull(messageKey, "SimpleDialog messageKey must be set.");
|
||||||
Objects.requireNonNull(descriptionKey,"SimpleDialog descriptionKey must be set.");
|
Objects.requireNonNull(descriptionKey, "SimpleDialog descriptionKey must be set.");
|
||||||
Objects.requireNonNull(okButtonKey,"SimpleDialog okButtonKey must be set.");
|
Objects.requireNonNull(okButtonKey, "SimpleDialog okButtonKey must be set.");
|
||||||
Objects.requireNonNull(cancelButtonKey,"SimpleDialog cancelButtonKey must be set.");
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return new SimpleDialog(this);
|
return new SimpleDialog(this);
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ public class SimpleDialogController implements FxController {
|
|||||||
private final String cancelButtonText;
|
private final String cancelButtonText;
|
||||||
private final Runnable okAction;
|
private final Runnable okAction;
|
||||||
private final Runnable cancelAction;
|
private final Runnable cancelAction;
|
||||||
|
private final boolean cancelButtonVisible;
|
||||||
|
|
||||||
public SimpleDialogController(String message, String description, FontAwesome5Icon icon, String okButtonText, String cancelButtonText, Runnable okAction, Runnable cancelAction) {
|
public SimpleDialogController(String message, String description, FontAwesome5Icon icon, String okButtonText, String cancelButtonText, Runnable okAction, Runnable cancelAction) {
|
||||||
this.message = message;
|
this.message = message;
|
||||||
@@ -23,6 +24,11 @@ public class SimpleDialogController implements FxController {
|
|||||||
this.cancelButtonText = cancelButtonText;
|
this.cancelButtonText = cancelButtonText;
|
||||||
this.okAction = okAction;
|
this.okAction = okAction;
|
||||||
this.cancelAction = cancelAction;
|
this.cancelAction = cancelAction;
|
||||||
|
this.cancelButtonVisible = cancelButtonText != null && !cancelButtonText.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCancelButtonVisible() {
|
||||||
|
return cancelButtonVisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ public interface ErrorComponent {
|
|||||||
default Stage show() {
|
default Stage show() {
|
||||||
Stage stage = window();
|
Stage stage = window();
|
||||||
stage.setScene(scene());
|
stage.setScene(scene());
|
||||||
stage.setMinWidth(420);
|
stage.setMinWidth(450);
|
||||||
stage.setMinHeight(300);
|
stage.setMinHeight(450);
|
||||||
stage.show();
|
stage.show();
|
||||||
return stage;
|
return stage;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,329 @@
|
|||||||
|
package org.cryptomator.ui.eventview;
|
||||||
|
|
||||||
|
import org.cryptomator.event.FSEventBucket;
|
||||||
|
import org.cryptomator.event.FSEventBucketContent;
|
||||||
|
import org.cryptomator.event.FileSystemEventAggregator;
|
||||||
|
import org.cryptomator.common.Nullable;
|
||||||
|
import org.cryptomator.common.ObservableUtil;
|
||||||
|
import org.cryptomator.cryptofs.CryptoPath;
|
||||||
|
import org.cryptomator.cryptofs.event.BrokenDirFileEvent;
|
||||||
|
import org.cryptomator.cryptofs.event.BrokenFileNodeEvent;
|
||||||
|
import org.cryptomator.cryptofs.event.ConflictResolutionFailedEvent;
|
||||||
|
import org.cryptomator.cryptofs.event.ConflictResolvedEvent;
|
||||||
|
import org.cryptomator.cryptofs.event.DecryptionFailedEvent;
|
||||||
|
import org.cryptomator.integrations.revealpath.RevealFailedException;
|
||||||
|
import org.cryptomator.integrations.revealpath.RevealPathService;
|
||||||
|
import org.cryptomator.ui.common.FxController;
|
||||||
|
import org.cryptomator.ui.controls.FontAwesome5Icon;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javafx.beans.binding.Bindings;
|
||||||
|
import javafx.beans.property.BooleanProperty;
|
||||||
|
import javafx.beans.property.ObjectProperty;
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.beans.property.StringProperty;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.geometry.Side;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.ContextMenu;
|
||||||
|
import javafx.scene.control.MenuItem;
|
||||||
|
import javafx.scene.control.Tooltip;
|
||||||
|
import javafx.scene.input.Clipboard;
|
||||||
|
import javafx.scene.input.ClipboardContent;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
import javafx.util.Duration;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.FormatStyle;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class EventListCellController implements FxController {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(EventListCellController.class);
|
||||||
|
private static final DateTimeFormatter LOCAL_DATE_FORMATTER = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).withZone(ZoneId.systemDefault());
|
||||||
|
private static final DateTimeFormatter LOCAL_TIME_FORMATTER = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).withZone(ZoneId.systemDefault());
|
||||||
|
|
||||||
|
private final FileSystemEventAggregator fileSystemEventAggregator;
|
||||||
|
@Nullable
|
||||||
|
private final RevealPathService revealService;
|
||||||
|
private final ResourceBundle resourceBundle;
|
||||||
|
private final ObjectProperty<Map.Entry<FSEventBucket, FSEventBucketContent>> eventEntry;
|
||||||
|
private final StringProperty eventMessage;
|
||||||
|
private final StringProperty eventDescription;
|
||||||
|
private final ObjectProperty<FontAwesome5Icon> eventIcon;
|
||||||
|
private final ObservableValue<String> eventCount;
|
||||||
|
private final ObservableValue<Boolean> vaultUnlocked;
|
||||||
|
private final ObservableValue<String> readableTime;
|
||||||
|
private final ObservableValue<String> readableDate;
|
||||||
|
private final ObservableValue<String> message;
|
||||||
|
private final ObservableValue<String> description;
|
||||||
|
private final ObservableValue<FontAwesome5Icon> icon;
|
||||||
|
private final BooleanProperty actionsButtonVisible;
|
||||||
|
private final Tooltip eventTooltip;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
HBox root;
|
||||||
|
@FXML
|
||||||
|
ContextMenu eventActionsMenu;
|
||||||
|
@FXML
|
||||||
|
Button eventActionsButton;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public EventListCellController(FileSystemEventAggregator fileSystemEventAggregator, Optional<RevealPathService> revealService, ResourceBundle resourceBundle) {
|
||||||
|
this.fileSystemEventAggregator = fileSystemEventAggregator;
|
||||||
|
this.revealService = revealService.orElseGet(() -> null);
|
||||||
|
this.resourceBundle = resourceBundle;
|
||||||
|
this.eventEntry = new SimpleObjectProperty<>(null);
|
||||||
|
this.eventMessage = new SimpleStringProperty();
|
||||||
|
this.eventDescription = new SimpleStringProperty();
|
||||||
|
this.eventIcon = new SimpleObjectProperty<>();
|
||||||
|
this.eventCount = ObservableUtil.mapWithDefault(eventEntry, e -> e.getValue().count() == 1? "" : "("+ e.getValue().count() +")", "");
|
||||||
|
this.vaultUnlocked = ObservableUtil.mapWithDefault(eventEntry.flatMap(e -> e.getKey().vault().unlockedProperty()), Function.identity(), false);
|
||||||
|
this.readableTime = ObservableUtil.mapWithDefault(eventEntry, e -> LOCAL_TIME_FORMATTER.format(e.getValue().mostRecentEvent().getTimestamp()), "");
|
||||||
|
this.readableDate = ObservableUtil.mapWithDefault(eventEntry, e -> LOCAL_DATE_FORMATTER.format(e.getValue().mostRecentEvent().getTimestamp()), "");
|
||||||
|
this.message = Bindings.createStringBinding(this::selectMessage, vaultUnlocked, eventMessage);
|
||||||
|
this.description = Bindings.createStringBinding(this::selectDescription, vaultUnlocked, eventDescription);
|
||||||
|
this.icon = Bindings.createObjectBinding(this::selectIcon, vaultUnlocked, eventIcon);
|
||||||
|
this.actionsButtonVisible = new SimpleBooleanProperty();
|
||||||
|
this.eventTooltip = new Tooltip();
|
||||||
|
eventTooltip.setShowDelay(Duration.millis(500.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void initialize() {
|
||||||
|
actionsButtonVisible.bind(Bindings.createBooleanBinding(this::determineActionsButtonVisibility, root.hoverProperty(), eventActionsMenu.showingProperty(), vaultUnlocked));
|
||||||
|
vaultUnlocked.addListener((_, _, newValue) -> eventActionsMenu.hide());
|
||||||
|
Tooltip.install(root, eventTooltip);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean determineActionsButtonVisibility() {
|
||||||
|
return vaultUnlocked.getValue() && (eventActionsMenu.isShowing() || root.isHover());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEventEntry(@NotNull Map.Entry<FSEventBucket, FSEventBucketContent> item) {
|
||||||
|
eventEntry.set(item);
|
||||||
|
eventActionsMenu.hide();
|
||||||
|
eventActionsMenu.getItems().clear();
|
||||||
|
eventTooltip.setText(item.getKey().vault().getDisplayName());
|
||||||
|
addAction("generic.action.dismiss", () -> {
|
||||||
|
fileSystemEventAggregator.remove(item.getKey());
|
||||||
|
});
|
||||||
|
switch (item.getValue().mostRecentEvent()) {
|
||||||
|
case ConflictResolvedEvent fse -> this.adjustToConflictResolvedEvent(fse);
|
||||||
|
case ConflictResolutionFailedEvent fse -> this.adjustToConflictEvent(fse);
|
||||||
|
case DecryptionFailedEvent fse -> this.adjustToDecryptionFailedEvent(fse);
|
||||||
|
case BrokenDirFileEvent fse -> this.adjustToBrokenDirFileEvent(fse);
|
||||||
|
case BrokenFileNodeEvent fse -> this.adjustToBrokenFileNodeEvent(fse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void adjustToBrokenFileNodeEvent(BrokenFileNodeEvent bfe) {
|
||||||
|
eventIcon.setValue(FontAwesome5Icon.TIMES);
|
||||||
|
eventMessage.setValue(resourceBundle.getString("eventView.entry.brokenFileNode.message"));
|
||||||
|
eventDescription.setValue(bfe.ciphertextPath().getFileName().toString());
|
||||||
|
if (revealService != null) {
|
||||||
|
addAction("eventView.entry.brokenFileNode.showEncrypted", () -> reveal(revealService, bfe.ciphertextPath()));
|
||||||
|
} else {
|
||||||
|
addAction("eventView.entry.brokenFileNode.copyEncrypted", () -> copyToClipboard(bfe.ciphertextPath().toString()));
|
||||||
|
}
|
||||||
|
addAction("eventView.entry.brokenFileNode.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(bfe.cleartextPath()).toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void adjustToConflictResolvedEvent(ConflictResolvedEvent cre) {
|
||||||
|
eventIcon.setValue(FontAwesome5Icon.CHECK);
|
||||||
|
eventMessage.setValue(resourceBundle.getString("eventView.entry.conflictResolved.message"));
|
||||||
|
eventDescription.setValue(cre.resolvedCiphertextPath().getFileName().toString());
|
||||||
|
if (revealService != null) {
|
||||||
|
addAction("eventView.entry.conflictResolved.showDecrypted", () -> reveal(revealService, convertVaultPathToSystemPath(cre.resolvedCleartextPath())));
|
||||||
|
} else {
|
||||||
|
addAction("eventView.entry.conflictResolved.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(cre.resolvedCleartextPath()).toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void adjustToConflictEvent(ConflictResolutionFailedEvent cfe) {
|
||||||
|
eventIcon.setValue(FontAwesome5Icon.COMPRESS_ALT);
|
||||||
|
eventMessage.setValue(resourceBundle.getString("eventView.entry.conflict.message"));
|
||||||
|
eventDescription.setValue(cfe.conflictingCiphertextPath().getFileName().toString());
|
||||||
|
if (revealService != null) {
|
||||||
|
addAction("eventView.entry.conflict.showDecrypted", () -> reveal(revealService, convertVaultPathToSystemPath(cfe.canonicalCleartextPath())));
|
||||||
|
addAction("eventView.entry.conflict.showEncrypted", () -> reveal(revealService, cfe.conflictingCiphertextPath()));
|
||||||
|
} else {
|
||||||
|
addAction("eventView.entry.conflict.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(cfe.canonicalCleartextPath()).toString()));
|
||||||
|
addAction("eventView.entry.conflict.copyEncrypted", () -> copyToClipboard(cfe.conflictingCiphertextPath().toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void adjustToDecryptionFailedEvent(DecryptionFailedEvent dfe) {
|
||||||
|
eventIcon.setValue(FontAwesome5Icon.BAN);
|
||||||
|
eventMessage.setValue(resourceBundle.getString("eventView.entry.decryptionFailed.message"));
|
||||||
|
eventDescription.setValue(dfe.ciphertextPath().getFileName().toString());
|
||||||
|
if (revealService != null) {
|
||||||
|
addAction("eventView.entry.decryptionFailed.showEncrypted", () -> reveal(revealService, dfe.ciphertextPath()));
|
||||||
|
} else {
|
||||||
|
addAction("eventView.entry.decryptionFailed.copyEncrypted", () -> copyToClipboard(dfe.ciphertextPath().toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void adjustToBrokenDirFileEvent(BrokenDirFileEvent bde) {
|
||||||
|
eventIcon.setValue(FontAwesome5Icon.TIMES);
|
||||||
|
eventMessage.setValue(resourceBundle.getString("eventView.entry.brokenDirFile.message"));
|
||||||
|
eventDescription.setValue(bde.ciphertextPath().getParent().getFileName().toString());
|
||||||
|
if (revealService != null) {
|
||||||
|
addAction("eventView.entry.brokenDirFile.showEncrypted", () -> reveal(revealService, bde.ciphertextPath()));
|
||||||
|
} else {
|
||||||
|
addAction("eventView.entry.brokenDirFile.copyEncrypted", () -> copyToClipboard(bde.ciphertextPath().toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addAction(String localizationKey, Runnable action) {
|
||||||
|
var entry = new MenuItem(resourceBundle.getString(localizationKey));
|
||||||
|
entry.getStyleClass().addLast("dropdown-button-context-menu-item");
|
||||||
|
entry.setOnAction(_ -> action.run());
|
||||||
|
eventActionsMenu.getItems().addLast(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private FontAwesome5Icon selectIcon() {
|
||||||
|
if (vaultUnlocked.getValue()) {
|
||||||
|
return eventIcon.getValue();
|
||||||
|
} else {
|
||||||
|
return FontAwesome5Icon.LOCK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String selectMessage() {
|
||||||
|
if (vaultUnlocked.getValue()) {
|
||||||
|
return eventMessage.getValue();
|
||||||
|
} else {
|
||||||
|
return "***********";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String selectDescription() {
|
||||||
|
if (vaultUnlocked.getValue()) {
|
||||||
|
return eventDescription.getValue();
|
||||||
|
} else if (eventEntry.getValue() != null) {
|
||||||
|
var e = eventEntry.getValue().getKey();
|
||||||
|
return resourceBundle.getString("eventView.entry.vaultLocked.description").formatted(e != null ? e.vault().getDisplayName() : "");
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void toggleEventActionsMenu() {
|
||||||
|
var e = eventEntry.get();
|
||||||
|
if (e != null) {
|
||||||
|
if (eventActionsMenu.isShowing()) {
|
||||||
|
eventActionsMenu.hide();
|
||||||
|
} else {
|
||||||
|
eventActionsMenu.show(eventActionsButton, Side.BOTTOM, 0.0, 0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Path convertVaultPathToSystemPath(Path p) {
|
||||||
|
if (!(p instanceof CryptoPath)) {
|
||||||
|
throw new IllegalArgumentException("Path " + p + " is not a vault path");
|
||||||
|
}
|
||||||
|
var v = eventEntry.getValue().getKey().vault();
|
||||||
|
if (!v.isUnlocked()) {
|
||||||
|
return Path.of(System.getProperty("user.home"));
|
||||||
|
}
|
||||||
|
|
||||||
|
var mountUri = v.getMountPoint().uri();
|
||||||
|
var internalPath = p.toString().substring(1);
|
||||||
|
return Path.of(mountUri.getPath().concat(internalPath).substring(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reveal(RevealPathService s, Path p) {
|
||||||
|
try {
|
||||||
|
s.reveal(p);
|
||||||
|
} catch (RevealFailedException e) {
|
||||||
|
LOG.warn("Failed to show path {}", p, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyToClipboard(String s) {
|
||||||
|
var content = new ClipboardContent();
|
||||||
|
content.putString(s);
|
||||||
|
Clipboard.getSystemClipboard().setContent(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-- property accessors --
|
||||||
|
public ObservableValue<String> messageProperty() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableValue<String> countProperty() {
|
||||||
|
return eventCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCount() {
|
||||||
|
return eventCount.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableValue<String> descriptionProperty() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableValue<FontAwesome5Icon> iconProperty() {
|
||||||
|
return icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FontAwesome5Icon getIcon() {
|
||||||
|
return icon.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableValue<Boolean> actionsButtonVisibleProperty() {
|
||||||
|
return actionsButtonVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isActionsButtonVisible() {
|
||||||
|
return actionsButtonVisible.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableValue<String> eventLocalTimeProperty() {
|
||||||
|
return readableTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEventLocalTime() {
|
||||||
|
return readableTime.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableValue<String> eventLocalDateProperty() {
|
||||||
|
return readableDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEventLocalDate() {
|
||||||
|
return readableDate.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableValue<Boolean> vaultUnlockedProperty() {
|
||||||
|
return vaultUnlocked;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isVaultUnlocked() {
|
||||||
|
return vaultUnlocked.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package org.cryptomator.ui.eventview;
|
||||||
|
|
||||||
|
import org.cryptomator.event.FSEventBucket;
|
||||||
|
import org.cryptomator.event.FSEventBucketContent;
|
||||||
|
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.scene.Parent;
|
||||||
|
import javafx.scene.control.ContentDisplay;
|
||||||
|
import javafx.scene.control.ListCell;
|
||||||
|
import javafx.scene.control.ListView;
|
||||||
|
import javafx.util.Callback;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@EventViewScoped
|
||||||
|
public class EventListCellFactory implements Callback<ListView<Map.Entry<FSEventBucket, FSEventBucketContent>>, ListCell<Map.Entry<FSEventBucket, FSEventBucketContent>>> {
|
||||||
|
|
||||||
|
private static final String FXML_PATH = "/fxml/eventview_cell.fxml";
|
||||||
|
|
||||||
|
private final FxmlLoaderFactory fxmlLoaders;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
EventListCellFactory(@EventViewWindow FxmlLoaderFactory fxmlLoaders) {
|
||||||
|
this.fxmlLoaders = fxmlLoaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListCell<Map.Entry<FSEventBucket, FSEventBucketContent>> call(ListView<Map.Entry<FSEventBucket, FSEventBucketContent>> eventListView) {
|
||||||
|
try {
|
||||||
|
FXMLLoader fxmlLoader = fxmlLoaders.load(FXML_PATH);
|
||||||
|
return new Cell(fxmlLoader.getRoot(), fxmlLoader.getController());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new UncheckedIOException("Failed to load %s.".formatted(FXML_PATH), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Cell extends ListCell<Map.Entry<FSEventBucket, FSEventBucketContent>> {
|
||||||
|
|
||||||
|
private final Parent root;
|
||||||
|
private final EventListCellController controller;
|
||||||
|
|
||||||
|
public Cell(Parent root, EventListCellController controller) {
|
||||||
|
this.root = root;
|
||||||
|
this.controller = controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateItem(Map.Entry<FSEventBucket, FSEventBucketContent> item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
|
||||||
|
if (empty || item == null) {
|
||||||
|
setGraphic(null);
|
||||||
|
this.getStyleClass().remove("list-cell");
|
||||||
|
} else {
|
||||||
|
this.getStyleClass().addLast("list-cell");
|
||||||
|
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
|
||||||
|
setGraphic(root);
|
||||||
|
controller.setEventEntry(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package org.cryptomator.ui.eventview;
|
||||||
|
|
||||||
|
import dagger.Lazy;
|
||||||
|
import dagger.Subcomponent;
|
||||||
|
import org.cryptomator.ui.common.FxmlFile;
|
||||||
|
import org.cryptomator.ui.common.FxmlScene;
|
||||||
|
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
@EventViewScoped
|
||||||
|
@Subcomponent(modules = {EventViewModule.class})
|
||||||
|
public interface EventViewComponent {
|
||||||
|
|
||||||
|
@EventViewWindow
|
||||||
|
Stage window();
|
||||||
|
|
||||||
|
@FxmlScene(FxmlFile.EVENT_VIEW)
|
||||||
|
Lazy<Scene> scene();
|
||||||
|
|
||||||
|
default Stage showEventViewerWindow() {
|
||||||
|
Stage stage = window();
|
||||||
|
stage.setScene(scene().get());
|
||||||
|
stage.sizeToScene();
|
||||||
|
stage.show();
|
||||||
|
stage.requestFocus();
|
||||||
|
return stage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subcomponent.Factory
|
||||||
|
interface Factory {
|
||||||
|
|
||||||
|
EventViewComponent create();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
package org.cryptomator.ui.eventview;
|
||||||
|
|
||||||
|
import org.cryptomator.common.vaults.Vault;
|
||||||
|
import org.cryptomator.event.FSEventBucket;
|
||||||
|
import org.cryptomator.event.FSEventBucketContent;
|
||||||
|
import org.cryptomator.event.FileSystemEventAggregator;
|
||||||
|
import org.cryptomator.ui.common.FxController;
|
||||||
|
import org.cryptomator.ui.fxapp.FxFSEventList;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ListChangeListener;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.collections.transformation.FilteredList;
|
||||||
|
import javafx.collections.transformation.SortedList;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.scene.control.ChoiceBox;
|
||||||
|
import javafx.scene.control.ListView;
|
||||||
|
import javafx.util.StringConverter;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
|
@EventViewScoped
|
||||||
|
public class EventViewController implements FxController {
|
||||||
|
|
||||||
|
private final FilteredList<Map.Entry<FSEventBucket, FSEventBucketContent>> filteredEventList;
|
||||||
|
private final ObservableList<Vault> vaults;
|
||||||
|
private final FileSystemEventAggregator aggregator;
|
||||||
|
private final SortedList<Map.Entry<FSEventBucket, FSEventBucketContent>> sortedEventList;
|
||||||
|
private final ObservableList<Vault> choiceBoxEntries;
|
||||||
|
private final ResourceBundle resourceBundle;
|
||||||
|
private final EventListCellFactory cellFactory;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
ChoiceBox<Vault> vaultFilterChoiceBox;
|
||||||
|
@FXML
|
||||||
|
ListView<Map.Entry<FSEventBucket, FSEventBucketContent>> eventListView;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public EventViewController(FxFSEventList fxFSEventList, ObservableList<Vault> vaults, ResourceBundle resourceBundle, EventListCellFactory cellFactory, FileSystemEventAggregator aggregator) {
|
||||||
|
this.filteredEventList = fxFSEventList.getObservableList().filtered(_ -> true);
|
||||||
|
this.vaults = vaults;
|
||||||
|
this.aggregator = aggregator;
|
||||||
|
this.sortedEventList = new SortedList<>(filteredEventList, this::compareBuckets);
|
||||||
|
this.choiceBoxEntries = FXCollections.observableArrayList();
|
||||||
|
this.resourceBundle = resourceBundle;
|
||||||
|
this.cellFactory = cellFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comparison method for the lru cache. During comparsion the map is accessed.
|
||||||
|
* First the entries are compared by the event timestamp, then vaultId, then identifying path and lastly by class name.
|
||||||
|
*
|
||||||
|
* @param left an entry of a {@link FSEventBucket} and its content
|
||||||
|
* @param right another entry of a {@link FSEventBucket} plus content, compared to {@code left}
|
||||||
|
* @return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
|
||||||
|
*/
|
||||||
|
private int compareBuckets(Map.Entry<FSEventBucket, FSEventBucketContent> left, Map.Entry<FSEventBucket, FSEventBucketContent> right) {
|
||||||
|
var t1 = left.getValue().mostRecentEvent().getTimestamp();
|
||||||
|
var t2 = right.getValue().mostRecentEvent().getTimestamp();
|
||||||
|
var timeComparison = t1.compareTo(t2);
|
||||||
|
if (timeComparison != 0) {
|
||||||
|
return -timeComparison; //we need the reverse timesorting
|
||||||
|
}
|
||||||
|
var vaultIdComparison = left.getKey().vault().getId().compareTo(right.getKey().vault().getId());
|
||||||
|
if (vaultIdComparison != 0) {
|
||||||
|
return vaultIdComparison;
|
||||||
|
}
|
||||||
|
var pathComparison = left.getKey().idPath().compareTo(right.getKey().idPath());
|
||||||
|
if (pathComparison != 0) {
|
||||||
|
return pathComparison;
|
||||||
|
}
|
||||||
|
return left.getKey().c().getName().compareTo(right.getKey().c().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void initialize() {
|
||||||
|
choiceBoxEntries.add(null);
|
||||||
|
choiceBoxEntries.addAll(vaults);
|
||||||
|
vaults.addListener((ListChangeListener<? super Vault>) c -> {
|
||||||
|
while (c.next()) {
|
||||||
|
choiceBoxEntries.removeAll(c.getRemoved());
|
||||||
|
choiceBoxEntries.addAll(c.getAddedSubList());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
eventListView.setCellFactory(cellFactory);
|
||||||
|
eventListView.setItems(sortedEventList);
|
||||||
|
|
||||||
|
vaultFilterChoiceBox.setItems(choiceBoxEntries);
|
||||||
|
vaultFilterChoiceBox.valueProperty().addListener(this::applyVaultFilter);
|
||||||
|
vaultFilterChoiceBox.setConverter(new VaultConverter(resourceBundle));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyVaultFilter(ObservableValue<? extends Vault> v, Vault oldV, Vault newV) {
|
||||||
|
if (newV == null) {
|
||||||
|
filteredEventList.setPredicate(_ -> true);
|
||||||
|
} else {
|
||||||
|
filteredEventList.setPredicate(e -> e.getKey().vault().equals(newV));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
void clearEvents() {
|
||||||
|
aggregator.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class VaultConverter extends StringConverter<Vault> {
|
||||||
|
|
||||||
|
private final ResourceBundle resourceBundle;
|
||||||
|
|
||||||
|
VaultConverter(ResourceBundle resourceBundle) {
|
||||||
|
this.resourceBundle = resourceBundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(Vault v) {
|
||||||
|
if (v == null) {
|
||||||
|
return resourceBundle.getString("eventView.filter.allVaults");
|
||||||
|
} else {
|
||||||
|
return v.getDisplayName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vault fromString(String displayLanguage) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package org.cryptomator.ui.eventview;
|
||||||
|
|
||||||
|
import dagger.Binds;
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
import dagger.multibindings.IntoMap;
|
||||||
|
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||||
|
import org.cryptomator.ui.common.FxController;
|
||||||
|
import org.cryptomator.ui.common.FxControllerKey;
|
||||||
|
import org.cryptomator.ui.common.FxmlFile;
|
||||||
|
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||||
|
import org.cryptomator.ui.common.FxmlScene;
|
||||||
|
import org.cryptomator.ui.common.StageFactory;
|
||||||
|
import org.cryptomator.ui.fxapp.FxFSEventList;
|
||||||
|
|
||||||
|
import javax.inject.Provider;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.stage.Modality;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
abstract class EventViewModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@EventViewScoped
|
||||||
|
@EventViewWindow
|
||||||
|
static Stage provideStage(StageFactory factory, ResourceBundle resourceBundle, FxFSEventList fxFSEventList) {
|
||||||
|
Stage stage = factory.create();
|
||||||
|
stage.setHeight(498);
|
||||||
|
stage.setTitle(resourceBundle.getString("eventView.title"));
|
||||||
|
stage.setResizable(true);
|
||||||
|
stage.initModality(Modality.NONE);
|
||||||
|
stage.focusedProperty().addListener((_,_,isFocused) -> {
|
||||||
|
if(isFocused) {
|
||||||
|
fxFSEventList.unreadEventsProperty().setValue(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return stage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@EventViewScoped
|
||||||
|
@EventViewWindow
|
||||||
|
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||||
|
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@FxmlScene(FxmlFile.EVENT_VIEW)
|
||||||
|
@EventViewScoped
|
||||||
|
static Scene provideEventViewerScene(@EventViewWindow FxmlLoaderFactory fxmlLoaders) {
|
||||||
|
return fxmlLoaders.createScene(FxmlFile.EVENT_VIEW);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@FxControllerKey(EventViewController.class)
|
||||||
|
abstract FxController bindEventViewController(EventViewController controller);
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@FxControllerKey(EventListCellController.class)
|
||||||
|
abstract FxController bindEventListCellController(EventListCellController controller);
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user