mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-09-22 16:04:28 +00:00
Compare commits
305
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d013497c48 | ||
|
|
8691eec42b | ||
|
|
0f9d572677 | ||
|
|
baee23b6d4 | ||
|
|
532ffb1202 | ||
|
|
2a704d5eb4 | ||
|
|
e8f8466d9a | ||
|
|
9297562c99 | ||
|
|
7d62fc78de | ||
|
|
8e7e7de358 | ||
|
|
10c60d7492 | ||
|
|
aa03bd119a | ||
|
|
325ffda9af | ||
|
|
d1270ceeb2 | ||
|
|
7bfd0ed341 | ||
|
|
901a290dd9 | ||
|
|
35b9dadfc2 | ||
|
|
5f57678edc | ||
|
|
30e1922bc9 | ||
|
|
2e0908ab15 | ||
|
|
689ce5b985 | ||
|
|
a71a23aa31 | ||
|
|
864454e6fc | ||
|
|
94c3381723 | ||
|
|
d9f945e70a | ||
|
|
dc9b39202f | ||
|
|
2a01aba3cf | ||
|
|
4305fd3285 | ||
|
|
a24cd1ba7f | ||
|
|
2ba0d963ec | ||
|
|
cd0c6fbd33 | ||
|
|
f4374a2606 | ||
|
|
a1d5b8a4e2 | ||
|
|
34e430aff6 | ||
|
|
c79766cdf6 | ||
|
|
bf76bad626 | ||
|
|
c3f654b454 | ||
|
|
d1d990d47c | ||
|
|
6052c0589e | ||
|
|
db2560fccf | ||
|
|
3a50c32e50 | ||
|
|
65eca31d26 | ||
|
|
3462e0b540 | ||
|
|
697529136e | ||
|
|
50d31bdc18 | ||
|
|
84caf96d3f | ||
|
|
a1a5fd3609 | ||
|
|
6c11cc8f1d | ||
|
|
2b391a6ee3 | ||
|
|
b7fc03213d | ||
|
|
dfe17569e1 | ||
|
|
827f9ad141 | ||
|
|
c8a6d0339e | ||
|
|
b5bbd21f25 | ||
|
|
771468c8c6 | ||
|
|
ea2a48771f | ||
|
|
0e10da25b3 | ||
|
|
943a3e9cfd | ||
|
|
c988fb50a7 | ||
|
|
219ee0da9a | ||
|
|
5665e92839 | ||
|
|
04ff188624 | ||
|
|
ec7d6eafec | ||
|
|
28bb2ff9b1 | ||
|
|
a92ebfdc7b | ||
|
|
f1e97fa64b | ||
|
|
b9d5cf04c2 | ||
|
|
75cd3e44d8 | ||
|
|
3cf1b829b8 | ||
|
|
6e4e9cd261 | ||
|
|
e15dd7565f | ||
|
|
77bc60fe5b | ||
|
|
9f633a1ecb | ||
|
|
fcf59d12a8 | ||
|
|
6721075831 | ||
|
|
4bb0026415 | ||
|
|
bebae14744 | ||
|
|
997315eaf5 | ||
|
|
16d677c40f | ||
|
|
42a1913c17 | ||
|
|
c3f6655e48 | ||
|
|
fa1b0f2de8 | ||
|
|
385574a618 | ||
|
|
a67477bf3b | ||
|
|
03a362e9b4 | ||
|
|
2223bc5e78 | ||
|
|
fdc0d2d6b5 | ||
|
|
58ed48b097 | ||
|
|
7a0d255bd3 | ||
|
|
228fa099cb | ||
|
|
a60ff20f15 | ||
|
|
2328a5e3a8 | ||
|
|
e7e181b1a5 | ||
|
|
f3e7c08b43 | ||
|
|
2a41afcfa9 | ||
|
|
5bf38a328c | ||
|
|
f983b29034 | ||
|
|
4bc217e489 | ||
|
|
b24f52a4ec | ||
|
|
91e7fa3de3 | ||
|
|
1365efab3f | ||
|
|
852963b785 | ||
|
|
c47d4eaf02 | ||
|
|
36da26c6b9 | ||
|
|
33e1cb3131 | ||
|
|
ed4b433df0 | ||
|
|
d2ece543c8 | ||
|
|
4bb2df7d8f | ||
|
|
4d5c6ca29a | ||
|
|
f0d597ba73 | ||
|
|
310329d0b5 | ||
|
|
30f86a7f2a | ||
|
|
5237dc8cae | ||
|
|
67ff4da05b | ||
|
|
947eb11198 | ||
|
|
c6a9af1a04 | ||
|
|
0ddf221e26 | ||
|
|
3f2b5ccde9 | ||
|
|
4fc07c27b3 | ||
|
|
3d0b6dde28 | ||
|
|
45534b0a2b | ||
|
|
6d906beeb8 | ||
|
|
e577c64c35 | ||
|
|
b848e78372 | ||
|
|
39e9395b4b | ||
|
|
ca3157cc70 | ||
|
|
f94c1f07d6 | ||
|
|
d43f197c11 | ||
|
|
67e566832c | ||
|
|
6f5a88af1d | ||
|
|
210b891616 | ||
|
|
20e820c903 | ||
|
|
5307e93c1b | ||
|
|
ec1d25bf65 | ||
|
|
7aa554498b | ||
|
|
85ac3c244d | ||
|
|
5db5346c88 | ||
|
|
e221019b57 | ||
|
|
eeaaced976 | ||
|
|
d246b54268 | ||
|
|
8f4bf144c3 | ||
|
|
e94572960e | ||
|
|
2d1c59bea9 | ||
|
|
921cbd6439 | ||
|
|
f811144ffa | ||
|
|
2ecc711f50 | ||
|
|
cfcc8782ef | ||
|
|
a1379bac40 | ||
|
|
fe3f2b5bd3 | ||
|
|
7fc07ae02c | ||
|
|
268c66a108 | ||
|
|
2a70e2f0f4 | ||
|
|
ffe0302fba | ||
|
|
c5b86bc355 | ||
|
|
5f86473e3e | ||
|
|
a91c74b6eb | ||
|
|
76949d6ccb | ||
|
|
71a09eae67 | ||
|
|
8087fcecfb | ||
|
|
29c73e1bc8 | ||
|
|
8bbdb69cda | ||
|
|
e9ee15dcd5 | ||
|
|
03f6e0a33c | ||
|
|
c5b21b0d8c | ||
|
|
c5c5e297b7 | ||
|
|
24839985e9 | ||
|
|
a7b2802f34 | ||
|
|
c85d0b4beb | ||
|
|
3dff3a8664 | ||
|
|
5b0bbf539b | ||
|
|
1ff7c40fd9 | ||
|
|
d0875ef49e | ||
|
|
e35ed9af72 | ||
|
|
ac43efe149 | ||
|
|
202a2ea79f | ||
|
|
c19a86a348 | ||
|
|
539dcaa85a | ||
|
|
fb91c1a461 | ||
|
|
bd75370dfd | ||
|
|
7a9a9cf4eb | ||
|
|
489e9fce90 | ||
|
|
d378d84832 | ||
|
|
69d73d0fb9 | ||
|
|
97c0cb4f5f | ||
|
|
b4faae7fa0 | ||
|
|
55d76b65cc | ||
|
|
fd6e1e6741 | ||
|
|
155558caa8 | ||
|
|
28217b2de3 | ||
|
|
b9e57ce895 | ||
|
|
95ea23ee6e | ||
|
|
c269184217 | ||
|
|
68d32957e4 | ||
|
|
a771f0a5b7 | ||
|
|
e56e6a8359 | ||
|
|
5f9b77241f | ||
|
|
fb54ee04a6 | ||
|
|
a106b04c7e | ||
|
|
285d48b70b | ||
|
|
0d8d7e4ee5 | ||
|
|
f232f9d958 | ||
|
|
88c3b0cc4f | ||
|
|
ef190db739 | ||
|
|
b378354bb9 | ||
|
|
822e863e27 | ||
|
|
40fbe4f59d | ||
|
|
bf779b5b41 | ||
|
|
ce5dbd14d8 | ||
|
|
48744018a2 | ||
|
|
bd9f79cb56 | ||
|
|
f4c4f72539 | ||
|
|
74718754ad | ||
|
|
eb595379d6 | ||
|
|
220782b84f | ||
|
|
1c104737c1 | ||
|
|
7c8a519919 | ||
|
|
ae1fa5851f | ||
|
|
86ccb1a58f | ||
|
|
c3fb58f7d0 | ||
|
|
b4c384acc9 | ||
|
|
8580e97791 | ||
|
|
5d348ee229 | ||
|
|
dda0ff545c | ||
|
|
708b5938ac | ||
|
|
a3cb8cd2f1 | ||
|
|
3587d53d15 | ||
|
|
2f5e2af8d9 | ||
|
|
8139cb8c38 | ||
|
|
09d5f71335 | ||
|
|
3a638735b7 | ||
|
|
f1f5f7e02f | ||
|
|
94fe8ca449 | ||
|
|
1251e1b873 | ||
|
|
50405c0bd5 | ||
|
|
774d24625c | ||
|
|
ba4902a5bc | ||
|
|
90408504e2 | ||
|
|
c8c44e0554 | ||
|
|
7afab6fe78 | ||
|
|
ad321dfe55 | ||
|
|
d6388d6205 | ||
|
|
b8326907bf | ||
|
|
5beeeae27f | ||
|
|
fb1f3c4757 | ||
|
|
5e32cbcdd0 | ||
|
|
08d741ecf5 | ||
|
|
23060a8497 | ||
|
|
47a32893f0 | ||
|
|
0f7ba4e00e | ||
|
|
0d75b999a3 | ||
|
|
b6d97528d2 | ||
|
|
94c53989b1 | ||
|
|
a72ea1b9f5 | ||
|
|
6395f17736 | ||
|
|
5c61944757 | ||
|
|
c641695a40 | ||
|
|
d93ef2e905 | ||
|
|
8b9377cf4e | ||
|
|
991b03e000 | ||
|
|
73d8c4098e | ||
|
|
6a52d15510 | ||
|
|
d07b1b96dd | ||
|
|
24d472ed8b | ||
|
|
6fe2d73c52 | ||
|
|
523e5d7904 | ||
|
|
304064d9ab | ||
|
|
0d49c60d4d | ||
|
|
0e0e00f116 | ||
|
|
77c0a3e265 | ||
|
|
1807888860 | ||
|
|
be7ac50928 | ||
|
|
9182c415eb | ||
|
|
1a6258eb17 | ||
|
|
9c0c6a91fb | ||
|
|
53436520c9 | ||
|
|
fd5aeaf90a | ||
|
|
f3fcfc913b | ||
|
|
0b0870e313 | ||
|
|
6704bb1f8c | ||
|
|
48d1938b99 | ||
|
|
6199277002 | ||
|
|
9fefe8e462 | ||
|
|
5fcd53be18 | ||
|
|
7147636428 | ||
|
|
690bd833e8 | ||
|
|
1e12590681 | ||
|
|
eea568ca4e | ||
|
|
8009205da7 | ||
|
|
c0f73a2802 | ||
|
|
8e902877a3 | ||
|
|
fd76c89393 | ||
|
|
975baf594c | ||
|
|
5a99c7bb61 | ||
|
|
e2898f0c8b | ||
|
|
cf2b236df5 | ||
|
|
819fa803f3 | ||
|
|
980e2b184b | ||
|
|
ebad677e84 | ||
|
|
4fda4a2b2e | ||
|
|
ffaf7ad360 | ||
|
|
76689705f5 | ||
|
|
0d6d7b0dd6 | ||
|
|
9dfd8adcce | ||
|
|
433eecc6a8 | ||
|
|
36ed4554b2 |
@@ -37,12 +37,17 @@ body:
|
||||
id: volume-type
|
||||
attributes:
|
||||
label: Volume Type
|
||||
description: What is selected under Settings → Virtual Drive?
|
||||
multiple: true
|
||||
description: What volume type is selected under Settings → Virtual Drive?
|
||||
options:
|
||||
- FUSE
|
||||
- Dokany
|
||||
- WebDAV
|
||||
- WinFsp
|
||||
- WinFsp (Local Drive)
|
||||
- FUSE-T
|
||||
- macFUSE
|
||||
- WebDAV (Windows Explorer)
|
||||
- WebDAV (AppleScript)
|
||||
- WebDAV (gio)
|
||||
- WebDAV (HTTP Address)
|
||||
- Dokany (1.5)
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
# Configuration for probot-no-response - https://github.com/probot/no-response
|
||||
|
||||
# Number of days of inactivity before an Issue is closed for lack of response
|
||||
daysUntilClose: 14
|
||||
# Label requiring a response
|
||||
responseRequiredLabel: state:awaiting-response
|
||||
# Comment to post when closing an Issue for lack of response. Set to `false` to disable
|
||||
closeComment: >
|
||||
This issue has been automatically closed because there has been no response
|
||||
to our request for more information from the original author. With only the
|
||||
information that is currently in the issue, we don't have enough information
|
||||
to take action. Please reach out if you have or find the answers we need so
|
||||
that we can investigate further.
|
||||
@@ -0,0 +1,29 @@
|
||||
# .github/release.yml
|
||||
# see https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes#configuring-automatically-generated-release-notes
|
||||
|
||||
changelog:
|
||||
exclude:
|
||||
authors:
|
||||
- cryptobot
|
||||
- dependabot
|
||||
- github-actions
|
||||
categories:
|
||||
- title: What's New 🎉
|
||||
labels:
|
||||
- type:feature-request
|
||||
- type:enhancement
|
||||
- title: Bugfixes 🐛
|
||||
labels:
|
||||
- type:security-issue
|
||||
- type:bug
|
||||
- type:minor-bug
|
||||
- title: Other Changes 📎
|
||||
labels:
|
||||
- "*"
|
||||
exclude:
|
||||
labels:
|
||||
- type:feature-request
|
||||
- type:enhancement
|
||||
- type:security-issue
|
||||
- type:bug
|
||||
- type:minor-bug
|
||||
@@ -1,24 +0,0 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 365
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 90
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- type:security-issue # never close automatically
|
||||
- type:feature-request # never close automatically
|
||||
- type:enhancement # never close automatically
|
||||
- type:upstream-bug # never close automatically
|
||||
- state:awaiting-response # handled by different bot
|
||||
- state:blocked
|
||||
- state:confirmed
|
||||
# Set to true to ignore issues in a milestone (defaults to false)
|
||||
exemptMilestones: true
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: state:stale
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
get-version:
|
||||
uses: ./.github/workflows/get-version.yml
|
||||
with:
|
||||
version: ${{ github.event.inputs.version }}
|
||||
version: ${{ inputs.version }}
|
||||
|
||||
build:
|
||||
name: Build AppImage
|
||||
@@ -47,7 +47,6 @@ jobs:
|
||||
- name: Patch target dir
|
||||
run: |
|
||||
cp LICENSE.txt target
|
||||
cp dist/linux/launcher.sh target
|
||||
cp target/cryptomator-*.jar target/mods
|
||||
- name: Run jlink
|
||||
run: >
|
||||
@@ -55,7 +54,7 @@ jobs:
|
||||
--verbose
|
||||
--output runtime
|
||||
--module-path "${JAVA_HOME}/jmods"
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.security.auth,jdk.accessibility,jdk.management.jfr,jdk.zipfs
|
||||
--strip-native-commands
|
||||
--no-header-files
|
||||
--no-man-pages
|
||||
@@ -78,7 +77,7 @@ jobs:
|
||||
--dest appdir
|
||||
--name Cryptomator
|
||||
--vendor "Skymatic GmbH"
|
||||
--copyright "(C) 2016 - 2022 Skymatic GmbH"
|
||||
--copyright "(C) 2016 - 2023 Skymatic GmbH"
|
||||
--app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}"
|
||||
--java-options "--enable-preview"
|
||||
--java-options "--enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64"
|
||||
@@ -111,12 +110,6 @@ jobs:
|
||||
ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/.DirIcon
|
||||
ln -s usr/share/applications/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/Cryptomator.desktop
|
||||
ln -s bin/cryptomator.sh Cryptomator.AppDir/AppRun
|
||||
- name: Extract libjffi.so # workaround for https://github.com/cryptomator/cryptomator-linux/issues/27
|
||||
run: |
|
||||
JFFI_NATIVE_JAR=`ls lib/app/ | grep -e 'jffi-[1-9]\.[0-9]\{1,2\}.[0-9]\{1,2\}-native.jar'`
|
||||
${JAVA_HOME}/bin/jar -xf lib/app/${JFFI_NATIVE_JAR} /jni/x86_64-Linux/
|
||||
mv jni/x86_64-Linux/* lib/app/libjffi.so
|
||||
working-directory: Cryptomator.AppDir
|
||||
- name: Download AppImageKit
|
||||
run: |
|
||||
curl -L https://github.com/AppImage/AppImageKit/releases/download/13/appimagetool-x86_64.AppImage -o appimagetool.AppImage
|
||||
|
||||
@@ -53,4 +53,8 @@ jobs:
|
||||
body: |-
|
||||
:construction: Work in Progress
|
||||
|
||||
Please be patient, the builds are still running. We will publish new versions of Cryptomator here in a few moments.
|
||||
|
||||
As usual, the GPG signatures can be checked using [our public key `5811 7AFA 1F85 B3EE C154 677D 615D 449F E6E6 A235`](https://gist.github.com/cryptobot/211111cf092037490275f39d408f461a).
|
||||
---
|
||||
<!-- Don't forget to include the 💾 SHA-256 checksums of release artifacts: -->
|
||||
@@ -20,8 +20,8 @@ on:
|
||||
|
||||
env:
|
||||
JAVA_VERSION: 19
|
||||
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/19/openjfx-19_linux-x64_bin-jmods.zip'
|
||||
OPENJFX_JMODS_AARCH64: 'https://download2.gluonhq.com/openjfx/19/openjfx-19_linux-aarch64_bin-jmods.zip'
|
||||
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/19.0.2.1/openjfx-19.0.2.1_linux-x64_bin-jmods.zip'
|
||||
OPENJFX_JMODS_AARCH64: 'https://download2.gluonhq.com/openjfx/19.0.2.1/openjfx-19.0.2.1_linux-aarch64_bin-jmods.zip'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -65,10 +65,10 @@ jobs:
|
||||
unzip -j openjfx-aarch64.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d jmods/aarch64
|
||||
- name: Ensure major jfx version in pom and in jmods is the same
|
||||
run: |
|
||||
JMOD_VERSION_AMD64=$(jmod describe ${JAVA_HOME}/jmods/amd64/javafx.base.jmod | head -1)
|
||||
JMOD_VERSION_AMD64=$(jmod describe jmods/amd64/javafx.base.jmod | head -1)
|
||||
JMOD_VERSION_AMD64=${JMOD_VERSION_AMD64#*@}
|
||||
JMOD_VERSION_AMD64=${JMOD_VERSION_AMD64%%.*}
|
||||
JMOD_VERSION_AARCH64=$(jmod describe ${JAVA_HOME}/jmods/aarch64/javafx.base.jmod | head -1)
|
||||
JMOD_VERSION_AARCH64=$(jmod describe jmods/aarch64/javafx.base.jmod | head -1)
|
||||
JMOD_VERSION_AARCH64=${JMOD_VERSION_AARCH64#*@}
|
||||
JMOD_VERSION_AARCH64=${JMOD_VERSION_AARCH64%%.*}
|
||||
POM_JFX_VERSION=$(mvn help:evaluate "-Dexpression=javafx.version" -q -DforceStdout)
|
||||
@@ -148,11 +148,8 @@ jobs:
|
||||
echo "TAG_NAME=${REF##*/}" >> $GITHUB_ENV
|
||||
- name: Publish Debian package on GitHub Releases
|
||||
if: startsWith(inputs.ref, 'refs/tags/')
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
fail_on_unmatched_files: true
|
||||
tag_name: ${{ github.env.TAG_NAME }}
|
||||
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
|
||||
files: |
|
||||
cryptomator_*_amd64.deb
|
||||
cryptomator_*.asc
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
|
||||
run: |
|
||||
artifacts=$(ls | grep cryptomator*.deb)
|
||||
gh release upload ${{ env.TAG_NAME }} $artifacts
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
get-version:
|
||||
uses: ./.github/workflows/get-version.yml
|
||||
with:
|
||||
version: ${{ github.event.inputs.version }}
|
||||
version: ${{ inputs.version }}
|
||||
|
||||
build:
|
||||
name: Build Cryptomator.app for ${{ matrix.output-suffix }}
|
||||
@@ -30,10 +30,12 @@ jobs:
|
||||
architecture: x64
|
||||
output-suffix: x64
|
||||
xcode-path: '/Applications/Xcode_13.2.1.app'
|
||||
fuse-lib: macFUSE
|
||||
- os: [self-hosted, macOS, ARM64]
|
||||
architecture: aarch64
|
||||
output-suffix: arm64
|
||||
xcode-path: '/Applications/Xcode_13.2.1.app'
|
||||
fuse-lib: FUSE-T
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup Java
|
||||
@@ -61,7 +63,6 @@ jobs:
|
||||
- name: Patch target dir
|
||||
run: |
|
||||
cp LICENSE.txt target
|
||||
cp dist/mac/launcher.sh target
|
||||
cp target/cryptomator-*.jar target/mods
|
||||
- name: Run jlink
|
||||
run: >
|
||||
@@ -69,7 +70,7 @@ jobs:
|
||||
--verbose
|
||||
--output runtime
|
||||
--module-path "${JAVA_HOME}/jmods"
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr,jdk.zipfs
|
||||
--strip-native-commands
|
||||
--no-header-files
|
||||
--no-man-pages
|
||||
@@ -87,7 +88,7 @@ jobs:
|
||||
--dest appdir
|
||||
--name Cryptomator
|
||||
--vendor "Skymatic GmbH"
|
||||
--copyright "(C) 2016 - 2022 Skymatic GmbH"
|
||||
--copyright "(C) 2016 - 2023 Skymatic GmbH"
|
||||
--app-version "${{ needs.get-version.outputs.semVerNum }}"
|
||||
--java-options "--enable-preview"
|
||||
--java-options "--enable-native-access=org.cryptomator.jfuse.mac"
|
||||
@@ -103,6 +104,7 @@ jobs:
|
||||
--java-options "-Dcryptomator.p12Path=\"~/Library/Application Support/Cryptomator/key.p12\""
|
||||
--java-options "-Dcryptomator.ipcSocketPath=\"~/Library/Application Support/Cryptomator/ipc.socket\""
|
||||
--java-options "-Dcryptomator.integrationsMac.keychainServiceName=\"Cryptomator\""
|
||||
--java-options "-Dcryptomator.mountPointsDir=\"~/Cryptomator\""
|
||||
--java-options "-Dcryptomator.showTrayIcon=true"
|
||||
--java-options "-Dcryptomator.buildNumber=\"dmg-${{ needs.get-version.outputs.revNum }}\""
|
||||
--mac-package-identifier org.cryptomator
|
||||
@@ -177,7 +179,7 @@ jobs:
|
||||
run: |
|
||||
mkdir dmg
|
||||
mv Cryptomator.app dmg
|
||||
cp dist/mac/dmg/resources/macFUSE.webloc dmg
|
||||
cp dist/mac/dmg/resources/${{ matrix.fuse-lib }}.webloc dmg
|
||||
ls -l dmg
|
||||
- name: Install create-dmg
|
||||
run: |
|
||||
@@ -188,14 +190,14 @@ jobs:
|
||||
create-dmg
|
||||
--volname Cryptomator
|
||||
--volicon "dist/mac/dmg/resources/Cryptomator-Volume.icns"
|
||||
--background "dist/mac/dmg/resources/Cryptomator-background.tiff"
|
||||
--background "dist/mac/dmg/resources/Cryptomator-${{ matrix.fuse-lib }}-background.tiff"
|
||||
--window-pos 400 100
|
||||
--window-size 640 694
|
||||
--icon-size 128
|
||||
--icon "Cryptomator.app" 128 245
|
||||
--hide-extension "Cryptomator.app"
|
||||
--icon "macFUSE.webloc" 320 501
|
||||
--hide-extension "macFUSE.webloc"
|
||||
--icon "${{ matrix.fuse-lib }}.webloc" 320 501
|
||||
--hide-extension "${{ matrix.fuse-lib }}.webloc"
|
||||
--app-drop-link 512 245
|
||||
--eula "dist/mac/dmg/resources/license.rtf"
|
||||
--icon ".background" 128 758
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# Configuration for close-stale-issues - https://github.com/marketplace/actions/close-stale-issues
|
||||
|
||||
name: 'Close awaiting response issues'
|
||||
on:
|
||||
schedule:
|
||||
- cron: '00 09 * * *'
|
||||
|
||||
jobs:
|
||||
no-response:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/stale@v8
|
||||
with:
|
||||
days-before-stale: 14
|
||||
days-before-close: 0
|
||||
days-before-pr-close: -1
|
||||
stale-issue-label: 'state:stale'
|
||||
close-issue-message: "This issue has been automatically closed because there has been no response to our request for more information from the original author. With only the information that is currently in the issue, we don't have enough information to take action. Please reach out if you have or find the answers we need so that we can investigate further."
|
||||
only-labels: 'state:awaiting-response'
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
steps:
|
||||
- name: Download source tarball
|
||||
run: |
|
||||
curl -L -H "Accept: application/vnd.github+json" ${{ github.event.release.tarball_url }} --output cryptomator-${{ github.event.release.tag_name }}.tar.gz
|
||||
curl -L -H "Accept: application/vnd.github+json" https://github.com/cryptomator/cryptomator/archive/refs/tags/${{ github.event.release.tag_name }}.tar.gz --output cryptomator-${{ github.event.release.tag_name }}.tar.gz
|
||||
- name: Sign source tarball with key 615D449FE6E6A235
|
||||
run: |
|
||||
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# Configuration for close-stale-issues - https://github.com/marketplace/actions/close-stale-issues
|
||||
|
||||
name: 'Close stale issues'
|
||||
on:
|
||||
schedule:
|
||||
- cron: '00 09 * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/stale@v8
|
||||
with:
|
||||
days-before-stale: 365
|
||||
days-before-close: 90
|
||||
exempt-issue-labels: 'type:security-issue,type:feature-request,type:enhancement,type:upstream-bug,state:awaiting-response,state:blocked,state:confirmed'
|
||||
exempt-all-milestones: true
|
||||
stale-issue-label: 'state:stale'
|
||||
stale-pr-label: 'state:stale'
|
||||
stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'
|
||||
stale-pr-message: 'This PR has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'
|
||||
@@ -8,11 +8,17 @@ on:
|
||||
version:
|
||||
description: 'Version'
|
||||
required: false
|
||||
isDebug:
|
||||
description: 'Build debug version with console output'
|
||||
type: boolean
|
||||
|
||||
|
||||
env:
|
||||
JAVA_VERSION: 19
|
||||
JAVA_DIST: 'zulu'
|
||||
JAVA_DIST: 'temurin'
|
||||
JAVA_CACHE: 'maven'
|
||||
JFX_JMODS_URL: 'https://download2.gluonhq.com/openjfx/19.0.2.1/openjfx-19.0.2.1_windows-x64_bin-jmods.zip'
|
||||
JFX_JMODS_HASH: 'B7CF2CAD2468842B3B78D99F6C0555771499A36FA1F1EE3DD1B9A4597F1FAB86'
|
||||
|
||||
defaults:
|
||||
run:
|
||||
@@ -22,7 +28,7 @@ jobs:
|
||||
get-version:
|
||||
uses: ./.github/workflows/get-version.yml
|
||||
with:
|
||||
version: ${{ github.event.inputs.version }}
|
||||
version: ${{ inputs.version }}
|
||||
|
||||
build-msi:
|
||||
name: Build .msi Installer
|
||||
@@ -30,6 +36,7 @@ jobs:
|
||||
needs: [get-version]
|
||||
env:
|
||||
LOOPBACK_ALIAS: 'cryptomator-vault'
|
||||
WIN_CONSOLE_FLAG: ''
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup Java
|
||||
@@ -37,17 +44,31 @@ jobs:
|
||||
with:
|
||||
distribution: ${{ env.JAVA_DIST }}
|
||||
java-version: ${{ env.JAVA_VERSION }}
|
||||
java-package: 'jdk+fx'
|
||||
java-package: 'jdk'
|
||||
cache: ${{ env.JAVA_CACHE }}
|
||||
- name: Ensure major jfx version in pom equals in jdk
|
||||
shell: pwsh
|
||||
- name: Download and extract JavaFX jmods from Gluon
|
||||
#In the last step we move all jmods files a dir level up because jmods are placed inside a directory in the zip
|
||||
run: |
|
||||
$jfxPomVersion = (&mvn help:evaluate "-Dexpression=javafx.version" -q -DforceStdout) -split "\."
|
||||
$jfxJdkVersion = ((Get-Content -path "${env:JAVA_HOME}/lib/javafx.properties" | Where-Object {$_ -like 'javafx.version=*' }) -replace '.*=','') -split "\."
|
||||
if ($jfxPomVersion[0] -ne $jfxJdkVersion[0]) {
|
||||
Write-Error "Major part of JavaFX version in pom($($jfxPomVersion[0])) does not match the version in JDK($($jfxJdkVersion[0])) "
|
||||
exit 1
|
||||
curl --output jfxjmods.zip -L "${{ env.JFX_JMODS_URL }}"
|
||||
if(!(Get-FileHash -Path jfxjmods.zip -Algorithm SHA256).Hash.equals("${{ env.JFX_JMODS_HASH }}")) {
|
||||
exit 1;
|
||||
}
|
||||
Expand-Archive -Path jfxjmods.zip -DestinationPath jfxjmods
|
||||
Get-ChildItem -Path jfxjmods -Recurse -Filter "*.jmod" | ForEach-Object { Move-Item -Path $_ -Destination $_.Directory.Parent}
|
||||
shell: pwsh
|
||||
- name: Ensure major jfx version in pom and in jmods is the same
|
||||
run: |
|
||||
JMOD_VERSION_AMD64=$(jmod describe jfxjmods/javafx.base.jmod | head -1)
|
||||
JMOD_VERSION_AMD64=${JMOD_VERSION_AMD64#*@}
|
||||
JMOD_VERSION_AMD64=${JMOD_VERSION_AMD64%%.*}
|
||||
POM_JFX_VERSION=$(mvn help:evaluate "-Dexpression=javafx.version" -q -DforceStdout)
|
||||
POM_JFX_VERSION=${POM_JFX_VERSION#*@}
|
||||
POM_JFX_VERSION=${POM_JFX_VERSION%%.*}
|
||||
|
||||
if [ $POM_JFX_VERSION -ne $JMOD_VERSION_AMD64 ]; then
|
||||
>&2 echo "Major JavaFX version in pom.xml (${POM_JFX_VERSION}) != amd64 jmod version (${JMOD_VERSION_AMD64})"
|
||||
exit 1
|
||||
fi
|
||||
- name: Set version
|
||||
run : mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }}
|
||||
- name: Run maven
|
||||
@@ -55,20 +76,22 @@ jobs:
|
||||
- name: Patch target dir
|
||||
run: |
|
||||
cp LICENSE.txt target
|
||||
cp dist/linux/launcher.sh target
|
||||
cp target/cryptomator-*.jar target/mods
|
||||
- name: Run jlink
|
||||
run: >
|
||||
${JAVA_HOME}/bin/jlink
|
||||
--verbose
|
||||
--output runtime
|
||||
--module-path "${JAVA_HOME}/jmods"
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr
|
||||
--module-path "jfxjmods;${JAVA_HOME}/jmods"
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr,jdk.zipfs
|
||||
--strip-native-commands
|
||||
--no-header-files
|
||||
--no-man-pages
|
||||
--strip-debug
|
||||
--compress=1
|
||||
- name: Change win-console flag if debug is active
|
||||
if: ${{ inputs.isDebug }}
|
||||
run: echo "WIN_CONSOLE_FLAG=--win-console" >> $GITHUB_ENV
|
||||
- name: Run jpackage
|
||||
run: >
|
||||
${JAVA_HOME}/bin/jpackage
|
||||
@@ -81,7 +104,7 @@ jobs:
|
||||
--dest appdir
|
||||
--name Cryptomator
|
||||
--vendor "Skymatic GmbH"
|
||||
--copyright "(C) 2016 - 2022 Skymatic GmbH"
|
||||
--copyright "(C) 2016 - 2023 Skymatic GmbH"
|
||||
--app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}"
|
||||
--java-options "--enable-preview"
|
||||
--java-options "--enable-native-access=org.cryptomator.jfuse.win"
|
||||
@@ -100,8 +123,10 @@ jobs:
|
||||
--java-options "-Dcryptomator.buildNumber=\"msi-${{ needs.get-version.outputs.revNum }}\""
|
||||
--java-options "-Dcryptomator.integrationsWin.autoStartShellLinkName=\"Cryptomator\""
|
||||
--java-options "-Dcryptomator.integrationsWin.keychainPaths=\"~/AppData/Roaming/Cryptomator/keychain.json\""
|
||||
--java-options "-Djavafx.verbose=${{ inputs.isDebug }}"
|
||||
--resource-dir dist/win/resources
|
||||
--icon dist/win/resources/Cryptomator.ico
|
||||
${WIN_CONSOLE_FLAG}
|
||||
- name: Patch Application Directory
|
||||
run: |
|
||||
cp dist/win/contrib/* appdir/Cryptomator
|
||||
@@ -118,6 +143,9 @@ jobs:
|
||||
- name: Fix permissions
|
||||
run: attrib -r appdir/Cryptomator/Cryptomator.exe
|
||||
shell: pwsh
|
||||
- name: Extract integrations DLL for code signing
|
||||
shell: pwsh
|
||||
run: gci ./appdir/Cryptomator/app/mods/ -File integrations-win-*.jar | ForEach-Object {Set-Location -Path $_.Directory; jar --file=$($_.FullName) --extract integrations.dll }
|
||||
- name: Codesign
|
||||
uses: skymatic/code-sign-action@v2
|
||||
with:
|
||||
@@ -128,6 +156,10 @@ jobs:
|
||||
timestampUrl: 'http://timestamp.digicert.com'
|
||||
folder: appdir/Cryptomator
|
||||
recursive: true
|
||||
- name: Repack signed DLL into jar
|
||||
shell: pwsh
|
||||
run: |
|
||||
gci ./appdir/Cryptomator/app/mods/ -File integrations-win-*.jar | ForEach-Object {Set-Location -Path $_.Directory; jar --file=$($_.FullName) --update integrations.dll; Remove-Item integrations.dll}
|
||||
- name: Generate license for MSI
|
||||
run: >
|
||||
mvn -B license:add-third-party
|
||||
@@ -149,8 +181,8 @@ jobs:
|
||||
--dest installer
|
||||
--name Cryptomator
|
||||
--vendor "Skymatic GmbH"
|
||||
--copyright "(C) 2016 - 2022 Skymatic GmbH"
|
||||
--app-version "${{ needs.get-version.outputs.semVerNum }}"
|
||||
--copyright "(C) 2016 - 2023 Skymatic GmbH"
|
||||
--app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum}}"
|
||||
--win-menu
|
||||
--win-dir-chooser
|
||||
--win-shortcut-prompt
|
||||
@@ -197,15 +229,6 @@ jobs:
|
||||
*.msi
|
||||
*.asc
|
||||
|
||||
call-winget-flow:
|
||||
needs: [get-version, build-msi]
|
||||
if: github.event.action == 'published' && needs.get-version.outputs.versionType == 'stable'
|
||||
uses: ./.github/workflows/winget.yml
|
||||
with:
|
||||
releaseTag: ${{ github.event.release.tag_name }}
|
||||
secrets: inherit
|
||||
|
||||
|
||||
build-exe:
|
||||
name: Build .exe installer
|
||||
runs-on: windows-latest
|
||||
@@ -237,17 +260,18 @@ jobs:
|
||||
shell: pwsh
|
||||
- name: Download WinFsp
|
||||
run: |
|
||||
$winfspUrl= (Select-String -Path ".\dist\win\bundle\resources\winfsp-download.url" -Pattern 'https:.*').Matches.Value
|
||||
$winfspUrl = (Select-String -Path ".\dist\win\bundle\resources\winFspMetaData.wxi" -Pattern '<\?define BundledWinFspDownloadLink="(.+)".*?>').Matches.Groups[1].Value
|
||||
curl --output dist/win/bundle/resources/winfsp.msi -L $winfspUrl
|
||||
shell: pwsh
|
||||
- name: Compile to wixObj file
|
||||
run: >
|
||||
"${WIX}/bin/candle.exe" dist/win/bundle/bundleWithWinfsp.wxs
|
||||
-ext WixBalExtension
|
||||
-ext WixUtilExtension
|
||||
-out dist/win/bundle/
|
||||
-dBundleVersion="${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}"
|
||||
-dBundleVendor="Skymatic GmbH"
|
||||
-dBundleCopyright="(C) 2016 - 2022 Skymatic GmbH"
|
||||
-dBundleCopyright="(C) 2016 - 2023 Skymatic GmbH"
|
||||
-dAboutUrl="https://cryptomator.org"
|
||||
-dHelpUrl="https://cryptomator.org/contact"
|
||||
-dUpdateUrl="https://cryptomator.org/downloads/"
|
||||
@@ -255,6 +279,7 @@ jobs:
|
||||
run: >
|
||||
"${WIX}/bin/light.exe" -b dist/win/ dist/win/bundle/bundleWithWinfsp.wixobj
|
||||
-ext WixBalExtension
|
||||
-ext WixUtilExtension
|
||||
-out installer/unsigned/Cryptomator-Installer.exe
|
||||
- name: Detach burn engine in preparation to sign
|
||||
run: >
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
name: Release to Winget
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
releaseTag:
|
||||
required: true
|
||||
type: string
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
releaseTag:
|
||||
description: 'Release tag name'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
publish-winget:
|
||||
name: Publish on winget repo
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Get download url for release assets
|
||||
id: get-release-assets
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
const query =`query($tag:String!) {
|
||||
repository(owner:"cryptomator", name:"cryptomator"){
|
||||
release(tagName: $tag) {
|
||||
releaseAssets(first:20) {
|
||||
nodes {
|
||||
name
|
||||
downloadUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`;
|
||||
const variables = {
|
||||
tag: "${{ inputs.releaseTag }}"
|
||||
}
|
||||
return await github.graphql(query, variables)
|
||||
- name: Submit package to Windows Package Manager Community Repository
|
||||
id: submit-winget
|
||||
run: |
|
||||
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
|
||||
$releaseAssets = (ConvertFrom-Json '${{ steps.get-release-assets.outputs.result }}').repository.release.releaseAssets.nodes
|
||||
$installerUrl = $releaseAssets | Where-Object -Property name -match '^Cryptomator-.*\.msi$' | Select -ExpandProperty downloadUrl -First 1
|
||||
.\wingetcreate.exe update Cryptomator.Cryptomator -s -v "${{ inputs.releaseTag }}" -u "$installerUrl" -t ${{ secrets.CRYPTOBOT_WINGET_TOKEN }}
|
||||
shell: pwsh
|
||||
Generated
+6
-4
@@ -14,10 +14,10 @@
|
||||
<option name="dagger.fastInit" value="enabled" />
|
||||
<option name="dagger.formatGeneratedSource" value="enabled" />
|
||||
<processorPath useClasspath="false">
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-compiler/2.44/dagger-compiler-2.44.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger/2.44/dagger-2.44.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-compiler/2.45/dagger-compiler-2.45.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger/2.45/dagger-2.45.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/javax/inject/javax.inject/1/javax.inject-1.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-producers/2.44/dagger-producers-2.44.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-producers/2.45/dagger-producers-2.45.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/guava/guava/31.0.1-jre/guava-31.0.1-jre.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar" />
|
||||
@@ -26,14 +26,16 @@
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/errorprone/error_prone_annotations/2.7.1/error_prone_annotations-2.7.1.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/j2objc/j2objc-annotations/1.3/j2objc-annotations-1.3.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/checkerframework/checker-compat-qual/2.5.5/checker-compat-qual-2.5.5.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-spi/2.44/dagger-spi-2.44.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-spi/2.45/dagger-spi-2.45.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/devtools/ksp/symbol-processing-api/1.7.0-1.0.6/symbol-processing-api-1.7.0-1.0.6.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.7.0/kotlin-stdlib-1.7.0.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-common/1.7.0/kotlin-stdlib-common-1.7.0.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/squareup/javapoet/1.13.0/javapoet-1.13.0.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/squareup/kotlinpoet/1.11.0/kotlinpoet-1.11.0.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.7.0/kotlin-stdlib-jdk8-1.7.0.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.7.0/kotlin-stdlib-jdk7-1.7.0.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-reflect/1.6.10/kotlin-reflect-1.6.10.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/googlejavaformat/google-java-format/1.5/google-java-format-1.5.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/errorprone/javac-shaded/9-dev-r4023-3/javac-shaded-9-dev-r4023-3.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/net/ltgt/gradle/incap/incap/0.2/incap-0.2.jar" />
|
||||
|
||||
@@ -21,7 +21,6 @@ Cryptomator is provided free of charge as an open-source project despite the hig
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a href="https://www.gee-whiz.de/"><img src="https://cryptomator.org/img/sponsors/geewhiz.svg" alt="gee-whiz" height="80"></a></td>
|
||||
<td><a href="https://proxy-hub.com/"><img src="https://cryptomator.org/img/sponsors/proxyhub.svg" alt="Proxy-Hub" height="80"></a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -33,6 +32,7 @@ Cryptomator is provided free of charge as an open-source project despite the hig
|
||||
<tr>
|
||||
<td><a href="https://mowcapital.com/"><img src="https://cryptomator.org/img/sponsors/mowcapital.svg" alt="Mow Capital" height="40"></a></td>
|
||||
<td><a href="https://www.easeus.com/"><img src="https://cryptomator.org/img/sponsors/easeus.png" alt="EaseUS" height="40"></a></td>
|
||||
<td><a href="https://www.hassmann-it-forensik.de/"><img src="https://cryptomator.org/img/sponsors/hassmannitforensik.png" alt="Hassmann IT-Forensik" height="40"></a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -73,7 +73,7 @@ Download native binaries of Cryptomator on [cryptomator.org](https://cryptomator
|
||||
|
||||
### Consistency
|
||||
|
||||
- HMAC over file contents to recognize changed ciphertext before decryption
|
||||
- Authenticated encryption is used for file content to recognize changed ciphertext before decryption
|
||||
- I/O operations are transactional and atomic, if the filesystems support it
|
||||
- Each file contains all information needed for decryption (except for the key of course), no common metadata means no [SPOF](http://en.wikipedia.org/wiki/Single_point_of_failure)
|
||||
|
||||
|
||||
Vendored
+19
-14
@@ -11,15 +11,20 @@ command -v curl >/dev/null 2>&1 || { echo >&2 "curl not found."; exit 1; }
|
||||
VERSION=$(mvn -f ../../../pom.xml help:evaluate -Dexpression=project.version -q -DforceStdout)
|
||||
SEMVER_STR=${VERSION}
|
||||
|
||||
mvn -f ../../../pom.xml versions:set -DnewVersion=${SEMVER_STR}
|
||||
|
||||
# compile
|
||||
mvn -B -f ../../../pom.xml clean package -DskipTests -Plinux
|
||||
mvn -B -f ../../../pom.xml clean package -Plinux -DskipTests
|
||||
cp ../../../LICENSE.txt ../../../target
|
||||
cp ../launcher.sh ../../../target
|
||||
cp ../../../target/cryptomator-*.jar ../../../target/mods
|
||||
|
||||
# add runtime
|
||||
${JAVA_HOME}/bin/jlink \
|
||||
--verbose \
|
||||
--output runtime \
|
||||
--module-path "${JAVA_HOME}/jmods" \
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr \
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.security.auth,jdk.accessibility,jdk.management.jfr,jdk.zipfs \
|
||||
--strip-native-commands \
|
||||
--no-header-files \
|
||||
--no-man-pages \
|
||||
@@ -27,7 +32,7 @@ ${JAVA_HOME}/bin/jlink \
|
||||
--compress=1
|
||||
|
||||
# create app dir
|
||||
envsubst '${SEMVER_STR} ${REVISION_NUM}' < dist/linux/launcher-gtk2.properties > launcher-gtk2.properties
|
||||
envsubst '${SEMVER_STR} ${REVISION_NUM}' < ../launcher-gtk2.properties > launcher-gtk2.properties
|
||||
${JAVA_HOME}/bin/jpackage \
|
||||
--verbose \
|
||||
--type app-image \
|
||||
@@ -35,12 +40,12 @@ ${JAVA_HOME}/bin/jpackage \
|
||||
--input ../../../target/libs \
|
||||
--module-path ../../../target/mods \
|
||||
--module org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator \
|
||||
--dest . \
|
||||
--dest appdir \
|
||||
--name Cryptomator \
|
||||
--vendor "Skymatic GmbH" \
|
||||
--copyright "(C) 2016 - 2022 Skymatic GmbH" \
|
||||
--java-options "--enable-preview" \
|
||||
--java-options "--enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64" \
|
||||
--copyright "(C) 2016 - 2023 Skymatic GmbH" \
|
||||
--java-options "-Xss5m" \
|
||||
--java-options "-Xmx256m" \
|
||||
--app-version "${VERSION}.${REVISION_NO}" \
|
||||
@@ -48,6 +53,7 @@ ${JAVA_HOME}/bin/jpackage \
|
||||
--java-options "-Dcryptomator.logDir=\"~/.local/share/Cryptomator/logs\"" \
|
||||
--java-options "-Dcryptomator.pluginDir=\"~/.local/share/Cryptomator/plugins\"" \
|
||||
--java-options "-Dcryptomator.settingsPath=\"~/.config/Cryptomator/settings.json:~/.Cryptomator/settings.json\"" \
|
||||
--java-options "-Dcryptomator.p12Path=\"~/.config/Cryptomator/key.p12\"" \
|
||||
--java-options "-Dcryptomator.ipcSocketPath=\"~/.config/Cryptomator/ipc.socket\"" \
|
||||
--java-options "-Dcryptomator.mountPointsDir=\"~/.local/share/Cryptomator/mnt\"" \
|
||||
--java-options "-Dcryptomator.showTrayIcon=false" \
|
||||
@@ -56,9 +62,8 @@ ${JAVA_HOME}/bin/jpackage \
|
||||
--resource-dir ../resources
|
||||
|
||||
# transform AppDir
|
||||
mv Cryptomator Cryptomator.AppDir
|
||||
mv appdir/Cryptomator Cryptomator.AppDir
|
||||
cp -r resources/AppDir/* Cryptomator.AppDir/
|
||||
chmod +x Cryptomator.AppDir/lib/runtime/bin/java
|
||||
envsubst '${REVISION_NO}' < resources/AppDir/bin/cryptomator.sh > Cryptomator.AppDir/bin/cryptomator.sh
|
||||
cp ../common/org.cryptomator.Cryptomator256.png Cryptomator.AppDir/usr/share/icons/hicolor/256x256/apps/org.cryptomator.Cryptomator.png
|
||||
cp ../common/org.cryptomator.Cryptomator512.png Cryptomator.AppDir/usr/share/icons/hicolor/512x512/apps/org.cryptomator.Cryptomator.png
|
||||
@@ -72,12 +77,6 @@ ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryp
|
||||
ln -s usr/share/applications/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/Cryptomator.desktop
|
||||
ln -s bin/cryptomator.sh Cryptomator.AppDir/AppRun
|
||||
|
||||
# extract jffi
|
||||
JFFI_NATIVE_JAR=`ls Cryptomator.AppDir/lib/app | grep -e 'jffi-[1-9]\.[0-9]\{1,2\}.[0-9]\{1,2\}-native.jar'`
|
||||
${JAVA_HOME}/bin/jar -xf Cryptomator.AppDir/lib/app/${JFFI_NATIVE_JAR} /jni/x86_64-Linux/
|
||||
mv jni/x86_64-Linux/* Cryptomator.AppDir/lib/app/libjffi.so
|
||||
rm -r jni/x86_64-Linux
|
||||
|
||||
# load AppImageTool
|
||||
curl -L https://github.com/AppImage/AppImageKit/releases/download/13/appimagetool-x86_64.AppImage -o /tmp/appimagetool.AppImage
|
||||
chmod +x /tmp/appimagetool.AppImage
|
||||
@@ -85,5 +84,11 @@ chmod +x /tmp/appimagetool.AppImage
|
||||
# create AppImage
|
||||
/tmp/appimagetool.AppImage \
|
||||
Cryptomator.AppDir \
|
||||
cryptomator-SNAPSHOT-x86_64.AppImage \
|
||||
cryptomator-${SEMVER_STR}-x86_64.AppImage \
|
||||
-u 'gh-releases-zsync|cryptomator|cryptomator|latest|cryptomator-*-x86_64.AppImage.zsync'
|
||||
|
||||
echo ""
|
||||
echo "Done. AppImage successfully created: cryptomator-${SEMVER_STR}-x86_64.AppImage"
|
||||
echo ""
|
||||
echo >&2 "To clean up, run: rm -rf Cryptomator.AppDir appdir jni runtime squashfs-root; rm launcher-gtk2.properties /tmp/appimagetool.AppImage"
|
||||
echo ""
|
||||
@@ -15,9 +15,6 @@ elif command -v pacman &> /dev/null; then # don't forget arch
|
||||
GTK3_PRESENT=`pacman -Qi gtk3 &> /dev/null; echo $?`
|
||||
fi
|
||||
|
||||
# workaround for https://github.com/cryptomator/cryptomator-linux/issues/27
|
||||
export LD_PRELOAD=lib/app/libjffi.so
|
||||
|
||||
if [ "$GTK2_PRESENT" -eq 0 ] && [ "$GTK3_PRESENT" -ne 0 ]; then
|
||||
bin/Cryptomator-gtk2 $@
|
||||
else
|
||||
|
||||
@@ -66,6 +66,14 @@
|
||||
</content_rating>
|
||||
|
||||
<releases>
|
||||
<release date="2023-04-25" version="1.8.0"/>
|
||||
<release date="2023-04-07" version="1.7.5"/>
|
||||
<release date="2023-04-05" version="1.7.4"/>
|
||||
<release date="2023-03-15" version="1.7.3"/>
|
||||
<release date="2023-03-07" version="1.7.2"/>
|
||||
<release date="2023-03-03" version="1.7.1"/>
|
||||
<release date="2023-03-01" version="1.7.0"/>
|
||||
<release date="2022-12-14" version="1.6.17"/>
|
||||
<release date="2022-12-06" version="1.6.16"/>
|
||||
<release date="2022-10-06" version="1.6.15"/>
|
||||
<release date="2022-08-31" version="1.6.14"/>
|
||||
|
||||
Vendored
+1
-1
@@ -12,7 +12,7 @@ Package: cryptomator
|
||||
Architecture: any
|
||||
Section: utils
|
||||
Priority: optional
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, libfuse2, xdg-utils, libjffi-jni
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, fuse3
|
||||
Recommends: gvfs-backends, gvfs-fuse, gnome-keyring
|
||||
XB-AppName: Cryptomator
|
||||
XB-Category: Utility;Security;FileTools;
|
||||
|
||||
Vendored
+2
-2
@@ -4,11 +4,11 @@ Upstream-Contact: Cryptomator <info@cryptomator.org>
|
||||
Source: https://cryptomator.org
|
||||
|
||||
Files: *
|
||||
Copyright: 2016-2022 Skymatic GmbH
|
||||
Copyright: 2016-2023 Skymatic GmbH
|
||||
License: GPL-3+
|
||||
|
||||
Files: debian/org.cryptomator.Cryptomator.appdata.xml
|
||||
Copyright: 2016-2022 Skymatic GmbH
|
||||
Copyright: 2016-2023 Skymatic GmbH
|
||||
License: FSFAP
|
||||
|
||||
License: GPL-3+
|
||||
|
||||
-1
@@ -1,5 +1,4 @@
|
||||
cryptomator usr/lib
|
||||
debian/cryptomator.sh usr/lib/cryptomator/bin
|
||||
common/org.cryptomator.Cryptomator.desktop usr/share/applications
|
||||
common/org.cryptomator.Cryptomator.svg usr/share/icons/hicolor/scalable/apps
|
||||
common/org.cryptomator.Cryptomator256.png usr/share/icons/hicolor/256x256/apps
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
usr/lib/cryptomator/bin/cryptomator.sh usr/bin/cryptomator
|
||||
usr/lib/cryptomator/bin/cryptomator usr/bin/cryptomator
|
||||
|
||||
Vendored
-6
@@ -1,6 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# fix for https://github.com/cryptomator/cryptomator/issues/1370
|
||||
export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/jni/libjffi-1.2.so
|
||||
|
||||
/usr/lib/cryptomator/bin/cryptomator $@
|
||||
Vendored
+2
-9
@@ -27,7 +27,7 @@ override_dh_auto_build:
|
||||
$(JAVA_HOME)/bin/jlink \
|
||||
--output runtime \
|
||||
--module-path "${JMODS_PATH}" \
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr \
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.security.auth,jdk.accessibility,jdk.management.jfr,jdk.zipfs \
|
||||
--strip-native-commands \
|
||||
--no-header-files \
|
||||
--no-man-pages \
|
||||
@@ -42,9 +42,9 @@ override_dh_auto_build:
|
||||
--dest . \
|
||||
--name cryptomator \
|
||||
--vendor "Skymatic GmbH" \
|
||||
--copyright "(C) 2016 - 2022 Skymatic GmbH" \
|
||||
--java-options "--enable-preview" \
|
||||
--java-options "--enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64" \
|
||||
--copyright "(C) 2016 - 2023 Skymatic GmbH" \
|
||||
--java-options "-Xss5m" \
|
||||
--java-options "-Xmx256m" \
|
||||
--java-options "-Dfile.encoding=\"utf-8\"" \
|
||||
@@ -60,10 +60,3 @@ override_dh_auto_build:
|
||||
--app-version "${VERSION_NUM}.${REVISION_NUM}" \
|
||||
--resource-dir resources \
|
||||
--verbose
|
||||
|
||||
override_dh_fixperms:
|
||||
dh_fixperms
|
||||
chmod +x debian/cryptomator/usr/lib/cryptomator/bin/cryptomator.sh
|
||||
|
||||
# override_dh_strip:
|
||||
# no-op
|
||||
|
||||
Vendored
-15
@@ -1,15 +0,0 @@
|
||||
#!/bin/sh
|
||||
cd $(dirname $0)
|
||||
java \
|
||||
-p "mods" \
|
||||
-cp "libs/*" \
|
||||
-Dcryptomator.settingsPath="~/.config/Cryptomator/settings.json" \
|
||||
-Dcryptomator.ipcSocketPath="~/.config/Cryptomator/ipc.socket" \
|
||||
-Dcryptomator.logDir="~/.local/share/Cryptomator/logs" \
|
||||
-Dcryptomator.mountPointsDir="~/.local/share/Cryptomator/mnt" \
|
||||
-Djdk.gtk.version=2 \
|
||||
-Xss2m \
|
||||
-Xmx512m \
|
||||
--enable-preview \
|
||||
--enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64 \
|
||||
-m org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator
|
||||
Vendored
+8
-6
@@ -21,12 +21,13 @@ rm -rf runtime dmg *.app *.dmg
|
||||
# set variables
|
||||
APP_NAME="Cryptomator"
|
||||
VENDOR="Skymatic GmbH"
|
||||
COPYRIGHT_YEARS="2016 - 2022"
|
||||
COPYRIGHT_YEARS="2016 - 2023"
|
||||
PACKAGE_IDENTIFIER="org.cryptomator"
|
||||
MAIN_JAR_GLOB="cryptomator-*.jar"
|
||||
MODULE_AND_MAIN_CLASS="org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator"
|
||||
REVISION_NO=`git rev-list --count HEAD`
|
||||
VERSION_NO=`mvn -f../../../pom.xml help:evaluate -Dexpression=project.version -q -DforceStdout | sed -rn 's/.*([0-9]+\.[0-9]+\.[0-9]+).*/\1/p'`
|
||||
FUSE_LIB="FUSE-T"
|
||||
|
||||
# check preconditions
|
||||
if [ -z "${JAVA_HOME}" ]; then echo "JAVA_HOME not set. Run using JAVA_HOME=/path/to/jdk ./build.sh"; exit 1; fi
|
||||
@@ -45,7 +46,7 @@ cp ../../../target/${MAIN_JAR_GLOB} ../../../target/mods
|
||||
${JAVA_HOME}/bin/jlink \
|
||||
--output runtime \
|
||||
--module-path "${JAVA_HOME}/jmods" \
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr \
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr,jdk.zipfs \
|
||||
--strip-native-commands \
|
||||
--no-header-files \
|
||||
--no-man-pages \
|
||||
@@ -79,6 +80,7 @@ ${JAVA_HOME}/bin/jpackage \
|
||||
--java-options "-Dcryptomator.ipcSocketPath=\"~/Library/Application Support/${APP_NAME}/ipc.socket\"" \
|
||||
--java-options "-Dcryptomator.p12Path=\"~/Library/Application Support/${APP_NAME}/key.p12\"" \
|
||||
--java-options "-Dcryptomator.integrationsMac.keychainServiceName=\"${APP_NAME}\"" \
|
||||
--java-options "-Dcryptomator.mountPointsDir=\"~/${APP_NAME}\"" \
|
||||
--java-options "-Dcryptomator.showTrayIcon=true" \
|
||||
--java-options "-Dcryptomator.buildNumber=\"dmg-${REVISION_NO}\"" \
|
||||
--mac-package-identifier ${PACKAGE_IDENTIFIER} \
|
||||
@@ -124,20 +126,20 @@ fi
|
||||
# prepare dmg contents
|
||||
mkdir dmg
|
||||
mv ${APP_NAME}.app dmg
|
||||
cp resources/macFUSE.webloc dmg
|
||||
cp resources/${FUSE_LIB}.webloc dmg
|
||||
|
||||
# create dmg
|
||||
create-dmg \
|
||||
--volname ${APP_NAME} \
|
||||
--volicon "resources/${APP_NAME}-Volume.icns" \
|
||||
--background "resources/${APP_NAME}-background.tiff" \
|
||||
--background "resources/${APP_NAME}-${FUSE_LIB}-background.tiff" \
|
||||
--window-pos 400 100 \
|
||||
--window-size 640 694 \
|
||||
--icon-size 128 \
|
||||
--icon "${APP_NAME}.app" 128 245 \
|
||||
--hide-extension "${APP_NAME}.app" \
|
||||
--icon "macFUSE.webloc" 320 501 \
|
||||
--hide-extension "macFUSE.webloc" \
|
||||
--icon "${FUSE_LIB}.webloc" 320 501 \
|
||||
--hide-extension "${FUSE_LIB}.webloc" \
|
||||
--app-drop-link 512 245 \
|
||||
--eula "resources/license.rtf" \
|
||||
--icon ".background" 128 758 \
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>URL</key>
|
||||
<string>https://www.fuse-t.org/</string>
|
||||
</dict>
|
||||
</plist>
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
\f1\b0 \
|
||||
\
|
||||
|
||||
\f0\b \'a9 2016 \'96 2022 Skymatic GmbH
|
||||
\f0\b \'a9 2016 \'96 2023 Skymatic GmbH
|
||||
\f1\b0 \
|
||||
\
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\
|
||||
|
||||
Vendored
-14
@@ -1,14 +0,0 @@
|
||||
#!/bin/sh
|
||||
cd $(dirname $0)
|
||||
java \
|
||||
-p "mods" \
|
||||
-cp "libs/*" \
|
||||
-Dcryptomator.settingsPath="~/Library/Application Support/Cryptomator/settings.json" \
|
||||
-Dcryptomator.ipcSocketPath="~/Library/Application Support/Cryptomator/ipc.socket" \
|
||||
-Dcryptomator.logDir="~/Library/Logs/Cryptomator" \
|
||||
-Dcryptomator.mountPointsDir="/Volumes" \
|
||||
-Xss20m \
|
||||
-Xmx512m \
|
||||
--enable-preview \
|
||||
--enable-native-access=org.cryptomator.jfuse.mac \
|
||||
-m org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator
|
||||
Vendored
+5
-5
@@ -51,7 +51,7 @@ if ($clean -and (Test-Path -Path $runtimeImagePath)) {
|
||||
--verbose `
|
||||
--output runtime `
|
||||
--module-path "$Env:JAVA_HOME/jmods" `
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr `
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr,jdk.zipfs `
|
||||
--strip-native-commands `
|
||||
--no-header-files `
|
||||
--no-man-pages `
|
||||
@@ -129,7 +129,7 @@ $Env:JP_WIXWIZARD_RESOURCES = "$buildDir\resources"
|
||||
--name $AppName `
|
||||
--vendor $Vendor `
|
||||
--copyright $copyright `
|
||||
--app-version "$semVerNo" `
|
||||
--app-version "$semVerNo.$revisionNo" `
|
||||
--win-menu `
|
||||
--win-dir-chooser `
|
||||
--win-shortcut-prompt `
|
||||
@@ -153,7 +153,7 @@ $Env:JP_WIXWIZARD_RESOURCES = "$buildDir\resources"
|
||||
# download Winfsp
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
$ProgressPreference = 'SilentlyContinue' # disables Invoke-WebRequest's progress bar, which slows down downloads to a few bytes/s
|
||||
$winfspMsiUrl= (Select-String -Path ".\bundle\resources\winfsp-download.url" -Pattern 'https:.*').Matches.Value
|
||||
$winfspMsiUrl= (Select-String -Path ".\bundle\resources\winFspMetaData.wxi" -Pattern '<\?define BundledWinFspDownloadLink="(.+)".*?>').Matches.Groups[1].Value
|
||||
Write-Output "Downloading ${winfspMsiUrl}..."
|
||||
Invoke-WebRequest $winfspMsiUrl -OutFile ".\bundle\resources\winfsp.msi" # redirects are followed by default
|
||||
|
||||
@@ -161,11 +161,11 @@ Invoke-WebRequest $winfspMsiUrl -OutFile ".\bundle\resources\winfsp.msi" # redir
|
||||
Copy-Item ".\installer\$AppName-*.msi" -Destination ".\bundle\resources\$AppName.msi"
|
||||
|
||||
# create bundle including winfsp
|
||||
& "$env:WIX\bin\candle.exe" .\bundle\bundleWithWinfsp.wxs -ext WixBalExtension -out bundle\ `
|
||||
& "$env:WIX\bin\candle.exe" .\bundle\bundleWithWinfsp.wxs -ext WixBalExtension -ext WixUtilextension -out bundle\ `
|
||||
-dBundleVersion="$semVerNo.$revisionNo" `
|
||||
-dBundleVendor="$Vendor" `
|
||||
-dBundleCopyright="$copyright" `
|
||||
-dAboutUrl="$AboutUrl" `
|
||||
-dHelpUrl="$HelpUrl" `
|
||||
-dUpdateUrl="$UpdateUrl"
|
||||
& "$env:WIX\bin\light.exe" -b . .\bundle\BundlewithWinfsp.wixobj -ext WixBalExtension -out installer\$AppName-Installer.exe
|
||||
& "$env:WIX\bin\light.exe" -b . .\bundle\BundlewithWinfsp.wixobj -ext WixBalExtension -ext WixUtilextension -out installer\$AppName-Installer.exe
|
||||
Vendored
+19
-1
@@ -1,13 +1,31 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:bal="http://schemas.microsoft.com/wix/BalExtension">
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:bal="http://schemas.microsoft.com/wix/BalExtension" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
|
||||
<!-- see https://wixtoolset.org/documentation/manual/v3/xsd/wix/bundle.html-->
|
||||
<!-- Attributes explicitly not used:
|
||||
Condition - the single msi files have their own install conditions, no need to copy them here
|
||||
-->
|
||||
|
||||
<Bundle Name="Cryptomator" UpgradeCode="29eea626-2e5b-4449-b5f8-4602925ddf7b" Version="$(var.BundleVersion)" Manufacturer="$(var.BundleVendor)"
|
||||
AboutUrl="$(var.AboutUrl)" HelpUrl="$(var.HelpUrl)" UpdateUrl="$(var.UpdateUrl)" Copyright="$(var.BundleCopyright)" IconSourceFile="bundle\resources\Cryptomator.ico">
|
||||
|
||||
<!-- detect outdated WinFsp installations -->
|
||||
<?include "resources\winFspMetaData.wxi" ?>
|
||||
<util:ProductSearch
|
||||
Variable="InstalledWinFspVersion"
|
||||
Result="version"
|
||||
UpgradeCode="82F812D9-4083-4EF1-8BC8-0F1EDA05B46B"
|
||||
/>
|
||||
<!-- Note: The bundle engine takes the Message format literaly -->
|
||||
<bal:Condition Message=
|
||||
"The WinFsp driver used by Cryptomator is outdated and must be removed before the installation.
|
||||
|
||||
1. Open the view of installed apps
|
||||
2. Search for "WinFsp"
|
||||
3. Uninstall the listed application
|
||||
4. Reboot your device
|
||||
5. Restart this installer">(InstalledWinFspVersion = v0.0.0.0) OR ($(var.BundledWinFspVersion) <= InstalledWinFspVersion)</bal:Condition>
|
||||
|
||||
<!-- for definition of the standard themes, see https://github.com/wixtoolset/wix3/blob/master/src/ext/BalExtension/wixstdba/Resources/-->
|
||||
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLargeLicense">
|
||||
<!-- see https://wixtoolset.org/documentation/manual/v3/xsd/bal/wixstandardbootstrapperapplication.html -->
|
||||
|
||||
+2
-1
@@ -10,6 +10,7 @@
|
||||
<Font Id="2" Height="-22" Weight="500" Foreground="666666">Segoe UI</Font>
|
||||
<Font Id="3" Height="-12" Weight="500" Foreground="000000" Background="FFFFFF">Segoe UI</Font>
|
||||
<Font Id="4" Height="-12" Weight="500" Foreground="ff0000" Background="FFFFFF" Underline="yes">Segoe UI</Font>
|
||||
<Font Id="5" Height="-12" Weight="700" Foreground="000000" Background="FFFFFF">Segoe UI</Font>
|
||||
|
||||
<Image X="11" Y="11" Width="64" Height="64" ImageFile="logo.png" />
|
||||
<Text X="80" Y="11" Width="-11" Height="64" FontId="1" DisablePrefix="yes">#(loc.Title)</Text>
|
||||
@@ -82,7 +83,7 @@
|
||||
<Text Name="FailureUninstallHeader" X="185" Y="50" Width="-11" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureUninstallHeader)</Text>
|
||||
<Text Name="FailureRepairHeader" X="185" Y="50" Width="-11" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureRepairHeader)</Text>
|
||||
<Hypertext Name="FailureLogFileLink" X="185" Y="121" Width="-11" Height="68" FontId="3" TabStop="yes" HideWhenDisabled="yes">#(loc.FailureHyperlinkLogText)</Hypertext>
|
||||
<Hypertext Name="FailureMessageText" X="185" Y="-115" Width="-11" Height="80" FontId="3" TabStop="yes" HideWhenDisabled="yes" />
|
||||
<Hypertext Name="FailureMessageText" X="185" Y="-80" Width="-11" Height="140" FontId="5" TabStop="yes" HideWhenDisabled="yes" />
|
||||
<Text Name="FailureRestartText" X="185" Y="-57" Width="-11" Height="80" FontId="3" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureRestartText)</Text>
|
||||
<Button Name="FailureRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.FailureRestartButton)</Button>
|
||||
<Button Name="FailureCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.FailureCloseButton)</Button>
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
\vieww12000\viewh15840\viewkind0
|
||||
\pard\tx283\tx567\tx850\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\b\fs16\lang7 Cryptomator is distributed under the GPLv3 License, found below. Please see the bottom of this document for any other license applicable to code used within Cryptomator.\b0\par
|
||||
\par
|
||||
\b\'a9 2016 \'96 2022 Skymatic GmbH \b0\par
|
||||
\b\'a9 2016 \'96 2023 Skymatic GmbH \b0\par
|
||||
\par
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\par
|
||||
\par
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<Include xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<!-- A version number MUST be prefixed with letter "v", otherwise it is considered a normal string -->
|
||||
<?define BundledWinFspVersion="v1.12.22339" ?>
|
||||
<?define BundledWinFspDownloadLink="https://github.com/winfsp/winfsp/releases/download/v1.12.22339/winfsp-1.12.22339.msi" ?> <!-- Only used by external build scripts -->
|
||||
</Include>
|
||||
@@ -1,2 +0,0 @@
|
||||
[InternetShortcut]
|
||||
URL=https://github.com/winfsp/winfsp/releases/download/v1.12/winfsp-1.12.22301.msi
|
||||
Vendored
-12
@@ -1,12 +0,0 @@
|
||||
@echo off
|
||||
java ^
|
||||
-p "app/mods" ^
|
||||
-cp "app/*" ^
|
||||
-Dcryptomator.settingsPath="~/AppData/Roaming/Cryptomator/settings.json" ^
|
||||
-Dcryptomator.ipcSocketPath="~/AppData/Roaming/Cryptomator/ipc.socket" ^
|
||||
-Dcryptomator.logDir="~/AppData/Roaming/Cryptomator" ^
|
||||
-Dcryptomator.mountPointsDir="~/Cryptomator" ^
|
||||
-Dcryptomator.keychainPath="~/AppData/Roaming/Cryptomator/keychain.json" ^
|
||||
-Xss20m ^
|
||||
-Xmx512m ^
|
||||
-m org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator
|
||||
@@ -0,0 +1,5 @@
|
||||
@echo off
|
||||
:: see comments in file ./version170-migrate-settings.ps1
|
||||
|
||||
cd %~dp0
|
||||
powershell -NoLogo -NonInteractive -ExecutionPolicy Unrestricted -Command .\version170-migrate-settings.ps1
|
||||
@@ -0,0 +1,35 @@
|
||||
# This script migrates Cryptomator settings for all local users on Windows in case the users uses custom directories as mountpoint
|
||||
# See also https://github.com/cryptomator/cryptomator/pull/2654.
|
||||
#
|
||||
# TODO: This script should be evaluated in a yearly interval if it is still needed and if not, should be removed
|
||||
#
|
||||
#Requires -RunAsAdministrator
|
||||
|
||||
#Get all active, local user profiles
|
||||
$profileList = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList'
|
||||
Get-ChildItem $profileList | ForEach-Object {
|
||||
$profilePath = $_.GetValue("ProfileImagePath")
|
||||
$settingsPath = "$profilePath\AppData\Roaming\Cryptomator\settings.json"
|
||||
if(!(Test-Path -Path $settingsPath -PathType Leaf)) {
|
||||
#No settings file, nothing to do.
|
||||
return;
|
||||
}
|
||||
$settings = Get-Content -Path $settingsPath | ConvertFrom-Json
|
||||
if($settings.preferredVolumeImpl -ne "FUSE") {
|
||||
#Fuse not used, nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
#check if customMountPoints are used
|
||||
$atLeastOneCustomPath = $false;
|
||||
foreach ($vault in $settings.directories){
|
||||
$atLeastOneCustomPath = $atLeastOneCustomPath -or ($vault.useCustomMountPath -eq "True")
|
||||
}
|
||||
|
||||
#if so, use WinFsp Local Drive
|
||||
if( $atLeastOneCustomPath ) {
|
||||
Add-Member -Force -InputObject $settings -Name "mountService" -Value "org.cryptomator.frontend.fuse.mount.WinFspMountProvider" -MemberType NoteProperty
|
||||
$newSettings = $settings | Select-Object * -ExcludeProperty "preferredVolumeImpl"
|
||||
ConvertTo-Json $newSettings | Set-Content -Path $settingsPath
|
||||
}
|
||||
}
|
||||
Vendored
+2
-5
@@ -65,13 +65,10 @@
|
||||
<Control Id="Title" Type="Text" X="135" Y="20" Width="220" Height="60" Transparent="yes" NoPrefix="yes" Text="!(loc.ExitDialogTitle)" />
|
||||
<!-- TODO: localize? -->
|
||||
<Control Id="Suggestion" Type="Text" X="135" Y="100" Width="220" Height="60" Transparent="yes" NoPrefix="yes">
|
||||
<Text>We recommend for the best user experience to download and install one of the following third party Windows drivers:</Text>
|
||||
<Text>We recommend for the best user experience to download and install the following third party Windows driver:</Text>
|
||||
</Control>
|
||||
<Control Id="WinFsp" Type="Hyperlink" X="140" Y="125" Width="220" Height="60" Transparent="yes">
|
||||
<Text><![CDATA[• WinFsp (<a href="http://www.secfs.net/winfsp/rel/">Homepage</a>)]]></Text>
|
||||
</Control>
|
||||
<Control Id="Dokany" Type="Hyperlink" X="140" Y="137" Width="220" Height="60" Transparent="yes">
|
||||
<Text><![CDATA[• Dokany (<a href="https://dokan-dev.github.io/">Homepage</a>)]]></Text>
|
||||
<Text><![CDATA[WinFsp (<a href="https://winfsp.dev/">Homepage</a>)]]></Text>
|
||||
</Control>
|
||||
</Dialog>
|
||||
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
\vieww12000\viewh15840\viewkind0
|
||||
\pard\tx283\tx567\tx850\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\b\fs16\lang7 Cryptomator is distributed under the GPLv3 License, found below. Please see the bottom of this document for any other license applicable to code used within Cryptomator.\b0\par
|
||||
\par
|
||||
\b\'a9 2016 \'96 2022 Skymatic GmbH \b0\par
|
||||
\b\'a9 2016 \'96 2023 Skymatic GmbH \b0\par
|
||||
\par
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\par
|
||||
\par
|
||||
|
||||
Vendored
+8
-4
@@ -54,7 +54,7 @@
|
||||
Property="JP_UPGRADABLE_FOUND"
|
||||
Maximum="$(var.JpAppVersion)"
|
||||
MigrateFeatures="yes"
|
||||
IncludeMaximum="$(var.JpUpgradeVersionOnlyDetectUpgrade)" />
|
||||
IncludeMaximum="yes" /> <!-- TODO: check if this needs to be set to yes-->
|
||||
<UpgradeVersion
|
||||
OnlyDetect="$(var.JpUpgradeVersionOnlyDetectDowngrade)"
|
||||
Property="JP_DOWNGRADABLE_FOUND"
|
||||
@@ -132,6 +132,9 @@
|
||||
<!-- WebDAV patches -->
|
||||
<CustomAction Id="PatchWebDAV" Impersonate="no" ExeCommand="[INSTALLDIR]patchWebDAV.bat" Directory="INSTALLDIR" Execute="deferred" Return="asyncWait" />
|
||||
|
||||
<!-- Special Settings migration for 1.7.0,. Should be removed eventually, for more info, see ../contrib/version170-migrate-settings.ps1-->
|
||||
<CustomAction Id="V170MigrateSettings" Impersonate="no" ExeCommand="[INSTALLDIR]version170-migrate-settings.bat" Directory="INSTALLDIR" Execute="deferred" Return="asyncWait" />
|
||||
|
||||
<!-- Running App detection and exit -->
|
||||
<Property Id="FOUNDRUNNINGAPP" Admin="yes"/>
|
||||
<util:CloseApplication
|
||||
@@ -140,11 +143,11 @@
|
||||
CloseMessage="no"
|
||||
RebootPrompt="no"
|
||||
PromptToContinue="yes"
|
||||
Description="A running instance of $(var.JpAppName) is found. Please close it to continue."
|
||||
Description="A running instance of $(var.JpAppName) is found, using files marked for update. Please close it to continue."
|
||||
Property="FOUNDRUNNINGAPP"
|
||||
>
|
||||
</util:CloseApplication>
|
||||
<CustomAction Id="FailOnRunningApp" Impersonate="no" ExeCommand="[SystemFolder]\cmd.exe /c "exit 1"" Directory="INSTALLDIR" Execute="immediate" Return="check" />
|
||||
<CustomAction Id="FailOnRunningApp" Error="Installation aborted, because files marked for update are used by a running instance of $(var.JpAppName)."/>
|
||||
|
||||
<?ifdef JpIcon ?>
|
||||
<Property Id="ARPPRODUCTICON" Value="JpARPPRODUCTICON"/>
|
||||
@@ -179,9 +182,10 @@
|
||||
<Custom Action="WixCloseApplications" Before="InstallValidate"></Custom>
|
||||
<Custom Action="FailOnRunningApp" After="WixCloseApplications" >FOUNDRUNNINGAPP</Custom>
|
||||
|
||||
<RemoveExistingProducts After="InstallValidate"/>
|
||||
<RemoveExistingProducts After="InstallValidate"/> <!-- Moved from CostInitialize, due to WixCloseApplications -->
|
||||
|
||||
<Custom Action="PatchWebDAV" After="InstallFiles">NOT Installed OR REINSTALL</Custom>
|
||||
<Custom Action="V170MigrateSettings" After="InstallFiles">NOT Installed OR REINSTALL</Custom>
|
||||
</InstallExecuteSequence>
|
||||
|
||||
<WixVariable Id="WixUIBannerBmp" Value="$(env.JP_WIXWIZARD_RESOURCES)\banner.bmp" />
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>cryptomator</artifactId>
|
||||
<version>1.7.0</version>
|
||||
<version>1.9.0-SNAPSHOT</version>
|
||||
<name>Cryptomator Desktop App</name>
|
||||
|
||||
<organization>
|
||||
@@ -17,6 +17,11 @@
|
||||
<email>sebastian.stenzel@gmail.com</email>
|
||||
<timezone>+1</timezone>
|
||||
</developer>
|
||||
<developer>
|
||||
<name>Armin Schrenk</name>
|
||||
<email>armin.schrenk+dev@mailbox.org</email>
|
||||
<timezone>+1</timezone>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<properties>
|
||||
@@ -24,41 +29,41 @@
|
||||
<project.jdk.version>19</project.jdk.version>
|
||||
|
||||
<!-- Group IDs of jars that need to stay on the class path for now -->
|
||||
<!-- Check progress on https://github.com/swiesend/secret-service/issues/31 to remove hypfvieh, swiesend and jnr -->
|
||||
<nonModularGroupIds>com.github.jnr,org.ow2.asm,org.apache.jackrabbit,org.apache.httpcomponents,de.swiesend,org.purejava,com.github.hypfvieh</nonModularGroupIds>
|
||||
<!-- Once hypfvieh, swiesend, purejava and integrations-linux have module-info, remove them-->
|
||||
<nonModularGroupIds>org.ow2.asm,org.apache.jackrabbit,org.apache.httpcomponents,de.swiesend,org.purejava,com.github.hypfvieh</nonModularGroupIds>
|
||||
|
||||
<!-- cryptomator dependencies -->
|
||||
<cryptomator.cryptofs.version>2.5.3</cryptomator.cryptofs.version>
|
||||
<cryptomator.integrations.version>1.2.0-beta2</cryptomator.integrations.version>
|
||||
<cryptomator.integrations.win.version>1.1.2</cryptomator.integrations.win.version>
|
||||
<cryptomator.integrations.mac.version>1.1.2</cryptomator.integrations.mac.version>
|
||||
<cryptomator.integrations.linux.version>1.1.0</cryptomator.integrations.linux.version>
|
||||
<cryptomator.fuse.version>2.0.0-beta2</cryptomator.fuse.version>
|
||||
<cryptomator.dokany.version>2.0.0-beta1</cryptomator.dokany.version>
|
||||
<cryptomator.webdav.version>2.0.0-beta1</cryptomator.webdav.version>
|
||||
<cryptomator.cryptofs.version>2.6.2</cryptomator.cryptofs.version>
|
||||
<cryptomator.integrations.version>1.2.0</cryptomator.integrations.version>
|
||||
<cryptomator.integrations.win.version>1.2.0</cryptomator.integrations.win.version>
|
||||
<cryptomator.integrations.mac.version>1.2.0</cryptomator.integrations.mac.version>
|
||||
<cryptomator.integrations.linux.version>1.2.0</cryptomator.integrations.linux.version>
|
||||
<cryptomator.fuse.version>2.0.5</cryptomator.fuse.version>
|
||||
<cryptomator.dokany.version>2.0.0</cryptomator.dokany.version>
|
||||
<cryptomator.webdav.version>2.0.2</cryptomator.webdav.version>
|
||||
|
||||
<!-- 3rd party dependencies -->
|
||||
<commons-lang3.version>3.12.0</commons-lang3.version>
|
||||
<dagger.version>2.44</dagger.version>
|
||||
<dagger.version>2.45</dagger.version>
|
||||
<easybind.version>2.2</easybind.version>
|
||||
<guava.version>31.1-jre</guava.version>
|
||||
<gson.version>2.9.1</gson.version>
|
||||
<javafx.version>19</javafx.version>
|
||||
<jwt.version>4.2.1</jwt.version>
|
||||
<nimbus-jose.version>9.25.4</nimbus-jose.version>
|
||||
<logback.version>1.4.4</logback.version>
|
||||
<slf4j.version>2.0.3</slf4j.version>
|
||||
<gson.version>2.10.1</gson.version>
|
||||
<javafx.version>19.0.2.1</javafx.version>
|
||||
<jwt.version>4.3.0</jwt.version>
|
||||
<nimbus-jose.version>9.31</nimbus-jose.version>
|
||||
<logback.version>1.4.5</logback.version>
|
||||
<slf4j.version>2.0.6</slf4j.version>
|
||||
<tinyoauth2.version>0.5.1</tinyoauth2.version>
|
||||
<zxcvbn.version>1.7.0</zxcvbn.version>
|
||||
|
||||
<!-- test dependencies -->
|
||||
<junit.jupiter.version>5.9.1</junit.jupiter.version>
|
||||
<mockito.version>4.8.0</mockito.version>
|
||||
<junit.jupiter.version>5.9.2</junit.jupiter.version>
|
||||
<mockito.version>5.1.1</mockito.version>
|
||||
<hamcrest.version>2.2</hamcrest.version>
|
||||
|
||||
<!-- build-time dependencies -->
|
||||
<jetbrains.annotations.version>23.0.0</jetbrains.annotations.version>
|
||||
<dependency-check.version>7.4.0</dependency-check.version>
|
||||
<dependency-check.version>8.1.0</dependency-check.version>
|
||||
<jacoco.version>0.8.8</jacoco.version>
|
||||
</properties>
|
||||
|
||||
@@ -312,41 +317,6 @@
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>compile-light-theme</id>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>java</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<mainClass>javafx.graphics/com.sun.javafx.css.parser.Css2Bin</mainClass>
|
||||
<arguments>
|
||||
<arg>${project.basedir}/src/main/resources/css/light_theme.css</arg>
|
||||
<arg>${project.build.outputDirectory}/css/light_theme.bss</arg>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>compile-dark-theme</id>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>java</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<mainClass>javafx.graphics/com.sun.javafx.css.parser.Css2Bin</mainClass>
|
||||
<arguments>
|
||||
<arg>${project.basedir}/src/main/resources/css/dark_theme.css</arg>
|
||||
<arg>${project.build.outputDirectory}/css/dark_theme.bss</arg>
|
||||
</arguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
|
||||
@@ -16,6 +16,7 @@ import org.cryptomator.common.settings.SettingsProvider;
|
||||
import org.cryptomator.common.vaults.VaultComponent;
|
||||
import org.cryptomator.common.vaults.VaultListModule;
|
||||
import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
|
||||
import org.cryptomator.integrations.revealpath.RevealPathService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -26,6 +27,7 @@ import java.net.InetSocketAddress;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Comparator;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
@@ -83,6 +85,13 @@ public abstract class CommonsModule {
|
||||
return new SemVerComparator();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static Optional<RevealPathService> provideRevealPathService() {
|
||||
return RevealPathService.get().findFirst();
|
||||
}
|
||||
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static Settings provideSettings(SettingsProvider settingsProvider) {
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package org.cryptomator.common;
|
||||
|
||||
import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingStrategy;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
public interface Constants {
|
||||
|
||||
String MASTERKEY_FILENAME = "masterkey.cryptomator";
|
||||
@@ -7,6 +11,7 @@ public interface Constants {
|
||||
String VAULTCONFIG_FILENAME = "vault.cryptomator";
|
||||
String CRYPTOMATOR_FILENAME_EXT = ".cryptomator";
|
||||
String CRYPTOMATOR_FILENAME_GLOB = "*.cryptomator";
|
||||
URI DEFAULT_KEY_ID = URI.create(MasterkeyFileLoadingStrategy.SCHEME + ":" + MASTERKEY_FILENAME);
|
||||
byte[] PEPPER = new byte[0];
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.cryptomator.common;
|
||||
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ObservableUtil {
|
||||
|
||||
public static <T, U> ObservableValue<U> mapWithDefault(ObservableValue<T> observable, Function<? super T, ? extends U> mapper, U defaultValue) {
|
||||
return Bindings.createObjectBinding(() -> {
|
||||
if (observable.getValue() == null) {
|
||||
return defaultValue;
|
||||
} else {
|
||||
return mapper.apply(observable.getValue());
|
||||
}
|
||||
}, observable);
|
||||
}
|
||||
|
||||
public static <T, U> ObservableValue<U> mapWithDefault(ObservableValue<T> observable, Function<? super T, ? extends U> mapper, Supplier<U> defaultValue) {
|
||||
return Bindings.createObjectBinding(() -> {
|
||||
if (observable.getValue() == null) {
|
||||
return defaultValue.get();
|
||||
} else {
|
||||
return mapper.apply(observable.getValue());
|
||||
}
|
||||
}, observable);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.cryptomator.common.mount;
|
||||
|
||||
import org.cryptomator.integrations.mount.MountService;
|
||||
|
||||
public record ActualMountService(MountService service, boolean isDesired) {
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.cryptomator.common.mount;
|
||||
|
||||
public class IllegalMountPointException extends IllegalArgumentException {
|
||||
|
||||
public IllegalMountPointException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,16 +2,23 @@ package org.cryptomator.common.mount;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import org.cryptomator.common.ObservableUtil;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.integrations.mount.Mount;
|
||||
import org.cryptomator.integrations.mount.MountService;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@Module
|
||||
public class MountModule {
|
||||
|
||||
private static final AtomicReference<MountService> formerSelectedMountService = new AtomicReference<>(null);
|
||||
private static final List<String> problematicFuseMountServices = List.of("org.cryptomator.frontend.fuse.mount.MacFuseMountProvider", "org.cryptomator.frontend.fuse.mount.FuseTMountProvider");
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static List<MountService> provideSupportedMountServices() {
|
||||
@@ -20,11 +27,46 @@ public class MountModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static ObservableValue<MountService> provideMountService(Settings settings, List<MountService> serviceImpls) {
|
||||
return settings.mountService().map(desiredServiceImpl -> {
|
||||
var fallbackProvider = serviceImpls.stream().findFirst().orElse(null);
|
||||
return serviceImpls.stream().filter(serviceImpl -> serviceImpl.getClass().getName().equals(desiredServiceImpl)).findAny().orElse(fallbackProvider);
|
||||
});
|
||||
@Named("FUPFMS")
|
||||
static AtomicReference<MountService> provideFirstUsedProblematicFuseMountService() {
|
||||
return new AtomicReference<>(null);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static ObservableValue<ActualMountService> provideMountService(Settings settings, List<MountService> serviceImpls, @Named("FUPFMS") AtomicReference<MountService> fupfms) {
|
||||
var fallbackProvider = serviceImpls.stream().findFirst().orElse(null);
|
||||
|
||||
var observableMountService = ObservableUtil.mapWithDefault(settings.mountService(), //
|
||||
desiredServiceImpl -> { //
|
||||
var serviceFromSettings = serviceImpls.stream().filter(serviceImpl -> serviceImpl.getClass().getName().equals(desiredServiceImpl)).findAny(); //
|
||||
var targetedService = serviceFromSettings.orElse(fallbackProvider);
|
||||
return applyWorkaroundForProblematicFuse(targetedService, serviceFromSettings.isPresent(), fupfms);
|
||||
}, //
|
||||
() -> { //
|
||||
return applyWorkaroundForProblematicFuse(fallbackProvider, true, fupfms);
|
||||
});
|
||||
return observableMountService;
|
||||
}
|
||||
|
||||
//see https://github.com/cryptomator/cryptomator/issues/2786
|
||||
private synchronized static ActualMountService applyWorkaroundForProblematicFuse(MountService targetedService, boolean isDesired, AtomicReference<MountService> firstUsedProblematicFuseMountService) {
|
||||
//set the first used problematic fuse service if applicable
|
||||
var targetIsProblematicFuse = isProblematicFuseService(targetedService);
|
||||
if (targetIsProblematicFuse && firstUsedProblematicFuseMountService.get() == null) {
|
||||
firstUsedProblematicFuseMountService.set(targetedService);
|
||||
}
|
||||
|
||||
//do not use the targeted mount service and fallback to former one, if the service is problematic _and_ not the first problematic one used.
|
||||
if (targetIsProblematicFuse && !firstUsedProblematicFuseMountService.get().equals(targetedService)) {
|
||||
return new ActualMountService(formerSelectedMountService.get(), false);
|
||||
} else {
|
||||
formerSelectedMountService.set(targetedService);
|
||||
return new ActualMountService(targetedService, isDesired);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isProblematicFuseService(MountService service) {
|
||||
return problematicFuseMountServices.contains(service.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.cryptomator.common.mount;
|
||||
|
||||
public class MountPointNotExistsException extends IllegalMountPointException {
|
||||
|
||||
public MountPointNotExistsException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.cryptomator.common.mount;
|
||||
|
||||
public class MountPointNotSupportedException extends IllegalMountPointException {
|
||||
|
||||
public MountPointNotSupportedException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.cryptomator.common.mount;
|
||||
|
||||
public class MountPointPreparationException extends RuntimeException {
|
||||
|
||||
public MountPointPreparationException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public MountPointPreparationException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package org.cryptomator.common.mount;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.DirectoryNotEmptyException;
|
||||
import java.nio.file.FileAlreadyExistsException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.LinkOption;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.NotDirectoryException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public final class MountWithinParentUtil {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Mounter.class);
|
||||
private static final String HIDEAWAY_PREFIX = ".~$";
|
||||
private static final String HIDEAWAY_SUFFIX = ".tmp";
|
||||
private static final String WIN_HIDDEN_ATTR = "dos:hidden";
|
||||
|
||||
private MountWithinParentUtil() {}
|
||||
|
||||
static void prepareParentNoMountPoint(Path mountPoint) throws MountPointPreparationException {
|
||||
Path hideaway = getHideaway(mountPoint);
|
||||
var mpExists = Files.exists(mountPoint, LinkOption.NOFOLLOW_LINKS);
|
||||
var hideExists = Files.exists(hideaway, LinkOption.NOFOLLOW_LINKS);
|
||||
|
||||
//TODO: possible improvement by just deleting an _empty_ hideaway
|
||||
if (mpExists && hideExists) { //both resources exist (whatever type)
|
||||
throw new MountPointPreparationException(new FileAlreadyExistsException(hideaway.toString()));
|
||||
} else if (!mpExists && !hideExists) { //neither mountpoint nor hideaway exist
|
||||
throw new MountPointPreparationException(new NoSuchFileException(mountPoint.toString()));
|
||||
} else if (!mpExists) { //only hideaway exists
|
||||
checkIsDirectory(hideaway);
|
||||
LOG.info("Mountpoint {} seems to be not properly cleaned up. Will be fixed on unmount.", mountPoint);
|
||||
try {
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
Files.setAttribute(hideaway, WIN_HIDDEN_ATTR, true, LinkOption.NOFOLLOW_LINKS);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new MountPointPreparationException(e);
|
||||
}
|
||||
} else { //only mountpoint exists
|
||||
try {
|
||||
checkIsDirectory(mountPoint);
|
||||
checkIsEmpty(mountPoint);
|
||||
|
||||
Files.move(mountPoint, hideaway);
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
Files.setAttribute(hideaway, WIN_HIDDEN_ATTR, true, LinkOption.NOFOLLOW_LINKS);
|
||||
}
|
||||
int attempts = 0;
|
||||
while (!Files.notExists(mountPoint)) {
|
||||
if (attempts >= 10) {
|
||||
throw new MountPointPreparationException("Path " + mountPoint + " could not be cleared");
|
||||
}
|
||||
Thread.sleep(1000);
|
||||
attempts++;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new MountPointPreparationException(e);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new MountPointPreparationException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cleanup(Path mountPoint) {
|
||||
Path hideaway = getHideaway(mountPoint);
|
||||
try {
|
||||
waitForMountpointRestoration(mountPoint);
|
||||
Files.move(hideaway, mountPoint);
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
Files.setAttribute(mountPoint, WIN_HIDDEN_ATTR, false);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error("Unable to restore hidden directory to mountpoint {}.", mountPoint, e);
|
||||
}
|
||||
}
|
||||
|
||||
//on Windows removing the mountpoint takes some time, so we poll for at most 3 seconds
|
||||
private static void waitForMountpointRestoration(Path mountPoint) throws FileAlreadyExistsException {
|
||||
int attempts = 0;
|
||||
while (!Files.notExists(mountPoint, LinkOption.NOFOLLOW_LINKS)) {
|
||||
attempts++;
|
||||
if (attempts >= 5) {
|
||||
throw new FileAlreadyExistsException("Timeout waiting for mountpoint cleanup for " + mountPoint + " .");
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(300);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new FileAlreadyExistsException("Interrupted before mountpoint " + mountPoint + " was cleared");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkIsDirectory(Path toCheck) throws MountPointPreparationException {
|
||||
if (!Files.isDirectory(toCheck, LinkOption.NOFOLLOW_LINKS)) {
|
||||
throw new MountPointPreparationException(new NotDirectoryException(toCheck.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkIsEmpty(Path toCheck) throws MountPointPreparationException, IOException {
|
||||
try (var dirStream = Files.list(toCheck)) {
|
||||
if (dirStream.findFirst().isPresent()) {
|
||||
throw new MountPointPreparationException(new DirectoryNotEmptyException(toCheck.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//visible for testing
|
||||
static Path getHideaway(Path mountPoint) {
|
||||
return mountPoint.resolveSibling(HIDEAWAY_PREFIX + mountPoint.getFileName().toString() + HIDEAWAY_SUFFIX);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package org.cryptomator.common.mount;
|
||||
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.common.settings.VaultSettings;
|
||||
import org.cryptomator.integrations.mount.Mount;
|
||||
import org.cryptomator.integrations.mount.MountBuilder;
|
||||
import org.cryptomator.integrations.mount.MountFailedException;
|
||||
import org.cryptomator.integrations.mount.MountService;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.cryptomator.integrations.mount.MountCapability.MOUNT_AS_DRIVE_LETTER;
|
||||
import static org.cryptomator.integrations.mount.MountCapability.MOUNT_TO_EXISTING_DIR;
|
||||
import static org.cryptomator.integrations.mount.MountCapability.MOUNT_TO_SYSTEM_CHOSEN_PATH;
|
||||
import static org.cryptomator.integrations.mount.MountCapability.MOUNT_WITHIN_EXISTING_PARENT;
|
||||
import static org.cryptomator.integrations.mount.MountCapability.UNMOUNT_FORCED;
|
||||
|
||||
@Singleton
|
||||
public class Mounter {
|
||||
|
||||
private final Settings settings;
|
||||
private final Environment env;
|
||||
private final WindowsDriveLetters driveLetters;
|
||||
private final ObservableValue<ActualMountService> mountServiceObservable;
|
||||
|
||||
@Inject
|
||||
public Mounter(Settings settings, Environment env, WindowsDriveLetters driveLetters, ObservableValue<ActualMountService> mountServiceObservable) {
|
||||
this.settings = settings;
|
||||
this.env = env;
|
||||
this.driveLetters = driveLetters;
|
||||
this.mountServiceObservable = mountServiceObservable;
|
||||
}
|
||||
|
||||
private class SettledMounter {
|
||||
|
||||
private MountService service;
|
||||
private MountBuilder builder;
|
||||
private VaultSettings vaultSettings;
|
||||
|
||||
public SettledMounter(MountService service, MountBuilder builder, VaultSettings vaultSettings) {
|
||||
this.service = service;
|
||||
this.builder = builder;
|
||||
this.vaultSettings = vaultSettings;
|
||||
}
|
||||
|
||||
Runnable prepare() throws IOException {
|
||||
for (var capability : service.capabilities()) {
|
||||
switch (capability) {
|
||||
case FILE_SYSTEM_NAME -> builder.setFileSystemName("cryptoFs");
|
||||
case LOOPBACK_PORT ->
|
||||
builder.setLoopbackPort(settings.port().get()); //TODO: move port from settings to vaultsettings (see https://github.com/cryptomator/cryptomator/tree/feature/mount-setting-per-vault)
|
||||
case LOOPBACK_HOST_NAME -> env.getLoopbackAlias().ifPresent(builder::setLoopbackHostName);
|
||||
case READ_ONLY -> builder.setReadOnly(vaultSettings.usesReadOnlyMode().get());
|
||||
case MOUNT_FLAGS -> {
|
||||
var mountFlags = vaultSettings.mountFlags().get();
|
||||
if (mountFlags == null || mountFlags.isBlank()) {
|
||||
builder.setMountFlags(service.getDefaultMountFlags());
|
||||
} else {
|
||||
builder.setMountFlags(mountFlags);
|
||||
}
|
||||
}
|
||||
case VOLUME_ID -> builder.setVolumeId(vaultSettings.getId());
|
||||
case VOLUME_NAME -> builder.setVolumeName(vaultSettings.mountName().get());
|
||||
}
|
||||
}
|
||||
|
||||
return prepareMountPoint();
|
||||
}
|
||||
|
||||
private Runnable prepareMountPoint() throws IOException {
|
||||
Runnable cleanup = () -> {};
|
||||
var userChosenMountPoint = vaultSettings.getMountPoint();
|
||||
var defaultMountPointBase = env.getMountPointsDir().orElseThrow();
|
||||
var canMountToDriveLetter = service.hasCapability(MOUNT_AS_DRIVE_LETTER);
|
||||
var canMountToParent = service.hasCapability(MOUNT_WITHIN_EXISTING_PARENT);
|
||||
var canMountToDir = service.hasCapability(MOUNT_TO_EXISTING_DIR);
|
||||
var canMountToSystem = service.hasCapability(MOUNT_TO_SYSTEM_CHOSEN_PATH);
|
||||
|
||||
if (userChosenMountPoint == null) {
|
||||
if (canMountToSystem) {
|
||||
// no need to set a mount point
|
||||
} else if (canMountToDriveLetter) {
|
||||
builder.setMountpoint(driveLetters.getFirstDesiredAvailable().orElseThrow()); //TODO: catch exception and translate
|
||||
} else if (canMountToParent) {
|
||||
Files.createDirectories(defaultMountPointBase);
|
||||
builder.setMountpoint(defaultMountPointBase);
|
||||
} else if (canMountToDir) {
|
||||
var mountPoint = defaultMountPointBase.resolve(vaultSettings.mountName().get());
|
||||
Files.createDirectories(mountPoint);
|
||||
builder.setMountpoint(mountPoint);
|
||||
}
|
||||
} else {
|
||||
var mpIsDriveLetter = userChosenMountPoint.toString().matches("[A-Z]:\\\\");
|
||||
if (!mpIsDriveLetter && canMountToParent && !canMountToDir) {
|
||||
MountWithinParentUtil.prepareParentNoMountPoint(userChosenMountPoint);
|
||||
cleanup = () -> {
|
||||
MountWithinParentUtil.cleanup(userChosenMountPoint);
|
||||
};
|
||||
}
|
||||
try {
|
||||
builder.setMountpoint(userChosenMountPoint);
|
||||
} catch (IllegalArgumentException | UnsupportedOperationException e) {
|
||||
var configNotSupported = (!canMountToDriveLetter && mpIsDriveLetter) //mounting as driveletter, albeit not supported
|
||||
|| (!canMountToDir && !mpIsDriveLetter) //mounting to directory, albeit not supported
|
||||
|| (!canMountToParent && !mpIsDriveLetter) //
|
||||
|| (!canMountToDir && !canMountToParent && !canMountToSystem && !canMountToDriveLetter);
|
||||
if (configNotSupported) {
|
||||
throw new MountPointNotSupportedException(e.getMessage());
|
||||
} else if (canMountToDir && !canMountToParent && !Files.exists(userChosenMountPoint)) {
|
||||
//mountpoint must exist
|
||||
throw new MountPointNotExistsException(e.getMessage());
|
||||
} else {
|
||||
//TODO: add specific exception for !canMountToDir && canMountToParent && !Files.notExists(userChosenMountPoint)
|
||||
throw new IllegalMountPointException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
return cleanup;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public MountHandle mount(VaultSettings vaultSettings, Path cryptoFsRoot) throws IOException, MountFailedException {
|
||||
var mountService = this.mountServiceObservable.getValue().service();
|
||||
var builder = mountService.forFileSystem(cryptoFsRoot);
|
||||
var internal = new SettledMounter(mountService, builder, vaultSettings);
|
||||
var cleanup = internal.prepare();
|
||||
return new MountHandle(builder.mount(), mountService.hasCapability(UNMOUNT_FORCED), cleanup);
|
||||
}
|
||||
|
||||
public record MountHandle(Mount mountObj, boolean supportsUnmountForced, Runnable specialCleanup) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -76,6 +76,11 @@ public class DeviceKey {
|
||||
|
||||
private P384KeyPair createAndStoreNewKeyPair(char[] passphrase, Path p12File) throws IOException {
|
||||
var keyPair = P384KeyPair.generate();
|
||||
var tmpFile = p12File.resolveSibling(p12File.getFileName().toString() + ".tmp");
|
||||
if(Files.exists(tmpFile)) {
|
||||
LOG.debug("Leftover from devicekey creation detected. Deleting {}", tmpFile);
|
||||
Files.delete(tmpFile);
|
||||
}
|
||||
LOG.debug("Store new device key to {}", p12File);
|
||||
keyPair.store(p12File, passphrase);
|
||||
return keyPair;
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -36,29 +37,30 @@ public class SettingsJsonAdapter extends TypeAdapter<Settings> {
|
||||
@Override
|
||||
public void write(JsonWriter out, Settings value) throws IOException {
|
||||
out.beginObject();
|
||||
out.name("writtenByVersion").value(env.getAppVersion() + env.getBuildNumber().map("-"::concat).orElse(""));
|
||||
out.name("directories");
|
||||
writeVaultSettingsArray(out, value.getDirectories());
|
||||
out.name("askedForUpdateCheck").value(value.askedForUpdateCheck().get());
|
||||
out.name("checkForUpdatesEnabled").value(value.checkForUpdates().get());
|
||||
out.name("startHidden").value(value.startHidden().get());
|
||||
out.name("autoCloseVaults").value(value.autoCloseVaults().get());
|
||||
out.name("port").value(value.port().get());
|
||||
out.name("numTrayNotifications").value(value.numTrayNotifications().get());
|
||||
out.name("checkForUpdatesEnabled").value(value.checkForUpdates().get());
|
||||
out.name("debugMode").value(value.debugMode().get());
|
||||
out.name("theme").value(value.theme().get().name());
|
||||
out.name("uiOrientation").value(value.userInterfaceOrientation().get().name());
|
||||
out.name("displayConfiguration").value((value.displayConfigurationProperty().get()));
|
||||
out.name("keychainProvider").value(value.keychainProvider().get());
|
||||
out.name("useKeychain").value(value.useKeychain().get());
|
||||
out.name("language").value((value.languageProperty().get()));
|
||||
out.name("licenseKey").value(value.licenseKey().get());
|
||||
out.name("mountService").value(value.mountService().get());
|
||||
out.name("numTrayNotifications").value(value.numTrayNotifications().get());
|
||||
out.name("port").value(value.port().get());
|
||||
out.name("showMinimizeButton").value(value.showMinimizeButton().get());
|
||||
out.name("showTrayIcon").value(value.showTrayIcon().get());
|
||||
out.name("startHidden").value(value.startHidden().get());
|
||||
out.name("theme").value(value.theme().get().name());
|
||||
out.name("uiOrientation").value(value.userInterfaceOrientation().get().name());
|
||||
out.name("useKeychain").value(value.useKeychain().get());
|
||||
out.name("windowHeight").value((value.windowHeightProperty().get()));
|
||||
out.name("windowWidth").value((value.windowWidthProperty().get()));
|
||||
out.name("windowXPosition").value((value.windowXPositionProperty().get()));
|
||||
out.name("windowYPosition").value((value.windowYPositionProperty().get()));
|
||||
out.name("windowWidth").value((value.windowWidthProperty().get()));
|
||||
out.name("windowHeight").value((value.windowHeightProperty().get()));
|
||||
out.name("displayConfiguration").value((value.displayConfigurationProperty().get()));
|
||||
out.name("language").value((value.languageProperty().get()));
|
||||
out.name("mountService").value(value.mountService().get());
|
||||
out.endObject();
|
||||
}
|
||||
|
||||
@@ -73,50 +75,84 @@ public class SettingsJsonAdapter extends TypeAdapter<Settings> {
|
||||
@Override
|
||||
public Settings read(JsonReader in) throws IOException {
|
||||
Settings settings = new Settings(env);
|
||||
|
||||
//1.6.x legacy
|
||||
String volumeImpl = null;
|
||||
//legacy end
|
||||
in.beginObject();
|
||||
while (in.hasNext()) {
|
||||
String name = in.nextName();
|
||||
switch (name) {
|
||||
case "writtenByVersion" -> in.skipValue(); //noop
|
||||
case "directories" -> settings.getDirectories().addAll(readVaultSettingsArray(in));
|
||||
case "askedForUpdateCheck" -> settings.askedForUpdateCheck().set(in.nextBoolean());
|
||||
case "checkForUpdatesEnabled" -> settings.checkForUpdates().set(in.nextBoolean());
|
||||
case "startHidden" -> settings.startHidden().set(in.nextBoolean());
|
||||
case "autoCloseVaults" -> settings.autoCloseVaults().set(in.nextBoolean());
|
||||
case "port" -> settings.port().set(in.nextInt());
|
||||
case "numTrayNotifications" -> settings.numTrayNotifications().set(in.nextInt());
|
||||
case "checkForUpdatesEnabled" -> settings.checkForUpdates().set(in.nextBoolean());
|
||||
case "debugMode" -> settings.debugMode().set(in.nextBoolean());
|
||||
case "theme" -> settings.theme().set(parseUiTheme(in.nextString()));
|
||||
case "uiOrientation" -> settings.userInterfaceOrientation().set(parseUiOrientation(in.nextString()));
|
||||
case "keychainProvider" -> settings.keychainProvider().set(in.nextString());
|
||||
case "useKeychain" -> settings.useKeychain().set(in.nextBoolean());
|
||||
case "licenseKey" -> settings.licenseKey().set(in.nextString());
|
||||
case "showMinimizeButton" -> settings.showMinimizeButton().set(in.nextBoolean());
|
||||
case "showTrayIcon" -> settings.showTrayIcon().set(in.nextBoolean());
|
||||
case "windowXPosition" -> settings.windowXPositionProperty().set(in.nextInt());
|
||||
case "windowYPosition" -> settings.windowYPositionProperty().set(in.nextInt());
|
||||
case "windowWidth" -> settings.windowWidthProperty().set(in.nextInt());
|
||||
case "windowHeight" -> settings.windowHeightProperty().set(in.nextInt());
|
||||
case "displayConfiguration" -> settings.displayConfigurationProperty().set(in.nextString());
|
||||
case "keychainProvider" -> settings.keychainProvider().set(in.nextString());
|
||||
case "language" -> settings.languageProperty().set(in.nextString());
|
||||
case "licenseKey" -> settings.licenseKey().set(in.nextString());
|
||||
case "mountService" -> {
|
||||
var token = in.peek();
|
||||
if (JsonToken.STRING == token) {
|
||||
settings.mountService().set(in.nextString());
|
||||
}
|
||||
}
|
||||
|
||||
case "numTrayNotifications" -> settings.numTrayNotifications().set(in.nextInt());
|
||||
case "port" -> settings.port().set(in.nextInt());
|
||||
case "showMinimizeButton" -> settings.showMinimizeButton().set(in.nextBoolean());
|
||||
case "showTrayIcon" -> settings.showTrayIcon().set(in.nextBoolean());
|
||||
case "startHidden" -> settings.startHidden().set(in.nextBoolean());
|
||||
case "theme" -> settings.theme().set(parseUiTheme(in.nextString()));
|
||||
case "uiOrientation" -> settings.userInterfaceOrientation().set(parseUiOrientation(in.nextString()));
|
||||
case "useKeychain" -> settings.useKeychain().set(in.nextBoolean());
|
||||
case "windowHeight" -> settings.windowHeightProperty().set(in.nextInt());
|
||||
case "windowWidth" -> settings.windowWidthProperty().set(in.nextInt());
|
||||
case "windowXPosition" -> settings.windowXPositionProperty().set(in.nextInt());
|
||||
case "windowYPosition" -> settings.windowYPositionProperty().set(in.nextInt());
|
||||
//1.6.x legacy
|
||||
case "preferredVolumeImpl" -> volumeImpl = in.nextString();
|
||||
//legacy end
|
||||
default -> {
|
||||
LOG.warn("Unsupported vault setting found in JSON: {}", name);
|
||||
in.skipValue();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
in.endObject();
|
||||
|
||||
//1.6.x legacy
|
||||
if (volumeImpl != null) {
|
||||
settings.mountService().set(convertLegacyVolumeImplToMountService(volumeImpl));
|
||||
}
|
||||
//legacy end
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
private String convertLegacyVolumeImplToMountService(String volumeImpl) {
|
||||
if (volumeImpl.equals("Dokany")) {
|
||||
return "org.cryptomator.frontend.dokany.mount.DokanyMountProvider";
|
||||
} else if (volumeImpl.equals("FUSE")) {
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
return "org.cryptomator.frontend.fuse.mount.WinFspNetworkMountProvider";
|
||||
} else if (SystemUtils.IS_OS_MAC) {
|
||||
return "org.cryptomator.frontend.fuse.mount.MacFuseMountProvider";
|
||||
} else {
|
||||
return "org.cryptomator.frontend.fuse.mount.LinuxFuseMountProvider";
|
||||
}
|
||||
} else {
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
return "org.cryptomator.frontend.webdav.mount.WindowsMounter";
|
||||
} else if (SystemUtils.IS_OS_MAC) {
|
||||
return "org.cryptomator.frontend.webdav.mount.MacAppleScriptMounter";
|
||||
} else {
|
||||
return "org.cryptomator.frontend.webdav.mount.LinuxGioMounter";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private UiTheme parseUiTheme(String uiThemeName) {
|
||||
try {
|
||||
return UiTheme.valueOf(uiThemeName.toUpperCase());
|
||||
|
||||
@@ -45,7 +45,7 @@ public class VaultSettings {
|
||||
private final BooleanProperty unlockAfterStartup = new SimpleBooleanProperty(DEFAULT_UNLOCK_AFTER_STARTUP);
|
||||
private final BooleanProperty revealAfterMount = new SimpleBooleanProperty(DEFAULT_REVEAL_AFTER_MOUNT);
|
||||
private final BooleanProperty usesReadOnlyMode = new SimpleBooleanProperty(DEFAULT_USES_READONLY_MODE);
|
||||
private final StringProperty mountFlags = new SimpleStringProperty(DEFAULT_MOUNT_FLAGS);
|
||||
private final StringProperty mountFlags = new SimpleStringProperty(DEFAULT_MOUNT_FLAGS); //TODO: remove empty default mount flags and let this property be null if not used
|
||||
private final IntegerProperty maxCleartextFilenameLength = new SimpleIntegerProperty(DEFAULT_MAX_CLEARTEXT_FILENAME_LENGTH);
|
||||
private final ObjectProperty<WhenUnlocked> actionAfterUnlock = new SimpleObjectProperty<>(DEFAULT_ACTION_AFTER_UNLOCK);
|
||||
private final BooleanProperty autoLockWhenIdle = new SimpleBooleanProperty(DEFAULT_AUTOLOCK_WHEN_IDLE);
|
||||
|
||||
@@ -38,8 +38,6 @@ class VaultSettingsJsonAdapter {
|
||||
out.endObject();
|
||||
}
|
||||
|
||||
//TODO: usesCustomMountPath, customMountPath and winDriveLetter removed
|
||||
// -> migration required
|
||||
public VaultSettings read(JsonReader in) throws IOException {
|
||||
String id = null;
|
||||
String path = null;
|
||||
@@ -55,6 +53,12 @@ class VaultSettingsJsonAdapter {
|
||||
boolean autoLockWhenIdle = VaultSettings.DEFAULT_AUTOLOCK_WHEN_IDLE;
|
||||
int autoLockIdleSeconds = VaultSettings.DEFAULT_AUTOLOCK_IDLE_SECONDS;
|
||||
|
||||
//legacy from 1.6.x
|
||||
boolean useCustomMountPath = false;
|
||||
String customMountPath = "";
|
||||
String winDriveLetter = "";
|
||||
//legacy end
|
||||
|
||||
in.beginObject();
|
||||
while (in.hasNext()) {
|
||||
String name = in.nextName();
|
||||
@@ -78,6 +82,11 @@ class VaultSettingsJsonAdapter {
|
||||
case "actionAfterUnlock" -> actionAfterUnlock = parseActionAfterUnlock(in.nextString());
|
||||
case "autoLockWhenIdle" -> autoLockWhenIdle = in.nextBoolean();
|
||||
case "autoLockIdleSeconds" -> autoLockIdleSeconds = in.nextInt();
|
||||
//legacy from 1.6.x
|
||||
case "winDriveLetter" -> winDriveLetter = in.nextString();
|
||||
case "usesIndividualMountPath", "useCustomMountPath" -> useCustomMountPath = in.nextBoolean();
|
||||
case "individualMountPath", "customMountPath" -> customMountPath = in.nextString();
|
||||
//legacy end
|
||||
default -> {
|
||||
LOG.warn("Unsupported vault setting found in JSON: {}", name);
|
||||
in.skipValue();
|
||||
@@ -102,6 +111,13 @@ class VaultSettingsJsonAdapter {
|
||||
vaultSettings.autoLockWhenIdle().set(autoLockWhenIdle);
|
||||
vaultSettings.autoLockIdleSeconds().set(autoLockIdleSeconds);
|
||||
vaultSettings.mountPoint().set(mountPoint);
|
||||
//legacy from 1.6.x
|
||||
if(useCustomMountPath && !customMountPath.isBlank()) {
|
||||
vaultSettings.mountPoint().set(parseMountPoint(customMountPath));
|
||||
} else if(!winDriveLetter.isBlank() ) {
|
||||
vaultSettings.mountPoint().set(parseMountPoint(winDriveLetter+":\\"));
|
||||
}
|
||||
//legacy end
|
||||
return vaultSettings;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
package org.cryptomator.common.settings;
|
||||
|
||||
public enum VolumeImpl {
|
||||
WEBDAV("WebDAV"),
|
||||
FUSE("FUSE"),
|
||||
DOKANY("Dokany");
|
||||
|
||||
private String displayName;
|
||||
|
||||
VolumeImpl(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javafx.application.Platform;
|
||||
import javafx.collections.ObservableList;
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
@@ -40,6 +41,7 @@ public class AutoLocker {
|
||||
private void autolock(Vault vault) {
|
||||
try {
|
||||
vault.lock(false);
|
||||
Platform.runLater(() -> vault.stateProperty().set(VaultState.Value.LOCKED));
|
||||
LOG.info("Autolocked {} after idle timeout", vault.getDisplayName());
|
||||
} catch (UnmountFailedException | IOException e) {
|
||||
LOG.error("Autolocking failed.", e);
|
||||
|
||||
@@ -8,12 +8,10 @@
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.common.vaults;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.Constants;
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.cryptomator.common.mount.Mounter;
|
||||
import org.cryptomator.common.mount.WindowsDriveLetters;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.common.settings.VaultSettings;
|
||||
import org.cryptomator.cryptofs.CryptoFileSystem;
|
||||
import org.cryptomator.cryptofs.CryptoFileSystemProperties;
|
||||
@@ -23,11 +21,7 @@ import org.cryptomator.cryptofs.common.FileSystemCapabilityChecker;
|
||||
import org.cryptomator.cryptolib.api.CryptoException;
|
||||
import org.cryptomator.cryptolib.api.MasterkeyLoader;
|
||||
import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
|
||||
import org.cryptomator.integrations.mount.Mount;
|
||||
import org.cryptomator.integrations.mount.MountBuilder;
|
||||
import org.cryptomator.integrations.mount.MountCapability;
|
||||
import org.cryptomator.integrations.mount.MountFailedException;
|
||||
import org.cryptomator.integrations.mount.MountService;
|
||||
import org.cryptomator.integrations.mount.Mountpoint;
|
||||
import org.cryptomator.integrations.mount.UnmountFailedException;
|
||||
import org.slf4j.Logger;
|
||||
@@ -44,9 +38,7 @@ import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.ReadOnlyStringProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.EnumSet;
|
||||
@@ -54,11 +46,6 @@ import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static org.cryptomator.integrations.mount.MountCapability.MOUNT_AS_DRIVE_LETTER;
|
||||
import static org.cryptomator.integrations.mount.MountCapability.MOUNT_TO_EXISTING_DIR;
|
||||
import static org.cryptomator.integrations.mount.MountCapability.MOUNT_TO_SYSTEM_CHOSEN_PATH;
|
||||
import static org.cryptomator.integrations.mount.MountCapability.MOUNT_WITHIN_EXISTING_PARENT;
|
||||
|
||||
@PerVault
|
||||
public class Vault {
|
||||
|
||||
@@ -66,14 +53,10 @@ public class Vault {
|
||||
private static final Path HOME_DIR = Paths.get(SystemUtils.USER_HOME);
|
||||
private static final int UNLIMITED_FILENAME_LENGTH = Integer.MAX_VALUE;
|
||||
|
||||
private final Environment env;
|
||||
private final Settings settings;
|
||||
private final VaultSettings vaultSettings;
|
||||
private final AtomicReference<CryptoFileSystem> cryptoFileSystem;
|
||||
private final VaultState state;
|
||||
private final ObjectProperty<Exception> lastKnownException;
|
||||
private final ObservableValue<MountService> mountService;
|
||||
private final ObservableValue<String> defaultMountFlags;
|
||||
private final VaultConfigCache configCache;
|
||||
private final VaultStats stats;
|
||||
private final StringBinding displayablePath;
|
||||
@@ -84,22 +67,18 @@ public class Vault {
|
||||
private final BooleanBinding needsMigration;
|
||||
private final BooleanBinding unknownError;
|
||||
private final ObjectBinding<Mountpoint> mountPoint;
|
||||
private final WindowsDriveLetters windowsDriveLetters;
|
||||
private final Mounter mounter;
|
||||
private final BooleanProperty showingStats;
|
||||
|
||||
private AtomicReference<MountHandle> mountHandle = new AtomicReference<>(null);
|
||||
private AtomicReference<Mounter.MountHandle> mountHandle = new AtomicReference<>(null);
|
||||
|
||||
@Inject
|
||||
Vault(Environment env, Settings settings, VaultSettings vaultSettings, VaultConfigCache configCache, AtomicReference<CryptoFileSystem> cryptoFileSystem, VaultState state, @Named("lastKnownException") ObjectProperty<Exception> lastKnownException, ObservableValue<MountService> mountService, VaultStats stats, WindowsDriveLetters windowsDriveLetters) {
|
||||
this.env = env;
|
||||
this.settings = settings;
|
||||
Vault(VaultSettings vaultSettings, VaultConfigCache configCache, AtomicReference<CryptoFileSystem> cryptoFileSystem, VaultState state, @Named("lastKnownException") ObjectProperty<Exception> lastKnownException, VaultStats stats, WindowsDriveLetters windowsDriveLetters, Mounter mounter) {
|
||||
this.vaultSettings = vaultSettings;
|
||||
this.configCache = configCache;
|
||||
this.cryptoFileSystem = cryptoFileSystem;
|
||||
this.state = state;
|
||||
this.lastKnownException = lastKnownException;
|
||||
this.mountService = mountService;
|
||||
this.defaultMountFlags = mountService.map(MountService::getDefaultMountFlags);
|
||||
this.stats = stats;
|
||||
this.displayablePath = Bindings.createStringBinding(this::getDisplayablePath, vaultSettings.path());
|
||||
this.locked = Bindings.createBooleanBinding(this::isLocked, state);
|
||||
@@ -109,7 +88,7 @@ public class Vault {
|
||||
this.needsMigration = Bindings.createBooleanBinding(this::isNeedsMigration, state);
|
||||
this.unknownError = Bindings.createBooleanBinding(this::isUnknownError, state);
|
||||
this.mountPoint = Bindings.createObjectBinding(this::getMountPoint, state);
|
||||
this.windowsDriveLetters = windowsDriveLetters;
|
||||
this.mounter = mounter;
|
||||
this.showingStats = new SimpleBooleanProperty(false);
|
||||
}
|
||||
|
||||
@@ -159,45 +138,6 @@ public class Vault {
|
||||
}
|
||||
}
|
||||
|
||||
private MountBuilder prepareMount(Path cryptoRoot) throws IOException {
|
||||
var mountProvider = mountService.getValue();
|
||||
var builder = mountProvider.forFileSystem(cryptoRoot);
|
||||
|
||||
for (var capability : mountProvider.capabilities()) {
|
||||
switch (capability) {
|
||||
case FILE_SYSTEM_NAME -> builder.setFileSystemName("crypto");
|
||||
case LOOPBACK_PORT -> builder.setLoopbackPort(settings.port().get()); //TODO: move port from settings to vaultsettings?
|
||||
case LOOPBACK_HOST_NAME -> builder.setLoopbackHostName("cryptomator-vault"); //TODO: Read from system property
|
||||
case READ_ONLY -> builder.setReadOnly(vaultSettings.usesReadOnlyMode().get());
|
||||
case MOUNT_FLAGS -> builder.setMountFlags(defaultMountFlags.getValue()); // TODO use custom mount flags (pre-populated with default mount flags)
|
||||
case VOLUME_ID -> builder.setVolumeId(vaultSettings.getId());
|
||||
case VOLUME_NAME -> builder.setVolumeName(vaultSettings.mountName().get());
|
||||
}
|
||||
}
|
||||
|
||||
var userChosenMountPoint = vaultSettings.getMountPoint();
|
||||
var defaultMountPointBase = env.getMountPointsDir().orElseThrow();
|
||||
if (userChosenMountPoint == null) {
|
||||
if (mountProvider.hasCapability(MOUNT_TO_SYSTEM_CHOSEN_PATH)) {
|
||||
// no need to set a mount point
|
||||
} else if (mountProvider.hasCapability(MOUNT_AS_DRIVE_LETTER)) {
|
||||
builder.setMountpoint(windowsDriveLetters.getFirstDesiredAvailable().orElseThrow());
|
||||
} else if (mountProvider.hasCapability(MOUNT_WITHIN_EXISTING_PARENT)) {
|
||||
Files.createDirectories(defaultMountPointBase);
|
||||
builder.setMountpoint(defaultMountPointBase);
|
||||
} else if (mountProvider.hasCapability(MOUNT_TO_EXISTING_DIR) ) {
|
||||
var mountPoint = defaultMountPointBase.resolve(vaultSettings.mountName().get());
|
||||
Files.createDirectories(mountPoint);
|
||||
builder.setMountpoint(mountPoint);
|
||||
}
|
||||
} else if (mountProvider.hasCapability(MOUNT_TO_EXISTING_DIR) || mountProvider.hasCapability(MOUNT_WITHIN_EXISTING_PARENT) || mountProvider.hasCapability(MOUNT_AS_DRIVE_LETTER)) {
|
||||
// TODO: move the mount point away in case of MOUNT_WITHIN_EXISTING_PARENT?
|
||||
builder.setMountpoint(userChosenMountPoint);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public synchronized void unlock(MasterkeyLoader keyLoader) throws CryptoException, IOException, MountFailedException {
|
||||
if (cryptoFileSystem.get() != null) {
|
||||
throw new IllegalStateException("Already unlocked.");
|
||||
@@ -207,8 +147,7 @@ public class Vault {
|
||||
try {
|
||||
cryptoFileSystem.set(fs);
|
||||
var rootPath = fs.getRootDirectories().iterator().next();
|
||||
var supportsForcedUnmount = mountService.getValue().hasCapability(MountCapability.UNMOUNT_FORCED);
|
||||
var mountHandle = new MountHandle(prepareMount(rootPath).mount(), supportsForcedUnmount);
|
||||
var mountHandle = mounter.mount(vaultSettings, rootPath);
|
||||
success = this.mountHandle.compareAndSet(null, mountHandle);
|
||||
} finally {
|
||||
if (!success) {
|
||||
@@ -217,7 +156,6 @@ public class Vault {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public synchronized void lock(boolean forced) throws UnmountFailedException, IOException {
|
||||
var mountHandle = this.mountHandle.get();
|
||||
if (mountHandle == null) {
|
||||
@@ -225,14 +163,15 @@ public class Vault {
|
||||
return;
|
||||
}
|
||||
|
||||
if (forced && mountHandle.supportsUnmountForced) {
|
||||
mountHandle.mount.unmountForced();
|
||||
if (forced && mountHandle.supportsUnmountForced()) {
|
||||
mountHandle.mountObj().unmountForced();
|
||||
} else {
|
||||
mountHandle.mount.unmount();
|
||||
mountHandle.mountObj().unmount();
|
||||
}
|
||||
|
||||
try {
|
||||
mountHandle.mount.close();
|
||||
mountHandle.mountObj().close();
|
||||
mountHandle.specialCleanup().run();
|
||||
} finally {
|
||||
destroyCryptoFileSystem();
|
||||
}
|
||||
@@ -327,7 +266,7 @@ public class Vault {
|
||||
|
||||
public Mountpoint getMountPoint() {
|
||||
var handle = mountHandle.get();
|
||||
return handle == null ? null : handle.mount.getMountpoint();
|
||||
return handle == null ? null : handle.mountObj().getMountpoint();
|
||||
}
|
||||
|
||||
public StringBinding displayablePathProperty() {
|
||||
@@ -375,24 +314,30 @@ public class Vault {
|
||||
return vaultSettings.path().getValue();
|
||||
}
|
||||
|
||||
public boolean isHavingCustomMountFlags() {
|
||||
return !Strings.isNullOrEmpty(vaultSettings.mountFlags().get());
|
||||
}
|
||||
/**
|
||||
* Gets from the cleartext path its ciphertext counterpart.
|
||||
*
|
||||
* @return Local os path to the ciphertext resource
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws IllegalStateException if the vault is not unlocked
|
||||
*/
|
||||
public Path getCiphertextPath(Path cleartextPath) throws IOException {
|
||||
if (!state.getValue().equals(VaultState.Value.UNLOCKED)) {
|
||||
throw new IllegalStateException("Vault is not unlocked");
|
||||
}
|
||||
var fs = cryptoFileSystem.get();
|
||||
var osPathSeparator = cleartextPath.getFileSystem().getSeparator();
|
||||
var cryptoFsPathSeparator = fs.getSeparator();
|
||||
|
||||
public ObservableValue<String> defaultMountFlagsProperty() {
|
||||
return defaultMountFlags;
|
||||
}
|
||||
|
||||
public String getDefaultMountFlags() {
|
||||
return defaultMountFlags.getValue();
|
||||
}
|
||||
|
||||
public String getEffectiveMountFlags() {
|
||||
String mountFlags = vaultSettings.mountFlags().get();
|
||||
if (Strings.isNullOrEmpty(mountFlags)) {
|
||||
return ""; //TODO: should the provider provide dem defaults??
|
||||
if (getMountPoint() instanceof Mountpoint.WithPath mp) {
|
||||
var absoluteCryptoFsPath = cryptoFsPathSeparator + mp.path().relativize(cleartextPath).toString();
|
||||
if (!cryptoFsPathSeparator.equals(osPathSeparator)) {
|
||||
absoluteCryptoFsPath = absoluteCryptoFsPath.replace(osPathSeparator, cryptoFsPathSeparator);
|
||||
}
|
||||
var cryptoPath = fs.getPath(absoluteCryptoFsPath);
|
||||
return fs.getCiphertextPath(cryptoPath);
|
||||
} else {
|
||||
return mountFlags;
|
||||
throw new UnsupportedOperationException("URI mount points not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,10 +345,6 @@ public class Vault {
|
||||
return configCache;
|
||||
}
|
||||
|
||||
public void setCustomMountFlags(String mountFlags) {
|
||||
vaultSettings.mountFlags().set(mountFlags);
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return vaultSettings.getId();
|
||||
}
|
||||
@@ -426,15 +367,12 @@ public class Vault {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* TODO: reactivate/ needed at all?
|
||||
public boolean supportsForcedUnmount() {
|
||||
return volume.supportsForcedUnmount();
|
||||
var mh = mountHandle.get();
|
||||
if (mh == null) {
|
||||
throw new IllegalStateException("Vault is not mounted");
|
||||
}
|
||||
return mountHandle.get().supportsUnmountForced();
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
private record MountHandle(Mount mount, boolean supportsUnmountForced) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,39 +1,95 @@
|
||||
package org.cryptomator.launcher;
|
||||
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.text.Collator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
@Singleton
|
||||
public class SupportedLanguages {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SupportedLanguages.class);
|
||||
// these are BCP 47 language codes, not ISO. Note the "-" instead of the "_":
|
||||
public static final List<String> LANGUAGAE_TAGS = List.of("en", "ar", "be", "bn", "bs", "ca", "cs", "da", "de", "el", "es", "fil", "fa", "fr", "gl", "he", //
|
||||
"hi", "hr", "hu", "id", "it", "ja", "ko", "lv", "mk", "nb", "nl", "nn", "no", "pa", "pl", "pt", "pt-BR", "ro", "ru", "si", "sk", "sr", "sr-Latn", "sv", "sw", //
|
||||
"ta", "te", "th", "tr", "uk", "vi", "zh", "zh-HK", "zh-TW");
|
||||
public static final String ENGLISH = "en";
|
||||
|
||||
@Nullable
|
||||
private final String preferredLanguage;
|
||||
private final List<String> sortedLanguageTags;
|
||||
private final Locale preferredLocale;
|
||||
|
||||
@Inject
|
||||
public SupportedLanguages(Settings settings) {
|
||||
this.preferredLanguage = settings.languageProperty().get();
|
||||
var preferredLanguage = settings.languageProperty().get();
|
||||
preferredLocale = preferredLanguage == null ? Locale.getDefault() : Locale.forLanguageTag(preferredLanguage);
|
||||
var collator = Collator.getInstance(preferredLocale);
|
||||
collator.setStrength(Collator.PRIMARY);
|
||||
List<String> sortedTags = new ArrayList<>();
|
||||
sortedTags.add(0, Settings.DEFAULT_LANGUAGE);
|
||||
sortedTags.add(1, ENGLISH);
|
||||
getSupportedLanguageTags().stream() //
|
||||
.sorted((a, b) -> collator.compare(Locale.forLanguageTag(a).getDisplayName(), Locale.forLanguageTag(b).getDisplayName())) //
|
||||
.forEach(sortedTags::add);
|
||||
sortedLanguageTags = Collections.unmodifiableList(sortedTags);
|
||||
}
|
||||
|
||||
public void applyPreferred() {
|
||||
if (preferredLanguage == null) {
|
||||
LOG.debug("Using system locale");
|
||||
return;
|
||||
}
|
||||
var preferredLocale = Locale.forLanguageTag(preferredLanguage);
|
||||
LOG.debug("Applying preferred locale {}", preferredLocale.getDisplayName(Locale.ENGLISH));
|
||||
LOG.debug("Using locale {}", preferredLocale);
|
||||
Locale.setDefault(preferredLocale);
|
||||
}
|
||||
|
||||
public List<String> getLanguageTags() {
|
||||
return sortedLanguageTags;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Iterates over the /i18n directory and extracts from every localization file the BCP 47 code.
|
||||
*
|
||||
* @return list of supported BCP 47 language codes
|
||||
*/
|
||||
private static List<String> getSupportedLanguageTags() {
|
||||
try {
|
||||
var i18DirURI = SupportedLanguages.class.getResource("/i18n").toURI();
|
||||
var uriScheme = i18DirURI.getScheme();
|
||||
if (uriScheme.equals("jar")) {
|
||||
final String[] array = i18DirURI.toString().split("!");
|
||||
try (var jarFs = FileSystems.newFileSystem(URI.create(array[0]), Map.<String, String>of())) {
|
||||
return streamDirectory(jarFs.getPath(array[1]));
|
||||
}
|
||||
} else if (uriScheme.equals("file")) {
|
||||
return streamDirectory(Path.of(i18DirURI));
|
||||
} else {
|
||||
throw new IOException("Unsupported uri scheme: " + uriScheme);
|
||||
}
|
||||
} catch (URISyntaxException | IOException e) {
|
||||
LOG.warn("Unable to determine additional supported languages.", e);
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> streamDirectory(Path i18Dir) throws IOException {
|
||||
try (var dirStream = Files.newDirectoryStream(i18Dir, "strings_*.properties")) {
|
||||
return StreamSupport.stream(dirStream.spliterator(), false) //
|
||||
.map(SupportedLanguages::getBCP47CodeFromFileName) //
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
private static String getBCP47CodeFromFileName(Path p) {
|
||||
var fileName = p.getFileName().toString();
|
||||
return fileName.substring("strings_".length(), fileName.indexOf(".properties")).replace('_', '-');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -84,6 +84,10 @@ public class LogbackConfigurator extends ContextAwareBase implements Configurato
|
||||
upgrades.addAppender(upgrade);
|
||||
upgrades.addAppender(file);
|
||||
upgrades.setAdditive(false);
|
||||
|
||||
// configure fuse file locking logger:
|
||||
Logger fuseLocking = context.getLogger("org.cryptomator.frontend.fuse.locks");
|
||||
fuseLocking.setLevel(Level.OFF);
|
||||
}
|
||||
return ExecutionStatus.DO_NOT_INVOKE_NEXT_IF_ANY;
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.common.NewPasswordController;
|
||||
import org.cryptomator.ui.common.PasswordStrengthUtil;
|
||||
import org.cryptomator.ui.changepassword.NewPasswordController;
|
||||
import org.cryptomator.ui.changepassword.PasswordStrengthUtil;
|
||||
import org.cryptomator.ui.common.StageFactory;
|
||||
import org.cryptomator.ui.fxapp.PrimaryStage;
|
||||
import org.cryptomator.ui.recoverykey.RecoveryKeyDisplayController;
|
||||
|
||||
+3
-3
@@ -13,7 +13,7 @@ import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.common.NewPasswordController;
|
||||
import org.cryptomator.ui.changepassword.NewPasswordController;
|
||||
import org.cryptomator.ui.common.Tasks;
|
||||
import org.cryptomator.ui.fxapp.FxApplicationWindows;
|
||||
import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingStrategy;
|
||||
@@ -48,13 +48,13 @@ import java.util.ResourceBundle;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||
import static org.cryptomator.common.Constants.DEFAULT_KEY_ID;
|
||||
import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
|
||||
|
||||
@AddVaultWizardScoped
|
||||
public class CreateNewVaultPasswordController implements FxController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(CreateNewVaultPasswordController.class);
|
||||
private static final URI DEFAULT_KEY_ID = URI.create(MasterkeyFileLoadingStrategy.SCHEME + ":" + MASTERKEY_FILENAME); // TODO better place?
|
||||
|
||||
private final Stage window;
|
||||
private final Lazy<Scene> chooseLocationScene;
|
||||
@@ -176,7 +176,7 @@ public class CreateNewVaultPasswordController implements FxController {
|
||||
// 2. initialize vault:
|
||||
try {
|
||||
MasterkeyLoader loader = ignored -> masterkey.copy();
|
||||
CryptoFileSystemProperties fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties().withCipherCombo(CryptorProvider.Scheme.SIV_CTRMAC).withKeyLoader(loader).build();
|
||||
CryptoFileSystemProperties fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties().withCipherCombo(CryptorProvider.Scheme.SIV_GCM).withKeyLoader(loader).build();
|
||||
CryptoFileSystemProvider.initialize(path, fsProps, DEFAULT_KEY_ID);
|
||||
|
||||
// 3. write vault-internal readme file:
|
||||
|
||||
@@ -9,7 +9,6 @@ import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
|
||||
import org.cryptomator.integrations.keychain.KeychainAccessException;
|
||||
import org.cryptomator.ui.common.Animations;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.NewPasswordController;
|
||||
import org.cryptomator.ui.controls.NiceSecurePasswordField;
|
||||
import org.cryptomator.ui.fxapp.FxApplicationWindows;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
@@ -10,8 +10,6 @@ import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.common.NewPasswordController;
|
||||
import org.cryptomator.ui.common.PasswordStrengthUtil;
|
||||
import org.cryptomator.ui.common.StageFactory;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
+7
-1
@@ -1,5 +1,7 @@
|
||||
package org.cryptomator.ui.common;
|
||||
package org.cryptomator.ui.changepassword;
|
||||
|
||||
import org.cryptomator.common.Passphrase;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.controls.FontAwesome5IconView;
|
||||
import org.cryptomator.ui.controls.NiceSecurePasswordField;
|
||||
|
||||
@@ -91,4 +93,8 @@ public class NewPasswordController implements FxController {
|
||||
return passwordStrength.get();
|
||||
}
|
||||
|
||||
public Passphrase getNewPassword() {
|
||||
return passwordField.getCharacters();
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
* Contributors:
|
||||
* Jean-Noël Charon - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.ui.common;
|
||||
package org.cryptomator.ui.changepassword;
|
||||
|
||||
import com.nulabinc.zxcvbn.Zxcvbn;
|
||||
import org.cryptomator.common.Environment;
|
||||
@@ -9,12 +9,16 @@ public enum FxmlFile {
|
||||
ADDVAULT_SUCCESS("/fxml/addvault_success.fxml"), //
|
||||
ADDVAULT_WELCOME("/fxml/addvault_welcome.fxml"), //
|
||||
CHANGEPASSWORD("/fxml/changepassword.fxml"), //
|
||||
CONVERTVAULT_HUBTOPASSWORD_START("/fxml/convertvault_hubtopassword_start.fxml"), //
|
||||
CONVERTVAULT_HUBTOPASSWORD_CONVERT("/fxml/convertvault_hubtopassword_convert.fxml"), //
|
||||
CONVERTVAULT_HUBTOPASSWORD_SUCCESS("/fxml/convertvault_hubtopassword_success.fxml"), //
|
||||
ERROR("/fxml/error.fxml"), //
|
||||
FORGET_PASSWORD("/fxml/forget_password.fxml"), //
|
||||
HEALTH_START("/fxml/health_start.fxml"), //
|
||||
HEALTH_CHECK_LIST("/fxml/health_check_list.fxml"), //
|
||||
HUB_NO_KEYCHAIN("/fxml/hub_no_keychain.fxml"), //
|
||||
HUB_AUTH_FLOW("/fxml/hub_auth_flow.fxml"), //
|
||||
HUB_LICENSE_EXCEEDED("/fxml/hub_license_exceeded.fxml"), //
|
||||
HUB_INVALID_LICENSE("/fxml/hub_invalid_license.fxml"), //
|
||||
HUB_RECEIVE_KEY("/fxml/hub_receive_key.fxml"), //
|
||||
HUB_REGISTER_DEVICE("/fxml/hub_register_device.fxml"), //
|
||||
HUB_REGISTER_SUCCESS("/fxml/hub_register_success.fxml"), //
|
||||
|
||||
@@ -18,6 +18,7 @@ public enum FontAwesome5Icon {
|
||||
COPY("\uF0C5"), //
|
||||
CROWN("\uF521"), //
|
||||
EDIT("\uF044"), //
|
||||
EXCHANGE_ALT("\uF362"), //
|
||||
EXCLAMATION("\uF12A"), //
|
||||
EXCLAMATION_CIRCLE("\uF06A"), //
|
||||
EXCLAMATION_TRIANGLE("\uF071"), //
|
||||
@@ -25,6 +26,7 @@ public enum FontAwesome5Icon {
|
||||
EYE_SLASH("\uF070"), //
|
||||
FAST_FORWARD("\uF050"), //
|
||||
FILE("\uF15B"), //
|
||||
FILE_DOWNLOAD("\uF56D"), //
|
||||
FILE_IMPORT("\uF56F"), //
|
||||
FOLDER_OPEN("\uF07C"), //
|
||||
FUNNEL("\uF0B0"), //
|
||||
@@ -41,6 +43,7 @@ public enum FontAwesome5Icon {
|
||||
PLUS("\uF067"), //
|
||||
PRINT("\uF02F"), //
|
||||
QUESTION("\uF128"), //
|
||||
QUESTION_CIRCLE("\uf059"), //
|
||||
REDO("\uF01E"), //
|
||||
SEARCH("\uF002"), //
|
||||
SPINNER("\uF110"), //
|
||||
|
||||
@@ -43,7 +43,7 @@ public class SecurePasswordField extends TextField {
|
||||
private static final char WIPE_CHAR = ' ';
|
||||
private static final int INITIAL_BUFFER_SIZE = 50;
|
||||
private static final int GROW_BUFFER_SIZE = 50;
|
||||
private static final String DEFAULT_PLACEHOLDER = "●";
|
||||
private static final String DEFAULT_PLACEHOLDER = "•";
|
||||
private static final String STYLE_CLASS = "secure-password-field";
|
||||
private static final KeyCodeCombination SHORTCUT_BACKSPACE = new KeyCodeCombination(KeyCode.BACK_SPACE, KeyCombination.SHORTCUT_DOWN);
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Skymatic UG (haftungsbeschränkt).
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the accompanying LICENSE file.
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.ui.convertvault;
|
||||
|
||||
import dagger.BindsInstance;
|
||||
import dagger.Lazy;
|
||||
import dagger.Subcomponent;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
@ConvertVaultScoped
|
||||
@Subcomponent(modules = {ConvertVaultModule.class})
|
||||
public interface ConvertVaultComponent {
|
||||
|
||||
@ConvertVaultWindow
|
||||
Stage window();
|
||||
|
||||
@FxmlScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_START)
|
||||
Lazy<Scene> hubToPasswordScene();
|
||||
|
||||
default void showHubToPasswordWindow() {
|
||||
Stage stage = window();
|
||||
stage.setScene(hubToPasswordScene().get());
|
||||
stage.sizeToScene();
|
||||
stage.show();
|
||||
}
|
||||
|
||||
@Subcomponent.Factory
|
||||
interface Factory {
|
||||
|
||||
ConvertVaultComponent create(@BindsInstance @ConvertVaultWindow Vault vault, @BindsInstance @Named("convertVaultOwner") Stage owner);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package org.cryptomator.ui.convertvault;
|
||||
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.cryptofs.VaultConfig;
|
||||
import org.cryptomator.ui.changepassword.NewPasswordController;
|
||||
import org.cryptomator.ui.changepassword.PasswordStrengthUtil;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.common.StageFactory;
|
||||
import org.cryptomator.ui.recoverykey.RecoveryKeyFactory;
|
||||
import org.cryptomator.ui.recoverykey.RecoveryKeyValidateController;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
@Module
|
||||
abstract class ConvertVaultModule {
|
||||
|
||||
//TODO: if this fails, we cannot display an error
|
||||
@Provides
|
||||
@ConvertVaultWindow
|
||||
@ConvertVaultScoped
|
||||
static VaultConfig.UnverifiedVaultConfig vaultConfig(@ConvertVaultWindow Vault vault) {
|
||||
try {
|
||||
return vault.getVaultConfigCache().get();
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ConvertVaultWindow
|
||||
@ConvertVaultScoped
|
||||
static StringProperty provideRecoveryKeyProperty() {
|
||||
return new SimpleStringProperty();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ConvertVaultWindow
|
||||
@ConvertVaultScoped
|
||||
static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
|
||||
return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@ConvertVaultWindow
|
||||
@ConvertVaultScoped
|
||||
static Stage provideStage(StageFactory factory, @Named("convertVaultOwner") Stage owner, ResourceBundle resourceBundle) {
|
||||
Stage stage = factory.create();
|
||||
stage.setResizable(false);
|
||||
stage.initModality(Modality.WINDOW_MODAL);
|
||||
stage.initOwner(owner);
|
||||
stage.setTitle(resourceBundle.getString("convertVault.title"));
|
||||
return stage;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_START)
|
||||
@ConvertVaultScoped
|
||||
static Scene provideHubToPasswordStartScene(@ConvertVaultWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_START);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_CONVERT)
|
||||
@ConvertVaultScoped
|
||||
static Scene provideHubToPasswordConvertScene(@ConvertVaultWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_CONVERT);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_SUCCESS)
|
||||
@ConvertVaultScoped
|
||||
static Scene provideHubToPasswordSuccessScene(@ConvertVaultWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_SUCCESS);
|
||||
}
|
||||
|
||||
// ------------------
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(HubToPasswordStartController.class)
|
||||
abstract FxController bindHubToPasswordStartController(HubToPasswordStartController controller);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(HubToPasswordConvertController.class)
|
||||
abstract FxController bindHubToPasswordConvertController(HubToPasswordConvertController controller);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(HubToPasswordSuccessController.class)
|
||||
abstract FxController bindHubToPasswordSuccessController(HubToPasswordSuccessController controller);
|
||||
|
||||
|
||||
@Provides
|
||||
@IntoMap
|
||||
@FxControllerKey(NewPasswordController.class)
|
||||
static FxController provideNewPasswordController(ResourceBundle resourceBundle, PasswordStrengthUtil strengthRater) {
|
||||
return new NewPasswordController(resourceBundle, strengthRater);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@IntoMap
|
||||
@FxControllerKey(RecoveryKeyValidateController.class)
|
||||
static FxController bindRecoveryKeyValidateController(@ConvertVaultWindow Vault vault, @ConvertVaultWindow VaultConfig.UnverifiedVaultConfig vaultConfig, @ConvertVaultWindow StringProperty recoveryKey, RecoveryKeyFactory recoveryKeyFactory) {
|
||||
return new RecoveryKeyValidateController(vault, vaultConfig, recoveryKey, recoveryKeyFactory);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.cryptomator.ui.convertvault;
|
||||
|
||||
import javax.inject.Scope;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Scope
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface ConvertVaultScoped {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.cryptomator.ui.convertvault;
|
||||
|
||||
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 ConvertVaultWindow {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package org.cryptomator.ui.convertvault;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import dagger.Lazy;
|
||||
import org.cryptomator.common.Constants;
|
||||
import org.cryptomator.common.Passphrase;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.cryptofs.VaultConfig;
|
||||
import org.cryptomator.cryptofs.VaultVersionMismatchException;
|
||||
import org.cryptomator.cryptofs.common.BackupHelper;
|
||||
import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
|
||||
import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
|
||||
import org.cryptomator.ui.changepassword.NewPasswordController;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.fxapp.FxApplicationWindows;
|
||||
import org.cryptomator.ui.recoverykey.RecoveryKeyFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ContentDisplay;
|
||||
import javafx.stage.Stage;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import static java.nio.file.StandardOpenOption.CREATE_NEW;
|
||||
import static java.nio.file.StandardOpenOption.WRITE;
|
||||
import static org.cryptomator.common.Constants.MASTERKEY_BACKUP_SUFFIX;
|
||||
import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
|
||||
import static org.cryptomator.common.Constants.VAULTCONFIG_FILENAME;
|
||||
|
||||
public class HubToPasswordConvertController implements FxController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(HubToPasswordConvertController.class);
|
||||
|
||||
private final Stage window;
|
||||
private final Lazy<Scene> successScene;
|
||||
private final FxApplicationWindows applicationWindows;
|
||||
private final Vault vault;
|
||||
private final StringProperty recoveryKey;
|
||||
private final RecoveryKeyFactory recoveryKeyFactory;
|
||||
private final MasterkeyFileAccess masterkeyFileAccess;
|
||||
private final ExecutorService backgroundExecutorService;
|
||||
private final ResourceBundle resourceBundle;
|
||||
private final BooleanProperty conversionStarted;
|
||||
|
||||
@FXML
|
||||
NewPasswordController newPasswordController;
|
||||
public Button convertBtn;
|
||||
|
||||
@Inject
|
||||
public HubToPasswordConvertController(@ConvertVaultWindow Stage window, @FxmlScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_SUCCESS) Lazy<Scene> successScene, FxApplicationWindows applicationWindows, @ConvertVaultWindow Vault vault, @ConvertVaultWindow StringProperty recoveryKey, RecoveryKeyFactory recoveryKeyFactory, MasterkeyFileAccess masterkeyFileAccess, ExecutorService backgroundExecutorService, ResourceBundle resourceBundle) {
|
||||
this.window = window;
|
||||
this.successScene = successScene;
|
||||
this.applicationWindows = applicationWindows;
|
||||
this.vault = vault;
|
||||
this.recoveryKey = recoveryKey;
|
||||
this.recoveryKeyFactory = recoveryKeyFactory;
|
||||
this.masterkeyFileAccess = masterkeyFileAccess;
|
||||
this.backgroundExecutorService = backgroundExecutorService;
|
||||
this.resourceBundle = resourceBundle;
|
||||
this.conversionStarted = new SimpleBooleanProperty(false);
|
||||
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
convertBtn.disableProperty().bind(Bindings.createBooleanBinding( //
|
||||
() -> !newPasswordController.isGoodPassword() || conversionStarted.get(), //
|
||||
newPasswordController.goodPasswordProperty(), //
|
||||
conversionStarted));
|
||||
convertBtn.contentDisplayProperty().bind(Bindings.createObjectBinding( //
|
||||
() -> conversionStarted.getValue() ? ContentDisplay.LEFT : ContentDisplay.TEXT_ONLY, //
|
||||
conversionStarted));
|
||||
convertBtn.textProperty().bind(Bindings.createStringBinding( //
|
||||
() -> resourceBundle.getString("convertVault.convert.convertBtn." + (conversionStarted.get() ? "processing" : "before")), //
|
||||
conversionStarted));
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void close() {
|
||||
window.close();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void convert() {
|
||||
Preconditions.checkState(newPasswordController.isGoodPassword());
|
||||
LOG.info("Converting access method of vault {} from hub to password", vault.getPath());
|
||||
CompletableFuture.runAsync(() -> conversionStarted.setValue(true), Platform::runLater) //
|
||||
.thenRunAsync(this::convertInternal, backgroundExecutorService) //
|
||||
.whenCompleteAsync((result, exception) -> {
|
||||
if (exception == null) {
|
||||
LOG.info("Conversion of vault {} succeeded.", vault.getPath());
|
||||
window.setScene(successScene.get());
|
||||
} else {
|
||||
LOG.error("Conversion of vault {} failed.", vault.getPath(), exception);
|
||||
applicationWindows.showErrorWindow(exception, window, null);
|
||||
}
|
||||
}, Platform::runLater); //
|
||||
}
|
||||
|
||||
//visible for testing
|
||||
void convertInternal() throws CompletionException, IllegalArgumentException {
|
||||
var passphrase = newPasswordController.getNewPassword();
|
||||
var vaultPath = vault.getPath();
|
||||
try {
|
||||
//create masterkey
|
||||
recoveryKeyFactory.newMasterkeyFileWithPassphrase(vaultPath, recoveryKey.get(), passphrase);
|
||||
LOG.debug("Successfully created masterkey file for vault {}", vaultPath);
|
||||
//create password config
|
||||
Path passwordConfigPath = vaultPath.resolve("passwordBased." + VAULTCONFIG_FILENAME + ".tmp");
|
||||
passwordConfigPath = createPasswordConfig(passwordConfigPath, vaultPath.resolve(MASTERKEY_FILENAME), passphrase);
|
||||
//backup hub config
|
||||
var hubConfigPath = vaultPath.resolve(VAULTCONFIG_FILENAME);
|
||||
backupHubConfig(hubConfigPath);
|
||||
//replace hub by password
|
||||
Files.move(passwordConfigPath, hubConfigPath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
|
||||
} catch (MasterkeyLoadingFailedException e) {
|
||||
throw new CompletionException(new IOException("Vault conversion failed", e));
|
||||
} catch (IOException e) {
|
||||
throw new CompletionException("Vault conversion failed", e);
|
||||
} finally {
|
||||
passphrase.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
//visible for testing
|
||||
void backupHubConfig(Path hubConfigPath) throws IOException {
|
||||
byte[] hubConfigBytes = Files.readAllBytes(hubConfigPath);
|
||||
Path backupPath = hubConfigPath.resolveSibling(VAULTCONFIG_FILENAME + BackupHelper.generateFileIdSuffix(hubConfigBytes) + MASTERKEY_BACKUP_SUFFIX);
|
||||
Files.copy(hubConfigPath, backupPath, StandardCopyOption.REPLACE_EXISTING);
|
||||
LOG.debug("Successfully created hub config backup {}", backupPath.getFileName());
|
||||
}
|
||||
|
||||
//visible for testing
|
||||
Path createPasswordConfig(Path passwordConfigPath, Path masterkeyFile, Passphrase passphrase) throws IOException, MasterkeyLoadingFailedException {
|
||||
var unverifiedVaultConfig = vault.getVaultConfigCache().get();
|
||||
try (var masterkey = masterkeyFileAccess.load(masterkeyFile, passphrase)) {
|
||||
var hubConfig = unverifiedVaultConfig.verify(masterkey.getEncoded(), unverifiedVaultConfig.allegedVaultVersion());
|
||||
var passwordConfig = VaultConfig.createNew() //
|
||||
.cipherCombo(hubConfig.getCipherCombo()) //
|
||||
.shorteningThreshold(hubConfig.getShorteningThreshold()) //
|
||||
.build();
|
||||
if (passwordConfig.getVaultVersion() != hubConfig.getVaultVersion()) {
|
||||
throw new VaultVersionMismatchException("Only vaults of version " + passwordConfig.getVaultVersion() + " can be converted.");
|
||||
}
|
||||
var token = passwordConfig.toToken(Constants.DEFAULT_KEY_ID.toString(), masterkey.getEncoded());
|
||||
Files.writeString(passwordConfigPath, token, StandardCharsets.US_ASCII, WRITE, CREATE_NEW);
|
||||
LOG.debug("Successfully created password config {}", passwordConfigPath);
|
||||
return passwordConfigPath;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.cryptomator.ui.convertvault;
|
||||
|
||||
import dagger.Lazy;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.recoverykey.RecoveryKeyValidateController;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
public class HubToPasswordStartController implements FxController {
|
||||
|
||||
private final Stage window;
|
||||
private final Lazy<Scene> convertScene;
|
||||
|
||||
@FXML
|
||||
RecoveryKeyValidateController recoveryKeyValidateController;
|
||||
|
||||
@Inject
|
||||
public HubToPasswordStartController(@ConvertVaultWindow Stage window, @FxmlScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_CONVERT) Lazy<Scene> convertScene) {
|
||||
this.window = window;
|
||||
this.convertScene = convertScene;
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void close() {
|
||||
window.close();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void next() {
|
||||
window.setScene(convertScene.get());
|
||||
}
|
||||
|
||||
/* Getter/Setter */
|
||||
|
||||
public RecoveryKeyValidateController getValidateController() {
|
||||
return recoveryKeyValidateController;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.cryptomator.ui.convertvault;
|
||||
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
public class HubToPasswordSuccessController implements FxController {
|
||||
|
||||
private final Stage window;
|
||||
private final Vault vault;
|
||||
|
||||
@Inject
|
||||
HubToPasswordSuccessController(@ConvertVaultWindow Stage window, @ConvertVaultWindow Vault vault) {
|
||||
this.window = window;
|
||||
this.vault = vault;
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void close() {
|
||||
window.close();
|
||||
window.getOwner().hide();
|
||||
}
|
||||
|
||||
/* Observables */
|
||||
|
||||
public Vault getVault() {
|
||||
return vault;
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -1,8 +1,10 @@
|
||||
package org.cryptomator.ui.common;
|
||||
package org.cryptomator.ui.error;
|
||||
|
||||
import dagger.BindsInstance;
|
||||
import dagger.Subcomponent;
|
||||
import org.cryptomator.common.Nullable;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
+7
-2
@@ -1,8 +1,9 @@
|
||||
package org.cryptomator.ui.common;
|
||||
package org.cryptomator.ui.error;
|
||||
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.cryptomator.common.ErrorCode;
|
||||
import org.cryptomator.common.Nullable;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
@@ -29,9 +30,13 @@ public class ErrorController implements FxController {
|
||||
OS: %s / %s
|
||||
App: %s / %s
|
||||
|
||||
<!-- ✏️ Please describe what happened as accurately as possible. -->
|
||||
<!-- ✏ Please describe what happened as accurately as possible. -->
|
||||
|
||||
<!-- 📋 Please also copy and paste the detail text from the error window. -->
|
||||
|
||||
<!-- ℹ Text enclosed like this (chevrons, exclamation mark, two dashes) is not visible to others! -->
|
||||
|
||||
<!-- ❗ If the description or the detail text is missing, the discussion will be deleted. -->
|
||||
""";
|
||||
|
||||
private final Application application;
|
||||
+7
-1
@@ -1,10 +1,16 @@
|
||||
package org.cryptomator.ui.common;
|
||||
package org.cryptomator.ui.error;
|
||||
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import org.cryptomator.common.ErrorCode;
|
||||
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 javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.cryptomator.ui.forgetPassword;
|
||||
package org.cryptomator.ui.forgetpassword;
|
||||
|
||||
import dagger.BindsInstance;
|
||||
import dagger.Lazy;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.cryptomator.ui.forgetPassword;
|
||||
package org.cryptomator.ui.forgetpassword;
|
||||
|
||||
import org.cryptomator.common.keychain.KeychainManager;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.cryptomator.ui.forgetPassword;
|
||||
package org.cryptomator.ui.forgetpassword;
|
||||
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.cryptomator.ui.forgetPassword;
|
||||
package org.cryptomator.ui.forgetpassword;
|
||||
|
||||
import javax.inject.Scope;
|
||||
import java.lang.annotation.Documented;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package org.cryptomator.ui.forgetPassword;
|
||||
package org.cryptomator.ui.forgetpassword;
|
||||
|
||||
import javax.inject.Qualifier;
|
||||
import java.lang.annotation.Documented;
|
||||
@@ -7,9 +7,7 @@ package org.cryptomator.ui.fxapp;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.ui.common.ErrorComponent;
|
||||
import org.cryptomator.ui.common.StageFactory;
|
||||
import org.cryptomator.ui.error.ErrorComponent;
|
||||
import org.cryptomator.ui.lock.LockComponent;
|
||||
import org.cryptomator.ui.mainwindow.MainWindowComponent;
|
||||
import org.cryptomator.ui.preferences.PreferencesComponent;
|
||||
@@ -18,13 +16,9 @@ import org.cryptomator.ui.quit.QuitComponent;
|
||||
import org.cryptomator.ui.traymenu.TrayMenuComponent;
|
||||
import org.cryptomator.ui.unlock.UnlockComponent;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javafx.scene.image.Image;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Module(includes = {UpdateCheckerModule.class}, subcomponents = {TrayMenuComponent.class, MainWindowComponent.class, PreferencesComponent.class, UnlockComponent.class, LockComponent.class, QuitComponent.class, ErrorComponent.class})
|
||||
abstract class FxApplicationModule {
|
||||
|
||||
@@ -5,7 +5,7 @@ import dagger.Lazy;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.common.vaults.VaultState;
|
||||
import org.cryptomator.integrations.tray.TrayIntegrationProvider;
|
||||
import org.cryptomator.ui.common.ErrorComponent;
|
||||
import org.cryptomator.ui.error.ErrorComponent;
|
||||
import org.cryptomator.ui.lock.LockComponent;
|
||||
import org.cryptomator.ui.mainwindow.MainWindowComponent;
|
||||
import org.cryptomator.ui.preferences.PreferencesComponent;
|
||||
|
||||
@@ -15,8 +15,6 @@ import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.common.NewPasswordController;
|
||||
import org.cryptomator.ui.common.PasswordStrengthUtil;
|
||||
import org.cryptomator.ui.keyloading.KeyLoading;
|
||||
import org.cryptomator.ui.keyloading.KeyLoadingScoped;
|
||||
import org.cryptomator.ui.keyloading.KeyLoadingStrategy;
|
||||
@@ -87,6 +85,13 @@ public abstract class HubKeyLoadingModule {
|
||||
@StringKey(HubKeyLoadingStrategy.SCHEME_HUB_HTTPS)
|
||||
abstract KeyLoadingStrategy bindHubKeyLoadingStrategyToHubHttps(HubKeyLoadingStrategy strategy);
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.HUB_NO_KEYCHAIN)
|
||||
@KeyLoadingScoped
|
||||
static Scene provideHubNoKeychainScene(@KeyLoading FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.HUB_NO_KEYCHAIN);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.HUB_AUTH_FLOW)
|
||||
@KeyLoadingScoped
|
||||
@@ -95,10 +100,10 @@ public abstract class HubKeyLoadingModule {
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.HUB_LICENSE_EXCEEDED)
|
||||
@FxmlScene(FxmlFile.HUB_INVALID_LICENSE)
|
||||
@KeyLoadingScoped
|
||||
static Scene provideLicenseExceededScene(@KeyLoading FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.HUB_LICENSE_EXCEEDED);
|
||||
static Scene provideInvalidLicenseScene(@KeyLoading FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.HUB_INVALID_LICENSE);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -138,20 +143,18 @@ public abstract class HubKeyLoadingModule {
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(AuthFlowController.class)
|
||||
abstract FxController bindAuthFlowController(AuthFlowController controller);
|
||||
|
||||
@Provides
|
||||
@IntoMap
|
||||
@FxControllerKey(NewPasswordController.class)
|
||||
static FxController provideNewPasswordController(ResourceBundle resourceBundle, PasswordStrengthUtil strengthRater) {
|
||||
return new NewPasswordController(resourceBundle, strengthRater);
|
||||
}
|
||||
@FxControllerKey(NoKeychainController.class)
|
||||
abstract FxController bindNoKeychainController(NoKeychainController controller);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(LicenseExceededController.class)
|
||||
abstract FxController bindLicenseExceededController(LicenseExceededController controller);
|
||||
@FxControllerKey(AuthFlowController.class)
|
||||
abstract FxController bindAuthFlowController(AuthFlowController controller);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(InvalidLicenseController.class)
|
||||
abstract FxController bindInvalidLicenseController(InvalidLicenseController controller);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
|
||||
@@ -3,6 +3,8 @@ package org.cryptomator.ui.keyloading.hub;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.nimbusds.jose.JWEObject;
|
||||
import dagger.Lazy;
|
||||
import org.cryptomator.common.keychain.KeychainManager;
|
||||
import org.cryptomator.common.keychain.NoKeychainAccessProviderException;
|
||||
import org.cryptomator.common.settings.DeviceKey;
|
||||
import org.cryptomator.cryptolib.api.Masterkey;
|
||||
import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
|
||||
@@ -27,19 +29,23 @@ import java.util.concurrent.ExecutionException;
|
||||
public class HubKeyLoadingStrategy implements KeyLoadingStrategy {
|
||||
|
||||
private static final String SCHEME_PREFIX = "hub+";
|
||||
static final String SCHEME_HUB_HTTP = SCHEME_PREFIX + "http";
|
||||
static final String SCHEME_HUB_HTTPS = SCHEME_PREFIX + "https";
|
||||
public static final String SCHEME_HUB_HTTP = SCHEME_PREFIX + "http";
|
||||
public static final String SCHEME_HUB_HTTPS = SCHEME_PREFIX + "https";
|
||||
|
||||
private final Stage window;
|
||||
private final KeychainManager keychainManager;
|
||||
private final Lazy<Scene> authFlowScene;
|
||||
private final Lazy<Scene> noKeychainScene;
|
||||
private final CompletableFuture<JWEObject> result;
|
||||
private final DeviceKey deviceKey;
|
||||
|
||||
@Inject
|
||||
public HubKeyLoadingStrategy(@KeyLoading Stage window, @FxmlScene(FxmlFile.HUB_AUTH_FLOW) Lazy<Scene> authFlowScene, CompletableFuture<JWEObject> result, DeviceKey deviceKey, @Named("windowTitle") String windowTitle) {
|
||||
public HubKeyLoadingStrategy(@KeyLoading Stage window, @FxmlScene(FxmlFile.HUB_AUTH_FLOW) Lazy<Scene> authFlowScene, @FxmlScene(FxmlFile.HUB_NO_KEYCHAIN) Lazy<Scene> noKeychainScene, CompletableFuture<JWEObject> result, DeviceKey deviceKey, KeychainManager keychainManager, @Named("windowTitle") String windowTitle) {
|
||||
this.window = window;
|
||||
this.keychainManager = keychainManager;
|
||||
window.setTitle(windowTitle);
|
||||
this.authFlowScene = authFlowScene;
|
||||
this.noKeychainScene = noKeychainScene;
|
||||
this.result = result;
|
||||
this.deviceKey = deviceKey;
|
||||
}
|
||||
@@ -48,9 +54,16 @@ public class HubKeyLoadingStrategy implements KeyLoadingStrategy {
|
||||
public Masterkey loadKey(URI keyId) throws MasterkeyLoadingFailedException {
|
||||
Preconditions.checkArgument(keyId.getScheme().startsWith(SCHEME_PREFIX));
|
||||
try {
|
||||
startAuthFlow();
|
||||
if (!keychainManager.isSupported()) {
|
||||
throw new NoKeychainAccessProviderException();
|
||||
}
|
||||
var keypair = deviceKey.get();
|
||||
showWindow(authFlowScene);
|
||||
var jwe = result.get();
|
||||
return JWEHelper.decrypt(jwe, deviceKey.get().getPrivate());
|
||||
return JWEHelper.decrypt(jwe, keypair.getPrivate());
|
||||
} catch (NoKeychainAccessProviderException e) {
|
||||
showWindow(noKeychainScene);
|
||||
throw new UnlockCancelledException("Unlock canceled due to missing prerequisites", e);
|
||||
} catch (DeviceKey.DeviceKeyRetrievalException e) {
|
||||
throw new MasterkeyLoadingFailedException("Failed to load keypair", e);
|
||||
} catch (CancellationException e) {
|
||||
@@ -63,9 +76,9 @@ public class HubKeyLoadingStrategy implements KeyLoadingStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
private void startAuthFlow() {
|
||||
private void showWindow(Lazy<Scene> scene) {
|
||||
Platform.runLater(() -> {
|
||||
window.setScene(authFlowScene.get());
|
||||
window.setScene(scene.get());
|
||||
window.show();
|
||||
Window owner = window.getOwner();
|
||||
if (owner != null) {
|
||||
|
||||
+2
-2
@@ -7,12 +7,12 @@ import javax.inject.Inject;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
public class LicenseExceededController implements FxController {
|
||||
public class InvalidLicenseController implements FxController {
|
||||
|
||||
private final Stage window;
|
||||
|
||||
@Inject
|
||||
public LicenseExceededController(@KeyLoading Stage window) {
|
||||
public InvalidLicenseController(@KeyLoading Stage window) {
|
||||
this.window = window;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.cryptomator.ui.keyloading.hub;
|
||||
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.fxapp.FxApplicationWindows;
|
||||
import org.cryptomator.ui.keyloading.KeyLoading;
|
||||
import org.cryptomator.ui.preferences.SelectedPreferencesTab;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
public class NoKeychainController implements FxController {
|
||||
|
||||
private final Stage window;
|
||||
private final FxApplicationWindows appWindows;
|
||||
|
||||
@Inject
|
||||
public NoKeychainController(@KeyLoading Stage window, FxApplicationWindows appWindows) {
|
||||
this.window = window;
|
||||
this.appWindows = appWindows;
|
||||
}
|
||||
|
||||
|
||||
public void cancel() {
|
||||
window.close();
|
||||
}
|
||||
|
||||
public void openPreferences() {
|
||||
appWindows.showPreferencesWindow(SelectedPreferencesTab.GENERAL);
|
||||
window.close();
|
||||
}
|
||||
}
|
||||
@@ -42,11 +42,11 @@ public class ReceiveKeyController implements FxController {
|
||||
private final Lazy<Scene> registerDeviceScene;
|
||||
private final Lazy<Scene> unauthorizedScene;
|
||||
private final URI vaultBaseUri;
|
||||
private final Lazy<Scene> licenseExceededScene;
|
||||
private final Lazy<Scene> invalidLicenseScene;
|
||||
private final HttpClient httpClient;
|
||||
|
||||
@Inject
|
||||
public ReceiveKeyController(@KeyLoading Vault vault, ExecutorService executor, @KeyLoading Stage window, @Named("deviceId") String deviceId, @Named("bearerToken") AtomicReference<String> tokenRef, CompletableFuture<JWEObject> result, @FxmlScene(FxmlFile.HUB_REGISTER_DEVICE) Lazy<Scene> registerDeviceScene, @FxmlScene(FxmlFile.HUB_UNAUTHORIZED_DEVICE) Lazy<Scene> unauthorizedScene, @FxmlScene(FxmlFile.HUB_LICENSE_EXCEEDED) Lazy<Scene> licenseExceededScene) {
|
||||
public ReceiveKeyController(@KeyLoading Vault vault, ExecutorService executor, @KeyLoading Stage window, @Named("deviceId") String deviceId, @Named("bearerToken") AtomicReference<String> tokenRef, CompletableFuture<JWEObject> result, @FxmlScene(FxmlFile.HUB_REGISTER_DEVICE) Lazy<Scene> registerDeviceScene, @FxmlScene(FxmlFile.HUB_UNAUTHORIZED_DEVICE) Lazy<Scene> unauthorizedScene, @FxmlScene(FxmlFile.HUB_INVALID_LICENSE) Lazy<Scene> invalidLicenseScene) {
|
||||
this.window = window;
|
||||
this.deviceId = deviceId;
|
||||
this.bearerToken = Objects.requireNonNull(tokenRef.get());
|
||||
@@ -54,7 +54,7 @@ public class ReceiveKeyController implements FxController {
|
||||
this.registerDeviceScene = registerDeviceScene;
|
||||
this.unauthorizedScene = unauthorizedScene;
|
||||
this.vaultBaseUri = getVaultBaseUri(vault);
|
||||
this.licenseExceededScene = licenseExceededScene;
|
||||
this.invalidLicenseScene = invalidLicenseScene;
|
||||
this.window.addEventHandler(WindowEvent.WINDOW_HIDING, this::windowClosed);
|
||||
this.httpClient = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).executor(executor).build();
|
||||
}
|
||||
@@ -96,7 +96,7 @@ public class ReceiveKeyController implements FxController {
|
||||
}
|
||||
|
||||
private void licenseExceeded() {
|
||||
window.setScene(licenseExceededScene.get());
|
||||
window.setScene(invalidLicenseScene.get());
|
||||
}
|
||||
|
||||
private void needsDeviceRegistration() {
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ import dagger.multibindings.StringKey;
|
||||
import org.cryptomator.common.keychain.KeychainManager;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.integrations.keychain.KeychainAccessException;
|
||||
import org.cryptomator.ui.forgetPassword.ForgetPasswordComponent;
|
||||
import org.cryptomator.ui.forgetpassword.ForgetPasswordComponent;
|
||||
import org.cryptomator.ui.keyloading.KeyLoading;
|
||||
import org.cryptomator.ui.keyloading.KeyLoadingScoped;
|
||||
import org.cryptomator.ui.keyloading.KeyLoadingStrategy;
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.WeakBindings;
|
||||
import org.cryptomator.ui.controls.NiceSecurePasswordField;
|
||||
import org.cryptomator.ui.forgetPassword.ForgetPasswordComponent;
|
||||
import org.cryptomator.ui.forgetpassword.ForgetPasswordComponent;
|
||||
import org.cryptomator.ui.keyloading.KeyLoading;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -53,7 +53,7 @@ public class LockForcedController implements FxController {
|
||||
}
|
||||
|
||||
public boolean isForceSupported() {
|
||||
return false;//vault.supportsForcedUnmount(); TODO
|
||||
return vault.supportsForcedUnmount();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,33 +3,17 @@ package org.cryptomator.ui.mainwindow;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.common.vaults.VaultListManager;
|
||||
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
|
||||
import org.cryptomator.cryptofs.DirStructure;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.wrongfilealert.WrongFileAlertComponent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.input.DragEvent;
|
||||
import javafx.scene.input.TransferMode;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.stage.Stage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.cryptomator.common.Constants.CRYPTOMATOR_FILENAME_EXT;
|
||||
import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
|
||||
import static org.cryptomator.common.Constants.VAULTCONFIG_FILENAME;
|
||||
|
||||
@MainWindowScoped
|
||||
public class MainWindowController implements FxController {
|
||||
@@ -37,28 +21,19 @@ public class MainWindowController implements FxController {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MainWindowController.class);
|
||||
|
||||
private final Stage window;
|
||||
private final VaultListManager vaultListManager;
|
||||
private final ReadOnlyObjectProperty<Vault> selectedVault;
|
||||
private final WrongFileAlertComponent.Builder wrongFileAlert;
|
||||
private final BooleanProperty draggingOver = new SimpleBooleanProperty();
|
||||
private final BooleanProperty draggingVaultOver = new SimpleBooleanProperty();
|
||||
|
||||
public StackPane root;
|
||||
|
||||
@Inject
|
||||
public MainWindowController(@MainWindow Stage window, VaultListManager vaultListManager, ObjectProperty<Vault> selectedVault, WrongFileAlertComponent.Builder wrongFileAlert) {
|
||||
public MainWindowController(@MainWindow Stage window, ObjectProperty<Vault> selectedVault) {
|
||||
this.window = window;
|
||||
this.vaultListManager = vaultListManager;
|
||||
this.selectedVault = selectedVault;
|
||||
this.wrongFileAlert = wrongFileAlert;
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
LOG.trace("init MainWindowController");
|
||||
root.setOnDragEntered(this::handleDragEvent);
|
||||
root.setOnDragOver(this::handleDragEvent);
|
||||
root.setOnDragDropped(this::handleDragEvent);
|
||||
root.setOnDragExited(this::handleDragEvent);
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
root.getStyleClass().add("os-windows");
|
||||
}
|
||||
@@ -72,65 +47,4 @@ public class MainWindowController implements FxController {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDragEvent(DragEvent event) {
|
||||
if (DragEvent.DRAG_ENTERED.equals(event.getEventType()) && event.getGestureSource() == null) {
|
||||
draggingOver.set(true);
|
||||
} else if (DragEvent.DRAG_OVER.equals(event.getEventType()) && event.getGestureSource() == null && event.getDragboard().hasFiles()) {
|
||||
event.acceptTransferModes(TransferMode.ANY);
|
||||
draggingVaultOver.set(event.getDragboard().getFiles().stream().map(File::toPath).anyMatch(this::containsVault));
|
||||
} else if (DragEvent.DRAG_DROPPED.equals(event.getEventType()) && event.getGestureSource() == null && event.getDragboard().hasFiles()) {
|
||||
Set<Path> vaultPaths = event.getDragboard().getFiles().stream().map(File::toPath).filter(this::containsVault).collect(Collectors.toSet());
|
||||
if (vaultPaths.isEmpty()) {
|
||||
wrongFileAlert.build().showWrongFileAlertWindow();
|
||||
} else {
|
||||
vaultPaths.forEach(this::addVault);
|
||||
}
|
||||
event.setDropCompleted(!vaultPaths.isEmpty());
|
||||
event.consume();
|
||||
} else if (DragEvent.DRAG_EXITED.equals(event.getEventType())) {
|
||||
draggingOver.set(false);
|
||||
draggingVaultOver.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean containsVault(Path path) {
|
||||
try {
|
||||
if (path.getFileName().toString().endsWith(CRYPTOMATOR_FILENAME_EXT)) {
|
||||
path = path.getParent();
|
||||
}
|
||||
return CryptoFileSystemProvider.checkDirStructureForVault(path, VAULTCONFIG_FILENAME, MASTERKEY_FILENAME) != DirStructure.UNRELATED;
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void addVault(Path pathToVault) {
|
||||
try {
|
||||
if (pathToVault.getFileName().toString().endsWith(CRYPTOMATOR_FILENAME_EXT)) {
|
||||
vaultListManager.add(pathToVault.getParent());
|
||||
} else {
|
||||
vaultListManager.add(pathToVault);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.debug("Not a vault: {}", pathToVault);
|
||||
}
|
||||
}
|
||||
|
||||
/* Getter/Setter */
|
||||
|
||||
public BooleanProperty draggingOverProperty() {
|
||||
return draggingOver;
|
||||
}
|
||||
|
||||
public boolean isDraggingOver() {
|
||||
return draggingOver.get();
|
||||
}
|
||||
|
||||
public BooleanProperty draggingVaultOverProperty() {
|
||||
return draggingVaultOver;
|
||||
}
|
||||
|
||||
public boolean isDraggingVaultOver() {
|
||||
return draggingVaultOver.get();
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user