mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-14 16:51:28 +00:00
Compare commits
699 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
61a45fc738 | ||
|
|
3a65b5551f | ||
|
|
94ed5c18b8 | ||
|
|
a559483d86 | ||
|
|
3acdef1dd0 | ||
|
|
def6f8ab95 | ||
|
|
11ba1f3ddc | ||
|
|
3228f2cf5f | ||
|
|
9c4f7ad79d | ||
|
|
3bd57d162b | ||
|
|
5ea73a5a8d | ||
|
|
38670838c7 | ||
|
|
3e0b84dbce | ||
|
|
2302db6206 | ||
|
|
a94bf99660 | ||
|
|
0c5ce353b1 | ||
|
|
b3ce777a42 | ||
|
|
3085df3397 | ||
|
|
fb740b605f | ||
|
|
6a74d9f3b2 | ||
|
|
1c7dffb63f | ||
|
|
a213f073b1 | ||
|
|
1ab73be1f4 | ||
|
|
8412871090 | ||
|
|
fa63f3ca67 | ||
|
|
dbc0f52481 | ||
|
|
b8cd1caeac | ||
|
|
43c25b6d97 | ||
|
|
e44bc09074 | ||
|
|
7b02f78ef5 | ||
|
|
f7e8a4d1e6 | ||
|
|
664375d692 | ||
|
|
2d968eac8c | ||
|
|
542d2fcfe1 | ||
|
|
144e929896 | ||
|
|
803748f78d | ||
|
|
3410e7243a | ||
|
|
84732337ca | ||
|
|
c527808710 | ||
|
|
99c89dbf39 | ||
|
|
829b64cd3d | ||
|
|
f4007267fb | ||
|
|
c82a0bfaf3 | ||
|
|
251ad65344 | ||
|
|
155ba4607b | ||
|
|
62f6865d3e | ||
|
|
ffb3290248 | ||
|
|
a013ae3d91 | ||
|
|
19a954e677 | ||
|
|
f262980acc | ||
|
|
3b3aa18c92 | ||
|
|
c7b8bc89c2 | ||
|
|
5fc981abd3 | ||
|
|
36ec1a5ebc | ||
|
|
be4aad4168 | ||
|
|
fcb940e29c | ||
|
|
4f3ca2a6c4 | ||
|
|
27cd34bee0 | ||
|
|
c07e51be51 | ||
|
|
0421879b39 | ||
|
|
2d627717a0 | ||
|
|
dc0e88a694 | ||
|
|
a5e3630375 | ||
|
|
17335e8f70 | ||
|
|
42dd2fba48 | ||
|
|
e1cca6427c | ||
|
|
42d3dbaa23 | ||
|
|
185d67c492 | ||
|
|
a8af3c8b40 | ||
|
|
038a7fac62 | ||
|
|
48408fa40d | ||
|
|
18a417667e | ||
|
|
aab07b13e3 | ||
|
|
869e40e351 | ||
|
|
bf91e3f15c | ||
|
|
17544828e4 | ||
|
|
cfef3139b1 | ||
|
|
b01ba27b06 | ||
|
|
5a33e66a7d | ||
|
|
3c4e35406e | ||
|
|
d3275fa4e7 | ||
|
|
a30db34c19 | ||
|
|
509100e7ae | ||
|
|
024c34172b | ||
|
|
638570562b | ||
|
|
ee5a5c6563 | ||
|
|
85c52c60c5 | ||
|
|
93184abd3c | ||
|
|
8062392ccd | ||
|
|
d49c02c7de | ||
|
|
d66cfe0e7c | ||
|
|
fa26fa9dee | ||
|
|
52fc94ca01 | ||
|
|
e9a412ae16 | ||
|
|
8104c35d76 | ||
|
|
baa2e05e69 | ||
|
|
f50b204cef | ||
|
|
ed902bc59f | ||
|
|
693299a5d7 | ||
|
|
def64aa2ac | ||
|
|
c5bb8a131d | ||
|
|
2e443c72a9 | ||
|
|
e9ee17493b | ||
|
|
35eb548d8e | ||
|
|
dc5d6e734e | ||
|
|
729f38866f | ||
|
|
4de8434f1b | ||
|
|
cd40731b5f | ||
|
|
24293b316f | ||
|
|
062c674ef1 | ||
|
|
830bb5776f | ||
|
|
bfdb23785e | ||
|
|
248d655afb | ||
|
|
995c0a4b92 | ||
|
|
42425afe56 | ||
|
|
a1b712495f | ||
|
|
2225476bf8 | ||
|
|
325057c548 | ||
|
|
b1a5eed2aa | ||
|
|
4ca190cfb9 | ||
|
|
828fd321cc | ||
|
|
2e32f39986 | ||
|
|
daa026b285 | ||
|
|
87084e8c2a | ||
|
|
8e52058373 | ||
|
|
8bf0acf35f | ||
|
|
e0d3a3d9c7 | ||
|
|
b59ce75ecd | ||
|
|
748f895b98 | ||
|
|
6d974c7fcf | ||
|
|
0ed73e8b41 | ||
|
|
538b4ecd0b | ||
|
|
8f32b46b30 | ||
|
|
4de25afde0 | ||
|
|
2e6c228f3f | ||
|
|
00fc2a9837 | ||
|
|
22e80e7dac | ||
|
|
517e05c378 | ||
|
|
5759b7e596 | ||
|
|
bfb26f6171 | ||
|
|
f36e2bb4b7 | ||
|
|
b85e455ff5 | ||
|
|
a902400522 | ||
|
|
a6d6474294 | ||
|
|
06859fe36b | ||
|
|
7d7b7c1dc9 | ||
|
|
706d2b51be | ||
|
|
92bf136a8b | ||
|
|
f00f028d8b | ||
|
|
325092efb0 | ||
|
|
aaf8036713 | ||
|
|
c86ee679a9 | ||
|
|
a0fcb63a1a | ||
|
|
55ba255651 | ||
|
|
47df4213c3 | ||
|
|
6929760979 | ||
|
|
720fbd0e6b | ||
|
|
923af4bc83 | ||
|
|
e9c464ba8f | ||
|
|
7b0f616747 | ||
|
|
65788f3c1f | ||
|
|
f55fbf0f64 | ||
|
|
851838e3a2 | ||
|
|
e194f9b205 | ||
|
|
2f8df88ad5 | ||
|
|
55247d9f8a | ||
|
|
48f273b755 | ||
|
|
4fc31cb13f | ||
|
|
a795b82a42 | ||
|
|
1e28a04a7b | ||
|
|
b88eef4591 | ||
|
|
eef5edf775 | ||
|
|
bdb1d605eb | ||
|
|
dfe4b74f3d | ||
|
|
985a3c30de | ||
|
|
1b5125dfed | ||
|
|
da240ce8b9 | ||
|
|
52affb891e | ||
|
|
fac72ca24a | ||
|
|
5cbed502ed | ||
|
|
dce4c60881 | ||
|
|
63bf0315c7 | ||
|
|
8b543c48ee | ||
|
|
087a5326df | ||
|
|
a4545352d8 | ||
|
|
a07dea7ca8 | ||
|
|
c369487e8e | ||
|
|
98590ecec5 | ||
|
|
316f3975ed | ||
|
|
71bf7e0913 | ||
|
|
c7839e2c46 | ||
|
|
89b8bc4148 | ||
|
|
43ad1c05c0 | ||
|
|
1343099be6 | ||
|
|
b895ac69fb | ||
|
|
7d281e2878 | ||
|
|
688450bf5a | ||
|
|
e994133177 | ||
|
|
68713ef9a7 | ||
|
|
dbacbc8874 | ||
|
|
8382299a05 | ||
|
|
93b09cf449 | ||
|
|
dac3311b81 | ||
|
|
5b1ca7a533 | ||
|
|
e940c29110 | ||
|
|
6a704ca0ad | ||
|
|
38c102a64b | ||
|
|
b632c84bb6 | ||
|
|
6bb5ed1d73 | ||
|
|
1052e4c3d2 | ||
|
|
44f776050f | ||
|
|
baa29dbd73 | ||
|
|
1caf391936 | ||
|
|
82caf76e12 | ||
|
|
de27bbf96e | ||
|
|
1199ef40dd | ||
|
|
e7e88f13e3 | ||
|
|
41c22b7840 | ||
|
|
19cc4e8a37 | ||
|
|
7bc1d52bf8 | ||
|
|
fd84ff09e1 | ||
|
|
3dce175f94 | ||
|
|
0aaa3263cf | ||
|
|
c4dcbd8c44 | ||
|
|
ef9cdd8e92 | ||
|
|
09ced50590 | ||
|
|
b2ab1a30a5 | ||
|
|
9eff3916b3 | ||
|
|
98472d1952 | ||
|
|
1ceafb69a5 | ||
|
|
f3f4b6576c | ||
|
|
e699d7dafc | ||
|
|
5eb6d186c0 | ||
|
|
edc9409e56 | ||
|
|
d015719fae | ||
|
|
afc69e447e | ||
|
|
54fbbd734f | ||
|
|
2f657c7c14 | ||
|
|
d29872e69e | ||
|
|
ab9278a9fc | ||
|
|
49769f986a | ||
|
|
b68b895bba | ||
|
|
99fb9972f9 | ||
|
|
f2e7d0fae2 | ||
|
|
77f9e6c411 | ||
|
|
31fcf294e9 | ||
|
|
a03f00ee9a | ||
|
|
80af32bd82 | ||
|
|
b7e4c0fe31 | ||
|
|
76d499596f | ||
|
|
1818344c49 | ||
|
|
7ff2e22f17 | ||
|
|
4eee66b0ef | ||
|
|
19fe7ba6bf | ||
|
|
7b522582fb | ||
|
|
e79c975d7b | ||
|
|
7594e51e2b | ||
|
|
b3f0ff3662 | ||
|
|
8ce304a0c3 | ||
|
|
c85823fe04 | ||
|
|
8f46aec851 | ||
|
|
cd6d1eeab3 | ||
|
|
52b74a74fe | ||
|
|
368f0630c1 | ||
|
|
040bc4c5df | ||
|
|
07906fbea5 | ||
|
|
f893b2b5be | ||
|
|
db868c6df7 | ||
|
|
44f67b7c89 | ||
|
|
6225d8d1f0 | ||
|
|
ed975b459e | ||
|
|
652a6f5c4d | ||
|
|
a7a94099a8 | ||
|
|
71a3cbc334 | ||
|
|
800b2440b3 | ||
|
|
f50a49e7a3 | ||
|
|
92ece4dfb6 | ||
|
|
174225c60e | ||
|
|
3071410a22 | ||
|
|
5c5777ffc5 | ||
|
|
8dd8b93656 | ||
|
|
3b2d455b4a | ||
|
|
b0dfa22903 | ||
|
|
88b1c28d88 | ||
|
|
5b85d7859a | ||
|
|
468eed58d5 | ||
|
|
34c17be474 | ||
|
|
5dedd6b1c1 | ||
|
|
25e8e81686 | ||
|
|
1f7ab03bbb | ||
|
|
86f3cb7288 | ||
|
|
a1b8bf23b4 | ||
|
|
1f21d5ea4c | ||
|
|
f8ff7201d7 | ||
|
|
3567c036c3 | ||
|
|
0cf1f087ad | ||
|
|
209f60727e | ||
|
|
56624fc079 | ||
|
|
218c5243e3 | ||
|
|
560a979e0e | ||
|
|
1debe4c7c8 | ||
|
|
2e2aa77727 | ||
|
|
162ebf6545 | ||
|
|
cf09eff640 | ||
|
|
2d503a0edb | ||
|
|
7f7f0a099a | ||
|
|
109f5d1faa | ||
|
|
38a5d40b64 | ||
|
|
9b55f6fc56 | ||
|
|
83879f5cfe | ||
|
|
083ac5a7e0 | ||
|
|
a7eba377ba | ||
|
|
4ee1e6d9f1 | ||
|
|
24a63c10d0 | ||
|
|
0d805b2d43 | ||
|
|
7bc47fe6d7 | ||
|
|
ae50846257 | ||
|
|
ce466e7715 | ||
|
|
15885545b5 | ||
|
|
29fedcd390 | ||
|
|
fadd6b761f | ||
|
|
d857335901 | ||
|
|
93b4cbfb2c | ||
|
|
625334c6c8 | ||
|
|
943374856e | ||
|
|
e1d7fd92ad | ||
|
|
c10dc74818 | ||
|
|
92d9f2c18d | ||
|
|
d7488b6984 | ||
|
|
88ad3cd724 | ||
|
|
ba9e0b0c12 | ||
|
|
bbe7255901 | ||
|
|
51e55d3e3b | ||
|
|
f704dc0de9 | ||
|
|
e858280f30 | ||
|
|
f9b170204a | ||
|
|
0ed7415a0d | ||
|
|
7a0d50ecca | ||
|
|
19e035aa33 | ||
|
|
830970cb75 | ||
|
|
9b2987d0a2 | ||
|
|
76a4062f8b | ||
|
|
113717f955 | ||
|
|
c40ad58028 | ||
|
|
d6a7efcb7f | ||
|
|
910b89d6ce | ||
|
|
5554dfdd89 | ||
|
|
1657cd50fc | ||
|
|
57bf5e11b5 | ||
|
|
594ca47c85 | ||
|
|
6c5ee14c73 | ||
|
|
8e9d54b44b | ||
|
|
70805665bf | ||
|
|
ac243a706e | ||
|
|
aa382ce80d | ||
|
|
b7da508ccc | ||
|
|
47bd0ca647 | ||
|
|
c5d6c0ce98 | ||
|
|
6017d6b7a9 | ||
|
|
e31e06b288 | ||
|
|
84ac803a7d | ||
|
|
bcb970afb1 | ||
|
|
9d640b57ce | ||
|
|
4c83617847 | ||
|
|
5d7906972b | ||
|
|
666cd4a4f0 | ||
|
|
eb4d39e8b4 | ||
|
|
44ec19122a | ||
|
|
8ba2540b35 | ||
|
|
a1ad89a2e2 | ||
|
|
38108299fa | ||
|
|
189e2679f1 | ||
|
|
22ceb57052 | ||
|
|
0130c7cce6 | ||
|
|
18b6484731 | ||
|
|
f19ff59005 | ||
|
|
8786b5ee2a | ||
|
|
c7e23f9646 | ||
|
|
4043e3f71f | ||
|
|
08887f1147 | ||
|
|
13a0578ab7 | ||
|
|
888bf04ec2 | ||
|
|
d0822041ec | ||
|
|
e65a57bba9 | ||
|
|
2bb1b09789 | ||
|
|
b83dad4e24 | ||
|
|
4bb28f4286 | ||
|
|
721cdf20e7 | ||
|
|
cf248c5cbc | ||
|
|
151ca75e5f | ||
|
|
0e52b7aff4 | ||
|
|
3a0199a1e5 | ||
|
|
50e96095ba | ||
|
|
2f5bce6229 | ||
|
|
06f288ef76 | ||
|
|
ffcad9f1ec | ||
|
|
031dc8a31a | ||
|
|
62f50ce366 | ||
|
|
864c1c9c0d | ||
|
|
cfd433b328 | ||
|
|
ad97338f9b | ||
|
|
5d596f4fd0 | ||
|
|
aa14d79642 | ||
|
|
745d435a57 | ||
|
|
094a7c6a20 | ||
|
|
aedbefc38a | ||
|
|
0cd3cf9e1c | ||
|
|
422efcc89f | ||
|
|
ef24141713 | ||
|
|
820d4ff573 | ||
|
|
c1c0c2e82f | ||
|
|
f024f0ee5d | ||
|
|
a038b34e29 | ||
|
|
4cc516def6 | ||
|
|
bb1095eb78 | ||
|
|
4c11190be9 | ||
|
|
c6790fec70 | ||
|
|
8a7a5eeea1 | ||
|
|
34328c10bf | ||
|
|
c4d503c8d5 | ||
|
|
5fdf5141a5 | ||
|
|
9be00a2693 | ||
|
|
17778f32b9 | ||
|
|
bcbdad99bc | ||
|
|
1e6d2bb6fb | ||
|
|
e9ef122e7f | ||
|
|
57fee3e428 | ||
|
|
4ea45e937a | ||
|
|
dc80d79da0 | ||
|
|
57f68376fe | ||
|
|
f47cfa60c5 | ||
|
|
de78cd014d | ||
|
|
f23348eda2 | ||
|
|
6edfaf3eb6 | ||
|
|
9d02035263 | ||
|
|
8bbcb86bfc | ||
|
|
abdc8672f1 | ||
|
|
333c7457ca | ||
|
|
9b9a354902 | ||
|
|
f48963a6d0 | ||
|
|
83b2ff8ce8 | ||
|
|
b7f514e16b | ||
|
|
5c4c59fe18 | ||
|
|
296ae20cc2 | ||
|
|
7af5e00d71 | ||
|
|
deaf71b4ce | ||
|
|
27f3d85ae2 | ||
|
|
f91a854b3e | ||
|
|
be7b265a00 | ||
|
|
32a17407de | ||
|
|
76340f31d1 | ||
|
|
b2f2d3ac36 | ||
|
|
9bd5b45ea7 | ||
|
|
a17b2029ec | ||
|
|
4c819807de | ||
|
|
175e05aae4 | ||
|
|
fa3e0efd12 | ||
|
|
d08d992768 | ||
|
|
7f0c92e2f0 | ||
|
|
f4ad7aa43d | ||
|
|
40611b4ebe | ||
|
|
1f09a3fa3a | ||
|
|
7d7b88829d | ||
|
|
4078abeb33 | ||
|
|
6f6c3936aa | ||
|
|
6771963686 | ||
|
|
ab409152e3 | ||
|
|
6ce34efb52 | ||
|
|
f92cf9c9e0 | ||
|
|
8b9d5d136e | ||
|
|
3071cfbfb1 | ||
|
|
1a153e1f6e | ||
|
|
b0a7c23055 | ||
|
|
27ca6591ea | ||
|
|
ad3d36e06a | ||
|
|
83e91d361f | ||
|
|
221b4e85bc | ||
|
|
b536bd3e09 | ||
|
|
b73993c375 | ||
|
|
ae392b4014 | ||
|
|
1c34402c87 | ||
|
|
a415e3b0a9 | ||
|
|
e41a33d250 | ||
|
|
587cff9518 | ||
|
|
ea8e850aa9 | ||
|
|
9bb24320bf | ||
|
|
108df3ddbc | ||
|
|
6efb839fd0 | ||
|
|
ca71bb207f | ||
|
|
0800c53aac | ||
|
|
59d89faf38 | ||
|
|
ca3a11de90 | ||
|
|
8f67404766 | ||
|
|
91ece74f57 | ||
|
|
1942850888 | ||
|
|
821cc0940d | ||
|
|
b9f77cb1d6 | ||
|
|
b6d09016cd | ||
|
|
0a07103a4f | ||
|
|
96253f636a | ||
|
|
419a7ab245 | ||
|
|
a29ebfd302 | ||
|
|
73da954355 | ||
|
|
c6ab05979c | ||
|
|
2c8d5d3d5d | ||
|
|
b76a311ddc | ||
|
|
879e6dcab7 | ||
|
|
f9f8a6b357 | ||
|
|
3ea6da3c6d | ||
|
|
bb0b1b3592 | ||
|
|
0b6782d44b | ||
|
|
bd932b1067 | ||
|
|
238aaeb5a0 | ||
|
|
ade277daf4 | ||
|
|
14776fc571 | ||
|
|
c18f489e9d | ||
|
|
bfc1e25335 | ||
|
|
4c2e6088a9 | ||
|
|
ed6f1ad8d1 | ||
|
|
c3ac043c68 | ||
|
|
315bf0d51f | ||
|
|
a90e75ceba | ||
|
|
aa2e63acb0 | ||
|
|
a259d554fa | ||
|
|
4cdbe50eb6 | ||
|
|
f5e035fa3b | ||
|
|
f1d4bd4cd4 | ||
|
|
2a0e0738be | ||
|
|
9e25d0fcc0 | ||
|
|
96ebb67085 | ||
|
|
3fbc5e84e3 | ||
|
|
1fec9781bf | ||
|
|
886c69f298 | ||
|
|
614756c740 | ||
|
|
2a9d1e3fba | ||
|
|
9361a75cd8 | ||
|
|
becc5e316a | ||
|
|
08a1e1ec7d | ||
|
|
12f5f41968 | ||
|
|
58c7774e0d | ||
|
|
da8410842b | ||
|
|
1cae1a5f2f | ||
|
|
df31b214f5 | ||
|
|
25474ce014 | ||
|
|
5f62f038d5 | ||
|
|
eebba45909 | ||
|
|
ead0f0fae1 | ||
|
|
5e2e8c35d5 | ||
|
|
328f2f89a8 | ||
|
|
92b77baf40 | ||
|
|
982e88d1c5 | ||
|
|
632d39bc9f | ||
|
|
f25afb720f | ||
|
|
bc361ea592 | ||
|
|
3d0741f4d2 | ||
|
|
b75459fbc6 | ||
|
|
2202c91564 | ||
|
|
e484813233 | ||
|
|
cd10d38990 | ||
|
|
f817bc5378 | ||
|
|
c30c90d2c3 | ||
|
|
09b638eafa | ||
|
|
91de0c1813 | ||
|
|
a3c953d437 | ||
|
|
743da019f9 | ||
|
|
2c506fcc97 | ||
|
|
dd71df8382 | ||
|
|
8cb21c97e3 | ||
|
|
0ad8ce77ef | ||
|
|
e358ffd666 | ||
|
|
2c984ad405 | ||
|
|
171b0e61ad | ||
|
|
e5047c242c | ||
|
|
496f9a9cd5 | ||
|
|
61025de0d6 | ||
|
|
f08049b960 | ||
|
|
131145e8b8 | ||
|
|
11a0136cb9 | ||
|
|
e92b80bdf4 | ||
|
|
9d81b2312f | ||
|
|
511dbe355a | ||
|
|
cca6d475b3 | ||
|
|
88c6246ceb | ||
|
|
7bf2de6339 | ||
|
|
894d0528df | ||
|
|
168b9ef096 | ||
|
|
711a3881f8 | ||
|
|
399c5c0565 | ||
|
|
6c8005e1b2 | ||
|
|
ca6c1e244c | ||
|
|
449e330992 | ||
|
|
0f0855165e | ||
|
|
746c8f54eb | ||
|
|
ed8457ff36 | ||
|
|
a50bc8e05c | ||
|
|
e382a3bab9 | ||
|
|
9cd50e8ae4 | ||
|
|
1a6836dac6 | ||
|
|
067814d5db | ||
|
|
29d63a0a83 | ||
|
|
8c3ede0d2a | ||
|
|
ee82965ef5 | ||
|
|
ab048508a8 | ||
|
|
47ae271126 | ||
|
|
ef22928e01 | ||
|
|
287584429b | ||
|
|
e23c0c23c9 | ||
|
|
e9bb3195dd | ||
|
|
b1ff94bdd6 | ||
|
|
79eea4814e | ||
|
|
cee0486d71 | ||
|
|
12e990a8b3 | ||
|
|
24fc2888ef | ||
|
|
9b0c940195 | ||
|
|
ce596698e3 | ||
|
|
9383abbdbd | ||
|
|
a31d3185dc | ||
|
|
3098628db1 | ||
|
|
3c53968dd2 | ||
|
|
6c18e3a929 | ||
|
|
99862869bc | ||
|
|
c0368f2a50 | ||
|
|
c6c292b505 | ||
|
|
ebc60c4fb3 | ||
|
|
5f2497de90 | ||
|
|
b2a184bdf0 | ||
|
|
01da51e6e7 | ||
|
|
9fc1efa005 | ||
|
|
8417618615 | ||
|
|
386bdd3490 | ||
|
|
fe3abcaaa8 | ||
|
|
56ba12fe56 | ||
|
|
448eac8ff5 | ||
|
|
5a18d086e0 | ||
|
|
5e52f715ce | ||
|
|
2c2606d6ad | ||
|
|
b3d8df0da0 | ||
|
|
ebea8ef7e5 | ||
|
|
ec645a4bb9 | ||
|
|
2c0474ec46 | ||
|
|
4d09728880 | ||
|
|
173b1e8386 | ||
|
|
9b18a179c2 | ||
|
|
12b38ad8c8 | ||
|
|
4065e15aa1 | ||
|
|
6fda206b9e | ||
|
|
638a6d1195 | ||
|
|
27bc62e602 | ||
|
|
2e7af0affa | ||
|
|
19c41a3cca | ||
|
|
3bf4473f9d | ||
|
|
f92c436339 | ||
|
|
f054a1af03 | ||
|
|
c46eeb0401 | ||
|
|
3ae847d5ad | ||
|
|
d680c5812d | ||
|
|
58bb266085 | ||
|
|
918ace2eb6 | ||
|
|
c8ed30574a | ||
|
|
3120751d3e | ||
|
|
3c623b7ed1 | ||
|
|
150dd3e542 | ||
|
|
8f3f23939c | ||
|
|
5d796efe30 | ||
|
|
1cb5a3531a | ||
|
|
d5cad1a704 | ||
|
|
c9dd7454f5 | ||
|
|
7a7332a3f6 | ||
|
|
a22bfacfa2 | ||
|
|
1abf591459 | ||
|
|
641b21a144 | ||
|
|
20664ff3d3 | ||
|
|
fe733967dc | ||
|
|
0e7a27b2e1 | ||
|
|
d82d11feb7 | ||
|
|
c8cfe473f1 | ||
|
|
ec03bc569c | ||
|
|
1093cb618f | ||
|
|
8c05c774bf | ||
|
|
6af9132721 | ||
|
|
1f443453c7 | ||
|
|
71caefbe70 | ||
|
|
6bb69ea8d3 | ||
|
|
06690e98c7 | ||
|
|
6e858746c1 | ||
|
|
8b94c82889 | ||
|
|
fbe997e6c4 | ||
|
|
491fdaa9bb | ||
|
|
59f5c0cb12 | ||
|
|
b10523ea6c | ||
|
|
2d17ad9a2e | ||
|
|
5502f58637 | ||
|
|
1006cb506f | ||
|
|
d7bc92aa09 | ||
|
|
948a62b482 | ||
|
|
2fbdce26ea | ||
|
|
317f3c3458 | ||
|
|
97cede12b7 | ||
|
|
6da107f4db |
4
.github/ISSUE_TEMPLATE/bug.yml
vendored
4
.github/ISSUE_TEMPLATE/bug.yml
vendored
@@ -26,6 +26,7 @@ body:
|
||||
Examples:
|
||||
- Operating System: Windows 10
|
||||
- Cryptomator: 1.5.16
|
||||
- OneDrive: 23.226
|
||||
- LibreOffice: 7.1.4
|
||||
value: |
|
||||
- Operating System:
|
||||
@@ -43,6 +44,7 @@ body:
|
||||
- WinFsp (Local Drive)
|
||||
- FUSE-T
|
||||
- macFUSE
|
||||
- FUSE
|
||||
- WebDAV (Windows Explorer)
|
||||
- WebDAV (AppleScript)
|
||||
- WebDAV (gio)
|
||||
@@ -95,4 +97,4 @@ body:
|
||||
id: further-info
|
||||
attributes:
|
||||
label: Anything else?
|
||||
description: Links? References? Screenshots? Configurations? Any data that might be necessary to reproduce the issue?
|
||||
description: Links? References? Screenshots? Configurations? Any data that might be necessary to reproduce the issue?
|
||||
|
||||
136
.github/SECURITY.md
vendored
136
.github/SECURITY.md
vendored
@@ -2,123 +2,25 @@
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
For reporting security-related vulnerabilities or exploits that [haven't been reported yet](https://github.com/cryptomator/cryptomator/labels/type%3Asecurity-issue), contact us at: security@cryptomator.org
|
||||
We take security seriously at Cryptomator. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions.
|
||||
|
||||
<details>
|
||||
<summary>PGP Key</summary>
|
||||
To report a security vulnerability, please use the [GitHub Security Advisory feature](https://github.com/cryptomator/cryptomator/security/advisories). This feature allows you to privately discuss, fix, and publish information about security vulnerabilities.
|
||||
|
||||
```
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Comment: GPGTools - https://gpgtools.org
|
||||
If you prefer to report the vulnerability via email, please send an email to security@cryptomator.org.
|
||||
|
||||
mQINBFbgeicBEADM9AcU6DTgM5KZnBaJc6x9DBLr+TCMHntTt7YM9GLTlO2Z43Jt
|
||||
oYoyqdRWAY28veqpLEFgRvvVD3fdBj/KUOxF1cr2JsErwXqbjwaLq0o/0KIXz7UK
|
||||
a6pQSemZKfpOtJrfacofOTwvG6AuG9uakBYNMyxuojyOkoh3xsYS1KZ7TwPgCdET
|
||||
t8/zva41Pa5kh5+GeSZJdCuygG6ynPBJEpmK5V7Qizvics5fziXecF+QaFZijafv
|
||||
YahfxokvF9pXCQTmV4m57NQma9uK0w83U9nJCPjEd+x3wK0Hxrc1ojy8ZFTA1YND
|
||||
AQg/MTABgHbQQkXDQhjS/TloOObqtbMBqNSbcSXpaR4teaCWKBl1MSq00nJLj8db
|
||||
vPJGqfg7UbXhlALggp029/kskYlR5SmbxWquLbl0Xre3fDHuHEiWcJL6MS3454Wt
|
||||
Mno13/4UhOlRFh5g0pLmPz7seOTJjDqc9abn/RXOLq0+3qX0gC0bDm5aCE5dQ2MV
|
||||
FMbrrlw/dZESNLZvtB3gOsramSry1R3HVZ0QJ2vMaF2cxewebqcYbuecUNj6bxpv
|
||||
5LEhEmqz6dG1meLLWDsvQLPEUWEIJnfpBiDSm342yxJq4pXnVF+aqAQsCL3FpmvZ
|
||||
2j0FgFOs7iXOcFUJIiR0xUmWPk1NWYcUowqmRW8pMM9nFUzFF99iggPznwARAQAB
|
||||
tC1DcnlwdG9tYXRvciBTdXBwb3J0IDxzdXBwb3J0QGNyeXB0b21hdG9yLm9yZz6J
|
||||
AkAEEwEKACoCGwMFCQcrKAAFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AFAleu2cQC
|
||||
GQEACgkQI7Xb75TU2B3+7A/7BKRWdo5/moCCEbBzYQ7vRMLFdwmjFFlSZ7aGC0fP
|
||||
YHdeUwxPbO0cATwmNpGMma7rBn1FDg3Vto6/wottGxm+XIRwlyY84CD1VZAihZ/e
|
||||
WvjOO28/7VgRy6PGKzlhpDSoT8GwFOgO69e7bEff1Zj562RZe7nXc4tDivILMB++
|
||||
KgmmSgtddygmNQCS3RD3KssGo+l+cSjsg09F5WAJ6nQe8Jq2hICq+o/P6UXPI5lX
|
||||
bhvWYDn4/8sRHsIlGpQYYDDe0fz7IQKuSLAHpF5upNDxj6dYb05F8PPVrk6MW6nL
|
||||
/kf1fZ27DlLN5/NFvhhBRuwxxoAFqPS7Iel3z7L0JkRUYmGLVB5m9Cqiw6FK8JRv
|
||||
OtvakdDoKb5lVAoN5NeBfNBSqEcXVF/EdfTfIyyo7hZRA6xFMEVbmYbzt0sj0djV
|
||||
ZOey2TOFrTCpkHfUUDgKvk5sn+F3u8mmPIbqquEzlFJSFjcyiYYDv22rg1In+zKV
|
||||
Xmw4BFZRDS6IVSQRGlskRGJBixCaGyDYxHXXT2cg4Rk9uiCX11+0E9qlAsg6xPe6
|
||||
rnaYDT8dU0AFyVpDpshflXH3kVQSpiqZS3jkAk1/54ODO8pE80Zrnd5m5AMuNcmX
|
||||
+9MkZKE+h0882UskDs1dyt26GU2hoy4lAeRUaut7zIK/WO6nnuLaTvGWT95RDz+q
|
||||
kD2JAiIEEwEKAAwFAleu2iYFgweGH4AACgkQZnuGbqgkCgnmCA//U22uhyEC/Tp3
|
||||
Cbt5lctQmqbgMbjRBaHQyW52tPFMaq8vXMbo/5TTtVC6xsp2PJT84cxAd8KX8hWq
|
||||
cPtF4wWCJGng/AzyxQ5dWfGvA/ll32ygjtJN3P/AvA9KlhG+6XYmS8cPkBkJBi6B
|
||||
2yCdZT1cXc/TPAFzjgAwz7K9g3awG0OeOc/CXymH0DD/snkiwKQoucStolYywZGc
|
||||
GszjMQgeT4zOc1wtEz24uL3dMNDlDcQMAh56YvK2oB0iMYmAFyX/IS+f2bM9paXi
|
||||
HX+mg/z53iwgf5ZXbslNDbMTJ5GNksjEGjCFfDHAdNdgT+lcW4l2U7q4PYUaN4LA
|
||||
DE9j2OlOlQ9qjucOgoCStirnTP7XHd4p31lgdz8+THOQowB5Ji95OkiNQAFCfxBt
|
||||
mcA/bWnJZQDm7L8RVzHovBpAaK6vUjxEvR+DXdESSzyZwkpsZwGZcyqGRT26R1/L
|
||||
JE5WvjKufNc5v3Cat320MjyrLZwVGRgvEpDMoCw3nTWl9AtOj5vgaakEWr7AnqET
|
||||
xk7UFbYmdTlQqkWuLKubz9Rx/FbrBmvd6vwTHy1Dfl6QyMWNCClatgN00Hxped/6
|
||||
CErg+R/RXd8apGxnOuWDqoujPn5LOHzgJolp1Ox16nTiZe2G+LbDr3hqRFi1wW6w
|
||||
ioMB4KpkdA03uyxJSWmDEMiR1l3Oxom0KUNyeXB0b21hdG9yIFByZXNzIDxwcmVz
|
||||
c0BjcnlwdG9tYXRvci5vcmc+iQI9BBMBCgAnBQJXrtnDAhsDBQkHKygABQsJCAcD
|
||||
BRUKCQgLBRYCAwEAAh4BAheAAAoJECO12++U1NgdQYMQAKCIzNJF8rURQcFLSv3J
|
||||
sPBjRy2HCzCWm21MuhU+bsaZx7U9M9dgEjzLfxN9s19VsBH3WKLgok2FgiYSGka3
|
||||
6Oy/P8VFLFmHs7dS9i2fro2eF7i4zj/ZD/9t0jM4ZIgLpbzr5sTBld292nsfXGob
|
||||
xOJeOx3oWYyR2FO9VQxXjC3JvJyZkFgoy0tauS4Mvii4cF56wJGcxDTbe1s7UaRC
|
||||
a/fh4zgISZSBE3rYhCawkN4mqMDM5RDjrdtjKUPWk345HcjjQ4Wos8xw4YbGbNr9
|
||||
Pc7m2URYJJ0jFM4tnoRF6cmA3bT9tm8pcOFg+K/ycVrltVEy+A8Wj8UGjyP1uI1t
|
||||
EqWHN3LZpIGfW0w9AGrw7OUI9czXcukfngj/DsOU3WMBDIM8pW9+zBpr75yIS6lz
|
||||
C0IqksLXSqX0b/Rby4O+wb6UZ1ZFkaim2GGtAZV+nGXtdnEXSNFiP7ykzjZ02m/1
|
||||
7CKyj3VmdAgT56zEIypFSfxm9gOWsJPmfhSyuE8bFyoitgNxpheZk6xZy4upVMPR
|
||||
WK3hutScU0yDv2HVCiA3o3Ggy42nmz9HpGF6W2DmBx4bhMaVs6I2VFyKdQzmJD/3
|
||||
FCWjwz8PiEgVGHGPnD+WdPFLhrc/44gF4h/VuLjkubtULGuTVvgjeTIJ5LR1Gmwc
|
||||
YOk6eD7MAJPzJVj5/PYFtIbKiQIiBBMBCgAMBQJXrtonBYMHhh+AAAoJEGZ7hm6o
|
||||
JAoJBh4P/1w88YMTKUHpFTfJEwH2hK36BZN96Bf/k+vP7n1Xxp3NheInJblHFOt/
|
||||
ccsup6am+APrk8gGtlIVmtVc3nO8WMsWxfJxGDecyRsNbessnODv/llyg3tzVU/H
|
||||
tLk7gLiK0TcIsOLfeNXGTxRRSKWjVFsNfuixNCzzHa7tFq6ddVn9VRZ8fqJB2p21
|
||||
OogWSDqUo9q9Wfb4RkYHguDx+8Jzoo/MxR1TSt8gUO2xDvEbqgeQiMCLF8R0lO3Y
|
||||
zz0FrpyOsFU1CxVp+wo55bWv1UdwgQKQt4o0m5/zDJ2RAtscXpd4YcTE+XxKeK+4
|
||||
qhihhkhLGpKsxzK5m9/qwMbodHwoBCBzfalkUR9xOq9yQIeEoC8XYL62NqB3BCSU
|
||||
KfWFIHxUkE9WH5zHWaV+bhrlNgk7nz3xBfPf1P2mNIc1VUHoNqOZOmWwz2VaKLSW
|
||||
f3GIqx9wGythFbLdXmUoC3W//DDYgQnvImvkncMqQ5nRHPf8uHcLQK5WZyIxpgWT
|
||||
eKon5G/cj0BTptcBhapMwSIyfaC5FV7so0/CkOA6R9Fyq2VpGoHy7XPhFS+6ieLi
|
||||
KUWhCvbuf2deWbSaJ0peMdzy1p72UXwrsEM0M3Fz+Jd8zvCaFzf5Fx27+pAAdlfg
|
||||
4bT3/2gSf7S+cU3+DnYOH0NeRt2Z2mjEKg9OwttTO/oDboQHdZlrtDRDcnlwdG9t
|
||||
YXRvciBTZWN1cml0eS1UZWFtIDxzZWN1cml0eUBjcnlwdG9tYXRvci5vcmc+iQI9
|
||||
BBMBCgAnBQJXrtnWAhsDBQkHKygABQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAAAoJ
|
||||
ECO12++U1NgddzoQAI78+Nvm6VvNuptXJjEmrpHRyKCnHF9wH5kxvF8WZCgpOkJ4
|
||||
vONmyS+9ZlepnT83MpGm/MzdIMCnDJmDmqmA5ISBRcD7k9Gjzz5rPKwE2zDyo0M0
|
||||
wF1L2UEUqAlcvE0e4twZcP2DGoNqdSf6IaWsXhQMb1a/rTMsoGZLuTB8kCbv6Ntl
|
||||
ULahcRToTB2shsbZjzE896P6X5hDCfGWl0Jhcbf53pnXX1dOsEw3et9AGru1IUMs
|
||||
UGM+wpgTwagRj+XB/WY1x9IznKtiHTq83Fvt+3bkg0+NIcV3GDqXDIUtqIwy8gDd
|
||||
4KgBU+LkyxXFDa4OxLc53n6b+Iy1nDosM+SiqSzdCCgEs/dY1tQBn/7P1GT18dEe
|
||||
tFgeH/c6wLvEpDIc9urAsYXf8H+1uy7glWpWTq8DE0yhCr4adjCqlIsVHQQO4UUW
|
||||
NfqMGEFpJ+3HjSSwnvDGY78lLQh5d4vqWV435aNaMqZg0gJIA0FtiP1fRtmT73BG
|
||||
N/tBNiBxretFR4B+x/TWqPd5iJV7/MAn/pa1WSOcaxzJrVUsjXdgLQCqcHWd4/w1
|
||||
f4DU9cJjl3sxZlMdAlg8Q1bF+pmjQQ4WKZkqMtwpoUilfVXmL42ay1LBCgW68/uJ
|
||||
OTyGfp8ntUsbbm5raGsny3TLqnacyG9hxcPGNTzD1+MrbUvfsc7+4U0dCZTuiQIi
|
||||
BBMBCgAMBQJXrtonBYMHhh+AAAoJEGZ7hm6oJAoJ1DQP/R+1drZiZQU45ChMbfTb
|
||||
XQjJRsUOGZp3PTWtx4KrVFvE8ea0PF+DZX5gLJYIU+iZmPXRpzFu6dKPbcZ7RfRt
|
||||
5RRH102zDZzijt2CQd7YLO8wxUFoWX9X7DGgxXEcNjl9kFVmnyHgiTwTzuZ0Zy4y
|
||||
PvoiwrhcZmXEYbOeV40gLFie6wuzz5IIcs01e30xIs+1/1gwmgI5UnG3jveUgmcj
|
||||
f/lvg3POKiwrY5Uzw1FSruJx21X06wTpDcfOACID4L7aY9eg2B/qL2Xj8nuhejqG
|
||||
+1AVTMk2o6pxkvevHmxYQfEpuWGCw0RCBn9ObWwz6Zn5J9pjGbMrM+b1/M2Ouv3N
|
||||
cpoGgCSahKNsRMKO7RMrBG0jtLcasPSgZFYPJSZAAb+YhxKUbpPHzDIwTEjgM7CL
|
||||
gKSyRTKyp5IoFK53bpXL/ZIjkAhMvyDult6+BL6vI0+h3BBA9I0FF2Qhe139xLv/
|
||||
DS7aDiYAE9vGMGoeCBfxJPwUsDU3hrGe/wgL7fR6nmN7R2QffisBHKHsklORy9t3
|
||||
w3YFRd5sBAxv+EOcdkgXEmqKOfVQ8KU9adQcxPDGMAK/esjVwxUxsaf2PF5noxxW
|
||||
3zL2ureUO/mMoH5Cwr0BuM3HFb82t1JJd4IXlLEyNvDMFMwD2d7h37bGK7Y5hEsl
|
||||
zL7Dm+wQRY8sxg4QOZHbJjQXuQINBFbgeicBEADnkxGSEL1zwACaiVqADKC6/pgO
|
||||
MMWjxoENBT6r8Vnp1D5hfNDkEi9iXUpCEO6nzywBf3/4c4Yk1wBOBZ7YWyWXMf4v
|
||||
2g1evxELO5z1UlAwna6HSl7G0omIBqzz1Er5IS7C9WEZM8ZggwcuswCrbxfz4+fN
|
||||
t7cCL5QyOvuxez+vrn+VIgLQzKm+LV4Wc+OFbHIys+0saQUhItKO0/CsXGc8R314
|
||||
jdN5UsZk/MUdPPAs+6OCr8d3PpJvR6IST76TtN8aDjSS9T6em7dwdGFEwCGww3Jc
|
||||
xrAkvvUmSlscz+rnvHA5DYQGK6NXLenB40sVQVfch1r1VqwvlzA0u7OovjwM8+7u
|
||||
+DaBQ0YejbdnC7yfeE91LmZkG6jRKfvTJkv18tjNsgZsVmM13xzP67fCFIB9M+lN
|
||||
t9zEldGKHVwm+06FHIWJsBDRgrquNb9xd1vgHHeIbJvKf+LqZhVrbKVEneG34Km+
|
||||
ndtb+mvcGc0fOoMU9lYrFaxAWl8oU9BchC9IyjcPZB445R+AhfTuoHSUViSCo6IO
|
||||
TG0hQsJuNoKmDAU8l5sTsiFXuXBOo1wK8gTkRnhZHduZrZIjJXvT7efz1knLQ6eG
|
||||
prZHf4CtbgHyAe2XZabetWtCsFcPbOjC7ezNK57UvVH98h2GkckxOM00BESMCTee
|
||||
kYy7uG0v0rrajzHY1wARAQABiQIlBBgBCgAPBQJW4HonAhsMBQkHKygAAAoJECO1
|
||||
2++U1NgdyAsQAKZUVA6pY225BASkeNiW31L7K4VeRYpAdFkiRex2zQFtj9Vovfi1
|
||||
JeTs0fRm35dUsQraf1bkhsjEdPVZ3gD324/baauFO04KX+soyQvK/tUq8KO+5ALt
|
||||
Ul5aAljuSwxfJWFpApv+Mbf7gOjm+77jirs7pgG/gCow/mkRlmKTwAmn2DXjkckC
|
||||
2EH0mqmh5pdoNWKO7WeTFFbUmESsPcnB2FwTpEjHFvgHll+rmKpXZTgFYN4dDhhm
|
||||
HsL/SCf/Nw+YIsuvErQ9TJVdJDLG8ZYatruk7dZZMPtFxvxM1Q36gDIpPEOKPkvm
|
||||
dMXg6jHaIdYIaoMpzXFaXsQMdRuMtzbcA+CdwXVY55qGLtfmM/QuEiIJdDeeh7iB
|
||||
+VAMyEFOOpi8IFhixaeMoZAmrKDqOkzPcMJVklLYq8N+b9p5JszYNwZEbpyWCACM
|
||||
6K+iJzlWzW/OPZttGLJBgYuSYIJIuG80Cx5m5m1e5RAgQ1iT8nbfrS+gYttwP48J
|
||||
V7SXQg7QugxG9l1vlK4VjnXiOFulJ7V0e/VyUBpJp3qHcCxFq3RnxVwlIqKZh+jm
|
||||
Q1bk0H0Xodd27nQITfDP5ullByGW2Jrjs6SsXeR3jl9+t0XQfInU1L9d/wSOkMjL
|
||||
9IMUt06lV4vB/WP2xioqLZiZ4eAi0E+lWkFxjZsgNs2xbOAYRThMB8a5
|
||||
=W1Ri
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
```
|
||||
</details>
|
||||
PGP key fingerprint: `3647 9903 B23A E0A5 9359 9A3E 23B5 DBEF 94D4 D81D` ([public key](https://gist.github.com/cryptobot/864300b6b44ae2d2a15abedfe14bd040))
|
||||
|
||||
## Expectations
|
||||
|
||||
When reporting a vulnerability, please provide us with a detailed report that includes:
|
||||
|
||||
- A description of the vulnerability
|
||||
- Steps to reproduce the vulnerability
|
||||
- Possible impact of the vulnerability
|
||||
- Any additional information that may be helpful
|
||||
|
||||
We ask that you do not publicly disclose the vulnerability until we have had a chance to address it.
|
||||
|
||||
## Thank You
|
||||
|
||||
We appreciate your help in keeping Cryptomator secure. Thank you for your contributions to the security of our project.
|
||||
|
||||
51
.github/dependabot.yml
vendored
Normal file
51
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "maven"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "monday"
|
||||
time: "06:00"
|
||||
timezone: "Etc/UTC"
|
||||
groups:
|
||||
java-test-dependencies:
|
||||
patterns:
|
||||
- "org.junit.jupiter:*"
|
||||
- "org.mockito:*"
|
||||
- "org.hamcrest:*"
|
||||
- "com.google.jimfs:jimfs"
|
||||
maven-build-plugins:
|
||||
patterns:
|
||||
- "org.apache.maven.plugins:*"
|
||||
- "org.jacoco:jacoco-maven-plugin"
|
||||
- "org.owasp:dependency-check-maven"
|
||||
- "me.fabriciorby:maven-surefire-junit5-tree-reporter"
|
||||
- "org.codehaus.mojo:license-maven-plugin"
|
||||
javafx:
|
||||
patterns:
|
||||
- "org.openjfx:*"
|
||||
java-production-dependencies:
|
||||
patterns:
|
||||
- "*"
|
||||
exclude-patterns:
|
||||
- "org.openjfx:*"
|
||||
- "org.apache.maven.plugins:*"
|
||||
- "org.jacoco:jacoco-maven-plugin"
|
||||
- "org.owasp:dependency-check-maven"
|
||||
- "me.fabriciorby:maven-surefire-junit5-tree-reporter"
|
||||
- "org.codehaus.mojo:license-maven-plugin"
|
||||
- "org.junit.jupiter:*"
|
||||
- "org.mockito:*"
|
||||
- "org.hamcrest:*"
|
||||
- "com.google.jimfs:jimfs"
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/" # even for `.github/workflows`
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
groups:
|
||||
github-actions:
|
||||
patterns:
|
||||
- "*"
|
||||
labels:
|
||||
- "misc:ci"
|
||||
100
.github/workflows/appimage.yml
vendored
100
.github/workflows/appimage.yml
vendored
@@ -10,7 +10,8 @@ on:
|
||||
required: false
|
||||
|
||||
env:
|
||||
JAVA_VERSION: 20
|
||||
JAVA_DIST: 'zulu'
|
||||
JAVA_VERSION: '21.0.2+13'
|
||||
|
||||
jobs:
|
||||
get-version:
|
||||
@@ -20,52 +21,71 @@ jobs:
|
||||
|
||||
build:
|
||||
name: Build AppImage
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs: [get-version]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
appimage-suffix: x86_64
|
||||
openjfx-url: 'https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_linux-x64_bin-jmods.zip'
|
||||
openjfx-sha: '7baed11ca56d5fee85995fa6612d4299f1e8b7337287228f7f12fd50407c56f8'
|
||||
- os: [self-hosted, Linux, ARM64]
|
||||
appimage-suffix: aarch64
|
||||
openjfx-url: 'https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_linux-aarch64_bin-jmods.zip'
|
||||
openjfx-sha: '871e7b9d7af16aef2e55c1b7830d0e0b2503b13dd8641374ba7e55ecb81d2ef9'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v3
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
distribution: ${{ env.JAVA_DIST }}
|
||||
java-version: ${{ env.JAVA_VERSION }}
|
||||
java-package: 'jdk+fx'
|
||||
check-latest: true
|
||||
cache: 'maven'
|
||||
- name: Ensure major jfx version in pom equals in jdk
|
||||
shell: pwsh
|
||||
|
||||
- name: Download OpenJFX jmods
|
||||
id: download-jmods
|
||||
run: |
|
||||
$jfxPomVersion = (&mvn help:evaluate "-Dexpression=javafx.version" -q -DforceStdout) -split "\."
|
||||
$jfxJdkVersion = ((Get-Content -path "${env:JAVA_HOME}/lib/javafx.properties" | Where-Object {$_ -like 'javafx.version=*' }) -replace '.*=','') -split "\."
|
||||
if ($jfxPomVersion[0] -ne $jfxJdkVersion[0]) {
|
||||
Write-Error "Major part of JavaFX version in pom($($jfxPomVersion[0])) does not match the version in JDK($($jfxJdkVersion[0])) "
|
||||
curl -L ${{ matrix.openjfx-url }} -o openjfx-jmods.zip
|
||||
echo "${{ matrix.openjfx-sha }} openjfx-jmods.zip" | shasum -a256 --check
|
||||
mkdir -p openjfx-jmods
|
||||
unzip -j openjfx-jmods.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d openjfx-jmods
|
||||
- name: Ensure major jfx version in pom and in jmods is the same
|
||||
run: |
|
||||
JMOD_VERSION=$(jmod describe openjfx-jmods/javafx.base.jmod | head -1)
|
||||
JMOD_VERSION=${JMOD_VERSION#*@}
|
||||
JMOD_VERSION=${JMOD_VERSION%%.*}
|
||||
POM_JFX_VERSION=$(mvn help:evaluate "-Dexpression=javafx.version" -q -DforceStdout)
|
||||
POM_JFX_VERSION=${POM_JFX_VERSION#*@}
|
||||
POM_JFX_VERSION=${POM_JFX_VERSION%%.*}
|
||||
|
||||
if [ $POM_JFX_VERSION -ne $JMOD_VERSION_AMD64 ]; then
|
||||
>&2 echo "Major JavaFX version in pom.xml (${POM_JFX_VERSION}) != amd64 jmod version (${JMOD_VERSION})"
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
- name: Set version
|
||||
run : mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }}
|
||||
- name: Run maven
|
||||
run: mvn -B clean package -Pdependency-check,linux -DskipTests
|
||||
run: mvn -B clean package -Plinux -DskipTests
|
||||
- name: Patch target dir
|
||||
run: |
|
||||
cp LICENSE.txt target
|
||||
cp target/cryptomator-*.jar target/mods
|
||||
- name: Run jlink
|
||||
#Remark: no compression is applied for improved build compression later (here appimage)
|
||||
run: >
|
||||
${JAVA_HOME}/bin/jlink
|
||||
--verbose
|
||||
--output runtime
|
||||
--module-path "${JAVA_HOME}/jmods"
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.security.auth,jdk.accessibility,jdk.management.jfr
|
||||
--module-path "${JAVA_HOME}/jmods:openjfx-jmods"
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.security.auth,jdk.accessibility,jdk.management.jfr,jdk.net
|
||||
--strip-native-commands
|
||||
--no-header-files
|
||||
--no-man-pages
|
||||
--strip-debug
|
||||
--compress=1
|
||||
- name: Prepare additional launcher
|
||||
run: envsubst '${SEMVER_STR} ${REVISION_NUM}' < dist/linux/launcher-gtk2.properties > launcher-gtk2.properties
|
||||
env:
|
||||
SEMVER_STR: ${{ needs.get-version.outputs.semVerStr }}
|
||||
REVISION_NUM: ${{ needs.get-version.outputs.revNum }}
|
||||
--compress zip-0
|
||||
- name: Run jpackage
|
||||
run: >
|
||||
${JAVA_HOME}/bin/jpackage
|
||||
@@ -78,21 +98,23 @@ jobs:
|
||||
--dest appdir
|
||||
--name Cryptomator
|
||||
--vendor "Skymatic GmbH"
|
||||
--copyright "(C) 2016 - 2023 Skymatic GmbH"
|
||||
--copyright "(C) 2016 - 2024 Skymatic GmbH"
|
||||
--app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}"
|
||||
--java-options "--enable-preview"
|
||||
--java-options "--enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64"
|
||||
--java-options "--enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator"
|
||||
--java-options "-Xss5m"
|
||||
--java-options "-Xmx256m"
|
||||
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
|
||||
--java-options "-Dfile.encoding=\"utf-8\""
|
||||
--java-options "-Dcryptomator.logDir=\"~/.local/share/Cryptomator/logs\""
|
||||
--java-options "-Dcryptomator.pluginDir=\"~/.local/share/Cryptomator/plugins\""
|
||||
--java-options "-Dcryptomator.settingsPath=\"~/.config/Cryptomator/settings.json:~/.Cryptomator/settings.json\""
|
||||
--java-options "-Dcryptomator.p12Path=\"~/.config/Cryptomator/key.p12\""
|
||||
--java-options "-Dcryptomator.ipcSocketPath=\"~/.config/Cryptomator/ipc.socket\""
|
||||
--java-options "-Dcryptomator.mountPointsDir=\"~/.local/share/Cryptomator/mnt\""
|
||||
--java-options "-Dcryptomator.showTrayIcon=false"
|
||||
--java-options "-Djava.net.useSystemProxies=true"
|
||||
--java-options "-Dcryptomator.logDir=\"@{userhome}/.local/share/Cryptomator/logs\""
|
||||
--java-options "-Dcryptomator.pluginDir=\"@{userhome}/.local/share/Cryptomator/plugins\""
|
||||
--java-options "-Dcryptomator.settingsPath=\"@{userhome}/.config/Cryptomator/settings.json:@{userhome}/.Cryptomator/settings.json\""
|
||||
--java-options "-Dcryptomator.p12Path=\"@{userhome}/.config/Cryptomator/key.p12\""
|
||||
--java-options "-Dcryptomator.ipcSocketPath=\"@{userhome}/.config/Cryptomator/ipc.socket\""
|
||||
--java-options "-Dcryptomator.mountPointsDir=\"@{userhome}/.local/share/Cryptomator/mnt\""
|
||||
--java-options "-Dcryptomator.showTrayIcon=true"
|
||||
--java-options "-Dcryptomator.integrationsLinux.trayIconsDir=\"@{appdir}/usr/share/icons/hicolor/symbolic/apps\""
|
||||
--java-options "-Dcryptomator.buildNumber=\"appimage-${{ needs.get-version.outputs.revNum }}\""
|
||||
--add-launcher Cryptomator-gtk2=launcher-gtk2.properties
|
||||
--resource-dir dist/linux/resources
|
||||
@@ -103,6 +125,10 @@ jobs:
|
||||
cp dist/linux/common/org.cryptomator.Cryptomator256.png Cryptomator.AppDir/usr/share/icons/hicolor/256x256/apps/org.cryptomator.Cryptomator.png
|
||||
cp dist/linux/common/org.cryptomator.Cryptomator512.png Cryptomator.AppDir/usr/share/icons/hicolor/512x512/apps/org.cryptomator.Cryptomator.png
|
||||
cp dist/linux/common/org.cryptomator.Cryptomator.svg Cryptomator.AppDir/usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg
|
||||
cp dist/linux/common/org.cryptomator.Cryptomator.tray.svg Cryptomator.AppDir/usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.tray.svg
|
||||
cp dist/linux/common/org.cryptomator.Cryptomator.tray-unlocked.svg Cryptomator.AppDir/usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.tray-unlocked.svg
|
||||
cp dist/linux/common/org.cryptomator.Cryptomator.tray.svg Cryptomator.AppDir/usr/share/icons/hicolor/symbolic/apps/org.cryptomator.Cryptomator.tray-symbolic.svg
|
||||
cp dist/linux/common/org.cryptomator.Cryptomator.tray-unlocked.svg Cryptomator.AppDir/usr/share/icons/hicolor/symbolic/apps/org.cryptomator.Cryptomator.tray-unlocked-symbolic.svg
|
||||
cp dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml Cryptomator.AppDir/usr/share/metainfo/org.cryptomator.Cryptomator.metainfo.xml
|
||||
cp dist/linux/common/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/usr/share/applications/org.cryptomator.Cryptomator.desktop
|
||||
cp dist/linux/common/application-vnd.cryptomator.vault.xml Cryptomator.AppDir/usr/share/mime/packages/application-vnd.cryptomator.vault.xml
|
||||
@@ -113,7 +139,7 @@ jobs:
|
||||
ln -s bin/cryptomator.sh Cryptomator.AppDir/AppRun
|
||||
- name: Download AppImageKit
|
||||
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-${{ matrix.appimage-suffix }}.AppImage -o appimagetool.AppImage
|
||||
chmod +x appimagetool.AppImage
|
||||
./appimagetool.AppImage --appimage-extract
|
||||
- name: Prepare GPG-Agent for signing with key 615D449FE6E6A235
|
||||
@@ -125,24 +151,24 @@ jobs:
|
||||
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
|
||||
- name: Build AppImage
|
||||
run: >
|
||||
./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'
|
||||
./squashfs-root/AppRun Cryptomator.AppDir cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.appimage-suffix }}.AppImage
|
||||
-u 'gh-releases-zsync|cryptomator|cryptomator|latest|cryptomator-*-${{ matrix.appimage-suffix }}.AppImage.zsync'
|
||||
--sign --sign-key=615D449FE6E6A235 --sign-args="--batch --pinentry-mode loopback"
|
||||
- name: Create detached GPG signatures
|
||||
run: |
|
||||
gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator-*.AppImage
|
||||
gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator-*.AppImage.zsync
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: appimage
|
||||
name: appimage-${{ matrix.appimage-suffix }}
|
||||
path: |
|
||||
cryptomator-*.AppImage
|
||||
cryptomator-*.AppImage.zsync
|
||||
cryptomator-*.asc
|
||||
if-no-files-found: error
|
||||
- name: Publish AppImage on GitHub Releases
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published'
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
fail_on_unmatched_files: true
|
||||
|
||||
13
.github/workflows/build.yml
vendored
13
.github/workflows/build.yml
vendored
@@ -6,7 +6,8 @@ on:
|
||||
types: [labeled]
|
||||
|
||||
env:
|
||||
JAVA_VERSION: 20
|
||||
JAVA_DIST: 'zulu'
|
||||
JAVA_VERSION: 21
|
||||
|
||||
defaults:
|
||||
run:
|
||||
@@ -17,14 +18,14 @@ jobs:
|
||||
name: Compile and Test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-java@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
distribution: ${{ env.JAVA_DIST }}
|
||||
java-version: ${{ env.JAVA_VERSION }}
|
||||
cache: 'maven'
|
||||
- name: Cache SonarCloud packages
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.sonar/cache
|
||||
key: ${{ runner.os }}-sonar
|
||||
@@ -35,7 +36,7 @@ jobs:
|
||||
mvn -B verify
|
||||
jacoco:report
|
||||
org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
|
||||
-Pcoverage,dependency-check
|
||||
-Pcoverage
|
||||
-Dsonar.projectKey=cryptomator_cryptomator
|
||||
-Dsonar.organization=cryptomator
|
||||
-Dsonar.host.url=https://sonarcloud.io
|
||||
|
||||
64
.github/workflows/check-jdk-updates.yml
vendored
Normal file
64
.github/workflows/check-jdk-updates.yml
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
name: Checks JDK version for minor updates
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 1 * *' # run once a month at the first day of month
|
||||
|
||||
env:
|
||||
JDK_VERSION: '21.0.1+12'
|
||||
JDK_VENDOR: zulu
|
||||
|
||||
jobs:
|
||||
jdk-current:
|
||||
name: Check out current version
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
jdk-date: ${{ steps.get-data.outputs.jdk-date}}
|
||||
steps:
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: ${{ env.JDK_VERSION }}
|
||||
distribution: ${{ env.JDK_VENDOR }}
|
||||
check-latest: false
|
||||
- name: Read JAVA_VERSION_DATE and store in env variable
|
||||
id: get-data
|
||||
run: |
|
||||
date=$(cat ${JAVA_HOME}/release | grep "JAVA_VERSION_DATE=\"" | awk -F'=' '{print $2}' | tr -d '"')
|
||||
echo "jdk-date=${date}" >> "$GITHUB_OUTPUT"
|
||||
jdk-latest:
|
||||
name: Checkout latest jdk version
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
jdk-date: ${{ steps.get-data.outputs.jdk-date}}
|
||||
jdk-version: ${{ steps.get-data.outputs.jdk-version}}
|
||||
steps:
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 21
|
||||
distribution: ${{ env.JDK_VENDOR }}
|
||||
check-latest: true
|
||||
- name: Read JAVA_VERSION_DATE and store in env variable
|
||||
id: get-data
|
||||
run: |
|
||||
date=$(cat ${JAVA_HOME}/release | grep "JAVA_VERSION_DATE=\"" | awk -F'=' '{print $2}' | tr -d '"')
|
||||
echo "jdk-date=${date}" >> "$GITHUB_OUTPUT"
|
||||
version=$(cat ${JAVA_HOME}/release | grep "JAVA_RUNTIME_VERSION=\"" | awk -F'=' '{print $2}' | tr -d '"')
|
||||
echo "jdk-version=${version}" >> "$GITHUB_OUTPUT"
|
||||
notify:
|
||||
name: Notifies for jdk update
|
||||
runs-on: ubuntu-latest
|
||||
needs: [jdk-current, jdk-latest]
|
||||
if: ${{ needs.jdk-latest.outputs.jdk-date }} > ${{ needs.jdk-current.outputs.jdk-date }}
|
||||
steps:
|
||||
- name: Slack Notification
|
||||
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: "JDK update available"
|
||||
SLACK_MESSAGE: "Cryptomator-CI JDK can be upgraded to ${{ needs.jdk-latest.outputs.jdk-version }}. See https://github.com/cryptomator/cryptomator/wiki/How-to-update-the-build-JDK for instructions."
|
||||
SLACK_FOOTER: false
|
||||
MSG_MINIMAL: true
|
||||
44
.github/workflows/debian.yml
vendored
44
.github/workflows/debian.yml
vendored
@@ -3,9 +3,6 @@ name: Build Debian Package
|
||||
on:
|
||||
workflow_dispatch:
|
||||
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
|
||||
@@ -19,19 +16,21 @@ on:
|
||||
type: boolean
|
||||
|
||||
env:
|
||||
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'
|
||||
JAVA_DIST: 'zulu'
|
||||
JAVA_VERSION: '21.0.2+13'
|
||||
COFFEELIBS_JDK: 21
|
||||
COFFEELIBS_JDK_VERSION: '21.0.2+13-0ppa1'
|
||||
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_linux-x64_bin-jmods.zip'
|
||||
OPENJFX_JMODS_AMD64_HASH: '7baed11ca56d5fee85995fa6612d4299f1e8b7337287228f7f12fd50407c56f8'
|
||||
OPENJFX_JMODS_AARCH64: 'https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_linux-aarch64_bin-jmods.zip'
|
||||
OPENJFX_JMODS_AARCH64_HASH: '871e7b9d7af16aef2e55c1b7830d0e0b2503b13dd8641374ba7e55ecb81d2ef9'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build Debian Package
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ inputs.ref }}
|
||||
fetch-depth: 0
|
||||
- uses: actions/checkout@v4
|
||||
- id: versions
|
||||
name: Get version information
|
||||
run: |
|
||||
@@ -45,23 +44,25 @@ jobs:
|
||||
run: |
|
||||
sudo add-apt-repository ppa:coffeelibs/openjdk
|
||||
sudo apt-get update
|
||||
sudo apt-get install debhelper devscripts dput coffeelibs-jdk-${{ env.JAVA_VERSION }} libgtk2.0-0
|
||||
sudo apt-get install debhelper devscripts dput coffeelibs-jdk-${{ env.COFFEELIBS_JDK }}=${{ env.COFFEELIBS_JDK_VERSION }}
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v3
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
distribution: ${{ env.JAVA_DIST }}
|
||||
java-version: ${{ env.JAVA_VERSION }}
|
||||
check-latest: true
|
||||
cache: 'maven'
|
||||
- name: Run maven
|
||||
run: mvn -B clean package -Pdependency-check,linux -DskipTests
|
||||
run: mvn -B clean package -Plinux -DskipTests
|
||||
- name: Download OpenJFX jmods
|
||||
id: download-jmods
|
||||
run: |
|
||||
curl -L ${{ env.OPENJFX_JMODS_AMD64 }} -o openjfx-amd64.zip
|
||||
echo "${{ env.OPENJFX_JMODS_AMD64_HASH }} openjfx-amd64.zip" | shasum -a256 --check
|
||||
mkdir -p jmods/amd64
|
||||
unzip -j openjfx-amd64.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d jmods/amd64
|
||||
curl -L ${{ env.OPENJFX_JMODS_AARCH64 }} -o openjfx-aarch64.zip
|
||||
echo "${{ env.OPENJFX_JMODS_AARCH64_HASH }} openjfx-aarch64.zip" | shasum -a256 --check
|
||||
mkdir -p jmods/aarch64
|
||||
unzip -j openjfx-aarch64.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d jmods/aarch64
|
||||
- name: Ensure major jfx version in pom and in jmods is the same
|
||||
@@ -98,7 +99,8 @@ jobs:
|
||||
run: |
|
||||
cp -r dist/linux/debian/ pkgdir
|
||||
export RFC2822_TIMESTAMP=`date --rfc-2822`
|
||||
envsubst '${SEMVER_STR} ${VERSION_NUM} ${REVISION_NUM}' < dist/linux/debian/rules > pkgdir/debian/rules
|
||||
export DISABLE_UPDATE_CHECK=${{ inputs.dput }}
|
||||
envsubst '${SEMVER_STR} ${VERSION_NUM} ${REVISION_NUM} ${DISABLE_UPDATE_CHECK}' < dist/linux/debian/rules > pkgdir/debian/rules
|
||||
envsubst '${PPA_VERSION} ${RFC2822_TIMESTAMP}' < dist/linux/debian/changelog > pkgdir/debian/changelog
|
||||
find . -name "*.jar" >> pkgdir/debian/source/include-binaries
|
||||
mv pkgdir cryptomator_${{ inputs.ppaver }}
|
||||
@@ -126,7 +128,7 @@ jobs:
|
||||
run: |
|
||||
gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator_*_amd64.deb
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: linux-deb-package
|
||||
path: |
|
||||
@@ -140,17 +142,11 @@ jobs:
|
||||
- name: Publish on PPA
|
||||
if: inputs.dput
|
||||
run: dput ppa:sebastian-stenzel/cryptomator-beta cryptomator_*_source.changes
|
||||
|
||||
# If ref is a tag, also upload to GitHub Releases:
|
||||
- name: 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
|
||||
if: startsWith(inputs.ref, 'refs/tags/')
|
||||
if: startsWith(github.ref, 'refs/tags/') && inputs.dput
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
|
||||
run: |
|
||||
artifacts=$(ls | grep cryptomator*.deb)
|
||||
gh release upload ${{ env.TAG_NAME }} $artifacts
|
||||
gh release upload ${{ github.ref_name }} $artifacts
|
||||
|
||||
17
.github/workflows/dependency-check.yml
vendored
Normal file
17
.github/workflows/dependency-check.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
name: OWASP Maven Dependency Check
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 8 * * 0'
|
||||
workflow_dispatch:
|
||||
|
||||
|
||||
jobs:
|
||||
check-dependencies:
|
||||
uses: skymatic/workflows/.github/workflows/run-dependency-check.yml@v1
|
||||
with:
|
||||
runner-os: 'ubuntu-latest'
|
||||
java-distribution: 'temurin'
|
||||
java-version: 21
|
||||
secrets:
|
||||
nvd-api-key: ${{ secrets.NVD_API_KEY }}
|
||||
slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
2
.github/workflows/dl-stats.yml
vendored
2
.github/workflows/dl-stats.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
steps:
|
||||
- name: Get download count of latest releases
|
||||
id: get-stats
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const query = `query($owner:String!, $name:String!) {
|
||||
|
||||
14
.github/workflows/error-db.yml
vendored
14
.github/workflows/error-db.yml
vendored
@@ -2,7 +2,7 @@ name: Update Error Database
|
||||
|
||||
on:
|
||||
discussion:
|
||||
types: [created, edited, category_changed, answered, unanswered]
|
||||
types: [created, edited, deleted, category_changed, answered, unanswered]
|
||||
discussion_comment:
|
||||
types: [created, edited, deleted]
|
||||
|
||||
@@ -12,8 +12,9 @@ jobs:
|
||||
if: github.event.discussion.category.name == 'Errors'
|
||||
steps:
|
||||
- name: Query Discussion Data
|
||||
if: github.event_name == 'discussion_comment' || github.event_name == 'discussion' && github.event.action != 'deleted'
|
||||
id: query-data
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const query = `query ($owner: String!, $name: String!, $discussionNumber: Int!) {
|
||||
@@ -47,8 +48,13 @@ jobs:
|
||||
- name: Merge Error Code Data
|
||||
run: |
|
||||
jq -c '.' ${{ steps.get-gist.outputs.file }} > original.json
|
||||
echo $DISCUSSION | jq -c '.repository.discussion | .comments = .comments.totalCount | {(.id|tostring) : .}' > new.json
|
||||
jq -s '.[0] * .[1]' original.json new.json > merged.json
|
||||
if [ ! -z "$DISCUSSION" ]
|
||||
then
|
||||
echo $DISCUSSION | jq -c '.repository.discussion | .comments = .comments.totalCount | {(.id|tostring) : .}' > new.json
|
||||
jq -s '.[0] * .[1]' original.json new.json > merged.json
|
||||
else
|
||||
cat original.json | jq 'del(.[] | select(.url=="https://github.com/cryptomator/cryptomator/discussions/${{ github.event.discussion.number }}"))' > merged.json
|
||||
fi
|
||||
env:
|
||||
DISCUSSION: ${{ steps.query-data.outputs.result }}
|
||||
- name: Patch Gist
|
||||
|
||||
88
.github/workflows/flathub.yml
vendored
Normal file
88
.github/workflows/flathub.yml
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
name: Create PR for flathub
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Release tag'
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
get-version:
|
||||
uses: ./.github/workflows/get-version.yml
|
||||
with:
|
||||
version: ${{ inputs.tag }}
|
||||
tarball:
|
||||
name: Determines tarball url and compute checksum
|
||||
runs-on: ubuntu-latest
|
||||
needs: [get-version]
|
||||
if: github.event_name == 'workflow_dispatch' || needs.get-version.outputs.versionType == 'stable'
|
||||
outputs:
|
||||
url: ${{ steps.url.outputs.url}}
|
||||
sha512: ${{ steps.sha512.outputs.sha512}}
|
||||
steps:
|
||||
- name: Determine tarball url
|
||||
id: url
|
||||
run: |
|
||||
URL="";
|
||||
if [[ -n "${{ inputs.tag }}" ]]; then
|
||||
URL="https://github.com/cryptomator/cryptomator/archive/refs/tags/${{ inputs.tag }}.tar.gz"
|
||||
else
|
||||
URL="https://github.com/cryptomator/cryptomator/archive/refs/tags/${{ github.event.release.tag_name }}.tar.gz"
|
||||
fi
|
||||
echo "url=${URL}" >> "$GITHUB_OUTPUT"
|
||||
- name: Download source tarball and compute checksum
|
||||
id: sha512
|
||||
run: |
|
||||
curl --silent --fail-with-body -L -H "Accept: application/vnd.github+json" ${{ steps.url.outputs.url }} --output cryptomator.tar.gz
|
||||
TARBALL_SHA512=$(sha512sum cryptomator.tar.gz | cut -d ' ' -f1)
|
||||
echo "sha512=${TARBALL_SHA512}" >> "$GITHUB_OUTPUT"
|
||||
flathub:
|
||||
name: Create PR for flathub
|
||||
runs-on: ubuntu-latest
|
||||
needs: [tarball, get-version]
|
||||
env:
|
||||
FLATHUB_PR_URL: tbd
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'flathub/org.cryptomator.Cryptomator'
|
||||
token: ${{ secrets.CRYPTOBOT_WINGET_TOKEN }}
|
||||
- name: Checkout release branch
|
||||
run: |
|
||||
git checkout -b release/${{ needs.get-version.outputs.semVerStr }}
|
||||
- name: Update build file
|
||||
run: |
|
||||
sed -i -e 's/VERSION: [0-9]\+\.[0-9]\+\.[0-9]\+.*/VERSION: ${{ needs.get-version.outputs.semVerStr }}/g' org.cryptomator.Cryptomator.yaml
|
||||
sed -i -e 's/sha512: [0-9A-Za-z_-\+]\{128\} #CRYPTOMATOR/sha512: ${{ needs.tarball.outputs.sha512 }} #CRYPTOMATOR/g' org.cryptomator.Cryptomator.yaml
|
||||
sed -i -e 's;url: https://github.com/cryptomator/cryptomator/archive/refs/tags/[^[:blank:]]\+;url: ${{ needs.tarball.outputs.url }};g' org.cryptomator.Cryptomator.yaml
|
||||
- name: Commit and push
|
||||
run: |
|
||||
git config user.name "${{ github.actor }}"
|
||||
git config user.email "${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com"
|
||||
git config push.autoSetupRemote true
|
||||
git stage .
|
||||
git commit -m "Prepare release ${{needs.get-version.outputs.semVerStr}}"
|
||||
git push
|
||||
- name: Create pull request
|
||||
run: |
|
||||
echo "> [!IMPORTANT]\n> Todos:\n> - [ ] Update maven dependencies\n> - [ ] Check for JDK update\n> - [ ] Check for JFX update" > pr_body.md
|
||||
PR_URL=$(gh pr create --title "Release ${{ needs.get-version.outputs.semVerStr }}" --body-file pr_body.md)
|
||||
echo "FLATHUB_PR_URL=$PR_URL" >> "$GITHUB_ENV"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.CRYPTOBOT_WINGET_TOKEN }}
|
||||
- name: Slack Notification
|
||||
uses: rtCamp/action-slack-notify@v2
|
||||
if: github.event_name == 'release'
|
||||
env:
|
||||
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
SLACK_USERNAME: 'Cryptobot'
|
||||
SLACK_ICON: false
|
||||
SLACK_ICON_EMOJI: ':bot:'
|
||||
SLACK_CHANNEL: 'cryptomator-desktop'
|
||||
SLACK_TITLE: "Flathub release PR created for ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} created."
|
||||
SLACK_MESSAGE: "See <${{ env.FLATHUB_PR_URL }}|PR> on how to proceed.>."
|
||||
SLACK_FOOTER: false
|
||||
MSG_MINIMAL: true
|
||||
15
.github/workflows/get-version.yml
vendored
15
.github/workflows/get-version.yml
vendored
@@ -22,9 +22,8 @@ on:
|
||||
value: ${{ jobs.determine-version.outputs.type }}
|
||||
|
||||
env:
|
||||
JAVA_VERSION: 20
|
||||
JAVA_DIST: 'temurin'
|
||||
JAVA_CACHE: 'maven'
|
||||
JAVA_DIST: 'zulu'
|
||||
JAVA_VERSION: 21
|
||||
|
||||
jobs:
|
||||
determine-version:
|
||||
@@ -36,22 +35,22 @@ jobs:
|
||||
revNum: ${{ steps.versions.outputs.revNum }}
|
||||
type: ${{ steps.versions.outputs.type}}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v3
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: ${{ env.JAVA_DIST }}
|
||||
java-version: ${{ env.JAVA_VERSION }}
|
||||
cache: ${{ env.JAVA_CACHE }}
|
||||
cache: 'maven'
|
||||
- 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 }}"
|
||||
SEM_VER_STR="${{ inputs.version }}"
|
||||
else
|
||||
SEM_VER_STR=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout`
|
||||
fi
|
||||
@@ -74,4 +73,4 @@ jobs:
|
||||
- name: Validate Version
|
||||
uses: skymatic/semver-validation-action@v2
|
||||
with:
|
||||
version: ${{ steps.versions.outputs.semVerStr }}
|
||||
version: ${{ steps.versions.outputs.semVerStr }}
|
||||
78
.github/workflows/mac-dmg.yml
vendored
78
.github/workflows/mac-dmg.yml
vendored
@@ -8,9 +8,15 @@ on:
|
||||
version:
|
||||
description: 'Version'
|
||||
required: false
|
||||
notarize:
|
||||
description: 'Notarize'
|
||||
required: true
|
||||
default: false
|
||||
type: boolean
|
||||
|
||||
env:
|
||||
JAVA_VERSION: 20
|
||||
JAVA_DIST: 'zulu'
|
||||
JAVA_VERSION: '21.0.2+13'
|
||||
|
||||
jobs:
|
||||
get-version:
|
||||
@@ -31,52 +37,66 @@ jobs:
|
||||
output-suffix: x64
|
||||
xcode-path: '/Applications/Xcode_13.2.1.app'
|
||||
fuse-lib: macFUSE
|
||||
openjfx-url: 'https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_osx-x64_bin-jmods.zip'
|
||||
openjfx-sha: 'bd6abab20da73d5a968dcf2fd915d81b5fb919340e3bb84979ee9a888a829939'
|
||||
- os: [self-hosted, macOS, ARM64]
|
||||
architecture: aarch64
|
||||
output-suffix: arm64
|
||||
xcode-path: '/Applications/Xcode_13.2.1.app'
|
||||
fuse-lib: FUSE-T
|
||||
openjfx-url: 'https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_osx-aarch64_bin-jmods.zip'
|
||||
openjfx-sha: '7afaa1c57a6cc3c384d636e597b9a5364693e2db4aaec0a6e63d2fa964400b58'
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v3
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
distribution: ${{ env.JAVA_DIST }}
|
||||
java-version: ${{ env.JAVA_VERSION }}
|
||||
java-package: 'jdk+fx'
|
||||
architecture: ${{ matrix.architecture }}
|
||||
check-latest: true
|
||||
cache: 'maven'
|
||||
- name: Ensure major jfx version in pom equals in jdk
|
||||
if: ${{ !contains(matrix.os, 'self-hosted') }}
|
||||
shell: pwsh
|
||||
- name: Download OpenJFX jmods
|
||||
id: download-jmods
|
||||
run: |
|
||||
$jfxPomVersion = (&mvn help:evaluate "-Dexpression=javafx.version" -q -DforceStdout) -split "\."
|
||||
$jfxJdkVersion = ((Get-Content -path "${env:JAVA_HOME}/lib/javafx.properties" | Where-Object {$_ -like 'javafx.version=*' }) -replace '.*=','') -split "\."
|
||||
if ($jfxPomVersion[0] -ne $jfxJdkVersion[0]) {
|
||||
Write-Error "Major part of JavaFX version in pom($($jfxPomVersion[0])) does not match the version in JDK($($jfxJdkVersion[0])) "
|
||||
curl -L ${{ matrix.openjfx-url }} -o openjfx-jmods.zip
|
||||
echo "${{ matrix.openjfx-sha }} *openjfx-jmods.zip" | shasum -a256 --check
|
||||
mkdir -p openjfx-jmods/
|
||||
unzip -jo openjfx-jmods.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d openjfx-jmods
|
||||
- name: Ensure major jfx version in pom and in jmods is the same
|
||||
run: |
|
||||
JMOD_VERSION=$(jmod describe openjfx-jmods/javafx.base.jmod | head -1)
|
||||
JMOD_VERSION=${JMOD_VERSION#*@}
|
||||
JMOD_VERSION=${JMOD_VERSION%%.*}
|
||||
POM_JFX_VERSION=$(mvn help:evaluate "-Dexpression=javafx.version" -q -DforceStdout)
|
||||
POM_JFX_VERSION=${POM_JFX_VERSION#*@}
|
||||
POM_JFX_VERSION=${POM_JFX_VERSION%%.*}
|
||||
|
||||
if [ "${POM_JFX_VERSION}" -ne "${JMOD_VERSION}" ]; then
|
||||
>&2 echo "Major JavaFX version in pom.xml (${POM_JFX_VERSION}) != jmod version (${JMOD_VERSION})"
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
- name: Set version
|
||||
run : mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }}
|
||||
- name: Run maven
|
||||
run: mvn -B clean package -Pdependency-check,mac -DskipTests
|
||||
run: mvn -B clean package -Pmac -DskipTests
|
||||
- name: Patch target dir
|
||||
run: |
|
||||
cp LICENSE.txt target
|
||||
cp target/cryptomator-*.jar target/mods
|
||||
- name: Run jlink
|
||||
#Remark: no compression is applied for improved build compression later (here dmg)
|
||||
run: >
|
||||
${JAVA_HOME}/bin/jlink
|
||||
--verbose
|
||||
--output runtime
|
||||
--module-path "${JAVA_HOME}/jmods"
|
||||
--module-path "${JAVA_HOME}/jmods:openjfx-jmods"
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr
|
||||
--strip-native-commands
|
||||
--no-header-files
|
||||
--no-man-pages
|
||||
--strip-debug
|
||||
--compress=1
|
||||
--compress zip-0
|
||||
- name: Run jpackage
|
||||
run: >
|
||||
${JAVA_HOME}/bin/jpackage
|
||||
@@ -89,23 +109,24 @@ jobs:
|
||||
--dest appdir
|
||||
--name Cryptomator
|
||||
--vendor "Skymatic GmbH"
|
||||
--copyright "(C) 2016 - 2023 Skymatic GmbH"
|
||||
--copyright "(C) 2016 - 2024 Skymatic GmbH"
|
||||
--app-version "${{ needs.get-version.outputs.semVerNum }}"
|
||||
--java-options "--enable-preview"
|
||||
--java-options "--enable-native-access=org.cryptomator.jfuse.mac"
|
||||
--java-options "-Xss5m"
|
||||
--java-options "-Xmx256m"
|
||||
--java-options "-Dfile.encoding=\"utf-8\""
|
||||
--java-options "-Djava.net.useSystemProxies=true"
|
||||
--java-options "-Dapple.awt.enableTemplateImages=true"
|
||||
--java-options "-Dsun.java2d.metal=true"
|
||||
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
|
||||
--java-options "-Dcryptomator.logDir=\"~/Library/Logs/Cryptomator\""
|
||||
--java-options "-Dcryptomator.pluginDir=\"~/Library/Application Support/Cryptomator/Plugins\""
|
||||
--java-options "-Dcryptomator.settingsPath=\"~/Library/Application Support/Cryptomator/settings.json\""
|
||||
--java-options "-Dcryptomator.p12Path=\"~/Library/Application Support/Cryptomator/key.p12\""
|
||||
--java-options "-Dcryptomator.ipcSocketPath=\"~/Library/Application Support/Cryptomator/ipc.socket\""
|
||||
--java-options "-Dcryptomator.logDir=\"@{userhome}/Library/Logs/Cryptomator\""
|
||||
--java-options "-Dcryptomator.pluginDir=\"@{userhome}/Library/Application Support/Cryptomator/Plugins\""
|
||||
--java-options "-Dcryptomator.settingsPath=\"@{userhome}/Library/Application Support/Cryptomator/settings.json\""
|
||||
--java-options "-Dcryptomator.p12Path=\"@{userhome}/Library/Application Support/Cryptomator/key.p12\""
|
||||
--java-options "-Dcryptomator.ipcSocketPath=\"@{userhome}/Library/Application Support/Cryptomator/ipc.socket\""
|
||||
--java-options "-Dcryptomator.integrationsMac.keychainServiceName=\"Cryptomator\""
|
||||
--java-options "-Dcryptomator.mountPointsDir=\"~/Cryptomator\""
|
||||
--java-options "-Dcryptomator.mountPointsDir=\"@{userhome}/Library/Application Support/Cryptomator/mnt\""
|
||||
--java-options "-Dcryptomator.showTrayIcon=true"
|
||||
--java-options "-Dcryptomator.buildNumber=\"dmg-${{ needs.get-version.outputs.revNum }}\""
|
||||
--mac-package-identifier org.cryptomator
|
||||
@@ -202,13 +223,12 @@ jobs:
|
||||
--app-drop-link 512 245
|
||||
--eula "dist/mac/dmg/resources/license.rtf"
|
||||
--icon ".background" 128 758
|
||||
--icon ".fseventsd" 320 758
|
||||
--icon ".VolumeIcon.icns" 512 758
|
||||
Cryptomator-${VERSION_NO}-${{ matrix.output-suffix }}.dmg dmg
|
||||
env:
|
||||
VERSION_NO: ${{ needs.get-version.outputs.semVerNum }}
|
||||
- name: Notarize .dmg
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
if: startsWith(github.ref, 'refs/tags/') || inputs.notarize
|
||||
uses: cocoalibs/xcode-notarization-action@v1
|
||||
with:
|
||||
app-path: 'Cryptomator-*.dmg'
|
||||
@@ -230,13 +250,15 @@ jobs:
|
||||
run: security delete-keychain $RUNNER_TEMP/codesign.keychain-db
|
||||
continue-on-error: true
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: dmg-${{ matrix.output-suffix }}
|
||||
path: Cryptomator-*.dmg
|
||||
path: |
|
||||
Cryptomator-*.dmg
|
||||
Cryptomator-*.asc
|
||||
if-no-files-found: error
|
||||
- name: Publish dmg on GitHub Releases
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published'
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
fail_on_unmatched_files: true
|
||||
|
||||
2
.github/workflows/no-response.yml
vendored
2
.github/workflows/no-response.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/stale@v8
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
days-before-stale: 14
|
||||
days-before-close: 0
|
||||
|
||||
11
.github/workflows/pullrequest.yml
vendored
11
.github/workflows/pullrequest.yml
vendored
@@ -4,7 +4,8 @@ on:
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
JAVA_VERSION: 20
|
||||
JAVA_DIST: 'zulu'
|
||||
JAVA_VERSION: 21
|
||||
|
||||
defaults:
|
||||
run:
|
||||
@@ -16,11 +17,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]')"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-java@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
distribution: ${{ env.JAVA_DIST }}
|
||||
java-version: ${{ env.JAVA_VERSION }}
|
||||
cache: 'maven'
|
||||
- name: Build and Test
|
||||
run: xvfb-run mvn -B clean install jacoco:report -Pcoverage,dependency-check
|
||||
run: xvfb-run mvn -B clean install jacoco:report -Pcoverage
|
||||
36
.github/workflows/release-check.yml
vendored
36
.github/workflows/release-check.yml
vendored
@@ -6,19 +6,26 @@ on:
|
||||
- 'release/**'
|
||||
- 'hotfix/**'
|
||||
|
||||
env:
|
||||
JAVA_VERSION: 20
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
env:
|
||||
JAVA_DIST: 'zulu'
|
||||
JAVA_VERSION: 21
|
||||
|
||||
jobs:
|
||||
release-check-precondition:
|
||||
check-preconditions:
|
||||
name: Validate commits pushed to release/hotfix branch to fulfill release requirements
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: ${{ env.JAVA_DIST }}
|
||||
java-version: ${{ env.JAVA_VERSION }}
|
||||
cache: 'maven'
|
||||
- id: validate-pom-version
|
||||
name: Validate POM version
|
||||
run: |
|
||||
@@ -37,7 +44,22 @@ jobs:
|
||||
fi
|
||||
- name: Validate release in org.cryptomator.Cryptomator.metainfo.xml file
|
||||
run: |
|
||||
if ! grep -q "<release date=\".*\" version=\"${{ steps.validate-pom-version.outputs.semVerStr }}\"/>" dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml; then
|
||||
if ! grep -q "<release date=\".*\" version=\"${{ steps.validate-pom-version.outputs.semVerStr }}\">" dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml; then
|
||||
echo "Release not set in dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
- name: Cache NVD DB
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.m2/repository/org/owasp/dependency-check-data/
|
||||
key: dependency-check-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
dependency-check
|
||||
env:
|
||||
SEGMENT_DOWNLOAD_TIMEOUT_MINS: 5
|
||||
- name: Run org.owasp:dependency-check plugin
|
||||
id: dependency-check
|
||||
continue-on-error: true
|
||||
run: mvn -B verify -Pdependency-check -DskipTests
|
||||
env:
|
||||
NVD_API_KEY: ${{ secrets.NVD_API_KEY }}
|
||||
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/stale@v8
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
days-before-stale: 365
|
||||
days-before-close: 90
|
||||
|
||||
155
.github/workflows/win-exe.yml
vendored
155
.github/workflows/win-exe.yml
vendored
@@ -10,15 +10,17 @@ on:
|
||||
required: false
|
||||
isDebug:
|
||||
description: 'Build debug version with console output'
|
||||
type: boolean
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
|
||||
env:
|
||||
JAVA_VERSION: 20
|
||||
JAVA_DIST: 'temurin'
|
||||
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'
|
||||
JAVA_DIST: 'zulu'
|
||||
JAVA_VERSION: '21.0.2+13'
|
||||
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_windows-x64_bin-jmods.zip'
|
||||
OPENJFX_JMODS_AMD64_HASH: 'daf8acae631c016c24cfe23f88469400274d3441dd890615a42dfb501f3eb94a'
|
||||
WINFSP_MSI: 'https://github.com/winfsp/winfsp/releases/download/v2.0/winfsp-2.0.23075.msi'
|
||||
WINFSP_UNINSTALLER: 'https://github.com/cryptomator/winfsp-uninstaller/releases/latest/download/winfsp-uninstaller.exe'
|
||||
|
||||
defaults:
|
||||
run:
|
||||
@@ -38,21 +40,20 @@ jobs:
|
||||
LOOPBACK_ALIAS: 'cryptomator-vault'
|
||||
WIN_CONSOLE_FLAG: ''
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v3
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: ${{ env.JAVA_DIST }}
|
||||
java-version: ${{ env.JAVA_VERSION }}
|
||||
java-package: 'jdk'
|
||||
check-latest: true
|
||||
cache: ${{ env.JAVA_CACHE }}
|
||||
cache: 'maven'
|
||||
- name: Download and extract JavaFX jmods from Gluon
|
||||
#In the last step we move all jmods files a dir level up because jmods are placed inside a directory in the zip
|
||||
run: |
|
||||
curl --output jfxjmods.zip -L "${{ env.JFX_JMODS_URL }}"
|
||||
if(!(Get-FileHash -Path jfxjmods.zip -Algorithm SHA256).Hash.equals("${{ env.JFX_JMODS_HASH }}")) {
|
||||
throw "Wrong checksum of JMOD archive downloaded from ${{ env.JFX_JMODS_URL }}.";
|
||||
curl --output jfxjmods.zip -L "${{ env.OPENJFX_JMODS_AMD64 }}"
|
||||
if(!(Get-FileHash -Path jfxjmods.zip -Algorithm SHA256).Hash.ToLower().equals("${{ env.OPENJFX_JMODS_AMD64_HASH }}")) {
|
||||
throw "Wrong checksum of JMOD archive downloaded from ${{ env.OPENJFX_JMODS_AMD64 }}.";
|
||||
}
|
||||
Expand-Archive -Path jfxjmods.zip -DestinationPath jfxjmods
|
||||
Get-ChildItem -Path jfxjmods -Recurse -Filter "*.jmod" | ForEach-Object { Move-Item -Path $_ -Destination $_.Directory.Parent}
|
||||
@@ -73,12 +74,13 @@ jobs:
|
||||
- name: Set version
|
||||
run : mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }}
|
||||
- name: Run maven
|
||||
run: mvn -B clean package -Pdependency-check,win -DskipTests
|
||||
run: mvn -B clean package -Pwin -DskipTests
|
||||
- name: Patch target dir
|
||||
run: |
|
||||
cp LICENSE.txt target
|
||||
cp target/cryptomator-*.jar target/mods
|
||||
- name: Run jlink
|
||||
#Remark: no compression is applied for improved build compression later (here msi)
|
||||
run: >
|
||||
${JAVA_HOME}/bin/jlink
|
||||
--verbose
|
||||
@@ -89,7 +91,7 @@ jobs:
|
||||
--no-header-files
|
||||
--no-man-pages
|
||||
--strip-debug
|
||||
--compress=1
|
||||
--compress zip-0
|
||||
- name: Change win-console flag if debug is active
|
||||
if: ${{ inputs.isDebug }}
|
||||
run: echo "WIN_CONSOLE_FLAG=--win-console" >> $GITHUB_ENV
|
||||
@@ -105,7 +107,7 @@ jobs:
|
||||
--dest appdir
|
||||
--name Cryptomator
|
||||
--vendor "Skymatic GmbH"
|
||||
--copyright "(C) 2016 - 2023 Skymatic GmbH"
|
||||
--copyright "(C) 2016 - 2024 Skymatic GmbH"
|
||||
--app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}"
|
||||
--java-options "--enable-preview"
|
||||
--java-options "--enable-native-access=org.cryptomator.jfuse.win"
|
||||
@@ -113,17 +115,18 @@ jobs:
|
||||
--java-options "-Xmx256m"
|
||||
--java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\""
|
||||
--java-options "-Dfile.encoding=\"utf-8\""
|
||||
--java-options "-Dcryptomator.logDir=\"~/AppData/Roaming/Cryptomator\""
|
||||
--java-options "-Dcryptomator.pluginDir=\"~/AppData/Roaming/Cryptomator/Plugins\""
|
||||
--java-options "-Dcryptomator.settingsPath=\"~/AppData/Roaming/Cryptomator/settings.json\""
|
||||
--java-options "-Dcryptomator.p12Path=\"~/AppData/Roaming/Cryptomator/key.p12\""
|
||||
--java-options "-Dcryptomator.ipcSocketPath=\"~/AppData/Roaming/Cryptomator/ipc.socket\""
|
||||
--java-options "-Dcryptomator.mountPointsDir=\"~/Cryptomator\""
|
||||
--java-options "-Djava.net.useSystemProxies=true"
|
||||
--java-options "-Dcryptomator.logDir=\"@{localappdata}/Cryptomator\""
|
||||
--java-options "-Dcryptomator.pluginDir=\"@{appdata}/Cryptomator/Plugins\""
|
||||
--java-options "-Dcryptomator.settingsPath=\"@{appdata}/Cryptomator/settings.json;@{userhome}/AppData/Roaming/Cryptomator/settings.json\""
|
||||
--java-options "-Dcryptomator.p12Path=\"@{appdata}/Cryptomator/key.p12;@{userhome}/AppData/Roaming/Cryptomator/key.p12\""
|
||||
--java-options "-Dcryptomator.ipcSocketPath=\"@{localappdata}/Cryptomator/ipc.socket\""
|
||||
--java-options "-Dcryptomator.mountPointsDir=\"@{userhome}/Cryptomator\""
|
||||
--java-options "-Dcryptomator.loopbackAlias=\"${{ env.LOOPBACK_ALIAS }}\""
|
||||
--java-options "-Dcryptomator.showTrayIcon=true"
|
||||
--java-options "-Dcryptomator.buildNumber=\"msi-${{ needs.get-version.outputs.revNum }}\""
|
||||
--java-options "-Dcryptomator.integrationsWin.autoStartShellLinkName=\"Cryptomator\""
|
||||
--java-options "-Dcryptomator.integrationsWin.keychainPaths=\"~/AppData/Roaming/Cryptomator/keychain.json\""
|
||||
--java-options "-Dcryptomator.integrationsWin.keychainPaths=\"@{appdata}/Cryptomator/keychain.json;@{userhome}/AppData/Roaming/Cryptomator/keychain.json\""
|
||||
--java-options "-Djavafx.verbose=${{ inputs.isDebug }}"
|
||||
--resource-dir dist/win/resources
|
||||
--icon dist/win/resources/Cryptomator.ico
|
||||
@@ -144,23 +147,53 @@ jobs:
|
||||
- name: Fix permissions
|
||||
run: attrib -r appdir/Cryptomator/Cryptomator.exe
|
||||
shell: pwsh
|
||||
- name: Extract integrations DLL for code signing
|
||||
- name: Extract jars with DLLs for Codesigning
|
||||
shell: pwsh
|
||||
run: gci ./appdir/Cryptomator/app/mods/ -File integrations-win-*.jar | ForEach-Object {Set-Location -Path $_.Directory; jar --file=$($_.FullName) --extract integrations.dll }
|
||||
run: |
|
||||
Add-Type -AssemblyName "System.io.compression.filesystem"
|
||||
$jarFolder = Resolve-Path ".\appdir\Cryptomator\app\mods"
|
||||
$jarExtractDir = New-Item -Path ".\appdir\jar-extract" -ItemType Directory
|
||||
|
||||
#for all jars inspect
|
||||
Get-ChildItem -Path $jarFolder -Filter "*.jar" | ForEach-Object {
|
||||
$jar = [Io.compression.zipfile]::OpenRead($_.FullName)
|
||||
if (@($jar.Entries | Where-Object {$_.Name.ToString().EndsWith(".dll")} | Select-Object -First 1).Count -gt 0) {
|
||||
#jars containing dlls extract
|
||||
Set-Location $jarExtractDir
|
||||
Expand-Archive -Path $_.FullName
|
||||
}
|
||||
$jar.Dispose()
|
||||
}
|
||||
- name: Extract wixhelper.dll for Codesigning #see https://github.com/cryptomator/cryptomator/issues/3130
|
||||
shell: pwsh
|
||||
run: |
|
||||
New-Item -Path appdir/jpackage-jmod -ItemType Directory
|
||||
& $env:JAVA_HOME\bin\jmod.exe extract --dir jpackage-jmod "${env:JAVA_HOME}\jmods\jdk.jpackage.jmod"
|
||||
Get-ChildItem -Recurse -Path "jpackage-jmod" -File wixhelper.dll | Select-Object -Last 1 | Copy-Item -Destination "appdir"
|
||||
- name: Codesign
|
||||
uses: skymatic/code-sign-action@v2
|
||||
uses: skymatic/code-sign-action@v3
|
||||
with:
|
||||
certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
|
||||
password: ${{ secrets.WIN_CODESIGN_P12_PW }}
|
||||
certificatesha1: 5FC94CE149E5B511E621F53A060AC67CBD446B3A
|
||||
description: Cryptomator
|
||||
timestampUrl: 'http://timestamp.digicert.com'
|
||||
folder: appdir/Cryptomator
|
||||
folder: appdir
|
||||
recursive: true
|
||||
- name: Repack signed DLL into jar
|
||||
- name: Replace DLLs inside jars with signed ones
|
||||
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}
|
||||
$jarExtractDir = Resolve-Path ".\appdir\jar-extract"
|
||||
$jarFolder = Resolve-Path ".\appdir\Cryptomator\app\mods"
|
||||
Get-ChildItem -Path $jarExtractDir | ForEach-Object {
|
||||
$jarName = $_.Name
|
||||
$jarFile = "${jarFolder}\${jarName}.jar"
|
||||
Set-Location $_
|
||||
Get-ChildItem -Path $_ -Recurse -File "*.dll" | ForEach-Object {
|
||||
# update jar with signed dll
|
||||
jar --file="$jarFile" --update $(Resolve-Path -Relative -Path $_)
|
||||
}
|
||||
}
|
||||
- name: Generate license for MSI
|
||||
run: >
|
||||
mvn -B license:add-third-party
|
||||
@@ -182,20 +215,21 @@ jobs:
|
||||
--dest installer
|
||||
--name Cryptomator
|
||||
--vendor "Skymatic GmbH"
|
||||
--copyright "(C) 2016 - 2023 Skymatic GmbH"
|
||||
--copyright "(C) 2016 - 2024 Skymatic GmbH"
|
||||
--app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum}}"
|
||||
--win-menu
|
||||
--win-dir-chooser
|
||||
--win-shortcut-prompt
|
||||
--win-update-url "https:\\cryptomator.org"
|
||||
--win-update-url "https:\\cryptomator.org\downloads"
|
||||
--win-menu-group Cryptomator
|
||||
--resource-dir dist/win/resources
|
||||
--license-file dist/win/resources/license.rtf
|
||||
--file-associations dist/win/resources/FAvaultFile.properties
|
||||
env:
|
||||
JP_WIXWIZARD_RESOURCES: ${{ github.workspace }}/dist/win/resources # requires abs path, used in resources/main.wxs
|
||||
JP_WIXHELPER_DIR: ${{ github.workspace }}\appdir
|
||||
- name: Codesign MSI
|
||||
uses: skymatic/code-sign-action@v2
|
||||
uses: skymatic/code-sign-action@v3
|
||||
with:
|
||||
certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
|
||||
password: ${{ secrets.WIN_CODESIGN_P12_PW }}
|
||||
@@ -213,7 +247,7 @@ jobs:
|
||||
GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }}
|
||||
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: msi
|
||||
path: |
|
||||
@@ -221,7 +255,7 @@ jobs:
|
||||
Cryptomator-*.asc
|
||||
if-no-files-found: error
|
||||
- name: Publish .msi on GitHub Releases
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published'
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
fail_on_unmatched_files: true
|
||||
@@ -235,20 +269,20 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
needs: [get-version, build-msi]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Download .msi
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: msi
|
||||
path: dist/win/bundle/resources
|
||||
- name: Strip version info from msi file name
|
||||
run: mv dist/win/bundle/resources/Cryptomator*.msi dist/win/bundle/resources/Cryptomator.msi
|
||||
- uses: actions/setup-java@v3
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: ${{ env.JAVA_DIST }}
|
||||
java-version: ${{ env.JAVA_VERSION }}
|
||||
check-latest: true
|
||||
cache: ${{ env.JAVA_CACHE }}
|
||||
cache: 'maven'
|
||||
- name: Generate license for exe
|
||||
run: >
|
||||
mvn -B license:add-third-party
|
||||
@@ -262,8 +296,11 @@ jobs:
|
||||
shell: pwsh
|
||||
- name: Download WinFsp
|
||||
run: |
|
||||
$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 ${{ env.WINFSP_MSI }}
|
||||
shell: pwsh
|
||||
- name: Download Legacy-WinFsp uninstaller
|
||||
run: |
|
||||
curl --output dist/win/bundle/resources/winfsp-uninstaller.exe -L ${{ env.WINFSP_UNINSTALLER }}
|
||||
shell: pwsh
|
||||
- name: Compile to wixObj file
|
||||
run: >
|
||||
@@ -273,7 +310,7 @@ jobs:
|
||||
-out dist/win/bundle/
|
||||
-dBundleVersion="${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}"
|
||||
-dBundleVendor="Skymatic GmbH"
|
||||
-dBundleCopyright="(C) 2016 - 2023 Skymatic GmbH"
|
||||
-dBundleCopyright="(C) 2016 - 2024 Skymatic GmbH"
|
||||
-dAboutUrl="https://cryptomator.org"
|
||||
-dHelpUrl="https://cryptomator.org/contact"
|
||||
-dUpdateUrl="https://cryptomator.org/downloads/"
|
||||
@@ -289,7 +326,7 @@ jobs:
|
||||
-ib installer/unsigned/Cryptomator-Installer.exe
|
||||
-o tmp/engine.exe
|
||||
- name: Codesign burn engine
|
||||
uses: skymatic/code-sign-action@v2
|
||||
uses: skymatic/code-sign-action@v3
|
||||
with:
|
||||
certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
|
||||
password: ${{ secrets.WIN_CODESIGN_P12_PW }}
|
||||
@@ -303,7 +340,7 @@ jobs:
|
||||
-ab tmp/engine.exe installer/unsigned/Cryptomator-Installer.exe
|
||||
-o installer/Cryptomator-Installer.exe
|
||||
- name: Codesign EXE
|
||||
uses: skymatic/code-sign-action@v2
|
||||
uses: skymatic/code-sign-action@v3
|
||||
with:
|
||||
certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
|
||||
password: ${{ secrets.WIN_CODESIGN_P12_PW }}
|
||||
@@ -321,7 +358,7 @@ jobs:
|
||||
GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }}
|
||||
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: exe
|
||||
path: |
|
||||
@@ -329,7 +366,7 @@ jobs:
|
||||
Cryptomator-*.asc
|
||||
if-no-files-found: error
|
||||
- name: Publish .msi on GitHub Releases
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published'
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
fail_on_unmatched_files: true
|
||||
@@ -340,17 +377,17 @@ jobs:
|
||||
|
||||
allowlist:
|
||||
name: Anti Virus Allowlisting
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published'
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build-msi, build-exe]
|
||||
steps:
|
||||
- name: Download .msi
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: msi
|
||||
path: msi
|
||||
- name: Download .exe
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: exe
|
||||
path: exe
|
||||
@@ -360,7 +397,7 @@ jobs:
|
||||
cp msi/*.msi files
|
||||
cp exe/*.exe files
|
||||
- name: Upload to Kaspersky
|
||||
uses: SamKirkland/FTP-Deploy-Action@4.3.3
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.3.4
|
||||
with:
|
||||
protocol: ftps
|
||||
server: allowlist.kaspersky-labs.com
|
||||
@@ -369,7 +406,7 @@ jobs:
|
||||
password: ${{ secrets.ALLOWLIST_KASPERSKY_PASSWORD }}
|
||||
local-dir: files/
|
||||
- name: Upload to Avast
|
||||
uses: SamKirkland/FTP-Deploy-Action@4.3.0
|
||||
uses: SamKirkland/FTP-Deploy-Action@v4.3.4
|
||||
with:
|
||||
protocol: ftp
|
||||
server: whitelisting.avast.com
|
||||
@@ -377,3 +414,21 @@ jobs:
|
||||
username: ${{ secrets.ALLOWLIST_AVAST_USERNAME }}
|
||||
password: ${{ secrets.ALLOWLIST_AVAST_PASSWORD }}
|
||||
local-dir: files/
|
||||
notify-winget:
|
||||
name: Notify for winget-release
|
||||
if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published' && needs.get-version.outputs.versionType == 'stable'
|
||||
needs: [build-msi, get-version]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Slack Notification
|
||||
uses: rtCamp/action-slack-notify@v2
|
||||
env:
|
||||
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
SLACK_USERNAME: 'Cryptobot'
|
||||
SLACK_ICON: false
|
||||
SLACK_ICON_EMOJI: ':bot:'
|
||||
SLACK_CHANNEL: 'cryptomator-desktop'
|
||||
SLACK_TITLE: "MSI of ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} published."
|
||||
SLACK_MESSAGE: "Ready to <https://github.com/${{ github.repository }}/actions/workflows/winget.yml| release to winget>."
|
||||
SLACK_FOOTER: false
|
||||
MSG_MINIMAL: true
|
||||
27
.github/workflows/winget.yml
vendored
Normal file
27
.github/workflows/winget.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
name: Publish MSI to winget-pkgs
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: 'Release tag'
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
winget:
|
||||
name: Publish winget package
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Sync winget-pkgs fork
|
||||
run: |
|
||||
gh repo sync cryptomator/winget-pkgs -b master --force
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.CRYPTOBOT_WINGET_TOKEN }}
|
||||
- name: Submit package
|
||||
uses: vedantmgoyal2009/winget-releaser@v2
|
||||
with:
|
||||
identifier: Cryptomator.Cryptomator
|
||||
version: ${{ inputs.tag }}
|
||||
release-tag: ${{ inputs.tag }}
|
||||
installers-regex: '\.msi$'
|
||||
token: ${{ secrets.CRYPTOBOT_WINGET_TOKEN }}
|
||||
3
.idea/codeStyles/Project.xml
generated
3
.idea/codeStyles/Project.xml
generated
@@ -53,9 +53,10 @@
|
||||
<option name="KEEP_LINE_BREAKS" value="false" />
|
||||
<option name="BLANK_LINES_AFTER_CLASS_HEADER" value="1" />
|
||||
<option name="BINARY_OPERATION_SIGN_ON_NEXT_LINE" value="true" />
|
||||
<option name="KEEP_SIMPLE_BLOCKS_IN_ONE_LINE" value="true" />
|
||||
<option name="KEEP_SIMPLE_METHODS_IN_ONE_LINE" value="true" />
|
||||
<option name="KEEP_SIMPLE_LAMBDAS_IN_ONE_LINE" value="true" />
|
||||
<option name="KEEP_SIMPLE_CLASSES_IN_ONE_LINE" value="true" />
|
||||
<option name="IF_BRACE_FORCE" value="3" />
|
||||
<option name="ENUM_CONSTANTS_WRAP" value="2" />
|
||||
<indentOptions>
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
|
||||
23
.idea/compiler.xml
generated
23
.idea/compiler.xml
generated
@@ -14,10 +14,10 @@
|
||||
<option name="dagger.fastInit" value="enabled" />
|
||||
<option name="dagger.formatGeneratedSource" value="enabled" />
|
||||
<processorPath useClasspath="false">
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-compiler/2.45/dagger-compiler-2.45.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger/2.45/dagger-2.45.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-compiler/2.48.1/dagger-compiler-2.48.1.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger/2.48.1/dagger-2.48.1.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/javax/inject/javax.inject/1/javax.inject-1.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-producers/2.45/dagger-producers-2.45.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-producers/2.48.1/dagger-producers-2.48.1.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/guava/guava/31.0.1-jre/guava-31.0.1-jre.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar" />
|
||||
@@ -26,20 +26,19 @@
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/errorprone/error_prone_annotations/2.7.1/error_prone_annotations-2.7.1.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/j2objc/j2objc-annotations/1.3/j2objc-annotations-1.3.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/checkerframework/checker-compat-qual/2.5.5/checker-compat-qual-2.5.5.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-spi/2.45/dagger-spi-2.45.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/devtools/ksp/symbol-processing-api/1.7.0-1.0.6/symbol-processing-api-1.7.0-1.0.6.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.7.0/kotlin-stdlib-1.7.0.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-common/1.7.0/kotlin-stdlib-common-1.7.0.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-spi/2.48.1/dagger-spi-2.48.1.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/devtools/ksp/symbol-processing-api/1.9.0-1.0.12/symbol-processing-api-1.9.0-1.0.12.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.0/kotlin-stdlib-1.9.0.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-common/1.9.0/kotlin-stdlib-common-1.9.0.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/squareup/javapoet/1.13.0/javapoet-1.13.0.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/squareup/kotlinpoet/1.11.0/kotlinpoet-1.11.0.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.7.0/kotlin-stdlib-jdk8-1.7.0.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.7.0/kotlin-stdlib-jdk7-1.7.0.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-reflect/1.6.10/kotlin-reflect-1.6.10.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/googlejavaformat/google-java-format/1.5/google-java-format-1.5.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/errorprone/javac-shaded/9-dev-r4023-3/javac-shaded-9-dev-r4023-3.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/squareup/kotlinpoet/1.11.0/kotlinpoet-1.11.0.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.6.10/kotlin-stdlib-jdk8-1.6.10.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/1.6.10/kotlin-stdlib-jdk7-1.6.10.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-reflect/1.6.10/kotlin-reflect-1.6.10.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/net/ltgt/gradle/incap/incap/0.2/incap-0.2.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-metadata-jvm/0.5.0/kotlinx-metadata-jvm-0.5.0.jar" />
|
||||
</processorPath>
|
||||
<module name="cryptomator" />
|
||||
</profile>
|
||||
|
||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -8,7 +8,7 @@
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_20_PREVIEW" project-jdk-name="20" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21_PREVIEW" project-jdk-name="21" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
2
.idea/runConfigurations/Cryptomator_Linux.xml
generated
2
.idea/runConfigurations/Cryptomator_Linux.xml
generated
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="Cryptomator Linux" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="cryptomator" />
|
||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="~/.config/Cryptomator/settings.json" -Dcryptomator.p12Path="~/.config/Cryptomator/key.p12" -Dcryptomator.ipcSocketPath="~/.config/Cryptomator/ipc.socket" -Dcryptomator.logDir="~/.local/share/Cryptomator/logs" -Dcryptomator.pluginDir="~/.local/share/Cryptomator/plugins" -Dcryptomator.mountPointsDir="~/.local/share/Cryptomator/mnt" -Dcryptomator.showTrayIcon=true -Xss20m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64" />
|
||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="@{userhome}/.config/Cryptomator/settings.json" -Dcryptomator.p12Path="@{userhome}/.config/Cryptomator/key.p12" -Dcryptomator.ipcSocketPath="@{userhome}/.config/Cryptomator/ipc.socket" -Dcryptomator.logDir="@{userhome}/.local/share/Cryptomator/logs" -Dcryptomator.pluginDir="@{userhome}/.local/share/Cryptomator/plugins" -Dcryptomator.mountPointsDir="@{userhome}/.local/share/Cryptomator/mnt" -Dcryptomator.showTrayIcon=true -Xss20m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="Cryptomator Linux Dev" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="cryptomator" />
|
||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="~/.config/Cryptomator-Dev/settings.json" -Dcryptomator.p12Path="~/.config/Cryptomator-Dev/key.p12" -Dcryptomator.ipcSocketPath="~/.config/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="~/.local/share/Cryptomator-Dev/logs" -Dcryptomator.pluginDir="~/.local/share/Cryptomator-Dev/plugins" -Dcryptomator.mountPointsDir="~/.local/share/Cryptomator-Dev/mnt" -Dcryptomator.showTrayIcon=true -Dfuse.experimental="true" -Xss20m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64" />
|
||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="@{userhome}/.config/Cryptomator-Dev/settings.json" -Dcryptomator.p12Path="@{userhome}/.config/Cryptomator-Dev/key.p12" -Dcryptomator.ipcSocketPath="@{userhome}/.config/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="@{userhome}/.local/share/Cryptomator-Dev/logs" -Dcryptomator.pluginDir="@{userhome}/.local/share/Cryptomator-Dev/plugins" -Dcryptomator.mountPointsDir="@{userhome}/.local/share/Cryptomator-Dev/mnt" -Dcryptomator.showTrayIcon=true -Dfuse.experimental="true" -Xss20m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
2
.idea/runConfigurations/Cryptomator_Windows.xml
generated
2
.idea/runConfigurations/Cryptomator_Windows.xml
generated
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="Cryptomator Windows" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="cryptomator" />
|
||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="~/AppData/Roaming/Cryptomator/settings.json" -Dcryptomator.ipcSocketPath="~/AppData/Roaming/Cryptomator/ipc.socket" -Dcryptomator.logDir="~/AppData/Roaming/Cryptomator" -Dcryptomator.pluginDir="~/AppData/Roaming/Cryptomator/Plugins" -Dcryptomator.integrationsWin.keychainPaths="~/AppData/Roaming/Cryptomator/keychain.json" -Dcryptomator.p12Path="~/AppData/Roaming/Cryptomator/key.p12" -Dcryptomator.mountPointsDir="~/Cryptomator" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.win" />
|
||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="@{appdata}/Cryptomator/settings.json;@{userhome}/AppData/Roaming/Cryptomator/settings.json" -Dcryptomator.ipcSocketPath="@{localappdata}/Cryptomator/ipc.socket" -Dcryptomator.logDir="@{localappdata}/Cryptomator" -Dcryptomator.pluginDir="@{appdata}/Cryptomator/Plugins" -Dcryptomator.integrationsWin.keychainPaths="@{appdata}/Cryptomator/keychain.json;@{userhome}/AppData/Roaming/Cryptomator/keychain.json" -Dcryptomator.p12Path="@{appdata}/Cryptomator/key.p12;@{userhome}/AppData/Roaming/Cryptomator/key.p12" -Dcryptomator.mountPointsDir="@{userhome}/Cryptomator" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.win" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="Cryptomator Windows Dev" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="cryptomator" />
|
||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="~/AppData/Roaming/Cryptomator-Dev/settings.json" -Dcryptomator.ipcSocketPath="~/AppData/Roaming/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="~/AppData/Roaming/Cryptomator-Dev" -Dcryptomator.pluginDir="~/AppData/Roaming/Cryptomator-Dev/Plugins" -Dcryptomator.integrationsWin.keychainPaths="~/AppData/Roaming/Cryptomator-Dev/keychain.json" -Dcryptomator.p12Path="~/AppData/Roaming/Cryptomator-Dev/key.p12" -Dcryptomator.mountPointsDir="~/Cryptomator-Dev" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.win" />
|
||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="@{appdata}/Cryptomator-Dev/settings.json;@{userhome}/AppData/Roaming/Cryptomator-Dev/settings.json" -Dcryptomator.ipcSocketPath="@{localappdata}/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="@{localappdata}/Cryptomator-Dev" -Dcryptomator.pluginDir="@{appdata}/Cryptomator-Dev/Plugins" -Dcryptomator.integrationsWin.keychainPaths="@{appdata}/Cryptomator-Dev/keychain.json;@{userhome}/AppData/Roaming/Cryptomator-Dev/keychain.json" -Dcryptomator.p12Path="@{appdata}/Cryptomator-Dev/key.p12;@{userhome}/AppData/Roaming/Cryptomator-Dev/key.p12" -Dcryptomator.mountPointsDir="@{userhome}/Cryptomator-Dev" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m --enable-preview --enable-native-access=org.cryptomator.jfuse.win" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
2
.idea/runConfigurations/Cryptomator_macOS.xml
generated
2
.idea/runConfigurations/Cryptomator_macOS.xml
generated
@@ -5,7 +5,7 @@
|
||||
</envs>
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="cryptomator" />
|
||||
<option name="VM_PARAMETERS" value="-Dapple.awt.enableTemplateImages=true -Dcryptomator.settingsPath="~/Library/Application Support/Cryptomator/settings.json" -Dcryptomator.p12Path="~/Library/Application Support/Cryptomator/key.p12" -Dcryptomator.ipcSocketPath="~/Library/Application Support/Cryptomator/ipc.socket" -Dcryptomator.logDir="~/Library/Logs/Cryptomator" -Dcryptomator.pluginDir="~/Library/Application Support/Cryptomator/Plugins" -Dcryptomator.mountPointsDir="~/Cryptomator" -Dcryptomator.showTrayIcon=true -Dcryptomator.integrationsMac.keychainServiceName=Cryptomator -Xss2m -Xmx512m -ea --enable-preview --enable-native-access=org.cryptomator.jfuse.mac" />
|
||||
<option name="VM_PARAMETERS" value="-Dapple.awt.enableTemplateImages=true -Dcryptomator.settingsPath="@{userhome}/Library/Application Support/Cryptomator/settings.json" -Dcryptomator.p12Path="@{userhome}/Library/Application Support/Cryptomator/key.p12" -Dcryptomator.ipcSocketPath="@{userhome}/Library/Application Support/Cryptomator/ipc.socket" -Dcryptomator.logDir="@{userhome}/Library/Logs/Cryptomator" -Dcryptomator.pluginDir="@{userhome}/Library/Application Support/Cryptomator/Plugins" -Dcryptomator.mountPointsDir="@{userhome}/Cryptomator" -Dcryptomator.showTrayIcon=true -Dcryptomator.integrationsMac.keychainServiceName=Cryptomator -Xss2m -Xmx512m -ea --enable-preview --enable-native-access=org.cryptomator.jfuse.mac" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
</envs>
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="cryptomator" />
|
||||
<option name="VM_PARAMETERS" value="-Dapple.awt.enableTemplateImages=true -Dcryptomator.settingsPath="~/Library/Application Support/Cryptomator-Dev/settings.json" -Dcryptomator.p12Path="~/Library/Application Support/Cryptomator-Dev/key.p12" -Dcryptomator.ipcSocketPath="~/Library/Application Support/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="~/Library/Logs/Cryptomator-Dev" -Dcryptomator.pluginDir="~/Library/Application Support/Cryptomator-Dev/Plugins" -Dcryptomator.mountPointsDir="~/Cryptomator" -Dcryptomator.showTrayIcon=true -Dcryptomator.integrationsMac.keychainServiceName=Cryptomator -Xss2m -Xmx512m -ea --enable-preview --enable-native-access=org.cryptomator.jfuse.mac" />
|
||||
<option name="VM_PARAMETERS" value="-Dapple.awt.enableTemplateImages=true -Dcryptomator.settingsPath="@{userhome}/Library/Application Support/Cryptomator-Dev/settings.json" -Dcryptomator.p12Path="@{userhome}/Library/Application Support/Cryptomator-Dev/key.p12" -Dcryptomator.ipcSocketPath="@{userhome}/Library/Application Support/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="@{userhome}/Library/Logs/Cryptomator-Dev" -Dcryptomator.pluginDir="@{userhome}/Library/Application Support/Cryptomator-Dev/Plugins" -Dcryptomator.mountPointsDir="@{userhome}/Library/Application Support/Cryptomator-Dev/mnt" -Dcryptomator.showTrayIcon=true -Dcryptomator.integrationsMac.keychainServiceName=Cryptomator -Xss2m -Xmx512m -ea --enable-preview --enable-native-access=org.cryptomator.jfuse.mac" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
@@ -30,9 +30,10 @@ Cryptomator is provided free of charge as an open-source project despite the hig
|
||||
<table>
|
||||
<tbody>
|
||||
<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="28"></a></td>
|
||||
<td><a href="https://www.easeus.com/"><img src="https://cryptomator.org/img/sponsors/easeus.png" alt="EaseUS" height="40"></a></td>
|
||||
<td><a href="https://www.hassmann-it-forensik.de/"><img src="https://cryptomator.org/img/sponsors/hassmannitforensik.png" alt="Hassmann IT-Forensik" height="40"></a></td>
|
||||
<td><a href="https://ente.io/"><img src="https://cryptomator.org/img/sponsors/ente.svg" alt="Ente" height="58"></a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -85,7 +86,7 @@ For more information on the security details visit [cryptomator.org](https://doc
|
||||
|
||||
### Dependencies
|
||||
|
||||
* JDK 19 (e.g. temurin)
|
||||
* JDK 21 (e.g. temurin, zulu)
|
||||
* Maven 3
|
||||
|
||||
### Run Maven
|
||||
|
||||
78
dist/linux/appimage/build.sh
vendored
78
dist/linux/appimage/build.sh
vendored
@@ -1,4 +1,5 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
cd $(dirname $0)
|
||||
REVISION_NO=`git rev-list --count HEAD`
|
||||
@@ -7,32 +8,62 @@ REVISION_NO=`git rev-list --count HEAD`
|
||||
if [ -z "${JAVA_HOME}" ]; then echo "JAVA_HOME not set. Run using JAVA_HOME=/path/to/jdk ./build.sh"; exit 1; fi
|
||||
command -v mvn >/dev/null 2>&1 || { echo >&2 "mvn not found."; exit 1; }
|
||||
command -v curl >/dev/null 2>&1 || { echo >&2 "curl not found."; exit 1; }
|
||||
command -v unzip >/dev/null 2>&1 || { echo >&2 "unzip not found."; exit 1; }
|
||||
|
||||
VERSION=$(mvn -f ../../../pom.xml help:evaluate -Dexpression=project.version -q -DforceStdout)
|
||||
SEMVER_STR=${VERSION}
|
||||
MACHINE_TYPE=$(uname -m)
|
||||
|
||||
if [[ ! "${MACHINE_TYPE}" =~ x86_64|aarch64 ]]; then echo "Platform ${MACHINE_TYPE} not supported"; exit 1; fi
|
||||
|
||||
mvn -f ../../../pom.xml versions:set -DnewVersion=${SEMVER_STR}
|
||||
|
||||
# compile
|
||||
mvn -B -f ../../../pom.xml clean package -Plinux -DskipTests
|
||||
cp ../../../LICENSE.txt ../../../target
|
||||
cp ../launcher.sh ../../../target
|
||||
cp ../../../target/cryptomator-*.jar ../../../target/mods
|
||||
|
||||
|
||||
# download javaFX jmods
|
||||
OPENJFX_URL='https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_linux-x64_bin-jmods.zip'
|
||||
OPENJFX_SHA='7baed11ca56d5fee85995fa6612d4299f1e8b7337287228f7f12fd50407c56f8'
|
||||
OPENJFX_URL_aarch64='https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_linux-aarch64_bin-jmods.zip'
|
||||
OPENJFX_SHA_aarch64='871e7b9d7af16aef2e55c1b7830d0e0b2503b13dd8641374ba7e55ecb81d2ef9'
|
||||
|
||||
if [[ "${MACHINE_TYPE}" = "aarch64" ]]; then
|
||||
OPENJFX_URL="${OPENJFX_URL_aarch64}";
|
||||
OPENJFX_SHA="${OPENJFX_SHA_aarch64}";
|
||||
fi
|
||||
|
||||
curl -L ${OPENJFX_URL} -o openjfx-jmods.zip
|
||||
echo "${OPENJFX_SHA} openjfx-jmods.zip" | shasum -a256 --check
|
||||
mkdir -p openjfx-jmods
|
||||
unzip -o -j openjfx-jmods.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d openjfx-jmods
|
||||
JMOD_VERSION=$(jmod describe ./openjfx-jmods/javafx.base.jmod | head -1)
|
||||
JMOD_VERSION=${JMOD_VERSION#*@}
|
||||
JMOD_VERSION=${JMOD_VERSION%%.*}
|
||||
POM_JFX_VERSION=$(mvn help:evaluate "-Dexpression=javafx.version" -q -DforceStdout -B -f ../../../pom.xml)
|
||||
POM_JFX_VERSION=${POM_JFX_VERSION#*@}
|
||||
POM_JFX_VERSION=${POM_JFX_VERSION%%.*}
|
||||
if [ $POM_JFX_VERSION -ne $JMOD_VERSION ]; then
|
||||
>&2 echo "Major JavaFX version in pom.xml (${POM_JFX_VERSION}) != amd64 jmod version (${JMOD_VERSION})"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# add runtime
|
||||
${JAVA_HOME}/bin/jlink \
|
||||
--verbose \
|
||||
--output runtime \
|
||||
--module-path "${JAVA_HOME}/jmods" \
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.security.auth,jdk.accessibility,jdk.management.jfr \
|
||||
--module-path "${JAVA_HOME}/jmods:openjfx-jmods" \
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.security.auth,jdk.accessibility,jdk.management.jfr,jdk.net \
|
||||
--strip-native-commands \
|
||||
--no-header-files \
|
||||
--no-man-pages \
|
||||
--strip-debug \
|
||||
--compress=1
|
||||
--compress zip-0
|
||||
|
||||
# create app dir
|
||||
envsubst '${SEMVER_STR} ${REVISION_NUM}' < ../launcher-gtk2.properties > launcher-gtk2.properties
|
||||
${JAVA_HOME}/bin/jpackage \
|
||||
--verbose \
|
||||
--type app-image \
|
||||
@@ -44,21 +75,22 @@ ${JAVA_HOME}/bin/jpackage \
|
||||
--name Cryptomator \
|
||||
--vendor "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 "--enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator" \
|
||||
--copyright "(C) 2016 - 2024 Skymatic GmbH" \
|
||||
--java-options "-Xss5m" \
|
||||
--java-options "-Xmx256m" \
|
||||
--app-version "${VERSION}.${REVISION_NO}" \
|
||||
--java-options "-Dfile.encoding=\"utf-8\"" \
|
||||
--java-options "-Dcryptomator.logDir=\"~/.local/share/Cryptomator/logs\"" \
|
||||
--java-options "-Dcryptomator.pluginDir=\"~/.local/share/Cryptomator/plugins\"" \
|
||||
--java-options "-Dcryptomator.settingsPath=\"~/.config/Cryptomator/settings.json:~/.Cryptomator/settings.json\"" \
|
||||
--java-options "-Dcryptomator.p12Path=\"~/.config/Cryptomator/key.p12\"" \
|
||||
--java-options "-Dcryptomator.ipcSocketPath=\"~/.config/Cryptomator/ipc.socket\"" \
|
||||
--java-options "-Dcryptomator.mountPointsDir=\"~/.local/share/Cryptomator/mnt\"" \
|
||||
--java-options "-Dcryptomator.showTrayIcon=false" \
|
||||
--java-options "-Djava.net.useSystemProxies=true" \
|
||||
--java-options "-Dcryptomator.logDir=\"@{userhome}/.local/share/Cryptomator/logs\"" \
|
||||
--java-options "-Dcryptomator.pluginDir=\"@{userhome}/.local/share/Cryptomator/plugins\"" \
|
||||
--java-options "-Dcryptomator.settingsPath=\"@{userhome}/.config/Cryptomator/settings.json:@{userhome}/.Cryptomator/settings.json\"" \
|
||||
--java-options "-Dcryptomator.p12Path=\"@{userhome}/.config/Cryptomator/key.p12\"" \
|
||||
--java-options "-Dcryptomator.ipcSocketPath=\"@{userhome}/.config/Cryptomator/ipc.socket\"" \
|
||||
--java-options "-Dcryptomator.mountPointsDir=\"@{userhome}/.local/share/Cryptomator/mnt\"" \
|
||||
--java-options "-Dcryptomator.showTrayIcon=true" \
|
||||
--java-options "-Dcryptomator.integrationsLinux.trayIconsDir=\"@{appdir}/usr/share/icons/hicolor/symbolic/apps\"" \
|
||||
--java-options "-Dcryptomator.buildNumber=\"appimage-${REVISION_NO}\"" \
|
||||
--add-launcher cryptomator-gtk2=launcher-gtk2.properties \
|
||||
--resource-dir ../resources
|
||||
|
||||
# transform AppDir
|
||||
@@ -68,6 +100,10 @@ envsubst '${REVISION_NO}' < resources/AppDir/bin/cryptomator.sh > Cryptomator.Ap
|
||||
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.Cryptomator.svg Cryptomator.AppDir/usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.svg
|
||||
cp ../common/org.cryptomator.Cryptomator.tray.svg Cryptomator.AppDir/usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.tray.svg
|
||||
cp ../common/org.cryptomator.Cryptomator.tray-unlocked.svg Cryptomator.AppDir/usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.tray-unlocked.svg
|
||||
cp ../common/org.cryptomator.Cryptomator.tray.svg Cryptomator.AppDir/usr/share/icons/hicolor/symbolic/apps/org.cryptomator.Cryptomator.tray-symbolic.svg
|
||||
cp ../common/org.cryptomator.Cryptomator.tray-unlocked.svg Cryptomator.AppDir/usr/share/icons/hicolor/symbolic/apps/org.cryptomator.Cryptomator.tray-unlocked-symbolic.svg
|
||||
cp ../common/org.cryptomator.Cryptomator.desktop Cryptomator.AppDir/usr/share/applications/org.cryptomator.Cryptomator.desktop
|
||||
cp ../common/org.cryptomator.Cryptomator.metainfo.xml Cryptomator.AppDir/usr/share/metainfo/org.cryptomator.Cryptomator.metainfo.xml
|
||||
cp ../common/application-vnd.cryptomator.vault.xml Cryptomator.AppDir/usr/share/mime/packages/application-vnd.cryptomator.vault.xml
|
||||
@@ -78,17 +114,17 @@ ln -s usr/share/applications/org.cryptomator.Cryptomator.desktop Cryptomator.App
|
||||
ln -s bin/cryptomator.sh Cryptomator.AppDir/AppRun
|
||||
|
||||
# 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-${MACHINE_TYPE}.AppImage -o /tmp/appimagetool.AppImage
|
||||
chmod +x /tmp/appimagetool.AppImage
|
||||
|
||||
# create AppImage
|
||||
/tmp/appimagetool.AppImage \
|
||||
Cryptomator.AppDir \
|
||||
cryptomator-${SEMVER_STR}-x86_64.AppImage \
|
||||
-u 'gh-releases-zsync|cryptomator|cryptomator|latest|cryptomator-*-x86_64.AppImage.zsync'
|
||||
cryptomator-${SEMVER_STR}-${MACHINE_TYPE}.AppImage \
|
||||
-u 'gh-releases-zsync|cryptomator|cryptomator|latest|cryptomator-*-${MACHINE_TYPE}.AppImage.zsync'
|
||||
|
||||
echo ""
|
||||
echo "Done. AppImage successfully created: cryptomator-${SEMVER_STR}-x86_64.AppImage"
|
||||
echo "Done. AppImage successfully created: cryptomator-${SEMVER_STR}-${MACHINE_TYPE}.AppImage"
|
||||
echo ""
|
||||
echo >&2 "To clean up, run: rm -rf Cryptomator.AppDir appdir runtime squashfs-root openjfx-jmods; rm /tmp/appimagetool.AppImage openjfx-jmods.zip"
|
||||
echo ""
|
||||
echo >&2 "To clean up, run: rm -rf Cryptomator.AppDir appdir jni runtime squashfs-root; rm launcher-gtk2.properties /tmp/appimagetool.AppImage"
|
||||
echo ""
|
||||
0
dist/linux/appimage/resources/AppDir/usr/share/icons/hicolor/symbolic/apps/.gitkeep
vendored
Normal file
0
dist/linux/appimage/resources/AppDir/usr/share/icons/hicolor/symbolic/apps/.gitkeep
vendored
Normal file
@@ -5,26 +5,27 @@
|
||||
<metadata_license>FSFAP</metadata_license>
|
||||
<project_license>GPL-3.0-or-later</project_license>
|
||||
<name>Cryptomator</name>
|
||||
<summary>Multi-platform client-side encryption tool optimized for cloud storages</summary>
|
||||
<summary>Encryption made easy and optimized for the cloud</summary>
|
||||
|
||||
<description>
|
||||
<p>
|
||||
Cryptomator provides transparent, client-side encryption for your cloud. Protect your documents from unauthorized
|
||||
access. Cryptomator is free and open source software, so you can rest assured there are no backdoors.
|
||||
Cryptomator provides easy-to-use, transparent, client-side encryption for your cloud.
|
||||
It protects your documents from unauthorized access and prying eyes, while you will still be able to view and edit your documents locally.
|
||||
By not requiring any registration or account and performing all encryption locally, it gives you back control over your data and ensures your privacy.
|
||||
Cryptomator is offered for all major platforms (including Android and iOS).
|
||||
</p>
|
||||
<p>
|
||||
Cryptomator encrypts file contents and names using AES. Your passphrase is protected against bruteforcing attempts
|
||||
using scrypt. Directory structures get obfuscated. The only thing which cannot be encrypted without breaking your
|
||||
cloud synchronization is the modification date of your files.
|
||||
Cryptomator encrypts file contents and names using the widespread industry standard AES.
|
||||
Your passphrase is protected against brute forcing attempts using scrypt.
|
||||
Additionally, directory structures get obfuscated.
|
||||
For more info about the Cryptomator encryption scheme, check out the online documentation.
|
||||
</p>
|
||||
<p>
|
||||
Cryptomator is a free and open source software licensed under the GPLv3. This allows anyone to check our code. It
|
||||
is impossible to introduce backdoors for third parties. Also we cannot hide vulnerabilities. And the best thing
|
||||
is: There is no need to trust us, as you can control us!
|
||||
</p>
|
||||
<p>
|
||||
Vendor lock-ins are impossible. Even if we decided to stop development: The source code is already cloned by
|
||||
hundreds of other developers. As you don't need an account, you will never stand in front of locked doors.
|
||||
Cryptomator is a free and open-source software licensed under the GPLv3.
|
||||
This allows anyone to check our code.
|
||||
Thus, it is impossible to introduce backdoors for third parties or to hide vulnerabilities, so you do not need to trust Cryptomator.
|
||||
Also, vendor lock-ins are impossible.
|
||||
Even if we decided to stop development: The source code is already cloned by hundreds of other developers and development can be picked up by others.
|
||||
</p>
|
||||
</description>
|
||||
|
||||
@@ -42,7 +43,7 @@
|
||||
</provides>
|
||||
|
||||
<screenshots>
|
||||
<screenshot>
|
||||
<screenshot type="default">
|
||||
<caption>Light theme</caption>
|
||||
<image>https://user-images.githubusercontent.com/11858409/156986109-6e58f59c-8b8c-4501-b33b-bb1e33007cea.png</image>
|
||||
</screenshot>
|
||||
@@ -56,37 +57,108 @@
|
||||
<url type="bugtracker">https://github.com/cryptomator/cryptomator/issues/</url>
|
||||
<url type="donation">https://cryptomator.org/donate</url>
|
||||
<url type="faq">https://community.cryptomator.org/c/kb/faq</url>
|
||||
<url type="help">https://community.cryptomator.org/</url>
|
||||
<url type="help">https://docs.cryptomator.org/</url>
|
||||
<url type="translate">https://translate.cryptomator.org</url>
|
||||
|
||||
<developer_name>Skymatic GmbH</developer_name>
|
||||
<developer id="de.skymatic">
|
||||
<name>Skymatic GmbH</name>
|
||||
</developer>
|
||||
|
||||
|
||||
<content_rating type="oars-1.1">
|
||||
<content_attribute id="social-info">mild</content_attribute> <!-- update checker connects to https://api.cryptomator.org/updates/latestVersion.json -->
|
||||
</content_rating>
|
||||
|
||||
<releases>
|
||||
<release date="2023-08-11" version="1.9.4"/>
|
||||
<release date="2023-08-07" version="1.9.3"/>
|
||||
<release date="2023-07-24" version="1.9.2"/>
|
||||
<release date="2023-06-07" version="1.9.1"/>
|
||||
<release date="2023-05-30" version="1.9.0"/>
|
||||
<release date="2023-04-25" version="1.8.0"/>
|
||||
<release date="2023-04-07" version="1.7.5"/>
|
||||
<release date="2023-04-05" version="1.7.4"/>
|
||||
<release date="2023-03-15" version="1.7.3"/>
|
||||
<release date="2023-03-07" version="1.7.2"/>
|
||||
<release date="2023-03-03" version="1.7.1"/>
|
||||
<release date="2023-03-01" version="1.7.0"/>
|
||||
<release date="2022-12-14" version="1.6.17"/>
|
||||
<release date="2022-12-06" version="1.6.16"/>
|
||||
<release date="2022-10-06" version="1.6.15"/>
|
||||
<release date="2022-08-31" version="1.6.14"/>
|
||||
<release date="2022-07-27" version="1.6.12"/>
|
||||
<release date="2022-07-26" version="1.6.11"/>
|
||||
<release date="2022-05-03" version="1.6.10"/>
|
||||
<release date="2022-04-27" version="1.6.9"/>
|
||||
<release date="2022-03-30" version="1.6.8"/>
|
||||
<release date="2021-12-16" version="1.6.5"/>
|
||||
<release date="2024-02-27" version="1.12.3">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.12.3</url>
|
||||
</release>
|
||||
<release date="2024-02-09" version="1.12.2">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.12.2</url>
|
||||
</release>
|
||||
<release date="2024-02-07" version="1.12.1">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.12.1</url>
|
||||
</release>
|
||||
<release date="2024-02-06" version="1.12.0">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.12.0</url>
|
||||
</release>
|
||||
<release date="2023-12-05" version="1.11.1">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.11.1</url>
|
||||
</release>
|
||||
<release date="2023-11-08" version="1.11.0">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.11.0</url>
|
||||
</release>
|
||||
<release date="2023-09-20" version="1.10.1">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.10.1</url>
|
||||
</release>
|
||||
<release date="2023-09-11" version="1.10.0">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.10.0</url>
|
||||
</release>
|
||||
<release date="2023-08-11" version="1.9.4">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.9.4</url>
|
||||
</release>
|
||||
<release date="2023-08-07" version="1.9.3">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.9.3</url>
|
||||
</release>
|
||||
<release date="2023-07-24" version="1.9.2">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.9.2</url>
|
||||
</release>
|
||||
<release date="2023-06-07" version="1.9.1">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.9.1</url>
|
||||
</release>
|
||||
<release date="2023-05-30" version="1.9.0">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.9.0</url>
|
||||
</release>
|
||||
<release date="2023-04-25" version="1.8.0">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.8.0</url>
|
||||
</release>
|
||||
<release date="2023-04-07" version="1.7.5">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.7.5</url>
|
||||
</release>
|
||||
<release date="2023-04-05" version="1.7.4">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.7.4</url>
|
||||
</release>
|
||||
<release date="2023-03-15" version="1.7.3">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.7.3</url>
|
||||
</release>
|
||||
<release date="2023-03-07" version="1.7.2">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.7.2</url>
|
||||
</release>
|
||||
<release date="2023-03-03" version="1.7.1">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.7.1</url>
|
||||
</release>
|
||||
<release date="2023-03-01" version="1.7.0">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.7.0</url>
|
||||
</release>
|
||||
<release date="2022-12-14" version="1.6.17">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.6.17</url>
|
||||
</release>
|
||||
<release date="2022-12-06" version="1.6.16">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.6.16</url>
|
||||
</release>
|
||||
<release date="2022-10-06" version="1.6.15">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.6.15</url>
|
||||
</release>
|
||||
<release date="2022-08-31" version="1.6.14">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.6.14</url>
|
||||
</release>
|
||||
<release date="2022-07-27" version="1.6.12">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.6.12</url>
|
||||
</release>
|
||||
<release date="2022-07-26" version="1.6.11">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.6.11</url>
|
||||
</release>
|
||||
<release date="2022-05-03" version="1.6.10">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.6.10</url>
|
||||
</release>
|
||||
<release date="2022-04-27" version="1.6.9">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.6.9</url>
|
||||
</release>
|
||||
<release date="2022-03-30" version="1.6.8">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.6.8</url>
|
||||
</release>
|
||||
<release date="2021-12-16" version="1.6.5">
|
||||
<url type="details">https://github.com/cryptomator/cryptomator/releases/1.6.5</url>
|
||||
</release>
|
||||
</releases>
|
||||
</component>
|
||||
|
||||
12
dist/linux/common/org.cryptomator.Cryptomator.tray-unlocked.svg
vendored
Normal file
12
dist/linux/common/org.cryptomator.Cryptomator.tray-unlocked.svg
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
<svg height="16" viewBox="0 0 42 42" width="16" xmlns="http://www.w3.org/2000/svg">
|
||||
<style
|
||||
id="current-color-scheme" type="text/css">
|
||||
.ColorScheme-Text {
|
||||
color:#232629;
|
||||
}
|
||||
</style>
|
||||
<g fill-rule="evenodd" style="fill:#f2f2f2;fill-opacity:1" class="ColorScheme-Text" fill="currentColor">
|
||||
<path d="m15.591 35.824c-.019.009-.936.775-1.458 1.208a.418.418 0 0 1 -.627-.111 9.322 9.322 0 0 1 -.3-5.974 15.843 15.843 0 0 0 2.894 2.043c.051 1.03-.161 2.644-.509 2.834zm6.409-6.824h-2l.5-5a2 2 0 1 1 1 0zm-14.544-3.241.744-1.366a1.579 1.579 0 0 0 -.019-1.557l.653-1.2c.2.014-.03-.113.165-.14.051-.217-.051-.336 0-.5a3.269 3.269 0 0 0 0-1.5 7.151 7.151 0 0 1 0-3 2.366 2.366 0 0 0 -2.378 1.448 2.409 2.409 0 0 0 .229 2.661l-.7 1.278a1.779 1.779 0 0 0 -1.317.891l-.741 1.372a1.577 1.577 0 0 0 -.019 1.487 3.028 3.028 0 0 0 -2.746 1.525 2.648 2.648 0 0 0 .044 2.631.748.748 0 0 0 .981.266.656.656 0 0 0 .284-.92 1.37 1.37 0 0 1 -.023-1.361 1.6 1.6 0 0 1 2.079-.63 1.408 1.408 0 0 1 .672 1.95 1.546 1.546 0 0 1 -1.2.78.688.688 0 0 0 -.636.749.707.707 0 0 0 .717.6.789.789 0 0 0 .082 0 2.989 2.989 0 0 0 2.322-1.513 2.669 2.669 0 0 0 -.377-3.084 1.767 1.767 0 0 0 1.184-.867zm13.544-10.759a13.013 13.013 0 0 1 5-1 21.6 21.6 0 0 1 4.5.5 9.312 9.312 0 0 0 -9.5-8.5c-5.794 0-9.176 4-9.5 8.5a21.858 21.858 0 0 1 4.5-.5 12.819 12.819 0 0 1 5 1zm3.5-5c1.209 0 2.5.866 2.5 2h-5c0-1.134 1.291-2 2.5-2zm-7 0c1.209 0 2.5.866 2.5 2h-5c0-1.134 1.291-2 2.5-2zm14.473 6a8.067 8.067 0 0 0 -8.08 8v2.141a3.891 3.891 0 0 0 -2.893 3.734v5.125a23.166 23.166 0 0 1 -4.174-1.623 7.857 7.857 0 0 1 -.027.878 3.263 3.263 0 0 1 -.729 2.074l-1.794 1.483a.379.379 0 0 1 -.276.188h-4c-1.324 0-2.346-1.336-2.653-3.343a7.058 7.058 0 0 1 .234-3.18 3.477 3.477 0 0 1 1.636-2.157 1.868 1.868 0 0 1 .783-.32h1.5a8.035 8.035 0 0 1 -1.5-5 11.1 11.1 0 0 1 .5-3 2.519 2.519 0 0 0 0-1.5 13.272 13.272 0 0 1 -.5-3.5c6.687-1.936 11 0 11 0s4.319-1.955 11 0"/>
|
||||
<path d="m39 28h-10v-4a3.13 3.13 0 0 1 3-3 3.087 3.087 0 0 1 3 3v1a1.034 1.034 0 0 0 1 1h1a1.034 1.034 0 0 0 1-1v-1a6 6 0 0 0 -12 0v4h-1a2.073 2.073 0 0 0 -2 2v6a2.073 2.073 0 0 0 2 2h14a2.073 2.073 0 0 0 2-2v-6a2.073 2.073 0 0 0 -2-2zm-5.391 5.94a1.609 1.609 0 0 1 -3.217 0v-1.876a1.609 1.609 0 0 1 3.217 0z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.2 KiB |
8
dist/linux/common/org.cryptomator.Cryptomator.tray.svg
vendored
Normal file
8
dist/linux/common/org.cryptomator.Cryptomator.tray.svg
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg height="16" viewBox="0 0 42 42" width="16" xmlns="http://www.w3.org/2000/svg">
|
||||
<style id="current-color-scheme" type="text/css">
|
||||
.ColorScheme-Text {
|
||||
color:#232629;
|
||||
}
|
||||
</style>
|
||||
<path d="m32.66 29.319a1.432 1.432 0 0 0 -.66-.319h-1.5a8.125 8.125 0 0 0 1.5-5 11.027 11.027 0 0 0 -.5-3 2.519 2.519 0 0 1 0-1.5 12.987 12.987 0 0 0 .5-3.5c-6.681-1.955-11 0-11 0s-4.313-1.936-11 0a13.272 13.272 0 0 0 .5 3.5 2.519 2.519 0 0 1 0 1.5 11.1 11.1 0 0 0 -.5 3 8.035 8.035 0 0 0 1.5 5h-1.5a1.868 1.868 0 0 0 -.783.319 3.477 3.477 0 0 0 -1.636 2.157 7.058 7.058 0 0 0 -.234 3.18c.307 2.008 1.329 3.344 2.653 3.344h4a.379.379 0 0 0 .277-.187l1.793-1.483a3.263 3.263 0 0 0 .729-2.074 7.857 7.857 0 0 0 .027-.878 23.166 23.166 0 0 0 4.174 1.622 24.4 24.4 0 0 0 4.051-1.614 7.848 7.848 0 0 0 .027.869 3.263 3.263 0 0 0 .729 2.074l1.793 1.484a.61.61 0 0 0 .4.187h4c1.324 0 2.223-1.336 2.529-3.343a7.057 7.057 0 0 0 -.234-3.18 3.477 3.477 0 0 0 -1.635-2.158zm-17.069 6.5c-.019.009-.936.775-1.458 1.208a.418.418 0 0 1 -.627-.111 9.322 9.322 0 0 1 -.3-5.974 15.843 15.843 0 0 0 2.894 2.048c.051 1.03-.161 2.644-.509 2.834zm6.409-6.819h-2l.5-5a2 2 0 1 1 1 0zm6.38 7.921a.418.418 0 0 1 -.627.111c-.522-.433-1.439-1.2-1.458-1.208-.348-.189-.56-1.8-.505-2.828a15.84 15.84 0 0 0 2.9-2.037 9.322 9.322 0 0 1 -.31 5.962zm-20.924-11.162.744-1.366a1.579 1.579 0 0 0 -.019-1.557l.653-1.2c.2.014-.03-.113.165-.14.051-.217-.051-.336 0-.5a3.269 3.269 0 0 0 0-1.5 7.151 7.151 0 0 1 0-3 2.366 2.366 0 0 0 -2.378 1.448 2.409 2.409 0 0 0 .229 2.661l-.7 1.278a1.779 1.779 0 0 0 -1.317.891l-.741 1.372a1.577 1.577 0 0 0 -.019 1.487 3.028 3.028 0 0 0 -2.746 1.525 2.648 2.648 0 0 0 .044 2.631.748.748 0 0 0 .981.266.656.656 0 0 0 .284-.92 1.37 1.37 0 0 1 -.023-1.361 1.6 1.6 0 0 1 2.079-.63 1.408 1.408 0 0 1 .672 1.95 1.546 1.546 0 0 1 -1.2.78.688.688 0 0 0 -.636.749.707.707 0 0 0 .717.6.789.789 0 0 0 .082 0 2.989 2.989 0 0 0 2.322-1.513 2.669 2.669 0 0 0 -.377-3.084 1.767 1.767 0 0 0 1.184-.867zm33.217 1.2a3.021 3.021 0 0 0 -2.658-1.525 1.574 1.574 0 0 0 -.107-1.283l-.745-1.367a1.779 1.779 0 0 0 -1.317-.891l-.7-1.278a2.409 2.409 0 0 0 .229-2.661 2.283 2.283 0 0 0 -2.375-1.454 7.039 7.039 0 0 1 0 3 3.272 3.272 0 0 0 0 1.5c.047.152-.047.3 0 .5.227.04-.069.156.165.14l.653 1.2a1.579 1.579 0 0 0 -.019 1.557l.745 1.367a1.753 1.753 0 0 0 1.045.832 2.66 2.66 0 0 0 -.238 2.916 2.989 2.989 0 0 0 2.326 1.509.79.79 0 0 0 .082 0 .707.707 0 0 0 .717-.6.688.688 0 0 0 -.636-.749 1.546 1.546 0 0 1 -1.2-.78 1.408 1.408 0 0 1 .672-1.95 1.628 1.628 0 0 1 1.179-.089 1.512 1.512 0 0 1 .9.719 1.37 1.37 0 0 1 -.023 1.361.656.656 0 0 0 .284.92.748.748 0 0 0 .981-.266 2.648 2.648 0 0 0 .04-2.633zm-19.673-11.959a13.013 13.013 0 0 1 5-1 21.6 21.6 0 0 1 4.5.5 9.312 9.312 0 0 0 -9.5-8.5c-5.794 0-9.176 4-9.5 8.5a21.858 21.858 0 0 1 4.5-.5 12.819 12.819 0 0 1 5 1zm3.5-5c1.209 0 2.5.866 2.5 2h-5c0-1.134 1.291-2 2.5-2zm-7 0c1.209 0 2.5.866 2.5 2h-5c0-1.134 1.291-2 2.5-2z" fill-rule="evenodd" style="fill:#f2f2f2;fill-opacity:1" class="ColorScheme-Text" fill="currentColor"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
2
dist/linux/debian/control
vendored
2
dist/linux/debian/control
vendored
@@ -2,7 +2,7 @@ Source: cryptomator
|
||||
Maintainer: Cryptobot <releases@cryptomator.org>
|
||||
Section: utils
|
||||
Priority: optional
|
||||
Build-Depends: debhelper (>=10), coffeelibs-jdk-20, libgtk2.0-0, libgtk-3-0, libxxf86vm1, libgl1
|
||||
Build-Depends: debhelper (>=10), coffeelibs-jdk-21 (>= 21.0.2+12-0ppa1), libgtk-3-0, libxxf86vm1, libgl1
|
||||
Standards-Version: 4.5.0
|
||||
Homepage: https://cryptomator.org
|
||||
Vcs-Git: https://github.com/cryptomator/cryptomator.git
|
||||
|
||||
4
dist/linux/debian/copyright
vendored
4
dist/linux/debian/copyright
vendored
@@ -4,11 +4,11 @@ Upstream-Contact: Cryptomator <info@cryptomator.org>
|
||||
Source: https://cryptomator.org
|
||||
|
||||
Files: *
|
||||
Copyright: 2016-2023 Skymatic GmbH
|
||||
Copyright: 2016-2024 Skymatic GmbH
|
||||
License: GPL-3+
|
||||
|
||||
Files: debian/org.cryptomator.Cryptomator.appdata.xml
|
||||
Copyright: 2016-2023 Skymatic GmbH
|
||||
Copyright: 2016-2024 Skymatic GmbH
|
||||
License: FSFAP
|
||||
|
||||
License: GPL-3+
|
||||
|
||||
2
dist/linux/debian/cryptomator.install
vendored
2
dist/linux/debian/cryptomator.install
vendored
@@ -1,6 +1,8 @@
|
||||
cryptomator usr/lib
|
||||
common/org.cryptomator.Cryptomator.desktop usr/share/applications
|
||||
common/org.cryptomator.Cryptomator.svg usr/share/icons/hicolor/scalable/apps
|
||||
common/org.cryptomator.Cryptomator.tray.svg usr/share/icons/hicolor/scalable/apps
|
||||
common/org.cryptomator.Cryptomator.tray-unlocked.svg usr/share/icons/hicolor/scalable/apps
|
||||
common/org.cryptomator.Cryptomator256.png usr/share/icons/hicolor/256x256/apps
|
||||
common/org.cryptomator.Cryptomator512.png usr/share/icons/hicolor/512x512/apps
|
||||
common/org.cryptomator.Cryptomator.metainfo.xml usr/share/metainfo
|
||||
|
||||
2
dist/linux/debian/cryptomator.links
vendored
2
dist/linux/debian/cryptomator.links
vendored
@@ -1 +1,3 @@
|
||||
usr/lib/cryptomator/bin/cryptomator usr/bin/cryptomator
|
||||
usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.tray.svg usr/share/icons/hicolor/symbolic/apps/org.cryptomator.Cryptomator.tray-symbolic.svg
|
||||
usr/share/icons/hicolor/scalable/apps/org.cryptomator.Cryptomator.tray-unlocked.svg usr/share/icons/hicolor/symbolic/apps/org.cryptomator.Cryptomator.tray-unlocked-symbolic.svg
|
||||
28
dist/linux/debian/rules
vendored
28
dist/linux/debian/rules
vendored
@@ -4,7 +4,7 @@
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
JAVA_HOME = /usr/lib/jvm/java-20-coffeelibs
|
||||
JAVA_HOME = /usr/lib/jvm/java-21-coffeelibs
|
||||
DEB_BUILD_ARCH ?= $(shell dpkg-architecture -qDEB_BUILD_ARCH)
|
||||
ifeq ($(DEB_BUILD_ARCH),amd64)
|
||||
JMODS_PATH = jmods/amd64:${JAVA_HOME}/jmods
|
||||
@@ -24,15 +24,16 @@ override_dh_auto_clean:
|
||||
override_dh_auto_build:
|
||||
mkdir resources
|
||||
ln -s ../common/org.cryptomator.Cryptomator512.png resources/cryptomator.png
|
||||
# Remark: no compression is applied for improved build compression later (here deb)
|
||||
$(JAVA_HOME)/bin/jlink \
|
||||
--output runtime \
|
||||
--module-path "${JMODS_PATH}" \
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.security.auth,jdk.accessibility,jdk.management.jfr \
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.security.auth,jdk.accessibility,jdk.management.jfr,jdk.net \
|
||||
--strip-native-commands \
|
||||
--no-header-files \
|
||||
--no-man-pages \
|
||||
--strip-debug \
|
||||
--compress=2
|
||||
--compress zip-0
|
||||
$(JAVA_HOME)/bin/jpackage \
|
||||
--type app-image \
|
||||
--runtime-image runtime \
|
||||
@@ -43,20 +44,23 @@ override_dh_auto_build:
|
||||
--name cryptomator \
|
||||
--vendor "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 "--enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator" \
|
||||
--copyright "(C) 2016 - 2024 Skymatic GmbH" \
|
||||
--java-options "-Xss5m" \
|
||||
--java-options "-Xmx256m" \
|
||||
--java-options "-Dfile.encoding=\"utf-8\"" \
|
||||
--java-options "-Dcryptomator.logDir=\"~/.local/share/Cryptomator/logs\"" \
|
||||
--java-options "-Dcryptomator.pluginDir=\"~/.local/share/Cryptomator/plugins\"" \
|
||||
--java-options "-Dcryptomator.settingsPath=\"~/.config/Cryptomator/settings.json:~/.Cryptomator/settings.json\"" \
|
||||
--java-options "-Dcryptomator.p12Path=\"~/.config/Cryptomator/key.p12\"" \
|
||||
--java-options "-Dcryptomator.ipcSocketPath=\"~/.config/Cryptomator/ipc.socket\"" \
|
||||
--java-options "-Dcryptomator.mountPointsDir=\"~/.local/share/Cryptomator/mnt\"" \
|
||||
--java-options "-Dcryptomator.showTrayIcon=false" \
|
||||
--java-options "-Djava.net.useSystemProxies=true" \
|
||||
--java-options "-Dcryptomator.logDir=\"@{userhome}/.local/share/Cryptomator/logs\"" \
|
||||
--java-options "-Dcryptomator.pluginDir=\"@{userhome}/.local/share/Cryptomator/plugins\"" \
|
||||
--java-options "-Dcryptomator.settingsPath=\"@{userhome}/.config/Cryptomator/settings.json:@{userhome}/.Cryptomator/settings.json\"" \
|
||||
--java-options "-Dcryptomator.p12Path=\"@{userhome}/.config/Cryptomator/key.p12\"" \
|
||||
--java-options "-Dcryptomator.ipcSocketPath=\"@{userhome}/.config/Cryptomator/ipc.socket\"" \
|
||||
--java-options "-Dcryptomator.mountPointsDir=\"@{userhome}/.local/share/Cryptomator/mnt\"" \
|
||||
--java-options "-Dcryptomator.showTrayIcon=true" \
|
||||
--java-options "-Dcryptomator.integrationsLinux.trayIconsDir=\"/usr/share/icons/hicolor/symbolic/apps\"" \
|
||||
--java-options "-Dcryptomator.buildNumber=\"deb-${REVISION_NUM}\"" \
|
||||
--java-options "-Dcryptomator.appVersion=\"${SEMVER_STR}\"" \
|
||||
--java-options "-Dcryptomator.disableUpdateCheck=\"${DISABLE_UPDATE_CHECK}\"" \
|
||||
--app-version "${VERSION_NUM}.${REVISION_NUM}" \
|
||||
--resource-dir resources \
|
||||
--verbose
|
||||
|
||||
14
dist/linux/launcher-gtk2.properties
vendored
14
dist/linux/launcher-gtk2.properties
vendored
@@ -1,14 +0,0 @@
|
||||
java-options=-Xss5m \
|
||||
-Xmx256m \
|
||||
--enable-preview \
|
||||
--enable-native-access=org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64 \
|
||||
-Dfile.encoding=\"utf-8\" \
|
||||
-Dcryptomator.appVersion=\"${SEMVER_STR}\" \
|
||||
-Dcryptomator.logDir=\"~/.local/share/Cryptomator/logs\" \
|
||||
-Dcryptomator.pluginDir=\"~/.local/share/Cryptomator/plugins\" \
|
||||
-Dcryptomator.settingsPath=\"~/.config/Cryptomator/settings.json:~/.Cryptomator/settings.json\" \
|
||||
-Dcryptomator.ipcSocketPath=\"~/.config/Cryptomator/ipc.socket\" \
|
||||
-Dcryptomator.mountPointsDir=\"~/.local/share/Cryptomator/mnt\" \
|
||||
-Dcryptomator.showTrayIcon=false \
|
||||
-Dcryptomator.buildNumber=\"appimage-${REVISION_NUM}\" \
|
||||
-Djdk.gtk.version=2
|
||||
47
dist/mac/dmg/build.sh
vendored
47
dist/mac/dmg/build.sh
vendored
@@ -21,7 +21,7 @@ rm -rf runtime dmg *.app *.dmg
|
||||
# set variables
|
||||
APP_NAME="Cryptomator"
|
||||
VENDOR="Skymatic GmbH"
|
||||
COPYRIGHT_YEARS="2016 - 2023"
|
||||
COPYRIGHT_YEARS="2016 - 2024"
|
||||
PACKAGE_IDENTIFIER="org.cryptomator"
|
||||
MAIN_JAR_GLOB="cryptomator-*.jar"
|
||||
MODULE_AND_MAIN_CLASS="org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator"
|
||||
@@ -29,6 +29,14 @@ REVISION_NO=`git rev-list --count HEAD`
|
||||
VERSION_NO=`mvn -f../../../pom.xml help:evaluate -Dexpression=project.version -q -DforceStdout | sed -rn 's/.*([0-9]+\.[0-9]+\.[0-9]+).*/\1/p'`
|
||||
FUSE_LIB="FUSE-T"
|
||||
|
||||
ARCH="undefined"
|
||||
if [ "$(machine)" = "arm64e" ]; then
|
||||
ARCH="aarch64"
|
||||
else
|
||||
ARCH="x64"
|
||||
fi
|
||||
OPENJFX_JMODS="https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_osx-${ARCH}_bin-jmods.zip"
|
||||
|
||||
# check preconditions
|
||||
if [ -z "${JAVA_HOME}" ]; then echo "JAVA_HOME not set. Run using JAVA_HOME=/path/to/jdk ./build.sh"; exit 1; fi
|
||||
command -v mvn >/dev/null 2>&1 || { echo >&2 "mvn not found. Fix by 'brew install maven'."; exit 1; }
|
||||
@@ -38,20 +46,37 @@ if [ -n "${CODESIGN_IDENTITY}" ]; then
|
||||
if [[ ! `security find-identity -v -p codesigning | grep -w "${CODESIGN_IDENTITY}"` ]]; then echo "Given codesign identity is invalid."; exit 1; fi
|
||||
fi
|
||||
|
||||
# download and check jmods
|
||||
curl -L ${OPENJFX_JMODS} -o openjfx-jmods.zip
|
||||
mkdir -p openjfx-jmods/
|
||||
unzip -jo openjfx-jmods.zip \*/javafx.base.jmod \*/javafx.controls.jmod \*/javafx.fxml.jmod \*/javafx.graphics.jmod -d openjfx-jmods
|
||||
JMOD_VERSION=$(jmod describe openjfx-jmods/javafx.base.jmod | head -1)
|
||||
JMOD_VERSION=${JMOD_VERSION#*@}
|
||||
JMOD_VERSION=${JMOD_VERSION%%.*}
|
||||
POM_JFX_VERSION=$(mvn -f../../../pom.xml help:evaluate "-Dexpression=javafx.version" -q -DforceStdout)
|
||||
POM_JFX_VERSION=${POM_JFX_VERSION#*@}
|
||||
POM_JFX_VERSION=${POM_JFX_VERSION%%.*}
|
||||
|
||||
if [ "${POM_JFX_VERSION}" -ne "${JMOD_VERSION}" ]; then
|
||||
>&2 echo "Major JavaFX version in pom.xml (${POM_JFX_VERSION}) != jmod version (${JMOD_VERSION})"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# compile
|
||||
mvn -B -f../../../pom.xml clean package -DskipTests -Pmac
|
||||
cp ../../../LICENSE.txt ../../../target
|
||||
cp ../../../target/${MAIN_JAR_GLOB} ../../../target/mods
|
||||
|
||||
# add runtime
|
||||
${JAVA_HOME}/bin/jlink \
|
||||
--output runtime \
|
||||
--module-path "${JAVA_HOME}/jmods" \
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr \
|
||||
--module-path "${JAVA_HOME}/jmods:openjfx-jmods" \
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,javafx.base,javafx.graphics,javafx.controls,javafx.fxml,jdk.unsupported,jdk.crypto.ec,jdk.security.auth,jdk.accessibility,jdk.management.jfr \
|
||||
--strip-native-commands \
|
||||
--no-header-files \
|
||||
--no-man-pages \
|
||||
--strip-debug \
|
||||
--compress=1
|
||||
--compress zip-0
|
||||
|
||||
# create app dir
|
||||
${JAVA_HOME}/bin/jpackage \
|
||||
@@ -71,16 +96,17 @@ ${JAVA_HOME}/bin/jpackage \
|
||||
--java-options "-Xss5m" \
|
||||
--java-options "-Xmx256m" \
|
||||
--java-options "-Dfile.encoding=\"utf-8\"" \
|
||||
--java-options "-Djava.net.useSystemProxies=true" \
|
||||
--java-options "-Dapple.awt.enableTemplateImages=true" \
|
||||
--java-options "-Dsun.java2d.metal=true" \
|
||||
--java-options "-Dcryptomator.appVersion=\"${VERSION_NO}\"" \
|
||||
--java-options "-Dcryptomator.logDir=\"~/Library/Logs/${APP_NAME}\"" \
|
||||
--java-options "-Dcryptomator.pluginDir=\"~/Library/Application Support/${APP_NAME}/Plugins\"" \
|
||||
--java-options "-Dcryptomator.settingsPath=\"~/Library/Application Support/${APP_NAME}/settings.json\"" \
|
||||
--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.logDir=\"@{userhome}/Library/Logs/${APP_NAME}\"" \
|
||||
--java-options "-Dcryptomator.pluginDir=\"@{userhome}/Library/Application Support/${APP_NAME}/Plugins\"" \
|
||||
--java-options "-Dcryptomator.settingsPath=\"@{userhome}/Library/Application Support/${APP_NAME}/settings.json\"" \
|
||||
--java-options "-Dcryptomator.ipcSocketPath=\"@{userhome}/Library/Application Support/${APP_NAME}/ipc.socket\"" \
|
||||
--java-options "-Dcryptomator.p12Path=\"@{userhome}/Library/Application Support/${APP_NAME}/key.p12\"" \
|
||||
--java-options "-Dcryptomator.integrationsMac.keychainServiceName=\"${APP_NAME}\"" \
|
||||
--java-options "-Dcryptomator.mountPointsDir=\"~/${APP_NAME}\"" \
|
||||
--java-options "-Dcryptomator.mountPointsDir=\"@{userhome}/Library/Application Support${APP_NAME}/mnt\"" \
|
||||
--java-options "-Dcryptomator.showTrayIcon=true" \
|
||||
--java-options "-Dcryptomator.buildNumber=\"dmg-${REVISION_NO}\"" \
|
||||
--mac-package-identifier ${PACKAGE_IDENTIFIER} \
|
||||
@@ -143,6 +169,5 @@ create-dmg \
|
||||
--app-drop-link 512 245 \
|
||||
--eula "resources/license.rtf" \
|
||||
--icon ".background" 128 758 \
|
||||
--icon ".fseventsd" 320 758 \
|
||||
--icon ".VolumeIcon.icns" 512 758 \
|
||||
${APP_NAME}-${VERSION_NO}.dmg dmg
|
||||
|
||||
2
dist/mac/dmg/resources/licenseTemplate.ftl
vendored
2
dist/mac/dmg/resources/licenseTemplate.ftl
vendored
@@ -17,7 +17,7 @@
|
||||
\f1\b0 \
|
||||
\
|
||||
|
||||
\f0\b \'a9 2016 \'96 2023 Skymatic GmbH
|
||||
\f0\b \'a9 2016 \'96 2024 Skymatic GmbH
|
||||
\f1\b0 \
|
||||
\
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\
|
||||
|
||||
BIN
dist/mac/resources/Cryptomator.icns
vendored
BIN
dist/mac/resources/Cryptomator.icns
vendored
Binary file not shown.
2
dist/mac/resources/Info.plist
vendored
2
dist/mac/resources/Info.plist
vendored
@@ -3,7 +3,7 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.13.0</string>
|
||||
<string>11</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleAllowMixedLocalizations</key>
|
||||
|
||||
2
dist/win/.gitignore
vendored
2
dist/win/.gitignore
vendored
@@ -4,4 +4,6 @@ installer
|
||||
*.wixobj
|
||||
*.pdb
|
||||
*.msi
|
||||
*.exe
|
||||
*.jmod
|
||||
license.rtf
|
||||
2
dist/win/build.bat
vendored
2
dist/win/build.bat
vendored
@@ -11,7 +11,7 @@ SET HELP_URL="https://cryptomator.org/contact/"
|
||||
SET MODULE_AND_MAIN_CLASS="org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator"
|
||||
SET LOOPBACK_ALIAS="cryptomator-vault"
|
||||
|
||||
powershell -NoLogo -ExecutionPolicy Unrestricted -Command .\build.ps1^
|
||||
powershell -NoLogo -NoProfile -ExecutionPolicy Unrestricted -Command .\build.ps1^
|
||||
-AppName %APPNAME%^
|
||||
-MainJarGlob "%MAIN_JAR_GLOB%"^
|
||||
-ModuleAndMainClass "%MODULE_AND_MAIN_CLASS%"^
|
||||
|
||||
56
dist/win/build.ps1
vendored
56
dist/win/build.ps1
vendored
@@ -12,6 +12,9 @@ Param(
|
||||
[bool] $clean
|
||||
)
|
||||
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
$ProgressPreference = 'SilentlyContinue' # disables Invoke-WebRequest's progress bar, which slows down downloads to a few bytes/s
|
||||
|
||||
# check preconditions
|
||||
if ((Get-Command "git" -ErrorAction SilentlyContinue) -eq $null)
|
||||
{
|
||||
@@ -26,7 +29,7 @@ if ((Get-Command "mvn" -ErrorAction SilentlyContinue) -eq $null)
|
||||
|
||||
$buildDir = Split-Path -Parent $PSCommandPath
|
||||
$version = $(mvn -f $buildDir/../../pom.xml help:evaluate -Dexpression="project.version" -q -DforceStdout)
|
||||
$semVerNo = $version -replace '(\d\.\d\.\d).*','$1'
|
||||
$semVerNo = $version -replace '(\d+\.\d+\.\d+).*','$1'
|
||||
$revisionNo = $(git rev-list --count HEAD)
|
||||
|
||||
Write-Output "`$version=$version"
|
||||
@@ -47,16 +50,36 @@ if ($clean -and (Test-Path -Path $runtimeImagePath)) {
|
||||
Remove-Item -Path $runtimeImagePath -Force -Recurse
|
||||
}
|
||||
|
||||
## download jfx jmods
|
||||
$jmodsVersion='21.0.1'
|
||||
$jmodsUrl = "https://download2.gluonhq.com/openjfx/${jmodsVersion}/openjfx-${jmodsVersion}_windows-x64_bin-jmods.zip"
|
||||
$jfxJmodsChecksum = 'daf8acae631c016c24cfe23f88469400274d3441dd890615a42dfb501f3eb94a'
|
||||
$jfxJmodsZip = '.\resources\jfxJmods.zip'
|
||||
if( !(Test-Path -Path $jfxJmodsZip) ) {
|
||||
Write-Output "Downloading ${jmodsUrl}..."
|
||||
Invoke-WebRequest $jmodsUrl -OutFile $jfxJmodsZip # redirects are followed by default
|
||||
}
|
||||
|
||||
$jmodsChecksumActual = $(Get-FileHash -Path $jfxJmodsZip -Algorithm SHA256).Hash
|
||||
if( $jmodsChecksumActual -ne $jfxJmodsChecksum ) {
|
||||
Write-Error "Checksum mismatch for jfxJmods.zip. Expected: $jfxJmodsChecksum, actual: $jmodsChecksumActual"
|
||||
exit 1;
|
||||
}
|
||||
Expand-Archive -Path $jfxJmodsZip -Force -DestinationPath ".\resources\"
|
||||
Remove-Item -Recurse -Force -Path ".\resources\javafx-jmods"
|
||||
Move-Item -Force -Path ".\resources\javafx-jmods-*" -Destination ".\resources\javafx-jmods" -ErrorAction Stop
|
||||
|
||||
## create custom runtime
|
||||
& "$Env:JAVA_HOME\bin\jlink" `
|
||||
--verbose `
|
||||
--output runtime `
|
||||
--module-path "$Env:JAVA_HOME/jmods" `
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr `
|
||||
--module-path "$Env:JAVA_HOME/jmods;$buildDir/resources/javafx-jmods" `
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr,javafx.base,javafx.graphics,javafx.controls,javafx.fxml `
|
||||
--strip-native-commands `
|
||||
--no-header-files `
|
||||
--no-man-pages `
|
||||
--strip-debug `
|
||||
--compress=1
|
||||
--compress "zip-0" #do not compress to have improved msi compression
|
||||
|
||||
$appPath = ".\$AppName"
|
||||
if ($clean -and (Test-Path -Path $appPath)) {
|
||||
@@ -82,15 +105,16 @@ if ($clean -and (Test-Path -Path $appPath)) {
|
||||
--java-options "-Dcryptomator.appVersion=`"$semVerNo`"" `
|
||||
--app-version "$semVerNo.$revisionNo" `
|
||||
--java-options "-Dfile.encoding=`"utf-8`"" `
|
||||
--java-options "-Dcryptomator.logDir=`"~/AppData/Roaming/$AppName`"" `
|
||||
--java-options "-Dcryptomator.pluginDir=`"~/AppData/Roaming/$AppName/Plugins`"" `
|
||||
--java-options "-Dcryptomator.settingsPath=`"~/AppData/Roaming/$AppName/settings.json`"" `
|
||||
--java-options "-Dcryptomator.ipcSocketPath=`"~/AppData/Roaming/$AppName/ipc.socket`"" `
|
||||
--java-options "-Dcryptomator.p12Path=`"~/AppData/Roaming/$AppName/key.p12`"" `
|
||||
--java-options "-Dcryptomator.mountPointsDir=`"~/$AppName`"" `
|
||||
--java-options "-Djava.net.useSystemProxies=true" `
|
||||
--java-options "-Dcryptomator.logDir=`"@{localappdata}/$AppName`"" `
|
||||
--java-options "-Dcryptomator.pluginDir=`"@{appdata}/$AppName/Plugins`"" `
|
||||
--java-options "-Dcryptomator.settingsPath=`"@{appdata}/$AppName/settings.json;@{userhome}/AppData/Roaming/$AppName/settings.json`"" `
|
||||
--java-options "-Dcryptomator.ipcSocketPath=`"@{localappdata}/$AppName/ipc.socket`"" `
|
||||
--java-options "-Dcryptomator.p12Path=`"@{appdata}/$AppName/key.p12;@{userhome}/AppData/Roaming/$AppName/key.p12`"" `
|
||||
--java-options "-Dcryptomator.mountPointsDir=`"@{userhome}/$AppName`"" `
|
||||
--java-options "-Dcryptomator.loopbackAlias=`"$LoopbackAlias`"" `
|
||||
--java-options "-Dcryptomator.integrationsWin.autoStartShellLinkName=`"$AppName`"" `
|
||||
--java-options "-Dcryptomator.integrationsWin.keychainPaths=`"~/AppData/Roaming/$AppName/keychain.json`"" `
|
||||
--java-options "-Dcryptomator.integrationsWin.keychainPaths=`"@{appdata}/$AppName/keychain.json;@{userhome}/AppData/Roaming/$AppName/keychain.json`"" `
|
||||
--java-options "-Dcryptomator.showTrayIcon=true" `
|
||||
--java-options "-Dcryptomator.buildNumber=`"msi-$revisionNo`"" `
|
||||
--resource-dir resources `
|
||||
@@ -120,6 +144,7 @@ try {
|
||||
|
||||
# create .msi
|
||||
$Env:JP_WIXWIZARD_RESOURCES = "$buildDir\resources"
|
||||
$Env:JP_WIXHELPER_DIR = "."
|
||||
& "$Env:JAVA_HOME\bin\jpackage" `
|
||||
--verbose `
|
||||
--type msi `
|
||||
@@ -151,12 +176,15 @@ $Env:JP_WIXWIZARD_RESOURCES = "$buildDir\resources"
|
||||
"-Dlicense.licenseMergesUrl=file:///$buildDir/../../license/merges"
|
||||
|
||||
# download Winfsp
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
$ProgressPreference = 'SilentlyContinue' # disables Invoke-WebRequest's progress bar, which slows down downloads to a few bytes/s
|
||||
$winfspMsiUrl= (Select-String -Path ".\bundle\resources\winFspMetaData.wxi" -Pattern '<\?define BundledWinFspDownloadLink="(.+)".*?>').Matches.Groups[1].Value
|
||||
$winfspMsiUrl= 'https://github.com/winfsp/winfsp/releases/download/v2.0/winfsp-2.0.23075.msi'
|
||||
Write-Output "Downloading ${winfspMsiUrl}..."
|
||||
Invoke-WebRequest $winfspMsiUrl -OutFile ".\bundle\resources\winfsp.msi" # redirects are followed by default
|
||||
|
||||
# download legacy-winfsp uninstaller
|
||||
$winfspUninstaller= 'https://github.com/cryptomator/winfsp-uninstaller/releases/latest/download/winfsp-uninstaller.exe'
|
||||
Write-Output "Downloading ${winfspUninstaller}..."
|
||||
Invoke-WebRequest $winfspUninstaller -OutFile ".\bundle\resources\winfsp-uninstaller.exe" # redirects are followed by default
|
||||
|
||||
# copy MSI to bundle resources
|
||||
Copy-Item ".\installer\$AppName-*.msi" -Destination ".\bundle\resources\$AppName.msi"
|
||||
|
||||
|
||||
45
dist/win/bundle/bundleWithWinfsp.wxs
vendored
45
dist/win/bundle/bundleWithWinfsp.wxs
vendored
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!-- For Built in variables, see https://wixtoolset.org/docs/tools/burn/builtin-variables/-->
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:bal="http://schemas.microsoft.com/wix/BalExtension" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
|
||||
<!-- see https://wixtoolset.org/documentation/manual/v3/xsd/wix/bundle.html-->
|
||||
<!-- Attributes explicitly not used:
|
||||
@@ -10,21 +11,10 @@
|
||||
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"
|
||||
Variable="InstalledLegacyWinFspVersion"
|
||||
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>
|
||||
UpgradeCode="82F812D9-4083-4EF1-8BC8-0F1EDA05B46B"/>
|
||||
|
||||
<!-- for definition of the standard themes, see https://github.com/wixtoolset/wix3/blob/master/src/ext/BalExtension/wixstdba/Resources/-->
|
||||
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLargeLicense">
|
||||
@@ -36,26 +26,41 @@
|
||||
SuppressOptionsUI="yes"
|
||||
ThemeFile="bundle\customBootstrapperTheme.xml"
|
||||
LocalizationFile="bundle\customBootstrapperTheme.wxl"
|
||||
LogoFile="bundle\resources\logo.png"
|
||||
/>
|
||||
LogoFile="bundle\resources\logo.png"/>
|
||||
<Payload SourceFile="bundle\resources\logoSide.png" />
|
||||
</BootstrapperApplicationRef>
|
||||
|
||||
<Chain>
|
||||
<ExePackage Cache="yes" PerMachine="yes" Permanent="no"
|
||||
SourceFile="resources\winfsp-uninstaller.exe"
|
||||
DisplayName="Removing outdated WinFsp Driver"
|
||||
Description="Executable to remove old winfsp"
|
||||
DetectCondition="false"
|
||||
InstallCondition="(InstalledLegacyWinFspVersion <> v0.0.0.0) AND ((WixBundleAction = 7) OR (WixBundleAction = 5))">
|
||||
<CommandLine Condition="WixBundleUILevel <= 3" InstallArgument="-q -l "[WixBundleLog].winfsp-uninstaller.log"" RepairArgument="-q" UninstallArgument="-s" />
|
||||
<!-- XML allows line breaks in attributes, hence keep the line breaks here -->
|
||||
<CommandLine Condition="WixBundleUILevel > 3" InstallArgument="-l "[WixBundleLog].winfsp-uninstaller.log" -t "Cryptomator Installer" -m "Cryptomator requires a newer version of the WinFsp driver. The installer will now uninstall WinFsp, possibly reboot, and afterwards proceed with the installation.
|
||||
|
||||
Do you want to continue?"" RepairArgument="-q" UninstallArgument="-s" />
|
||||
<ExitCode Behavior="success" Value="0"/>
|
||||
<ExitCode Behavior="success" Value="1"/>
|
||||
<ExitCode Behavior="error" Value="2"/>
|
||||
<ExitCode Behavior="error" Value="3"/>
|
||||
<ExitCode Behavior="forceReboot" Value="4"/>
|
||||
<ExitCode Behavior="success" Value="5"/>
|
||||
</ExePackage>
|
||||
<!-- see https://wixtoolset.org/documentation/manual/v3/xsd/wix/msipackage.html-->
|
||||
<MsiPackage
|
||||
SourceFile="resources\Cryptomator.msi"
|
||||
CacheId="cryptomator-bundle-cryptomator"
|
||||
DisplayInternalUI="no"
|
||||
Visible="no"
|
||||
/>
|
||||
Visible="no"/>
|
||||
<MsiPackage
|
||||
SourceFile="resources\winfsp.msi"
|
||||
CacheId="cryptomator-bundle-winfsp"
|
||||
Visible="yes"
|
||||
DisplayInternalUI="no"
|
||||
Vital="no"
|
||||
Permanent="yes"
|
||||
/>
|
||||
Permanent="yes"/>
|
||||
</Chain>
|
||||
</Bundle>
|
||||
</Wix>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
\vieww12000\viewh15840\viewkind0
|
||||
\pard\tx283\tx567\tx850\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\b\fs16\lang7 Cryptomator is distributed under the GPLv3 License, found below. Please see the bottom of this document for any other license applicable to code used within Cryptomator.\b0\par
|
||||
\par
|
||||
\b\'a9 2016 \'96 2023 Skymatic GmbH \b0\par
|
||||
\b\'a9 2016 \'96 2024 Skymatic GmbH \b0\par
|
||||
\par
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\par
|
||||
\par
|
||||
|
||||
7
dist/win/bundle/resources/winFspMetaData.wxi
vendored
7
dist/win/bundle/resources/winFspMetaData.wxi
vendored
@@ -1,7 +0,0 @@
|
||||
<?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>
|
||||
2
dist/win/contrib/patchWebDAV.bat
vendored
2
dist/win/contrib/patchWebDAV.bat
vendored
@@ -3,5 +3,5 @@
|
||||
::REPLACE ME
|
||||
|
||||
cd %~dp0
|
||||
powershell -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command .\patchWebDAV.ps1^
|
||||
powershell -NoLogo -NoProfile -NonInteractive -ExecutionPolicy RemoteSigned -Command .\patchWebDAV.ps1^
|
||||
-LoopbackAlias %LOOPBACK_ALIAS%
|
||||
@@ -2,4 +2,4 @@
|
||||
:: see comments in file ./version170-migrate-settings.ps1
|
||||
|
||||
cd %~dp0
|
||||
powershell -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command .\version170-migrate-settings.ps1
|
||||
powershell -NoLogo -NoProfile -NonInteractive -ExecutionPolicy RemoteSigned -Command .\version170-migrate-settings.ps1
|
||||
|
||||
2
dist/win/resources/licenseTemplate.ftl
vendored
2
dist/win/resources/licenseTemplate.ftl
vendored
@@ -10,7 +10,7 @@
|
||||
\vieww12000\viewh15840\viewkind0
|
||||
\pard\tx283\tx567\tx850\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\b\fs16\lang7 Cryptomator is distributed under the GPLv3 License, found below. Please see the bottom of this document for any other license applicable to code used within Cryptomator.\b0\par
|
||||
\par
|
||||
\b\'a9 2016 \'96 2023 Skymatic GmbH \b0\par
|
||||
\b\'a9 2016 \'96 2024 Skymatic GmbH \b0\par
|
||||
\par
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\par
|
||||
\par
|
||||
|
||||
2
dist/win/resources/main.wxs
vendored
2
dist/win/resources/main.wxs
vendored
@@ -70,7 +70,7 @@
|
||||
<CustomAction Id="JpDisallowDowngrade" Error="!(loc.DowngradeErrorMessage)" />
|
||||
<?endif?>
|
||||
|
||||
<Binary Id="JpCaDll" SourceFile="wixhelper.dll"/>
|
||||
<Binary Id="JpCaDll" SourceFile="$(env.JP_WIXHELPER_DIR)\wixhelper.dll"/>
|
||||
<CustomAction Id="JpFindRelatedProducts" BinaryKey="JpCaDll" DllEntry="FindRelatedProductsEx" />
|
||||
|
||||
<?ifndef SkipCryptomatorLegacyCheck ?>
|
||||
|
||||
101
pom.xml
101
pom.xml
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>cryptomator</artifactId>
|
||||
<version>1.9.4</version>
|
||||
<version>1.12.3</version>
|
||||
<name>Cryptomator Desktop App</name>
|
||||
|
||||
<organization>
|
||||
@@ -26,45 +26,52 @@
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.jdk.version>20</project.jdk.version>
|
||||
<project.jdk.version>21</project.jdk.version>
|
||||
|
||||
<!-- Group IDs of jars that need to stay on the class path for now -->
|
||||
<!-- Once hypfvieh, swiesend, purejava and integrations-linux have module-info, remove them-->
|
||||
<nonModularGroupIds>org.ow2.asm,org.apache.jackrabbit,org.apache.httpcomponents,de.swiesend,org.purejava,com.github.hypfvieh</nonModularGroupIds>
|
||||
<!-- remove them, as soon they got modularized or support is dropped (i.e., WebDAV) -->
|
||||
<nonModularGroupIds>org.ow2.asm,org.apache.jackrabbit,org.apache.httpcomponents</nonModularGroupIds>
|
||||
|
||||
<!-- cryptomator dependencies -->
|
||||
<cryptomator.cryptofs.version>2.6.5</cryptomator.cryptofs.version>
|
||||
<cryptomator.integrations.version>1.2.0</cryptomator.integrations.version>
|
||||
<cryptomator.integrations.win.version>1.2.0</cryptomator.integrations.win.version>
|
||||
<cryptomator.integrations.mac.version>1.2.0</cryptomator.integrations.mac.version>
|
||||
<cryptomator.integrations.linux.version>1.2.1</cryptomator.integrations.linux.version>
|
||||
<cryptomator.fuse.version>3.0.0</cryptomator.fuse.version>
|
||||
<cryptomator.cryptofs.version>2.6.9</cryptomator.cryptofs.version>
|
||||
<cryptomator.integrations.version>1.3.1</cryptomator.integrations.version>
|
||||
<cryptomator.integrations.win.version>1.2.5</cryptomator.integrations.win.version>
|
||||
<cryptomator.integrations.mac.version>1.2.3</cryptomator.integrations.mac.version>
|
||||
<cryptomator.integrations.linux.version>1.4.4</cryptomator.integrations.linux.version>
|
||||
<cryptomator.fuse.version>4.0.0</cryptomator.fuse.version>
|
||||
<cryptomator.dokany.version>2.0.0</cryptomator.dokany.version>
|
||||
<cryptomator.webdav.version>2.0.3</cryptomator.webdav.version>
|
||||
<cryptomator.webdav.version>2.0.6</cryptomator.webdav.version>
|
||||
|
||||
<!-- 3rd party dependencies -->
|
||||
<commons-lang3.version>3.12.0</commons-lang3.version>
|
||||
<dagger.version>2.45</dagger.version>
|
||||
<commons-lang3.version>3.14.0</commons-lang3.version>
|
||||
<dagger.version>2.50</dagger.version>
|
||||
<easybind.version>2.2</easybind.version>
|
||||
<guava.version>32.0.0-jre</guava.version>
|
||||
<gson.version>2.10.1</gson.version>
|
||||
<javafx.version>20.0.1</javafx.version>
|
||||
<guava.version>33.0.0-jre</guava.version>
|
||||
<jackson.version>2.16.1</jackson.version>
|
||||
<javafx.version>21.0.1</javafx.version>
|
||||
<jwt.version>4.4.0</jwt.version>
|
||||
<nimbus-jose.version>9.31</nimbus-jose.version>
|
||||
<logback.version>1.4.7</logback.version>
|
||||
<slf4j.version>2.0.7</slf4j.version>
|
||||
<tinyoauth2.version>0.5.1</tinyoauth2.version>
|
||||
<zxcvbn.version>1.7.0</zxcvbn.version>
|
||||
<nimbus-jose.version>9.37.3</nimbus-jose.version>
|
||||
<logback.version>1.5.0</logback.version>
|
||||
<slf4j.version>2.0.12</slf4j.version>
|
||||
<tinyoauth2.version>0.8.0</tinyoauth2.version>
|
||||
<zxcvbn.version>1.8.2</zxcvbn.version>
|
||||
|
||||
<!-- test dependencies -->
|
||||
<junit.jupiter.version>5.9.3</junit.jupiter.version>
|
||||
<mockito.version>5.3.1</mockito.version>
|
||||
<junit.jupiter.version>5.10.2</junit.jupiter.version>
|
||||
<mockito.version>5.10.0</mockito.version>
|
||||
<hamcrest.version>2.2</hamcrest.version>
|
||||
|
||||
<!-- build-time dependencies -->
|
||||
<jetbrains.annotations.version>23.0.0</jetbrains.annotations.version>
|
||||
<dependency-check.version>8.1.2</dependency-check.version>
|
||||
<jacoco.version>0.8.9</jacoco.version>
|
||||
<jetbrains.annotations.version>24.1.0</jetbrains.annotations.version>
|
||||
<dependency-check.version>9.0.9</dependency-check.version>
|
||||
<jacoco.version>0.8.11</jacoco.version>
|
||||
<license-generator.version>2.4.0</license-generator.version>
|
||||
<junit-tree-reporter.version>1.2.1</junit-tree-reporter.version>
|
||||
<mvn-compiler.version>3.12.1</mvn-compiler.version>
|
||||
<mvn-resources.version>3.3.1</mvn-resources.version>
|
||||
<mvn-dependency.version>3.6.1</mvn-dependency.version>
|
||||
<mvn-surefire.version>3.2.5</mvn-surefire.version>
|
||||
<mvn-jar.version>3.3.0</mvn-jar.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -157,6 +164,11 @@
|
||||
<artifactId>nimbus-jose-jwt</artifactId>
|
||||
<version>${nimbus-jose.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- EasyBind -->
|
||||
<dependency>
|
||||
@@ -206,11 +218,6 @@
|
||||
<artifactId>dagger</artifactId>
|
||||
<version>${dagger.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>${gson.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JUnit / Mockito / Hamcrest -->
|
||||
<dependency>
|
||||
@@ -240,7 +247,7 @@
|
||||
<dependency>
|
||||
<groupId>com.google.jimfs</groupId>
|
||||
<artifactId>jimfs</artifactId>
|
||||
<version>1.2</version>
|
||||
<version>1.3.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -258,32 +265,32 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.10.1</version>
|
||||
<version>${mvn-compiler.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>${mvn-resources.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>${mvn-dependency.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.0.0-M7</version>
|
||||
<version>${mvn-surefire.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<version>${license-generator.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>${mvn-jar.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
@@ -332,8 +339,22 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>me.fabriciorby</groupId>
|
||||
<artifactId>maven-surefire-junit5-tree-reporter</artifactId>
|
||||
<version>${junit-tree-reporter.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<configuration>
|
||||
<argLine>--enable-preview</argLine>
|
||||
<reportFormat>plain</reportFormat>
|
||||
<consoleOutputReporter>
|
||||
<disable>true</disable>
|
||||
</consoleOutputReporter>
|
||||
<statelessTestsetInfoReporter
|
||||
implementation="org.apache.maven.plugin.surefire.extensions.junit5.JUnit5StatelessTestsetInfoTreeReporter">
|
||||
</statelessTestsetInfoReporter>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
@@ -439,17 +460,19 @@
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<configuration>
|
||||
<cveValidForHours>24</cveValidForHours>
|
||||
<nvdValidForHours>24</nvdValidForHours>
|
||||
<failBuildOnCVSS>0</failBuildOnCVSS>
|
||||
<skipTestScope>true</skipTestScope>
|
||||
<detail>true</detail>
|
||||
<suppressionFile>suppression.xml</suppressionFile>
|
||||
<nvdApiKey>${env.NVD_API_KEY}</nvdApiKey>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
<phase>validate</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
@@ -5,6 +5,7 @@ import org.cryptomator.common.locationpresets.DropboxWindowsLocationPresetsProvi
|
||||
import org.cryptomator.common.locationpresets.GoogleDriveLocationPresetsProvider;
|
||||
import org.cryptomator.common.locationpresets.ICloudMacLocationPresetsProvider;
|
||||
import org.cryptomator.common.locationpresets.ICloudWindowsLocationPresetsProvider;
|
||||
import org.cryptomator.common.locationpresets.LeitzcloudLocationPresetsProvider;
|
||||
import org.cryptomator.common.locationpresets.LocationPresetsProvider;
|
||||
import org.cryptomator.common.locationpresets.MegaLocationPresetsProvider;
|
||||
import org.cryptomator.common.locationpresets.OneDriveLinuxLocationPresetsProvider;
|
||||
@@ -37,7 +38,7 @@ open module org.cryptomator.desktop {
|
||||
requires ch.qos.logback.core;
|
||||
requires com.auth0.jwt;
|
||||
requires com.google.common;
|
||||
requires com.google.gson;
|
||||
requires com.fasterxml.jackson.databind;
|
||||
requires com.nimbusds.jose.jwt;
|
||||
requires com.nulabinc.zxcvbn;
|
||||
requires com.tobiasdiez.easybind;
|
||||
@@ -53,11 +54,12 @@ open module org.cryptomator.desktop {
|
||||
|
||||
provides TrayMenuController with AwtTrayMenuController;
|
||||
provides Configurator with LogbackConfiguratorFactory;
|
||||
provides LocationPresetsProvider with DropboxMacLocationPresetsProvider, //
|
||||
DropboxWindowsLocationPresetsProvider, DropboxLinuxLocationPresetsProvider, //
|
||||
ICloudMacLocationPresetsProvider, ICloudWindowsLocationPresetsProvider, //
|
||||
provides LocationPresetsProvider with //
|
||||
DropboxWindowsLocationPresetsProvider, DropboxMacLocationPresetsProvider, DropboxLinuxLocationPresetsProvider, //
|
||||
GoogleDriveLocationPresetsProvider, //
|
||||
PCloudLocationPresetsProvider, MegaLocationPresetsProvider, //
|
||||
OneDriveLinuxLocationPresetsProvider, OneDriveWindowsLocationPresetsProvider, //
|
||||
OneDriveMacLocationPresetsProvider;
|
||||
ICloudWindowsLocationPresetsProvider, ICloudMacLocationPresetsProvider, //
|
||||
LeitzcloudLocationPresetsProvider, //
|
||||
MegaLocationPresetsProvider, //
|
||||
OneDriveWindowsLocationPresetsProvider, OneDriveMacLocationPresetsProvider, OneDriveLinuxLocationPresetsProvider, //
|
||||
PCloudLocationPresetsProvider;
|
||||
}
|
||||
@@ -5,10 +5,8 @@
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.common;
|
||||
|
||||
import com.tobiasdiez.easybind.EasyBind;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.keychain.KeychainModule;
|
||||
import org.cryptomator.common.mount.MountModule;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
@@ -22,8 +20,6 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Comparator;
|
||||
@@ -136,13 +132,4 @@ public abstract class CommonsModule {
|
||||
LOG.error("Uncaught exception in " + thread.getName(), throwable);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static ObservableValue<InetSocketAddress> provideServerSocketAddressBinding(Settings settings) {
|
||||
return settings.port().map(port -> {
|
||||
String host = SystemUtils.IS_OS_WINDOWS ? "127.0.0.1" : "localhost";
|
||||
return InetSocketAddress.createUnresolved(host, settings.port().intValue());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.cryptomator.common;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
import org.jetbrains.annotations.VisibleForTesting;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -18,8 +19,6 @@ import java.util.stream.StreamSupport;
|
||||
public class Environment {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Environment.class);
|
||||
private static final Path RELATIVE_HOME_DIR = Paths.get("~");
|
||||
private static final char PATH_LIST_SEP = ':';
|
||||
private static final int DEFAULT_MIN_PW_LENGTH = 8;
|
||||
private static final String SETTINGS_PATH_PROP_NAME = "cryptomator.settingsPath";
|
||||
private static final String IPC_SOCKET_PATH_PROP_NAME = "cryptomator.ipcSocketPath";
|
||||
@@ -33,6 +32,7 @@ public class Environment {
|
||||
private static final String BUILD_NUMBER_PROP_NAME = "cryptomator.buildNumber";
|
||||
private static final String PLUGIN_DIR_PROP_NAME = "cryptomator.pluginDir";
|
||||
private static final String TRAY_ICON_PROP_NAME = "cryptomator.showTrayIcon";
|
||||
private static final String DISABLE_UPDATE_CHECK_PROP_NAME = "cryptomator.disableUpdateCheck";
|
||||
|
||||
private Environment() {}
|
||||
|
||||
@@ -45,15 +45,16 @@ public class Environment {
|
||||
logCryptomatorSystemProperty(SETTINGS_PATH_PROP_NAME);
|
||||
logCryptomatorSystemProperty(IPC_SOCKET_PATH_PROP_NAME);
|
||||
logCryptomatorSystemProperty(KEYCHAIN_PATHS_PROP_NAME);
|
||||
logCryptomatorSystemProperty(P12_PATH_PROP_NAME);
|
||||
logCryptomatorSystemProperty(LOG_DIR_PROP_NAME);
|
||||
logCryptomatorSystemProperty(LOOPBACK_ALIAS_PROP_NAME);
|
||||
logCryptomatorSystemProperty(PLUGIN_DIR_PROP_NAME);
|
||||
logCryptomatorSystemProperty(MOUNTPOINT_DIR_PROP_NAME);
|
||||
logCryptomatorSystemProperty(MIN_PW_LENGTH_PROP_NAME);
|
||||
logCryptomatorSystemProperty(APP_VERSION_PROP_NAME);
|
||||
logCryptomatorSystemProperty(BUILD_NUMBER_PROP_NAME);
|
||||
logCryptomatorSystemProperty(PLUGIN_DIR_PROP_NAME);
|
||||
logCryptomatorSystemProperty(TRAY_ICON_PROP_NAME);
|
||||
logCryptomatorSystemProperty(P12_PATH_PROP_NAME);
|
||||
logCryptomatorSystemProperty(DISABLE_UPDATE_CHECK_PROP_NAME);
|
||||
}
|
||||
|
||||
public static Environment getInstance() {
|
||||
@@ -76,11 +77,7 @@ public class Environment {
|
||||
return getPaths(SETTINGS_PATH_PROP_NAME);
|
||||
}
|
||||
|
||||
public Stream<Path> getP12Path() {
|
||||
return getPaths(P12_PATH_PROP_NAME);
|
||||
}
|
||||
|
||||
public Stream<Path> ipcSocketPath() {
|
||||
public Stream<Path> getIpcSocketPath() {
|
||||
return getPaths(IPC_SOCKET_PATH_PROP_NAME);
|
||||
}
|
||||
|
||||
@@ -88,20 +85,24 @@ public class Environment {
|
||||
return getPaths(KEYCHAIN_PATHS_PROP_NAME);
|
||||
}
|
||||
|
||||
public Stream<Path> getP12Path() {
|
||||
return getPaths(P12_PATH_PROP_NAME);
|
||||
}
|
||||
|
||||
public Optional<Path> getLogDir() {
|
||||
return getPath(LOG_DIR_PROP_NAME).map(this::replaceHomeDir);
|
||||
return getPath(LOG_DIR_PROP_NAME);
|
||||
}
|
||||
|
||||
public Optional<String> getLoopbackAlias() {
|
||||
return Optional.ofNullable(System.getProperty(LOOPBACK_ALIAS_PROP_NAME));
|
||||
}
|
||||
|
||||
public Optional<Path> getPluginDir() {
|
||||
return getPath(PLUGIN_DIR_PROP_NAME).map(this::replaceHomeDir);
|
||||
public Optional<Path> getMountPointsDir() {
|
||||
return getPath(MOUNTPOINT_DIR_PROP_NAME);
|
||||
}
|
||||
|
||||
public Optional<Path> getMountPointsDir() {
|
||||
return getPath(MOUNTPOINT_DIR_PROP_NAME).map(this::replaceHomeDir);
|
||||
public int getMinPwLength() {
|
||||
return Integer.getInteger(MIN_PW_LENGTH_PROP_NAME, DEFAULT_MIN_PW_LENGTH);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,36 +118,27 @@ public class Environment {
|
||||
return Optional.ofNullable(System.getProperty(BUILD_NUMBER_PROP_NAME));
|
||||
}
|
||||
|
||||
public int getMinPwLength() {
|
||||
return Integer.getInteger(MIN_PW_LENGTH_PROP_NAME, DEFAULT_MIN_PW_LENGTH);
|
||||
public Optional<Path> getPluginDir() {
|
||||
return getPath(PLUGIN_DIR_PROP_NAME);
|
||||
}
|
||||
|
||||
public boolean showTrayIcon() {
|
||||
return Boolean.getBoolean(TRAY_ICON_PROP_NAME);
|
||||
}
|
||||
|
||||
public boolean disableUpdateCheck() {
|
||||
return Boolean.getBoolean(DISABLE_UPDATE_CHECK_PROP_NAME);
|
||||
}
|
||||
|
||||
private Optional<Path> getPath(String propertyName) {
|
||||
String value = System.getProperty(propertyName);
|
||||
return Optional.ofNullable(value).map(Paths::get);
|
||||
}
|
||||
|
||||
// visible for testing
|
||||
public Path getHomeDir() {
|
||||
return getPath("user.home").orElseThrow();
|
||||
}
|
||||
|
||||
// visible for testing
|
||||
public Stream<Path> getPaths(String propertyName) {
|
||||
Stream<String> rawSettingsPaths = getRawList(propertyName, PATH_LIST_SEP);
|
||||
return rawSettingsPaths.filter(Predicate.not(Strings::isNullOrEmpty)).map(Paths::get).map(this::replaceHomeDir);
|
||||
}
|
||||
|
||||
private Path replaceHomeDir(Path path) {
|
||||
if (path.startsWith(RELATIVE_HOME_DIR)) {
|
||||
return getHomeDir().resolve(RELATIVE_HOME_DIR.relativize(path));
|
||||
} else {
|
||||
return path;
|
||||
}
|
||||
@VisibleForTesting
|
||||
Stream<Path> getPaths(String propertyName) {
|
||||
Stream<String> rawSettingsPaths = getRawList(propertyName, System.getProperty("path.separator").charAt(0));
|
||||
return rawSettingsPaths.filter(Predicate.not(Strings::isNullOrEmpty)).map(Path::of);
|
||||
}
|
||||
|
||||
private Stream<String> getRawList(String propertyName, char separator) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.cryptomator.common;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.base.Throwables;
|
||||
import org.jetbrains.annotations.VisibleForTesting;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
@@ -32,18 +33,15 @@ public class ErrorCode {
|
||||
this.rootCauseSpecificFrames = rootCauseSpecificFrames;
|
||||
}
|
||||
|
||||
// visible for testing
|
||||
String methodCode() {
|
||||
public String methodCode() {
|
||||
return format(traceCode(rootCause, LATEST_FRAME));
|
||||
}
|
||||
|
||||
// visible for testing
|
||||
String rootCauseCode() {
|
||||
public String rootCauseCode() {
|
||||
return format(traceCode(rootCause, rootCauseSpecificFrames));
|
||||
}
|
||||
|
||||
// visible for testing
|
||||
String throwableCode() {
|
||||
public String throwableCode() {
|
||||
return format(traceCode(throwable, ALL_FRAMES));
|
||||
}
|
||||
|
||||
@@ -117,7 +115,7 @@ public class ErrorCode {
|
||||
* @param bottomFrames Other stack frames, potentially forming the bottom of the stack of <code>allFrames</code>
|
||||
* @return The number of additional frames in <code>allFrames</code>. In most cases this should be equal to the difference in size.
|
||||
*/
|
||||
// visible for testing
|
||||
@VisibleForTesting
|
||||
static int countTopmostFrames(StackTraceElement[] allFrames, StackTraceElement[] bottomFrames) {
|
||||
if (allFrames.length < bottomFrames.length) {
|
||||
// if frames had been stacked on top of bottomFrames, allFrames would be larger
|
||||
@@ -127,7 +125,7 @@ public class ErrorCode {
|
||||
}
|
||||
}
|
||||
|
||||
// visible for testing
|
||||
@VisibleForTesting
|
||||
static <T> int commonSuffixLength(T[] set, T[] subset) {
|
||||
Preconditions.checkArgument(set.length >= subset.length);
|
||||
// iterate items backwards as long as they are identical
|
||||
|
||||
@@ -30,7 +30,7 @@ public class LicenseHolder {
|
||||
this.licenseSubject = validJwtClaims.map(DecodedJWT::getSubject);
|
||||
this.validLicenseProperty = validJwtClaims.isNotNull();
|
||||
|
||||
Optional<DecodedJWT> claims = licenseChecker.check(settings.licenseKey().get());
|
||||
Optional<DecodedJWT> claims = licenseChecker.check(settings.licenseKey.get());
|
||||
validJwtClaims.set(claims.orElse(null));
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ public class LicenseHolder {
|
||||
Optional<DecodedJWT> claims = licenseChecker.check(licenseKey);
|
||||
validJwtClaims.set(claims.orElse(null));
|
||||
if (claims.isPresent()) {
|
||||
settings.licenseKey().set(licenseKey);
|
||||
settings.licenseKey.set(licenseKey);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
||||
171
src/main/java/org/cryptomator/common/PropertiesDecorator.java
Normal file
171
src/main/java/org/cryptomator/common/PropertiesDecorator.java
Normal file
@@ -0,0 +1,171 @@
|
||||
package org.cryptomator.common;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.InvalidPropertiesFormatException;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
class PropertiesDecorator extends Properties {
|
||||
|
||||
protected final Properties delegate;
|
||||
|
||||
PropertiesDecorator(Properties delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProperty(String key) {return delegate.getProperty(key);}
|
||||
|
||||
@Override
|
||||
public String getProperty(String key, String defaultValue) {return delegate.getProperty(key, defaultValue);}
|
||||
|
||||
@Override
|
||||
public synchronized Object setProperty(String key, String value) {
|
||||
return delegate.setProperty(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void load(Reader reader) throws IOException {delegate.load(reader);}
|
||||
|
||||
@Override
|
||||
public synchronized void load(InputStream inStream) throws IOException {delegate.load(inStream);}
|
||||
|
||||
@Override
|
||||
public void store(Writer writer, String comments) throws IOException {delegate.store(writer, comments);}
|
||||
|
||||
@Override
|
||||
public void store(OutputStream out, @Nullable String comments) throws IOException {delegate.store(out, comments);}
|
||||
|
||||
@Override
|
||||
public synchronized void loadFromXML(InputStream in) throws IOException, InvalidPropertiesFormatException {delegate.loadFromXML(in);}
|
||||
|
||||
@Override
|
||||
public void storeToXML(OutputStream os, String comment) throws IOException {delegate.storeToXML(os, comment);}
|
||||
|
||||
@Override
|
||||
public void storeToXML(OutputStream os, String comment, String encoding) throws IOException {delegate.storeToXML(os, comment, encoding);}
|
||||
|
||||
@Override
|
||||
public void storeToXML(OutputStream os, String comment, Charset charset) throws IOException {delegate.storeToXML(os, comment, charset);}
|
||||
|
||||
@Override
|
||||
public Enumeration<?> propertyNames() {return delegate.propertyNames();}
|
||||
|
||||
@Override
|
||||
public Set<String> stringPropertyNames() {return delegate.stringPropertyNames();}
|
||||
|
||||
@Override
|
||||
public void list(PrintStream out) {delegate.list(out);}
|
||||
|
||||
@Override
|
||||
public void list(PrintWriter out) {delegate.list(out);}
|
||||
|
||||
@Override
|
||||
public int size() {return delegate.size();}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {return delegate.isEmpty();}
|
||||
|
||||
@Override
|
||||
public Enumeration<Object> keys() {return delegate.keys();}
|
||||
|
||||
@Override
|
||||
public Enumeration<Object> elements() {return delegate.elements();}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object value) {return delegate.contains(value);}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {return delegate.containsValue(value);}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {return delegate.containsKey(key);}
|
||||
|
||||
@Override
|
||||
public Object get(Object key) {return delegate.get(key);}
|
||||
|
||||
@Override
|
||||
public synchronized Object put(Object key, Object value) {return delegate.put(key, value);}
|
||||
|
||||
@Override
|
||||
public synchronized Object remove(Object key) {return delegate.remove(key);}
|
||||
|
||||
@Override
|
||||
public synchronized void putAll(Map<?, ?> t) {delegate.putAll(t);}
|
||||
|
||||
@Override
|
||||
public synchronized void clear() {delegate.clear();}
|
||||
|
||||
@Override
|
||||
public synchronized String toString() {return delegate.toString();}
|
||||
|
||||
@Override
|
||||
public Set<Object> keySet() {return delegate.keySet();}
|
||||
|
||||
@Override
|
||||
public Collection<Object> values() {return delegate.values();}
|
||||
|
||||
@Override
|
||||
public Set<Map.Entry<Object, Object>> entrySet() {return delegate.entrySet();}
|
||||
|
||||
@Override
|
||||
public synchronized boolean equals(Object o) {return delegate.equals(o);}
|
||||
|
||||
@Override
|
||||
public synchronized int hashCode() {return delegate.hashCode();}
|
||||
|
||||
@Override
|
||||
public Object getOrDefault(Object key, Object defaultValue) {return delegate.getOrDefault(key, defaultValue);}
|
||||
|
||||
@Override
|
||||
public synchronized void forEach(BiConsumer<? super Object, ? super Object> action) {delegate.forEach(action);}
|
||||
|
||||
@Override
|
||||
public synchronized void replaceAll(BiFunction<? super Object, ? super Object, ?> function) {delegate.replaceAll(function);}
|
||||
|
||||
@Override
|
||||
public synchronized Object putIfAbsent(Object key, Object value) {return delegate.putIfAbsent(key, value);}
|
||||
|
||||
@Override
|
||||
public synchronized boolean remove(Object key, Object value) {return delegate.remove(key, value);}
|
||||
|
||||
@Override
|
||||
public synchronized boolean replace(Object key, Object oldValue, Object newValue) {return delegate.replace(key, oldValue, newValue);}
|
||||
|
||||
@Override
|
||||
public synchronized Object replace(Object key, Object value) {return delegate.replace(key, value);}
|
||||
|
||||
@Override
|
||||
public synchronized Object computeIfAbsent(Object key, Function<? super Object, ?> mappingFunction) {return delegate.computeIfAbsent(key, mappingFunction);}
|
||||
|
||||
@Override
|
||||
public synchronized Object computeIfPresent(Object key, BiFunction<? super Object, ? super Object, ?> remappingFunction) {return delegate.computeIfPresent(key, remappingFunction);}
|
||||
|
||||
@Override
|
||||
public synchronized Object compute(Object key, BiFunction<? super Object, ? super Object, ?> remappingFunction) {return delegate.compute(key, remappingFunction);}
|
||||
|
||||
@Override
|
||||
public synchronized Object merge(Object key, Object value, BiFunction<? super Object, ? super Object, ?> remappingFunction) {return delegate.merge(key, value, remappingFunction);}
|
||||
|
||||
@Override
|
||||
public synchronized Object clone() {
|
||||
var delegateClone = (Properties) delegate.clone();
|
||||
return new PropertiesDecorator(delegateClone);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package org.cryptomator.common;
|
||||
|
||||
import org.jetbrains.annotations.VisibleForTesting;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class SubstitutingProperties extends PropertiesDecorator {
|
||||
|
||||
private static final Pattern TEMPLATE = Pattern.compile("@\\{(\\w+)}");
|
||||
|
||||
private final Map<String, String> env;
|
||||
|
||||
public SubstitutingProperties(Properties props, Map<String, String> systemEnvironment) {
|
||||
super(props);
|
||||
this.env = systemEnvironment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProperty(String key) {
|
||||
var value = delegate.getProperty(key);
|
||||
if (key.startsWith("cryptomator.") && value != null) {
|
||||
return process(value);
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProperty(String key, String defaultValue) {
|
||||
var result = getProperty(key);
|
||||
return result != null ? result : defaultValue;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
String process(String value) {
|
||||
return TEMPLATE.matcher(value).replaceAll(match -> //
|
||||
switch (match.group(1)) {
|
||||
case "appdir" -> resolveFrom("APPDIR", Source.ENV);
|
||||
case "appdata" -> resolveFrom("APPDATA", Source.ENV);
|
||||
case "localappdata" -> resolveFrom("LOCALAPPDATA", Source.ENV);
|
||||
case "userhome" -> resolveFrom("user.home", Source.PROPS);
|
||||
default -> {
|
||||
LoggerFactory.getLogger(SubstitutingProperties.class).warn("Unknown variable {} in property value {}.", match.group(), value);
|
||||
yield match.group();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private String resolveFrom(String key, Source src) {
|
||||
var val = switch (src) {
|
||||
case ENV -> env.get(key);
|
||||
case PROPS -> delegate.getProperty(key);
|
||||
};
|
||||
if (val == null) {
|
||||
LoggerFactory.getLogger(SubstitutingProperties.class).warn("Variable {} used for substitution not found in {}. Replaced with empty string.", key, src);
|
||||
return "";
|
||||
} else {
|
||||
return val.replace("\\", "\\\\");
|
||||
}
|
||||
}
|
||||
|
||||
private enum Source {
|
||||
ENV,
|
||||
PROPS;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,14 +23,14 @@ public class KeychainModule {
|
||||
@Singleton
|
||||
static ObjectExpression<KeychainAccessProvider> provideKeychainAccessProvider(Settings settings, List<KeychainAccessProvider> providers) {
|
||||
return Bindings.createObjectBinding(() -> {
|
||||
if (!settings.useKeychain().get()) {
|
||||
if (!settings.useKeychain.get()) {
|
||||
return null;
|
||||
}
|
||||
var selectedProviderClass = settings.keychainProvider().get();
|
||||
var selectedProviderClass = settings.keychainProvider.get();
|
||||
var selectedProvider = providers.stream().filter(provider -> provider.getClass().getName().equals(selectedProviderClass)).findAny();
|
||||
var fallbackProvider = providers.stream().findFirst().orElse(null);
|
||||
return selectedProvider.orElse(fallbackProvider);
|
||||
}, settings.keychainProvider(), settings.useKeychain());
|
||||
}, settings.keychainProvider, settings.useKeychain);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import org.cryptomator.integrations.common.OperatingSystem;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
|
||||
@@ -15,23 +17,25 @@ import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
|
||||
@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");
|
||||
|
||||
private static final List<Path> LOCATIONS = Arrays.asList( //
|
||||
LocationPresetsProvider.resolveLocation("~/GoogleDrive/My Drive"), //
|
||||
LocationPresetsProvider.resolveLocation("~/Google Drive/My Drive"), //
|
||||
LocationPresetsProvider.resolveLocation("~/GoogleDrive"), //
|
||||
LocationPresetsProvider.resolveLocation("~/Google Drive") //
|
||||
);
|
||||
|
||||
@CheckAvailability
|
||||
public static boolean isPresent() {
|
||||
return Files.isDirectory(LOCATION1) || Files.isDirectory(LOCATION2);
|
||||
return LOCATIONS.stream().anyMatch(Files::isDirectory);
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
return LOCATIONS.stream() //
|
||||
.filter(Files::isDirectory) //
|
||||
.map(location -> new LocationPreset("Google Drive", location)) //
|
||||
.findFirst() //
|
||||
.stream();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 LeitzcloudLocationPresetsProvider implements LocationPresetsProvider {
|
||||
|
||||
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/leitzcloud");
|
||||
|
||||
@CheckAvailability
|
||||
public static boolean isPresent() {
|
||||
return Files.isDirectory(LOCATION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<LocationPreset> getLocations() {
|
||||
return Stream.of(new LocationPreset("leitzcloud", LOCATION));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -62,7 +62,7 @@ public final class OneDriveWindowsLocationPresetsProvider implements LocationPre
|
||||
ProcessBuilder command = new ProcessBuilder(args);
|
||||
Process p = command.start();
|
||||
waitForSuccess(p, 3, "`reg query`");
|
||||
return p.inputReader(StandardCharsets.UTF_8).lines().filter(outputFilter);
|
||||
return p.inputReader(StandardCharsets.ISO_8859_1).lines().filter(outputFilter);
|
||||
}
|
||||
|
||||
|
||||
@@ -83,8 +83,8 @@ public final class OneDriveWindowsLocationPresetsProvider implements LocationPre
|
||||
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"));
|
||||
@SuppressWarnings("resource") var stdout = process.inputReader(StandardCharsets.ISO_8859_1).lines().collect(Collectors.joining("\n"));
|
||||
@SuppressWarnings("resource") var stderr = process.errorReader(StandardCharsets.ISO_8859_1).lines().collect(Collectors.joining("\n"));
|
||||
throw new CommandFailedException(cmdDescription, process.exitValue(), stdout, stderr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import org.cryptomator.integrations.common.OperatingSystem;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
|
||||
@@ -15,16 +17,23 @@ import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
|
||||
@CheckAvailability
|
||||
public final class PCloudLocationPresetsProvider implements LocationPresetsProvider {
|
||||
|
||||
|
||||
private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/pCloudDrive");
|
||||
private static final List<Path> LOCATIONS = Arrays.asList( //
|
||||
LocationPresetsProvider.resolveLocation("~/pCloudDrive"), //
|
||||
LocationPresetsProvider.resolveLocation("~/pCloud Drive") //
|
||||
);
|
||||
|
||||
@CheckAvailability
|
||||
public static boolean isPresent() {
|
||||
return Files.isDirectory(LOCATION);
|
||||
return LOCATIONS.stream().anyMatch(Files::isDirectory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<LocationPreset> getLocations() {
|
||||
return Stream.of(new LocationPreset("pCloud", LOCATION));
|
||||
return LOCATIONS.stream() //
|
||||
.filter(Files::isDirectory) //
|
||||
.map(location -> new LocationPreset("pCloud", location)) //
|
||||
.findFirst() //
|
||||
.stream();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
package org.cryptomator.common.mount;
|
||||
|
||||
import org.cryptomator.integrations.mount.MountService;
|
||||
|
||||
public record ActualMountService(MountService service, boolean isDesired) {
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.cryptomator.common.mount;
|
||||
|
||||
import org.cryptomator.integrations.mount.MountFailedException;
|
||||
|
||||
/**
|
||||
* Thrown by {@link Mounter} to indicate that the selected mount service can not be used
|
||||
* due to incompatibilities with a different mount service that is already in use.
|
||||
*/
|
||||
public class ConflictingMountServiceException extends MountFailedException {
|
||||
|
||||
public ConflictingMountServiceException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.cryptomator.common.mount;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class HideawayNotDirectoryException extends IllegalMountPointException {
|
||||
|
||||
private final Path hideaway;
|
||||
|
||||
public HideawayNotDirectoryException(Path path, Path hideaway) {
|
||||
super(path, "Existing hideaway (" + hideaway.toString() + ") for mountpoint is not a directory: " + path.toString());
|
||||
this.hideaway = hideaway;
|
||||
}
|
||||
|
||||
public Path getHideaway() {
|
||||
return hideaway;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,25 @@
|
||||
package org.cryptomator.common.mount;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* Indicates that validation or preparation of a mountpoint failed due to a configuration error or an invalid system state.<br>
|
||||
* Instances of this exception are usually caught and displayed to the user in an appropriate fashion, e.g. by {@link org.cryptomator.ui.unlock.UnlockInvalidMountPointController UnlockInvalidMountPointController.}
|
||||
*/
|
||||
public class IllegalMountPointException extends IllegalArgumentException {
|
||||
|
||||
public IllegalMountPointException(String msg) {
|
||||
super(msg);
|
||||
private final Path mountpoint;
|
||||
|
||||
public IllegalMountPointException(Path mountpoint) {
|
||||
this(mountpoint, "The provided mountpoint has a problem: " + mountpoint.toString());
|
||||
}
|
||||
|
||||
}
|
||||
public IllegalMountPointException(Path mountpoint, String msg) {
|
||||
super(msg);
|
||||
this.mountpoint = mountpoint;
|
||||
}
|
||||
|
||||
public Path getMountpoint() {
|
||||
return mountpoint;
|
||||
}
|
||||
}
|
||||
@@ -4,21 +4,18 @@ import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import org.cryptomator.common.ObservableUtil;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.integrations.mount.Mount;
|
||||
import org.cryptomator.integrations.mount.MountService;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Module
|
||||
public class MountModule {
|
||||
|
||||
private static final AtomicReference<MountService> formerSelectedMountService = new AtomicReference<>(null);
|
||||
private static final List<String> problematicFuseMountServices = List.of("org.cryptomator.frontend.fuse.mount.MacFuseMountProvider", "org.cryptomator.frontend.fuse.mount.FuseTMountProvider");
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static List<MountService> provideSupportedMountServices() {
|
||||
@@ -27,46 +24,18 @@ public class MountModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named("FUPFMS")
|
||||
static AtomicReference<MountService> provideFirstUsedProblematicFuseMountService() {
|
||||
return new AtomicReference<>(null);
|
||||
static ObservableValue<MountService> provideDefaultMountService(List<MountService> mountProviders, Settings settings) {
|
||||
var fallbackProvider = mountProviders.stream().findFirst().get(); //there should always be a mount provider, at least webDAV
|
||||
return ObservableUtil.mapWithDefault(settings.mountService, //
|
||||
serviceName -> mountProviders.stream().filter(s -> s.getClass().getName().equals(serviceName)).findFirst().orElse(fallbackProvider), //
|
||||
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;
|
||||
@Named("usedMountServices")
|
||||
static Set<MountService> provideSetOfUsedMountServices() {
|
||||
return ConcurrentHashMap.newKeySet();
|
||||
}
|
||||
|
||||
//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,10 @@
|
||||
package org.cryptomator.common.mount;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class MountPointCleanupFailedException extends IllegalMountPointException {
|
||||
|
||||
public MountPointCleanupFailedException(Path path) {
|
||||
super(path, "Mountpoint could not be cleared: " + path.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.cryptomator.common.mount;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class MountPointInUseException extends IllegalMountPointException {
|
||||
|
||||
public MountPointInUseException(Path path) {
|
||||
super(path);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.cryptomator.common.mount;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class MountPointNotEmptyDirectoryException extends IllegalMountPointException {
|
||||
|
||||
public MountPointNotEmptyDirectoryException(Path path, String msg) {
|
||||
super(path, msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.cryptomator.common.mount;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class MountPointNotExistingException extends IllegalMountPointException {
|
||||
|
||||
public MountPointNotExistingException(Path path, String msg) {
|
||||
super(path, msg);
|
||||
}
|
||||
|
||||
public MountPointNotExistingException(Path path) {
|
||||
super(path, "Mountpoint does not exist: " + path);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package org.cryptomator.common.mount;
|
||||
|
||||
public class MountPointNotExistsException extends IllegalMountPointException {
|
||||
|
||||
public MountPointNotExistsException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
package org.cryptomator.common.mount;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class MountPointNotSupportedException extends IllegalMountPointException {
|
||||
|
||||
public MountPointNotSupportedException(String msg) {
|
||||
super(msg);
|
||||
public MountPointNotSupportedException(Path path, String msg) {
|
||||
super(path, msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
package org.cryptomator.common.mount;
|
||||
|
||||
public class MountPointPreparationException extends RuntimeException {
|
||||
|
||||
public MountPointPreparationException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public MountPointPreparationException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,16 @@
|
||||
package org.cryptomator.common.mount;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.jetbrains.annotations.VisibleForTesting;
|
||||
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;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
|
||||
public final class MountWithinParentUtil {
|
||||
|
||||
@@ -22,31 +21,33 @@ public final class MountWithinParentUtil {
|
||||
|
||||
private MountWithinParentUtil() {}
|
||||
|
||||
static void prepareParentNoMountPoint(Path mountPoint) throws MountPointPreparationException {
|
||||
static void prepareParentNoMountPoint(Path mountPoint) throws IllegalMountPointException, IOException {
|
||||
Path hideaway = getHideaway(mountPoint);
|
||||
var mpExists = Files.exists(mountPoint, LinkOption.NOFOLLOW_LINKS);
|
||||
var mpState = getMountPointState(mountPoint);
|
||||
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);
|
||||
if (mpState == MountPointState.BROKEN_JUNCTION) {
|
||||
LOG.info("Mountpoint \"{}\" is still a junction. Deleting it.", mountPoint);
|
||||
Files.delete(mountPoint); //Throws if mountPoint is also a non-empty folder
|
||||
mpState = MountPointState.NOT_EXISTING;
|
||||
}
|
||||
|
||||
if (mpState == MountPointState.NOT_EXISTING && !hideExists) { //neither mountpoint nor hideaway exist
|
||||
throw new MountPointNotExistingException(mountPoint);
|
||||
} else if (mpState == MountPointState.NOT_EXISTING) { //only hideaway exists
|
||||
checkIsHideawayDirectory(mountPoint, hideaway);
|
||||
LOG.info("Mountpoint {} seems to be not properly cleaned up. Will be fixed on unmount.", mountPoint);
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
Files.setAttribute(hideaway, WIN_HIDDEN_ATTR, true, LinkOption.NOFOLLOW_LINKS);
|
||||
}
|
||||
} else {
|
||||
assert mpState == MountPointState.EMPTY_DIR;
|
||||
try {
|
||||
if (hideExists) { //... with hideaway
|
||||
removeResidualHideaway(mountPoint, hideaway);
|
||||
}
|
||||
|
||||
//... (now) without hideaway
|
||||
Files.move(mountPoint, hideaway);
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
Files.setAttribute(hideaway, WIN_HIDDEN_ATTR, true, LinkOption.NOFOLLOW_LINKS);
|
||||
@@ -54,30 +55,66 @@ public final class MountWithinParentUtil {
|
||||
int attempts = 0;
|
||||
while (!Files.notExists(mountPoint)) {
|
||||
if (attempts >= 10) {
|
||||
throw new MountPointPreparationException("Path " + mountPoint + " could not be cleared");
|
||||
throw new MountPointCleanupFailedException(mountPoint);
|
||||
}
|
||||
Thread.sleep(1000);
|
||||
attempts++;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new MountPointPreparationException(e);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new MountPointPreparationException(e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static MountPointState getMountPointState(Path path) throws IOException, IllegalMountPointException {
|
||||
if (Files.notExists(path, LinkOption.NOFOLLOW_LINKS)) {
|
||||
return MountPointState.NOT_EXISTING;
|
||||
}
|
||||
if (!Files.readAttributes(path, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS).isOther()) {
|
||||
checkIsMountPointDirectory(path);
|
||||
checkIsMountPointEmpty(path);
|
||||
return MountPointState.EMPTY_DIR;
|
||||
}
|
||||
if (Files.exists(path /* FOLLOW_LINKS */)) { //Both junction and target exist
|
||||
throw new MountPointInUseException(path);
|
||||
}
|
||||
return MountPointState.BROKEN_JUNCTION;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
enum MountPointState {
|
||||
|
||||
NOT_EXISTING,
|
||||
|
||||
EMPTY_DIR,
|
||||
|
||||
BROKEN_JUNCTION;
|
||||
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static void removeResidualHideaway(Path mountPoint, Path hideaway) throws IOException {
|
||||
checkIsHideawayDirectory(mountPoint, hideaway);
|
||||
Files.delete(hideaway); //Fails if not empty
|
||||
}
|
||||
|
||||
static void cleanup(Path mountPoint) {
|
||||
Path hideaway = getHideaway(mountPoint);
|
||||
try {
|
||||
waitForMountpointRestoration(mountPoint);
|
||||
if (Files.notExists(hideaway, LinkOption.NOFOLLOW_LINKS)) {
|
||||
LOG.error("Unable to restore hidden directory to mountpoint \"{}\": Directory does not exist.", mountPoint);
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
LOG.error("Unable to restore hidden directory to mountpoint \"{}\".", mountPoint, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,21 +136,27 @@ public final class MountWithinParentUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkIsDirectory(Path toCheck) throws MountPointPreparationException {
|
||||
private static void checkIsMountPointDirectory(Path toCheck) throws IllegalMountPointException {
|
||||
if (!Files.isDirectory(toCheck, LinkOption.NOFOLLOW_LINKS)) {
|
||||
throw new MountPointPreparationException(new NotDirectoryException(toCheck.toString()));
|
||||
throw new MountPointNotEmptyDirectoryException(toCheck, "Mountpoint is not a directory: " + toCheck);
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkIsEmpty(Path toCheck) throws MountPointPreparationException, IOException {
|
||||
private static void checkIsHideawayDirectory(Path mountPoint, Path hideawayToCheck) {
|
||||
if (!Files.isDirectory(hideawayToCheck, LinkOption.NOFOLLOW_LINKS)) {
|
||||
throw new HideawayNotDirectoryException(mountPoint, hideawayToCheck);
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkIsMountPointEmpty(Path toCheck) throws IllegalMountPointException, IOException {
|
||||
try (var dirStream = Files.list(toCheck)) {
|
||||
if (dirStream.findFirst().isPresent()) {
|
||||
throw new MountPointPreparationException(new DirectoryNotEmptyException(toCheck.toString()));
|
||||
throw new MountPointNotEmptyDirectoryException(toCheck, "Mountpoint directory is not empty: " + toCheck);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//visible for testing
|
||||
@VisibleForTesting
|
||||
static Path getHideaway(Path mountPoint) {
|
||||
return mountPoint.resolveSibling(HIDEAWAY_PREFIX + mountPoint.getFileName().toString() + HIDEAWAY_SUFFIX);
|
||||
}
|
||||
|
||||
@@ -7,13 +7,19 @@ import org.cryptomator.integrations.mount.Mount;
|
||||
import org.cryptomator.integrations.mount.MountBuilder;
|
||||
import org.cryptomator.integrations.mount.MountFailedException;
|
||||
import org.cryptomator.integrations.mount.MountService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.cryptomator.integrations.mount.MountCapability.MOUNT_AS_DRIVE_LETTER;
|
||||
import static org.cryptomator.integrations.mount.MountCapability.MOUNT_TO_EXISTING_DIR;
|
||||
@@ -24,24 +30,41 @@ import static org.cryptomator.integrations.mount.MountCapability.UNMOUNT_FORCED;
|
||||
@Singleton
|
||||
public class Mounter {
|
||||
|
||||
private final Settings settings;
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Mounter.class);
|
||||
|
||||
// mount providers (key) can not be used if any of the conflicting mount providers (values) are already in use
|
||||
private static final Map<String, Set<String>> CONFLICTING_MOUNT_SERVICES = Map.of(
|
||||
"org.cryptomator.frontend.fuse.mount.MacFuseMountProvider", Set.of("org.cryptomator.frontend.fuse.mount.FuseTMountProvider"),
|
||||
"org.cryptomator.frontend.fuse.mount.FuseTMountProvider", Set.of("org.cryptomator.frontend.fuse.mount.MacFuseMountProvider")
|
||||
);
|
||||
|
||||
private final Environment env;
|
||||
private final Settings settings;
|
||||
private final WindowsDriveLetters driveLetters;
|
||||
private final ObservableValue<ActualMountService> mountServiceObservable;
|
||||
private final List<MountService> mountProviders;
|
||||
private final Set<MountService> usedMountServices;
|
||||
private final ObservableValue<MountService> defaultMountService;
|
||||
|
||||
@Inject
|
||||
public Mounter(Settings settings, Environment env, WindowsDriveLetters driveLetters, ObservableValue<ActualMountService> mountServiceObservable) {
|
||||
this.settings = settings;
|
||||
public Mounter(Environment env, //
|
||||
Settings settings, //
|
||||
WindowsDriveLetters driveLetters, //
|
||||
List<MountService> mountProviders, //
|
||||
@Named("usedMountServices") Set<MountService> usedMountServices, //
|
||||
ObservableValue<MountService> defaultMountService) {
|
||||
this.env = env;
|
||||
this.settings = settings;
|
||||
this.driveLetters = driveLetters;
|
||||
this.mountServiceObservable = mountServiceObservable;
|
||||
this.mountProviders = mountProviders;
|
||||
this.usedMountServices = usedMountServices;
|
||||
this.defaultMountService = defaultMountService;
|
||||
}
|
||||
|
||||
private class SettledMounter {
|
||||
|
||||
private MountService service;
|
||||
private MountBuilder builder;
|
||||
private VaultSettings vaultSettings;
|
||||
private final MountService service;
|
||||
private final MountBuilder builder;
|
||||
private final VaultSettings vaultSettings;
|
||||
|
||||
public SettledMounter(MountService service, MountBuilder builder, VaultSettings vaultSettings) {
|
||||
this.service = service;
|
||||
@@ -53,20 +76,25 @@ public class Mounter {
|
||||
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_PORT -> {
|
||||
if (vaultSettings.mountService.getValue() == null) {
|
||||
builder.setLoopbackPort(settings.port.get());
|
||||
} else {
|
||||
builder.setLoopbackPort(vaultSettings.port.get());
|
||||
}
|
||||
}
|
||||
case LOOPBACK_HOST_NAME -> env.getLoopbackAlias().ifPresent(builder::setLoopbackHostName);
|
||||
case READ_ONLY -> builder.setReadOnly(vaultSettings.usesReadOnlyMode().get());
|
||||
case READ_ONLY -> builder.setReadOnly(vaultSettings.usesReadOnlyMode.get());
|
||||
case MOUNT_FLAGS -> {
|
||||
var mountFlags = vaultSettings.mountFlags().get();
|
||||
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());
|
||||
case VOLUME_ID -> builder.setVolumeId(vaultSettings.id);
|
||||
case VOLUME_NAME -> builder.setVolumeName(vaultSettings.mountName.get());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +103,7 @@ public class Mounter {
|
||||
|
||||
private Runnable prepareMountPoint() throws IOException {
|
||||
Runnable cleanup = () -> {};
|
||||
var userChosenMountPoint = vaultSettings.getMountPoint();
|
||||
var userChosenMountPoint = vaultSettings.mountPoint.get();
|
||||
var defaultMountPointBase = env.getMountPointsDir().orElseThrow();
|
||||
var canMountToDriveLetter = service.hasCapability(MOUNT_AS_DRIVE_LETTER);
|
||||
var canMountToParent = service.hasCapability(MOUNT_WITHIN_EXISTING_PARENT);
|
||||
@@ -91,17 +119,19 @@ public class Mounter {
|
||||
Files.createDirectories(defaultMountPointBase);
|
||||
builder.setMountpoint(defaultMountPointBase);
|
||||
} else if (canMountToDir) {
|
||||
var mountPoint = defaultMountPointBase.resolve(vaultSettings.mountName().get());
|
||||
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) {
|
||||
if (mpIsDriveLetter) {
|
||||
if (driveLetters.getOccupied().contains(userChosenMountPoint)) {
|
||||
throw new MountPointInUseException(userChosenMountPoint);
|
||||
}
|
||||
} else if (canMountToParent && !canMountToDir) {
|
||||
MountWithinParentUtil.prepareParentNoMountPoint(userChosenMountPoint);
|
||||
cleanup = () -> {
|
||||
MountWithinParentUtil.cleanup(userChosenMountPoint);
|
||||
};
|
||||
cleanup = () -> MountWithinParentUtil.cleanup(userChosenMountPoint);
|
||||
}
|
||||
try {
|
||||
builder.setMountpoint(userChosenMountPoint);
|
||||
@@ -111,13 +141,13 @@ public class Mounter {
|
||||
|| (!canMountToParent && !mpIsDriveLetter) //
|
||||
|| (!canMountToDir && !canMountToParent && !canMountToSystem && !canMountToDriveLetter);
|
||||
if (configNotSupported) {
|
||||
throw new MountPointNotSupportedException(e.getMessage());
|
||||
throw new MountPointNotSupportedException(userChosenMountPoint, e.getMessage());
|
||||
} else if (canMountToDir && !canMountToParent && !Files.exists(userChosenMountPoint)) {
|
||||
//mountpoint must exist
|
||||
throw new MountPointNotExistsException(e.getMessage());
|
||||
throw new MountPointNotExistingException(userChosenMountPoint, e.getMessage());
|
||||
} else {
|
||||
//TODO: add specific exception for !canMountToDir && canMountToParent && !Files.notExists(userChosenMountPoint)
|
||||
throw new IllegalMountPointException(e.getMessage());
|
||||
throw new IllegalMountPointException(userChosenMountPoint, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,13 +157,26 @@ public class Mounter {
|
||||
}
|
||||
|
||||
public MountHandle mount(VaultSettings vaultSettings, Path cryptoFsRoot) throws IOException, MountFailedException {
|
||||
var mountService = this.mountServiceObservable.getValue().service();
|
||||
var mountService = mountProviders.stream().filter(s -> s.getClass().getName().equals(vaultSettings.mountService.getValue())).findFirst().orElse(defaultMountService.getValue());
|
||||
|
||||
if (isConflictingMountService(mountService)) {
|
||||
var msg = STR."\{mountService.getClass()} unavailable due to conflict with either of \{CONFLICTING_MOUNT_SERVICES.get(mountService.getClass().getName())}";
|
||||
throw new ConflictingMountServiceException(msg);
|
||||
}
|
||||
|
||||
usedMountServices.add(mountService);
|
||||
|
||||
var builder = mountService.forFileSystem(cryptoFsRoot);
|
||||
var internal = new SettledMounter(mountService, builder, vaultSettings);
|
||||
var internal = new SettledMounter(mountService, builder, vaultSettings); // FIXME: no need for an inner class
|
||||
var cleanup = internal.prepare();
|
||||
return new MountHandle(builder.mount(), mountService.hasCapability(UNMOUNT_FORCED), cleanup);
|
||||
}
|
||||
|
||||
public boolean isConflictingMountService(MountService service) {
|
||||
var conflictingServices = CONFLICTING_MOUNT_SERVICES.getOrDefault(service.getClass().getName(), Set.of());
|
||||
return usedMountServices.stream().map(MountService::getClass).map(Class::getName).anyMatch(conflictingServices::contains);
|
||||
}
|
||||
|
||||
public record MountHandle(Mount mountObj, boolean supportsUnmountForced, Runnable specialCleanup) {
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ package org.cryptomator.common.settings;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
@@ -27,59 +29,86 @@ import java.util.function.Consumer;
|
||||
|
||||
public class Settings {
|
||||
|
||||
public static final int MIN_PORT = 1024;
|
||||
public static final int MAX_PORT = 65535;
|
||||
public static final boolean DEFAULT_ASKED_FOR_UPDATE_CHECK = false;
|
||||
public static final boolean DEFAULT_CHECK_FOR_UPDATES = false;
|
||||
public static final boolean DEFAULT_START_HIDDEN = false;
|
||||
public static final boolean DEFAULT_AUTO_CLOSE_VAULTS = false;
|
||||
public static final boolean DEFAULT_USE_KEYCHAIN = true;
|
||||
public static final int DEFAULT_PORT = 42427;
|
||||
public static final int DEFAULT_NUM_TRAY_NOTIFICATIONS = 3;
|
||||
public static final boolean DEFAULT_DEBUG_MODE = false;
|
||||
public static final UiTheme DEFAULT_THEME = UiTheme.LIGHT;
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Settings.class);
|
||||
|
||||
static final boolean DEFAULT_ASKED_FOR_UPDATE_CHECK = false;
|
||||
static final boolean DEFAULT_CHECK_FOR_UPDATES = false;
|
||||
static final boolean DEFAULT_START_HIDDEN = false;
|
||||
static final boolean DEFAULT_AUTO_CLOSE_VAULTS = false;
|
||||
static final boolean DEFAULT_USE_KEYCHAIN = true;
|
||||
static final int DEFAULT_PORT = 42427;
|
||||
static final int DEFAULT_NUM_TRAY_NOTIFICATIONS = 3;
|
||||
static final boolean DEFAULT_DEBUG_MODE = false;
|
||||
static final UiTheme DEFAULT_THEME = UiTheme.LIGHT;
|
||||
@Deprecated // to be changed to "whatever is available" eventually
|
||||
public static final String DEFAULT_KEYCHAIN_PROVIDER = SystemUtils.IS_OS_WINDOWS ? "org.cryptomator.windows.keychain.WindowsProtectedKeychainAccess" : SystemUtils.IS_OS_MAC ? "org.cryptomator.macos.keychain.MacSystemKeychainAccess" : "org.cryptomator.linux.keychain.SecretServiceKeychainAccess";
|
||||
public static final NodeOrientation DEFAULT_USER_INTERFACE_ORIENTATION = NodeOrientation.LEFT_TO_RIGHT;
|
||||
public static final String DEFAULT_LICENSE_KEY = "";
|
||||
public static final boolean DEFAULT_SHOW_MINIMIZE_BUTTON = false;
|
||||
public static final String DEFAULT_DISPLAY_CONFIGURATION = "";
|
||||
public static final String DEFAULT_LANGUAGE = null;
|
||||
|
||||
|
||||
private final ObservableList<VaultSettings> directories = FXCollections.observableArrayList(VaultSettings::observables);
|
||||
private final BooleanProperty askedForUpdateCheck = new SimpleBooleanProperty(DEFAULT_ASKED_FOR_UPDATE_CHECK);
|
||||
private final BooleanProperty checkForUpdates = new SimpleBooleanProperty(DEFAULT_CHECK_FOR_UPDATES);
|
||||
private final BooleanProperty startHidden = new SimpleBooleanProperty(DEFAULT_START_HIDDEN);
|
||||
private final BooleanProperty autoCloseVaults = new SimpleBooleanProperty(DEFAULT_AUTO_CLOSE_VAULTS);
|
||||
private final BooleanProperty useKeychain = new SimpleBooleanProperty(DEFAULT_USE_KEYCHAIN);
|
||||
private final IntegerProperty port = new SimpleIntegerProperty(DEFAULT_PORT);
|
||||
private final IntegerProperty numTrayNotifications = new SimpleIntegerProperty(DEFAULT_NUM_TRAY_NOTIFICATIONS);
|
||||
private final BooleanProperty debugMode = new SimpleBooleanProperty(DEFAULT_DEBUG_MODE);
|
||||
private final ObjectProperty<UiTheme> theme = new SimpleObjectProperty<>(DEFAULT_THEME);
|
||||
private final ObjectProperty<String> keychainProvider = new SimpleObjectProperty<>(DEFAULT_KEYCHAIN_PROVIDER);
|
||||
private final ObjectProperty<NodeOrientation> userInterfaceOrientation = new SimpleObjectProperty<>(DEFAULT_USER_INTERFACE_ORIENTATION);
|
||||
private final StringProperty licenseKey = new SimpleStringProperty(DEFAULT_LICENSE_KEY);
|
||||
private final BooleanProperty showMinimizeButton = new SimpleBooleanProperty(DEFAULT_SHOW_MINIMIZE_BUTTON);
|
||||
private final BooleanProperty showTrayIcon;
|
||||
private final IntegerProperty windowXPosition = new SimpleIntegerProperty();
|
||||
private final IntegerProperty windowYPosition = new SimpleIntegerProperty();
|
||||
private final IntegerProperty windowWidth = new SimpleIntegerProperty();
|
||||
private final IntegerProperty windowHeight = new SimpleIntegerProperty();
|
||||
private final ObjectProperty<String> displayConfiguration = new SimpleObjectProperty<>(DEFAULT_DISPLAY_CONFIGURATION);
|
||||
private final StringProperty language = new SimpleStringProperty(DEFAULT_LANGUAGE);
|
||||
|
||||
|
||||
private final StringProperty mountService = new SimpleStringProperty();
|
||||
static final String DEFAULT_KEYCHAIN_PROVIDER = SystemUtils.IS_OS_WINDOWS ? "org.cryptomator.windows.keychain.WindowsProtectedKeychainAccess" : SystemUtils.IS_OS_MAC ? "org.cryptomator.macos.keychain.MacSystemKeychainAccess" : "org.cryptomator.linux.keychain.SecretServiceKeychainAccess";
|
||||
static final String DEFAULT_USER_INTERFACE_ORIENTATION = NodeOrientation.LEFT_TO_RIGHT.name();
|
||||
static final boolean DEFAULT_SHOW_MINIMIZE_BUTTON = false;
|
||||
static final String DEFAULT_LAST_UPDATE_CHECK = "2000-01-01";
|
||||
|
||||
public final ObservableList<VaultSettings> directories;
|
||||
public final BooleanProperty askedForUpdateCheck;
|
||||
public final BooleanProperty checkForUpdates;
|
||||
public final BooleanProperty startHidden;
|
||||
public final BooleanProperty autoCloseVaults;
|
||||
public final BooleanProperty useKeychain;
|
||||
public final IntegerProperty port;
|
||||
public final IntegerProperty numTrayNotifications;
|
||||
public final BooleanProperty debugMode;
|
||||
public final ObjectProperty<UiTheme> theme;
|
||||
public final StringProperty keychainProvider;
|
||||
public final ObjectProperty<NodeOrientation> userInterfaceOrientation;
|
||||
public final StringProperty licenseKey;
|
||||
public final BooleanProperty showMinimizeButton;
|
||||
public final BooleanProperty showTrayIcon;
|
||||
public final IntegerProperty windowXPosition;
|
||||
public final IntegerProperty windowYPosition;
|
||||
public final IntegerProperty windowWidth;
|
||||
public final IntegerProperty windowHeight;
|
||||
public final StringProperty language;
|
||||
public final StringProperty mountService;
|
||||
public final StringProperty lastUpdateCheck;
|
||||
|
||||
private Consumer<Settings> saveCmd;
|
||||
|
||||
public static Settings create(Environment env) {
|
||||
var defaults = new SettingsJson();
|
||||
defaults.showTrayIcon = env.showTrayIcon();
|
||||
return new Settings(defaults);
|
||||
}
|
||||
|
||||
/**
|
||||
* Package-private constructor; use {@link SettingsProvider}.
|
||||
* Recreate settings from json
|
||||
*
|
||||
* @param json The parsed settings.json
|
||||
*/
|
||||
Settings(Environment env) {
|
||||
this.showTrayIcon = new SimpleBooleanProperty(env.showTrayIcon());
|
||||
Settings(SettingsJson json) {
|
||||
this.directories = FXCollections.observableArrayList(VaultSettings::observables);
|
||||
this.askedForUpdateCheck = new SimpleBooleanProperty(this, "askedForUpdateCheck", json.askedForUpdateCheck);
|
||||
this.checkForUpdates = new SimpleBooleanProperty(this, "checkForUpdates", json.checkForUpdatesEnabled);
|
||||
this.startHidden = new SimpleBooleanProperty(this, "startHidden", json.startHidden);
|
||||
this.autoCloseVaults = new SimpleBooleanProperty(this, "autoCloseVaults", json.autoCloseVaults);
|
||||
this.useKeychain = new SimpleBooleanProperty(this, "useKeychain", json.useKeychain);
|
||||
this.port = new SimpleIntegerProperty(this, "webDavPort", json.port);
|
||||
this.numTrayNotifications = new SimpleIntegerProperty(this, "numTrayNotifications", json.numTrayNotifications);
|
||||
this.debugMode = new SimpleBooleanProperty(this, "debugMode", json.debugMode);
|
||||
this.theme = new SimpleObjectProperty<>(this, "theme", json.theme);
|
||||
this.keychainProvider = new SimpleStringProperty(this, "keychainProvider", json.keychainProvider);
|
||||
this.userInterfaceOrientation = new SimpleObjectProperty<>(this, "userInterfaceOrientation", parseEnum(json.uiOrientation, NodeOrientation.class, NodeOrientation.LEFT_TO_RIGHT));
|
||||
this.licenseKey = new SimpleStringProperty(this, "licenseKey", json.licenseKey);
|
||||
this.showMinimizeButton = new SimpleBooleanProperty(this, "showMinimizeButton", json.showMinimizeButton);
|
||||
this.showTrayIcon = new SimpleBooleanProperty(this, "showTrayIcon", json.showTrayIcon);
|
||||
this.windowXPosition = new SimpleIntegerProperty(this, "windowXPosition", json.windowXPosition);
|
||||
this.windowYPosition = new SimpleIntegerProperty(this, "windowYPosition", json.windowYPosition);
|
||||
this.windowWidth = new SimpleIntegerProperty(this, "windowWidth", json.windowWidth);
|
||||
this.windowHeight = new SimpleIntegerProperty(this, "windowHeight", json.windowHeight);
|
||||
this.language = new SimpleStringProperty(this, "language", json.language);
|
||||
this.mountService = new SimpleStringProperty(this, "mountService", json.mountService);
|
||||
this.lastUpdateCheck = new SimpleStringProperty(this, "lastUpdateCheck", json.lastUpdateCheck);
|
||||
|
||||
this.directories.addAll(json.directories.stream().map(VaultSettings::new).toList());
|
||||
|
||||
migrateLegacySettings(json);
|
||||
|
||||
directories.addListener(this::somethingChanged);
|
||||
askedForUpdateCheck.addListener(this::somethingChanged);
|
||||
@@ -100,11 +129,77 @@ public class Settings {
|
||||
windowYPosition.addListener(this::somethingChanged);
|
||||
windowWidth.addListener(this::somethingChanged);
|
||||
windowHeight.addListener(this::somethingChanged);
|
||||
displayConfiguration.addListener(this::somethingChanged);
|
||||
language.addListener(this::somethingChanged);
|
||||
mountService.addListener(this::somethingChanged);
|
||||
lastUpdateCheck.addListener(this::somethingChanged);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private void migrateLegacySettings(SettingsJson json) {
|
||||
// implicit migration of 1.6.x legacy setting "preferredVolumeImpl":
|
||||
if (this.mountService.get() == null && json.preferredVolumeImpl != null) {
|
||||
this.mountService.set(switch (json.preferredVolumeImpl) {
|
||||
case "Dokany" -> "org.cryptomator.frontend.dokany.mount.DokanyMountProvider";
|
||||
case "FUSE" -> {
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
yield "org.cryptomator.frontend.fuse.mount.WinFspNetworkMountProvider";
|
||||
} else if (SystemUtils.IS_OS_MAC) {
|
||||
yield "org.cryptomator.frontend.fuse.mount.MacFuseMountProvider";
|
||||
} else {
|
||||
yield "org.cryptomator.frontend.fuse.mount.LinuxFuseMountProvider";
|
||||
}
|
||||
}
|
||||
default -> {
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
yield "org.cryptomator.frontend.webdav.mount.WindowsMounter";
|
||||
} else if (SystemUtils.IS_OS_MAC) {
|
||||
yield "org.cryptomator.frontend.webdav.mount.MacAppleScriptMounter";
|
||||
} else {
|
||||
yield "org.cryptomator.frontend.webdav.mount.LinuxGioMounter";
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
SettingsJson serialized() {
|
||||
var json = new SettingsJson();
|
||||
json.directories = directories.stream().map(VaultSettings::serialized).toList();
|
||||
json.askedForUpdateCheck = askedForUpdateCheck.get();
|
||||
json.checkForUpdatesEnabled = checkForUpdates.get();
|
||||
json.startHidden = startHidden.get();
|
||||
json.autoCloseVaults = autoCloseVaults.get();
|
||||
json.useKeychain = useKeychain.get();
|
||||
json.port = port.get();
|
||||
json.numTrayNotifications = numTrayNotifications.get();
|
||||
json.debugMode = debugMode.get();
|
||||
json.theme = theme.get();
|
||||
json.keychainProvider = keychainProvider.get();
|
||||
json.uiOrientation = userInterfaceOrientation.get().name();
|
||||
json.licenseKey = licenseKey.get();
|
||||
json.showMinimizeButton = showMinimizeButton.get();
|
||||
json.showTrayIcon = showTrayIcon.get();
|
||||
json.windowXPosition = windowXPosition.get();
|
||||
json.windowYPosition = windowYPosition.get();
|
||||
json.windowWidth = windowWidth.get();
|
||||
json.windowHeight = windowHeight.get();
|
||||
json.language = language.get();
|
||||
json.mountService = mountService.get();
|
||||
json.lastUpdateCheck = lastUpdateCheck.get();
|
||||
return json;
|
||||
}
|
||||
|
||||
private <E extends Enum<E>> E parseEnum(String value, Class<E> clazz, E defaultValue) {
|
||||
try {
|
||||
return Enum.valueOf(clazz, value.toUpperCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.warn("No value {}.{}. Defaulting to {}.", clazz.getSimpleName(), value, defaultValue);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO rename to setChangeListener
|
||||
void setSaveCmd(Consumer<Settings> saveCmd) {
|
||||
this.saveCmd = saveCmd;
|
||||
}
|
||||
@@ -119,90 +214,4 @@ public class Settings {
|
||||
}
|
||||
}
|
||||
|
||||
/* Getter/Setter */
|
||||
|
||||
public ObservableList<VaultSettings> getDirectories() {
|
||||
return directories;
|
||||
}
|
||||
|
||||
public BooleanProperty askedForUpdateCheck() {
|
||||
return askedForUpdateCheck;
|
||||
}
|
||||
|
||||
public BooleanProperty checkForUpdates() {
|
||||
return checkForUpdates;
|
||||
}
|
||||
|
||||
public BooleanProperty startHidden() {
|
||||
return startHidden;
|
||||
}
|
||||
|
||||
public BooleanProperty autoCloseVaults() {
|
||||
return autoCloseVaults;
|
||||
}
|
||||
|
||||
public BooleanProperty useKeychain() { return useKeychain; }
|
||||
|
||||
public IntegerProperty port() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public IntegerProperty numTrayNotifications() {
|
||||
return numTrayNotifications;
|
||||
}
|
||||
|
||||
public BooleanProperty debugMode() {
|
||||
return debugMode;
|
||||
}
|
||||
|
||||
public StringProperty mountService() {
|
||||
return mountService;
|
||||
}
|
||||
|
||||
public ObjectProperty<UiTheme> theme() {
|
||||
return theme;
|
||||
}
|
||||
|
||||
public ObjectProperty<String> keychainProvider() {return keychainProvider;}
|
||||
|
||||
public ObjectProperty<NodeOrientation> userInterfaceOrientation() {
|
||||
return userInterfaceOrientation;
|
||||
}
|
||||
|
||||
public StringProperty licenseKey() {
|
||||
return licenseKey;
|
||||
}
|
||||
|
||||
public BooleanProperty showMinimizeButton() {
|
||||
return showMinimizeButton;
|
||||
}
|
||||
|
||||
public BooleanProperty showTrayIcon() {
|
||||
return showTrayIcon;
|
||||
}
|
||||
|
||||
public IntegerProperty windowXPositionProperty() {
|
||||
return windowXPosition;
|
||||
}
|
||||
|
||||
public IntegerProperty windowYPositionProperty() {
|
||||
return windowYPosition;
|
||||
}
|
||||
|
||||
public IntegerProperty windowWidthProperty() {
|
||||
return windowWidth;
|
||||
}
|
||||
|
||||
public IntegerProperty windowHeightProperty() {
|
||||
return windowHeight;
|
||||
}
|
||||
|
||||
public ObjectProperty<String> displayConfigurationProperty() {
|
||||
return displayConfiguration;
|
||||
}
|
||||
|
||||
public StringProperty languageProperty() {
|
||||
return language;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
package org.cryptomator.common.settings;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
class SettingsJson {
|
||||
|
||||
@JsonProperty("directories")
|
||||
List<VaultSettingsJson> directories = List.of();
|
||||
|
||||
@JsonProperty("writtenByVersion")
|
||||
String writtenByVersion;
|
||||
|
||||
@JsonProperty("askedForUpdateCheck")
|
||||
boolean askedForUpdateCheck = Settings.DEFAULT_ASKED_FOR_UPDATE_CHECK;
|
||||
|
||||
@JsonProperty("autoCloseVaults")
|
||||
boolean autoCloseVaults = Settings.DEFAULT_AUTO_CLOSE_VAULTS;
|
||||
|
||||
@JsonProperty("checkForUpdatesEnabled")
|
||||
boolean checkForUpdatesEnabled = Settings.DEFAULT_CHECK_FOR_UPDATES;
|
||||
|
||||
@JsonProperty("debugMode")
|
||||
boolean debugMode = Settings.DEFAULT_DEBUG_MODE;
|
||||
|
||||
@JsonProperty("theme")
|
||||
UiTheme theme = Settings.DEFAULT_THEME;
|
||||
|
||||
@JsonProperty("keychainProvider")
|
||||
String keychainProvider = Settings.DEFAULT_KEYCHAIN_PROVIDER;
|
||||
|
||||
@JsonProperty("language")
|
||||
String language;
|
||||
|
||||
@JsonProperty("licenseKey")
|
||||
String licenseKey;
|
||||
|
||||
@JsonProperty("mountService")
|
||||
String mountService;
|
||||
|
||||
@JsonProperty("numTrayNotifications")
|
||||
int numTrayNotifications = Settings.DEFAULT_NUM_TRAY_NOTIFICATIONS;
|
||||
|
||||
@JsonProperty("port")
|
||||
int port = Settings.DEFAULT_PORT;
|
||||
|
||||
@JsonProperty("showMinimizeButton")
|
||||
boolean showMinimizeButton = Settings.DEFAULT_SHOW_MINIMIZE_BUTTON;
|
||||
|
||||
@JsonProperty("showTrayIcon")
|
||||
boolean showTrayIcon;
|
||||
|
||||
@JsonProperty("startHidden")
|
||||
boolean startHidden = Settings.DEFAULT_START_HIDDEN;
|
||||
|
||||
@JsonProperty("uiOrientation")
|
||||
String uiOrientation = Settings.DEFAULT_USER_INTERFACE_ORIENTATION;
|
||||
|
||||
@JsonProperty("useKeychain")
|
||||
boolean useKeychain = Settings.DEFAULT_USE_KEYCHAIN;
|
||||
|
||||
@JsonProperty("windowHeight")
|
||||
int windowHeight;
|
||||
|
||||
@JsonProperty("windowWidth")
|
||||
int windowWidth;
|
||||
|
||||
@JsonProperty("windowXPosition")
|
||||
int windowXPosition;
|
||||
|
||||
@JsonProperty("windowYPosition")
|
||||
int windowYPosition;
|
||||
|
||||
@Deprecated(since = "1.7.0")
|
||||
@JsonProperty(value = "preferredVolumeImpl", access = JsonProperty.Access.WRITE_ONLY) // WRITE_ONLY means value is "written" into the java object during deserialization. Upvote this: https://github.com/FasterXML/jackson-annotations/issues/233
|
||||
String preferredVolumeImpl;
|
||||
|
||||
@JsonProperty("lastUpdateCheck")
|
||||
String lastUpdateCheck = Settings.DEFAULT_LAST_UPDATE_CHECK;
|
||||
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Skymatic UG (haftungsbeschränkt).
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the accompanying LICENSE file.
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.common.settings;
|
||||
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javafx.geometry.NodeOrientation;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Singleton
|
||||
public class SettingsJsonAdapter extends TypeAdapter<Settings> {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SettingsJsonAdapter.class);
|
||||
|
||||
private final VaultSettingsJsonAdapter vaultSettingsJsonAdapter = new VaultSettingsJsonAdapter();
|
||||
private final Environment env;
|
||||
|
||||
@Inject
|
||||
public SettingsJsonAdapter(Environment env) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JsonWriter out, Settings value) throws IOException {
|
||||
out.beginObject();
|
||||
out.name("writtenByVersion").value(env.getAppVersion() + env.getBuildNumber().map("-"::concat).orElse(""));
|
||||
out.name("directories");
|
||||
writeVaultSettingsArray(out, value.getDirectories());
|
||||
out.name("askedForUpdateCheck").value(value.askedForUpdateCheck().get());
|
||||
out.name("autoCloseVaults").value(value.autoCloseVaults().get());
|
||||
out.name("checkForUpdatesEnabled").value(value.checkForUpdates().get());
|
||||
out.name("debugMode").value(value.debugMode().get());
|
||||
out.name("displayConfiguration").value((value.displayConfigurationProperty().get()));
|
||||
out.name("keychainProvider").value(value.keychainProvider().get());
|
||||
out.name("language").value((value.languageProperty().get()));
|
||||
out.name("licenseKey").value(value.licenseKey().get());
|
||||
out.name("mountService").value(value.mountService().get());
|
||||
out.name("numTrayNotifications").value(value.numTrayNotifications().get());
|
||||
out.name("port").value(value.port().get());
|
||||
out.name("showMinimizeButton").value(value.showMinimizeButton().get());
|
||||
out.name("showTrayIcon").value(value.showTrayIcon().get());
|
||||
out.name("startHidden").value(value.startHidden().get());
|
||||
out.name("theme").value(value.theme().get().name());
|
||||
out.name("uiOrientation").value(value.userInterfaceOrientation().get().name());
|
||||
out.name("useKeychain").value(value.useKeychain().get());
|
||||
out.name("windowHeight").value((value.windowHeightProperty().get()));
|
||||
out.name("windowWidth").value((value.windowWidthProperty().get()));
|
||||
out.name("windowXPosition").value((value.windowXPositionProperty().get()));
|
||||
out.name("windowYPosition").value((value.windowYPositionProperty().get()));
|
||||
out.endObject();
|
||||
}
|
||||
|
||||
private void writeVaultSettingsArray(JsonWriter out, Iterable<VaultSettings> vaultSettings) throws IOException {
|
||||
out.beginArray();
|
||||
for (VaultSettings value : vaultSettings) {
|
||||
vaultSettingsJsonAdapter.write(out, value);
|
||||
}
|
||||
out.endArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Settings read(JsonReader in) throws IOException {
|
||||
Settings settings = new Settings(env);
|
||||
//1.6.x legacy
|
||||
String volumeImpl = null;
|
||||
//legacy end
|
||||
in.beginObject();
|
||||
while (in.hasNext()) {
|
||||
String name = in.nextName();
|
||||
switch (name) {
|
||||
case "writtenByVersion" -> in.skipValue(); //noop
|
||||
case "directories" -> settings.getDirectories().addAll(readVaultSettingsArray(in));
|
||||
case "askedForUpdateCheck" -> settings.askedForUpdateCheck().set(in.nextBoolean());
|
||||
case "autoCloseVaults" -> settings.autoCloseVaults().set(in.nextBoolean());
|
||||
case "checkForUpdatesEnabled" -> settings.checkForUpdates().set(in.nextBoolean());
|
||||
case "debugMode" -> settings.debugMode().set(in.nextBoolean());
|
||||
case "displayConfiguration" -> settings.displayConfigurationProperty().set(in.nextString());
|
||||
case "keychainProvider" -> settings.keychainProvider().set(in.nextString());
|
||||
case "language" -> settings.languageProperty().set(in.nextString());
|
||||
case "licenseKey" -> settings.licenseKey().set(in.nextString());
|
||||
case "mountService" -> {
|
||||
var token = in.peek();
|
||||
if (JsonToken.STRING == token) {
|
||||
settings.mountService().set(in.nextString());
|
||||
}
|
||||
}
|
||||
case "numTrayNotifications" -> settings.numTrayNotifications().set(in.nextInt());
|
||||
case "port" -> settings.port().set(in.nextInt());
|
||||
case "showMinimizeButton" -> settings.showMinimizeButton().set(in.nextBoolean());
|
||||
case "showTrayIcon" -> settings.showTrayIcon().set(in.nextBoolean());
|
||||
case "startHidden" -> settings.startHidden().set(in.nextBoolean());
|
||||
case "theme" -> settings.theme().set(parseUiTheme(in.nextString()));
|
||||
case "uiOrientation" -> settings.userInterfaceOrientation().set(parseUiOrientation(in.nextString()));
|
||||
case "useKeychain" -> settings.useKeychain().set(in.nextBoolean());
|
||||
case "windowHeight" -> settings.windowHeightProperty().set(in.nextInt());
|
||||
case "windowWidth" -> settings.windowWidthProperty().set(in.nextInt());
|
||||
case "windowXPosition" -> settings.windowXPositionProperty().set(in.nextInt());
|
||||
case "windowYPosition" -> settings.windowYPositionProperty().set(in.nextInt());
|
||||
//1.6.x legacy
|
||||
case "preferredVolumeImpl" -> volumeImpl = in.nextString();
|
||||
//legacy end
|
||||
default -> {
|
||||
LOG.warn("Unsupported vault setting found in JSON: {}", name);
|
||||
in.skipValue();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
in.endObject();
|
||||
|
||||
//1.6.x legacy
|
||||
if (volumeImpl != null) {
|
||||
settings.mountService().set(convertLegacyVolumeImplToMountService(volumeImpl));
|
||||
}
|
||||
//legacy end
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
private String convertLegacyVolumeImplToMountService(String volumeImpl) {
|
||||
if (volumeImpl.equals("Dokany")) {
|
||||
return "org.cryptomator.frontend.dokany.mount.DokanyMountProvider";
|
||||
} else if (volumeImpl.equals("FUSE")) {
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
return "org.cryptomator.frontend.fuse.mount.WinFspNetworkMountProvider";
|
||||
} else if (SystemUtils.IS_OS_MAC) {
|
||||
return "org.cryptomator.frontend.fuse.mount.MacFuseMountProvider";
|
||||
} else {
|
||||
return "org.cryptomator.frontend.fuse.mount.LinuxFuseMountProvider";
|
||||
}
|
||||
} else {
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
return "org.cryptomator.frontend.webdav.mount.WindowsMounter";
|
||||
} else if (SystemUtils.IS_OS_MAC) {
|
||||
return "org.cryptomator.frontend.webdav.mount.MacAppleScriptMounter";
|
||||
} else {
|
||||
return "org.cryptomator.frontend.webdav.mount.LinuxGioMounter";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private UiTheme parseUiTheme(String uiThemeName) {
|
||||
try {
|
||||
return UiTheme.valueOf(uiThemeName.toUpperCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.warn("Invalid ui theme {}. Defaulting to {}.", uiThemeName, Settings.DEFAULT_THEME);
|
||||
return Settings.DEFAULT_THEME;
|
||||
}
|
||||
}
|
||||
|
||||
private NodeOrientation parseUiOrientation(String uiOrientationName) {
|
||||
try {
|
||||
return NodeOrientation.valueOf(uiOrientationName.toUpperCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.warn("Invalid ui orientation {}. Defaulting to {}.", uiOrientationName, Settings.DEFAULT_USER_INTERFACE_ORIENTATION);
|
||||
return Settings.DEFAULT_USER_INTERFACE_ORIENTATION;
|
||||
}
|
||||
}
|
||||
|
||||
private List<VaultSettings> readVaultSettingsArray(JsonReader in) throws IOException {
|
||||
List<VaultSettings> result = new ArrayList<>();
|
||||
in.beginArray();
|
||||
while (!JsonToken.END_ARRAY.equals(in.peek())) {
|
||||
result.add(vaultSettingsJsonAdapter.read(in));
|
||||
}
|
||||
in.endArray();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -8,12 +8,9 @@
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.common.settings;
|
||||
|
||||
import com.fasterxml.jackson.core.JacksonException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonParser;
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -22,12 +19,7 @@ import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
@@ -44,6 +36,7 @@ import java.util.stream.Stream;
|
||||
@Singleton
|
||||
public class SettingsProvider implements Supplier<Settings> {
|
||||
|
||||
private static final ObjectMapper JSON = new ObjectMapper().setDefaultLeniency(true);
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SettingsProvider.class);
|
||||
private static final long SAVE_DELAY_MS = 1000;
|
||||
|
||||
@@ -51,16 +44,11 @@ public class SettingsProvider implements Supplier<Settings> {
|
||||
private final Supplier<Settings> settings = Suppliers.memoize(this::load);
|
||||
private final Environment env;
|
||||
private final ScheduledExecutorService scheduler;
|
||||
private final Gson gson;
|
||||
|
||||
@Inject
|
||||
public SettingsProvider(SettingsJsonAdapter settingsJsonAdapter, Environment env, ScheduledExecutorService scheduler) {
|
||||
public SettingsProvider(Environment env, ScheduledExecutorService scheduler) {
|
||||
this.env = env;
|
||||
this.scheduler = scheduler;
|
||||
this.gson = new GsonBuilder() //
|
||||
.setPrettyPrinting().setLenient().disableHtmlEscaping() //
|
||||
.registerTypeAdapter(Settings.class, settingsJsonAdapter) //
|
||||
.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,28 +57,25 @@ public class SettingsProvider implements Supplier<Settings> {
|
||||
}
|
||||
|
||||
private Settings load() {
|
||||
Settings settings = env.getSettingsPath().flatMap(this::tryLoad).findFirst().orElse(new Settings(env));
|
||||
Settings settings = env.getSettingsPath().flatMap(this::tryLoad).findFirst().orElseGet(() -> Settings.create(env));
|
||||
settings.setSaveCmd(this::scheduleSave);
|
||||
return settings;
|
||||
}
|
||||
|
||||
private Stream<Settings> tryLoad(Path path) {
|
||||
LOG.debug("Attempting to load settings from {}", path);
|
||||
try (InputStream in = Files.newInputStream(path, StandardOpenOption.READ); //
|
||||
Reader reader = new InputStreamReader(in, StandardCharsets.UTF_8)) {
|
||||
JsonElement json = JsonParser.parseReader(reader);
|
||||
if (json.isJsonObject()) {
|
||||
Settings settings = gson.fromJson(json, Settings.class);
|
||||
LOG.info("Settings loaded from {}", path);
|
||||
return Stream.of(settings);
|
||||
} else {
|
||||
LOG.warn("Invalid json file {}", path);
|
||||
return Stream.empty();
|
||||
}
|
||||
try (InputStream in = Files.newInputStream(path, StandardOpenOption.READ)) {
|
||||
var json = JSON.reader().readValue(in, SettingsJson.class);
|
||||
LOG.info("Settings loaded from {}", path);
|
||||
var settings = new Settings(json);
|
||||
return Stream.of(settings);
|
||||
} catch (JacksonException e) {
|
||||
LOG.warn("Failed to parse json file {}", path, e);
|
||||
return Stream.empty();
|
||||
} catch (NoSuchFileException e) {
|
||||
return Stream.empty();
|
||||
} catch (IOException | JsonParseException e) {
|
||||
LOG.warn("Exception while loading settings from " + path, e);
|
||||
} catch (IOException e) {
|
||||
LOG.warn("Failed to load json file {}", path, e);
|
||||
return Stream.empty();
|
||||
}
|
||||
}
|
||||
@@ -116,13 +101,14 @@ public class SettingsProvider implements Supplier<Settings> {
|
||||
try {
|
||||
Files.createDirectories(settingsPath.getParent());
|
||||
Path tmpPath = settingsPath.resolveSibling(settingsPath.getFileName().toString() + ".tmp");
|
||||
try (OutputStream out = Files.newOutputStream(tmpPath, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE); //
|
||||
Writer writer = new OutputStreamWriter(out, StandardCharsets.UTF_8)) {
|
||||
gson.toJson(settings, writer);
|
||||
try (OutputStream out = Files.newOutputStream(tmpPath, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE)) {
|
||||
var jsonObj = settings.serialized();
|
||||
jsonObj.writtenByVersion = env.getAppVersion() + env.getBuildNumber().map("-"::concat).orElse("");
|
||||
JSON.writerWithDefaultPrettyPrinter().writeValue(out, jsonObj);
|
||||
}
|
||||
Files.move(tmpPath, settingsPath, StandardCopyOption.REPLACE_EXISTING);
|
||||
LOG.info("Settings saved to {}", settingsPath);
|
||||
} catch (IOException | JsonParseException e) {
|
||||
} catch (IOException e) {
|
||||
LOG.error("Failed to save settings.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package org.cryptomator.common.settings;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||
public enum UiTheme {
|
||||
LIGHT("preferences.interface.theme.light"), //
|
||||
@JsonEnumDefaultValue LIGHT("preferences.interface.theme.light"), //
|
||||
DARK("preferences.interface.theme.dark"), //
|
||||
AUTOMATIC("preferences.interface.theme.automatic");
|
||||
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
package org.cryptomator.common.settings;
|
||||
|
||||
import com.google.common.base.CharMatcher;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import org.jetbrains.annotations.VisibleForTesting;
|
||||
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.binding.Bindings;
|
||||
@@ -20,6 +22,7 @@ import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
|
||||
@@ -28,33 +31,50 @@ import java.util.Random;
|
||||
*/
|
||||
public class VaultSettings {
|
||||
|
||||
public static final boolean DEFAULT_UNLOCK_AFTER_STARTUP = false;
|
||||
public static final boolean DEFAULT_REVEAL_AFTER_MOUNT = true;
|
||||
public static final boolean DEFAULT_USES_READONLY_MODE = false;
|
||||
public static final String DEFAULT_MOUNT_FLAGS = "";
|
||||
public static final int DEFAULT_MAX_CLEARTEXT_FILENAME_LENGTH = -1;
|
||||
public static final WhenUnlocked DEFAULT_ACTION_AFTER_UNLOCK = WhenUnlocked.ASK;
|
||||
public static final boolean DEFAULT_AUTOLOCK_WHEN_IDLE = false;
|
||||
public static final int DEFAULT_AUTOLOCK_IDLE_SECONDS = 30 * 60;
|
||||
static final boolean DEFAULT_UNLOCK_AFTER_STARTUP = false;
|
||||
static final boolean DEFAULT_REVEAL_AFTER_MOUNT = true;
|
||||
static final boolean DEFAULT_USES_READONLY_MODE = false;
|
||||
static final String DEFAULT_MOUNT_FLAGS = ""; // TODO: remove empty default mount flags and let this property be null if not used
|
||||
static final int DEFAULT_MAX_CLEARTEXT_FILENAME_LENGTH = -1;
|
||||
static final WhenUnlocked DEFAULT_ACTION_AFTER_UNLOCK = WhenUnlocked.ASK;
|
||||
static final boolean DEFAULT_AUTOLOCK_WHEN_IDLE = false;
|
||||
static final int DEFAULT_AUTOLOCK_IDLE_SECONDS = 30 * 60;
|
||||
static final int DEFAULT_PORT = 42427;
|
||||
|
||||
private static final Random RNG = new Random();
|
||||
|
||||
private final String id;
|
||||
private final ObjectProperty<Path> path = new SimpleObjectProperty<>();
|
||||
private final StringProperty displayName = new SimpleStringProperty();
|
||||
private final BooleanProperty unlockAfterStartup = new SimpleBooleanProperty(DEFAULT_UNLOCK_AFTER_STARTUP);
|
||||
private final BooleanProperty revealAfterMount = new SimpleBooleanProperty(DEFAULT_REVEAL_AFTER_MOUNT);
|
||||
private final BooleanProperty usesReadOnlyMode = new SimpleBooleanProperty(DEFAULT_USES_READONLY_MODE);
|
||||
private final StringProperty mountFlags = new SimpleStringProperty(DEFAULT_MOUNT_FLAGS); //TODO: remove empty default mount flags and let this property be null if not used
|
||||
private final IntegerProperty maxCleartextFilenameLength = new SimpleIntegerProperty(DEFAULT_MAX_CLEARTEXT_FILENAME_LENGTH);
|
||||
private final ObjectProperty<WhenUnlocked> actionAfterUnlock = new SimpleObjectProperty<>(DEFAULT_ACTION_AFTER_UNLOCK);
|
||||
private final BooleanProperty autoLockWhenIdle = new SimpleBooleanProperty(DEFAULT_AUTOLOCK_WHEN_IDLE);
|
||||
private final IntegerProperty autoLockIdleSeconds = new SimpleIntegerProperty(DEFAULT_AUTOLOCK_IDLE_SECONDS);
|
||||
private final StringExpression mountName;
|
||||
private final ObjectProperty<Path> mountPoint = new SimpleObjectProperty<>();
|
||||
public final String id;
|
||||
public final ObjectProperty<Path> path;
|
||||
public final StringProperty displayName;
|
||||
public final BooleanProperty unlockAfterStartup;
|
||||
public final BooleanProperty revealAfterMount;
|
||||
public final BooleanProperty usesReadOnlyMode;
|
||||
public final StringProperty mountFlags;
|
||||
public final IntegerProperty maxCleartextFilenameLength;
|
||||
public final ObjectProperty<WhenUnlocked> actionAfterUnlock;
|
||||
public final BooleanProperty autoLockWhenIdle;
|
||||
public final IntegerProperty autoLockIdleSeconds;
|
||||
public final ObjectProperty<Path> mountPoint;
|
||||
public final StringExpression mountName;
|
||||
public final StringProperty mountService;
|
||||
public final IntegerProperty port;
|
||||
|
||||
public VaultSettings(String id) {
|
||||
this.id = Objects.requireNonNull(id);
|
||||
VaultSettings(VaultSettingsJson json) {
|
||||
this.id = json.id;
|
||||
this.path = new SimpleObjectProperty<>(this, "path", json.path == null ? null : Paths.get(json.path));
|
||||
this.displayName = new SimpleStringProperty(this, "displayName", json.displayName);
|
||||
this.unlockAfterStartup = new SimpleBooleanProperty(this, "unlockAfterStartup", json.unlockAfterStartup);
|
||||
this.revealAfterMount = new SimpleBooleanProperty(this, "revealAfterMount", json.revealAfterMount);
|
||||
this.usesReadOnlyMode = new SimpleBooleanProperty(this, "usesReadOnlyMode", json.usesReadOnlyMode);
|
||||
this.mountFlags = new SimpleStringProperty(this, "mountFlags", json.mountFlags);
|
||||
this.maxCleartextFilenameLength = new SimpleIntegerProperty(this, "maxCleartextFilenameLength", json.maxCleartextFilenameLength);
|
||||
this.actionAfterUnlock = new SimpleObjectProperty<>(this, "actionAfterUnlock", json.actionAfterUnlock);
|
||||
this.autoLockWhenIdle = new SimpleBooleanProperty(this, "autoLockWhenIdle", json.autoLockWhenIdle);
|
||||
this.autoLockIdleSeconds = new SimpleIntegerProperty(this, "autoLockIdleSeconds", json.autoLockIdleSeconds);
|
||||
this.mountPoint = new SimpleObjectProperty<>(this, "mountPoint", json.mountPoint == null ? null : Path.of(json.mountPoint));
|
||||
this.mountService = new SimpleStringProperty(this, "mountService", json.mountService);
|
||||
this.port = new SimpleIntegerProperty(this, "port", json.port);
|
||||
// mount name is no longer an explicit setting, see https://github.com/cryptomator/cryptomator/pull/1318
|
||||
this.mountName = StringExpression.stringExpression(Bindings.createStringBinding(() -> {
|
||||
final String name;
|
||||
if (displayName.isEmpty().get()) {
|
||||
@@ -64,14 +84,28 @@ public class VaultSettings {
|
||||
}
|
||||
return normalizeDisplayName(name);
|
||||
}, displayName, path));
|
||||
|
||||
migrateLegacySettings(json);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private void migrateLegacySettings(VaultSettingsJson json) {
|
||||
// implicit migration of 1.6.x legacy setting "customMountPath" / "winDriveLetter":
|
||||
if (json.useCustomMountPath && !Strings.isNullOrEmpty(json.customMountPath)) {
|
||||
this.mountPoint.set(Path.of(json.customMountPath));
|
||||
} else if (!Strings.isNullOrEmpty(json.winDriveLetter)) {
|
||||
this.mountPoint.set(Path.of(json.winDriveLetter + ":\\"));
|
||||
}
|
||||
}
|
||||
|
||||
Observable[] observables() {
|
||||
return new Observable[]{actionAfterUnlock, autoLockIdleSeconds, autoLockWhenIdle, displayName, maxCleartextFilenameLength, mountFlags, mountPoint, path, revealAfterMount, unlockAfterStartup, usesReadOnlyMode};
|
||||
return new Observable[]{actionAfterUnlock, autoLockIdleSeconds, autoLockWhenIdle, displayName, maxCleartextFilenameLength, mountFlags, mountPoint, path, revealAfterMount, unlockAfterStartup, usesReadOnlyMode, port, mountService};
|
||||
}
|
||||
|
||||
public static VaultSettings withRandomId() {
|
||||
return new VaultSettings(generateId());
|
||||
var defaults = new VaultSettingsJson();
|
||||
defaults.id = generateId();
|
||||
return new VaultSettings(defaults);
|
||||
}
|
||||
|
||||
private static String generateId() {
|
||||
@@ -80,7 +114,26 @@ public class VaultSettings {
|
||||
return BaseEncoding.base64Url().encode(randomBytes);
|
||||
}
|
||||
|
||||
//visible for testing
|
||||
VaultSettingsJson serialized() {
|
||||
var json = new VaultSettingsJson();
|
||||
json.id = id;
|
||||
json.path = path.map(Path::toString).getValue();
|
||||
json.displayName = displayName.get();
|
||||
json.unlockAfterStartup = unlockAfterStartup.get();
|
||||
json.revealAfterMount = revealAfterMount.get();
|
||||
json.usesReadOnlyMode = usesReadOnlyMode.get();
|
||||
json.mountFlags = mountFlags.get();
|
||||
json.maxCleartextFilenameLength = maxCleartextFilenameLength.get();
|
||||
json.actionAfterUnlock = actionAfterUnlock.get();
|
||||
json.autoLockWhenIdle = autoLockWhenIdle.get();
|
||||
json.autoLockIdleSeconds = autoLockIdleSeconds.get();
|
||||
json.mountPoint = mountPoint.map(Path::toString).getValue();
|
||||
json.mountService = mountService.get();
|
||||
json.port = port.get();
|
||||
return json;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static String normalizeDisplayName(String original) {
|
||||
if (original.isBlank() || ".".equals(original) || "..".equals(original)) {
|
||||
return "_";
|
||||
@@ -93,68 +146,6 @@ public class VaultSettings {
|
||||
return CharMatcher.anyOf("<>:\"/\\|?*").or(CharMatcher.javaIsoControl()).collapseFrom(withoutFancyWhitespaces, '_');
|
||||
}
|
||||
|
||||
/* Getter/Setter */
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public ObjectProperty<Path> path() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public StringProperty displayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public StringExpression mountName() {
|
||||
return mountName;
|
||||
}
|
||||
|
||||
public BooleanProperty unlockAfterStartup() {
|
||||
return unlockAfterStartup;
|
||||
}
|
||||
|
||||
public BooleanProperty revealAfterMount() {
|
||||
return revealAfterMount;
|
||||
}
|
||||
|
||||
public Path getMountPoint() {
|
||||
return mountPoint.get();
|
||||
}
|
||||
|
||||
public ObjectProperty<Path> mountPoint() {
|
||||
return mountPoint;
|
||||
}
|
||||
|
||||
public BooleanProperty usesReadOnlyMode() {
|
||||
return usesReadOnlyMode;
|
||||
}
|
||||
|
||||
public StringProperty mountFlags() {
|
||||
return mountFlags;
|
||||
}
|
||||
|
||||
public IntegerProperty maxCleartextFilenameLength() {
|
||||
return maxCleartextFilenameLength;
|
||||
}
|
||||
|
||||
public ObjectProperty<WhenUnlocked> actionAfterUnlock() {
|
||||
return actionAfterUnlock;
|
||||
}
|
||||
|
||||
public WhenUnlocked getActionAfterUnlock() {
|
||||
return actionAfterUnlock.get();
|
||||
}
|
||||
|
||||
public BooleanProperty autoLockWhenIdle() {
|
||||
return autoLockWhenIdle;
|
||||
}
|
||||
|
||||
public IntegerProperty autoLockIdleSeconds() {
|
||||
return autoLockIdleSeconds;
|
||||
}
|
||||
|
||||
/* Hashcode/Equals */
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package org.cryptomator.common.settings;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAlias;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
class VaultSettingsJson {
|
||||
|
||||
@JsonProperty(value = "id", required = true)
|
||||
String id;
|
||||
|
||||
@JsonProperty(value = "path")
|
||||
String path;
|
||||
|
||||
@JsonProperty("displayName")
|
||||
String displayName;
|
||||
|
||||
@JsonProperty("unlockAfterStartup")
|
||||
boolean unlockAfterStartup = VaultSettings.DEFAULT_UNLOCK_AFTER_STARTUP;
|
||||
|
||||
@JsonProperty("revealAfterMount")
|
||||
boolean revealAfterMount = VaultSettings.DEFAULT_REVEAL_AFTER_MOUNT;
|
||||
|
||||
@JsonProperty("mountPoint")
|
||||
String mountPoint;
|
||||
|
||||
@JsonProperty("usesReadOnlyMode")
|
||||
boolean usesReadOnlyMode = VaultSettings.DEFAULT_USES_READONLY_MODE;
|
||||
|
||||
@JsonProperty("mountFlags")
|
||||
String mountFlags = VaultSettings.DEFAULT_MOUNT_FLAGS;
|
||||
|
||||
@JsonProperty("maxCleartextFilenameLength")
|
||||
int maxCleartextFilenameLength = VaultSettings.DEFAULT_MAX_CLEARTEXT_FILENAME_LENGTH;
|
||||
|
||||
@JsonProperty("actionAfterUnlock")
|
||||
WhenUnlocked actionAfterUnlock = VaultSettings.DEFAULT_ACTION_AFTER_UNLOCK;
|
||||
|
||||
@JsonProperty("autoLockWhenIdle")
|
||||
boolean autoLockWhenIdle = VaultSettings.DEFAULT_AUTOLOCK_WHEN_IDLE;
|
||||
|
||||
@JsonProperty("autoLockIdleSeconds")
|
||||
int autoLockIdleSeconds = VaultSettings.DEFAULT_AUTOLOCK_IDLE_SECONDS;
|
||||
|
||||
@JsonProperty("mountService")
|
||||
String mountService;
|
||||
|
||||
@JsonProperty("port")
|
||||
int port = VaultSettings.DEFAULT_PORT;
|
||||
|
||||
@Deprecated(since = "1.7.0")
|
||||
@JsonProperty(value = "winDriveLetter", access = JsonProperty.Access.WRITE_ONLY) // WRITE_ONLY means value is "written" into the java object during deserialization. Upvote this: https://github.com/FasterXML/jackson-annotations/issues/233
|
||||
String winDriveLetter;
|
||||
|
||||
@Deprecated(since = "1.7.0")
|
||||
@JsonProperty(value = "useCustomMountPath", access = JsonProperty.Access.WRITE_ONLY) // WRITE_ONLY means value is "written" into the java object during deserialization. Upvote this: https://github.com/FasterXML/jackson-annotations/issues/233
|
||||
@JsonAlias("usesIndividualMountPath")
|
||||
boolean useCustomMountPath;
|
||||
|
||||
@Deprecated(since = "1.7.0")
|
||||
@JsonProperty(value = "customMountPath", access = JsonProperty.Access.WRITE_ONLY) // WRITE_ONLY means value is "written" into the java object during deserialization. Upvote this: https://github.com/FasterXML/jackson-annotations/issues/233
|
||||
@JsonAlias("individualMountPath")
|
||||
String customMountPath;
|
||||
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Skymatic UG (haftungsbeschränkt).
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the accompanying LICENSE file.
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.common.settings;
|
||||
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
class VaultSettingsJsonAdapter {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(VaultSettingsJsonAdapter.class);
|
||||
|
||||
public void write(JsonWriter out, VaultSettings value) throws IOException {
|
||||
out.beginObject();
|
||||
out.name("id").value(value.getId());
|
||||
out.name("path").value(value.path().get().toString());
|
||||
out.name("displayName").value(value.displayName().get());
|
||||
out.name("unlockAfterStartup").value(value.unlockAfterStartup().get());
|
||||
out.name("revealAfterMount").value(value.revealAfterMount().get());
|
||||
var mountPoint = value.mountPoint().get();
|
||||
out.name("mountPoint").value(mountPoint != null ? mountPoint.toAbsolutePath().toString() : null);
|
||||
out.name("usesReadOnlyMode").value(value.usesReadOnlyMode().get());
|
||||
out.name("mountFlags").value(value.mountFlags().get());
|
||||
out.name("maxCleartextFilenameLength").value(value.maxCleartextFilenameLength().get());
|
||||
out.name("actionAfterUnlock").value(value.actionAfterUnlock().get().name());
|
||||
out.name("autoLockWhenIdle").value(value.autoLockWhenIdle().get());
|
||||
out.name("autoLockIdleSeconds").value(value.autoLockIdleSeconds().get());
|
||||
out.endObject();
|
||||
}
|
||||
|
||||
public VaultSettings read(JsonReader in) throws IOException {
|
||||
String id = null;
|
||||
String path = null;
|
||||
String mountName = null; //see https://github.com/cryptomator/cryptomator/pull/1318
|
||||
String displayName = null;
|
||||
boolean unlockAfterStartup = VaultSettings.DEFAULT_UNLOCK_AFTER_STARTUP;
|
||||
boolean revealAfterMount = VaultSettings.DEFAULT_REVEAL_AFTER_MOUNT;
|
||||
boolean usesReadOnlyMode = VaultSettings.DEFAULT_USES_READONLY_MODE;
|
||||
String mountFlags = VaultSettings.DEFAULT_MOUNT_FLAGS;
|
||||
Path mountPoint = null;
|
||||
int maxCleartextFilenameLength = VaultSettings.DEFAULT_MAX_CLEARTEXT_FILENAME_LENGTH;
|
||||
WhenUnlocked actionAfterUnlock = VaultSettings.DEFAULT_ACTION_AFTER_UNLOCK;
|
||||
boolean autoLockWhenIdle = VaultSettings.DEFAULT_AUTOLOCK_WHEN_IDLE;
|
||||
int autoLockIdleSeconds = VaultSettings.DEFAULT_AUTOLOCK_IDLE_SECONDS;
|
||||
|
||||
//legacy from 1.6.x
|
||||
boolean useCustomMountPath = false;
|
||||
String customMountPath = "";
|
||||
String winDriveLetter = "";
|
||||
//legacy end
|
||||
|
||||
in.beginObject();
|
||||
while (in.hasNext()) {
|
||||
String name = in.nextName();
|
||||
switch (name) {
|
||||
case "id" -> id = in.nextString();
|
||||
case "path" -> path = in.nextString();
|
||||
case "mountName" -> mountName = in.nextString(); //see https://github.com/cryptomator/cryptomator/pull/1318
|
||||
case "displayName" -> displayName = in.nextString();
|
||||
case "unlockAfterStartup" -> unlockAfterStartup = in.nextBoolean();
|
||||
case "revealAfterMount" -> revealAfterMount = in.nextBoolean();
|
||||
case "usesReadOnlyMode" -> usesReadOnlyMode = in.nextBoolean();
|
||||
case "mountFlags" -> mountFlags = in.nextString();
|
||||
case "mountPoint" -> {
|
||||
if (JsonToken.NULL == in.peek()) {
|
||||
in.nextNull();
|
||||
} else {
|
||||
mountPoint = parseMountPoint(in.nextString());
|
||||
}
|
||||
}
|
||||
case "maxCleartextFilenameLength" -> maxCleartextFilenameLength = in.nextInt();
|
||||
case "actionAfterUnlock" -> actionAfterUnlock = parseActionAfterUnlock(in.nextString());
|
||||
case "autoLockWhenIdle" -> autoLockWhenIdle = in.nextBoolean();
|
||||
case "autoLockIdleSeconds" -> autoLockIdleSeconds = in.nextInt();
|
||||
//legacy from 1.6.x
|
||||
case "winDriveLetter" -> winDriveLetter = in.nextString();
|
||||
case "usesIndividualMountPath", "useCustomMountPath" -> useCustomMountPath = in.nextBoolean();
|
||||
case "individualMountPath", "customMountPath" -> customMountPath = in.nextString();
|
||||
//legacy end
|
||||
default -> {
|
||||
LOG.warn("Unsupported vault setting found in JSON: {}", name);
|
||||
in.skipValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
in.endObject();
|
||||
|
||||
VaultSettings vaultSettings = (id == null) ? VaultSettings.withRandomId() : new VaultSettings(id);
|
||||
if (displayName != null) { //see https://github.com/cryptomator/cryptomator/pull/1318
|
||||
vaultSettings.displayName().set(displayName);
|
||||
} else {
|
||||
vaultSettings.displayName().set(mountName);
|
||||
}
|
||||
vaultSettings.path().set(Paths.get(path));
|
||||
vaultSettings.unlockAfterStartup().set(unlockAfterStartup);
|
||||
vaultSettings.revealAfterMount().set(revealAfterMount);
|
||||
vaultSettings.usesReadOnlyMode().set(usesReadOnlyMode);
|
||||
vaultSettings.mountFlags().set(mountFlags);
|
||||
vaultSettings.maxCleartextFilenameLength().set(maxCleartextFilenameLength);
|
||||
vaultSettings.actionAfterUnlock().set(actionAfterUnlock);
|
||||
vaultSettings.autoLockWhenIdle().set(autoLockWhenIdle);
|
||||
vaultSettings.autoLockIdleSeconds().set(autoLockIdleSeconds);
|
||||
vaultSettings.mountPoint().set(mountPoint);
|
||||
//legacy from 1.6.x
|
||||
if(useCustomMountPath && !customMountPath.isBlank()) {
|
||||
vaultSettings.mountPoint().set(parseMountPoint(customMountPath));
|
||||
} else if(!winDriveLetter.isBlank() ) {
|
||||
vaultSettings.mountPoint().set(parseMountPoint(winDriveLetter+":\\"));
|
||||
}
|
||||
//legacy end
|
||||
return vaultSettings;
|
||||
}
|
||||
|
||||
private Path parseMountPoint(String mountPoint) {
|
||||
try {
|
||||
return Path.of(mountPoint);
|
||||
} catch (InvalidPathException e) {
|
||||
LOG.warn("Invalid string as mount point. Defaulting to null.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private WhenUnlocked parseActionAfterUnlock(String actionAfterUnlockName) {
|
||||
try {
|
||||
return WhenUnlocked.valueOf(actionAfterUnlockName.toUpperCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.warn("Invalid action after unlock {}. Defaulting to {}.", actionAfterUnlockName, VaultSettings.DEFAULT_ACTION_AFTER_UNLOCK);
|
||||
return VaultSettings.DEFAULT_ACTION_AFTER_UNLOCK;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +1,13 @@
|
||||
package org.cryptomator.common.settings;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING)
|
||||
public enum WhenUnlocked {
|
||||
IGNORE("vaultOptions.general.actionAfterUnlock.ignore"),
|
||||
REVEAL("vaultOptions.general.actionAfterUnlock.reveal"),
|
||||
ASK("vaultOptions.general.actionAfterUnlock.ask");
|
||||
@JsonEnumDefaultValue ASK("vaultOptions.general.actionAfterUnlock.ask");
|
||||
|
||||
private String displayName;
|
||||
|
||||
|
||||
@@ -50,8 +50,8 @@ public class AutoLocker {
|
||||
|
||||
private boolean exceedsIdleTime(Vault vault) {
|
||||
assert vault.isUnlocked();
|
||||
if (vault.getVaultSettings().autoLockWhenIdle().get()) {
|
||||
int maxIdleSeconds = vault.getVaultSettings().autoLockIdleSeconds().get();
|
||||
if (vault.getVaultSettings().autoLockWhenIdle.get()) {
|
||||
int maxIdleSeconds = vault.getVaultSettings().autoLockIdleSeconds.get();
|
||||
var deadline = vault.getStats().getLastActivity().plusSeconds(maxIdleSeconds);
|
||||
return deadline.isBefore(Instant.now());
|
||||
} else {
|
||||
|
||||
@@ -11,7 +11,6 @@ package org.cryptomator.common.vaults;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.Constants;
|
||||
import org.cryptomator.common.mount.Mounter;
|
||||
import org.cryptomator.common.mount.WindowsDriveLetters;
|
||||
import org.cryptomator.common.settings.VaultSettings;
|
||||
import org.cryptomator.cryptofs.CryptoFileSystem;
|
||||
import org.cryptomator.cryptofs.CryptoFileSystemProperties;
|
||||
@@ -70,17 +69,23 @@ public class Vault {
|
||||
private final Mounter mounter;
|
||||
private final BooleanProperty showingStats;
|
||||
|
||||
private AtomicReference<Mounter.MountHandle> mountHandle = new AtomicReference<>(null);
|
||||
private final AtomicReference<Mounter.MountHandle> mountHandle = new AtomicReference<>(null);
|
||||
|
||||
@Inject
|
||||
Vault(VaultSettings vaultSettings, VaultConfigCache configCache, AtomicReference<CryptoFileSystem> cryptoFileSystem, VaultState state, @Named("lastKnownException") ObjectProperty<Exception> lastKnownException, VaultStats stats, WindowsDriveLetters windowsDriveLetters, Mounter mounter) {
|
||||
Vault(VaultSettings vaultSettings, //
|
||||
VaultConfigCache configCache, //
|
||||
AtomicReference<CryptoFileSystem> cryptoFileSystem, //
|
||||
VaultState state, //
|
||||
@Named("lastKnownException") ObjectProperty<Exception> lastKnownException, //
|
||||
VaultStats stats, //
|
||||
Mounter mounter) {
|
||||
this.vaultSettings = vaultSettings;
|
||||
this.configCache = configCache;
|
||||
this.cryptoFileSystem = cryptoFileSystem;
|
||||
this.state = state;
|
||||
this.lastKnownException = lastKnownException;
|
||||
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.processing = Bindings.createBooleanBinding(this::isProcessing, state);
|
||||
this.unlocked = Bindings.createBooleanBinding(this::isUnlocked, state);
|
||||
@@ -98,29 +103,29 @@ public class Vault {
|
||||
|
||||
private CryptoFileSystem createCryptoFileSystem(MasterkeyLoader keyLoader) throws IOException, MasterkeyLoadingFailedException {
|
||||
Set<FileSystemFlags> flags = EnumSet.noneOf(FileSystemFlags.class);
|
||||
if (vaultSettings.usesReadOnlyMode().get()) {
|
||||
if (vaultSettings.usesReadOnlyMode.get()) {
|
||||
flags.add(FileSystemFlags.READONLY);
|
||||
} else if (vaultSettings.maxCleartextFilenameLength().get() == -1) {
|
||||
} else if (vaultSettings.maxCleartextFilenameLength.get() == -1) {
|
||||
LOG.debug("Determining cleartext filename length limitations...");
|
||||
var checker = new FileSystemCapabilityChecker();
|
||||
int shorteningThreshold = configCache.get().allegedShorteningThreshold();
|
||||
int ciphertextLimit = checker.determineSupportedCiphertextFileNameLength(getPath());
|
||||
if (ciphertextLimit < shorteningThreshold) {
|
||||
int cleartextLimit = checker.determineSupportedCleartextFileNameLength(getPath());
|
||||
vaultSettings.maxCleartextFilenameLength().set(cleartextLimit);
|
||||
vaultSettings.maxCleartextFilenameLength.set(cleartextLimit);
|
||||
} else {
|
||||
vaultSettings.maxCleartextFilenameLength().setValue(UNLIMITED_FILENAME_LENGTH);
|
||||
vaultSettings.maxCleartextFilenameLength.setValue(UNLIMITED_FILENAME_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
if (vaultSettings.maxCleartextFilenameLength().get() < UNLIMITED_FILENAME_LENGTH) {
|
||||
LOG.warn("Limiting cleartext filename length on this device to {}.", vaultSettings.maxCleartextFilenameLength().get());
|
||||
if (vaultSettings.maxCleartextFilenameLength.get() < UNLIMITED_FILENAME_LENGTH) {
|
||||
LOG.warn("Limiting cleartext filename length on this device to {}.", vaultSettings.maxCleartextFilenameLength.get());
|
||||
}
|
||||
|
||||
CryptoFileSystemProperties fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties() //
|
||||
.withKeyLoader(keyLoader) //
|
||||
.withFlags(flags) //
|
||||
.withMaxCleartextNameLength(vaultSettings.maxCleartextFilenameLength().get()) //
|
||||
.withMaxCleartextNameLength(vaultSettings.maxCleartextFilenameLength.get()) //
|
||||
.withVaultConfigFilename(Constants.VAULTCONFIG_FILENAME) //
|
||||
.build();
|
||||
return CryptoFileSystemProvider.newFileSystem(getPath(), fsProps);
|
||||
@@ -253,11 +258,11 @@ public class Vault {
|
||||
}
|
||||
|
||||
public ReadOnlyStringProperty displayNameProperty() {
|
||||
return vaultSettings.displayName();
|
||||
return vaultSettings.displayName;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return vaultSettings.displayName().get();
|
||||
return vaultSettings.displayName.get();
|
||||
}
|
||||
|
||||
public ObjectBinding<Mountpoint> mountPointProperty() {
|
||||
@@ -274,7 +279,7 @@ public class Vault {
|
||||
}
|
||||
|
||||
public String getDisplayablePath() {
|
||||
Path p = vaultSettings.path().get();
|
||||
Path p = vaultSettings.path.get();
|
||||
if (p.startsWith(HOME_DIR)) {
|
||||
Path relativePath = HOME_DIR.relativize(p);
|
||||
String homePrefix = SystemUtils.IS_OS_WINDOWS ? "~\\" : "~/";
|
||||
@@ -311,7 +316,7 @@ public class Vault {
|
||||
}
|
||||
|
||||
public Path getPath() {
|
||||
return vaultSettings.path().getValue();
|
||||
return vaultSettings.path.get();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -346,7 +351,7 @@ public class Vault {
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return vaultSettings.getId();
|
||||
return vaultSettings.id;
|
||||
}
|
||||
|
||||
// ******************************************************************************
|
||||
|
||||
@@ -27,7 +27,7 @@ public class VaultConfigCache {
|
||||
|
||||
void reloadConfig() throws IOException {
|
||||
try {
|
||||
config.set(readConfigFromStorage(this.settings.path().get()));
|
||||
config.set(readConfigFromStorage(this.settings.path.get()));
|
||||
} catch (IOException e) {
|
||||
config.set(null);
|
||||
throw e;
|
||||
|
||||
@@ -49,8 +49,8 @@ public class VaultListManager {
|
||||
this.vaultComponentFactory = vaultComponentFactory;
|
||||
this.defaultVaultName = resourceBundle.getString("defaults.vault.vaultName");
|
||||
|
||||
addAll(settings.getDirectories());
|
||||
vaultList.addListener(new VaultListChangeListener(settings.getDirectories()));
|
||||
addAll(settings.directories);
|
||||
vaultList.addListener(new VaultListChangeListener(settings.directories));
|
||||
autoLocker.init();
|
||||
}
|
||||
|
||||
@@ -70,11 +70,11 @@ public class VaultListManager {
|
||||
|
||||
private VaultSettings newVaultSettings(Path path) {
|
||||
VaultSettings vaultSettings = VaultSettings.withRandomId();
|
||||
vaultSettings.path().set(path);
|
||||
vaultSettings.path.set(path);
|
||||
if (path.getFileName() != null) {
|
||||
vaultSettings.displayName().set(path.getFileName().toString());
|
||||
vaultSettings.displayName.set(path.getFileName().toString());
|
||||
} else {
|
||||
vaultSettings.displayName().set(defaultVaultName);
|
||||
vaultSettings.displayName.set(defaultVaultName);
|
||||
}
|
||||
return vaultSettings;
|
||||
}
|
||||
@@ -95,13 +95,13 @@ public class VaultListManager {
|
||||
private Vault create(VaultSettings vaultSettings) {
|
||||
var wrapper = new VaultConfigCache(vaultSettings);
|
||||
try {
|
||||
var vaultState = determineVaultState(vaultSettings.path().get());
|
||||
var vaultState = determineVaultState(vaultSettings.path.get());
|
||||
if (vaultState == LOCKED) { //for legacy reasons: pre v8 vault do not have a config, but they are in the NEEDS_MIGRATION state
|
||||
wrapper.reloadConfig();
|
||||
}
|
||||
return vaultComponentFactory.create(vaultSettings, wrapper, vaultState, null).vault();
|
||||
} catch (IOException e) {
|
||||
LOG.warn("Failed to determine vault state for " + vaultSettings.path().get(), e);
|
||||
LOG.warn("Failed to determine vault state for " + vaultSettings.path.get(), e);
|
||||
return vaultComponentFactory.create(vaultSettings, wrapper, ERROR, e).vault();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import dagger.Lazy;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.cryptomator.common.SubstitutingProperties;
|
||||
import org.cryptomator.common.ShutdownHook;
|
||||
import org.cryptomator.ipc.IpcCommunicator;
|
||||
import org.cryptomator.logging.DebugMode;
|
||||
@@ -29,10 +30,18 @@ import java.util.concurrent.Executors;
|
||||
public class Cryptomator {
|
||||
|
||||
private static final long STARTUP_TIME = System.currentTimeMillis();
|
||||
|
||||
static {
|
||||
var lazyProcessedProps = new SubstitutingProperties(System.getProperties(), System.getenv());
|
||||
System.setProperties(lazyProcessedProps);
|
||||
CRYPTOMATOR_COMPONENT = DaggerCryptomatorComponent.factory().create(STARTUP_TIME);
|
||||
LOG = LoggerFactory.getLogger(Cryptomator.class);
|
||||
}
|
||||
|
||||
// DaggerCryptomatorComponent gets generated by Dagger.
|
||||
// Run Maven and include target/generated-sources/annotations in your IDE.
|
||||
private static final CryptomatorComponent CRYPTOMATOR_COMPONENT = DaggerCryptomatorComponent.factory().create(STARTUP_TIME);
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Cryptomator.class);
|
||||
private static final CryptomatorComponent CRYPTOMATOR_COMPONENT;
|
||||
private static final Logger LOG;
|
||||
|
||||
private final DebugMode debugMode;
|
||||
private final SupportedLanguages supportedLanguages;
|
||||
@@ -63,7 +72,6 @@ public class Cryptomator {
|
||||
System.out.printf("Cryptomator version %s (build %s)%n", appVer, buildNumber);
|
||||
return;
|
||||
}
|
||||
|
||||
int exitCode = CRYPTOMATOR_COMPONENT.application().run(args);
|
||||
LOG.info("Exit {}", exitCode);
|
||||
System.exit(exitCode); // end remaining non-daemon threads.
|
||||
@@ -86,7 +94,7 @@ public class Cryptomator {
|
||||
* Attempts to create an IPC connection to a running Cryptomator instance and sends it the given args.
|
||||
* If no external process could be reached, the args will be handled by the loopback IPC endpoint.
|
||||
*/
|
||||
try (var communicator = IpcCommunicator.create(env.ipcSocketPath().toList())) {
|
||||
try (var communicator = IpcCommunicator.create(env.getIpcSocketPath().toList())) {
|
||||
if (communicator.isClient()) {
|
||||
communicator.sendHandleLaunchargs(List.of(args));
|
||||
communicator.sendRevealRunningApp();
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.launcher;
|
||||
|
||||
import org.jetbrains.annotations.VisibleForTesting;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -48,7 +49,7 @@ class FileOpenRequestHandler {
|
||||
handleLaunchArgs(FileSystems.getDefault(), args);
|
||||
}
|
||||
|
||||
// visible for testing
|
||||
@VisibleForTesting
|
||||
void handleLaunchArgs(FileSystem fs, List<String> args) {
|
||||
Collection<Path> pathsToOpen = args.stream().map(str -> {
|
||||
try {
|
||||
|
||||
@@ -29,12 +29,12 @@ public class SupportedLanguages {
|
||||
|
||||
@Inject
|
||||
public SupportedLanguages(Settings settings) {
|
||||
var preferredLanguage = settings.languageProperty().get();
|
||||
var preferredLanguage = settings.language.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(0, null);
|
||||
sorted.add(1, ENGLISH);
|
||||
LANGUAGE_TAGS.stream() //
|
||||
.sorted((a, b) -> collator.compare(Locale.forLanguageTag(a).getDisplayName(), Locale.forLanguageTag(b).getDisplayName())) //
|
||||
|
||||
@@ -26,8 +26,8 @@ public class DebugMode {
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
setLogLevels(settings.debugMode().get());
|
||||
settings.debugMode().addListener(this::logLevelChanged);
|
||||
setLogLevels(settings.debugMode.get());
|
||||
settings.debugMode.addListener(this::logLevelChanged);
|
||||
}
|
||||
|
||||
private void logLevelChanged(@SuppressWarnings("unused") ObservableValue<? extends Boolean> observable, @SuppressWarnings("unused") Boolean oldValue, Boolean newValue) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import ch.qos.logback.classic.Logger;
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
|
||||
import ch.qos.logback.classic.spi.Configurator;
|
||||
import ch.qos.logback.classic.spi.ConfiguratorRank;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.Appender;
|
||||
import ch.qos.logback.core.ConsoleAppender;
|
||||
@@ -19,6 +20,7 @@ import org.cryptomator.common.Environment;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
|
||||
@ConfiguratorRank(ConfiguratorRank.CUSTOM_NORMAL_PRIORITY)
|
||||
public class LogbackConfigurator extends ContextAwareBase implements Configurator {
|
||||
|
||||
private static final String LOG_PATTERN = "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n";
|
||||
|
||||
@@ -5,21 +5,23 @@ import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.changepassword.NewPasswordController;
|
||||
import org.cryptomator.ui.changepassword.PasswordStrengthUtil;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.changepassword.NewPasswordController;
|
||||
import org.cryptomator.ui.changepassword.PasswordStrengthUtil;
|
||||
import org.cryptomator.ui.common.StageFactory;
|
||||
import org.cryptomator.ui.fxapp.PrimaryStage;
|
||||
import org.cryptomator.ui.recoverykey.RecoveryKeyDisplayController;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
@@ -43,9 +45,8 @@ public abstract class AddVaultModule {
|
||||
@Provides
|
||||
@AddVaultWizardWindow
|
||||
@AddVaultWizardScoped
|
||||
static Stage provideStage(StageFactory factory, @PrimaryStage Stage primaryStage, ResourceBundle resourceBundle) {
|
||||
static Stage provideStage(StageFactory factory, @PrimaryStage Stage primaryStage) {
|
||||
Stage stage = factory.create();
|
||||
stage.setTitle(resourceBundle.getString("addvaultwizard.title"));
|
||||
stage.setResizable(false);
|
||||
stage.initModality(Modality.WINDOW_MODAL);
|
||||
stage.initOwner(primaryStage);
|
||||
@@ -65,6 +66,13 @@ public abstract class AddVaultModule {
|
||||
return new SimpleStringProperty("");
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Named("shorteningThreshold")
|
||||
@AddVaultWizardScoped
|
||||
static IntegerProperty provideShorteningThreshold() {
|
||||
return new SimpleIntegerProperty(CreateNewVaultExpertSettingsController.MAX_SHORTENING_THRESHOLD);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@AddVaultWizardWindow
|
||||
@AddVaultWizardScoped
|
||||
@@ -81,13 +89,6 @@ public abstract class AddVaultModule {
|
||||
|
||||
// ------------------
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.ADDVAULT_WELCOME)
|
||||
@AddVaultWizardScoped
|
||||
static Scene provideWelcomeScene(@AddVaultWizardWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.ADDVAULT_WELCOME);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.ADDVAULT_EXISTING)
|
||||
@AddVaultWizardScoped
|
||||
@@ -130,12 +131,14 @@ public abstract class AddVaultModule {
|
||||
return fxmlLoaders.createScene(FxmlFile.ADDVAULT_SUCCESS);
|
||||
}
|
||||
|
||||
// ------------------
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.ADDVAULT_NEW_EXPERT_SETTINGS)
|
||||
@AddVaultWizardScoped
|
||||
static Scene provideCreateNewVaultExpertSettingsScene(@AddVaultWizardWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.ADDVAULT_NEW_EXPERT_SETTINGS);
|
||||
}
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(AddVaultWelcomeController.class)
|
||||
abstract FxController bindWelcomeController(AddVaultWelcomeController controller);
|
||||
// ------------------
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@@ -181,4 +184,9 @@ public abstract class AddVaultModule {
|
||||
@FxControllerKey(AddVaultSuccessController.class)
|
||||
abstract FxController bindAddVaultSuccessController(AddVaultSuccessController controller);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(CreateNewVaultExpertSettingsController.class)
|
||||
abstract FxController bindCreateNewVaultExpertSettingsController(CreateNewVaultExpertSettingsController controller);
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user