mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-09-23 16:34:34 +00:00
Compare commits
454
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0c0060262a | ||
|
|
9af4ffe83b | ||
|
|
c6f963793d | ||
|
|
8c34fc76c5 | ||
|
|
785cf7a9a6 | ||
|
|
c63837c4ce | ||
|
|
b1a3ef9023 | ||
|
|
32436f779f | ||
|
|
ccc6f605ba | ||
|
|
f338d2447b | ||
|
|
179240b325 | ||
|
|
32a65bddce | ||
|
|
710cdf800d | ||
|
|
1d6edb8373 | ||
|
|
a3d30612ec | ||
|
|
6acda9b13c | ||
|
|
28cb812dab | ||
|
|
68ea4af0ad | ||
|
|
0af0a9e440 | ||
|
|
0989c735c0 | ||
|
|
a3492b9ea3 | ||
|
|
e345e6415f | ||
|
|
5b6d09308b | ||
|
|
49bda58993 | ||
|
|
32d7189a12 | ||
|
|
1253b7db2b | ||
|
|
067a7ad3ee | ||
|
|
a9ec76a344 | ||
|
|
085f762a35 | ||
|
|
7dd1c3576f | ||
|
|
d23bd2865a | ||
|
|
4429d57b5e | ||
|
|
2ff71ed7b0 | ||
|
|
82de8b6994 | ||
|
|
d4cba2fd6e | ||
|
|
ff80f634d2 | ||
|
|
6386dd3d50 | ||
|
|
a3f05db189 | ||
|
|
151ef6c7b2 | ||
|
|
72fd38baf1 | ||
|
|
532ffb1202 | ||
|
|
2a704d5eb4 | ||
|
|
e8f8466d9a | ||
|
|
9297562c99 | ||
|
|
7d62fc78de | ||
|
|
ba627d0d60 | ||
|
|
8e7e7de358 | ||
|
|
10c60d7492 | ||
|
|
aa03bd119a | ||
|
|
325ffda9af | ||
|
|
d1270ceeb2 | ||
|
|
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 | ||
|
|
1a358f06e8 | ||
|
|
db4d845a5b | ||
|
|
0d6d7b0dd6 | ||
|
|
9dfd8adcce | ||
|
|
433eecc6a8 | ||
|
|
36ed4554b2 | ||
|
|
c2dac30f2d | ||
|
|
63a89b5bcf | ||
|
|
12b53acd22 | ||
|
|
9105d1af16 | ||
|
|
de46b91420 | ||
|
|
67b40649bc | ||
|
|
c41af77108 | ||
|
|
ba66d4bfce | ||
|
|
c45a00377d | ||
|
|
f9d588320c | ||
|
|
c61087e697 | ||
|
|
0725a63b09 | ||
|
|
ebcd0adf78 | ||
|
|
0e7ec8eb37 | ||
|
|
0e9b115647 | ||
|
|
5ba137dda5 | ||
|
|
db928ba034 | ||
|
|
2cc01be236 | ||
|
|
ba2a4955d0 | ||
|
|
d1971e3c2a | ||
|
|
5665984a9b | ||
|
|
1f2225991a | ||
|
|
1f0fe161fd | ||
|
|
4ff8bbaa62 | ||
|
|
e188169916 | ||
|
|
1b9480293a | ||
|
|
d8b71db8e5 | ||
|
|
4bd99d2b66 | ||
|
|
61027852e1 | ||
|
|
512500aaef | ||
|
|
f9d28f20b3 | ||
|
|
7f79c554f7 | ||
|
|
3cbe4aa7eb | ||
|
|
06922717c4 | ||
|
|
32399c4a09 | ||
|
|
00a3692dcf | ||
|
|
83b198d491 | ||
|
|
8086ec1c10 | ||
|
|
b2b49f4d2f | ||
|
|
d6e14dab9a | ||
|
|
497ddcfc9c | ||
|
|
169039903d | ||
|
|
3641b34c2d | ||
|
|
42400d1f0c | ||
|
|
8f7f8ffb11 | ||
|
|
3016d35c9b | ||
|
|
f21b8a0f7a | ||
|
|
0c1bbc5bfd | ||
|
|
d932091021 | ||
|
|
216abf224e | ||
|
|
d5523f07bd | ||
|
|
e097bea1f5 | ||
|
|
920866b1a1 | ||
|
|
c41ffe2568 | ||
|
|
792fe1eafe | ||
|
|
348bc2b2ec | ||
|
|
7bac78bc5d | ||
|
|
65e1993b43 | ||
|
|
b98eb8c656 | ||
|
|
33ebc17619 | ||
|
|
ba7029968d | ||
|
|
a3fc68ab6f | ||
|
|
abf944a130 | ||
|
|
99bc4dbdc5 | ||
|
|
019292f1db | ||
|
|
2f9818aade | ||
|
|
9cec45dc1f | ||
|
|
5f55530b4a | ||
|
|
96de2556a9 | ||
|
|
db63a82d76 | ||
|
|
11aea06ecf | ||
|
|
932cfd2200 | ||
|
|
edaa2b7391 | ||
|
|
9984b2af9b | ||
|
|
34986f5919 | ||
|
|
23d9521724 | ||
|
|
4dc1d59305 | ||
|
|
74e3c28441 | ||
|
|
6e526ba796 | ||
|
|
b978044383 | ||
|
|
6325c6f450 | ||
|
|
dd79b46d72 | ||
|
|
d896fe21b5 | ||
|
|
6983d9d72d | ||
|
|
faf39c2507 | ||
|
|
083d0cfbc4 | ||
|
|
9ca8072ab6 | ||
|
|
3223ea2e5d | ||
|
|
83af5e796f | ||
|
|
9d9f118a32 | ||
|
|
1b0eb34734 | ||
|
|
79952418f4 | ||
|
|
65e26971ff | ||
|
|
13debaafbe | ||
|
|
5729e2885d | ||
|
|
043184cf53 | ||
|
|
38062f9a8d | ||
|
|
14d0d95f23 | ||
|
|
759c21e5cf | ||
|
|
d8ed9f854a | ||
|
|
1414ab4681 | ||
|
|
1486826883 | ||
|
|
dda7255d8e | ||
|
|
6caf132cfb | ||
|
|
dc310c009f | ||
|
|
445be3b668 | ||
|
|
f852ae0392 | ||
|
|
e5e606f3ae | ||
|
|
e3c609351f | ||
|
|
01412070ad | ||
|
|
4944a634fb |
@@ -37,12 +37,17 @@ body:
|
|||||||
id: volume-type
|
id: volume-type
|
||||||
attributes:
|
attributes:
|
||||||
label: Volume Type
|
label: Volume Type
|
||||||
description: What is selected under Settings → Virtual Drive?
|
description: What volume type is selected under Settings → Virtual Drive?
|
||||||
multiple: true
|
|
||||||
options:
|
options:
|
||||||
- FUSE
|
- WinFsp
|
||||||
- Dokany
|
- WinFsp (Local Drive)
|
||||||
- WebDAV
|
- FUSE-T
|
||||||
|
- macFUSE
|
||||||
|
- WebDAV (Windows Explorer)
|
||||||
|
- WebDAV (AppleScript)
|
||||||
|
- WebDAV (gio)
|
||||||
|
- WebDAV (HTTP Address)
|
||||||
|
- Dokany (1.5)
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: textarea
|
- 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
|
|
||||||
@@ -10,49 +10,43 @@ on:
|
|||||||
required: false
|
required: false
|
||||||
|
|
||||||
env:
|
env:
|
||||||
JAVA_VERSION: 19
|
JAVA_VERSION: 20
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
get-version:
|
||||||
|
uses: ./.github/workflows/get-version.yml
|
||||||
|
with:
|
||||||
|
version: ${{ inputs.version }}
|
||||||
|
|
||||||
build:
|
build:
|
||||||
name: Build AppImage
|
name: Build AppImage
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
needs: [get-version]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Setup Java
|
- name: Setup Java
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: 'zulu'
|
distribution: 'zulu'
|
||||||
java-version: ${{ env.JAVA_VERSION }}
|
java-version: ${{ env.JAVA_VERSION }}
|
||||||
|
java-package: 'jdk+fx'
|
||||||
cache: 'maven'
|
cache: 'maven'
|
||||||
- id: versions
|
- name: Ensure major jfx version in pom equals in jdk
|
||||||
name: Apply version information
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
if [[ $GITHUB_REF =~ refs/tags/[0-9]+\.[0-9]+\.[0-9]+.* ]]; then
|
$jfxPomVersion = (&mvn help:evaluate "-Dexpression=javafx.version" -q -DforceStdout) -split "\."
|
||||||
SEM_VER_STR=${GITHUB_REF##*/}
|
$jfxJdkVersion = ((Get-Content -path "${env:JAVA_HOME}/lib/javafx.properties" | Where-Object {$_ -like 'javafx.version=*' }) -replace '.*=','') -split "\."
|
||||||
mvn versions:set -DnewVersion=${SEM_VER_STR}
|
if ($jfxPomVersion[0] -ne $jfxJdkVersion[0]) {
|
||||||
elif [[ "${{ github.event.inputs.version }}" =~ [0-9]+\.[0-9]+\.[0-9]+.* ]]; then
|
Write-Error "Major part of JavaFX version in pom($($jfxPomVersion[0])) does not match the version in JDK($($jfxJdkVersion[0])) "
|
||||||
SEM_VER_STR="${{ github.event.inputs.version }}"
|
exit 1
|
||||||
mvn versions:set -DnewVersion=${SEM_VER_STR}
|
}
|
||||||
else
|
- name: Set version
|
||||||
SEM_VER_STR=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout`
|
run : mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }}
|
||||||
fi
|
|
||||||
SEM_VER_NUM=`echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/'`
|
|
||||||
REVCOUNT=`git rev-list --count HEAD`
|
|
||||||
echo "::set-output name=semVerStr::${SEM_VER_STR}"
|
|
||||||
echo "::set-output name=semVerNum::${SEM_VER_NUM}"
|
|
||||||
echo "::set-output name=revNum::${REVCOUNT}"
|
|
||||||
- name: Validate Version
|
|
||||||
uses: skymatic/semver-validation-action@v1
|
|
||||||
with:
|
|
||||||
version: ${{ steps.versions.outputs.semVerStr }}
|
|
||||||
- name: Run maven
|
- name: Run maven
|
||||||
run: mvn -B clean package -Pdependency-check,linux -DskipTests
|
run: mvn -B clean package -Pdependency-check,linux -DskipTests
|
||||||
- name: Patch target dir
|
- name: Patch target dir
|
||||||
run: |
|
run: |
|
||||||
cp LICENSE.txt target
|
cp LICENSE.txt target
|
||||||
cp dist/linux/launcher.sh target
|
|
||||||
cp target/cryptomator-*.jar target/mods
|
cp target/cryptomator-*.jar target/mods
|
||||||
- name: Run jlink
|
- name: Run jlink
|
||||||
run: >
|
run: >
|
||||||
@@ -60,7 +54,7 @@ jobs:
|
|||||||
--verbose
|
--verbose
|
||||||
--output runtime
|
--output runtime
|
||||||
--module-path "${JAVA_HOME}/jmods"
|
--module-path "${JAVA_HOME}/jmods"
|
||||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr
|
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.security.auth,jdk.accessibility,jdk.management.jfr
|
||||||
--strip-native-commands
|
--strip-native-commands
|
||||||
--no-header-files
|
--no-header-files
|
||||||
--no-man-pages
|
--no-man-pages
|
||||||
@@ -69,8 +63,8 @@ jobs:
|
|||||||
- name: Prepare additional launcher
|
- name: Prepare additional launcher
|
||||||
run: envsubst '${SEMVER_STR} ${REVISION_NUM}' < dist/linux/launcher-gtk2.properties > launcher-gtk2.properties
|
run: envsubst '${SEMVER_STR} ${REVISION_NUM}' < dist/linux/launcher-gtk2.properties > launcher-gtk2.properties
|
||||||
env:
|
env:
|
||||||
SEMVER_STR: ${{ steps.versions.outputs.semVerStr }}
|
SEMVER_STR: ${{ needs.get-version.outputs.semVerStr }}
|
||||||
REVISION_NUM: ${{ steps.versions.outputs.revNum }}
|
REVISION_NUM: ${{ needs.get-version.outputs.revNum }}
|
||||||
- name: Run jpackage
|
- name: Run jpackage
|
||||||
run: >
|
run: >
|
||||||
${JAVA_HOME}/bin/jpackage
|
${JAVA_HOME}/bin/jpackage
|
||||||
@@ -83,11 +77,13 @@ jobs:
|
|||||||
--dest appdir
|
--dest appdir
|
||||||
--name Cryptomator
|
--name Cryptomator
|
||||||
--vendor "Skymatic GmbH"
|
--vendor "Skymatic GmbH"
|
||||||
--copyright "(C) 2016 - 2022 Skymatic GmbH"
|
--copyright "(C) 2016 - 2023 Skymatic GmbH"
|
||||||
--app-version "${{ steps.versions.outputs.semVerNum }}.${{ steps.versions.outputs.revNum }}"
|
--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"
|
||||||
--java-options "-Xss5m"
|
--java-options "-Xss5m"
|
||||||
--java-options "-Xmx256m"
|
--java-options "-Xmx256m"
|
||||||
--java-options "-Dcryptomator.appVersion=\"${{ steps.versions.outputs.semVerStr }}\""
|
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
|
||||||
--java-options "-Dfile.encoding=\"utf-8\""
|
--java-options "-Dfile.encoding=\"utf-8\""
|
||||||
--java-options "-Dcryptomator.logDir=\"~/.local/share/Cryptomator/logs\""
|
--java-options "-Dcryptomator.logDir=\"~/.local/share/Cryptomator/logs\""
|
||||||
--java-options "-Dcryptomator.pluginDir=\"~/.local/share/Cryptomator/plugins\""
|
--java-options "-Dcryptomator.pluginDir=\"~/.local/share/Cryptomator/plugins\""
|
||||||
@@ -96,7 +92,7 @@ jobs:
|
|||||||
--java-options "-Dcryptomator.ipcSocketPath=\"~/.config/Cryptomator/ipc.socket\""
|
--java-options "-Dcryptomator.ipcSocketPath=\"~/.config/Cryptomator/ipc.socket\""
|
||||||
--java-options "-Dcryptomator.mountPointsDir=\"~/.local/share/Cryptomator/mnt\""
|
--java-options "-Dcryptomator.mountPointsDir=\"~/.local/share/Cryptomator/mnt\""
|
||||||
--java-options "-Dcryptomator.showTrayIcon=false"
|
--java-options "-Dcryptomator.showTrayIcon=false"
|
||||||
--java-options "-Dcryptomator.buildNumber=\"appimage-${{ steps.versions.outputs.revNum }}\""
|
--java-options "-Dcryptomator.buildNumber=\"appimage-${{ needs.get-version.outputs.revNum }}\""
|
||||||
--add-launcher Cryptomator-gtk2=launcher-gtk2.properties
|
--add-launcher Cryptomator-gtk2=launcher-gtk2.properties
|
||||||
--resource-dir dist/linux/resources
|
--resource-dir dist/linux/resources
|
||||||
- name: Patch Cryptomator.AppDir
|
- name: Patch Cryptomator.AppDir
|
||||||
@@ -114,12 +110,6 @@ jobs:
|
|||||||
ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/.DirIcon
|
ln -s usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/.DirIcon
|
||||||
ln -s usr/share/applications/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/Cryptomator.desktop
|
ln -s usr/share/applications/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/Cryptomator.desktop
|
||||||
ln -s bin/cryptomator.sh Cryptomator.AppDir/AppRun
|
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
|
- name: Download AppImageKit
|
||||||
run: |
|
run: |
|
||||||
curl -L https://github.com/AppImage/AppImageKit/releases/download/13/appimagetool-x86_64.AppImage -o appimagetool.AppImage
|
curl -L https://github.com/AppImage/AppImageKit/releases/download/13/appimagetool-x86_64.AppImage -o appimagetool.AppImage
|
||||||
@@ -134,7 +124,7 @@ jobs:
|
|||||||
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
|
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
|
||||||
- name: Build AppImage
|
- name: Build AppImage
|
||||||
run: >
|
run: >
|
||||||
./squashfs-root/AppRun Cryptomator.AppDir cryptomator-${{ steps.versions.outputs.semVerStr }}-x86_64.AppImage
|
./squashfs-root/AppRun Cryptomator.AppDir cryptomator-${{ needs.get-version.outputs.semVerStr }}-x86_64.AppImage
|
||||||
-u 'gh-releases-zsync|cryptomator|cryptomator|latest|cryptomator-*-x86_64.AppImage.zsync'
|
-u 'gh-releases-zsync|cryptomator|cryptomator|latest|cryptomator-*-x86_64.AppImage.zsync'
|
||||||
--sign --sign-key=615D449FE6E6A235 --sign-args="--batch --pinentry-mode loopback"
|
--sign --sign-key=615D449FE6E6A235 --sign-args="--batch --pinentry-mode loopback"
|
||||||
- name: Create detached GPG signatures
|
- name: Create detached GPG signatures
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ on:
|
|||||||
types: [labeled]
|
types: [labeled]
|
||||||
|
|
||||||
env:
|
env:
|
||||||
JAVA_VERSION: 19
|
JAVA_VERSION: 20
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
@@ -42,15 +42,6 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
|
||||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||||
- name: Sign source tarball with key 615D449FE6E6A235
|
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
|
||||||
run: |
|
|
||||||
git archive --prefix="cryptomator-${{ github.ref_name }}/" -o "cryptomator-${{ github.ref_name }}.tar.gz" ${{ github.ref }}
|
|
||||||
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
|
|
||||||
echo "${GPG_PASSPHRASE}" | gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator-*.tar.gz
|
|
||||||
env:
|
|
||||||
GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }}
|
|
||||||
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
|
|
||||||
- name: Draft a release
|
- name: Draft a release
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v1
|
||||||
@@ -59,10 +50,11 @@ jobs:
|
|||||||
discussion_category_name: releases
|
discussion_category_name: releases
|
||||||
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
|
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
|
||||||
generate_release_notes: true
|
generate_release_notes: true
|
||||||
files: |
|
|
||||||
cryptomator-*.tar.gz.asc
|
|
||||||
fail_on_unmatched_files: true
|
|
||||||
body: |-
|
body: |-
|
||||||
:construction: Work in Progress
|
: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: -->
|
||||||
@@ -1,21 +1,27 @@
|
|||||||
name: Build Debian Package
|
name: Build Debian Package
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
|
||||||
types: [published]
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
|
ref:
|
||||||
|
description: 'GitHub Ref (e.g. refs/tags/1.6.16)'
|
||||||
|
required: true
|
||||||
|
semver:
|
||||||
|
description: 'SemVer String (e.g. 1.7.0-beta1)'
|
||||||
|
required: true
|
||||||
|
ppaver:
|
||||||
|
description: 'Base PPA Version String (e.g. 1.6.16+1.7.0~beta1) without -0ppa1'
|
||||||
|
required: true
|
||||||
dput:
|
dput:
|
||||||
description: 'Upload to PPA'
|
description: 'Upload to PPA'
|
||||||
required: true
|
required: true
|
||||||
default: false
|
default: false
|
||||||
type: boolean
|
type: boolean
|
||||||
version:
|
|
||||||
description: 'Version'
|
|
||||||
required: false
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
JAVA_VERSION: 19
|
JAVA_VERSION: 20
|
||||||
|
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/20.0.1/openjfx-20.0.1_linux-x64_bin-jmods.zip'
|
||||||
|
OPENJFX_JMODS_AARCH64: 'https://download2.gluonhq.com/openjfx/20.0.1/openjfx-20.0.1_linux-aarch64_bin-jmods.zip'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -24,50 +30,69 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
|
ref: ${{ inputs.ref }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
- id: versions
|
||||||
|
name: Get version information
|
||||||
|
run: |
|
||||||
|
SEM_VER_STR="${{ inputs.semver }}"
|
||||||
|
SEM_VER_NUM=`echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/'`
|
||||||
|
REVCOUNT=`git rev-list --count HEAD`
|
||||||
|
echo "semVerStr=${SEM_VER_STR}" >> $GITHUB_OUTPUT
|
||||||
|
echo "semVerNum=${SEM_VER_NUM}" >> $GITHUB_OUTPUT
|
||||||
|
echo "revNum=${REVCOUNT}" >> $GITHUB_OUTPUT
|
||||||
- name: Install build tools
|
- name: Install build tools
|
||||||
run: |
|
run: |
|
||||||
sudo add-apt-repository ppa:coffeelibs/openjdk
|
sudo add-apt-repository ppa:coffeelibs/openjdk
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install debhelper devscripts dput coffeelibs-jdk-19
|
sudo apt-get install debhelper devscripts dput coffeelibs-jdk-${{ env.JAVA_VERSION }} libgtk2.0-0
|
||||||
- name: Setup Java
|
- name: Setup Java
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: 'zulu'
|
distribution: 'zulu'
|
||||||
java-version: ${{ env.JAVA_VERSION }}
|
java-version: ${{ env.JAVA_VERSION }}
|
||||||
cache: 'maven'
|
cache: 'maven'
|
||||||
- id: versions
|
|
||||||
name: Apply version information
|
|
||||||
run: |
|
|
||||||
if [[ $GITHUB_REF =~ refs/tags/[0-9]+\.[0-9]+\.[0-9]+.* ]]; then
|
|
||||||
SEM_VER_STR=${GITHUB_REF##*/}
|
|
||||||
mvn versions:set -DnewVersion=${SEM_VER_STR}
|
|
||||||
elif [[ "${{ github.event.inputs.version }}" =~ [0-9]+\.[0-9]+\.[0-9]+.* ]]; then
|
|
||||||
SEM_VER_STR="${{ github.event.inputs.version }}"
|
|
||||||
mvn versions:set -DnewVersion=${SEM_VER_STR}
|
|
||||||
else
|
|
||||||
SEM_VER_STR=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout`
|
|
||||||
fi
|
|
||||||
SEM_VER_NUM=`echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/'`
|
|
||||||
REVCOUNT=`git rev-list --count HEAD`
|
|
||||||
echo "::set-output name=semVerStr::${SEM_VER_STR}"
|
|
||||||
echo "::set-output name=semVerNum::${SEM_VER_NUM}"
|
|
||||||
echo "::set-output name=revNum::${REVCOUNT}"
|
|
||||||
echo "::set-output name=ppaVerStr::${SEM_VER_STR/-/\~}-${REVCOUNT}"
|
|
||||||
- name: Validate Version
|
|
||||||
uses: skymatic/semver-validation-action@v1
|
|
||||||
with:
|
|
||||||
version: ${{ steps.versions.outputs.semVerStr }}
|
|
||||||
- name: Run maven
|
- name: Run maven
|
||||||
run: mvn -B clean package -Pdependency-check,linux -DskipTests
|
run: mvn -B clean package -Pdependency-check,linux -DskipTests
|
||||||
- name: Create orig.tar.gz with common/ libs/ mods/
|
- name: Download OpenJFX jmods
|
||||||
|
id: download-jmods
|
||||||
|
run: |
|
||||||
|
curl -L ${{ env.OPENJFX_JMODS_AMD64 }} -o openjfx-amd64.zip
|
||||||
|
mkdir -p jmods/amd64
|
||||||
|
unzip -j openjfx-amd64.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d jmods/amd64
|
||||||
|
curl -L ${{ env.OPENJFX_JMODS_AARCH64 }} -o openjfx-aarch64.zip
|
||||||
|
mkdir -p jmods/aarch64
|
||||||
|
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 jmods/amd64/javafx.base.jmod | head -1)
|
||||||
|
JMOD_VERSION_AMD64=${JMOD_VERSION_AMD64#*@}
|
||||||
|
JMOD_VERSION_AMD64=${JMOD_VERSION_AMD64%%.*}
|
||||||
|
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)
|
||||||
|
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
|
||||||
|
|
||||||
|
if [ $POM_JFX_VERSION -ne $JMOD_VERSION_AARCH64 ]; then
|
||||||
|
>&2 echo "Major JavaFX version in pom.xml (${POM_JFX_VERSION}) != aarch64 jmod version (${JMOD_VERSION_AARCH64})"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
- name: Create orig.tar.gz with common/ libs/ mods/ jmods/
|
||||||
run: |
|
run: |
|
||||||
mkdir pkgdir
|
mkdir pkgdir
|
||||||
cp -r target/libs pkgdir
|
cp -r target/libs pkgdir
|
||||||
cp -r target/mods pkgdir
|
cp -r target/mods pkgdir
|
||||||
|
cp -r jmods pkgdir
|
||||||
cp -r dist/linux/common/ pkgdir
|
cp -r dist/linux/common/ pkgdir
|
||||||
cp target/cryptomator-*.jar pkgdir/mods
|
cp target/cryptomator-*.jar pkgdir/mods
|
||||||
tar -cJf cryptomator_${{ steps.versions.outputs.ppaVerStr }}.orig.tar.xz -C pkgdir .
|
tar -cJf cryptomator_${{ inputs.ppaver }}.orig.tar.xz -C pkgdir .
|
||||||
- name: Patch and rename pkgdir
|
- name: Patch and rename pkgdir
|
||||||
run: |
|
run: |
|
||||||
cp -r dist/linux/debian/ pkgdir
|
cp -r dist/linux/debian/ pkgdir
|
||||||
@@ -75,12 +100,12 @@ jobs:
|
|||||||
envsubst '${SEMVER_STR} ${VERSION_NUM} ${REVISION_NUM}' < dist/linux/debian/rules > pkgdir/debian/rules
|
envsubst '${SEMVER_STR} ${VERSION_NUM} ${REVISION_NUM}' < dist/linux/debian/rules > pkgdir/debian/rules
|
||||||
envsubst '${PPA_VERSION} ${RFC2822_TIMESTAMP}' < dist/linux/debian/changelog > pkgdir/debian/changelog
|
envsubst '${PPA_VERSION} ${RFC2822_TIMESTAMP}' < dist/linux/debian/changelog > pkgdir/debian/changelog
|
||||||
find . -name "*.jar" >> pkgdir/debian/source/include-binaries
|
find . -name "*.jar" >> pkgdir/debian/source/include-binaries
|
||||||
mv pkgdir cryptomator_${{ steps.versions.outputs.ppaVerStr }}
|
mv pkgdir cryptomator_${{ inputs.ppaver }}
|
||||||
env:
|
env:
|
||||||
SEMVER_STR: ${{ steps.versions.outputs.semVerStr }}
|
SEMVER_STR: ${{ steps.versions.outputs.semVerStr }}
|
||||||
VERSION_NUM: ${{ steps.versions.outputs.semVerNum }}
|
VERSION_NUM: ${{ steps.versions.outputs.semVerNum }}
|
||||||
REVISION_NUM: ${{ steps.versions.outputs.revNum }}
|
REVISION_NUM: ${{ steps.versions.outputs.revNum }}
|
||||||
PPA_VERSION: ${{ steps.versions.outputs.ppaVerStr }}-0ppa1
|
PPA_VERSION: ${{ inputs.ppaver }}-0ppa1
|
||||||
- name: Prepare GPG-Agent for signing with key 615D449FE6E6A235
|
- name: Prepare GPG-Agent for signing with key 615D449FE6E6A235
|
||||||
run: |
|
run: |
|
||||||
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
|
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
|
||||||
@@ -95,7 +120,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
DEBSIGN_PROGRAM: gpg --batch --pinentry-mode loopback
|
DEBSIGN_PROGRAM: gpg --batch --pinentry-mode loopback
|
||||||
DEBSIGN_KEYID: 615D449FE6E6A235
|
DEBSIGN_KEYID: 615D449FE6E6A235
|
||||||
working-directory: cryptomator_${{ steps.versions.outputs.ppaVerStr }}
|
working-directory: cryptomator_${{ inputs.ppaver }}
|
||||||
- name: Create detached GPG signatures
|
- name: Create detached GPG signatures
|
||||||
run: |
|
run: |
|
||||||
gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator_*_amd64.deb
|
gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator_*_amd64.deb
|
||||||
@@ -112,14 +137,19 @@ jobs:
|
|||||||
cryptomator_*_amd64.deb
|
cryptomator_*_amd64.deb
|
||||||
cryptomator_*.asc
|
cryptomator_*.asc
|
||||||
- name: Publish on PPA
|
- name: Publish on PPA
|
||||||
if: startsWith(github.ref, 'refs/tags/') || inputs.dput
|
if: inputs.dput
|
||||||
run: dput ppa:sebastian-stenzel/cryptomator-beta cryptomator_*_source.changes
|
run: dput ppa:sebastian-stenzel/cryptomator-beta cryptomator_*_source.changes
|
||||||
|
|
||||||
|
# If ref is a tag, also upload to GitHub Releases:
|
||||||
|
- name: Determine tag name
|
||||||
|
if: startsWith(inputs.ref, 'refs/tags/')
|
||||||
|
run: |
|
||||||
|
REF=${{ inputs.ref }}
|
||||||
|
echo "TAG_NAME=${REF##*/}" >> $GITHUB_ENV
|
||||||
- name: Publish Debian package on GitHub Releases
|
- name: Publish Debian package on GitHub Releases
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(inputs.ref, 'refs/tags/')
|
||||||
uses: softprops/action-gh-release@v1
|
env:
|
||||||
with:
|
GITHUB_TOKEN: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
|
||||||
fail_on_unmatched_files: true
|
run: |
|
||||||
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
|
artifacts=$(ls | grep cryptomator*.deb)
|
||||||
files: |
|
gh release upload ${{ env.TAG_NAME }} $artifacts
|
||||||
cryptomator_*_amd64.deb
|
|
||||||
cryptomator_*.asc
|
|
||||||
@@ -48,7 +48,7 @@ jobs:
|
|||||||
jq -c 'select(.filename|endswith(".dmg")) | select(.filename|endswith("-arm64.dmg")|not) | {name: "github.releases.downloads", tags: ["file=dmg", "version=\(.release)", "arch=amd64"], value: .downloads, interval: .interval, time: .time}' input.json >> output.json
|
jq -c 'select(.filename|endswith(".dmg")) | select(.filename|endswith("-arm64.dmg")|not) | {name: "github.releases.downloads", tags: ["file=dmg", "version=\(.release)", "arch=amd64"], value: .downloads, interval: .interval, time: .time}' input.json >> output.json
|
||||||
|
|
||||||
RESULT=$(jq -s -c "." output.json)
|
RESULT=$(jq -s -c "." output.json)
|
||||||
echo "::set-output name=result::${RESULT}"
|
echo "result=${RESULT}" >> $GITHUB_OUTPUT
|
||||||
env:
|
env:
|
||||||
INTERVAL: 900
|
INTERVAL: 900
|
||||||
JSON_DATA: ${{ steps.get-stats.outputs.result }}
|
JSON_DATA: ${{ steps.get-stats.outputs.result }}
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
name: Parse and Validate a version string or tag
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
description: "A specific version to use"
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
outputs:
|
||||||
|
semVerStr:
|
||||||
|
description: "The full version string."
|
||||||
|
value: ${{ jobs.determine-version.outputs.semVerStr}}
|
||||||
|
semVerNum:
|
||||||
|
description: "The numerical part of the version string"
|
||||||
|
value: ${{ jobs.determine-version.outputs.semVerNum}}
|
||||||
|
revNum:
|
||||||
|
description: "The revision number"
|
||||||
|
value: ${{ jobs.determine-version.outputs.revNum}}
|
||||||
|
versionType:
|
||||||
|
description: "Type of the version. Values are [stable, alpha, beta, rc, unknown]"
|
||||||
|
value: ${{ jobs.determine-version.outputs.type }}
|
||||||
|
|
||||||
|
env:
|
||||||
|
JAVA_VERSION: 20
|
||||||
|
JAVA_DIST: 'temurin'
|
||||||
|
JAVA_CACHE: 'maven'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
determine-version:
|
||||||
|
name: 'Determines the version following semver'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
semVerNum: ${{ steps.versions.outputs.semVerNum }}
|
||||||
|
semVerStr: ${{ steps.versions.outputs.semVerStr }}
|
||||||
|
revNum: ${{ steps.versions.outputs.revNum }}
|
||||||
|
type: ${{ steps.versions.outputs.type}}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Setup Java
|
||||||
|
uses: actions/setup-java@v3
|
||||||
|
with:
|
||||||
|
distribution: ${{ env.JAVA_DIST }}
|
||||||
|
java-version: ${{ env.JAVA_VERSION }}
|
||||||
|
cache: ${{ env.JAVA_CACHE }}
|
||||||
|
- id: versions
|
||||||
|
name: Get version information
|
||||||
|
run: |
|
||||||
|
if [[ $GITHUB_REF =~ refs/tags/[0-9]+\.[0-9]+\.[0-9]+.* ]]; then
|
||||||
|
SEM_VER_STR=${GITHUB_REF##*/}
|
||||||
|
elif [[ "${{ inputs.version }}" =~ [0-9]+\.[0-9]+\.[0-9]+.* ]]; then
|
||||||
|
SEM_VER_STR="${{ github.event.inputs.version }}"
|
||||||
|
else
|
||||||
|
SEM_VER_STR=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout`
|
||||||
|
fi
|
||||||
|
SEM_VER_NUM=`echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/'`
|
||||||
|
REVCOUNT=`git rev-list --count HEAD`
|
||||||
|
TYPE="unknown"
|
||||||
|
if [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||||
|
TYPE="stable"
|
||||||
|
elif [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+-alpha[1-9]+$ ]]; then
|
||||||
|
TYPE="alpha"
|
||||||
|
elif [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+-beta[1-9]+$ ]]; then
|
||||||
|
TYPE="beta"
|
||||||
|
elif [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+-rc[1-9]$ ]]; then
|
||||||
|
TYPE="rc"
|
||||||
|
fi
|
||||||
|
echo "semVerStr=${SEM_VER_STR}" >> $GITHUB_OUTPUT
|
||||||
|
echo "semVerNum=${SEM_VER_NUM}" >> $GITHUB_OUTPUT
|
||||||
|
echo "revNum=${REVCOUNT}" >> $GITHUB_OUTPUT
|
||||||
|
echo "type=${TYPE}" >> $GITHUB_OUTPUT
|
||||||
|
- name: Validate Version
|
||||||
|
uses: skymatic/semver-validation-action@v2
|
||||||
|
with:
|
||||||
|
version: ${{ steps.versions.outputs.semVerStr }}
|
||||||
@@ -10,12 +10,18 @@ on:
|
|||||||
required: false
|
required: false
|
||||||
|
|
||||||
env:
|
env:
|
||||||
JAVA_VERSION: 19
|
JAVA_VERSION: 20
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
get-version:
|
||||||
|
uses: ./.github/workflows/get-version.yml
|
||||||
|
with:
|
||||||
|
version: ${{ inputs.version }}
|
||||||
|
|
||||||
build:
|
build:
|
||||||
name: Build Cryptomator.app for ${{ matrix.output-suffix }}
|
name: Build Cryptomator.app for ${{ matrix.output-suffix }}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
needs: [get-version]
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@@ -24,48 +30,39 @@ jobs:
|
|||||||
architecture: x64
|
architecture: x64
|
||||||
output-suffix: x64
|
output-suffix: x64
|
||||||
xcode-path: '/Applications/Xcode_13.2.1.app'
|
xcode-path: '/Applications/Xcode_13.2.1.app'
|
||||||
|
fuse-lib: macFUSE
|
||||||
- os: [self-hosted, macOS, ARM64]
|
- os: [self-hosted, macOS, ARM64]
|
||||||
architecture: aarch64
|
architecture: aarch64
|
||||||
output-suffix: arm64
|
output-suffix: arm64
|
||||||
xcode-path: '/Applications/Xcode_13.2.1.app'
|
xcode-path: '/Applications/Xcode_13.2.1.app'
|
||||||
|
fuse-lib: FUSE-T
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Setup Java
|
- name: Setup Java
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: 'zulu'
|
distribution: 'zulu'
|
||||||
java-version: ${{ env.JAVA_VERSION }}
|
java-version: ${{ env.JAVA_VERSION }}
|
||||||
|
java-package: 'jdk+fx'
|
||||||
architecture: ${{ matrix.architecture }}
|
architecture: ${{ matrix.architecture }}
|
||||||
cache: 'maven'
|
cache: 'maven'
|
||||||
- id: versions
|
- name: Ensure major jfx version in pom equals in jdk
|
||||||
name: Apply version information
|
if: ${{ !contains(matrix.os, 'self-hosted') }}
|
||||||
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
if [[ $GITHUB_REF =~ refs/tags/[0-9]+\.[0-9]+\.[0-9]+.* ]]; then
|
$jfxPomVersion = (&mvn help:evaluate "-Dexpression=javafx.version" -q -DforceStdout) -split "\."
|
||||||
SEM_VER_STR=${GITHUB_REF##*/}
|
$jfxJdkVersion = ((Get-Content -path "${env:JAVA_HOME}/lib/javafx.properties" | Where-Object {$_ -like 'javafx.version=*' }) -replace '.*=','') -split "\."
|
||||||
mvn versions:set -DnewVersion=${SEM_VER_STR}
|
if ($jfxPomVersion[0] -ne $jfxJdkVersion[0]) {
|
||||||
elif [[ "${{ github.event.inputs.version }}" =~ [0-9]+\.[0-9]+\.[0-9]+.* ]]; then
|
Write-Error "Major part of JavaFX version in pom($($jfxPomVersion[0])) does not match the version in JDK($($jfxJdkVersion[0])) "
|
||||||
SEM_VER_STR="${{ github.event.inputs.version }}"
|
exit 1
|
||||||
mvn versions:set -DnewVersion=${SEM_VER_STR}
|
}
|
||||||
else
|
- name: Set version
|
||||||
SEM_VER_STR=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout`
|
run : mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }}
|
||||||
fi
|
|
||||||
SEM_VER_NUM=`echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/'`
|
|
||||||
REVCOUNT=`git rev-list --count HEAD`
|
|
||||||
echo "::set-output name=semVerStr::${SEM_VER_STR}"
|
|
||||||
echo "::set-output name=semVerNum::${SEM_VER_NUM}"
|
|
||||||
echo "::set-output name=revNum::${REVCOUNT}"
|
|
||||||
- name: Validate Version
|
|
||||||
uses: skymatic/semver-validation-action@v1
|
|
||||||
with:
|
|
||||||
version: ${{ steps.versions.outputs.semVerStr }}
|
|
||||||
- name: Run maven
|
- name: Run maven
|
||||||
run: mvn -B clean package -Pdependency-check,mac -DskipTests
|
run: mvn -B clean package -Pdependency-check,mac -DskipTests
|
||||||
- name: Patch target dir
|
- name: Patch target dir
|
||||||
run: |
|
run: |
|
||||||
cp LICENSE.txt target
|
cp LICENSE.txt target
|
||||||
cp dist/mac/launcher.sh target
|
|
||||||
cp target/cryptomator-*.jar target/mods
|
cp target/cryptomator-*.jar target/mods
|
||||||
- name: Run jlink
|
- name: Run jlink
|
||||||
run: >
|
run: >
|
||||||
@@ -73,7 +70,7 @@ jobs:
|
|||||||
--verbose
|
--verbose
|
||||||
--output runtime
|
--output runtime
|
||||||
--module-path "${JAVA_HOME}/jmods"
|
--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.accessibility,jdk.management.jfr
|
||||||
--strip-native-commands
|
--strip-native-commands
|
||||||
--no-header-files
|
--no-header-files
|
||||||
--no-man-pages
|
--no-man-pages
|
||||||
@@ -91,22 +88,25 @@ jobs:
|
|||||||
--dest appdir
|
--dest appdir
|
||||||
--name Cryptomator
|
--name Cryptomator
|
||||||
--vendor "Skymatic GmbH"
|
--vendor "Skymatic GmbH"
|
||||||
--copyright "(C) 2016 - 2022 Skymatic GmbH"
|
--copyright "(C) 2016 - 2023 Skymatic GmbH"
|
||||||
--app-version "${{ steps.versions.outputs.semVerNum }}"
|
--app-version "${{ needs.get-version.outputs.semVerNum }}"
|
||||||
|
--java-options "--enable-preview"
|
||||||
|
--java-options "--enable-native-access=org.cryptomator.jfuse.mac"
|
||||||
--java-options "-Xss5m"
|
--java-options "-Xss5m"
|
||||||
--java-options "-Xmx256m"
|
--java-options "-Xmx256m"
|
||||||
--java-options "-Dfile.encoding=\"utf-8\""
|
--java-options "-Dfile.encoding=\"utf-8\""
|
||||||
--java-options "-Dapple.awt.enableTemplateImages=true"
|
--java-options "-Dapple.awt.enableTemplateImages=true"
|
||||||
--java-options "-Dsun.java2d.metal=true"
|
--java-options "-Dsun.java2d.metal=true"
|
||||||
--java-options "-Dcryptomator.appVersion=\"${{ steps.versions.outputs.semVerStr }}\""
|
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
|
||||||
--java-options "-Dcryptomator.logDir=\"~/Library/Logs/Cryptomator\""
|
--java-options "-Dcryptomator.logDir=\"~/Library/Logs/Cryptomator\""
|
||||||
--java-options "-Dcryptomator.pluginDir=\"~/Library/Application Support/Cryptomator/Plugins\""
|
--java-options "-Dcryptomator.pluginDir=\"~/Library/Application Support/Cryptomator/Plugins\""
|
||||||
--java-options "-Dcryptomator.settingsPath=\"~/Library/Application Support/Cryptomator/settings.json\""
|
--java-options "-Dcryptomator.settingsPath=\"~/Library/Application Support/Cryptomator/settings.json\""
|
||||||
--java-options "-Dcryptomator.p12Path=\"~/Library/Application Support/Cryptomator/key.p12\""
|
--java-options "-Dcryptomator.p12Path=\"~/Library/Application Support/Cryptomator/key.p12\""
|
||||||
--java-options "-Dcryptomator.ipcSocketPath=\"~/Library/Application Support/Cryptomator/ipc.socket\""
|
--java-options "-Dcryptomator.ipcSocketPath=\"~/Library/Application Support/Cryptomator/ipc.socket\""
|
||||||
--java-options "-Dcryptomator.integrationsMac.keychainServiceName=\"Cryptomator\""
|
--java-options "-Dcryptomator.integrationsMac.keychainServiceName=\"Cryptomator\""
|
||||||
|
--java-options "-Dcryptomator.mountPointsDir=\"~/Cryptomator\""
|
||||||
--java-options "-Dcryptomator.showTrayIcon=true"
|
--java-options "-Dcryptomator.showTrayIcon=true"
|
||||||
--java-options "-Dcryptomator.buildNumber=\"dmg-${{ steps.versions.outputs.revNum }}\""
|
--java-options "-Dcryptomator.buildNumber=\"dmg-${{ needs.get-version.outputs.revNum }}\""
|
||||||
--mac-package-identifier org.cryptomator
|
--mac-package-identifier org.cryptomator
|
||||||
--resource-dir dist/mac/resources
|
--resource-dir dist/mac/resources
|
||||||
- name: Patch Cryptomator.app
|
- name: Patch Cryptomator.app
|
||||||
@@ -116,8 +116,8 @@ jobs:
|
|||||||
sed -i '' "s|###BUNDLE_SHORT_VERSION_STRING###|${VERSION_NO}|g" Cryptomator.app/Contents/Info.plist
|
sed -i '' "s|###BUNDLE_SHORT_VERSION_STRING###|${VERSION_NO}|g" Cryptomator.app/Contents/Info.plist
|
||||||
sed -i '' "s|###BUNDLE_VERSION###|${REVISION_NO}|g" Cryptomator.app/Contents/Info.plist
|
sed -i '' "s|###BUNDLE_VERSION###|${REVISION_NO}|g" Cryptomator.app/Contents/Info.plist
|
||||||
env:
|
env:
|
||||||
VERSION_NO: ${{ steps.versions.outputs.semVerNum }}
|
VERSION_NO: ${{ needs.get-version.outputs.semVerNum }}
|
||||||
REVISION_NO: ${{ steps.versions.outputs.revNum }}
|
REVISION_NO: ${{ needs.get-version.outputs.revNum }}
|
||||||
- name: Generate license for dmg
|
- name: Generate license for dmg
|
||||||
run: >
|
run: >
|
||||||
mvn -B license:add-third-party
|
mvn -B license:add-third-party
|
||||||
@@ -151,6 +151,10 @@ jobs:
|
|||||||
CODESIGN_TMP_KEYCHAIN_PW: ${{ secrets.MACOS_CODESIGN_TMP_KEYCHAIN_PW }}
|
CODESIGN_TMP_KEYCHAIN_PW: ${{ secrets.MACOS_CODESIGN_TMP_KEYCHAIN_PW }}
|
||||||
- name: Codesign
|
- name: Codesign
|
||||||
run: |
|
run: |
|
||||||
|
echo "Codesigning jdk files..."
|
||||||
|
find Cryptomator.app/Contents/runtime/Contents/Home/lib/ -name '*.dylib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \;
|
||||||
|
find Cryptomator.app/Contents/runtime/Contents/Home/lib/ -name 'jspawnhelper' -exec codesign --force -o runtime -s ${CODESIGN_IDENTITY} {} \;
|
||||||
|
echo "Codesigning jar contents..."
|
||||||
find Cryptomator.app/Contents/runtime/Contents/MacOS -name '*.dylib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \;
|
find Cryptomator.app/Contents/runtime/Contents/MacOS -name '*.dylib' -exec codesign --force -s ${CODESIGN_IDENTITY} {} \;
|
||||||
for JAR_PATH in `find Cryptomator.app -name "*.jar"`; do
|
for JAR_PATH in `find Cryptomator.app -name "*.jar"`; do
|
||||||
if [[ `unzip -l ${JAR_PATH} | grep '.dylib\|.jnilib'` ]]; then
|
if [[ `unzip -l ${JAR_PATH} | grep '.dylib\|.jnilib'` ]]; then
|
||||||
@@ -175,7 +179,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mkdir dmg
|
mkdir dmg
|
||||||
mv Cryptomator.app 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
|
ls -l dmg
|
||||||
- name: Install create-dmg
|
- name: Install create-dmg
|
||||||
run: |
|
run: |
|
||||||
@@ -186,14 +190,14 @@ jobs:
|
|||||||
create-dmg
|
create-dmg
|
||||||
--volname Cryptomator
|
--volname Cryptomator
|
||||||
--volicon "dist/mac/dmg/resources/Cryptomator-Volume.icns"
|
--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-pos 400 100
|
||||||
--window-size 640 694
|
--window-size 640 694
|
||||||
--icon-size 128
|
--icon-size 128
|
||||||
--icon "Cryptomator.app" 128 245
|
--icon "Cryptomator.app" 128 245
|
||||||
--hide-extension "Cryptomator.app"
|
--hide-extension "Cryptomator.app"
|
||||||
--icon "macFUSE.webloc" 320 501
|
--icon "${{ matrix.fuse-lib }}.webloc" 320 501
|
||||||
--hide-extension "macFUSE.webloc"
|
--hide-extension "${{ matrix.fuse-lib }}.webloc"
|
||||||
--app-drop-link 512 245
|
--app-drop-link 512 245
|
||||||
--eula "dist/mac/dmg/resources/license.rtf"
|
--eula "dist/mac/dmg/resources/license.rtf"
|
||||||
--icon ".background" 128 758
|
--icon ".background" 128 758
|
||||||
@@ -201,7 +205,7 @@ jobs:
|
|||||||
--icon ".VolumeIcon.icns" 512 758
|
--icon ".VolumeIcon.icns" 512 758
|
||||||
Cryptomator-${VERSION_NO}-${{ matrix.output-suffix }}.dmg dmg
|
Cryptomator-${VERSION_NO}-${{ matrix.output-suffix }}.dmg dmg
|
||||||
env:
|
env:
|
||||||
VERSION_NO: ${{ steps.versions.outputs.semVerNum }}
|
VERSION_NO: ${{ needs.get-version.outputs.semVerNum }}
|
||||||
- name: Notarize .dmg
|
- name: Notarize .dmg
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
uses: cocoalibs/xcode-notarization-action@v1
|
uses: cocoalibs/xcode-notarization-action@v1
|
||||||
@@ -212,7 +216,7 @@ jobs:
|
|||||||
team-id: ${{ secrets.MACOS_NOTARIZATION_TEAM_ID }}
|
team-id: ${{ secrets.MACOS_NOTARIZATION_TEAM_ID }}
|
||||||
xcode-path: ${{ matrix.xcode-path }}
|
xcode-path: ${{ matrix.xcode-path }}
|
||||||
- name: Add possible alpha/beta tags to installer name
|
- name: Add possible alpha/beta tags to installer name
|
||||||
run: mv Cryptomator-*.dmg Cryptomator-${{ steps.versions.outputs.semVerStr }}-${{ matrix.output-suffix }}.dmg
|
run: mv Cryptomator-*.dmg Cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.output-suffix }}.dmg
|
||||||
- name: Create detached GPG signature with key 615D449FE6E6A235
|
- name: Create detached GPG signature with key 615D449FE6E6A235
|
||||||
run: |
|
run: |
|
||||||
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
|
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
|
||||||
|
|||||||
@@ -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'
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
name: Post Release Publish Tasks
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
get-version:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Download source tarball
|
||||||
|
run: |
|
||||||
|
curl -L -H "Accept: application/vnd.github+json" https://github.com/cryptomator/cryptomator/archive/refs/tags/${{ github.event.release.tag_name }}.tar.gz --output cryptomator-${{ github.event.release.tag_name }}.tar.gz
|
||||||
|
- name: Sign source tarball with key 615D449FE6E6A235
|
||||||
|
run: |
|
||||||
|
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
|
||||||
|
echo "${GPG_PASSPHRASE}" | gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator-*.tar.gz
|
||||||
|
env:
|
||||||
|
GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }}
|
||||||
|
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
|
||||||
|
- name: Publish asc on GitHub Releases
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
fail_on_unmatched_files: true
|
||||||
|
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
|
||||||
|
files: |
|
||||||
|
cryptomator-*.tar.gz.asc
|
||||||
|
- name: Slack Notification
|
||||||
|
uses: rtCamp/action-slack-notify@v2
|
||||||
|
env:
|
||||||
|
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||||
|
SLACK_USERNAME: 'Cryptobot'
|
||||||
|
SLACK_ICON: false
|
||||||
|
SLACK_ICON_EMOJI: ':bot:'
|
||||||
|
SLACK_CHANNEL: 'cryptomator-desktop'
|
||||||
|
SLACK_TITLE: "Release ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} published."
|
||||||
|
SLACK_MESSAGE: "Ready to <https://github.com/${{ github.repository }}/actions/workflows/debian.yml|build deb Package>."
|
||||||
|
SLACK_FOOTER: false
|
||||||
|
MSG_MINIMAL: true
|
||||||
@@ -4,7 +4,7 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
JAVA_VERSION: 19
|
JAVA_VERSION: 20
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ on:
|
|||||||
- 'hotfix/**'
|
- 'hotfix/**'
|
||||||
|
|
||||||
env:
|
env:
|
||||||
JAVA_VERSION: 19
|
JAVA_VERSION: 20
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
@@ -30,7 +30,7 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ${SEM_VER_STR} == `mvn help:evaluate -Dexpression=project.version -q -DforceStdout` ]]; then
|
if [[ ${SEM_VER_STR} == `mvn help:evaluate -Dexpression=project.version -q -DforceStdout` ]]; then
|
||||||
echo "::set-output name=semVerStr::${SEM_VER_STR}"
|
echo "semVerStr=${SEM_VER_STR}" >> $GITHUB_OUTPUT
|
||||||
else
|
else
|
||||||
echo "Version not set in POM"
|
echo "Version not set in POM"
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
@@ -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,70 +8,90 @@ on:
|
|||||||
version:
|
version:
|
||||||
description: 'Version'
|
description: 'Version'
|
||||||
required: false
|
required: false
|
||||||
|
isDebug:
|
||||||
|
description: 'Build debug version with console output'
|
||||||
|
type: boolean
|
||||||
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
JAVA_VERSION: 19
|
JAVA_VERSION: 20
|
||||||
JAVA_DIST: 'zulu'
|
JAVA_DIST: 'temurin'
|
||||||
JAVA_CACHE: 'maven'
|
JAVA_CACHE: 'maven'
|
||||||
|
JFX_JMODS_URL: 'https://download2.gluonhq.com/openjfx/20.0.1/openjfx-20.0.1_windows-x64_bin-jmods.zip'
|
||||||
|
JFX_JMODS_HASH: 'D00767334C43B8832B5CF10267D34CA8F563D187C4655B73EB6020DD79C054B5'
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
get-version:
|
||||||
|
uses: ./.github/workflows/get-version.yml
|
||||||
|
with:
|
||||||
|
version: ${{ inputs.version }}
|
||||||
|
|
||||||
build-msi:
|
build-msi:
|
||||||
name: Build .msi Installer
|
name: Build .msi Installer
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
|
needs: [get-version]
|
||||||
|
env:
|
||||||
|
LOOPBACK_ALIAS: 'cryptomator-vault'
|
||||||
|
WIN_CONSOLE_FLAG: ''
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Setup Java
|
- name: Setup Java
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: ${{ env.JAVA_DIST }}
|
distribution: ${{ env.JAVA_DIST }}
|
||||||
java-version: ${{ env.JAVA_VERSION }}
|
java-version: ${{ env.JAVA_VERSION }}
|
||||||
|
java-package: 'jdk'
|
||||||
cache: ${{ env.JAVA_CACHE }}
|
cache: ${{ env.JAVA_CACHE }}
|
||||||
- id: versions
|
- name: Download and extract JavaFX jmods from Gluon
|
||||||
name: Apply version information
|
#In the last step we move all jmods files a dir level up because jmods are placed inside a directory in the zip
|
||||||
run: |
|
run: |
|
||||||
if [[ $GITHUB_REF =~ refs/tags/[0-9]+\.[0-9]+\.[0-9]+.* ]]; then
|
curl --output jfxjmods.zip -L "${{ env.JFX_JMODS_URL }}"
|
||||||
SEM_VER_STR=${GITHUB_REF##*/}
|
if(!(Get-FileHash -Path jfxjmods.zip -Algorithm SHA256).Hash.equals("${{ env.JFX_JMODS_HASH }}")) {
|
||||||
mvn versions:set -DnewVersion=${SEM_VER_STR}
|
throw "Wrong checksum of JMOD archive downloaded from ${{ env.JFX_JMODS_URL }}.";
|
||||||
elif [[ "${{ github.event.inputs.version }}" =~ [0-9]+\.[0-9]+\.[0-9]+.* ]]; then
|
}
|
||||||
SEM_VER_STR="${{ github.event.inputs.version }}"
|
Expand-Archive -Path jfxjmods.zip -DestinationPath jfxjmods
|
||||||
mvn versions:set -DnewVersion=${SEM_VER_STR}
|
Get-ChildItem -Path jfxjmods -Recurse -Filter "*.jmod" | ForEach-Object { Move-Item -Path $_ -Destination $_.Directory.Parent}
|
||||||
else
|
shell: pwsh
|
||||||
SEM_VER_STR=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout`
|
- 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
|
fi
|
||||||
SEM_VER_NUM=`echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/'`
|
- name: Set version
|
||||||
REVCOUNT=`git rev-list --count HEAD`
|
run : mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }}
|
||||||
echo "::set-output name=semVerStr::${SEM_VER_STR}"
|
|
||||||
echo "::set-output name=semVerNum::${SEM_VER_NUM}"
|
|
||||||
echo "::set-output name=revNum::${REVCOUNT}"
|
|
||||||
- name: Validate Version
|
|
||||||
uses: skymatic/semver-validation-action@v1
|
|
||||||
with:
|
|
||||||
version: ${{ steps.versions.outputs.semVerStr }}
|
|
||||||
- name: Run maven
|
- name: Run maven
|
||||||
run: mvn -B clean package -Pdependency-check,win -DskipTests
|
run: mvn -B clean package -Pdependency-check,win -DskipTests
|
||||||
- name: Patch target dir
|
- name: Patch target dir
|
||||||
run: |
|
run: |
|
||||||
cp LICENSE.txt target
|
cp LICENSE.txt target
|
||||||
cp dist/linux/launcher.sh target
|
|
||||||
cp target/cryptomator-*.jar target/mods
|
cp target/cryptomator-*.jar target/mods
|
||||||
- name: Run jlink
|
- name: Run jlink
|
||||||
run: >
|
run: >
|
||||||
${JAVA_HOME}/bin/jlink
|
${JAVA_HOME}/bin/jlink
|
||||||
--verbose
|
--verbose
|
||||||
--output runtime
|
--output runtime
|
||||||
--module-path "${JAVA_HOME}/jmods"
|
--module-path "jfxjmods;${JAVA_HOME}/jmods"
|
||||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,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
|
||||||
--strip-native-commands
|
--strip-native-commands
|
||||||
--no-header-files
|
--no-header-files
|
||||||
--no-man-pages
|
--no-man-pages
|
||||||
--strip-debug
|
--strip-debug
|
||||||
--compress=1
|
--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
|
- name: Run jpackage
|
||||||
run: >
|
run: >
|
||||||
${JAVA_HOME}/bin/jpackage
|
${JAVA_HOME}/bin/jpackage
|
||||||
@@ -84,11 +104,13 @@ jobs:
|
|||||||
--dest appdir
|
--dest appdir
|
||||||
--name Cryptomator
|
--name Cryptomator
|
||||||
--vendor "Skymatic GmbH"
|
--vendor "Skymatic GmbH"
|
||||||
--copyright "(C) 2016 - 2022 Skymatic GmbH"
|
--copyright "(C) 2016 - 2023 Skymatic GmbH"
|
||||||
--app-version "${{ steps.versions.outputs.semVerNum }}.${{ steps.versions.outputs.revNum }}"
|
--app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}"
|
||||||
|
--java-options "--enable-preview"
|
||||||
|
--java-options "--enable-native-access=org.cryptomator.jfuse.win"
|
||||||
--java-options "-Xss5m"
|
--java-options "-Xss5m"
|
||||||
--java-options "-Xmx256m"
|
--java-options "-Xmx256m"
|
||||||
--java-options "-Dcryptomator.appVersion=\"${{ steps.versions.outputs.semVerStr }}\""
|
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
|
||||||
--java-options "-Dfile.encoding=\"utf-8\""
|
--java-options "-Dfile.encoding=\"utf-8\""
|
||||||
--java-options "-Dcryptomator.logDir=\"~/AppData/Roaming/Cryptomator\""
|
--java-options "-Dcryptomator.logDir=\"~/AppData/Roaming/Cryptomator\""
|
||||||
--java-options "-Dcryptomator.pluginDir=\"~/AppData/Roaming/Cryptomator/Plugins\""
|
--java-options "-Dcryptomator.pluginDir=\"~/AppData/Roaming/Cryptomator/Plugins\""
|
||||||
@@ -96,20 +118,36 @@ jobs:
|
|||||||
--java-options "-Dcryptomator.p12Path=\"~/AppData/Roaming/Cryptomator/key.p12\""
|
--java-options "-Dcryptomator.p12Path=\"~/AppData/Roaming/Cryptomator/key.p12\""
|
||||||
--java-options "-Dcryptomator.ipcSocketPath=\"~/AppData/Roaming/Cryptomator/ipc.socket\""
|
--java-options "-Dcryptomator.ipcSocketPath=\"~/AppData/Roaming/Cryptomator/ipc.socket\""
|
||||||
--java-options "-Dcryptomator.mountPointsDir=\"~/Cryptomator\""
|
--java-options "-Dcryptomator.mountPointsDir=\"~/Cryptomator\""
|
||||||
|
--java-options "-Dcryptomator.loopbackAlias=\"${{ env.LOOPBACK_ALIAS }}\""
|
||||||
--java-options "-Dcryptomator.showTrayIcon=true"
|
--java-options "-Dcryptomator.showTrayIcon=true"
|
||||||
--java-options "-Dcryptomator.buildNumber=\"msi-${{ steps.versions.outputs.revNum }}\""
|
--java-options "-Dcryptomator.buildNumber=\"msi-${{ needs.get-version.outputs.revNum }}\""
|
||||||
--java-options "-Dcryptomator.integrationsWin.autoStartShellLinkName=\"Cryptomator\""
|
--java-options "-Dcryptomator.integrationsWin.autoStartShellLinkName=\"Cryptomator\""
|
||||||
--java-options "-Dcryptomator.integrationsWin.keychainPaths=\"~/AppData/Roaming/Cryptomator/keychain.json\""
|
--java-options "-Dcryptomator.integrationsWin.keychainPaths=\"~/AppData/Roaming/Cryptomator/keychain.json\""
|
||||||
|
--java-options "-Djavafx.verbose=${{ inputs.isDebug }}"
|
||||||
--resource-dir dist/win/resources
|
--resource-dir dist/win/resources
|
||||||
--icon dist/win/resources/Cryptomator.ico
|
--icon dist/win/resources/Cryptomator.ico
|
||||||
|
${WIN_CONSOLE_FLAG}
|
||||||
- name: Patch Application Directory
|
- name: Patch Application Directory
|
||||||
run: |
|
run: |
|
||||||
cp dist/win/contrib/* appdir/Cryptomator
|
cp dist/win/contrib/* appdir/Cryptomator
|
||||||
|
- name: Set LOOPBACK_ALIAS in patchWebDAV.bat
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
$patchScript = "appdir\Cryptomator\patchWebDAV.bat"
|
||||||
|
try {
|
||||||
|
(Get-Content $patchScript ) -replace '::REPLACE ME', "SET LOOPBACK_ALIAS=`"${{ env.LOOPBACK_ALIAS}}`"" | Set-Content $patchScript
|
||||||
|
} catch {
|
||||||
|
Write-Host "Failed to set LOOPBACK_ALIAS for patchWebDAV.bat"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
- name: Fix permissions
|
- name: Fix permissions
|
||||||
run: attrib -r appdir/Cryptomator/Cryptomator.exe
|
run: attrib -r appdir/Cryptomator/Cryptomator.exe
|
||||||
shell: pwsh
|
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
|
- name: Codesign
|
||||||
uses: skymatic/code-sign-action@v1
|
uses: skymatic/code-sign-action@v2
|
||||||
with:
|
with:
|
||||||
certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
|
certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
|
||||||
password: ${{ secrets.WIN_CODESIGN_P12_PW }}
|
password: ${{ secrets.WIN_CODESIGN_P12_PW }}
|
||||||
@@ -118,6 +156,10 @@ jobs:
|
|||||||
timestampUrl: 'http://timestamp.digicert.com'
|
timestampUrl: 'http://timestamp.digicert.com'
|
||||||
folder: appdir/Cryptomator
|
folder: appdir/Cryptomator
|
||||||
recursive: true
|
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
|
- name: Generate license for MSI
|
||||||
run: >
|
run: >
|
||||||
mvn -B license:add-third-party
|
mvn -B license:add-third-party
|
||||||
@@ -139,8 +181,8 @@ jobs:
|
|||||||
--dest installer
|
--dest installer
|
||||||
--name Cryptomator
|
--name Cryptomator
|
||||||
--vendor "Skymatic GmbH"
|
--vendor "Skymatic GmbH"
|
||||||
--copyright "(C) 2016 - 2022 Skymatic GmbH"
|
--copyright "(C) 2016 - 2023 Skymatic GmbH"
|
||||||
--app-version "${{ steps.versions.outputs.semVerNum }}"
|
--app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum}}"
|
||||||
--win-menu
|
--win-menu
|
||||||
--win-dir-chooser
|
--win-dir-chooser
|
||||||
--win-shortcut-prompt
|
--win-shortcut-prompt
|
||||||
@@ -152,7 +194,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
JP_WIXWIZARD_RESOURCES: ${{ github.workspace }}/dist/win/resources # requires abs path, used in resources/main.wxs
|
JP_WIXWIZARD_RESOURCES: ${{ github.workspace }}/dist/win/resources # requires abs path, used in resources/main.wxs
|
||||||
- name: Codesign MSI
|
- name: Codesign MSI
|
||||||
uses: skymatic/code-sign-action@v1
|
uses: skymatic/code-sign-action@v2
|
||||||
with:
|
with:
|
||||||
certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
|
certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
|
||||||
password: ${{ secrets.WIN_CODESIGN_P12_PW }}
|
password: ${{ secrets.WIN_CODESIGN_P12_PW }}
|
||||||
@@ -161,7 +203,7 @@ jobs:
|
|||||||
timestampUrl: 'http://timestamp.digicert.com'
|
timestampUrl: 'http://timestamp.digicert.com'
|
||||||
folder: installer
|
folder: installer
|
||||||
- name: Add possible alpha/beta tags to installer name
|
- name: Add possible alpha/beta tags to installer name
|
||||||
run: mv installer/Cryptomator-*.msi Cryptomator-${{ steps.versions.outputs.semVerStr }}-x64.msi
|
run: mv installer/Cryptomator-*.msi Cryptomator-${{ needs.get-version.outputs.semVerStr }}-x64.msi
|
||||||
- name: Create detached GPG signature with key 615D449FE6E6A235
|
- name: Create detached GPG signature with key 615D449FE6E6A235
|
||||||
run: |
|
run: |
|
||||||
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
|
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
|
||||||
@@ -186,23 +228,11 @@ jobs:
|
|||||||
files: |
|
files: |
|
||||||
*.msi
|
*.msi
|
||||||
*.asc
|
*.asc
|
||||||
outputs:
|
|
||||||
semVerNum: ${{ steps.versions.outputs.semVerNum }}
|
|
||||||
semVerStr: ${{ steps.versions.outputs.semVerStr }}
|
|
||||||
revNum: ${{ steps.versions.outputs.revNum }}
|
|
||||||
|
|
||||||
call-winget-flow:
|
|
||||||
needs: [build-msi]
|
|
||||||
if: github.event.action == 'published'
|
|
||||||
uses: ./.github/workflows/winget.yml
|
|
||||||
with:
|
|
||||||
releaseTag: ${{ github.event.release.tag_name }}
|
|
||||||
|
|
||||||
|
|
||||||
build-exe:
|
build-exe:
|
||||||
name: Build .exe installer
|
name: Build .exe installer
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
needs: [build-msi]
|
needs: [get-version, build-msi]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Download .msi
|
- name: Download .msi
|
||||||
@@ -230,17 +260,18 @@ jobs:
|
|||||||
shell: pwsh
|
shell: pwsh
|
||||||
- name: Download WinFsp
|
- name: Download WinFsp
|
||||||
run: |
|
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
|
curl --output dist/win/bundle/resources/winfsp.msi -L $winfspUrl
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
- name: Compile to wixObj file
|
- name: Compile to wixObj file
|
||||||
run: >
|
run: >
|
||||||
"${WIX}/bin/candle.exe" dist/win/bundle/bundleWithWinfsp.wxs
|
"${WIX}/bin/candle.exe" dist/win/bundle/bundleWithWinfsp.wxs
|
||||||
-ext WixBalExtension
|
-ext WixBalExtension
|
||||||
|
-ext WixUtilExtension
|
||||||
-out dist/win/bundle/
|
-out dist/win/bundle/
|
||||||
-dBundleVersion="${{ needs.build-msi.outputs.semVerNum }}.${{ needs.build-msi.outputs.revNum }}"
|
-dBundleVersion="${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}"
|
||||||
-dBundleVendor="Skymatic GmbH"
|
-dBundleVendor="Skymatic GmbH"
|
||||||
-dBundleCopyright="(C) 2016 - 2022 Skymatic GmbH"
|
-dBundleCopyright="(C) 2016 - 2023 Skymatic GmbH"
|
||||||
-dAboutUrl="https://cryptomator.org"
|
-dAboutUrl="https://cryptomator.org"
|
||||||
-dHelpUrl="https://cryptomator.org/contact"
|
-dHelpUrl="https://cryptomator.org/contact"
|
||||||
-dUpdateUrl="https://cryptomator.org/downloads/"
|
-dUpdateUrl="https://cryptomator.org/downloads/"
|
||||||
@@ -248,6 +279,7 @@ jobs:
|
|||||||
run: >
|
run: >
|
||||||
"${WIX}/bin/light.exe" -b dist/win/ dist/win/bundle/bundleWithWinfsp.wixobj
|
"${WIX}/bin/light.exe" -b dist/win/ dist/win/bundle/bundleWithWinfsp.wixobj
|
||||||
-ext WixBalExtension
|
-ext WixBalExtension
|
||||||
|
-ext WixUtilExtension
|
||||||
-out installer/unsigned/Cryptomator-Installer.exe
|
-out installer/unsigned/Cryptomator-Installer.exe
|
||||||
- name: Detach burn engine in preparation to sign
|
- name: Detach burn engine in preparation to sign
|
||||||
run: >
|
run: >
|
||||||
@@ -255,7 +287,7 @@ jobs:
|
|||||||
-ib installer/unsigned/Cryptomator-Installer.exe
|
-ib installer/unsigned/Cryptomator-Installer.exe
|
||||||
-o tmp/engine.exe
|
-o tmp/engine.exe
|
||||||
- name: Codesign burn engine
|
- name: Codesign burn engine
|
||||||
uses: skymatic/code-sign-action@v1
|
uses: skymatic/code-sign-action@v2
|
||||||
with:
|
with:
|
||||||
certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
|
certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
|
||||||
password: ${{ secrets.WIN_CODESIGN_P12_PW }}
|
password: ${{ secrets.WIN_CODESIGN_P12_PW }}
|
||||||
@@ -269,7 +301,7 @@ jobs:
|
|||||||
-ab tmp/engine.exe installer/unsigned/Cryptomator-Installer.exe
|
-ab tmp/engine.exe installer/unsigned/Cryptomator-Installer.exe
|
||||||
-o installer/Cryptomator-Installer.exe
|
-o installer/Cryptomator-Installer.exe
|
||||||
- name: Codesign EXE
|
- name: Codesign EXE
|
||||||
uses: skymatic/code-sign-action@v1
|
uses: skymatic/code-sign-action@v2
|
||||||
with:
|
with:
|
||||||
certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
|
certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
|
||||||
password: ${{ secrets.WIN_CODESIGN_P12_PW }}
|
password: ${{ secrets.WIN_CODESIGN_P12_PW }}
|
||||||
@@ -278,7 +310,7 @@ jobs:
|
|||||||
timestampUrl: 'http://timestamp.digicert.com'
|
timestampUrl: 'http://timestamp.digicert.com'
|
||||||
folder: installer
|
folder: installer
|
||||||
- name: Add possible alpha/beta tags to installer name
|
- name: Add possible alpha/beta tags to installer name
|
||||||
run: mv installer/Cryptomator-Installer.exe Cryptomator-${{ needs.build-msi.outputs.semVerStr }}-x64.exe
|
run: mv installer/Cryptomator-Installer.exe Cryptomator-${{ needs.get-version.outputs.semVerStr }}-x64.exe
|
||||||
- name: Create detached GPG signature with key 615D449FE6E6A235
|
- name: Create detached GPG signature with key 615D449FE6E6A235
|
||||||
run: |
|
run: |
|
||||||
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
|
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
|
||||||
@@ -311,12 +343,12 @@ jobs:
|
|||||||
needs: [build-msi, build-exe]
|
needs: [build-msi, build-exe]
|
||||||
steps:
|
steps:
|
||||||
- name: Download .msi
|
- name: Download .msi
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: msi
|
name: msi
|
||||||
path: msi
|
path: msi
|
||||||
- name: Download .exe
|
- name: Download .exe
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: exe
|
name: exe
|
||||||
path: exe
|
path: exe
|
||||||
@@ -326,7 +358,7 @@ jobs:
|
|||||||
cp msi/*.msi files
|
cp msi/*.msi files
|
||||||
cp exe/*.exe files
|
cp exe/*.exe files
|
||||||
- name: Upload to Kaspersky
|
- name: Upload to Kaspersky
|
||||||
uses: SamKirkland/FTP-Deploy-Action@4.3.0
|
uses: SamKirkland/FTP-Deploy-Action@4.3.3
|
||||||
with:
|
with:
|
||||||
protocol: ftps
|
protocol: ftps
|
||||||
server: allowlist.kaspersky-labs.com
|
server: allowlist.kaspersky-labs.com
|
||||||
|
|||||||
@@ -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 msi artifacts
|
|
||||||
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.fastInit" value="enabled" />
|
||||||
<option name="dagger.formatGeneratedSource" value="enabled" />
|
<option name="dagger.formatGeneratedSource" value="enabled" />
|
||||||
<processorPath useClasspath="false">
|
<processorPath useClasspath="false">
|
||||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-compiler/2.44/dagger-compiler-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.44/dagger-2.44.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$/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/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/guava/31.0.1-jre/guava-31.0.1-jre.jar" />
|
||||||
<entry name="$MAVEN_REPOSITORY$/com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar" />
|
<entry name="$MAVEN_REPOSITORY$/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/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$/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$/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$/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/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/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$/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/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-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-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/googlejavaformat/google-java-format/1.5/google-java-format-1.5.jar" />
|
||||||
<entry name="$MAVEN_REPOSITORY$/com/google/errorprone/javac-shaded/9-dev-r4023-3/javac-shaded-9-dev-r4023-3.jar" />
|
<entry name="$MAVEN_REPOSITORY$/com/google/errorprone/javac-shaded/9-dev-r4023-3/javac-shaded-9-dev-r4023-3.jar" />
|
||||||
<entry name="$MAVEN_REPOSITORY$/net/ltgt/gradle/incap/incap/0.2/incap-0.2.jar" />
|
<entry name="$MAVEN_REPOSITORY$/net/ltgt/gradle/incap/incap/0.2/incap-0.2.jar" />
|
||||||
|
|||||||
Generated
+1
-1
@@ -8,7 +8,7 @@
|
|||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_19" default="true" project-jdk-name="19" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_20_PREVIEW" project-jdk-name="20" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -21,7 +21,6 @@ Cryptomator is provided free of charge as an open-source project despite the hig
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<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://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>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -33,6 +32,7 @@ Cryptomator is provided free of charge as an open-source project despite the hig
|
|||||||
<tr>
|
<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://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.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>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -61,7 +61,7 @@ Download native binaries of Cryptomator on [cryptomator.org](https://cryptomator
|
|||||||
- File names get encrypted
|
- File names get encrypted
|
||||||
- Folder structure gets obfuscated
|
- Folder structure gets obfuscated
|
||||||
- Use as many vaults in your Dropbox as you want, each having individual passwords
|
- Use as many vaults in your Dropbox as you want, each having individual passwords
|
||||||
- Three thousand commits for the security of your data!! :tada:
|
- Four thousand commits for the security of your data!! :tada:
|
||||||
|
|
||||||
### Privacy
|
### Privacy
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ Download native binaries of Cryptomator on [cryptomator.org](https://cryptomator
|
|||||||
|
|
||||||
### Consistency
|
### 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
|
- 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)
|
- 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)
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ For more information on the security details visit [cryptomator.org](https://doc
|
|||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
|
|
||||||
* JDK 17 (e.g. temurin)
|
* JDK 19 (e.g. temurin)
|
||||||
* Maven 3
|
* Maven 3
|
||||||
|
|
||||||
### Run Maven
|
### Run Maven
|
||||||
@@ -99,10 +99,6 @@ mvn clean install
|
|||||||
|
|
||||||
This will build all the jars and bundle them together with their OS-specific dependencies under `target`. This can now be used to build native packages.
|
This will build all the jars and bundle them together with their OS-specific dependencies under `target`. This can now be used to build native packages.
|
||||||
|
|
||||||
### Start Cryptomator
|
|
||||||
|
|
||||||
If you unzip the buildkit for your OS, you will find a launcher script with some basic settings. You might want to adjust these to your needs. To start Cryptomator, simply execute the launcher script from a terminal, e.g. `launcher-linux.sh`, if you're on a Linux system.
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is dual-licensed under the GPLv3 for FOSS projects as well as a commercial license for independent software vendors and resellers. If you want to modify this application under different conditions, feel free to contact our support team.
|
This project is dual-licensed under the GPLv3 for FOSS projects as well as a commercial license for independent software vendors and resellers. If you want to modify this application under different conditions, feel free to contact our support team.
|
||||||
|
|||||||
Vendored
+21
-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)
|
VERSION=$(mvn -f ../../../pom.xml help:evaluate -Dexpression=project.version -q -DforceStdout)
|
||||||
SEMVER_STR=${VERSION}
|
SEMVER_STR=${VERSION}
|
||||||
|
|
||||||
|
mvn -f ../../../pom.xml versions:set -DnewVersion=${SEMVER_STR}
|
||||||
|
|
||||||
# compile
|
# 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
|
cp ../../../target/cryptomator-*.jar ../../../target/mods
|
||||||
|
|
||||||
# add runtime
|
# add runtime
|
||||||
${JAVA_HOME}/bin/jlink \
|
${JAVA_HOME}/bin/jlink \
|
||||||
|
--verbose \
|
||||||
--output runtime \
|
--output runtime \
|
||||||
--module-path "${JAVA_HOME}/jmods" \
|
--module-path "${JAVA_HOME}/jmods" \
|
||||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr \
|
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.security.auth,jdk.accessibility,jdk.management.jfr \
|
||||||
--strip-native-commands \
|
--strip-native-commands \
|
||||||
--no-header-files \
|
--no-header-files \
|
||||||
--no-man-pages \
|
--no-man-pages \
|
||||||
@@ -27,7 +32,7 @@ ${JAVA_HOME}/bin/jlink \
|
|||||||
--compress=1
|
--compress=1
|
||||||
|
|
||||||
# create app dir
|
# 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 \
|
${JAVA_HOME}/bin/jpackage \
|
||||||
--verbose \
|
--verbose \
|
||||||
--type app-image \
|
--type app-image \
|
||||||
@@ -35,10 +40,12 @@ ${JAVA_HOME}/bin/jpackage \
|
|||||||
--input ../../../target/libs \
|
--input ../../../target/libs \
|
||||||
--module-path ../../../target/mods \
|
--module-path ../../../target/mods \
|
||||||
--module org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator \
|
--module org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator \
|
||||||
--dest . \
|
--dest appdir \
|
||||||
--name Cryptomator \
|
--name Cryptomator \
|
||||||
--vendor "Skymatic GmbH" \
|
--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 "-Xss5m" \
|
||||||
--java-options "-Xmx256m" \
|
--java-options "-Xmx256m" \
|
||||||
--app-version "${VERSION}.${REVISION_NO}" \
|
--app-version "${VERSION}.${REVISION_NO}" \
|
||||||
@@ -46,6 +53,7 @@ ${JAVA_HOME}/bin/jpackage \
|
|||||||
--java-options "-Dcryptomator.logDir=\"~/.local/share/Cryptomator/logs\"" \
|
--java-options "-Dcryptomator.logDir=\"~/.local/share/Cryptomator/logs\"" \
|
||||||
--java-options "-Dcryptomator.pluginDir=\"~/.local/share/Cryptomator/plugins\"" \
|
--java-options "-Dcryptomator.pluginDir=\"~/.local/share/Cryptomator/plugins\"" \
|
||||||
--java-options "-Dcryptomator.settingsPath=\"~/.config/Cryptomator/settings.json:~/.Cryptomator/settings.json\"" \
|
--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.ipcSocketPath=\"~/.config/Cryptomator/ipc.socket\"" \
|
||||||
--java-options "-Dcryptomator.mountPointsDir=\"~/.local/share/Cryptomator/mnt\"" \
|
--java-options "-Dcryptomator.mountPointsDir=\"~/.local/share/Cryptomator/mnt\"" \
|
||||||
--java-options "-Dcryptomator.showTrayIcon=false" \
|
--java-options "-Dcryptomator.showTrayIcon=false" \
|
||||||
@@ -54,9 +62,8 @@ ${JAVA_HOME}/bin/jpackage \
|
|||||||
--resource-dir ../resources
|
--resource-dir ../resources
|
||||||
|
|
||||||
# transform AppDir
|
# transform AppDir
|
||||||
mv Cryptomator Cryptomator.AppDir
|
mv appdir/Cryptomator Cryptomator.AppDir
|
||||||
cp -r resources/AppDir/* 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
|
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.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
|
cp ../common/org.cryptomator.Cryptomator512.png Cryptomator.AppDir/usr/share/icons/hicolor/512x512/apps/org.cryptomator.Cryptomator.png
|
||||||
@@ -70,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 usr/share/applications/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/Cryptomator.desktop
|
||||||
ln -s bin/cryptomator.sh Cryptomator.AppDir/AppRun
|
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
|
# load AppImageTool
|
||||||
curl -L https://github.com/AppImage/AppImageKit/releases/download/13/appimagetool-x86_64.AppImage -o /tmp/appimagetool.AppImage
|
curl -L https://github.com/AppImage/AppImageKit/releases/download/13/appimagetool-x86_64.AppImage -o /tmp/appimagetool.AppImage
|
||||||
chmod +x /tmp/appimagetool.AppImage
|
chmod +x /tmp/appimagetool.AppImage
|
||||||
@@ -83,5 +84,11 @@ chmod +x /tmp/appimagetool.AppImage
|
|||||||
# create AppImage
|
# create AppImage
|
||||||
/tmp/appimagetool.AppImage \
|
/tmp/appimagetool.AppImage \
|
||||||
Cryptomator.AppDir \
|
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'
|
-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 $?`
|
GTK3_PRESENT=`pacman -Qi gtk3 &> /dev/null; echo $?`
|
||||||
fi
|
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
|
if [ "$GTK2_PRESENT" -eq 0 ] && [ "$GTK3_PRESENT" -ne 0 ]; then
|
||||||
bin/Cryptomator-gtk2 $@
|
bin/Cryptomator-gtk2 $@
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -66,6 +66,15 @@
|
|||||||
</content_rating>
|
</content_rating>
|
||||||
|
|
||||||
<releases>
|
<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-10-06" version="1.6.15"/>
|
||||||
<release date="2022-08-31" version="1.6.14"/>
|
<release date="2022-08-31" version="1.6.14"/>
|
||||||
<release date="2022-07-27" version="1.6.12"/>
|
<release date="2022-07-27" version="1.6.12"/>
|
||||||
|
|||||||
Vendored
+2
-2
@@ -2,7 +2,7 @@ Source: cryptomator
|
|||||||
Maintainer: Cryptobot <releases@cryptomator.org>
|
Maintainer: Cryptobot <releases@cryptomator.org>
|
||||||
Section: utils
|
Section: utils
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Build-Depends: debhelper (>=10), coffeelibs-jdk-19
|
Build-Depends: debhelper (>=10), coffeelibs-jdk-20, libgtk2.0-0, libgtk-3-0, libxxf86vm1, libgl1
|
||||||
Standards-Version: 4.5.0
|
Standards-Version: 4.5.0
|
||||||
Homepage: https://cryptomator.org
|
Homepage: https://cryptomator.org
|
||||||
Vcs-Git: https://github.com/cryptomator/cryptomator.git
|
Vcs-Git: https://github.com/cryptomator/cryptomator.git
|
||||||
@@ -12,7 +12,7 @@ Package: cryptomator
|
|||||||
Architecture: any
|
Architecture: any
|
||||||
Section: utils
|
Section: utils
|
||||||
Priority: optional
|
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
|
Recommends: gvfs-backends, gvfs-fuse, gnome-keyring
|
||||||
XB-AppName: Cryptomator
|
XB-AppName: Cryptomator
|
||||||
XB-Category: Utility;Security;FileTools;
|
XB-Category: Utility;Security;FileTools;
|
||||||
|
|||||||
Vendored
+2
-2
@@ -4,11 +4,11 @@ Upstream-Contact: Cryptomator <info@cryptomator.org>
|
|||||||
Source: https://cryptomator.org
|
Source: https://cryptomator.org
|
||||||
|
|
||||||
Files: *
|
Files: *
|
||||||
Copyright: 2016-2022 Skymatic GmbH
|
Copyright: 2016-2023 Skymatic GmbH
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|
||||||
Files: debian/org.cryptomator.Cryptomator.appdata.xml
|
Files: debian/org.cryptomator.Cryptomator.appdata.xml
|
||||||
Copyright: 2016-2022 Skymatic GmbH
|
Copyright: 2016-2023 Skymatic GmbH
|
||||||
License: FSFAP
|
License: FSFAP
|
||||||
|
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
|
|||||||
-1
@@ -1,5 +1,4 @@
|
|||||||
cryptomator usr/lib
|
cryptomator usr/lib
|
||||||
debian/cryptomator.sh usr/lib/cryptomator/bin
|
|
||||||
common/org.cryptomator.Cryptomator.desktop usr/share/applications
|
common/org.cryptomator.Cryptomator.desktop usr/share/applications
|
||||||
common/org.cryptomator.Cryptomator.svg usr/share/icons/hicolor/scalable/apps
|
common/org.cryptomator.Cryptomator.svg usr/share/icons/hicolor/scalable/apps
|
||||||
common/org.cryptomator.Cryptomator256.png usr/share/icons/hicolor/256x256/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
+12
-10
@@ -4,7 +4,13 @@
|
|||||||
# Uncomment this to turn on verbose mode.
|
# Uncomment this to turn on verbose mode.
|
||||||
#export DH_VERBOSE=1
|
#export DH_VERBOSE=1
|
||||||
|
|
||||||
JAVA_HOME = /usr/lib/jvm/java-19-coffeelibs
|
JAVA_HOME = /usr/lib/jvm/java-20-coffeelibs
|
||||||
|
DEB_BUILD_ARCH ?= $(shell dpkg-architecture -qDEB_BUILD_ARCH)
|
||||||
|
ifeq ($(DEB_BUILD_ARCH),amd64)
|
||||||
|
JMODS_PATH = jmods/amd64:${JAVA_HOME}/jmods
|
||||||
|
else ifeq ($(DEB_BUILD_ARCH),arm64)
|
||||||
|
JMODS_PATH = jmods/aarch64:${JAVA_HOME}/jmods
|
||||||
|
endif
|
||||||
|
|
||||||
%:
|
%:
|
||||||
dh $@
|
dh $@
|
||||||
@@ -20,7 +26,8 @@ override_dh_auto_build:
|
|||||||
ln -s ../common/org.cryptomator.Cryptomator512.png resources/cryptomator.png
|
ln -s ../common/org.cryptomator.Cryptomator512.png resources/cryptomator.png
|
||||||
$(JAVA_HOME)/bin/jlink \
|
$(JAVA_HOME)/bin/jlink \
|
||||||
--output runtime \
|
--output runtime \
|
||||||
--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 \
|
--module-path "${JMODS_PATH}" \
|
||||||
|
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.security.auth,jdk.accessibility,jdk.management.jfr \
|
||||||
--strip-native-commands \
|
--strip-native-commands \
|
||||||
--no-header-files \
|
--no-header-files \
|
||||||
--no-man-pages \
|
--no-man-pages \
|
||||||
@@ -35,7 +42,9 @@ override_dh_auto_build:
|
|||||||
--dest . \
|
--dest . \
|
||||||
--name cryptomator \
|
--name cryptomator \
|
||||||
--vendor "Skymatic GmbH" \
|
--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 "-Xss5m" \
|
||||||
--java-options "-Xmx256m" \
|
--java-options "-Xmx256m" \
|
||||||
--java-options "-Dfile.encoding=\"utf-8\"" \
|
--java-options "-Dfile.encoding=\"utf-8\"" \
|
||||||
@@ -51,10 +60,3 @@ override_dh_auto_build:
|
|||||||
--app-version "${VERSION_NUM}.${REVISION_NUM}" \
|
--app-version "${VERSION_NUM}.${REVISION_NUM}" \
|
||||||
--resource-dir resources \
|
--resource-dir resources \
|
||||||
--verbose
|
--verbose
|
||||||
|
|
||||||
override_dh_fixperms:
|
|
||||||
dh_fixperms
|
|
||||||
chmod +x debian/cryptomator/usr/lib/cryptomator/bin/cryptomator.sh
|
|
||||||
|
|
||||||
# override_dh_strip:
|
|
||||||
# no-op
|
|
||||||
|
|||||||
Vendored
+2
@@ -1,5 +1,7 @@
|
|||||||
java-options=-Xss5m \
|
java-options=-Xss5m \
|
||||||
-Xmx256m \
|
-Xmx256m \
|
||||||
|
--enable-preview \
|
||||||
|
--enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64 \
|
||||||
-Dfile.encoding=\"utf-8\" \
|
-Dfile.encoding=\"utf-8\" \
|
||||||
-Dcryptomator.appVersion=\"${SEMVER_STR}\" \
|
-Dcryptomator.appVersion=\"${SEMVER_STR}\" \
|
||||||
-Dcryptomator.logDir=\"~/.local/share/Cryptomator/logs\" \
|
-Dcryptomator.logDir=\"~/.local/share/Cryptomator/logs\" \
|
||||||
|
|||||||
Vendored
-13
@@ -1,13 +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 \
|
|
||||||
-m org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator
|
|
||||||
Vendored
+9
-5
@@ -21,12 +21,13 @@ rm -rf runtime dmg *.app *.dmg
|
|||||||
# set variables
|
# set variables
|
||||||
APP_NAME="Cryptomator"
|
APP_NAME="Cryptomator"
|
||||||
VENDOR="Skymatic GmbH"
|
VENDOR="Skymatic GmbH"
|
||||||
COPYRIGHT_YEARS="2016 - 2022"
|
COPYRIGHT_YEARS="2016 - 2023"
|
||||||
PACKAGE_IDENTIFIER="org.cryptomator"
|
PACKAGE_IDENTIFIER="org.cryptomator"
|
||||||
MAIN_JAR_GLOB="cryptomator-*.jar"
|
MAIN_JAR_GLOB="cryptomator-*.jar"
|
||||||
MODULE_AND_MAIN_CLASS="org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator"
|
MODULE_AND_MAIN_CLASS="org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator"
|
||||||
REVISION_NO=`git rev-list --count HEAD`
|
REVISION_NO=`git rev-list --count HEAD`
|
||||||
VERSION_NO=`mvn -f../../../pom.xml help:evaluate -Dexpression=project.version -q -DforceStdout | sed -rn 's/.*([0-9]+\.[0-9]+\.[0-9]+).*/\1/p'`
|
VERSION_NO=`mvn -f../../../pom.xml help:evaluate -Dexpression=project.version -q -DforceStdout | sed -rn 's/.*([0-9]+\.[0-9]+\.[0-9]+).*/\1/p'`
|
||||||
|
FUSE_LIB="FUSE-T"
|
||||||
|
|
||||||
# check preconditions
|
# check preconditions
|
||||||
if [ -z "${JAVA_HOME}" ]; then echo "JAVA_HOME not set. Run using JAVA_HOME=/path/to/jdk ./build.sh"; exit 1; fi
|
if [ -z "${JAVA_HOME}" ]; then echo "JAVA_HOME not set. Run using JAVA_HOME=/path/to/jdk ./build.sh"; exit 1; fi
|
||||||
@@ -65,6 +66,8 @@ ${JAVA_HOME}/bin/jpackage \
|
|||||||
--vendor "${VENDOR}" \
|
--vendor "${VENDOR}" \
|
||||||
--copyright "(C) ${COPYRIGHT_YEARS} ${VENDOR}" \
|
--copyright "(C) ${COPYRIGHT_YEARS} ${VENDOR}" \
|
||||||
--app-version "${VERSION_NO}" \
|
--app-version "${VERSION_NO}" \
|
||||||
|
--java-options "--enable-preview" \
|
||||||
|
--java-options "--enable-native-access=org.cryptomator.jfuse.mac" \
|
||||||
--java-options "-Xss5m" \
|
--java-options "-Xss5m" \
|
||||||
--java-options "-Xmx256m" \
|
--java-options "-Xmx256m" \
|
||||||
--java-options "-Dfile.encoding=\"utf-8\"" \
|
--java-options "-Dfile.encoding=\"utf-8\"" \
|
||||||
@@ -77,6 +80,7 @@ ${JAVA_HOME}/bin/jpackage \
|
|||||||
--java-options "-Dcryptomator.ipcSocketPath=\"~/Library/Application Support/${APP_NAME}/ipc.socket\"" \
|
--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.p12Path=\"~/Library/Application Support/${APP_NAME}/key.p12\"" \
|
||||||
--java-options "-Dcryptomator.integrationsMac.keychainServiceName=\"${APP_NAME}\"" \
|
--java-options "-Dcryptomator.integrationsMac.keychainServiceName=\"${APP_NAME}\"" \
|
||||||
|
--java-options "-Dcryptomator.mountPointsDir=\"~/${APP_NAME}\"" \
|
||||||
--java-options "-Dcryptomator.showTrayIcon=true" \
|
--java-options "-Dcryptomator.showTrayIcon=true" \
|
||||||
--java-options "-Dcryptomator.buildNumber=\"dmg-${REVISION_NO}\"" \
|
--java-options "-Dcryptomator.buildNumber=\"dmg-${REVISION_NO}\"" \
|
||||||
--mac-package-identifier ${PACKAGE_IDENTIFIER} \
|
--mac-package-identifier ${PACKAGE_IDENTIFIER} \
|
||||||
@@ -122,20 +126,20 @@ fi
|
|||||||
# prepare dmg contents
|
# prepare dmg contents
|
||||||
mkdir dmg
|
mkdir dmg
|
||||||
mv ${APP_NAME}.app dmg
|
mv ${APP_NAME}.app dmg
|
||||||
cp resources/macFUSE.webloc dmg
|
cp resources/${FUSE_LIB}.webloc dmg
|
||||||
|
|
||||||
# create dmg
|
# create dmg
|
||||||
create-dmg \
|
create-dmg \
|
||||||
--volname ${APP_NAME} \
|
--volname ${APP_NAME} \
|
||||||
--volicon "resources/${APP_NAME}-Volume.icns" \
|
--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-pos 400 100 \
|
||||||
--window-size 640 694 \
|
--window-size 640 694 \
|
||||||
--icon-size 128 \
|
--icon-size 128 \
|
||||||
--icon "${APP_NAME}.app" 128 245 \
|
--icon "${APP_NAME}.app" 128 245 \
|
||||||
--hide-extension "${APP_NAME}.app" \
|
--hide-extension "${APP_NAME}.app" \
|
||||||
--icon "macFUSE.webloc" 320 501 \
|
--icon "${FUSE_LIB}.webloc" 320 501 \
|
||||||
--hide-extension "macFUSE.webloc" \
|
--hide-extension "${FUSE_LIB}.webloc" \
|
||||||
--app-drop-link 512 245 \
|
--app-drop-link 512 245 \
|
||||||
--eula "resources/license.rtf" \
|
--eula "resources/license.rtf" \
|
||||||
--icon ".background" 128 758 \
|
--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 \
|
\f1\b0 \
|
||||||
\
|
\
|
||||||
|
|
||||||
\f0\b \'a9 2016 \'96 2022 Skymatic GmbH
|
\f0\b \'a9 2016 \'96 2023 Skymatic GmbH
|
||||||
\f1\b0 \
|
\f1\b0 \
|
||||||
\
|
\
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\
|
||||||
|
|||||||
Vendored
-12
@@ -1,12 +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 \
|
|
||||||
-m org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator
|
|
||||||
Vendored
+3
-1
@@ -9,8 +9,9 @@ SET ABOUT_URL="https://cryptomator.org"
|
|||||||
SET UPDATE_URL="https://cryptomator.org/downloads/"
|
SET UPDATE_URL="https://cryptomator.org/downloads/"
|
||||||
SET HELP_URL="https://cryptomator.org/contact/"
|
SET HELP_URL="https://cryptomator.org/contact/"
|
||||||
SET MODULE_AND_MAIN_CLASS="org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator"
|
SET MODULE_AND_MAIN_CLASS="org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator"
|
||||||
|
SET LOOPBACK_ALIAS="cryptomator-vault"
|
||||||
|
|
||||||
powershell -NoLogo -NoExit -ExecutionPolicy Unrestricted -Command .\build.ps1^
|
powershell -NoLogo -ExecutionPolicy Unrestricted -Command .\build.ps1^
|
||||||
-AppName %APPNAME%^
|
-AppName %APPNAME%^
|
||||||
-MainJarGlob "%MAIN_JAR_GLOB%"^
|
-MainJarGlob "%MAIN_JAR_GLOB%"^
|
||||||
-ModuleAndMainClass "%MODULE_AND_MAIN_CLASS%"^
|
-ModuleAndMainClass "%MODULE_AND_MAIN_CLASS%"^
|
||||||
@@ -20,4 +21,5 @@ powershell -NoLogo -NoExit -ExecutionPolicy Unrestricted -Command .\build.ps1^
|
|||||||
-AboutUrl "%ABOUT_URL%"^
|
-AboutUrl "%ABOUT_URL%"^
|
||||||
-HelpUrl "%HELP_URL%"^
|
-HelpUrl "%HELP_URL%"^
|
||||||
-UpdateUrl "%UPDATE_URL%"^
|
-UpdateUrl "%UPDATE_URL%"^
|
||||||
|
-LoopbackAlias "%LOOPBACK_ALIAS%"^
|
||||||
-Clean 1
|
-Clean 1
|
||||||
Vendored
+16
-4
@@ -8,6 +8,7 @@ Param(
|
|||||||
[Parameter(Mandatory, HelpMessage="Please provide a help url")][string] $HelpUrl,
|
[Parameter(Mandatory, HelpMessage="Please provide a help url")][string] $HelpUrl,
|
||||||
[Parameter(Mandatory, HelpMessage="Please provide an update url")][string] $UpdateUrl,
|
[Parameter(Mandatory, HelpMessage="Please provide an update url")][string] $UpdateUrl,
|
||||||
[Parameter(Mandatory, HelpMessage="Please provide an about url")][string] $AboutUrl,
|
[Parameter(Mandatory, HelpMessage="Please provide an about url")][string] $AboutUrl,
|
||||||
|
[Parameter(Mandatory, HelpMessage="Please provide an alias for localhost")][string] $LoopbackAlias,
|
||||||
[bool] $clean
|
[bool] $clean
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -74,6 +75,8 @@ if ($clean -and (Test-Path -Path $appPath)) {
|
|||||||
--name $AppName `
|
--name $AppName `
|
||||||
--vendor $Vendor `
|
--vendor $Vendor `
|
||||||
--copyright $copyright `
|
--copyright $copyright `
|
||||||
|
--java-options "--enable-preview" `
|
||||||
|
--java-options "--enable-native-access=org.cryptomator.jfuse.win" `
|
||||||
--java-options "-Xss5m" `
|
--java-options "-Xss5m" `
|
||||||
--java-options "-Xmx256m" `
|
--java-options "-Xmx256m" `
|
||||||
--java-options "-Dcryptomator.appVersion=`"$semVerNo`"" `
|
--java-options "-Dcryptomator.appVersion=`"$semVerNo`"" `
|
||||||
@@ -85,6 +88,7 @@ if ($clean -and (Test-Path -Path $appPath)) {
|
|||||||
--java-options "-Dcryptomator.ipcSocketPath=`"~/AppData/Roaming/$AppName/ipc.socket`"" `
|
--java-options "-Dcryptomator.ipcSocketPath=`"~/AppData/Roaming/$AppName/ipc.socket`"" `
|
||||||
--java-options "-Dcryptomator.p12Path=`"~/AppData/Roaming/$AppName/key.p12`"" `
|
--java-options "-Dcryptomator.p12Path=`"~/AppData/Roaming/$AppName/key.p12`"" `
|
||||||
--java-options "-Dcryptomator.mountPointsDir=`"~/$AppName`"" `
|
--java-options "-Dcryptomator.mountPointsDir=`"~/$AppName`"" `
|
||||||
|
--java-options "-Dcryptomator.loopbackAlias=`"$LoopbackAlias`"" `
|
||||||
--java-options "-Dcryptomator.integrationsWin.autoStartShellLinkName=`"$AppName`"" `
|
--java-options "-Dcryptomator.integrationsWin.autoStartShellLinkName=`"$AppName`"" `
|
||||||
--java-options "-Dcryptomator.integrationsWin.keychainPaths=`"~/AppData/Roaming/$AppName/keychain.json`"" `
|
--java-options "-Dcryptomator.integrationsWin.keychainPaths=`"~/AppData/Roaming/$AppName/keychain.json`"" `
|
||||||
--java-options "-Dcryptomator.showTrayIcon=true" `
|
--java-options "-Dcryptomator.showTrayIcon=true" `
|
||||||
@@ -105,6 +109,14 @@ if ($clean -and (Test-Path -Path $appPath)) {
|
|||||||
# patch app dir
|
# patch app dir
|
||||||
Copy-Item "contrib\*" -Destination "$AppName"
|
Copy-Item "contrib\*" -Destination "$AppName"
|
||||||
attrib -r "$AppName\$AppName.exe"
|
attrib -r "$AppName\$AppName.exe"
|
||||||
|
# patch batch script to set hostfile
|
||||||
|
$webDAVPatcher = "$AppName\patchWebDAV.bat"
|
||||||
|
try {
|
||||||
|
(Get-Content $webDAVPatcher ) -replace '::REPLACE ME', "SET LOOPBACK_ALIAS=`"$LoopbackAlias`"" | Set-Content $webDAVPatcher
|
||||||
|
} catch {
|
||||||
|
Write-Host "Failed to set LOOPBACK_ALIAS for patchWebDAV.bat"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
# create .msi
|
# create .msi
|
||||||
$Env:JP_WIXWIZARD_RESOURCES = "$buildDir\resources"
|
$Env:JP_WIXWIZARD_RESOURCES = "$buildDir\resources"
|
||||||
@@ -117,7 +129,7 @@ $Env:JP_WIXWIZARD_RESOURCES = "$buildDir\resources"
|
|||||||
--name $AppName `
|
--name $AppName `
|
||||||
--vendor $Vendor `
|
--vendor $Vendor `
|
||||||
--copyright $copyright `
|
--copyright $copyright `
|
||||||
--app-version "$semVerNo" `
|
--app-version "$semVerNo.$revisionNo" `
|
||||||
--win-menu `
|
--win-menu `
|
||||||
--win-dir-chooser `
|
--win-dir-chooser `
|
||||||
--win-shortcut-prompt `
|
--win-shortcut-prompt `
|
||||||
@@ -141,7 +153,7 @@ $Env:JP_WIXWIZARD_RESOURCES = "$buildDir\resources"
|
|||||||
# download Winfsp
|
# download Winfsp
|
||||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||||
$ProgressPreference = 'SilentlyContinue' # disables Invoke-WebRequest's progress bar, which slows down downloads to a few bytes/s
|
$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}..."
|
Write-Output "Downloading ${winfspMsiUrl}..."
|
||||||
Invoke-WebRequest $winfspMsiUrl -OutFile ".\bundle\resources\winfsp.msi" # redirects are followed by default
|
Invoke-WebRequest $winfspMsiUrl -OutFile ".\bundle\resources\winfsp.msi" # redirects are followed by default
|
||||||
|
|
||||||
@@ -149,11 +161,11 @@ Invoke-WebRequest $winfspMsiUrl -OutFile ".\bundle\resources\winfsp.msi" # redir
|
|||||||
Copy-Item ".\installer\$AppName-*.msi" -Destination ".\bundle\resources\$AppName.msi"
|
Copy-Item ".\installer\$AppName-*.msi" -Destination ".\bundle\resources\$AppName.msi"
|
||||||
|
|
||||||
# create bundle including winfsp
|
# 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" `
|
-dBundleVersion="$semVerNo.$revisionNo" `
|
||||||
-dBundleVendor="$Vendor" `
|
-dBundleVendor="$Vendor" `
|
||||||
-dBundleCopyright="$copyright" `
|
-dBundleCopyright="$copyright" `
|
||||||
-dAboutUrl="$AboutUrl" `
|
-dAboutUrl="$AboutUrl" `
|
||||||
-dHelpUrl="$HelpUrl" `
|
-dHelpUrl="$HelpUrl" `
|
||||||
-dUpdateUrl="$UpdateUrl"
|
-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"?>
|
<?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-->
|
<!-- see https://wixtoolset.org/documentation/manual/v3/xsd/wix/bundle.html-->
|
||||||
<!-- Attributes explicitly not used:
|
<!-- Attributes explicitly not used:
|
||||||
Condition - the single msi files have their own install conditions, no need to copy them here
|
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)"
|
<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">
|
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/-->
|
<!-- for definition of the standard themes, see https://github.com/wixtoolset/wix3/blob/master/src/ext/BalExtension/wixstdba/Resources/-->
|
||||||
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLargeLicense">
|
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLargeLicense">
|
||||||
<!-- see https://wixtoolset.org/documentation/manual/v3/xsd/bal/wixstandardbootstrapperapplication.html -->
|
<!-- 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="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="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="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" />
|
<Image X="11" Y="11" Width="64" Height="64" ImageFile="logo.png" />
|
||||||
<Text X="80" Y="11" Width="-11" Height="64" FontId="1" DisablePrefix="yes">#(loc.Title)</Text>
|
<Text X="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="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>
|
<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="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>
|
<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="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>
|
<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
|
\vieww12000\viewh15840\viewkind0
|
||||||
\pard\tx283\tx567\tx850\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\b\fs16\lang7 Cryptomator is distributed under the GPLv3 License, found below. Please see the bottom of this document for any other license applicable to code used within Cryptomator.\b0\par
|
\pard\tx283\tx567\tx850\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\b\fs16\lang7 Cryptomator is distributed under the GPLv3 License, found below. Please see the bottom of this document for any other license applicable to code used within Cryptomator.\b0\par
|
||||||
\par
|
\par
|
||||||
\b\'a9 2016 \'96 2022 Skymatic GmbH \b0\par
|
\b\'a9 2016 \'96 2023 Skymatic GmbH \b0\par
|
||||||
\par
|
\par
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\par
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\par
|
||||||
\par
|
\par
|
||||||
|
|||||||
@@ -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
|
|
||||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
@echo off
|
@echo off
|
||||||
:: Default values for Cryptomator builds
|
:: Default values for Cryptomator builds
|
||||||
SET LOOPBACK_ALIAS="cryptomator-vault"
|
::REPLACE ME
|
||||||
|
|
||||||
cd %~dp0
|
cd %~dp0
|
||||||
powershell -NoLogo -NonInteractive -ExecutionPolicy Unrestricted -Command .\patchWebDAV.ps1^
|
powershell -NoLogo -NonInteractive -ExecutionPolicy Unrestricted -Command .\patchWebDAV.ps1^
|
||||||
|
|||||||
@@ -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
@@ -9,4 +9,6 @@ java ^
|
|||||||
-Dcryptomator.keychainPath="~/AppData/Roaming/Cryptomator/keychain.json" ^
|
-Dcryptomator.keychainPath="~/AppData/Roaming/Cryptomator/keychain.json" ^
|
||||||
-Xss20m ^
|
-Xss20m ^
|
||||||
-Xmx512m ^
|
-Xmx512m ^
|
||||||
|
--enable-preview `
|
||||||
|
--enable-native-access=org.cryptomator.jfuse.win `
|
||||||
-m org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator
|
-m org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator
|
||||||
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)" />
|
<Control Id="Title" Type="Text" X="135" Y="20" Width="220" Height="60" Transparent="yes" NoPrefix="yes" Text="!(loc.ExitDialogTitle)" />
|
||||||
<!-- TODO: localize? -->
|
<!-- TODO: localize? -->
|
||||||
<Control Id="Suggestion" Type="Text" X="135" Y="100" Width="220" Height="60" Transparent="yes" NoPrefix="yes">
|
<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>
|
||||||
<Control Id="WinFsp" Type="Hyperlink" X="140" Y="125" Width="220" Height="60" Transparent="yes">
|
<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>
|
<Text><![CDATA[WinFsp (<a href="https://winfsp.dev/">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>
|
|
||||||
</Control>
|
</Control>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@
|
|||||||
\vieww12000\viewh15840\viewkind0
|
\vieww12000\viewh15840\viewkind0
|
||||||
\pard\tx283\tx567\tx850\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\b\fs16\lang7 Cryptomator is distributed under the GPLv3 License, found below. Please see the bottom of this document for any other license applicable to code used within Cryptomator.\b0\par
|
\pard\tx283\tx567\tx850\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\b\fs16\lang7 Cryptomator is distributed under the GPLv3 License, found below. Please see the bottom of this document for any other license applicable to code used within Cryptomator.\b0\par
|
||||||
\par
|
\par
|
||||||
\b\'a9 2016 \'96 2022 Skymatic GmbH \b0\par
|
\b\'a9 2016 \'96 2023 Skymatic GmbH \b0\par
|
||||||
\par
|
\par
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\par
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\par
|
||||||
\par
|
\par
|
||||||
|
|||||||
Vendored
+33
-16
@@ -23,6 +23,11 @@
|
|||||||
<?define JpUpgradeVersionOnlyDetectDowngrade="yes"?>
|
<?define JpUpgradeVersionOnlyDetectDowngrade="yes"?>
|
||||||
<?endif?>
|
<?endif?>
|
||||||
|
|
||||||
|
<!-- Cryptomator defaults -->
|
||||||
|
<?define IconFileEncryptedData= "Cryptomator-Vault.ico" ?>
|
||||||
|
<?define ProgIdContentType= "application/vnd.cryptomator.encrypted" ?>
|
||||||
|
<?define CloseApplicationTarget= "cryptomator.exe" ?>
|
||||||
|
|
||||||
<?include $(var.JpConfigDir)/overrides.wxi ?>
|
<?include $(var.JpConfigDir)/overrides.wxi ?>
|
||||||
|
|
||||||
<Product
|
<Product
|
||||||
@@ -49,7 +54,7 @@
|
|||||||
Property="JP_UPGRADABLE_FOUND"
|
Property="JP_UPGRADABLE_FOUND"
|
||||||
Maximum="$(var.JpAppVersion)"
|
Maximum="$(var.JpAppVersion)"
|
||||||
MigrateFeatures="yes"
|
MigrateFeatures="yes"
|
||||||
IncludeMaximum="$(var.JpUpgradeVersionOnlyDetectUpgrade)" />
|
IncludeMaximum="yes" /> <!-- TODO: check if this needs to be set to yes-->
|
||||||
<UpgradeVersion
|
<UpgradeVersion
|
||||||
OnlyDetect="$(var.JpUpgradeVersionOnlyDetectDowngrade)"
|
OnlyDetect="$(var.JpUpgradeVersionOnlyDetectDowngrade)"
|
||||||
Property="JP_DOWNGRADABLE_FOUND"
|
Property="JP_DOWNGRADABLE_FOUND"
|
||||||
@@ -65,16 +70,19 @@
|
|||||||
<CustomAction Id="JpDisallowDowngrade" Error="!(loc.DowngradeErrorMessage)" />
|
<CustomAction Id="JpDisallowDowngrade" Error="!(loc.DowngradeErrorMessage)" />
|
||||||
<?endif?>
|
<?endif?>
|
||||||
|
|
||||||
|
<Binary Id="JpCaDll" SourceFile="wixhelper.dll"/>
|
||||||
|
<CustomAction Id="JpFindRelatedProducts" BinaryKey="JpCaDll" DllEntry="FindRelatedProductsEx" />
|
||||||
|
|
||||||
<!-- Looking for legacy Cryptomator versions-->
|
<?ifndef SkipCryptomatorLegacyCheck ?>
|
||||||
<Property Id="OLDEXEINSTALLER">
|
<!-- Block installation if innosetup entry of Cryptomator is found -->
|
||||||
<RegistrySearch Id="InnoSetupInstallation" Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\Cryptomator_is1" Type="raw" Name="DisplayName" />
|
<Property Id="OLDEXEINSTALLER">
|
||||||
</Property>
|
<RegistrySearch Id="InnoSetupInstallation" Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\Cryptomator_is1" Type="raw" Name="DisplayName" />
|
||||||
<!-- Block installation if innosetup entry of Cryptomator is found -->
|
</Property>
|
||||||
<!-- TODO: localize -->
|
<!-- TODO: localize -->
|
||||||
<Condition Message="A lower version of [ProductName] is already installed. Uninstall it first and then start the setup again. Setup will now exit.">
|
<Condition Message="A lower version of [ProductName] is already installed. Uninstall it first and then start the setup again. Setup will now exit.">
|
||||||
<![CDATA[Installed OR NOT OLDEXEINSTALLER]]>
|
<![CDATA[Installed OR NOT OLDEXEINSTALLER]]>
|
||||||
</Condition>
|
</Condition>
|
||||||
|
<?endif?>
|
||||||
<!-- Cryptomator uses UNIX Sockets, which are supported starting with Windows 10 v1803-->
|
<!-- Cryptomator uses UNIX Sockets, which are supported starting with Windows 10 v1803-->
|
||||||
<Property Id="WINDOWSBUILDNUMBER" Secure="yes">
|
<Property Id="WINDOWSBUILDNUMBER" Secure="yes">
|
||||||
<RegistrySearch Id="BuildNumberSearch" Root="HKLM" Key="SOFTWARE\Microsoft\Windows NT\CurrentVersion" Name="CurrentBuildNumber" Type="raw" />
|
<RegistrySearch Id="BuildNumberSearch" Root="HKLM" Key="SOFTWARE\Microsoft\Windows NT\CurrentVersion" Name="CurrentBuildNumber" Type="raw" />
|
||||||
@@ -86,7 +94,7 @@
|
|||||||
<!-- Non-Opening ProgID -->
|
<!-- Non-Opening ProgID -->
|
||||||
<DirectoryRef Id="INSTALLDIR">
|
<DirectoryRef Id="INSTALLDIR">
|
||||||
<Component Win64="yes" Id="nonStartingProgID" >
|
<Component Win64="yes" Id="nonStartingProgID" >
|
||||||
<File Id="IconFileForEncryptedData" KeyPath="yes" Source="$(env.JP_WIXWIZARD_RESOURCES)\$(var.IconFileC9rC9s)" Name="$(var.IconFileC9rC9s)"></File>
|
<File Id="IconFileForEncryptedData" KeyPath="yes" Source="$(env.JP_WIXWIZARD_RESOURCES)\$(var.IconFileEncryptedData)" Name="$(var.IconFileEncryptedData)"></File>
|
||||||
<ProgId Id="$(var.JpAppName).Encrypted.1" Description="$(var.JpAppName) Encrypted Data" Icon="IconFileForEncryptedData" IconIndex="0">
|
<ProgId Id="$(var.JpAppName).Encrypted.1" Description="$(var.JpAppName) Encrypted Data" Icon="IconFileForEncryptedData" IconIndex="0">
|
||||||
<Extension Id="c9r" Advertise="no" ContentType="$(var.ProgIdContentType)">
|
<Extension Id="c9r" Advertise="no" ContentType="$(var.ProgIdContentType)">
|
||||||
<MIME ContentType="$(var.ProgIdContentType)" Default="yes"></MIME>
|
<MIME ContentType="$(var.ProgIdContentType)" Default="yes"></MIME>
|
||||||
@@ -127,6 +135,9 @@
|
|||||||
<!-- WebDAV patches -->
|
<!-- WebDAV patches -->
|
||||||
<CustomAction Id="PatchWebDAV" Impersonate="no" ExeCommand="[INSTALLDIR]patchWebDAV.bat" Directory="INSTALLDIR" Execute="deferred" Return="asyncWait" />
|
<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 -->
|
<!-- Running App detection and exit -->
|
||||||
<Property Id="FOUNDRUNNINGAPP" Admin="yes"/>
|
<Property Id="FOUNDRUNNINGAPP" Admin="yes"/>
|
||||||
<util:CloseApplication
|
<util:CloseApplication
|
||||||
@@ -135,11 +146,11 @@
|
|||||||
CloseMessage="no"
|
CloseMessage="no"
|
||||||
RebootPrompt="no"
|
RebootPrompt="no"
|
||||||
PromptToContinue="yes"
|
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"
|
Property="FOUNDRUNNINGAPP"
|
||||||
>
|
>
|
||||||
</util:CloseApplication>
|
</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 ?>
|
<?ifdef JpIcon ?>
|
||||||
<Property Id="ARPPRODUCTICON" Value="JpARPPRODUCTICON"/>
|
<Property Id="ARPPRODUCTICON" Value="JpARPPRODUCTICON"/>
|
||||||
@@ -164,21 +175,27 @@
|
|||||||
<?endif?>
|
<?endif?>
|
||||||
|
|
||||||
<?ifndef JpAllowUpgrades ?>
|
<?ifndef JpAllowUpgrades ?>
|
||||||
<Custom Action="JpDisallowUpgrade" After="FindRelatedProducts">JP_UPGRADABLE_FOUND</Custom>
|
<Custom Action="JpDisallowUpgrade" After="JpFindRelatedProducts">JP_UPGRADABLE_FOUND</Custom>
|
||||||
<?endif?>
|
<?endif?>
|
||||||
<?ifndef JpAllowDowngrades ?>
|
<?ifndef JpAllowDowngrades ?>
|
||||||
<Custom Action="JpDisallowDowngrade" After="FindRelatedProducts">JP_DOWNGRADABLE_FOUND</Custom>
|
<Custom Action="JpDisallowDowngrade" After="JpFindRelatedProducts">JP_DOWNGRADABLE_FOUND</Custom>
|
||||||
<?endif?>
|
<?endif?>
|
||||||
|
<Custom Action="JpFindRelatedProducts" After="FindRelatedProducts"/>
|
||||||
|
|
||||||
<!-- Check and fail if Cryptomator is running -->
|
<!-- Check and fail if Cryptomator is running -->
|
||||||
<Custom Action="WixCloseApplications" Before="InstallValidate"></Custom>
|
<Custom Action="WixCloseApplications" Before="InstallValidate"></Custom>
|
||||||
<Custom Action="FailOnRunningApp" After="WixCloseApplications" >FOUNDRUNNINGAPP</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="PatchWebDAV" After="InstallFiles">NOT Installed OR REINSTALL</Custom>
|
||||||
|
<Custom Action="V170MigrateSettings" After="InstallFiles">NOT Installed OR REINSTALL</Custom>
|
||||||
</InstallExecuteSequence>
|
</InstallExecuteSequence>
|
||||||
|
|
||||||
|
<InstallUISequence>
|
||||||
|
<Custom Action="JpFindRelatedProducts" After="FindRelatedProducts"/>
|
||||||
|
</InstallUISequence>
|
||||||
|
|
||||||
<WixVariable Id="WixUIBannerBmp" Value="$(env.JP_WIXWIZARD_RESOURCES)\banner.bmp" />
|
<WixVariable Id="WixUIBannerBmp" Value="$(env.JP_WIXWIZARD_RESOURCES)\banner.bmp" />
|
||||||
<WixVariable Id="WixUIDialogBmp" Value="$(env.JP_WIXWIZARD_RESOURCES)\background.bmp" />
|
<WixVariable Id="WixUIDialogBmp" Value="$(env.JP_WIXWIZARD_RESOURCES)\background.bmp" />
|
||||||
</Product>
|
</Product>
|
||||||
|
|||||||
Vendored
+17
-6
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Stub by design -->
|
<!-- Stub by design -->
|
||||||
|
|
||||||
<!--
|
<!-- jPackage Section
|
||||||
overrides.wxi is a placeholder to set/alter WiX variables referenced from default
|
overrides.wxi is a placeholder to set/alter WiX variables referenced from default
|
||||||
main.wxs file.
|
main.wxs file.
|
||||||
|
|
||||||
@@ -30,10 +30,21 @@ Should be defined to enable upgrades and undefined to disable upgrades.
|
|||||||
Default value is `yes`.
|
Default value is `yes`.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!-- Non-opening ProgID settings-->
|
<!-- Cryptomator Section
|
||||||
<?define IconFileC9rC9s= "Cryptomator-Vault.ico" ?>
|
|
||||||
<?define ProgIdContentType= "application/vnd.cryptomator.encrypted" ?>
|
|
||||||
|
|
||||||
<!-- Close Application util -->
|
Non-opening ProgID settings:
|
||||||
<?define CloseApplicationTarget= "cryptomator.exe" ?>
|
- IconFileEncryptedData
|
||||||
|
Full file name of icon file used for encrypted data files. Default is "Cryptomator-Vault.ico"
|
||||||
|
|
||||||
|
- ProgIdContentType
|
||||||
|
Media Type of the encrypted data files. Default is "application/vnd.cryptomator.encrypted"
|
||||||
|
|
||||||
|
Close Application settings:
|
||||||
|
- CloseApplicationTarget
|
||||||
|
Full name of executable to be checkd in the close application util. Default is "cryptomator.exe"
|
||||||
|
|
||||||
|
Legacy Installation settings:
|
||||||
|
- SkipCryptomatorLegacyCheck
|
||||||
|
Should be defined to disable checking for the inno setup installation of Cryptomator and undefined, to enable it.
|
||||||
|
-->
|
||||||
<Include/>
|
<Include/>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>org.cryptomator</groupId>
|
<groupId>org.cryptomator</groupId>
|
||||||
<artifactId>cryptomator</artifactId>
|
<artifactId>cryptomator</artifactId>
|
||||||
<version>1.7.0</version>
|
<version>1.9.0</version>
|
||||||
<name>Cryptomator Desktop App</name>
|
<name>Cryptomator Desktop App</name>
|
||||||
|
|
||||||
<organization>
|
<organization>
|
||||||
@@ -17,59 +17,58 @@
|
|||||||
<email>sebastian.stenzel@gmail.com</email>
|
<email>sebastian.stenzel@gmail.com</email>
|
||||||
<timezone>+1</timezone>
|
<timezone>+1</timezone>
|
||||||
</developer>
|
</developer>
|
||||||
|
<developer>
|
||||||
|
<name>Armin Schrenk</name>
|
||||||
|
<email>armin.schrenk+dev@mailbox.org</email>
|
||||||
|
<timezone>+1</timezone>
|
||||||
|
</developer>
|
||||||
</developers>
|
</developers>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<project.jdk.version>19</project.jdk.version>
|
<project.jdk.version>20</project.jdk.version>
|
||||||
|
|
||||||
<!-- Group IDs of jars that need to stay on the class path for now -->
|
<!-- 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 -->
|
<!-- Once hypfvieh, swiesend, purejava and integrations-linux have module-info, remove them-->
|
||||||
<nonModularGroupIds>com.github.jnr,org.ow2.asm,org.apache.jackrabbit,org.apache.httpcomponents,de.swiesend,org.purejava,com.github.hypfvieh</nonModularGroupIds>
|
<nonModularGroupIds>org.ow2.asm,org.apache.jackrabbit,org.apache.httpcomponents,de.swiesend,org.purejava,com.github.hypfvieh</nonModularGroupIds>
|
||||||
|
|
||||||
<!-- cryptomator dependencies -->
|
<!-- cryptomator dependencies -->
|
||||||
<cryptomator.cryptolib.version>2.1.0-rc1</cryptomator.cryptolib.version>
|
<cryptomator.cryptofs.version>2.6.4</cryptomator.cryptofs.version>
|
||||||
<cryptomator.cryptofs.version>2.4.5</cryptomator.cryptofs.version>
|
<cryptomator.integrations.version>1.2.0</cryptomator.integrations.version>
|
||||||
<cryptomator.integrations.version>1.2.0-beta2</cryptomator.integrations.version>
|
<cryptomator.integrations.win.version>1.2.0</cryptomator.integrations.win.version>
|
||||||
<cryptomator.integrations.win.version>1.1.2</cryptomator.integrations.win.version>
|
<cryptomator.integrations.mac.version>1.2.0</cryptomator.integrations.mac.version>
|
||||||
<cryptomator.integrations.mac.version>1.1.2</cryptomator.integrations.mac.version>
|
<cryptomator.integrations.linux.version>1.2.1</cryptomator.integrations.linux.version>
|
||||||
<cryptomator.integrations.linux.version>1.1.0</cryptomator.integrations.linux.version>
|
<cryptomator.fuse.version>3.0.0</cryptomator.fuse.version>
|
||||||
<cryptomator.fuse.version>2.0.0-beta1</cryptomator.fuse.version>
|
<cryptomator.dokany.version>2.0.0</cryptomator.dokany.version>
|
||||||
<cryptomator.dokany.version>2.0.0-beta1</cryptomator.dokany.version>
|
<cryptomator.webdav.version>2.0.3</cryptomator.webdav.version>
|
||||||
<cryptomator.webdav.version>2.0.0-beta1</cryptomator.webdav.version>
|
|
||||||
|
|
||||||
<!-- 3rd party dependencies -->
|
<!-- 3rd party dependencies -->
|
||||||
<commons-lang3.version>3.12.0</commons-lang3.version>
|
<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>
|
<easybind.version>2.2</easybind.version>
|
||||||
<guava.version>31.1-jre</guava.version>
|
<guava.version>31.1-jre</guava.version>
|
||||||
<gson.version>2.9.1</gson.version>
|
<gson.version>2.10.1</gson.version>
|
||||||
<javafx.version>19</javafx.version>
|
<javafx.version>20.0.1</javafx.version>
|
||||||
<jwt.version>4.2.1</jwt.version>
|
<jwt.version>4.4.0</jwt.version>
|
||||||
<nimbus-jose.version>9.25.4</nimbus-jose.version>
|
<nimbus-jose.version>9.31</nimbus-jose.version>
|
||||||
<logback.version>1.4.4</logback.version>
|
<logback.version>1.4.7</logback.version>
|
||||||
<slf4j.version>2.0.3</slf4j.version>
|
<slf4j.version>2.0.7</slf4j.version>
|
||||||
<tinyoauth2.version>0.5.1</tinyoauth2.version>
|
<tinyoauth2.version>0.5.1</tinyoauth2.version>
|
||||||
<zxcvbn.version>1.7.0</zxcvbn.version>
|
<zxcvbn.version>1.7.0</zxcvbn.version>
|
||||||
|
|
||||||
<!-- test dependencies -->
|
<!-- test dependencies -->
|
||||||
<junit.jupiter.version>5.9.1</junit.jupiter.version>
|
<junit.jupiter.version>5.9.3</junit.jupiter.version>
|
||||||
<mockito.version>4.8.0</mockito.version>
|
<mockito.version>5.3.1</mockito.version>
|
||||||
<hamcrest.version>2.2</hamcrest.version>
|
<hamcrest.version>2.2</hamcrest.version>
|
||||||
|
|
||||||
<!-- build-time dependencies -->
|
<!-- build-time dependencies -->
|
||||||
<jetbrains.annotations.version>23.0.0</jetbrains.annotations.version>
|
<jetbrains.annotations.version>23.0.0</jetbrains.annotations.version>
|
||||||
<dependency-check.version>7.2.1</dependency-check.version>
|
<dependency-check.version>8.1.0</dependency-check.version>
|
||||||
<jacoco.version>0.8.8</jacoco.version>
|
<jacoco.version>0.8.9</jacoco.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<!-- Cryptomator Libs -->
|
<!-- Cryptomator Libs -->
|
||||||
<dependency>
|
|
||||||
<groupId>org.cryptomator</groupId>
|
|
||||||
<artifactId>cryptolib</artifactId>
|
|
||||||
<version>${cryptomator.cryptolib.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.cryptomator</groupId>
|
<groupId>org.cryptomator</groupId>
|
||||||
<artifactId>cryptofs</artifactId>
|
<artifactId>cryptofs</artifactId>
|
||||||
@@ -318,41 +317,6 @@
|
|||||||
</compilerArgs>
|
</compilerArgs>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</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>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
@@ -368,11 +332,15 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<argLine>--enable-preview</argLine>
|
||||||
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-dependency-plugin</artifactId>
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
<executions>
|
<executions>
|
||||||
|
<!-- sort jars into two buckets (classpath and modulepath). exclude openjfx, which gets jlinked separately -->
|
||||||
<execution>
|
<execution>
|
||||||
<id>copy-mods</id>
|
<id>copy-mods</id>
|
||||||
<phase>prepare-package</phase>
|
<phase>prepare-package</phase>
|
||||||
@@ -382,7 +350,7 @@
|
|||||||
<configuration>
|
<configuration>
|
||||||
<includeScope>runtime</includeScope>
|
<includeScope>runtime</includeScope>
|
||||||
<outputDirectory>${project.build.directory}/mods</outputDirectory>
|
<outputDirectory>${project.build.directory}/mods</outputDirectory>
|
||||||
<excludeGroupIds>${nonModularGroupIds}</excludeGroupIds>
|
<excludeGroupIds>org.openjfx,${nonModularGroupIds}</excludeGroupIds>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
<execution>
|
<execution>
|
||||||
|
|||||||
@@ -1,4 +1,16 @@
|
|||||||
import ch.qos.logback.classic.spi.Configurator;
|
import ch.qos.logback.classic.spi.Configurator;
|
||||||
|
import org.cryptomator.common.locationpresets.DropboxLinuxLocationPresetsProvider;
|
||||||
|
import org.cryptomator.common.locationpresets.DropboxMacLocationPresetsProvider;
|
||||||
|
import org.cryptomator.common.locationpresets.DropboxWindowsLocationPresetsProvider;
|
||||||
|
import org.cryptomator.common.locationpresets.GoogleDriveLocationPresetsProvider;
|
||||||
|
import org.cryptomator.common.locationpresets.ICloudMacLocationPresetsProvider;
|
||||||
|
import org.cryptomator.common.locationpresets.ICloudWindowsLocationPresetsProvider;
|
||||||
|
import org.cryptomator.common.locationpresets.LocationPresetsProvider;
|
||||||
|
import org.cryptomator.common.locationpresets.MegaLocationPresetsProvider;
|
||||||
|
import org.cryptomator.common.locationpresets.OneDriveLinuxLocationPresetsProvider;
|
||||||
|
import org.cryptomator.common.locationpresets.OneDriveMacLocationPresetsProvider;
|
||||||
|
import org.cryptomator.common.locationpresets.OneDriveWindowsLocationPresetsProvider;
|
||||||
|
import org.cryptomator.common.locationpresets.PCloudLocationPresetsProvider;
|
||||||
import org.cryptomator.integrations.tray.TrayMenuController;
|
import org.cryptomator.integrations.tray.TrayMenuController;
|
||||||
import org.cryptomator.logging.LogbackConfiguratorFactory;
|
import org.cryptomator.logging.LogbackConfiguratorFactory;
|
||||||
import org.cryptomator.ui.traymenu.AwtTrayMenuController;
|
import org.cryptomator.ui.traymenu.AwtTrayMenuController;
|
||||||
@@ -37,6 +49,15 @@ open module org.cryptomator.desktop {
|
|||||||
/* TODO: filename-based modules: */
|
/* TODO: filename-based modules: */
|
||||||
requires static javax.inject; /* ugly dagger/guava crap */
|
requires static javax.inject; /* ugly dagger/guava crap */
|
||||||
|
|
||||||
|
uses org.cryptomator.common.locationpresets.LocationPresetsProvider;
|
||||||
|
|
||||||
provides TrayMenuController with AwtTrayMenuController;
|
provides TrayMenuController with AwtTrayMenuController;
|
||||||
provides Configurator with LogbackConfiguratorFactory;
|
provides Configurator with LogbackConfiguratorFactory;
|
||||||
|
provides LocationPresetsProvider with DropboxMacLocationPresetsProvider, //
|
||||||
|
DropboxWindowsLocationPresetsProvider, DropboxLinuxLocationPresetsProvider, //
|
||||||
|
ICloudMacLocationPresetsProvider, ICloudWindowsLocationPresetsProvider, //
|
||||||
|
GoogleDriveLocationPresetsProvider, //
|
||||||
|
PCloudLocationPresetsProvider, MegaLocationPresetsProvider, //
|
||||||
|
OneDriveLinuxLocationPresetsProvider, OneDriveWindowsLocationPresetsProvider, //
|
||||||
|
OneDriveMacLocationPresetsProvider;
|
||||||
}
|
}
|
||||||
@@ -16,6 +16,7 @@ import org.cryptomator.common.settings.SettingsProvider;
|
|||||||
import org.cryptomator.common.vaults.VaultComponent;
|
import org.cryptomator.common.vaults.VaultComponent;
|
||||||
import org.cryptomator.common.vaults.VaultListModule;
|
import org.cryptomator.common.vaults.VaultListModule;
|
||||||
import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
|
import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
|
||||||
|
import org.cryptomator.integrations.revealpath.RevealPathService;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -26,6 +27,7 @@ import java.net.InetSocketAddress;
|
|||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.SynchronousQueue;
|
import java.util.concurrent.SynchronousQueue;
|
||||||
@@ -83,6 +85,13 @@ public abstract class CommonsModule {
|
|||||||
return new SemVerComparator();
|
return new SemVerComparator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
static Optional<RevealPathService> provideRevealPathService() {
|
||||||
|
return RevealPathService.get().findFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
static Settings provideSettings(SettingsProvider settingsProvider) {
|
static Settings provideSettings(SettingsProvider settingsProvider) {
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
package org.cryptomator.common;
|
package org.cryptomator.common;
|
||||||
|
|
||||||
|
import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingStrategy;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
public interface Constants {
|
public interface Constants {
|
||||||
|
|
||||||
String MASTERKEY_FILENAME = "masterkey.cryptomator";
|
String MASTERKEY_FILENAME = "masterkey.cryptomator";
|
||||||
@@ -7,6 +11,7 @@ public interface Constants {
|
|||||||
String VAULTCONFIG_FILENAME = "vault.cryptomator";
|
String VAULTCONFIG_FILENAME = "vault.cryptomator";
|
||||||
String CRYPTOMATOR_FILENAME_EXT = ".cryptomator";
|
String CRYPTOMATOR_FILENAME_EXT = ".cryptomator";
|
||||||
String CRYPTOMATOR_FILENAME_GLOB = "*.cryptomator";
|
String CRYPTOMATOR_FILENAME_GLOB = "*.cryptomator";
|
||||||
|
URI DEFAULT_KEY_ID = URI.create(MasterkeyFileLoadingStrategy.SCHEME + ":" + MASTERKEY_FILENAME);
|
||||||
byte[] PEPPER = new byte[0];
|
byte[] PEPPER = new byte[0];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ public class Environment {
|
|||||||
private static final String KEYCHAIN_PATHS_PROP_NAME = "cryptomator.integrationsWin.keychainPaths";
|
private static final String KEYCHAIN_PATHS_PROP_NAME = "cryptomator.integrationsWin.keychainPaths";
|
||||||
private static final String P12_PATH_PROP_NAME = "cryptomator.p12Path";
|
private static final String P12_PATH_PROP_NAME = "cryptomator.p12Path";
|
||||||
private static final String LOG_DIR_PROP_NAME = "cryptomator.logDir";
|
private static final String LOG_DIR_PROP_NAME = "cryptomator.logDir";
|
||||||
|
private static final String LOOPBACK_ALIAS_PROP_NAME = "cryptomator.loopbackAlias";
|
||||||
private static final String MOUNTPOINT_DIR_PROP_NAME = "cryptomator.mountPointsDir";
|
private static final String MOUNTPOINT_DIR_PROP_NAME = "cryptomator.mountPointsDir";
|
||||||
private static final String MIN_PW_LENGTH_PROP_NAME = "cryptomator.minPwLength";
|
private static final String MIN_PW_LENGTH_PROP_NAME = "cryptomator.minPwLength";
|
||||||
private static final String APP_VERSION_PROP_NAME = "cryptomator.appVersion";
|
private static final String APP_VERSION_PROP_NAME = "cryptomator.appVersion";
|
||||||
@@ -45,6 +46,7 @@ public class Environment {
|
|||||||
logCryptomatorSystemProperty(IPC_SOCKET_PATH_PROP_NAME);
|
logCryptomatorSystemProperty(IPC_SOCKET_PATH_PROP_NAME);
|
||||||
logCryptomatorSystemProperty(KEYCHAIN_PATHS_PROP_NAME);
|
logCryptomatorSystemProperty(KEYCHAIN_PATHS_PROP_NAME);
|
||||||
logCryptomatorSystemProperty(LOG_DIR_PROP_NAME);
|
logCryptomatorSystemProperty(LOG_DIR_PROP_NAME);
|
||||||
|
logCryptomatorSystemProperty(LOOPBACK_ALIAS_PROP_NAME);
|
||||||
logCryptomatorSystemProperty(PLUGIN_DIR_PROP_NAME);
|
logCryptomatorSystemProperty(PLUGIN_DIR_PROP_NAME);
|
||||||
logCryptomatorSystemProperty(MOUNTPOINT_DIR_PROP_NAME);
|
logCryptomatorSystemProperty(MOUNTPOINT_DIR_PROP_NAME);
|
||||||
logCryptomatorSystemProperty(MIN_PW_LENGTH_PROP_NAME);
|
logCryptomatorSystemProperty(MIN_PW_LENGTH_PROP_NAME);
|
||||||
@@ -90,6 +92,10 @@ public class Environment {
|
|||||||
return getPath(LOG_DIR_PROP_NAME).map(this::replaceHomeDir);
|
return getPath(LOG_DIR_PROP_NAME).map(this::replaceHomeDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<String> getLoopbackAlias() {
|
||||||
|
return Optional.ofNullable(System.getProperty(LOOPBACK_ALIAS_PROP_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
public Optional<Path> getPluginDir() {
|
public Optional<Path> getPluginDir() {
|
||||||
return getPath(PLUGIN_DIR_PROP_NAME).map(this::replaceHomeDir);
|
return getPath(PLUGIN_DIR_PROP_NAME).map(this::replaceHomeDir);
|
||||||
}
|
}
|
||||||
@@ -112,22 +118,13 @@ public class Environment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getMinPwLength() {
|
public int getMinPwLength() {
|
||||||
return getInt(MIN_PW_LENGTH_PROP_NAME, DEFAULT_MIN_PW_LENGTH);
|
return Integer.getInteger(MIN_PW_LENGTH_PROP_NAME, DEFAULT_MIN_PW_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean showTrayIcon() {
|
public boolean showTrayIcon() {
|
||||||
return Boolean.getBoolean(TRAY_ICON_PROP_NAME);
|
return Boolean.getBoolean(TRAY_ICON_PROP_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getInt(String propertyName, int defaultValue) {
|
|
||||||
String value = System.getProperty(propertyName);
|
|
||||||
try {
|
|
||||||
return Integer.parseInt(value);
|
|
||||||
} catch (NumberFormatException e) { // includes "null" values
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Optional<Path> getPath(String propertyName) {
|
private Optional<Path> getPath(String propertyName) {
|
||||||
String value = System.getProperty(propertyName);
|
String value = System.getProperty(propertyName);
|
||||||
return Optional.ofNullable(value).map(Paths::get);
|
return Optional.ofNullable(value).map(Paths::get);
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
package org.cryptomator.common;
|
|
||||||
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enum of common cloud providers and their default local storage location path.
|
|
||||||
*/
|
|
||||||
public enum LocationPreset {
|
|
||||||
|
|
||||||
DROPBOX("Dropbox", "~/Dropbox"),
|
|
||||||
ICLOUDDRIVE("iCloud Drive", "~/Library/Mobile Documents/com~apple~CloudDocs", "~/iCloudDrive"),
|
|
||||||
GDRIVE("Google Drive", "~/Google Drive/My Drive", "~/Google Drive"),
|
|
||||||
MEGA("MEGA", "~/MEGA"),
|
|
||||||
ONEDRIVE("OneDrive", "~/OneDrive"),
|
|
||||||
PCLOUD("pCloud", "~/pCloudDrive"),
|
|
||||||
|
|
||||||
LOCAL("local");
|
|
||||||
|
|
||||||
private final String name;
|
|
||||||
private final List<Path> candidates;
|
|
||||||
|
|
||||||
LocationPreset(String name, String... candidates) {
|
|
||||||
this.name = name;
|
|
||||||
this.candidates = Arrays.stream(candidates).map(UserHome::resolve).map(Path::of).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks for this LocationPreset if any of the associated paths exist.
|
|
||||||
*
|
|
||||||
* @return the first existing path or null, if none exists.
|
|
||||||
*/
|
|
||||||
public Path existingPath() {
|
|
||||||
return candidates.stream().filter(Files::isDirectory).findFirst().orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDisplayName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return getDisplayName();
|
|
||||||
}
|
|
||||||
|
|
||||||
//this contruct is needed, since static members are initialized after every enum member is initialized
|
|
||||||
//TODO: refactor this to normal class and use this also in different parts of the project
|
|
||||||
private static class UserHome {
|
|
||||||
|
|
||||||
private static final String USER_HOME = System.getProperty("user.home");
|
|
||||||
|
|
||||||
private static String resolve(String path) {
|
|
||||||
if (path.startsWith("~/")) {
|
|
||||||
return UserHome.USER_HOME + path.substring(1);
|
|
||||||
} else {
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package org.cryptomator.common;
|
||||||
|
|
||||||
|
import javafx.beans.binding.Bindings;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class ObservableUtil {
|
||||||
|
|
||||||
|
public static <T, U> ObservableValue<U> mapWithDefault(ObservableValue<T> observable, Function<? super T, ? extends U> mapper, U defaultValue) {
|
||||||
|
return Bindings.createObjectBinding(() -> {
|
||||||
|
if (observable.getValue() == null) {
|
||||||
|
return defaultValue;
|
||||||
|
} else {
|
||||||
|
return mapper.apply(observable.getValue());
|
||||||
|
}
|
||||||
|
}, observable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, U> ObservableValue<U> mapWithDefault(ObservableValue<T> observable, Function<? super T, ? extends U> mapper, Supplier<U> defaultValue) {
|
||||||
|
return Bindings.createObjectBinding(() -> {
|
||||||
|
if (observable.getValue() == null) {
|
||||||
|
return defaultValue.get();
|
||||||
|
} else {
|
||||||
|
return mapper.apply(observable.getValue());
|
||||||
|
}
|
||||||
|
}, observable);
|
||||||
|
}
|
||||||
|
}
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
package org.cryptomator.common.locationpresets;
|
||||||
|
|
||||||
|
import org.cryptomator.integrations.common.OperatingSystem;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.cryptomator.integrations.common.OperatingSystem.Value.LINUX;
|
||||||
|
|
||||||
|
@OperatingSystem(LINUX)
|
||||||
|
public final class DropboxLinuxLocationPresetsProvider implements LocationPresetsProvider {
|
||||||
|
|
||||||
|
private static final Path USER_HOME = LocationPresetsProvider.resolveLocation("~/.").toAbsolutePath();
|
||||||
|
private static final Predicate<String> PATTERN = Pattern.compile("Dropbox \\(.+\\)").asMatchPredicate();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<LocationPreset> getLocations() {
|
||||||
|
try (var dirStream = Files.list(USER_HOME)) {
|
||||||
|
var presets = dirStream.filter(p -> Files.isDirectory(p) && PATTERN.test(p.getFileName().toString())) //
|
||||||
|
.map(p -> new LocationPreset(p.getFileName().toString(), p)) //
|
||||||
|
.toList();
|
||||||
|
return presets.stream(); //workaround to ensure that the directory stream is always closed
|
||||||
|
} catch (IOException | UncheckedIOException e) { //UncheckedIOException thrown by the stream of Files.list()
|
||||||
|
return Stream.of();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
package org.cryptomator.common.locationpresets;
|
||||||
|
|
||||||
|
import org.cryptomator.integrations.common.CheckAvailability;
|
||||||
|
import org.cryptomator.integrations.common.OperatingSystem;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
|
||||||
|
|
||||||
|
@OperatingSystem(MAC)
|
||||||
|
@CheckAvailability
|
||||||
|
public final class DropboxMacLocationPresetsProvider implements LocationPresetsProvider {
|
||||||
|
|
||||||
|
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/Library/CloudStorage/Dropbox");
|
||||||
|
private static final Path FALLBACK_LOCATION = LocationPresetsProvider.resolveLocation("~/Dropbox");
|
||||||
|
|
||||||
|
|
||||||
|
@CheckAvailability
|
||||||
|
public static boolean isPresent() {
|
||||||
|
return Files.isDirectory(LOCATION) || Files.isDirectory(FALLBACK_LOCATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<LocationPreset> getLocations() {
|
||||||
|
if(Files.isDirectory(LOCATION)) {
|
||||||
|
return Stream.of(new LocationPreset("Dropbox", LOCATION));
|
||||||
|
} else if(Files.isDirectory(FALLBACK_LOCATION)) {
|
||||||
|
return Stream.of(new LocationPreset("Dropbox", FALLBACK_LOCATION));
|
||||||
|
} else {
|
||||||
|
return Stream.of();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
package org.cryptomator.common.locationpresets;
|
||||||
|
|
||||||
|
import org.cryptomator.integrations.common.CheckAvailability;
|
||||||
|
import org.cryptomator.integrations.common.OperatingSystem;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
|
||||||
|
|
||||||
|
@OperatingSystem(WINDOWS)
|
||||||
|
@CheckAvailability
|
||||||
|
public final class DropboxWindowsLocationPresetsProvider implements LocationPresetsProvider {
|
||||||
|
|
||||||
|
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/Dropbox");
|
||||||
|
|
||||||
|
|
||||||
|
@CheckAvailability
|
||||||
|
public static boolean isPresent() {
|
||||||
|
return Files.isDirectory(LOCATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<LocationPreset> getLocations() {
|
||||||
|
return Stream.of(new LocationPreset("Dropbox", LOCATION));
|
||||||
|
}
|
||||||
|
}
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
package org.cryptomator.common.locationpresets;
|
||||||
|
|
||||||
|
import org.cryptomator.integrations.common.CheckAvailability;
|
||||||
|
import org.cryptomator.integrations.common.OperatingSystem;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
|
||||||
|
import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
|
||||||
|
|
||||||
|
@OperatingSystem(WINDOWS)
|
||||||
|
@OperatingSystem(MAC)
|
||||||
|
@CheckAvailability
|
||||||
|
public final class GoogleDriveLocationPresetsProvider implements LocationPresetsProvider {
|
||||||
|
|
||||||
|
private static final Path LOCATION1 = LocationPresetsProvider.resolveLocation("~/GoogleDrive");
|
||||||
|
private static final Path LOCATION2 = LocationPresetsProvider.resolveLocation("~/GoogleDrive/My Drive");
|
||||||
|
|
||||||
|
|
||||||
|
@CheckAvailability
|
||||||
|
public static boolean isPresent() {
|
||||||
|
return Files.isDirectory(LOCATION1) || Files.isDirectory(LOCATION2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<LocationPreset> getLocations() {
|
||||||
|
if(Files.isDirectory(LOCATION1)) {
|
||||||
|
return Stream.of(new LocationPreset("Google Drive", LOCATION1));
|
||||||
|
} else if(Files.isDirectory(LOCATION2)) {
|
||||||
|
return Stream.of(new LocationPreset("Google Drive", LOCATION2));
|
||||||
|
} else {
|
||||||
|
return Stream.of();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
package org.cryptomator.common.locationpresets;
|
||||||
|
|
||||||
|
import org.cryptomator.integrations.common.CheckAvailability;
|
||||||
|
import org.cryptomator.integrations.common.OperatingSystem;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
|
||||||
|
|
||||||
|
@OperatingSystem(MAC)
|
||||||
|
@CheckAvailability
|
||||||
|
public final class ICloudMacLocationPresetsProvider implements LocationPresetsProvider {
|
||||||
|
|
||||||
|
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/Library/Mobile Documents/com~apple~CloudDocs");
|
||||||
|
|
||||||
|
@CheckAvailability
|
||||||
|
public static boolean isPresent() {
|
||||||
|
return Files.isDirectory(LOCATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<LocationPreset> getLocations() {
|
||||||
|
return Stream.of(new LocationPreset("iCloud Drive", LOCATION));
|
||||||
|
}
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
package org.cryptomator.common.locationpresets;
|
||||||
|
|
||||||
|
import org.cryptomator.integrations.common.CheckAvailability;
|
||||||
|
import org.cryptomator.integrations.common.OperatingSystem;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
|
||||||
|
|
||||||
|
@OperatingSystem(WINDOWS)
|
||||||
|
@CheckAvailability
|
||||||
|
public final class ICloudWindowsLocationPresetsProvider implements LocationPresetsProvider {
|
||||||
|
|
||||||
|
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/iCloudDrive");
|
||||||
|
|
||||||
|
@CheckAvailability
|
||||||
|
public static boolean isPresent() {
|
||||||
|
return Files.isDirectory(LOCATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<LocationPreset> getLocations() {
|
||||||
|
return Stream.of(new LocationPreset("iCloud Drive", LOCATION));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package org.cryptomator.common.locationpresets;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public record LocationPreset(String name, Path path) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package org.cryptomator.common.locationpresets;
|
||||||
|
|
||||||
|
import org.cryptomator.integrations.common.CheckAvailability;
|
||||||
|
import org.cryptomator.integrations.common.IntegrationsLoader;
|
||||||
|
import org.cryptomator.integrations.common.OperatingSystem;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.ServiceLoader;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public interface LocationPresetsProvider {
|
||||||
|
|
||||||
|
Logger LOG = LoggerFactory.getLogger(LocationPresetsProvider.class);
|
||||||
|
String USER_HOME = System.getProperty("user.home");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Streams account-separated location presets found by this provider
|
||||||
|
* @return Stream of LocationPresets
|
||||||
|
*/
|
||||||
|
Stream<LocationPreset> getLocations();
|
||||||
|
|
||||||
|
static Path resolveLocation(String p) {
|
||||||
|
if (p.startsWith("~/")) {
|
||||||
|
return Path.of(USER_HOME, p.substring(2));
|
||||||
|
} else {
|
||||||
|
return Path.of(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//copied from org.cryptomator.integrations.common.IntegrationsLoader
|
||||||
|
//TODO: delete, once migrated to integrations-api
|
||||||
|
static <T> Stream<T> loadAll(Class<T> clazz) {
|
||||||
|
return ServiceLoader.load(clazz)
|
||||||
|
.stream()
|
||||||
|
.filter(LocationPresetsProvider::isSupportedOperatingSystem)
|
||||||
|
.filter(LocationPresetsProvider::passesStaticAvailabilityCheck)
|
||||||
|
.map(ServiceLoader.Provider::get)
|
||||||
|
.peek(impl -> logServiceIsAvailable(clazz, impl.getClass()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static boolean isSupportedOperatingSystem(ServiceLoader.Provider<?> provider) {
|
||||||
|
var annotations = provider.type().getAnnotationsByType(OperatingSystem.class);
|
||||||
|
return annotations.length == 0 || Arrays.stream(annotations).anyMatch(OperatingSystem.Value::isCurrent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean passesStaticAvailabilityCheck(ServiceLoader.Provider<?> provider) {
|
||||||
|
return passesStaticAvailabilityCheck(provider.type());
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean passesStaticAvailabilityCheck(Class<?> type) {
|
||||||
|
return passesAvailabilityCheck(type, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void logServiceIsAvailable(Class<?> apiType, Class<?> implType) {
|
||||||
|
if (LOG.isDebugEnabled()) {
|
||||||
|
LOG.debug("{}: Implementation is available: {}", apiType.getSimpleName(), implType.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> boolean passesAvailabilityCheck(Class<? extends T> type, @Nullable T instance) {
|
||||||
|
if (!type.isAnnotationPresent(CheckAvailability.class)) {
|
||||||
|
return true; // if type is not annotated, skip tests
|
||||||
|
}
|
||||||
|
if (!type.getModule().isExported(type.getPackageName(), IntegrationsLoader.class.getModule())) {
|
||||||
|
LOG.error("Can't run @CheckAvailability tests for class {}. Make sure to export {} to {}!", type.getName(), type.getPackageName(), IntegrationsLoader.class.getPackageName());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Arrays.stream(type.getMethods())
|
||||||
|
.filter(m -> isAvailabilityCheck(m, instance == null))
|
||||||
|
.allMatch(m -> passesAvailabilityCheck(m, instance));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean passesAvailabilityCheck(Method m, @Nullable Object instance) {
|
||||||
|
assert Boolean.TYPE.equals(m.getReturnType());
|
||||||
|
try {
|
||||||
|
return (boolean) m.invoke(instance);
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
LOG.warn("Failed to invoke @CheckAvailability test {}#{}", m.getDeclaringClass(), m.getName(), e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isAvailabilityCheck(Method m, boolean isStatic) {
|
||||||
|
return m.isAnnotationPresent(CheckAvailability.class)
|
||||||
|
&& Boolean.TYPE.equals(m.getReturnType())
|
||||||
|
&& m.getParameterCount() == 0
|
||||||
|
&& Modifier.isStatic(m.getModifiers()) == isStatic;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package org.cryptomator.common.locationpresets;
|
||||||
|
|
||||||
|
import org.cryptomator.integrations.common.CheckAvailability;
|
||||||
|
import org.cryptomator.integrations.common.OperatingSystem;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
|
||||||
|
import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
|
||||||
|
|
||||||
|
@OperatingSystem(WINDOWS)
|
||||||
|
@OperatingSystem(MAC)
|
||||||
|
@CheckAvailability
|
||||||
|
public final class MegaLocationPresetsProvider implements LocationPresetsProvider {
|
||||||
|
|
||||||
|
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/MEGA");
|
||||||
|
|
||||||
|
@CheckAvailability
|
||||||
|
public static boolean isPresent() {
|
||||||
|
return Files.isDirectory(LOCATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<LocationPreset> getLocations() {
|
||||||
|
return Stream.of(new LocationPreset("MEGA", LOCATION));
|
||||||
|
}
|
||||||
|
}
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
package org.cryptomator.common.locationpresets;
|
||||||
|
|
||||||
|
import org.cryptomator.integrations.common.CheckAvailability;
|
||||||
|
import org.cryptomator.integrations.common.OperatingSystem;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.cryptomator.integrations.common.OperatingSystem.Value.LINUX;
|
||||||
|
|
||||||
|
@OperatingSystem(LINUX)
|
||||||
|
@CheckAvailability
|
||||||
|
public final class OneDriveLinuxLocationPresetsProvider implements LocationPresetsProvider {
|
||||||
|
|
||||||
|
|
||||||
|
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/OneDrive");
|
||||||
|
|
||||||
|
@CheckAvailability
|
||||||
|
public static boolean isPresent() {
|
||||||
|
return Files.isDirectory(LOCATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<LocationPreset> getLocations() {
|
||||||
|
return Stream.of(new LocationPreset("OneDrive", LOCATION));
|
||||||
|
}
|
||||||
|
}
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
package org.cryptomator.common.locationpresets;
|
||||||
|
|
||||||
|
import org.cryptomator.integrations.common.OperatingSystem;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
|
import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
|
||||||
|
|
||||||
|
@OperatingSystem(MAC)
|
||||||
|
public final class OneDriveMacLocationPresetsProvider implements LocationPresetsProvider {
|
||||||
|
|
||||||
|
private static final Path FALLBACK_LOCATION = LocationPresetsProvider.resolveLocation("~/OneDrive");
|
||||||
|
private static final Path PARENT_LOCATION = LocationPresetsProvider.resolveLocation("~/Library/CloudStorage");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<LocationPreset> getLocations() {
|
||||||
|
var newLocations = getNewLocations().toList();
|
||||||
|
if (newLocations.size() >= 1) {
|
||||||
|
return newLocations.stream();
|
||||||
|
} else {
|
||||||
|
return getOldLocation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Stream<LocationPreset> getNewLocations() {
|
||||||
|
try (var dirStream = Files.newDirectoryStream(PARENT_LOCATION, "OneDrive*")) {
|
||||||
|
return StreamSupport.stream(dirStream.spliterator(), false) //
|
||||||
|
.filter(Files::isDirectory) //
|
||||||
|
.map(p -> new LocationPreset(String.join(" - ", p.getFileName().toString().split("-")), p));
|
||||||
|
} catch (IOException e) {
|
||||||
|
return Stream.of();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Stream<LocationPreset> getOldLocation() {
|
||||||
|
return Stream.of(new LocationPreset("OneDrive", FALLBACK_LOCATION)).filter(preset -> Files.isDirectory(preset.path()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+108
@@ -0,0 +1,108 @@
|
|||||||
|
package org.cryptomator.common.locationpresets;
|
||||||
|
|
||||||
|
import org.cryptomator.integrations.common.OperatingSystem;
|
||||||
|
import org.jetbrains.annotations.Blocking;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
|
||||||
|
|
||||||
|
@OperatingSystem(WINDOWS)
|
||||||
|
public final class OneDriveWindowsLocationPresetsProvider implements LocationPresetsProvider {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(OneDriveWindowsLocationPresetsProvider.class);
|
||||||
|
private static final String REGSTR_TOKEN = "REG_SZ";
|
||||||
|
private static final String REG_ONEDRIVE_ACCOUNTS = "HKEY_CURRENT_USER\\Software\\Microsoft\\OneDrive\\Accounts\\";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<LocationPreset> getLocations() {
|
||||||
|
try {
|
||||||
|
var accountRegKeys = queryRegistry(REG_ONEDRIVE_ACCOUNTS, List.of(), l -> l.startsWith(REG_ONEDRIVE_ACCOUNTS)).toList();
|
||||||
|
var cloudLocations = new ArrayList<LocationPreset>();
|
||||||
|
for (var accountRegKey : accountRegKeys) {
|
||||||
|
var path = queryRegistry(accountRegKey, List.of("/v", "UserFolder"), l -> l.contains("UserFolder")).map(result -> result.substring(result.indexOf(REGSTR_TOKEN) + REGSTR_TOKEN.length()).trim()) //
|
||||||
|
.map(Path::of) //
|
||||||
|
.findFirst().orElseThrow();
|
||||||
|
var name = "OneDrive"; //we assume personal oneDrive account by default
|
||||||
|
if (!accountRegKey.endsWith("Personal")) {
|
||||||
|
name = queryRegistry(accountRegKey, List.of("/v", "DisplayName"), l -> l.contains("DisplayName")).map(result -> result.substring(result.indexOf(REGSTR_TOKEN) + REGSTR_TOKEN.length()).trim()) //
|
||||||
|
.map("OneDrive - "::concat) //
|
||||||
|
.findFirst().orElseThrow();
|
||||||
|
}
|
||||||
|
cloudLocations.add(new LocationPreset(name, path));
|
||||||
|
}
|
||||||
|
return cloudLocations.stream();
|
||||||
|
} catch (IOException | CommandFailedException | TimeoutException e) {
|
||||||
|
LOG.error("Unable to determine OneDrive location", e);
|
||||||
|
return Stream.of();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
LOG.error("Determination of OneDrive location interrupted", e);
|
||||||
|
return Stream.of();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Stream<String> queryRegistry(String keyname, List<String> moreArgs, Predicate<String> outputFilter) throws InterruptedException, CommandFailedException, TimeoutException, IOException {
|
||||||
|
var args = new ArrayList<String>();
|
||||||
|
args.add("reg");
|
||||||
|
args.add("query");
|
||||||
|
args.add(keyname);
|
||||||
|
args.addAll(moreArgs);
|
||||||
|
ProcessBuilder command = new ProcessBuilder(args);
|
||||||
|
Process p = command.start();
|
||||||
|
waitForSuccess(p, 3, "`reg query`");
|
||||||
|
return p.inputReader(StandardCharsets.UTF_8).lines().filter(outputFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits {@code timeoutSeconds} seconds for {@code process} to finish with exit code {@code 0}.
|
||||||
|
*
|
||||||
|
* @param process The process to wait for
|
||||||
|
* @param timeoutSeconds How long to wait (in seconds)
|
||||||
|
* @param cmdDescription A short description of the process used to generate log and exception messages
|
||||||
|
* @throws TimeoutException Thrown when the process doesn't finish in time
|
||||||
|
* @throws InterruptedException Thrown when the thread is interrupted while waiting for the process to finish
|
||||||
|
* @throws CommandFailedException Thrown when the process exit code is non-zero
|
||||||
|
*/
|
||||||
|
@Blocking
|
||||||
|
private static void waitForSuccess(Process process, int timeoutSeconds, String cmdDescription) throws TimeoutException, InterruptedException, CommandFailedException {
|
||||||
|
boolean exited = process.waitFor(timeoutSeconds, TimeUnit.SECONDS);
|
||||||
|
if (!exited) {
|
||||||
|
throw new TimeoutException(cmdDescription + " timed out after " + timeoutSeconds + "s");
|
||||||
|
}
|
||||||
|
if (process.exitValue() != 0) {
|
||||||
|
@SuppressWarnings("resource") var stdout = process.inputReader(StandardCharsets.UTF_8).lines().collect(Collectors.joining("\n"));
|
||||||
|
@SuppressWarnings("resource") var stderr = process.errorReader(StandardCharsets.UTF_8).lines().collect(Collectors.joining("\n"));
|
||||||
|
throw new CommandFailedException(cmdDescription, process.exitValue(), stdout, stderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class CommandFailedException extends Exception {
|
||||||
|
|
||||||
|
int exitCode;
|
||||||
|
String stdout;
|
||||||
|
String stderr;
|
||||||
|
|
||||||
|
private CommandFailedException(String cmdDescription, int exitCode, String stdout, String stderr) {
|
||||||
|
super(cmdDescription + " returned with non-zero exit code " + exitCode);
|
||||||
|
this.exitCode = exitCode;
|
||||||
|
this.stdout = stdout;
|
||||||
|
this.stderr = stderr;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
package org.cryptomator.common.locationpresets;
|
||||||
|
|
||||||
|
import org.cryptomator.integrations.common.CheckAvailability;
|
||||||
|
import org.cryptomator.integrations.common.OperatingSystem;
|
||||||
|
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
|
||||||
|
import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
|
||||||
|
|
||||||
|
@OperatingSystem(WINDOWS)
|
||||||
|
@OperatingSystem(MAC)
|
||||||
|
@CheckAvailability
|
||||||
|
public final class PCloudLocationPresetsProvider implements LocationPresetsProvider {
|
||||||
|
|
||||||
|
|
||||||
|
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/pCloudDrive");
|
||||||
|
|
||||||
|
@CheckAvailability
|
||||||
|
public static boolean isPresent() {
|
||||||
|
return Files.isDirectory(LOCATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<LocationPreset> getLocations() {
|
||||||
|
return Stream.of(new LocationPreset("pCloud", LOCATION));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package org.cryptomator.common.mount;
|
||||||
|
|
||||||
|
import org.cryptomator.integrations.mount.MountService;
|
||||||
|
|
||||||
|
public record ActualMountService(MountService service, boolean isDesired) {
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package org.cryptomator.common.mount;
|
||||||
|
|
||||||
|
public class IllegalMountPointException extends IllegalArgumentException {
|
||||||
|
|
||||||
|
public IllegalMountPointException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,16 +2,23 @@ package org.cryptomator.common.mount;
|
|||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
|
import org.cryptomator.common.ObservableUtil;
|
||||||
import org.cryptomator.common.settings.Settings;
|
import org.cryptomator.common.settings.Settings;
|
||||||
|
import org.cryptomator.integrations.mount.Mount;
|
||||||
import org.cryptomator.integrations.mount.MountService;
|
import org.cryptomator.integrations.mount.MountService;
|
||||||
|
|
||||||
|
import javax.inject.Named;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
public class MountModule {
|
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
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
static List<MountService> provideSupportedMountServices() {
|
static List<MountService> provideSupportedMountServices() {
|
||||||
@@ -20,11 +27,46 @@ public class MountModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
static ObservableValue<MountService> provideMountService(Settings settings, List<MountService> serviceImpls) {
|
@Named("FUPFMS")
|
||||||
return settings.mountService().map(desiredServiceImpl -> {
|
static AtomicReference<MountService> provideFirstUsedProblematicFuseMountService() {
|
||||||
var fallbackProvider = serviceImpls.stream().findFirst().orElse(null);
|
return new AtomicReference<>(null);
|
||||||
return serviceImpls.stream().filter(serviceImpl -> serviceImpl.getClass().getName().equals(desiredServiceImpl)).findAny().orElse(fallbackProvider);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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 {
|
private P384KeyPair createAndStoreNewKeyPair(char[] passphrase, Path p12File) throws IOException {
|
||||||
var keyPair = P384KeyPair.generate();
|
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);
|
LOG.debug("Store new device key to {}", p12File);
|
||||||
keyPair.store(p12File, passphrase);
|
keyPair.store(p12File, passphrase);
|
||||||
return keyPair;
|
return keyPair;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import com.google.gson.TypeAdapter;
|
|||||||
import com.google.gson.stream.JsonReader;
|
import com.google.gson.stream.JsonReader;
|
||||||
import com.google.gson.stream.JsonToken;
|
import com.google.gson.stream.JsonToken;
|
||||||
import com.google.gson.stream.JsonWriter;
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
import org.apache.commons.lang3.SystemUtils;
|
||||||
import org.cryptomator.common.Environment;
|
import org.cryptomator.common.Environment;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -36,29 +37,30 @@ public class SettingsJsonAdapter extends TypeAdapter<Settings> {
|
|||||||
@Override
|
@Override
|
||||||
public void write(JsonWriter out, Settings value) throws IOException {
|
public void write(JsonWriter out, Settings value) throws IOException {
|
||||||
out.beginObject();
|
out.beginObject();
|
||||||
|
out.name("writtenByVersion").value(env.getAppVersion() + env.getBuildNumber().map("-"::concat).orElse(""));
|
||||||
out.name("directories");
|
out.name("directories");
|
||||||
writeVaultSettingsArray(out, value.getDirectories());
|
writeVaultSettingsArray(out, value.getDirectories());
|
||||||
out.name("askedForUpdateCheck").value(value.askedForUpdateCheck().get());
|
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("autoCloseVaults").value(value.autoCloseVaults().get());
|
||||||
out.name("port").value(value.port().get());
|
out.name("checkForUpdatesEnabled").value(value.checkForUpdates().get());
|
||||||
out.name("numTrayNotifications").value(value.numTrayNotifications().get());
|
|
||||||
out.name("debugMode").value(value.debugMode().get());
|
out.name("debugMode").value(value.debugMode().get());
|
||||||
out.name("theme").value(value.theme().get().name());
|
out.name("displayConfiguration").value((value.displayConfigurationProperty().get()));
|
||||||
out.name("uiOrientation").value(value.userInterfaceOrientation().get().name());
|
|
||||||
out.name("keychainProvider").value(value.keychainProvider().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("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("showMinimizeButton").value(value.showMinimizeButton().get());
|
||||||
out.name("showTrayIcon").value(value.showTrayIcon().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("windowXPosition").value((value.windowXPositionProperty().get()));
|
||||||
out.name("windowYPosition").value((value.windowYPositionProperty().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();
|
out.endObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,50 +75,84 @@ public class SettingsJsonAdapter extends TypeAdapter<Settings> {
|
|||||||
@Override
|
@Override
|
||||||
public Settings read(JsonReader in) throws IOException {
|
public Settings read(JsonReader in) throws IOException {
|
||||||
Settings settings = new Settings(env);
|
Settings settings = new Settings(env);
|
||||||
|
//1.6.x legacy
|
||||||
|
String volumeImpl = null;
|
||||||
|
//legacy end
|
||||||
in.beginObject();
|
in.beginObject();
|
||||||
while (in.hasNext()) {
|
while (in.hasNext()) {
|
||||||
String name = in.nextName();
|
String name = in.nextName();
|
||||||
switch (name) {
|
switch (name) {
|
||||||
|
case "writtenByVersion" -> in.skipValue(); //noop
|
||||||
case "directories" -> settings.getDirectories().addAll(readVaultSettingsArray(in));
|
case "directories" -> settings.getDirectories().addAll(readVaultSettingsArray(in));
|
||||||
case "askedForUpdateCheck" -> settings.askedForUpdateCheck().set(in.nextBoolean());
|
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 "autoCloseVaults" -> settings.autoCloseVaults().set(in.nextBoolean());
|
||||||
case "port" -> settings.port().set(in.nextInt());
|
case "checkForUpdatesEnabled" -> settings.checkForUpdates().set(in.nextBoolean());
|
||||||
case "numTrayNotifications" -> settings.numTrayNotifications().set(in.nextInt());
|
|
||||||
case "debugMode" -> settings.debugMode().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 "displayConfiguration" -> settings.displayConfigurationProperty().set(in.nextString());
|
||||||
|
case "keychainProvider" -> settings.keychainProvider().set(in.nextString());
|
||||||
case "language" -> settings.languageProperty().set(in.nextString());
|
case "language" -> settings.languageProperty().set(in.nextString());
|
||||||
|
case "licenseKey" -> settings.licenseKey().set(in.nextString());
|
||||||
case "mountService" -> {
|
case "mountService" -> {
|
||||||
var token = in.peek();
|
var token = in.peek();
|
||||||
if (JsonToken.STRING == token) {
|
if (JsonToken.STRING == token) {
|
||||||
settings.mountService().set(in.nextString());
|
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 -> {
|
default -> {
|
||||||
LOG.warn("Unsupported vault setting found in JSON: {}", name);
|
LOG.warn("Unsupported vault setting found in JSON: {}", name);
|
||||||
in.skipValue();
|
in.skipValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
in.endObject();
|
in.endObject();
|
||||||
|
|
||||||
|
//1.6.x legacy
|
||||||
|
if (volumeImpl != null) {
|
||||||
|
settings.mountService().set(convertLegacyVolumeImplToMountService(volumeImpl));
|
||||||
|
}
|
||||||
|
//legacy end
|
||||||
|
|
||||||
return settings;
|
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) {
|
private UiTheme parseUiTheme(String uiThemeName) {
|
||||||
try {
|
try {
|
||||||
return UiTheme.valueOf(uiThemeName.toUpperCase());
|
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 unlockAfterStartup = new SimpleBooleanProperty(DEFAULT_UNLOCK_AFTER_STARTUP);
|
||||||
private final BooleanProperty revealAfterMount = new SimpleBooleanProperty(DEFAULT_REVEAL_AFTER_MOUNT);
|
private final BooleanProperty revealAfterMount = new SimpleBooleanProperty(DEFAULT_REVEAL_AFTER_MOUNT);
|
||||||
private final BooleanProperty usesReadOnlyMode = new SimpleBooleanProperty(DEFAULT_USES_READONLY_MODE);
|
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 IntegerProperty maxCleartextFilenameLength = new SimpleIntegerProperty(DEFAULT_MAX_CLEARTEXT_FILENAME_LENGTH);
|
||||||
private final ObjectProperty<WhenUnlocked> actionAfterUnlock = new SimpleObjectProperty<>(DEFAULT_ACTION_AFTER_UNLOCK);
|
private final ObjectProperty<WhenUnlocked> actionAfterUnlock = new SimpleObjectProperty<>(DEFAULT_ACTION_AFTER_UNLOCK);
|
||||||
private final BooleanProperty autoLockWhenIdle = new SimpleBooleanProperty(DEFAULT_AUTOLOCK_WHEN_IDLE);
|
private final BooleanProperty autoLockWhenIdle = new SimpleBooleanProperty(DEFAULT_AUTOLOCK_WHEN_IDLE);
|
||||||
|
|||||||
@@ -38,8 +38,6 @@ class VaultSettingsJsonAdapter {
|
|||||||
out.endObject();
|
out.endObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: usesCustomMountPath, customMountPath and winDriveLetter removed
|
|
||||||
// -> migration required
|
|
||||||
public VaultSettings read(JsonReader in) throws IOException {
|
public VaultSettings read(JsonReader in) throws IOException {
|
||||||
String id = null;
|
String id = null;
|
||||||
String path = null;
|
String path = null;
|
||||||
@@ -55,6 +53,12 @@ class VaultSettingsJsonAdapter {
|
|||||||
boolean autoLockWhenIdle = VaultSettings.DEFAULT_AUTOLOCK_WHEN_IDLE;
|
boolean autoLockWhenIdle = VaultSettings.DEFAULT_AUTOLOCK_WHEN_IDLE;
|
||||||
int autoLockIdleSeconds = VaultSettings.DEFAULT_AUTOLOCK_IDLE_SECONDS;
|
int autoLockIdleSeconds = VaultSettings.DEFAULT_AUTOLOCK_IDLE_SECONDS;
|
||||||
|
|
||||||
|
//legacy from 1.6.x
|
||||||
|
boolean useCustomMountPath = false;
|
||||||
|
String customMountPath = "";
|
||||||
|
String winDriveLetter = "";
|
||||||
|
//legacy end
|
||||||
|
|
||||||
in.beginObject();
|
in.beginObject();
|
||||||
while (in.hasNext()) {
|
while (in.hasNext()) {
|
||||||
String name = in.nextName();
|
String name = in.nextName();
|
||||||
@@ -78,6 +82,11 @@ class VaultSettingsJsonAdapter {
|
|||||||
case "actionAfterUnlock" -> actionAfterUnlock = parseActionAfterUnlock(in.nextString());
|
case "actionAfterUnlock" -> actionAfterUnlock = parseActionAfterUnlock(in.nextString());
|
||||||
case "autoLockWhenIdle" -> autoLockWhenIdle = in.nextBoolean();
|
case "autoLockWhenIdle" -> autoLockWhenIdle = in.nextBoolean();
|
||||||
case "autoLockIdleSeconds" -> autoLockIdleSeconds = in.nextInt();
|
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 -> {
|
default -> {
|
||||||
LOG.warn("Unsupported vault setting found in JSON: {}", name);
|
LOG.warn("Unsupported vault setting found in JSON: {}", name);
|
||||||
in.skipValue();
|
in.skipValue();
|
||||||
@@ -102,6 +111,13 @@ class VaultSettingsJsonAdapter {
|
|||||||
vaultSettings.autoLockWhenIdle().set(autoLockWhenIdle);
|
vaultSettings.autoLockWhenIdle().set(autoLockWhenIdle);
|
||||||
vaultSettings.autoLockIdleSeconds().set(autoLockIdleSeconds);
|
vaultSettings.autoLockIdleSeconds().set(autoLockIdleSeconds);
|
||||||
vaultSettings.mountPoint().set(mountPoint);
|
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;
|
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.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
@@ -40,6 +41,7 @@ public class AutoLocker {
|
|||||||
private void autolock(Vault vault) {
|
private void autolock(Vault vault) {
|
||||||
try {
|
try {
|
||||||
vault.lock(false);
|
vault.lock(false);
|
||||||
|
Platform.runLater(() -> vault.stateProperty().set(VaultState.Value.LOCKED));
|
||||||
LOG.info("Autolocked {} after idle timeout", vault.getDisplayName());
|
LOG.info("Autolocked {} after idle timeout", vault.getDisplayName());
|
||||||
} catch (UnmountFailedException | IOException e) {
|
} catch (UnmountFailedException | IOException e) {
|
||||||
LOG.error("Autolocking failed.", e);
|
LOG.error("Autolocking failed.", e);
|
||||||
|
|||||||
@@ -8,12 +8,10 @@
|
|||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.cryptomator.common.vaults;
|
package org.cryptomator.common.vaults;
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
|
||||||
import org.apache.commons.lang3.SystemUtils;
|
import org.apache.commons.lang3.SystemUtils;
|
||||||
import org.cryptomator.common.Constants;
|
import org.cryptomator.common.Constants;
|
||||||
import org.cryptomator.common.Environment;
|
import org.cryptomator.common.mount.Mounter;
|
||||||
import org.cryptomator.common.mount.WindowsDriveLetters;
|
import org.cryptomator.common.mount.WindowsDriveLetters;
|
||||||
import org.cryptomator.common.settings.Settings;
|
|
||||||
import org.cryptomator.common.settings.VaultSettings;
|
import org.cryptomator.common.settings.VaultSettings;
|
||||||
import org.cryptomator.cryptofs.CryptoFileSystem;
|
import org.cryptomator.cryptofs.CryptoFileSystem;
|
||||||
import org.cryptomator.cryptofs.CryptoFileSystemProperties;
|
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.CryptoException;
|
||||||
import org.cryptomator.cryptolib.api.MasterkeyLoader;
|
import org.cryptomator.cryptolib.api.MasterkeyLoader;
|
||||||
import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
|
import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
|
||||||
import org.cryptomator.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.MountFailedException;
|
||||||
import org.cryptomator.integrations.mount.MountService;
|
|
||||||
import org.cryptomator.integrations.mount.Mountpoint;
|
import org.cryptomator.integrations.mount.Mountpoint;
|
||||||
import org.cryptomator.integrations.mount.UnmountFailedException;
|
import org.cryptomator.integrations.mount.UnmountFailedException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -44,9 +38,7 @@ import javafx.beans.property.BooleanProperty;
|
|||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
import javafx.beans.property.ReadOnlyStringProperty;
|
import javafx.beans.property.ReadOnlyStringProperty;
|
||||||
import javafx.beans.property.SimpleBooleanProperty;
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
import javafx.beans.value.ObservableValue;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
@@ -54,11 +46,6 @@ import java.util.Objects;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
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
|
@PerVault
|
||||||
public class Vault {
|
public class Vault {
|
||||||
|
|
||||||
@@ -66,14 +53,10 @@ public class Vault {
|
|||||||
private static final Path HOME_DIR = Paths.get(SystemUtils.USER_HOME);
|
private static final Path HOME_DIR = Paths.get(SystemUtils.USER_HOME);
|
||||||
private static final int UNLIMITED_FILENAME_LENGTH = Integer.MAX_VALUE;
|
private static final int UNLIMITED_FILENAME_LENGTH = Integer.MAX_VALUE;
|
||||||
|
|
||||||
private final Environment env;
|
|
||||||
private final Settings settings;
|
|
||||||
private final VaultSettings vaultSettings;
|
private final VaultSettings vaultSettings;
|
||||||
private final AtomicReference<CryptoFileSystem> cryptoFileSystem;
|
private final AtomicReference<CryptoFileSystem> cryptoFileSystem;
|
||||||
private final VaultState state;
|
private final VaultState state;
|
||||||
private final ObjectProperty<Exception> lastKnownException;
|
private final ObjectProperty<Exception> lastKnownException;
|
||||||
private final ObservableValue<MountService> mountService;
|
|
||||||
private final ObservableValue<String> defaultMountFlags;
|
|
||||||
private final VaultConfigCache configCache;
|
private final VaultConfigCache configCache;
|
||||||
private final VaultStats stats;
|
private final VaultStats stats;
|
||||||
private final StringBinding displayablePath;
|
private final StringBinding displayablePath;
|
||||||
@@ -84,22 +67,18 @@ public class Vault {
|
|||||||
private final BooleanBinding needsMigration;
|
private final BooleanBinding needsMigration;
|
||||||
private final BooleanBinding unknownError;
|
private final BooleanBinding unknownError;
|
||||||
private final ObjectBinding<Mountpoint> mountPoint;
|
private final ObjectBinding<Mountpoint> mountPoint;
|
||||||
private final WindowsDriveLetters windowsDriveLetters;
|
private final Mounter mounter;
|
||||||
private final BooleanProperty showingStats;
|
private final BooleanProperty showingStats;
|
||||||
|
|
||||||
private AtomicReference<MountHandle> mountHandle = new AtomicReference<>(null);
|
private AtomicReference<Mounter.MountHandle> mountHandle = new AtomicReference<>(null);
|
||||||
|
|
||||||
@Inject
|
@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) {
|
Vault(VaultSettings vaultSettings, VaultConfigCache configCache, AtomicReference<CryptoFileSystem> cryptoFileSystem, VaultState state, @Named("lastKnownException") ObjectProperty<Exception> lastKnownException, VaultStats stats, WindowsDriveLetters windowsDriveLetters, Mounter mounter) {
|
||||||
this.env = env;
|
|
||||||
this.settings = settings;
|
|
||||||
this.vaultSettings = vaultSettings;
|
this.vaultSettings = vaultSettings;
|
||||||
this.configCache = configCache;
|
this.configCache = configCache;
|
||||||
this.cryptoFileSystem = cryptoFileSystem;
|
this.cryptoFileSystem = cryptoFileSystem;
|
||||||
this.state = state;
|
this.state = state;
|
||||||
this.lastKnownException = lastKnownException;
|
this.lastKnownException = lastKnownException;
|
||||||
this.mountService = mountService;
|
|
||||||
this.defaultMountFlags = mountService.map(MountService::getDefaultMountFlags);
|
|
||||||
this.stats = stats;
|
this.stats = stats;
|
||||||
this.displayablePath = Bindings.createStringBinding(this::getDisplayablePath, vaultSettings.path());
|
this.displayablePath = Bindings.createStringBinding(this::getDisplayablePath, vaultSettings.path());
|
||||||
this.locked = Bindings.createBooleanBinding(this::isLocked, state);
|
this.locked = Bindings.createBooleanBinding(this::isLocked, state);
|
||||||
@@ -109,7 +88,7 @@ public class Vault {
|
|||||||
this.needsMigration = Bindings.createBooleanBinding(this::isNeedsMigration, state);
|
this.needsMigration = Bindings.createBooleanBinding(this::isNeedsMigration, state);
|
||||||
this.unknownError = Bindings.createBooleanBinding(this::isUnknownError, state);
|
this.unknownError = Bindings.createBooleanBinding(this::isUnknownError, state);
|
||||||
this.mountPoint = Bindings.createObjectBinding(this::getMountPoint, state);
|
this.mountPoint = Bindings.createObjectBinding(this::getMountPoint, state);
|
||||||
this.windowsDriveLetters = windowsDriveLetters;
|
this.mounter = mounter;
|
||||||
this.showingStats = new SimpleBooleanProperty(false);
|
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 {
|
public synchronized void unlock(MasterkeyLoader keyLoader) throws CryptoException, IOException, MountFailedException {
|
||||||
if (cryptoFileSystem.get() != null) {
|
if (cryptoFileSystem.get() != null) {
|
||||||
throw new IllegalStateException("Already unlocked.");
|
throw new IllegalStateException("Already unlocked.");
|
||||||
@@ -207,8 +147,7 @@ public class Vault {
|
|||||||
try {
|
try {
|
||||||
cryptoFileSystem.set(fs);
|
cryptoFileSystem.set(fs);
|
||||||
var rootPath = fs.getRootDirectories().iterator().next();
|
var rootPath = fs.getRootDirectories().iterator().next();
|
||||||
var supportsForcedUnmount = mountService.getValue().hasCapability(MountCapability.UNMOUNT_FORCED);
|
var mountHandle = mounter.mount(vaultSettings, rootPath);
|
||||||
var mountHandle = new MountHandle(prepareMount(rootPath).mount(), supportsForcedUnmount);
|
|
||||||
success = this.mountHandle.compareAndSet(null, mountHandle);
|
success = this.mountHandle.compareAndSet(null, mountHandle);
|
||||||
} finally {
|
} finally {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@@ -217,7 +156,6 @@ public class Vault {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public synchronized void lock(boolean forced) throws UnmountFailedException, IOException {
|
public synchronized void lock(boolean forced) throws UnmountFailedException, IOException {
|
||||||
var mountHandle = this.mountHandle.get();
|
var mountHandle = this.mountHandle.get();
|
||||||
if (mountHandle == null) {
|
if (mountHandle == null) {
|
||||||
@@ -225,14 +163,15 @@ public class Vault {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (forced && mountHandle.supportsUnmountForced) {
|
if (forced && mountHandle.supportsUnmountForced()) {
|
||||||
mountHandle.mount.unmountForced();
|
mountHandle.mountObj().unmountForced();
|
||||||
} else {
|
} else {
|
||||||
mountHandle.mount.unmount();
|
mountHandle.mountObj().unmount();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mountHandle.mount.close();
|
mountHandle.mountObj().close();
|
||||||
|
mountHandle.specialCleanup().run();
|
||||||
} finally {
|
} finally {
|
||||||
destroyCryptoFileSystem();
|
destroyCryptoFileSystem();
|
||||||
}
|
}
|
||||||
@@ -327,7 +266,7 @@ public class Vault {
|
|||||||
|
|
||||||
public Mountpoint getMountPoint() {
|
public Mountpoint getMountPoint() {
|
||||||
var handle = mountHandle.get();
|
var handle = mountHandle.get();
|
||||||
return handle == null ? null : handle.mount.getMountpoint();
|
return handle == null ? null : handle.mountObj().getMountpoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
public StringBinding displayablePathProperty() {
|
public StringBinding displayablePathProperty() {
|
||||||
@@ -375,24 +314,30 @@ public class Vault {
|
|||||||
return vaultSettings.path().getValue();
|
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() {
|
if (getMountPoint() instanceof Mountpoint.WithPath mp) {
|
||||||
return defaultMountFlags;
|
var absoluteCryptoFsPath = cryptoFsPathSeparator + mp.path().relativize(cleartextPath).toString();
|
||||||
}
|
if (!cryptoFsPathSeparator.equals(osPathSeparator)) {
|
||||||
|
absoluteCryptoFsPath = absoluteCryptoFsPath.replace(osPathSeparator, cryptoFsPathSeparator);
|
||||||
public String getDefaultMountFlags() {
|
}
|
||||||
return defaultMountFlags.getValue();
|
var cryptoPath = fs.getPath(absoluteCryptoFsPath);
|
||||||
}
|
return fs.getCiphertextPath(cryptoPath);
|
||||||
|
|
||||||
public String getEffectiveMountFlags() {
|
|
||||||
String mountFlags = vaultSettings.mountFlags().get();
|
|
||||||
if (Strings.isNullOrEmpty(mountFlags)) {
|
|
||||||
return ""; //TODO: should the provider provide dem defaults??
|
|
||||||
} else {
|
} else {
|
||||||
return mountFlags;
|
throw new UnsupportedOperationException("URI mount points not supported.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,10 +345,6 @@ public class Vault {
|
|||||||
return configCache;
|
return configCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCustomMountFlags(String mountFlags) {
|
|
||||||
vaultSettings.mountFlags().set(mountFlags);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return vaultSettings.getId();
|
return vaultSettings.getId();
|
||||||
}
|
}
|
||||||
@@ -426,15 +367,12 @@ public class Vault {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* TODO: reactivate/ needed at all?
|
|
||||||
public boolean supportsForcedUnmount() {
|
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) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -41,6 +41,8 @@ public class VaultStats {
|
|||||||
private final LongProperty totalBytesDecrypted = new SimpleLongProperty();
|
private final LongProperty totalBytesDecrypted = new SimpleLongProperty();
|
||||||
private final LongProperty filesRead = new SimpleLongProperty();
|
private final LongProperty filesRead = new SimpleLongProperty();
|
||||||
private final LongProperty filesWritten = new SimpleLongProperty();
|
private final LongProperty filesWritten = new SimpleLongProperty();
|
||||||
|
private final LongProperty filesAccessed = new SimpleLongProperty();
|
||||||
|
private final LongProperty totalFilesAccessed = new SimpleLongProperty();
|
||||||
private final ObjectProperty<Instant> lastActivity = new SimpleObjectProperty<>();
|
private final ObjectProperty<Instant> lastActivity = new SimpleObjectProperty<>();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -82,6 +84,8 @@ public class VaultStats {
|
|||||||
var oldAccessCount = filesRead.get() + filesWritten.get();
|
var oldAccessCount = filesRead.get() + filesWritten.get();
|
||||||
filesRead.set(stats.map(CryptoFileSystemStats::pollAmountOfAccessesRead).orElse(0L));
|
filesRead.set(stats.map(CryptoFileSystemStats::pollAmountOfAccessesRead).orElse(0L));
|
||||||
filesWritten.set(stats.map(CryptoFileSystemStats::pollAmountOfAccessesWritten).orElse(0L));
|
filesWritten.set(stats.map(CryptoFileSystemStats::pollAmountOfAccessesWritten).orElse(0L));
|
||||||
|
filesAccessed.set(stats.map(CryptoFileSystemStats::pollAmountOfAccesses).orElse(0L));
|
||||||
|
totalFilesAccessed.set(stats.map(CryptoFileSystemStats::pollTotalAmountOfAccesses).orElse(0L));
|
||||||
var newAccessCount = filesRead.get() + filesWritten.get();
|
var newAccessCount = filesRead.get() + filesWritten.get();
|
||||||
|
|
||||||
// check for any I/O activity
|
// check for any I/O activity
|
||||||
@@ -188,6 +192,19 @@ public class VaultStats {
|
|||||||
|
|
||||||
public long getFilesWritten() {return filesWritten.get();}
|
public long getFilesWritten() {return filesWritten.get();}
|
||||||
|
|
||||||
|
public LongProperty filesAccessed() {
|
||||||
|
return filesAccessed;}
|
||||||
|
|
||||||
|
public long getFilesAccessed() {return filesAccessed.get();}
|
||||||
|
|
||||||
|
public LongProperty totalFilesAccessed(){
|
||||||
|
return totalFilesAccessed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTotalFilesAccessed(){
|
||||||
|
return totalFilesAccessed.get();
|
||||||
|
}
|
||||||
|
|
||||||
public ObjectProperty<Instant> lastActivityProperty() {
|
public ObjectProperty<Instant> lastActivityProperty() {
|
||||||
return lastActivity;
|
return lastActivity;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import java.nio.channels.ReadableByteChannel;
|
|||||||
import java.nio.channels.WritableByteChannel;
|
import java.nio.channels.WritableByteChannel;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
// TODO make sealed, remove enum
|
//TODO can the enum be removed?
|
||||||
interface IpcMessage {
|
sealed interface IpcMessage permits HandleLaunchArgsMessage, RevealRunningAppMessage {
|
||||||
|
|
||||||
enum MessageType {
|
enum MessageType {
|
||||||
REVEAL_RUNNING_APP(RevealRunningAppMessage::decode),
|
REVEAL_RUNNING_APP(RevealRunningAppMessage::decode),
|
||||||
|
|||||||
@@ -5,10 +5,9 @@ import java.util.List;
|
|||||||
public interface IpcMessageListener {
|
public interface IpcMessageListener {
|
||||||
|
|
||||||
default void handleMessage(IpcMessage message) {
|
default void handleMessage(IpcMessage message) {
|
||||||
if (message instanceof RevealRunningAppMessage) {
|
switch (message) {
|
||||||
revealRunningApp();
|
case RevealRunningAppMessage m -> revealRunningApp(); // TODO: rename to _ with JEP 443
|
||||||
} else if (message instanceof HandleLaunchArgsMessage m) {
|
case HandleLaunchArgsMessage m -> handleLaunchArgs(m.args());
|
||||||
handleLaunchArgs(m.args());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
package org.cryptomator.launcher;
|
package org.cryptomator.launcher;
|
||||||
|
|
||||||
import org.cryptomator.common.settings.Settings;
|
import org.cryptomator.common.settings.Settings;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
import java.text.Collator;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
@@ -14,26 +16,39 @@ import java.util.Locale;
|
|||||||
public class SupportedLanguages {
|
public class SupportedLanguages {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(SupportedLanguages.class);
|
private static final Logger LOG = LoggerFactory.getLogger(SupportedLanguages.class);
|
||||||
// these are BCP 47 language codes, not ISO. Note the "-" instead of the "_":
|
// 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", //
|
// "en" is not part of this list - it is always inserted at the top.
|
||||||
"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", //
|
public static final List<String> LANGUAGE_TAGS = List.of("ar", "be", "bn", "bs", "ca", "cs", "da", "de", "el", "es", "fr", "gl", "he", //
|
||||||
"ta", "te", "th", "tr", "uk", "vi", "zh", "zh-HK", "zh-TW");
|
"hi", "hr", "hu", "id", "it", "ja", "ko", "lv", "nb", "nl", "nn", "pa", "pl", "pt", "pt-BR", "ro", "ru", "sk", "sr", "sr-Latn", "sv", "sw", //
|
||||||
|
"ta", "th", "tr", "uk", "vi", "zh", "zh-HK", "zh-TW");
|
||||||
|
public static final String ENGLISH = "en";
|
||||||
|
|
||||||
@Nullable
|
private final List<String> sortedLanguageTags;
|
||||||
private final String preferredLanguage;
|
|
||||||
|
private final Locale preferredLocale;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public SupportedLanguages(Settings settings) {
|
public SupportedLanguages(Settings settings) {
|
||||||
this.preferredLanguage = settings.languageProperty().get();
|
var preferredLanguage = settings.languageProperty().get();
|
||||||
|
preferredLocale = preferredLanguage == null ? Locale.getDefault() : Locale.forLanguageTag(preferredLanguage);
|
||||||
|
var collator = Collator.getInstance(preferredLocale);
|
||||||
|
collator.setStrength(Collator.PRIMARY);
|
||||||
|
var sorted = new ArrayList<String>();
|
||||||
|
sorted.add(0, Settings.DEFAULT_LANGUAGE);
|
||||||
|
sorted.add(1, ENGLISH);
|
||||||
|
LANGUAGE_TAGS.stream() //
|
||||||
|
.sorted((a, b) -> collator.compare(Locale.forLanguageTag(a).getDisplayName(), Locale.forLanguageTag(b).getDisplayName())) //
|
||||||
|
.forEach(sorted::add);
|
||||||
|
sortedLanguageTags = Collections.unmodifiableList(sorted);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void applyPreferred() {
|
public void applyPreferred() {
|
||||||
if (preferredLanguage == null) {
|
LOG.debug("Using locale {}", preferredLocale);
|
||||||
LOG.debug("Using system locale");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var preferredLocale = Locale.forLanguageTag(preferredLanguage);
|
|
||||||
LOG.debug("Applying preferred locale {}", preferredLocale.getDisplayName(Locale.ENGLISH));
|
|
||||||
Locale.setDefault(preferredLocale);
|
Locale.setDefault(preferredLocale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getLanguageTags() {
|
||||||
|
return sortedLanguageTags;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,6 +84,10 @@ public class LogbackConfigurator extends ContextAwareBase implements Configurato
|
|||||||
upgrades.addAppender(upgrade);
|
upgrades.addAppender(upgrade);
|
||||||
upgrades.addAppender(file);
|
upgrades.addAppender(file);
|
||||||
upgrades.setAdditive(false);
|
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;
|
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.FxmlFile;
|
||||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||||
import org.cryptomator.ui.common.FxmlScene;
|
import org.cryptomator.ui.common.FxmlScene;
|
||||||
import org.cryptomator.ui.common.NewPasswordController;
|
import org.cryptomator.ui.changepassword.NewPasswordController;
|
||||||
import org.cryptomator.ui.common.PasswordStrengthUtil;
|
import org.cryptomator.ui.changepassword.PasswordStrengthUtil;
|
||||||
import org.cryptomator.ui.common.StageFactory;
|
import org.cryptomator.ui.common.StageFactory;
|
||||||
import org.cryptomator.ui.fxapp.PrimaryStage;
|
import org.cryptomator.ui.fxapp.PrimaryStage;
|
||||||
import org.cryptomator.ui.recoverykey.RecoveryKeyDisplayController;
|
import org.cryptomator.ui.recoverykey.RecoveryKeyDisplayController;
|
||||||
|
|||||||
+21
-12
@@ -2,19 +2,20 @@ package org.cryptomator.ui.addvaultwizard;
|
|||||||
|
|
||||||
import dagger.Lazy;
|
import dagger.Lazy;
|
||||||
import org.apache.commons.lang3.SystemUtils;
|
import org.apache.commons.lang3.SystemUtils;
|
||||||
import org.cryptomator.common.settings.Settings;
|
|
||||||
import org.cryptomator.common.settings.UiTheme;
|
|
||||||
import org.cryptomator.common.vaults.Vault;
|
import org.cryptomator.common.vaults.Vault;
|
||||||
import org.cryptomator.common.vaults.VaultListManager;
|
import org.cryptomator.common.vaults.VaultListManager;
|
||||||
|
import org.cryptomator.integrations.uiappearance.Theme;
|
||||||
import org.cryptomator.ui.common.FxController;
|
import org.cryptomator.ui.common.FxController;
|
||||||
import org.cryptomator.ui.common.FxmlFile;
|
import org.cryptomator.ui.common.FxmlFile;
|
||||||
import org.cryptomator.ui.common.FxmlScene;
|
import org.cryptomator.ui.common.FxmlScene;
|
||||||
|
import org.cryptomator.ui.fxapp.FxApplicationStyle;
|
||||||
import org.cryptomator.ui.fxapp.FxApplicationWindows;
|
import org.cryptomator.ui.fxapp.FxApplicationWindows;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
@@ -23,6 +24,7 @@ import javafx.stage.Stage;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
import static org.cryptomator.common.Constants.CRYPTOMATOR_FILENAME_GLOB;
|
import static org.cryptomator.common.Constants.CRYPTOMATOR_FILENAME_GLOB;
|
||||||
@@ -40,12 +42,10 @@ public class ChooseExistingVaultController implements FxController {
|
|||||||
private final ObjectProperty<Vault> vault;
|
private final ObjectProperty<Vault> vault;
|
||||||
private final VaultListManager vaultListManager;
|
private final VaultListManager vaultListManager;
|
||||||
private final ResourceBundle resourceBundle;
|
private final ResourceBundle resourceBundle;
|
||||||
private final Settings settings;
|
private final ObservableValue<Image> screenshot;
|
||||||
|
|
||||||
private Image screenshot;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ChooseExistingVaultController(@AddVaultWizardWindow Stage window, @FxmlScene(FxmlFile.ADDVAULT_WELCOME) Lazy<Scene> welcomeScene, @FxmlScene(FxmlFile.ADDVAULT_SUCCESS) Lazy<Scene> successScene, FxApplicationWindows appWindows, ObjectProperty<Path> vaultPath, @AddVaultWizardWindow ObjectProperty<Vault> vault, VaultListManager vaultListManager, ResourceBundle resourceBundle, Settings settings) {
|
ChooseExistingVaultController(@AddVaultWizardWindow Stage window, @FxmlScene(FxmlFile.ADDVAULT_WELCOME) Lazy<Scene> welcomeScene, @FxmlScene(FxmlFile.ADDVAULT_SUCCESS) Lazy<Scene> successScene, FxApplicationWindows appWindows, ObjectProperty<Path> vaultPath, @AddVaultWizardWindow ObjectProperty<Vault> vault, VaultListManager vaultListManager, ResourceBundle resourceBundle, FxApplicationStyle applicationStyle) {
|
||||||
this.window = window;
|
this.window = window;
|
||||||
this.welcomeScene = welcomeScene;
|
this.welcomeScene = welcomeScene;
|
||||||
this.successScene = successScene;
|
this.successScene = successScene;
|
||||||
@@ -54,16 +54,20 @@ public class ChooseExistingVaultController implements FxController {
|
|||||||
this.vault = vault;
|
this.vault = vault;
|
||||||
this.vaultListManager = vaultListManager;
|
this.vaultListManager = vaultListManager;
|
||||||
this.resourceBundle = resourceBundle;
|
this.resourceBundle = resourceBundle;
|
||||||
this.settings = settings;
|
this.screenshot = applicationStyle.appliedThemeProperty().map(this::selectScreenshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
private Image selectScreenshot(Theme theme) {
|
||||||
public void initialize() {
|
String imageResourcePath;
|
||||||
if (SystemUtils.IS_OS_MAC) {
|
if (SystemUtils.IS_OS_MAC) {
|
||||||
this.screenshot = new Image(getClass().getResource("/img/select-masterkey-mac"+(UiTheme.LIGHT == settings.theme().get()? "":"-dark")+".png").toString());
|
imageResourcePath = switch (theme) {
|
||||||
|
case LIGHT -> "/img/select-masterkey-mac.png";
|
||||||
|
case DARK -> "/img/select-masterkey-mac-dark.png";
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
this.screenshot = new Image(getClass().getResource("/img/select-masterkey-win.png").toString());
|
imageResourcePath = "/img/select-masterkey-win.png";
|
||||||
}
|
}
|
||||||
|
return new Image((Objects.requireNonNull(getClass().getResource(imageResourcePath)).toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
@@ -92,8 +96,13 @@ public class ChooseExistingVaultController implements FxController {
|
|||||||
|
|
||||||
/* Getter */
|
/* Getter */
|
||||||
|
|
||||||
public Image getScreenshot() {
|
public ObservableValue<Image> screenshotProperty() {
|
||||||
return screenshot;
|
return screenshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Image getScreenshot() {
|
||||||
|
return screenshot.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+63
-84
@@ -1,6 +1,9 @@
|
|||||||
package org.cryptomator.ui.addvaultwizard;
|
package org.cryptomator.ui.addvaultwizard;
|
||||||
|
|
||||||
import dagger.Lazy;
|
import dagger.Lazy;
|
||||||
|
import org.cryptomator.common.ObservableUtil;
|
||||||
|
import org.cryptomator.common.locationpresets.LocationPreset;
|
||||||
|
import org.cryptomator.common.locationpresets.LocationPresetsProvider;
|
||||||
import org.cryptomator.ui.common.FxController;
|
import org.cryptomator.ui.common.FxController;
|
||||||
import org.cryptomator.ui.common.FxmlFile;
|
import org.cryptomator.ui.common.FxmlFile;
|
||||||
import org.cryptomator.ui.common.FxmlScene;
|
import org.cryptomator.ui.common.FxmlScene;
|
||||||
@@ -10,22 +13,19 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import javafx.beans.binding.Bindings;
|
|
||||||
import javafx.beans.binding.BooleanBinding;
|
import javafx.beans.binding.BooleanBinding;
|
||||||
import javafx.beans.property.BooleanProperty;
|
import javafx.beans.property.BooleanProperty;
|
||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
import javafx.beans.property.SimpleBooleanProperty;
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
|
||||||
import javafx.beans.property.StringProperty;
|
import javafx.beans.property.StringProperty;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.Node;
|
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.control.RadioButton;
|
import javafx.scene.control.RadioButton;
|
||||||
import javafx.scene.control.Toggle;
|
import javafx.scene.control.Toggle;
|
||||||
import javafx.scene.control.ToggleGroup;
|
import javafx.scene.control.ToggleGroup;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
import javafx.stage.DirectoryChooser;
|
import javafx.stage.DirectoryChooser;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -34,6 +34,9 @@ import java.nio.file.Files;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.StandardOpenOption;
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
@AddVaultWizardScoped
|
@AddVaultWizardScoped
|
||||||
@@ -46,70 +49,72 @@ public class CreateNewVaultLocationController implements FxController {
|
|||||||
private final Stage window;
|
private final Stage window;
|
||||||
private final Lazy<Scene> chooseNameScene;
|
private final Lazy<Scene> chooseNameScene;
|
||||||
private final Lazy<Scene> choosePasswordScene;
|
private final Lazy<Scene> choosePasswordScene;
|
||||||
private final ObservedLocationPresets locationPresets;
|
private final List<RadioButton> locationPresetBtns;
|
||||||
private final ObjectProperty<Path> vaultPath;
|
private final ObjectProperty<Path> vaultPath;
|
||||||
private final StringProperty vaultName;
|
private final StringProperty vaultName;
|
||||||
private final ResourceBundle resourceBundle;
|
private final ResourceBundle resourceBundle;
|
||||||
private final BooleanBinding validVaultPath;
|
private final ObservableValue<VaultPathStatus> vaultPathStatus;
|
||||||
|
private final ObservableValue<Boolean> validVaultPath;
|
||||||
private final BooleanProperty usePresetPath;
|
private final BooleanProperty usePresetPath;
|
||||||
private final StringProperty statusText;
|
|
||||||
private final ObjectProperty<Node> statusGraphic;
|
|
||||||
|
|
||||||
private Path customVaultPath = DEFAULT_CUSTOM_VAULT_PATH;
|
private Path customVaultPath = DEFAULT_CUSTOM_VAULT_PATH;
|
||||||
|
|
||||||
//FXML
|
//FXML
|
||||||
public ToggleGroup predefinedLocationToggler;
|
public ToggleGroup locationPresetsToggler;
|
||||||
public RadioButton iclouddriveRadioButton;
|
public VBox radioButtonVBox;
|
||||||
public RadioButton dropboxRadioButton;
|
|
||||||
public RadioButton gdriveRadioButton;
|
|
||||||
public RadioButton onedriveRadioButton;
|
|
||||||
public RadioButton megaRadioButton;
|
|
||||||
public RadioButton pcloudRadioButton;
|
|
||||||
public RadioButton customRadioButton;
|
public RadioButton customRadioButton;
|
||||||
public Label vaultPathStatus;
|
public Label locationStatusLabel;
|
||||||
public FontAwesome5IconView goodLocation;
|
public FontAwesome5IconView goodLocation;
|
||||||
public FontAwesome5IconView badLocation;
|
public FontAwesome5IconView badLocation;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
CreateNewVaultLocationController(@AddVaultWizardWindow Stage window, @FxmlScene(FxmlFile.ADDVAULT_NEW_NAME) Lazy<Scene> chooseNameScene, @FxmlScene(FxmlFile.ADDVAULT_NEW_PASSWORD) Lazy<Scene> choosePasswordScene, ObservedLocationPresets locationPresets, ObjectProperty<Path> vaultPath, @Named("vaultName") StringProperty vaultName, ResourceBundle resourceBundle) {
|
CreateNewVaultLocationController(@AddVaultWizardWindow Stage window, @FxmlScene(FxmlFile.ADDVAULT_NEW_NAME) Lazy<Scene> chooseNameScene, @FxmlScene(FxmlFile.ADDVAULT_NEW_PASSWORD) Lazy<Scene> choosePasswordScene, ObjectProperty<Path> vaultPath, @Named("vaultName") StringProperty vaultName, ResourceBundle resourceBundle) {
|
||||||
this.window = window;
|
this.window = window;
|
||||||
this.chooseNameScene = chooseNameScene;
|
this.chooseNameScene = chooseNameScene;
|
||||||
this.choosePasswordScene = choosePasswordScene;
|
this.choosePasswordScene = choosePasswordScene;
|
||||||
this.locationPresets = locationPresets;
|
|
||||||
this.vaultPath = vaultPath;
|
this.vaultPath = vaultPath;
|
||||||
this.vaultName = vaultName;
|
this.vaultName = vaultName;
|
||||||
this.resourceBundle = resourceBundle;
|
this.resourceBundle = resourceBundle;
|
||||||
this.validVaultPath = Bindings.createBooleanBinding(this::validateVaultPathAndSetStatus, this.vaultPath);
|
this.vaultPathStatus = ObservableUtil.mapWithDefault(vaultPath, this::validatePath, new VaultPathStatus(false, "error.message"));
|
||||||
|
this.validVaultPath = ObservableUtil.mapWithDefault(vaultPathStatus, VaultPathStatus::valid, false);
|
||||||
|
this.vaultPathStatus.addListener(this::updateStatusLabel);
|
||||||
this.usePresetPath = new SimpleBooleanProperty();
|
this.usePresetPath = new SimpleBooleanProperty();
|
||||||
this.statusText = new SimpleStringProperty();
|
this.locationPresetBtns = LocationPresetsProvider.loadAll(LocationPresetsProvider.class) //
|
||||||
this.statusGraphic = new SimpleObjectProperty<>();
|
.flatMap(LocationPresetsProvider::getLocations) //
|
||||||
|
.sorted(Comparator.comparing(LocationPreset::name)) //
|
||||||
|
.map(preset -> { //
|
||||||
|
var btn = new RadioButton(preset.name());
|
||||||
|
btn.setUserData(preset.path());
|
||||||
|
return btn;
|
||||||
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean validateVaultPathAndSetStatus() {
|
private VaultPathStatus validatePath(Path p) throws NullPointerException {
|
||||||
final Path p = vaultPath.get();
|
if (!Files.exists(p.getParent())) {
|
||||||
if (p == null) {
|
return new VaultPathStatus(false, "addvaultwizard.new.locationDoesNotExist");
|
||||||
statusText.set("Error: Path is NULL.");
|
|
||||||
statusGraphic.set(badLocation);
|
|
||||||
return false;
|
|
||||||
} else if (!Files.exists(p.getParent())) {
|
|
||||||
statusText.set(resourceBundle.getString("addvaultwizard.new.locationDoesNotExist"));
|
|
||||||
statusGraphic.set(badLocation);
|
|
||||||
return false;
|
|
||||||
} else if (!isActuallyWritable(p.getParent())) {
|
} else if (!isActuallyWritable(p.getParent())) {
|
||||||
statusText.set(resourceBundle.getString("addvaultwizard.new.locationIsNotWritable"));
|
return new VaultPathStatus(false, "addvaultwizard.new.locationIsNotWritable");
|
||||||
statusGraphic.set(badLocation);
|
|
||||||
return false;
|
|
||||||
} else if (!Files.notExists(p)) {
|
} else if (!Files.notExists(p)) {
|
||||||
statusText.set(resourceBundle.getString("addvaultwizard.new.fileAlreadyExists"));
|
return new VaultPathStatus(false, "addvaultwizard.new.fileAlreadyExists");
|
||||||
statusGraphic.set(badLocation);
|
|
||||||
return false;
|
|
||||||
} else {
|
} else {
|
||||||
statusText.set(resourceBundle.getString("addvaultwizard.new.locationIsOk"));
|
return new VaultPathStatus(true, "addvaultwizard.new.locationIsOk");
|
||||||
statusGraphic.set(goodLocation);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateStatusLabel(ObservableValue<? extends VaultPathStatus> observable, VaultPathStatus oldValue, VaultPathStatus newValue) {
|
||||||
|
if (newValue.valid()) {
|
||||||
|
locationStatusLabel.setGraphic(goodLocation);
|
||||||
|
locationStatusLabel.getStyleClass().remove("label-red");
|
||||||
|
locationStatusLabel.getStyleClass().add("label-muted");
|
||||||
|
} else {
|
||||||
|
locationStatusLabel.setGraphic(badLocation);
|
||||||
|
locationStatusLabel.getStyleClass().remove("label-muted");
|
||||||
|
locationStatusLabel.getStyleClass().add("label-red");
|
||||||
|
}
|
||||||
|
this.locationStatusLabel.setText(resourceBundle.getString(newValue.localizationKey()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private boolean isActuallyWritable(Path p) {
|
private boolean isActuallyWritable(Path p) {
|
||||||
Path tmpFile = p.resolve(TEMP_FILE_FORMAT);
|
Path tmpFile = p.resolve(TEMP_FILE_FORMAT);
|
||||||
try (var chan = Files.newByteChannel(tmpFile, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE, StandardOpenOption.DELETE_ON_CLOSE)) {
|
try (var chan = Files.newByteChannel(tmpFile, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE, StandardOpenOption.DELETE_ON_CLOSE)) {
|
||||||
@@ -127,26 +132,15 @@ public class CreateNewVaultLocationController implements FxController {
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
predefinedLocationToggler.selectedToggleProperty().addListener(this::togglePredefinedLocation);
|
radioButtonVBox.getChildren().addAll(1, locationPresetBtns); //first item is the list header
|
||||||
usePresetPath.bind(predefinedLocationToggler.selectedToggleProperty().isNotEqualTo(customRadioButton));
|
locationPresetsToggler.getToggles().addAll(locationPresetBtns);
|
||||||
|
locationPresetsToggler.selectedToggleProperty().addListener(this::togglePredefinedLocation);
|
||||||
|
usePresetPath.bind(locationPresetsToggler.selectedToggleProperty().isNotEqualTo(customRadioButton));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void togglePredefinedLocation(@SuppressWarnings("unused") ObservableValue<? extends Toggle> observable, @SuppressWarnings("unused") Toggle oldValue, Toggle newValue) {
|
private void togglePredefinedLocation(@SuppressWarnings("unused") ObservableValue<? extends Toggle> observable, @SuppressWarnings("unused") Toggle oldValue, Toggle newValue) {
|
||||||
if (iclouddriveRadioButton.equals(newValue)) {
|
var storagePath = Optional.ofNullable((Path) newValue.getUserData()).orElse(customVaultPath);
|
||||||
vaultPath.set(locationPresets.getIclouddriveLocation().resolve(vaultName.get()));
|
vaultPath.set(storagePath.resolve(vaultName.get()));
|
||||||
} else if (dropboxRadioButton.equals(newValue)) {
|
|
||||||
vaultPath.set(locationPresets.getDropboxLocation().resolve(vaultName.get()));
|
|
||||||
} else if (gdriveRadioButton.equals(newValue)) {
|
|
||||||
vaultPath.set(locationPresets.getGdriveLocation().resolve(vaultName.get()));
|
|
||||||
} else if (onedriveRadioButton.equals(newValue)) {
|
|
||||||
vaultPath.set(locationPresets.getOnedriveLocation().resolve(vaultName.get()));
|
|
||||||
} else if (megaRadioButton.equals(newValue)) {
|
|
||||||
vaultPath.set(locationPresets.getMegaLocation().resolve(vaultName.get()));
|
|
||||||
} else if (pcloudRadioButton.equals(newValue)) {
|
|
||||||
vaultPath.set(locationPresets.getPcloudLocation().resolve(vaultName.get()));
|
|
||||||
} else if (customRadioButton.equals(newValue)) {
|
|
||||||
vaultPath.set(customVaultPath.resolve(vaultName.get()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
@@ -156,10 +150,8 @@ public class CreateNewVaultLocationController implements FxController {
|
|||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void next() {
|
public void next() {
|
||||||
if (validateVaultPathAndSetStatus()) {
|
if (validVaultPath.getValue()) {
|
||||||
window.setScene(choosePasswordScene.get());
|
window.setScene(choosePasswordScene.get());
|
||||||
} else {
|
|
||||||
validVaultPath.invalidate();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,6 +171,12 @@ public class CreateNewVaultLocationController implements FxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Internal classes */
|
||||||
|
|
||||||
|
private record VaultPathStatus(boolean valid, String localizationKey) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* Getter/Setter */
|
/* Getter/Setter */
|
||||||
|
|
||||||
public Path getVaultPath() {
|
public Path getVaultPath() {
|
||||||
@@ -189,47 +187,28 @@ public class CreateNewVaultLocationController implements FxController {
|
|||||||
return vaultPath;
|
return vaultPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BooleanBinding validVaultPathProperty() {
|
public ObservableValue<Boolean> validVaultPathProperty() {
|
||||||
return validVaultPath;
|
return validVaultPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean getValidVaultPath() {
|
public boolean isValidVaultPath() {
|
||||||
return validVaultPath.get();
|
return validVaultPath.getValue();
|
||||||
}
|
|
||||||
|
|
||||||
public ObservedLocationPresets getObservedLocationPresets() {
|
|
||||||
return locationPresets;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BooleanProperty usePresetPathProperty() {
|
public BooleanProperty usePresetPathProperty() {
|
||||||
return usePresetPath;
|
return usePresetPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getUsePresetPath() {
|
public boolean isUsePresetPath() {
|
||||||
return usePresetPath.get();
|
return usePresetPath.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public BooleanBinding anyRadioButtonSelectedProperty() {
|
public BooleanBinding anyRadioButtonSelectedProperty() {
|
||||||
return predefinedLocationToggler.selectedToggleProperty().isNotNull();
|
return locationPresetsToggler.selectedToggleProperty().isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAnyRadioButtonSelected() {
|
public boolean isAnyRadioButtonSelected() {
|
||||||
return anyRadioButtonSelectedProperty().get();
|
return anyRadioButtonSelectedProperty().get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public StringProperty statusTextProperty() {
|
|
||||||
return statusText;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getStatusText() {
|
|
||||||
return statusText.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObjectProperty<Node> statusGraphicProperty() {
|
|
||||||
return statusGraphic;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Node getStatusGraphic() {
|
|
||||||
return statusGraphic.get();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -13,7 +13,7 @@ import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
|
|||||||
import org.cryptomator.ui.common.FxController;
|
import org.cryptomator.ui.common.FxController;
|
||||||
import org.cryptomator.ui.common.FxmlFile;
|
import org.cryptomator.ui.common.FxmlFile;
|
||||||
import org.cryptomator.ui.common.FxmlScene;
|
import org.cryptomator.ui.common.FxmlScene;
|
||||||
import org.cryptomator.ui.common.NewPasswordController;
|
import org.cryptomator.ui.changepassword.NewPasswordController;
|
||||||
import org.cryptomator.ui.common.Tasks;
|
import org.cryptomator.ui.common.Tasks;
|
||||||
import org.cryptomator.ui.fxapp.FxApplicationWindows;
|
import org.cryptomator.ui.fxapp.FxApplicationWindows;
|
||||||
import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingStrategy;
|
import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingStrategy;
|
||||||
@@ -48,13 +48,13 @@ import java.util.ResourceBundle;
|
|||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
import static java.nio.charset.StandardCharsets.US_ASCII;
|
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;
|
import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
|
||||||
|
|
||||||
@AddVaultWizardScoped
|
@AddVaultWizardScoped
|
||||||
public class CreateNewVaultPasswordController implements FxController {
|
public class CreateNewVaultPasswordController implements FxController {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(CreateNewVaultPasswordController.class);
|
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 Stage window;
|
||||||
private final Lazy<Scene> chooseLocationScene;
|
private final Lazy<Scene> chooseLocationScene;
|
||||||
@@ -176,7 +176,7 @@ public class CreateNewVaultPasswordController implements FxController {
|
|||||||
// 2. initialize vault:
|
// 2. initialize vault:
|
||||||
try {
|
try {
|
||||||
MasterkeyLoader loader = ignored -> masterkey.copy();
|
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);
|
CryptoFileSystemProvider.initialize(path, fsProps, DEFAULT_KEY_ID);
|
||||||
|
|
||||||
// 3. write vault-internal readme file:
|
// 3. write vault-internal readme file:
|
||||||
|
|||||||
@@ -1,141 +0,0 @@
|
|||||||
package org.cryptomator.ui.addvaultwizard;
|
|
||||||
|
|
||||||
import org.cryptomator.common.LocationPreset;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javafx.beans.binding.BooleanBinding;
|
|
||||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
@AddVaultWizardScoped
|
|
||||||
public class ObservedLocationPresets {
|
|
||||||
|
|
||||||
private final ReadOnlyObjectProperty<Path> iclouddriveLocation;
|
|
||||||
private final ReadOnlyObjectProperty<Path> dropboxLocation;
|
|
||||||
private final ReadOnlyObjectProperty<Path> gdriveLocation;
|
|
||||||
private final ReadOnlyObjectProperty<Path> onedriveLocation;
|
|
||||||
private final ReadOnlyObjectProperty<Path> megaLocation;
|
|
||||||
private final ReadOnlyObjectProperty<Path> pcloudLocation;
|
|
||||||
private final BooleanBinding foundIclouddrive;
|
|
||||||
private final BooleanBinding foundDropbox;
|
|
||||||
private final BooleanBinding foundGdrive;
|
|
||||||
private final BooleanBinding foundOnedrive;
|
|
||||||
private final BooleanBinding foundMega;
|
|
||||||
private final BooleanBinding foundPcloud;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public ObservedLocationPresets() {
|
|
||||||
this.iclouddriveLocation = new SimpleObjectProperty<>(LocationPreset.ICLOUDDRIVE.existingPath());
|
|
||||||
this.dropboxLocation = new SimpleObjectProperty<>(LocationPreset.DROPBOX.existingPath());
|
|
||||||
this.gdriveLocation = new SimpleObjectProperty<>(LocationPreset.GDRIVE.existingPath());
|
|
||||||
this.onedriveLocation = new SimpleObjectProperty<>(LocationPreset.ONEDRIVE.existingPath());
|
|
||||||
this.megaLocation = new SimpleObjectProperty<>(LocationPreset.MEGA.existingPath());
|
|
||||||
this.pcloudLocation = new SimpleObjectProperty<>(LocationPreset.PCLOUD.existingPath());
|
|
||||||
this.foundIclouddrive = iclouddriveLocation.isNotNull();
|
|
||||||
this.foundDropbox = dropboxLocation.isNotNull();
|
|
||||||
this.foundGdrive = gdriveLocation.isNotNull();
|
|
||||||
this.foundOnedrive = onedriveLocation.isNotNull();
|
|
||||||
this.foundMega = megaLocation.isNotNull();
|
|
||||||
this.foundPcloud = pcloudLocation.isNotNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Observables */
|
|
||||||
|
|
||||||
public ReadOnlyObjectProperty<Path> iclouddriveLocationProperty() {
|
|
||||||
return iclouddriveLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Path getIclouddriveLocation() {
|
|
||||||
return iclouddriveLocation.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public BooleanBinding foundIclouddriveProperty() {
|
|
||||||
return foundIclouddrive;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFoundIclouddrive() {
|
|
||||||
return foundIclouddrive.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReadOnlyObjectProperty<Path> dropboxLocationProperty() {
|
|
||||||
return dropboxLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Path getDropboxLocation() {
|
|
||||||
return dropboxLocation.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public BooleanBinding foundDropboxProperty() {
|
|
||||||
return foundDropbox;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFoundDropbox() {
|
|
||||||
return foundDropbox.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReadOnlyObjectProperty<Path> gdriveLocationProperty() {
|
|
||||||
return gdriveLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Path getGdriveLocation() {
|
|
||||||
return gdriveLocation.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public BooleanBinding foundGdriveProperty() {
|
|
||||||
return foundGdrive;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFoundGdrive() {
|
|
||||||
return foundGdrive.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReadOnlyObjectProperty<Path> onedriveLocationProperty() {
|
|
||||||
return onedriveLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Path getOnedriveLocation() {
|
|
||||||
return onedriveLocation.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public BooleanBinding foundOnedriveProperty() {
|
|
||||||
return foundOnedrive;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFoundOnedrive() {
|
|
||||||
return foundOnedrive.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReadOnlyObjectProperty<Path> megaLocationProperty() {
|
|
||||||
return megaLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Path getMegaLocation() {
|
|
||||||
return megaLocation.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public BooleanBinding foundMegaProperty() {
|
|
||||||
return foundMega;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFoundMega() {
|
|
||||||
return foundMega.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReadOnlyObjectProperty<Path> pcloudLocationProperty() {
|
|
||||||
return pcloudLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Path getPcloudLocation() {
|
|
||||||
return pcloudLocation.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public BooleanBinding foundPcloudProperty() {
|
|
||||||
return foundPcloud;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFoundPcloud() {
|
|
||||||
return foundPcloud.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -9,7 +9,6 @@ import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
|
|||||||
import org.cryptomator.integrations.keychain.KeychainAccessException;
|
import org.cryptomator.integrations.keychain.KeychainAccessException;
|
||||||
import org.cryptomator.ui.common.Animations;
|
import org.cryptomator.ui.common.Animations;
|
||||||
import org.cryptomator.ui.common.FxController;
|
import org.cryptomator.ui.common.FxController;
|
||||||
import org.cryptomator.ui.common.NewPasswordController;
|
|
||||||
import org.cryptomator.ui.controls.NiceSecurePasswordField;
|
import org.cryptomator.ui.controls.NiceSecurePasswordField;
|
||||||
import org.cryptomator.ui.fxapp.FxApplicationWindows;
|
import org.cryptomator.ui.fxapp.FxApplicationWindows;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user