mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-21 04:01:27 +00:00
Compare commits
904 Commits
1.5.0-rc1
...
feature/16
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b4ff4d3a2 | ||
|
|
1edc6e1189 | ||
|
|
97222d3d67 | ||
|
|
172593517a | ||
|
|
16c64a20e3 | ||
|
|
d6f8ab13aa | ||
|
|
d92a8e7980 | ||
|
|
374493e8b4 | ||
|
|
f3953c2fb1 | ||
|
|
5c9c336a33 | ||
|
|
6b113f26ba | ||
|
|
dbef1466c1 | ||
|
|
6b0d8a48c2 | ||
|
|
c7b9735f13 | ||
|
|
a96115ecd6 | ||
|
|
c6aceb3e59 | ||
|
|
cadd071ebd | ||
|
|
b64264ef8b | ||
|
|
46691f057e | ||
|
|
f1b40e32a7 | ||
|
|
714a0c6664 | ||
|
|
b4a97803ff | ||
|
|
8ac253504f | ||
|
|
135b61070d | ||
|
|
903f55a24f | ||
|
|
f2fadafa66 | ||
|
|
0676732796 | ||
|
|
08cbfd47ea | ||
|
|
b15cda260e | ||
|
|
74355b128a | ||
|
|
000f27e166 | ||
|
|
e1d83c996e | ||
|
|
0dc401883f | ||
|
|
3762441230 | ||
|
|
d0d161023d | ||
|
|
6cd0fc6807 | ||
|
|
364d59fdf7 | ||
|
|
210050d9d5 | ||
|
|
f10d2b713b | ||
|
|
f9545b5532 | ||
|
|
58376bddef | ||
|
|
72e2f64a68 | ||
|
|
48ad74715e | ||
|
|
2e1f33ca82 | ||
|
|
2d3f4d1c03 | ||
|
|
04c13ba242 | ||
|
|
b70033e777 | ||
|
|
fafb7b229f | ||
|
|
7fac6da448 | ||
|
|
72bd9c1fdf | ||
|
|
39b8e25f4f | ||
|
|
c8fa7f1edd | ||
|
|
95b98b8a36 | ||
|
|
005d2a82fe | ||
|
|
820f7989d0 | ||
|
|
751a6079c3 | ||
|
|
9be95efd10 | ||
|
|
8f8fa0248c | ||
|
|
cd7acea54e | ||
|
|
18152e4f3d | ||
|
|
7b689c6b78 | ||
|
|
1159681824 | ||
|
|
c868ac32cc | ||
|
|
f85f953668 | ||
|
|
5185df631d | ||
|
|
617feec111 | ||
|
|
eb196165c5 | ||
|
|
8c37ab3675 | ||
|
|
7eaade1555 | ||
|
|
186c129a30 | ||
|
|
f74b9d3347 | ||
|
|
6038559172 | ||
|
|
98a899c7e2 | ||
|
|
783c8718c1 | ||
|
|
b47382811f | ||
|
|
62f279b9f7 | ||
|
|
ab961f1a8b | ||
|
|
9562db7e13 | ||
|
|
1ca2e029dc | ||
|
|
944e3e6c50 | ||
|
|
e134d2f422 | ||
|
|
04e5170403 | ||
|
|
ea008df9f7 | ||
|
|
e25dfaad35 | ||
|
|
e98f92c63f | ||
|
|
85b761a9d7 | ||
|
|
be8dcd4dc4 | ||
|
|
c01c405f20 | ||
|
|
b4f268f551 | ||
|
|
21f9e72cc5 | ||
|
|
4845984a35 | ||
|
|
b6f5ddaf30 | ||
|
|
1abf0e1bfa | ||
|
|
a8364a8c1a | ||
|
|
13c95868fa | ||
|
|
85ff7542f1 | ||
|
|
432be6dd80 | ||
|
|
ca0402aaf0 | ||
|
|
c7ef0056f9 | ||
|
|
cf13311665 | ||
|
|
a7133dbebe | ||
|
|
168f9b9fb9 | ||
|
|
2b332c3831 | ||
|
|
66e3625a0b | ||
|
|
20f88e203a | ||
|
|
66a8dc9811 | ||
|
|
9d89efc98c | ||
|
|
dfbe017316 | ||
|
|
d2680b9857 | ||
|
|
8e1be4c67b | ||
|
|
749e0ac02d | ||
|
|
a2ad7d69ab | ||
|
|
a47c05c87d | ||
|
|
6b871e56c8 | ||
|
|
40dbc0ba48 | ||
|
|
2e52afed51 | ||
|
|
64d54133f8 | ||
|
|
ac289cc3f7 | ||
|
|
189699d359 | ||
|
|
0ce41e7ac3 | ||
|
|
c1a249fd7f | ||
|
|
c266c7583b | ||
|
|
00331d4857 | ||
|
|
8fd484e2bb | ||
|
|
165d740acd | ||
|
|
fd4010c6c9 | ||
|
|
aa2900fa9e | ||
|
|
76d1875e01 | ||
|
|
bc83e23a34 | ||
|
|
6a326bcbce | ||
|
|
573ad03d68 | ||
|
|
07efb3e94d | ||
|
|
89e680fb45 | ||
|
|
54128a0016 | ||
|
|
e2565097cd | ||
|
|
f827b1fc89 | ||
|
|
c0baab2329 | ||
|
|
70baa4d09f | ||
|
|
d710d406d0 | ||
|
|
554f245f5d | ||
|
|
34995088ba | ||
|
|
69c63702f2 | ||
|
|
db7e731554 | ||
|
|
e08b43bf17 | ||
|
|
58b45bacd1 | ||
|
|
4f942bc23f | ||
|
|
09a8618fa0 | ||
|
|
52af530d1b | ||
|
|
86a42234c6 | ||
|
|
37c4e78b1d | ||
|
|
9c2c234bee | ||
|
|
59f91267ae | ||
|
|
b3ff9423b4 | ||
|
|
e3f3090341 | ||
|
|
83be6c0864 | ||
|
|
c654951dc1 | ||
|
|
4e177c9ea7 | ||
|
|
dc3a951a1b | ||
|
|
defa9c75eb | ||
|
|
c1f498a114 | ||
|
|
8457c50ebc | ||
|
|
0144cbb99f | ||
|
|
d6e4c7d177 | ||
|
|
3376b16b7b | ||
|
|
673fdcd095 | ||
|
|
0d00520ac1 | ||
|
|
22a0d3a9a5 | ||
|
|
24baa44e70 | ||
|
|
03886f88e8 | ||
|
|
642816b631 | ||
|
|
f3a03c71ec | ||
|
|
1fab246fcd | ||
|
|
cd5c55aad7 | ||
|
|
b066b4b045 | ||
|
|
41d2a2c77e | ||
|
|
69186b916c | ||
|
|
0840695e0a | ||
|
|
8447f105b0 | ||
|
|
c306d8df04 | ||
|
|
beba6490c3 | ||
|
|
fb1078b35b | ||
|
|
be0912e6ca | ||
|
|
13db1aa9b9 | ||
|
|
d2cd2c923d | ||
|
|
92de05b3db | ||
|
|
c1000d9958 | ||
|
|
2810c044ea | ||
|
|
e09bd160b7 | ||
|
|
e6d1e4697c | ||
|
|
497e5ce73f | ||
|
|
cf7cbae567 | ||
|
|
803f517c62 | ||
|
|
0afa7b8e37 | ||
|
|
1a0f70f8e8 | ||
|
|
8737eb83f0 | ||
|
|
a96239a19f | ||
|
|
2b7cfcd1dc | ||
|
|
ebccb61750 | ||
|
|
285f2aec23 | ||
|
|
217e31fbd7 | ||
|
|
f0ebf7a638 | ||
|
|
c05c5e3f90 | ||
|
|
30f0c5e697 | ||
|
|
f989b8627c | ||
|
|
ff84230566 | ||
|
|
3b4f6276b5 | ||
|
|
2be7a050a4 | ||
|
|
1c01228778 | ||
|
|
1c35780d9e | ||
|
|
96a612127c | ||
|
|
0bdfb7c9f9 | ||
|
|
f556301249 | ||
|
|
f77b237e59 | ||
|
|
61b7a39aad | ||
|
|
2cee6e45f1 | ||
|
|
1292548042 | ||
|
|
16bd84ee62 | ||
|
|
3d0a97fcdf | ||
|
|
5ae2419e6d | ||
|
|
786d156b9f | ||
|
|
629b6fb97d | ||
|
|
17dc32bb79 | ||
|
|
c05e00d32a | ||
|
|
9dc8b2cb47 | ||
|
|
0e32e96c7d | ||
|
|
97afadd7b9 | ||
|
|
b199b65e38 | ||
|
|
999abf3c13 | ||
|
|
2cdde54db6 | ||
|
|
6941603cdd | ||
|
|
cdca4e047d | ||
|
|
31e938de6a | ||
|
|
4c10ab764a | ||
|
|
4e075ab0ca | ||
|
|
f73ae9759f | ||
|
|
f6283b2f7e | ||
|
|
b23d2e4def | ||
|
|
91a2943599 | ||
|
|
e32ce22d24 | ||
|
|
e75c415b46 | ||
|
|
8592e3667b | ||
|
|
5a11d02fa8 | ||
|
|
0ab28602d1 | ||
|
|
62c8edff04 | ||
|
|
d01c6268f8 | ||
|
|
e083fd0bcc | ||
|
|
ff687f1bae | ||
|
|
557aaa2480 | ||
|
|
78e43d401d | ||
|
|
7b08c5d287 | ||
|
|
84d2644f19 | ||
|
|
d13dfe3526 | ||
|
|
f9a9d7b870 | ||
|
|
d75a8c4bba | ||
|
|
8fccb1b8f0 | ||
|
|
d326c7c990 | ||
|
|
e8e63ca4fc | ||
|
|
c82e5577a1 | ||
|
|
6878f2e94b | ||
|
|
a17b416262 | ||
|
|
fed572694f | ||
|
|
fe3d67d937 | ||
|
|
3dcdeb1033 | ||
|
|
0898158c5a | ||
|
|
81091d4bdf | ||
|
|
c9b1b1baa5 | ||
|
|
c81f3bd972 | ||
|
|
9f86b74320 | ||
|
|
2d8390a0f3 | ||
|
|
8d3671175f | ||
|
|
366011a222 | ||
|
|
c0c2e21055 | ||
|
|
63be96a151 | ||
|
|
fc1df4bd99 | ||
|
|
7657330931 | ||
|
|
4e44de3c3b | ||
|
|
8d902a72ca | ||
|
|
7378031a72 | ||
|
|
f898c07c27 | ||
|
|
c8f02d1045 | ||
|
|
4cc13b986b | ||
|
|
af7b6780f3 | ||
|
|
4a17d01004 | ||
|
|
1d68408e21 | ||
|
|
821b1ee660 | ||
|
|
c6616bd467 | ||
|
|
4bb2589f16 | ||
|
|
896c3b3565 | ||
|
|
6ee717a693 | ||
|
|
07ec858e1e | ||
|
|
a7c1e43ebc | ||
|
|
ac1cd3b073 | ||
|
|
7474519faf | ||
|
|
340e474c33 | ||
|
|
c90ab75427 | ||
|
|
848b3f77d3 | ||
|
|
fb8cdb31ca | ||
|
|
ba5f8053fb | ||
|
|
38165becca | ||
|
|
f731ac5c90 | ||
|
|
0291702736 | ||
|
|
ab63929861 | ||
|
|
ca36fb8af3 | ||
|
|
8cb29ff83b | ||
|
|
304fa67dd7 | ||
|
|
a80ec32d2c | ||
|
|
dc4f21162e | ||
|
|
3b8d7e0241 | ||
|
|
6891c68cf1 | ||
|
|
18b26fbc58 | ||
|
|
1db8da6b6b | ||
|
|
14bce7e91d | ||
|
|
2674bc6f23 | ||
|
|
74e1d6f991 | ||
|
|
25dba028f8 | ||
|
|
bf51cc13d1 | ||
|
|
24be36cccb | ||
|
|
797e15c775 | ||
|
|
2395dbcae9 | ||
|
|
efacbbe2b6 | ||
|
|
2518086e46 | ||
|
|
c733247611 | ||
|
|
4f44e71e13 | ||
|
|
02aa46ece8 | ||
|
|
635f64c847 | ||
|
|
0a8516ae9a | ||
|
|
c1edb30472 | ||
|
|
93c78b63ca | ||
|
|
3ccae93757 | ||
|
|
450dec2baf | ||
|
|
36121527ca | ||
|
|
f30451f7e1 | ||
|
|
74d7f63f64 | ||
|
|
350a4ab762 | ||
|
|
0e0e75b89c | ||
|
|
e76440d928 | ||
|
|
0cbace67a5 | ||
|
|
84a3082589 | ||
|
|
cdfcca06d1 | ||
|
|
630bfa4cee | ||
|
|
90cb7beb1f | ||
|
|
d37fa33278 | ||
|
|
eed9c906cc | ||
|
|
2b7ed5f4dd | ||
|
|
6a7a309a2b | ||
|
|
0382069995 | ||
|
|
7c5f40d7d1 | ||
|
|
09e9530660 | ||
|
|
947d25b335 | ||
|
|
80cbc6699a | ||
|
|
da0933fa92 | ||
|
|
9ad217ca55 | ||
|
|
adc9f32fb3 | ||
|
|
65369bdbff | ||
|
|
d18e618ef1 | ||
|
|
970216dd59 | ||
|
|
6840a649c7 | ||
|
|
1a0bc92bde | ||
|
|
e4709ed6fe | ||
|
|
21038212c1 | ||
|
|
b15471b4ff | ||
|
|
19ebc7e562 | ||
|
|
0fa052d2d1 | ||
|
|
402861b9c0 | ||
|
|
aca1666dea | ||
|
|
ff17b60f56 | ||
|
|
3284578445 | ||
|
|
70f6a4877c | ||
|
|
85c5dc8dfb | ||
|
|
4b670a59a3 | ||
|
|
23c113948f | ||
|
|
d86ea20c31 | ||
|
|
3f928cf958 | ||
|
|
01929c2288 | ||
|
|
2634433b2c | ||
|
|
c1f44f76b9 | ||
|
|
b2f27c0a3d | ||
|
|
b1d7cfc81b | ||
|
|
7cd5c66836 | ||
|
|
95cef34234 | ||
|
|
8977440697 | ||
|
|
d5eb84a000 | ||
|
|
81fb6b8794 | ||
|
|
92b390d5bb | ||
|
|
8867532210 | ||
|
|
77db435b4f | ||
|
|
cb2bc17283 | ||
|
|
aaa93239d0 | ||
|
|
93445e22d4 | ||
|
|
64897cfa21 | ||
|
|
7349a29831 | ||
|
|
73554b4759 | ||
|
|
0312f045aa | ||
|
|
1134c1b2ff | ||
|
|
efebbc059a | ||
|
|
6e860d293a | ||
|
|
8bb925fd93 | ||
|
|
ca5d9eba36 | ||
|
|
1a49e24d8a | ||
|
|
24b0ed2502 | ||
|
|
a226d5403a | ||
|
|
0f3085cc73 | ||
|
|
f0a040cf29 | ||
|
|
0676748dde | ||
|
|
589b8384eb | ||
|
|
9e3947f337 | ||
|
|
790cc4e772 | ||
|
|
72f4988632 | ||
|
|
b3fa6bbf32 | ||
|
|
c2dc487c79 | ||
|
|
e74dd3be9e | ||
|
|
1eeee61572 | ||
|
|
984b7a2d0e | ||
|
|
45c714a123 | ||
|
|
96bb97d50a | ||
|
|
046acb9bbf | ||
|
|
ce4ec16c62 | ||
|
|
96c8c9a9a9 | ||
|
|
44db97327d | ||
|
|
f441700c25 | ||
|
|
76b023bdbd | ||
|
|
241d9781bb | ||
|
|
ff94532560 | ||
|
|
e949023321 | ||
|
|
da31407d63 | ||
|
|
8c7c5da89a | ||
|
|
e3a0e1ec5a | ||
|
|
4cee27d8dd | ||
|
|
b0fce66d77 | ||
|
|
bf47ba0145 | ||
|
|
fc7b484c9a | ||
|
|
4402c19d90 | ||
|
|
4e89de9e47 | ||
|
|
a27c9d63d9 | ||
|
|
da6aa0f002 | ||
|
|
0bf3533f45 | ||
|
|
295cb0ef6d | ||
|
|
6fac84e9c2 | ||
|
|
77b2e67c49 | ||
|
|
c48c9b1568 | ||
|
|
6da7eae2f8 | ||
|
|
aec56c48c5 | ||
|
|
c0a9a95e4f | ||
|
|
3b73544766 | ||
|
|
fbc471635a | ||
|
|
3c5b9ed3a6 | ||
|
|
8479122561 | ||
|
|
91c883d5cc | ||
|
|
1cd4da0796 | ||
|
|
935aaccdae | ||
|
|
ab3dd779d2 | ||
|
|
1fbcf6d517 | ||
|
|
82538091c9 | ||
|
|
62ade6113b | ||
|
|
4779bbf415 | ||
|
|
c6b786a771 | ||
|
|
6381227897 | ||
|
|
e82167b5e6 | ||
|
|
dc4fd482b5 | ||
|
|
a71f8b350e | ||
|
|
c9ec8fecef | ||
|
|
e72d32f2d1 | ||
|
|
2545aa2a7e | ||
|
|
51aac15622 | ||
|
|
afa0cfeafb | ||
|
|
19e24ba12c | ||
|
|
c47ce2c730 | ||
|
|
5d00b3dd76 | ||
|
|
4db57cc0dc | ||
|
|
432a9a27f1 | ||
|
|
57bfa3276d | ||
|
|
02fc9b263a | ||
|
|
4c66f81736 | ||
|
|
2de151aebe | ||
|
|
c44911dcac | ||
|
|
bcf2a3d20c | ||
|
|
422ce4a387 | ||
|
|
21387bd76c | ||
|
|
52cd560cb2 | ||
|
|
6c440dfbbb | ||
|
|
a074450452 | ||
|
|
b781cf6f25 | ||
|
|
9b653f488b | ||
|
|
17c580267f | ||
|
|
490d1b8f87 | ||
|
|
b0ad86f16b | ||
|
|
df2b4ac086 | ||
|
|
aee4ececba | ||
|
|
b2992aa6ae | ||
|
|
4c546d281a | ||
|
|
c90e445a67 | ||
|
|
d3c2b0509e | ||
|
|
c6d1c2ca6b | ||
|
|
86dec80726 | ||
|
|
9083976989 | ||
|
|
d9c5d76417 | ||
|
|
c19c3754c6 | ||
|
|
947e0e2369 | ||
|
|
6eca8f2e0c | ||
|
|
9f61ad1941 | ||
|
|
41492a951a | ||
|
|
cbbfec5531 | ||
|
|
d7a4dff080 | ||
|
|
8e56218fbb | ||
|
|
9c40386106 | ||
|
|
c865805f55 | ||
|
|
8e352301cd | ||
|
|
52db1e8bdd | ||
|
|
1947623be8 | ||
|
|
4f8602684d | ||
|
|
75f66e40bf | ||
|
|
73587437cb | ||
|
|
18f6e70bba | ||
|
|
e067b94aca | ||
|
|
b04d5669fb | ||
|
|
ad44af338d | ||
|
|
4f4ddbc3e0 | ||
|
|
4e9af1c713 | ||
|
|
9a94b6f95e | ||
|
|
371b826aa0 | ||
|
|
d3fb90bf6d | ||
|
|
d24c478faa | ||
|
|
48d0aa423c | ||
|
|
5695fa2916 | ||
|
|
bcea1a4b32 | ||
|
|
2f8d4568fc | ||
|
|
5b55318e52 | ||
|
|
459f2ea2c3 | ||
|
|
d26147a34a | ||
|
|
afb9d4f010 | ||
|
|
db3bf9723e | ||
|
|
3a5937b35f | ||
|
|
f5cddda7a8 | ||
|
|
e9fa1d6476 | ||
|
|
084c1881ba | ||
|
|
ce131e4653 | ||
|
|
a121c7d0fe | ||
|
|
603bf99b25 | ||
|
|
9076fe5b46 | ||
|
|
6848f1a38e | ||
|
|
f4103fc917 | ||
|
|
c838da9df4 | ||
|
|
78df4e24b3 | ||
|
|
c0e2d01297 | ||
|
|
313f8b36d2 | ||
|
|
343794c1fe | ||
|
|
813c01aaed | ||
|
|
510ea8a6f6 | ||
|
|
a22fbea467 | ||
|
|
f64144d1da | ||
|
|
c01dd225c9 | ||
|
|
18b408a83a | ||
|
|
efaf107b20 | ||
|
|
86cba5e8a7 | ||
|
|
f4cee6d161 | ||
|
|
28c40b2277 | ||
|
|
8853054ed4 | ||
|
|
3eb44b06af | ||
|
|
1554437884 | ||
|
|
268bae8879 | ||
|
|
b382e436e2 | ||
|
|
6ccd248675 | ||
|
|
c760e63995 | ||
|
|
959dee153e | ||
|
|
aa22f656e8 | ||
|
|
d24734e16f | ||
|
|
01522e8c97 | ||
|
|
14e056551d | ||
|
|
82a42ea183 | ||
|
|
bfde26be79 | ||
|
|
51e43a0567 | ||
|
|
9a375cb3f6 | ||
|
|
2b8f39a149 | ||
|
|
2720a999d1 | ||
|
|
f675bd5017 | ||
|
|
16be3e7a97 | ||
|
|
551d9d1af1 | ||
|
|
0acc8ddb0a | ||
|
|
f0e1bcb899 | ||
|
|
d331c30224 | ||
|
|
d0d39a1c72 | ||
|
|
8904df91b4 | ||
|
|
786365c095 | ||
|
|
eb8f5f523d | ||
|
|
9c22adc97d | ||
|
|
265212cc0f | ||
|
|
9c860cc17c | ||
|
|
7f63153bc1 | ||
|
|
9531d44ab5 | ||
|
|
253abd4930 | ||
|
|
022ba81f2f | ||
|
|
26160e9bbc | ||
|
|
0a32de2c92 | ||
|
|
60aeb6a04b | ||
|
|
0206fc0b8f | ||
|
|
06b3343a6d | ||
|
|
598bec3050 | ||
|
|
0e5d72c22a | ||
|
|
21f4fab9ed | ||
|
|
58e2ec4742 | ||
|
|
6b6867b826 | ||
|
|
92321a7569 | ||
|
|
7781572b6d | ||
|
|
b5efe39eb8 | ||
|
|
cae86cd71f | ||
|
|
667617b480 | ||
|
|
9329311491 | ||
|
|
22438d1eba | ||
|
|
d295084312 | ||
|
|
ab538cd215 | ||
|
|
f9cb438a0b | ||
|
|
354de225ed | ||
|
|
0b7f8d71ed | ||
|
|
9657a13912 | ||
|
|
c5a3b29554 | ||
|
|
ae957c2588 | ||
|
|
da84133732 | ||
|
|
10275eb80f | ||
|
|
29a9c7dffe | ||
|
|
d5b8996a39 | ||
|
|
f012977aac | ||
|
|
8680bd1dee | ||
|
|
528510eb53 | ||
|
|
e8d17cfb7b | ||
|
|
cdbcd20241 | ||
|
|
fef3ade5c6 | ||
|
|
194d7f0da9 | ||
|
|
8ad20c27da | ||
|
|
f891a9f1a7 | ||
|
|
2a335eb7af | ||
|
|
6578ac0121 | ||
|
|
83f9514a42 | ||
|
|
c92f1aa655 | ||
|
|
688993ba37 | ||
|
|
ddfc8d5bc3 | ||
|
|
c3141e3601 | ||
|
|
f49974180b | ||
|
|
eb6ade49f6 | ||
|
|
6553c04256 | ||
|
|
a8cb015a06 | ||
|
|
ee81dca71c | ||
|
|
ce06ddf312 | ||
|
|
fee2d4bc0c | ||
|
|
a2a990bd0c | ||
|
|
cedbe6523d | ||
|
|
ec64055d93 | ||
|
|
6f542ac8b8 | ||
|
|
8a3c101764 | ||
|
|
49a8689090 | ||
|
|
8f5c4997b1 | ||
|
|
900fdd7f6f | ||
|
|
4723416d45 | ||
|
|
8483f71f57 | ||
|
|
5dac594cc9 | ||
|
|
06f4e160d6 | ||
|
|
1d38ee2fcb | ||
|
|
921b70ebaa | ||
|
|
0f56d424da | ||
|
|
4cd43a2b1c | ||
|
|
1ef359e68b | ||
|
|
58ce1e45b8 | ||
|
|
bd854e7f7a | ||
|
|
3ecc0cf906 | ||
|
|
ea6925f905 | ||
|
|
f45b78d8c0 | ||
|
|
75ca8a91f8 | ||
|
|
16462d05c8 | ||
|
|
cbef54f05c | ||
|
|
f601ff4ce3 | ||
|
|
84fbf7392b | ||
|
|
bbf9379f56 | ||
|
|
6aa14fcfb1 | ||
|
|
710c7d0da7 | ||
|
|
841d4eb9c7 | ||
|
|
8c4d35d3db | ||
|
|
4110057fa1 | ||
|
|
9b1d6d2f2f | ||
|
|
1c45455cb2 | ||
|
|
411aca8695 | ||
|
|
3de69021df | ||
|
|
8418038736 | ||
|
|
3bf2b499a7 | ||
|
|
430da2b78d | ||
|
|
51047dcbce | ||
|
|
708bcaa630 | ||
|
|
724b20c826 | ||
|
|
69f8c46f15 | ||
|
|
b7f2fb0bdf | ||
|
|
222ffd8c53 | ||
|
|
00e0a0f79a | ||
|
|
d6bbc4383b | ||
|
|
b51a2602a9 | ||
|
|
c3fbddc671 | ||
|
|
ce262b691a | ||
|
|
65de6fef9b | ||
|
|
31d95ae5b0 | ||
|
|
429098733c | ||
|
|
597899d2bf | ||
|
|
b1c66b181d | ||
|
|
100b836979 | ||
|
|
817907c25a | ||
|
|
25195fffe2 | ||
|
|
0e784a6ffc | ||
|
|
351f96fa8b | ||
|
|
703fb4fb51 | ||
|
|
a975df6f8c | ||
|
|
fb90128b63 | ||
|
|
ea4c91fb37 | ||
|
|
7c1d6973ba | ||
|
|
4f2120b729 | ||
|
|
51f7d74e4a | ||
|
|
32a810fe1d | ||
|
|
570482521a | ||
|
|
3bd2a2f911 | ||
|
|
1ac6d086bd | ||
|
|
8374599183 | ||
|
|
0091c401df | ||
|
|
00dd67e345 | ||
|
|
158677bd54 | ||
|
|
a1b375316c | ||
|
|
dae2814b0f | ||
|
|
341a98848d | ||
|
|
902e66906a | ||
|
|
c59d3cd03f | ||
|
|
ed9f16e012 | ||
|
|
ed77a4aacd | ||
|
|
ff2fa70bd6 | ||
|
|
3519346df9 | ||
|
|
45f6caa7bd | ||
|
|
e2e7755af2 | ||
|
|
4ab7bfaa20 | ||
|
|
7e0ffb43a6 | ||
|
|
526c8328f6 | ||
|
|
81bad4eb25 | ||
|
|
dcaa6e81a3 | ||
|
|
e78155396d | ||
|
|
d3063c8117 | ||
|
|
cd1ed088c3 | ||
|
|
e831debb94 | ||
|
|
8d15a6612f | ||
|
|
9c034f3be6 | ||
|
|
60dd9349a8 | ||
|
|
330b1cbf7d | ||
|
|
9ffa38d54e | ||
|
|
c925727269 | ||
|
|
ac2dc06bd6 | ||
|
|
80b83adb53 | ||
|
|
ddc31ac2bb | ||
|
|
eb7c5d0b2b | ||
|
|
e5ce3cb62d | ||
|
|
7a69692999 | ||
|
|
d00d9d98dc | ||
|
|
1846c5c14c | ||
|
|
0d9db783f7 | ||
|
|
d3a6964d8f | ||
|
|
55e9cabf51 | ||
|
|
5180f2061a | ||
|
|
05154cf6aa | ||
|
|
f61e955945 | ||
|
|
d80605532f | ||
|
|
8d5fb14b50 | ||
|
|
570286c7df | ||
|
|
11e3ee8d90 | ||
|
|
0664c670f7 | ||
|
|
f36f9d412c | ||
|
|
bd734f1960 | ||
|
|
675a0b1a73 | ||
|
|
a2816277bf | ||
|
|
e37f1f914b | ||
|
|
adf7694308 | ||
|
|
c13449c6ad | ||
|
|
f72035210c | ||
|
|
89ef5238ea | ||
|
|
8198f66c1f | ||
|
|
eb5aa4ee44 | ||
|
|
adb09a0efe | ||
|
|
241eb8bed5 | ||
|
|
842a0d6ff3 | ||
|
|
3200917df2 | ||
|
|
12dcf0647d | ||
|
|
22859c9ffa | ||
|
|
29182156df | ||
|
|
357d63f398 | ||
|
|
e594bf208d | ||
|
|
2f0de3520a | ||
|
|
8def68eb02 | ||
|
|
aef33dc864 | ||
|
|
06d2f2d9e9 | ||
|
|
dad0ad76fb | ||
|
|
99fa8e7c8e | ||
|
|
ab0f175edf | ||
|
|
8cb9728565 | ||
|
|
d91d27f2a4 | ||
|
|
b2a6e038ae | ||
|
|
75f360903c | ||
|
|
79c3137b90 | ||
|
|
d2189d379c | ||
|
|
49aead7323 | ||
|
|
7bd610563f | ||
|
|
5c1a1ad162 | ||
|
|
86906d0049 | ||
|
|
93011dc754 | ||
|
|
b084b651af | ||
|
|
fecf9c0423 | ||
|
|
117fe78a4a | ||
|
|
153d43573a | ||
|
|
9145f5d2f8 | ||
|
|
835ea3b640 | ||
|
|
1e7eb23d1b | ||
|
|
cfe25d0bf5 | ||
|
|
b14939bd77 | ||
|
|
26e140ee22 | ||
|
|
1c5ecf8c01 | ||
|
|
9b528a05b5 | ||
|
|
3a7aa6d64f | ||
|
|
55820e47f9 | ||
|
|
94af8bd15a | ||
|
|
4712c4f593 | ||
|
|
42c856fc6f | ||
|
|
3618c4b8db | ||
|
|
bb681fa6d9 | ||
|
|
22e3840caa | ||
|
|
461ec3ca43 | ||
|
|
8aa3da14a4 | ||
|
|
670d4a165c | ||
|
|
9a9b19e6e2 | ||
|
|
206ba4c69a | ||
|
|
1702c6a243 | ||
|
|
8d2fe2fc03 | ||
|
|
4864eb3204 | ||
|
|
5721b63135 | ||
|
|
c99e0ea656 | ||
|
|
b1dc983d6b | ||
|
|
808223d58e | ||
|
|
4d5f6cbb52 | ||
|
|
fcdbc7a6cc | ||
|
|
113b745050 | ||
|
|
e4cde7f66f | ||
|
|
f6c834fee2 | ||
|
|
96990788d9 | ||
|
|
c204ed2601 | ||
|
|
b882296c19 | ||
|
|
186ed5c115 | ||
|
|
db29513376 | ||
|
|
0469e99baa | ||
|
|
37fcae8f0e | ||
|
|
2902479fc1 | ||
|
|
5ef7a3e76d | ||
|
|
041ce2504c | ||
|
|
8db889dbf5 | ||
|
|
a869fc219d | ||
|
|
002935af60 | ||
|
|
f3db7722b1 | ||
|
|
169014ef62 | ||
|
|
32d9e37708 | ||
|
|
57ee96a739 | ||
|
|
72f2bf4c42 | ||
|
|
b8b2265f9d | ||
|
|
56db682571 | ||
|
|
3b690dfc6e | ||
|
|
243c74b0cb | ||
|
|
a9a983d7ed | ||
|
|
880260d467 | ||
|
|
07e5e18d4d | ||
|
|
9e243daffa | ||
|
|
3ec2d4b701 | ||
|
|
3eee522897 | ||
|
|
408d16fabf | ||
|
|
830941755b | ||
|
|
84cc81ec40 | ||
|
|
a8b76a6914 | ||
|
|
c9f560eb04 | ||
|
|
8993b3584b | ||
|
|
93048647f5 | ||
|
|
75e35ca0e1 | ||
|
|
9205bafc56 | ||
|
|
4a9dd7f175 | ||
|
|
8d0c370f5a | ||
|
|
200e8f7b79 | ||
|
|
467e87813d | ||
|
|
5b2af73c50 | ||
|
|
d107917065 | ||
|
|
d111a34736 | ||
|
|
a40847a280 | ||
|
|
6fc010e638 | ||
|
|
d42ff80b25 | ||
|
|
1e76a5e92c | ||
|
|
05d21f6784 | ||
|
|
c1bd777c17 | ||
|
|
128176db1f | ||
|
|
005c4787a2 | ||
|
|
d1b364fd1b | ||
|
|
006d201400 | ||
|
|
2a964ae501 | ||
|
|
09b6b0da28 | ||
|
|
cceea1c7c1 | ||
|
|
8c339d4f3c | ||
|
|
85eb459182 | ||
|
|
fc818b37fd | ||
|
|
cb9a33eeb3 | ||
|
|
10d39f6192 | ||
|
|
2e6246528e | ||
|
|
0732a55d0e | ||
|
|
c7597fbcc2 |
@@ -1,5 +1,6 @@
|
||||
commit_message: "[ci skip]"
|
||||
escape_special_characters: 0
|
||||
commit_message: '[ci skip]'
|
||||
files:
|
||||
- source: /main/ui/src/main/resources/i18n/strings.properties
|
||||
translation: /main/ui/src/main/resources/i18n/strings_%two_letters_code%.properties
|
||||
- source: /src/main/resources/i18n/strings.properties
|
||||
translation: /src/main/resources/i18n/strings_%two_letters_code%.properties
|
||||
escape_quotes: 0
|
||||
escape_special_characters: 0
|
||||
|
||||
2
.github/CODE_OF_CONDUCT.md
vendored
2
.github/CODE_OF_CONDUCT.md
vendored
@@ -22,7 +22,7 @@ include:
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
* The use of sexual language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
|
||||
19
.github/ISSUE_TEMPLATE/bug.md
vendored
19
.github/ISSUE_TEMPLATE/bug.md
vendored
@@ -5,14 +5,11 @@ labels: type:bug
|
||||
---
|
||||
|
||||
<!--
|
||||
Please make sure to:
|
||||
- Comply with our code of conduct: https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md
|
||||
- Search for existing similar issues first: https://github.com/cryptomator/cryptomator/issues?q=
|
||||
|
||||
Do you want to ask a QUESTION? Are you looking for SUPPORT?
|
||||
We're happy to help you via our support channels! Please read: https://github.com/cryptomator/cryptomator/blob/develop/SUPPORT.md
|
||||
|
||||
By filing an issue, you are expected to comply with our code of conduct: https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md
|
||||
|
||||
Of course, we also expect you to search for existing similar issues first! ;) https://github.com/cryptomator/cryptomator/issues?q=
|
||||
|
||||
⚠️ IMPORTANT: If you don't stick to this template, the issue will get closed.
|
||||
-->
|
||||
|
||||
### Description
|
||||
@@ -21,9 +18,9 @@ Of course, we also expect you to search for existing similar issues first! ;) ht
|
||||
|
||||
### System Setup
|
||||
|
||||
* Operating system and version: [Windows/macOS/Linux + Version]
|
||||
* Operating system and version: [Windows/macOS/Linux + Version ( + Desktop Environment, if Linux)]
|
||||
* Cryptomator version: [Shown in the settings]
|
||||
* Drive: [Dokany/FUSE/WebDAV]
|
||||
* Volume type: [Dokany/FUSE/WebDAV, shown in the settings]
|
||||
|
||||
### Steps to Reproduce
|
||||
|
||||
@@ -48,7 +45,6 @@ Of course, we also expect you to search for existing similar issues first! ;) ht
|
||||
[Any additional information, log files, screenshots, configuration, or data that might be necessary to reproduce the issue.]
|
||||
|
||||
<!--
|
||||
|
||||
If you want to add the log file or screenshots, please add them as attachments. If your log file seems empty and doesn't show any errors, you may enable the debug mode first. Here is how to do that: https://community.cryptomator.org/t/how-do-i-enable-debug-mode/36
|
||||
|
||||
Then reproduce the problem to ensure all important information is contained in there. You may use test data or redact sensitive information from the log file.
|
||||
@@ -57,5 +53,4 @@ Log file location:
|
||||
- Windows: %appdata%/Cryptomator
|
||||
- macOS: ~/Library/Logs/Cryptomator
|
||||
- Linux: ~/.local/share/Cryptomator/logs
|
||||
|
||||
-->
|
||||
-->
|
||||
|
||||
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Help & Support
|
||||
url: https://community.cryptomator.org/
|
||||
about: You will find answers in our community forum
|
||||
- name: User Manual
|
||||
url: https://docs.cryptomator.org/
|
||||
about: Read the Cryptomator documentation here
|
||||
13
.github/ISSUE_TEMPLATE/feature.md
vendored
13
.github/ISSUE_TEMPLATE/feature.md
vendored
@@ -5,14 +5,9 @@ labels: type:feature-request
|
||||
---
|
||||
|
||||
<!--
|
||||
|
||||
Do you want to ask a QUESTION? Are you looking for SUPPORT?
|
||||
We're happy to help you via our support channels! Please read: https://github.com/cryptomator/cryptomator/blob/develop/SUPPORT.md
|
||||
|
||||
By filing a feature request, you are expected to comply with our code of conduct: https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md
|
||||
|
||||
Of course, we also expect you to search for existing similar feature requests first! ;)
|
||||
|
||||
Please make sure to:
|
||||
- Comply with our code of conduct: https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md
|
||||
- Search for existing similar issues first: https://github.com/cryptomator/cryptomator/issues?q=
|
||||
-->
|
||||
|
||||
### Summary
|
||||
@@ -29,4 +24,4 @@ Of course, we also expect you to search for existing similar feature requests fi
|
||||
|
||||
### Additional Context
|
||||
|
||||
[Add any other context or screenshots about the feature request here.]
|
||||
[Add any other context or screenshots about the feature request here.]
|
||||
|
||||
0
SECURITY.md → .github/SECURITY.md
vendored
0
SECURITY.md → .github/SECURITY.md
vendored
2
SUPPORT.md → .github/SUPPORT.md
vendored
2
SUPPORT.md → .github/SUPPORT.md
vendored
@@ -14,5 +14,5 @@ For _everything else_, please visit our official [Cryptomator Community](https:/
|
||||
- Discussions about the apps
|
||||
- [Development discussions](https://community.cryptomator.org/c/development)
|
||||
- General questions
|
||||
- Discussions regarding our design decissions
|
||||
- Discussions regarding our design decisions
|
||||
- Our roadmap
|
||||
149
.github/workflows/build.yml
vendored
Normal file
149
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
[push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build and Test
|
||||
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@v2
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 16
|
||||
- uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-maven-
|
||||
- name: Ensure to use tagged version
|
||||
run: mvn versions:set -DnewVersion=${GITHUB_REF##*/} # use shell parameter expansion to strip of 'refs/tags'
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
- name: Build and Test
|
||||
run: mvn -B clean install jacoco:report -Pcoverage,dependency-check
|
||||
- name: Upload code coverage report
|
||||
id: codacyCoverageReporter
|
||||
run: bash <(curl -Ls https://coverage.codacy.com/get.sh)
|
||||
env:
|
||||
CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }}
|
||||
continue-on-error: true
|
||||
### TODO: move to matrix build:
|
||||
- name: Assemble buildkit-linux.zip
|
||||
run: mvn -B clean package -DskipTests -Plinux
|
||||
- name: Upload buildkit-linux.zip
|
||||
uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: buildkit-linux.zip
|
||||
path: target/buildkit-linux.zip
|
||||
- name: Assemble buildkit-mac.zip
|
||||
run: mvn -B clean package -DskipTests -Pmac
|
||||
- name: Upload buildkit-mac.zip
|
||||
uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: buildkit-mac.zip
|
||||
path: target/buildkit-mac.zip
|
||||
- name: Assemble buildkit-win.zip
|
||||
run: mvn -B clean package -DskipTests -Pwindows
|
||||
- name: Upload buildkit-win.zip
|
||||
uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: buildkit-win.zip
|
||||
path: target/buildkit-win.zip
|
||||
|
||||
release:
|
||||
name: Draft a Release on GitHub Releases
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
if: startsWith(github.ref, 'refs/tags/') && github.repository == 'cryptomator/cryptomator'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Download buildkit-linux.zip
|
||||
uses: actions/download-artifact@v1
|
||||
with:
|
||||
name: buildkit-linux.zip
|
||||
path: .
|
||||
- name: Download buildkit-mac.zip
|
||||
uses: actions/download-artifact@v1
|
||||
with:
|
||||
name: buildkit-mac.zip
|
||||
path: .
|
||||
- name: Download buildkit-win.zip
|
||||
uses: actions/download-artifact@v1
|
||||
with:
|
||||
name: buildkit-win.zip
|
||||
path: .
|
||||
- name: Create tarball
|
||||
run: git archive --prefix="cryptomator-${{ github.ref }}/" -o "cryptomator-${{ github.ref }}.tar.gz" ${{ github.ref }}
|
||||
- name: Sign tarball with key 615D449FE6E6A235
|
||||
run: |
|
||||
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
|
||||
echo "${GPG_PASSPHRASE}" | gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a "cryptomator-${{ github.ref }}.tar.gz"
|
||||
env:
|
||||
GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }}
|
||||
GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: ${{ github.ref }}
|
||||
body: |
|
||||
:construction: Work in Progress
|
||||
|
||||
TODO:
|
||||
* [ ] add Linux appimage, zsync file and signature file
|
||||
* [ ] add Windows installer and signature file
|
||||
* [ ] add MacOs disk image and signature file
|
||||
|
||||
## What's new
|
||||
|
||||
## Bugfixes
|
||||
|
||||
## Misc
|
||||
|
||||
---
|
||||
|
||||
:scroll: A complete list of closed issues is available [here](LINK)
|
||||
draft: true
|
||||
prerelease: false
|
||||
- name: Upload buildkit-linux.zip to GitHub Releases
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: buildkit-linux.zip
|
||||
asset_name: buildkit-linux.zip
|
||||
asset_content_type: application/zip
|
||||
- name: Upload buildkit-mac.zip to GitHub Releases
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: buildkit-mac.zip
|
||||
asset_name: buildkit-mac.zip
|
||||
asset_content_type: application/zip
|
||||
- name: Upload buildkit-win.zip to GitHub Releases
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: buildkit-win.zip
|
||||
asset_name: buildkit-win.zip
|
||||
asset_content_type: application/zip
|
||||
- name: Upload tarball signature to GitHub Releases
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: "cryptomator-${{ github.ref }}.tar.gz.asc"
|
||||
asset_name: "cryptomator-${{ github.ref }}.tar.gz.asc"
|
||||
asset_content_type: application/octet-stream
|
||||
37
.github/workflows/triageBugs.yml
vendored
Normal file
37
.github/workflows/triageBugs.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
name: Bug Report Triage
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
closeTemplateViolation:
|
||||
name: Validate bug report against issue template
|
||||
runs-on: ubuntu-latest
|
||||
if: contains(github.event.issue.labels.*.name, 'type:bug')
|
||||
steps:
|
||||
- name: Check "Description"
|
||||
if: |
|
||||
!contains(github.event.issue.body, env.MUST_CONTAIN)
|
||||
|| contains(toJson(github.event.issue.body), env.MUST_NOT_CONTAIN)
|
||||
run: exit 1
|
||||
env:
|
||||
MUST_CONTAIN: '### Description'
|
||||
MUST_NOT_CONTAIN: '### Description\r\n\r\n[Summarize your problem.]\r\n\r\n### System Setup'
|
||||
- name: Check "Steps to Reproduce"
|
||||
if: |
|
||||
!contains(github.event.issue.body, env.MUST_CONTAIN)
|
||||
|| contains(toJson(github.event.issue.body), env.MUST_NOT_CONTAIN)
|
||||
run: exit 1
|
||||
env:
|
||||
MUST_CONTAIN: '### Steps to Reproduce'
|
||||
MUST_NOT_CONTAIN: '### Steps to Reproduce\r\n\r\n1. [First step]\r\n2. [Second step]\r\n3. [and so on…]\r\n\r\n#### Expected Behavior'
|
||||
- name: Close issue if one of the checks failed
|
||||
if: ${{ failure() }}
|
||||
uses: peter-evans/close-issue@v1
|
||||
with:
|
||||
comment: |
|
||||
This bug report did ignore our issue template. 😞
|
||||
Auto-closing this issue, since it is most likely not useful.
|
||||
|
||||
_This decision was made by a bot. If you think the bot is wrong, let us know and we'll reopen this issue._
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -17,6 +17,12 @@ pom.xml.versionsBackup
|
||||
# IntelliJ Settings Files (https://intellij-support.jetbrains.com/hc/en-us/articles/206544839-How-to-manage-projects-under-Version-Control-Systems) #
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/dictionaries
|
||||
.idea/**/shelf
|
||||
.idea/dictionaries/**
|
||||
!.idea/dictionaries/dict_*
|
||||
.idea/compiler.xml
|
||||
.idea/encodings.xml
|
||||
.idea/jarRepositories.xml
|
||||
.idea/uiDesigner.xml
|
||||
.idea/**/libraries/
|
||||
*.iml
|
||||
29
.idea/codeStyles/Project.xml
generated
29
.idea/codeStyles/Project.xml
generated
@@ -9,14 +9,36 @@
|
||||
<option name="RIGHT_MARGIN" value="220" />
|
||||
<option name="FORMATTER_TAGS_ENABLED" value="true" />
|
||||
<JavaCodeStyleSettings>
|
||||
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="30" />
|
||||
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="999" />
|
||||
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="10" />
|
||||
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
|
||||
<value />
|
||||
</option>
|
||||
<option name="IMPORT_LAYOUT_TABLE">
|
||||
<value>
|
||||
<package name="" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="javax" withSubpackages="true" static="false" />
|
||||
<package name="javafx" withSubpackages="true" static="false" />
|
||||
<package name="java" withSubpackages="true" static="false" />
|
||||
<emptyLine />
|
||||
<package name="" withSubpackages="true" static="true" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="JD_ALIGN_PARAM_COMMENTS" value="false" />
|
||||
<option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" />
|
||||
</JavaCodeStyleSettings>
|
||||
<Properties>
|
||||
<option name="KEEP_BLANK_LINES" value="true" />
|
||||
</Properties>
|
||||
<XML>
|
||||
<option name="XML_ATTRIBUTE_WRAP" value="0" />
|
||||
</XML>
|
||||
<codeStyleSettings language="CSS">
|
||||
<indentOptions>
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="Groovy">
|
||||
<indentOptions>
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
@@ -30,12 +52,17 @@
|
||||
<codeStyleSettings language="JAVA">
|
||||
<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="ENUM_CONSTANTS_WRAP" value="2" />
|
||||
<indentOptions>
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
</indentOptions>
|
||||
<arrangement>
|
||||
<rules />
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="JSON">
|
||||
<indentOptions>
|
||||
|
||||
41
.idea/compiler.xml
generated
41
.idea/compiler.xml
generated
@@ -1,41 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<annotationProcessing>
|
||||
<profile name="Annotation profile for Cryptomator" enabled="true">
|
||||
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||
<outputRelativeToContentRoot value="true" />
|
||||
<processorPath useClasspath="false">
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-compiler/2.26/dagger-compiler-2.26.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger/2.26/dagger-2.26.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/javax/inject/javax.inject/1/javax.inject-1.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-producers/2.26/dagger-producers-2.26.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/27.1-jre/guava-27.1-jre.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/code/findbugs/jsr305/3.0.1/jsr305-3.0.1.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/checkerframework/checker-qual/2.5.2/checker-qual-2.5.2.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/errorprone/error_prone_annotations/2.2.0/error_prone_annotations-2.2.0.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/j2objc/j2objc-annotations/1.1/j2objc-annotations-1.1.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/codehaus/mojo/animal-sniffer-annotations/1.17/animal-sniffer-annotations-1.17.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/checkerframework/checker-compat-qual/2.5.3/checker-compat-qual-2.5.3.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/google/dagger/dagger-spi/2.26/dagger-spi-2.26.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/com/squareup/javapoet/1.11.1/javapoet-1.11.1.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$/javax/annotation/jsr250-api/1.0/jsr250-api-1.0.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/net/ltgt/gradle/incap/incap/0.2/incap-0.2.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.3.50/kotlin-stdlib-1.3.50.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-common/1.3.50/kotlin-stdlib-common-1.3.50.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar" />
|
||||
<entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-metadata-jvm/0.1.0/kotlinx-metadata-jvm-0.1.0.jar" />
|
||||
</processorPath>
|
||||
<module name="keychain" />
|
||||
<module name="launcher" />
|
||||
<module name="commons" />
|
||||
<module name="ui" />
|
||||
</profile>
|
||||
</annotationProcessing>
|
||||
</component>
|
||||
</project>
|
||||
15
.idea/dictionaries/dict_de.xml
generated
Normal file
15
.idea/dictionaries/dict_de.xml
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="dict_de">
|
||||
<words>
|
||||
<w>tresorinhalt</w>
|
||||
<w>tresorkonfigurationsdatei</w>
|
||||
<w>tresorlaufwerk</w>
|
||||
<w>tresorliste</w>
|
||||
<w>tresorname</w>
|
||||
<w>tresoroptionen</w>
|
||||
<w>tresorstatistik</w>
|
||||
<w>ungespeicherten</w>
|
||||
<w>ungespeicherter</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
</component>
|
||||
106
.idea/dictionaries/dict_project.xml
generated
Normal file
106
.idea/dictionaries/dict_project.xml
generated
Normal file
@@ -0,0 +1,106 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="dict_project">
|
||||
<words>
|
||||
<w>addvault</w>
|
||||
<w>addvaultwizard</w>
|
||||
<w>adoptopenjdk</w>
|
||||
<w>affero</w>
|
||||
<w>aquafx</w>
|
||||
<w>autolock</w>
|
||||
<w>autolocked</w>
|
||||
<w>autolocking</w>
|
||||
<w>baos</w>
|
||||
<w>bkup</w>
|
||||
<w>buildkit</w>
|
||||
<w>changepassword</w>
|
||||
<w>checkerframework</w>
|
||||
<w>crit</w>
|
||||
<w>crowdin</w>
|
||||
<w>cryptofs</w>
|
||||
<w>cryptomator</w>
|
||||
<w>cryptomator's</w>
|
||||
<w>cryptor</w>
|
||||
<w>csprng</w>
|
||||
<w>dcryptomator</w>
|
||||
<w>dfuse</w>
|
||||
<w>dirid</w>
|
||||
<w>djdk</w>
|
||||
<w>dokany</w>
|
||||
<w>dragboard</w>
|
||||
<w>easybind</w>
|
||||
<w>encr</w>
|
||||
<w>errorprone</w>
|
||||
<w>failureaccess</w>
|
||||
<w>fbidis</w>
|
||||
<w>fldinst</w>
|
||||
<w>fldrslt</w>
|
||||
<w>fontawesomefx</w>
|
||||
<w>gdrive</w>
|
||||
<w>gvfs</w>
|
||||
<w>hmmss</w>
|
||||
<w>httpcomponents</w>
|
||||
<w>httpcore</w>
|
||||
<w>iclouddrive</w>
|
||||
<w>jensd</w>
|
||||
<w>jffi</w>
|
||||
<w>keyloading</w>
|
||||
<w>kibs</w>
|
||||
<w>listcell</w>
|
||||
<w>listenablefuture</w>
|
||||
<w>lopp</w>
|
||||
<w>mainwindow</w>
|
||||
<w>masterkey</w>
|
||||
<w>masterkeyfile</w>
|
||||
<w>mibs</w>
|
||||
<w>mountpath</w>
|
||||
<w>mpc's</w>
|
||||
<w>needsmigration</w>
|
||||
<w>noncommercially</w>
|
||||
<w>noël</w>
|
||||
<w>nulab</w>
|
||||
<w>oatomic</w>
|
||||
<w>oauto</w>
|
||||
<w>objectgraph</w>
|
||||
<w>odefault</w>
|
||||
<w>ogid</w>
|
||||
<w>onoappledouble</w>
|
||||
<w>ordonly</w>
|
||||
<w>ouid</w>
|
||||
<w>ovolname</w>
|
||||
<w>passthrough</w>
|
||||
<w>patreon</w>
|
||||
<w>pcloud</w>
|
||||
<w>probot</w>
|
||||
<w>recoverykey</w>
|
||||
<w>relicensing</w>
|
||||
<w>removevault</w>
|
||||
<w>revealer</w>
|
||||
<w>serceman</w>
|
||||
<w>setolabs</w>
|
||||
<w>skymatic</w>
|
||||
<w>socio</w>
|
||||
<w>spof</w>
|
||||
<w>stenzel</w>
|
||||
<w>styleclass</w>
|
||||
<w>sublicenses</w>
|
||||
<w>sublicensing</w>
|
||||
<w>systemkeychain</w>
|
||||
<w>tada</w>
|
||||
<w>tidelift</w>
|
||||
<w>tmpmountpoint</w>
|
||||
<w>tobiasdiez</w>
|
||||
<w>toggler</w>
|
||||
<w>traymenu</w>
|
||||
<w>unknownerror</w>
|
||||
<w>unlockable</w>
|
||||
<w>vaultconfig</w>
|
||||
<w>vaultlist</w>
|
||||
<w>vaultname</w>
|
||||
<w>vaultoptions</w>
|
||||
<w>wrongfilealert</w>
|
||||
<w>xattr</w>
|
||||
<w>zillmann</w>
|
||||
<w>zxcvbn</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
</component>
|
||||
13
.idea/encodings.xml
generated
13
.idea/encodings.xml
generated
@@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8">
|
||||
<file url="file://$PROJECT_DIR$/main" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/main/commons/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/main/keychain/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/main/keychain/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/main/launcher/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/main/ui/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/main/ui/src/main/resources" charset="UTF-8" />
|
||||
<file url="PROJECT" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
||||
2
.idea/inspectionProfiles/Project_Default.xml
generated
2
.idea/inspectionProfiles/Project_Default.xml
generated
@@ -1,7 +1,7 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||
<inspection_tool class="SpellCheckingInspection" enabled="true" level="TYPO" enabled_by_default="true">
|
||||
<option name="processCode" value="true" />
|
||||
<option name="processLiterals" value="true" />
|
||||
<option name="processComments" value="true" />
|
||||
|
||||
4
.idea/misc.xml
generated
4
.idea/misc.xml
generated
@@ -4,11 +4,11 @@
|
||||
<component name="MavenProjectsManager">
|
||||
<option name="originalFiles">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/main/pom.xml" />
|
||||
<option value="$PROJECT_DIR$/pom.xml" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="false" project-jdk-name="11" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_16" project-jdk-name="16" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/Desktop.iml" filepath="$PROJECT_DIR$/.idea/Desktop.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
4
.idea/runConfigurations/Cryptomator_Linux.xml
generated
4
.idea/runConfigurations/Cryptomator_Linux.xml
generated
@@ -1,8 +1,8 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Cryptomator Linux" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="launcher" />
|
||||
<option name="VM_PARAMETERS" value="-Djdk.gtk.version=2 -Duser.language=en -Dcryptomator.settingsPath="~/.config/Cryptomator/settings.json" -Dcryptomator.ipcPortPath="~/.config/Cryptomator/ipcPort.bin" -Dcryptomator.logDir="~/.local/share/Cryptomator/logs" -Dcryptomator.mountPointsDir="~/.local/share/Cryptomator/mnt" -Xss20m -Xmx512m" />
|
||||
<module name="cryptomator" />
|
||||
<option name="VM_PARAMETERS" value="-Djdk.gtk.version=2 -Duser.language=en -Dcryptomator.settingsPath="~/.config/Cryptomator/settings.json" -Dcryptomator.ipcPortPath="~/.config/Cryptomator/ipcPort.bin" -Dcryptomator.logDir="~/.local/share/Cryptomator/logs" -Dcryptomator.mountPointsDir="~/.local/share/Cryptomator/mnt" -Dcryptomator.showTrayIcon=true -Xss20m -Xmx512m" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
10
.idea/runConfigurations/Cryptomator_Linux_Dev.xml
generated
Normal file
10
.idea/runConfigurations/Cryptomator_Linux_Dev.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<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="-Djdk.gtk.version=2 -Duser.language=en -Dcryptomator.settingsPath="~/.config/Cryptomator-Dev/settings.json" -Dcryptomator.ipcPortPath="~/.config/Cryptomator-Dev/ipcPort.bin" -Dcryptomator.logDir="~/.local/share/Cryptomator-Dev/logs" -Dcryptomator.mountPointsDir="~/.local/share/Cryptomator-Dev/mnt" -Dcryptomator.showTrayIcon=true -Dfuse.experimental="true" -Xss20m -Xmx512m" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
4
.idea/runConfigurations/Cryptomator_Windows.xml
generated
4
.idea/runConfigurations/Cryptomator_Windows.xml
generated
@@ -1,8 +1,8 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Cryptomator Windows" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="launcher" />
|
||||
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath="~/AppData/Roaming/Cryptomator/settings.json" -Dcryptomator.ipcPortPath="~/AppData/Roaming/Cryptomator/ipcPort.bin" -Dcryptomator.logDir="~/AppData/Roaming/Cryptomator" -Dcryptomator.keychainPath="~/AppData/Roaming/Cryptomator/keychain.json" -Xss2m -Xmx512m" />
|
||||
<module name="cryptomator" />
|
||||
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath="~/AppData/Roaming/Cryptomator/settings.json" -Dcryptomator.ipcPortPath="~/AppData/Roaming/Cryptomator/ipcPort.bin" -Dcryptomator.logDir="~/AppData/Roaming/Cryptomator" -Dcryptomator.keychainPath="~/AppData/Roaming/Cryptomator/keychain.json" -Dcryptomator.mountPointsDir="~/Cryptomator" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
10
.idea/runConfigurations/Cryptomator_Windows_Dev.xml
generated
Normal file
10
.idea/runConfigurations/Cryptomator_Windows_Dev.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<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="-Duser.language=en -Dcryptomator.settingsPath="~/AppData/Roaming/Cryptomator-Dev/settings.json" -Dcryptomator.ipcPortPath="~/AppData/Roaming/Cryptomator-Dev/ipcPort.bin" -Dcryptomator.logDir="~/AppData/Roaming/Cryptomator-Dev" -Dcryptomator.keychainPath="~/AppData/Roaming/Cryptomator-Dev/keychain.json" -Dcryptomator.mountPointsDir="~/Cryptomator-Dev" -Dfuse.experimental="true" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
8
.idea/runConfigurations/Cryptomator_macOS.xml
generated
8
.idea/runConfigurations/Cryptomator_macOS.xml
generated
@@ -1,9 +1,11 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Cryptomator macOS" type="Application" factoryName="Application">
|
||||
<envs>
|
||||
<env name="LD_LIBRARY_PATH" value="/usr/local/lib" />
|
||||
</envs>
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="launcher" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath="~/Library/Application Support/Cryptomator/settings.json" -Dcryptomator.ipcPortPath="~/Library/Application Support/Cryptomator/ipcPort.bin" -Dcryptomator.logDir="~/Library/Logs/Cryptomator" -Dcryptomator.mountPointsDir="/Volumes/" -Xss2m -Xmx512m -ea" />
|
||||
<module name="cryptomator" />
|
||||
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath="~/Library/Application Support/Cryptomator/settings.json" -Dcryptomator.ipcPortPath="~/Library/Application Support/Cryptomator/ipcPort.bin" -Dcryptomator.logDir="~/Library/Logs/Cryptomator" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m -ea" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
13
.idea/runConfigurations/Cryptomator_macOS_Dev.xml
generated
Normal file
13
.idea/runConfigurations/Cryptomator_macOS_Dev.xml
generated
Normal file
@@ -0,0 +1,13 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Cryptomator macOS Dev" type="Application" factoryName="Application">
|
||||
<envs>
|
||||
<env name="LD_LIBRARY_PATH" value="/usr/local/lib" />
|
||||
</envs>
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="cryptomator" />
|
||||
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath="~/Library/Application Support/Cryptomator-Dev/settings.json" -Dcryptomator.ipcPortPath="~/Library/Application Support/Cryptomator-Dev/ipcPort.bin" -Dcryptomator.logDir="~/Library/Logs/Cryptomator-Dev" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m -ea" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"package": {
|
||||
"name": "buildkit",
|
||||
"repo": "cryptomator",
|
||||
"subject": "cryptomator"
|
||||
},
|
||||
"version": {
|
||||
"name": "$TRAVIS_TAG",
|
||||
"desc": "Cryptomator version $TRAVIS_TAG",
|
||||
"released": "$TODAY",
|
||||
"vcs_tag": "$TRAVIS_TAG",
|
||||
"gpgSign": true
|
||||
},
|
||||
"files":
|
||||
[
|
||||
{"includePattern": "main/buildkit/target/(buildkit-[a-z]+\\.zip)", "uploadPattern": "/$TRAVIS_TAG/$1"}
|
||||
],
|
||||
"publish": true
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"package": {
|
||||
"name": "buildkit",
|
||||
"repo": "cryptomator",
|
||||
"subject": "cryptomator"
|
||||
},
|
||||
"version": {
|
||||
"name": "snapshot"
|
||||
},
|
||||
"files":
|
||||
[
|
||||
{"includePattern": "main/buildkit/target/(buildkit-[a-z]+\\.zip)", "uploadPattern": "/snapshot/$1", "matrixParams": {"override": 1}}
|
||||
],
|
||||
"publish": true
|
||||
}
|
||||
65
.travis.yml
65
.travis.yml
@@ -1,65 +0,0 @@
|
||||
dist: bionic
|
||||
language: java
|
||||
sudo: false
|
||||
jdk:
|
||||
- openjdk11
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.m2
|
||||
env:
|
||||
global:
|
||||
- secure: "HftEaabMmWn5GwKFKksUkOcelc3Mn7xazwAEy+4d4gL1+F8VhID/6DCK7nas+afUymWnxTano8Rv4Ci5MWryNkNkTH+FUPWmF3xWezc3hajSyS7RB92IZ8VPetl4Fo8UI1WwM5apDEaugalPxkIf8a7N+lpG5X/Gpumwzo3Be3w=" # BINTRAY_API_KEY
|
||||
- secure: "oWFgRTVP6lyTa7qVxlvkpm20MtVc3BtmsNXQJS6bfg2A0o/iCQMNx7OD59BaafCLGRKvCcJVESiC8FlSylVMS7CDSyYu0gg70NUiIuHp4NBM5inFWYCy/PdQsCTzr5uvNG+rMFQpMFRaCV0FrfM3tLondcVkhsHL68l93Xoexx4=" # CODACY_PROJECT_TOKEN
|
||||
- secure: "zJxgytA2Ks5Xzv+7kUaUq+EBFNQw9Qec63lcMJVuXVWczjL16nKW1EzzV515ag+OWL46z3lEPForDhufw0VtFnNmaX68jkO0mp01eLrHApc1llN2Y/U8GBXfNNazN4+Kom4H+z/AO+wJr8EsKMMUczCdQ3APgd9uVI0hzXw/Z3M=" # GITHUB_API_KEY
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- haveged
|
||||
install:
|
||||
# - curl -o $HOME/.m2/settings.xml https://gist.githubusercontent.com/cryptobot/cf5fbd909c4782aaeeeb7c7f4a1a43da/raw/e60ee486e34ee0c79f89f947abe2c83b4290c6bb/settings.xml
|
||||
- mvn -fmain/pom.xml clean install -DskipTests -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN org.codehaus.mojo:versions-maven-plugin:help dependency:go-offline -Pcoverage,release # "clean install" needed until we can exclude artifacts currently in the reactor, see https://maven.apache.org/plugins/maven-dependency-plugin/go-offline-mojo.html#excludeReactor and https://issues.apache.org/jira/browse/MDEP-568
|
||||
before_script:
|
||||
- |
|
||||
if [[ -n "$TRAVIS_TAG" ]]; then
|
||||
mvn -fmain/pom.xml org.codehaus.mojo:versions-maven-plugin:set -DnewVersion=$TRAVIS_TAG
|
||||
else
|
||||
mvn -fmain/pom.xml org.codehaus.mojo:versions-maven-plugin:set -DnewVersion=SNAPSHOT-$(echo $TRAVIS_COMMIT | head -c7)
|
||||
fi
|
||||
script:
|
||||
- mvn --update-snapshots -fmain/pom.xml clean test verify -Pcoverage
|
||||
after_success:
|
||||
- curl -o ~/codacy-coverage-reporter.jar https://repo.maven.apache.org/maven2/com/codacy/codacy-coverage-reporter/7.1.0/codacy-coverage-reporter-7.1.0-assembly.jar
|
||||
- $JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter.jar report -l Java -r main/commons/target/site/jacoco/jacoco.xml --partial
|
||||
- $JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter.jar report -l Java -r main/keychain/target/site/jacoco/jacoco.xml --partial
|
||||
- $JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter.jar report -l Java -r main/ui/target/site/jacoco/jacoco.xml --partial
|
||||
- $JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter.jar report -l Java -r main/launcher/target/site/jacoco/jacoco.xml --partial
|
||||
- $JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter.jar final
|
||||
before_deploy:
|
||||
- mvn -fmain/pom.xml package -Prelease -DskipTests
|
||||
- export TODAY=`date +'%Y-%m-%d'`; envsubst '$TRAVIS_TAG $TODAY' < .travis-deploy-release.tmpl.json > .travis-deploy-release.json
|
||||
deploy:
|
||||
- provider: bintray # SNAPSHOTS
|
||||
file: .travis-deploy-snapshot.json
|
||||
user: cryptobot
|
||||
key: $BINTRAY_API_KEY
|
||||
skip_cleanup: true
|
||||
on:
|
||||
repo: cryptomator/cryptomator
|
||||
branch: develop
|
||||
- provider: bintray # RELEASES
|
||||
file: .travis-deploy-release.json
|
||||
user: cryptobot
|
||||
key: $BINTRAY_API_KEY
|
||||
skip_cleanup: true
|
||||
on:
|
||||
repo: cryptomator/cryptomator
|
||||
tags: true
|
||||
- provider: releases
|
||||
api_key: $GITHUB_API_KEY
|
||||
file_glob: true
|
||||
file:
|
||||
- "main/buildkit/target/buildkit-*.zip"
|
||||
skip_cleanup: true
|
||||
on:
|
||||
repo: cryptomator/cryptomator
|
||||
tags: true
|
||||
43
README.md
43
README.md
@@ -1,8 +1,8 @@
|
||||
[](https://cryptomator.org/)
|
||||
|
||||
[](https://travis-ci.org/cryptomator/cryptomator)
|
||||
[](https://snyk.io/test/github/cryptomator/cryptomator?targetFile=main%2Fpom.xml)
|
||||
[](https://www.codacy.com/app/cryptomator/cryptomator?utm_source=github.com&utm_medium=referral&utm_content=cryptomator/cryptomator&utm_campaign=Badge_Grade)
|
||||
[](https://github.com/cryptomator/cryptomator/actions?query=workflow%3ABuild)
|
||||
[](https://snyk.io/test/github/cryptomator/cryptomator)
|
||||
[](https://www.codacy.com/gh/cryptomator/cryptomator/dashboard)
|
||||
[](http://twitter.com/Cryptomator)
|
||||
[](https://translate.cryptomator.org/)
|
||||
[](https://github.com/cryptomator/cryptomator/releases/latest)
|
||||
@@ -15,9 +15,28 @@ Cryptomator is provided free of charge as an open-source project despite the hig
|
||||
- [One-time or recurring donation via Cryptomator's website.](https://cryptomator.org/#donate)
|
||||
- [Become a sponsor via Cryptomator's sponsors website.](https://cryptomator.org/sponsors/)
|
||||
|
||||
### Gold Sponsors
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a href="https://www.gee-whiz.de/"><img src="https://cryptomator.org/img/sponsors/geewhiz.svg" alt="gee-whiz" height="80"></a></td>
|
||||
<td><a href="https://proxy-hub.com/"><img src="https://cryptomator.org/img/sponsors/proxyhub.svg" alt="Proxy-Hub" height="80"></a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Silver Sponsors
|
||||
|
||||
[](https://thebestvpn.com/)
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a href="https://thebestvpn.com/"><img src="https://cryptomator.org/img/sponsors/thebestvpn@2x.png" alt="TheBestVPN" height="64"></a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
- [Jameson Lopp](https://www.lopp.net/)
|
||||
|
||||
---
|
||||
|
||||
@@ -29,7 +48,7 @@ Download native binaries of Cryptomator on [cryptomator.org](https://cryptomator
|
||||
|
||||
## Features
|
||||
|
||||
- Works with Dropbox, Google Drive, OneDrive, ownCloud, Nextcloud and any other cloud storage service which synchronizes with a local directory
|
||||
- Works with Dropbox, Google Drive, OneDrive, MEGA, pCloud, ownCloud, Nextcloud and any other cloud storage service which synchronizes with a local directory
|
||||
- Open Source means: No backdoors, control is better than trust
|
||||
- Client-side: No accounts, no data shared with any online service
|
||||
- Totally transparent: Just work on the virtual drive as if it were a USB flash drive
|
||||
@@ -37,7 +56,7 @@ Download native binaries of Cryptomator on [cryptomator.org](https://cryptomator
|
||||
- File names get encrypted
|
||||
- Folder structure gets obfuscated
|
||||
- Use as many vaults in your Dropbox as you want, each having individual passwords
|
||||
- One thousand commits for the security of your data!! :tada:
|
||||
- Three thousand commits for the security of your data!! :tada:
|
||||
|
||||
### Privacy
|
||||
|
||||
@@ -55,24 +74,26 @@ Download native binaries of Cryptomator on [cryptomator.org](https://cryptomator
|
||||
|
||||
### Security Architecture
|
||||
|
||||
For more information on the security details visit [cryptomator.org](https://cryptomator.org/architecture/).
|
||||
For more information on the security details visit [cryptomator.org](https://docs.cryptomator.org/en/latest/security/architecture/).
|
||||
|
||||
## Building
|
||||
|
||||
### Dependencies
|
||||
|
||||
* JDK 11 (we recommend to use the latest version)
|
||||
* JDK 16 (e.g. adoptopenjdk)
|
||||
* Maven 3
|
||||
* Optional: OS-dependent build tools for native packaging (see [Windows](https://github.com/cryptomator/cryptomator-win), [OS X](https://github.com/cryptomator/cryptomator-osx), [Linux](https://github.com/cryptomator/builder-containers))
|
||||
|
||||
### Run Maven
|
||||
|
||||
```
|
||||
cd main
|
||||
mvn clean install -Prelease
|
||||
mvn clean install
|
||||
# or mvn clean install -Pwindows
|
||||
# or mvn clean install -Pmac
|
||||
# or mvn clean install -Plinux
|
||||
```
|
||||
|
||||
This will build all the jars and bundle them together with their OS-specific dependencies under `main/buildkit/target`. This can now be used to build native packages.
|
||||
This will build all the jars and bundle them together with their OS-specific dependencies under `target`. This can now be used to build native packages.
|
||||
|
||||
### Start Cryptomator
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
<assembly xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
|
||||
<id>tarball</id>
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
@@ -14,13 +14,6 @@
|
||||
</includes>
|
||||
<outputDirectory>libs</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>target/</directory>
|
||||
<includes>
|
||||
<include>ffi-version.txt</include>
|
||||
</includes>
|
||||
<outputDirectory>libs</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>target/</directory>
|
||||
<includes>
|
||||
@@ -37,14 +30,14 @@
|
||||
<fileMode>0755</fileMode>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>target/libs</directory>
|
||||
<directory>target/</directory>
|
||||
<includes>
|
||||
<include>*.jar</include>
|
||||
<include>cryptomator-*.jar</include>
|
||||
</includes>
|
||||
<outputDirectory>libs</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>target/linux-libs</directory>
|
||||
<directory>target/libs</directory>
|
||||
<includes>
|
||||
<include>*.jar</include>
|
||||
</includes>
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
<assembly xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
|
||||
<id>tarball</id>
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
@@ -14,13 +14,6 @@
|
||||
</includes>
|
||||
<outputDirectory>libs</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>target/</directory>
|
||||
<includes>
|
||||
<include>ffi-version.txt</include>
|
||||
</includes>
|
||||
<outputDirectory>libs</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>target/</directory>
|
||||
<includes>
|
||||
@@ -37,14 +30,14 @@
|
||||
<fileMode>0755</fileMode>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>target/libs</directory>
|
||||
<directory>target/</directory>
|
||||
<includes>
|
||||
<include>*.jar</include>
|
||||
<include>cryptomator-*.jar</include>
|
||||
</includes>
|
||||
<outputDirectory>libs</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>target/mac-libs</directory>
|
||||
<directory>target/libs</directory>
|
||||
<includes>
|
||||
<include>*.jar</include>
|
||||
</includes>
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
<assembly xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
|
||||
<id>tarball</id>
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
@@ -14,13 +14,6 @@
|
||||
</includes>
|
||||
<outputDirectory>libs</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>target/</directory>
|
||||
<includes>
|
||||
<include>ffi-version.txt</include>
|
||||
</includes>
|
||||
<outputDirectory>libs</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>target/</directory>
|
||||
<includes>
|
||||
@@ -37,14 +30,14 @@
|
||||
<fileMode>0755</fileMode>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>target/libs</directory>
|
||||
<directory>target/</directory>
|
||||
<includes>
|
||||
<include>*.jar</include>
|
||||
<include>cryptomator-*.jar</include>
|
||||
</includes>
|
||||
<outputDirectory>libs</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>target/win-libs</directory>
|
||||
<directory>target/libs</directory>
|
||||
<includes>
|
||||
<include>*.jar</include>
|
||||
</includes>
|
||||
@@ -1,174 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>main</artifactId>
|
||||
<version>1.5.0</version>
|
||||
</parent>
|
||||
<artifactId>buildkit</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<name>Cryptomator Build Kit</name>
|
||||
<description>Builds a package that can be built with Ant locally</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>launcher</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- copy resources -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-resources</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}</outputDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>${project.basedir}/src/main/resources</directory>
|
||||
<includes>
|
||||
<include>version.txt</include>
|
||||
<include>ffi-version.txt</include>
|
||||
<include>launcher-mac.sh</include>
|
||||
<include>launcher-linux.sh</include>
|
||||
<include>launcher-win.bat</include>
|
||||
<include>LICENSE.txt</include>
|
||||
</includes>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- copy libraries to target/libs/: -->
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-libs</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/libs</outputDirectory>
|
||||
<excludeClassifiers>linux,mac,win</excludeClassifiers>
|
||||
<excludeArtifactIds>dbus-java,secret-service,hkdf,java-utils</excludeArtifactIds>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-linux-libs</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/linux-libs</outputDirectory>
|
||||
<includeGroupIds>org.openjfx</includeGroupIds>
|
||||
<classifier>linux</classifier>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-linux-secret-service</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/linux-libs</outputDirectory>
|
||||
<includeArtifactIds>dbus-java,secret-service,hkdf,java-utils</includeArtifactIds>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-mac-libs</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/mac-libs</outputDirectory>
|
||||
<includeGroupIds>org.openjfx</includeGroupIds>
|
||||
<classifier>mac</classifier>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-win-libs</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/win-libs</outputDirectory>
|
||||
<includeGroupIds>org.openjfx</includeGroupIds>
|
||||
<classifier>win</classifier>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- create buildkit.zip: -->
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>assemble-linux</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>assembly-linux.xml</descriptor>
|
||||
</descriptors>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<finalName>buildkit-linux</finalName>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>assemble-mac</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>assembly-mac.xml</descriptor>
|
||||
</descriptors>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<finalName>buildkit-mac</finalName>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>assemble-win</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>assembly-win.xml</descriptor>
|
||||
</descriptors>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<finalName>buildkit-win</finalName>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -1 +0,0 @@
|
||||
${cryptomator.jni.version}
|
||||
@@ -1,86 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>main</artifactId>
|
||||
<version>1.5.0</version>
|
||||
</parent>
|
||||
<artifactId>commons</artifactId>
|
||||
<name>Cryptomator Commons</name>
|
||||
<description>Shared utilities</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>cryptofs</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>fuse-nio-adapter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>dokany-nio-adapter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>webdav-nio-adapter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>jni</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- JavaFx -->
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-base</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-graphics</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- EasyBind -->
|
||||
<dependency>
|
||||
<groupId>org.fxmisc.easybind</groupId>
|
||||
<artifactId>easybind</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- JWT -->
|
||||
<dependency>
|
||||
<groupId>com.auth0</groupId>
|
||||
<artifactId>java-jwt</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Google -->
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Apache Commons -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- DI -->
|
||||
<dependency>
|
||||
<groupId>com.google.dagger</groupId>
|
||||
<artifactId>dagger</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Logging -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,7 +0,0 @@
|
||||
package org.cryptomator.common;
|
||||
|
||||
public interface Constants {
|
||||
|
||||
String MASTERKEY_FILENAME = "masterkey.cryptomator";
|
||||
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2019 Skymatic GmbH.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the accompanying LICENSE file.
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.common;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import org.cryptomator.jni.JniFunctions;
|
||||
import org.cryptomator.jni.MacFunctions;
|
||||
import org.cryptomator.jni.WinFunctions;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
import java.util.Optional;
|
||||
|
||||
@Module
|
||||
public class JniModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
Optional<MacFunctions> provideOptionalMacFunctions() {
|
||||
return JniFunctions.macFunctions();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
Optional<WinFunctions> provideOptionalWinFunctions() {
|
||||
return JniFunctions.winFunctions();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,79 +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;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
|
||||
public final class LazyInitializer {
|
||||
|
||||
private LazyInitializer() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #initializeLazily(AtomicReference, SupplierThrowingException, Class)} except that no checked exception may be thrown by the factory function.
|
||||
*
|
||||
* @param <T> Type of the value
|
||||
* @param reference A reference to a maybe not yet initialized value.
|
||||
* @param factory A factory providing a value for the reference, if it doesn't exist yet. The factory may be invoked multiple times, but only one result will survive.
|
||||
* @return The initialized value
|
||||
*/
|
||||
public static <T> T initializeLazily(AtomicReference<T> reference, Supplier<T> factory) {
|
||||
SupplierThrowingException<T, RuntimeException> factoryThrowingRuntimeExceptions = () -> factory.get();
|
||||
return initializeLazily(reference, factoryThrowingRuntimeExceptions, RuntimeException.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Threadsafe lazy initialization pattern as proposed on http://stackoverflow.com/a/30247202/4014509
|
||||
*
|
||||
* @param <T> Type of the value
|
||||
* @param <E> Type of the any expected exception that may occur during initialization
|
||||
* @param reference A reference to a maybe not yet initialized value.
|
||||
* @param factory A factory providing a value for the reference, if it doesn't exist yet. The factory may be invoked multiple times, but only one result will survive.
|
||||
* @param exceptionType Expected exception type.
|
||||
* @return The initialized value
|
||||
* @throws E Exception thrown by the factory function.
|
||||
*/
|
||||
public static <T, E extends Exception> T initializeLazily(AtomicReference<T> reference, SupplierThrowingException<T, E> factory, Class<E> exceptionType) throws E {
|
||||
final T existing = reference.get();
|
||||
if (existing != null) {
|
||||
return existing;
|
||||
} else {
|
||||
try {
|
||||
return reference.updateAndGet(invokeFactoryIfNull(factory));
|
||||
} catch (InitializationException e) {
|
||||
Throwables.throwIfUnchecked(e.getCause());
|
||||
Throwables.throwIfInstanceOf(e.getCause(), exceptionType);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static <T, E extends Exception> UnaryOperator<T> invokeFactoryIfNull(SupplierThrowingException<T, E> factory) throws InitializationException {
|
||||
return currentValue -> {
|
||||
if (currentValue == null) {
|
||||
try {
|
||||
return factory.get();
|
||||
} catch (Exception e) {
|
||||
throw new InitializationException(e);
|
||||
}
|
||||
} else {
|
||||
return currentValue;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static class InitializationException extends RuntimeException {
|
||||
|
||||
public InitializationException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,167 +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.common.base.Strings;
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* The settings specific to a single vault.
|
||||
* TODO: Change the name of individualMountPath and its derivatives to customMountPath
|
||||
*/
|
||||
public class VaultSettings {
|
||||
|
||||
public static final boolean DEFAULT_UNLOCK_AFTER_STARTUP = false;
|
||||
public static final boolean DEFAULT_REAVEAL_AFTER_MOUNT = true;
|
||||
public static final boolean DEFAULT_USES_INDIVIDUAL_MOUNTPATH = false;
|
||||
public static final boolean DEFAULT_USES_READONLY_MODE = false;
|
||||
public static final String DEFAULT_MOUNT_FLAGS = "";
|
||||
|
||||
private static final Random RNG = new Random();
|
||||
|
||||
private final String id;
|
||||
private final ObjectProperty<Path> path = new SimpleObjectProperty();
|
||||
private final StringProperty mountName = new SimpleStringProperty();
|
||||
private final StringProperty winDriveLetter = new SimpleStringProperty();
|
||||
private final BooleanProperty unlockAfterStartup = new SimpleBooleanProperty(DEFAULT_UNLOCK_AFTER_STARTUP);
|
||||
private final BooleanProperty revealAfterMount = new SimpleBooleanProperty(DEFAULT_REAVEAL_AFTER_MOUNT);
|
||||
private final BooleanProperty usesIndividualMountPath = new SimpleBooleanProperty(DEFAULT_USES_INDIVIDUAL_MOUNTPATH);
|
||||
private final StringProperty individualMountPath = new SimpleStringProperty();
|
||||
private final BooleanProperty usesReadOnlyMode = new SimpleBooleanProperty(DEFAULT_USES_READONLY_MODE);
|
||||
private final StringProperty mountFlags = new SimpleStringProperty(DEFAULT_MOUNT_FLAGS);
|
||||
|
||||
public VaultSettings(String id) {
|
||||
this.id = Objects.requireNonNull(id);
|
||||
|
||||
EasyBind.subscribe(path, this::deriveMountNameFromPath);
|
||||
}
|
||||
|
||||
Observable[] observables() {
|
||||
return new Observable[]{path, mountName, winDriveLetter, unlockAfterStartup, revealAfterMount, usesIndividualMountPath, individualMountPath, usesReadOnlyMode, mountFlags};
|
||||
}
|
||||
|
||||
private void deriveMountNameFromPath(Path path) {
|
||||
if (path != null && StringUtils.isBlank(mountName.get())) {
|
||||
mountName.set(normalizeMountName(path.getFileName().toString()));
|
||||
}
|
||||
}
|
||||
|
||||
public static VaultSettings withRandomId() {
|
||||
return new VaultSettings(generateId());
|
||||
}
|
||||
|
||||
private static String generateId() {
|
||||
byte[] randomBytes = new byte[9];
|
||||
RNG.nextBytes(randomBytes);
|
||||
return BaseEncoding.base64Url().encode(randomBytes);
|
||||
}
|
||||
|
||||
public static String normalizeMountName(String mountName) {
|
||||
String normalizedMountName = StringUtils.stripAccents(mountName);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (char c : normalizedMountName.toCharArray()) {
|
||||
if (Character.isWhitespace(c)) {
|
||||
if (builder.length() == 0 || builder.charAt(builder.length() - 1) != '_') {
|
||||
builder.append('_');
|
||||
}
|
||||
} else if (c < 127 && Character.isLetterOrDigit(c)) {
|
||||
builder.append(c);
|
||||
} else {
|
||||
if (builder.length() == 0 || builder.charAt(builder.length() - 1) != '_') {
|
||||
builder.append('_');
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/* Getter/Setter */
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public ObjectProperty<Path> path() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public StringProperty mountName() {
|
||||
return mountName;
|
||||
}
|
||||
|
||||
public StringProperty winDriveLetter() {
|
||||
return winDriveLetter;
|
||||
}
|
||||
|
||||
public BooleanProperty unlockAfterStartup() {
|
||||
return unlockAfterStartup;
|
||||
}
|
||||
|
||||
public BooleanProperty revealAfterMount() {
|
||||
return revealAfterMount;
|
||||
}
|
||||
|
||||
public BooleanProperty usesIndividualMountPath() {
|
||||
return usesIndividualMountPath;
|
||||
}
|
||||
|
||||
public StringProperty individualMountPath() {
|
||||
return individualMountPath;
|
||||
}
|
||||
|
||||
public Optional<String> getIndividualMountPath() {
|
||||
if (usesIndividualMountPath.get()) {
|
||||
return Optional.ofNullable(Strings.emptyToNull(individualMountPath.get()));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public BooleanProperty usesReadOnlyMode() {
|
||||
return usesReadOnlyMode;
|
||||
}
|
||||
|
||||
public StringProperty mountFlags() {
|
||||
return mountFlags;
|
||||
}
|
||||
|
||||
/* Hashcode/Equals */
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof VaultSettings && obj.getClass().equals(this.getClass())) {
|
||||
VaultSettings other = (VaultSettings) obj;
|
||||
return Objects.equals(this.id, other.id);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,102 +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.JsonWriter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
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("mountName").value(value.mountName().get());
|
||||
out.name("winDriveLetter").value(value.winDriveLetter().get());
|
||||
out.name("unlockAfterStartup").value(value.unlockAfterStartup().get());
|
||||
out.name("revealAfterMount").value(value.revealAfterMount().get());
|
||||
out.name("usesIndividualMountPath").value(value.usesIndividualMountPath().get());
|
||||
out.name("individualMountPath").value(value.individualMountPath().get());
|
||||
out.name("usesReadOnlyMode").value(value.usesReadOnlyMode().get());
|
||||
out.name("mountFlags").value(value.mountFlags().get());
|
||||
out.endObject();
|
||||
}
|
||||
|
||||
public VaultSettings read(JsonReader in) throws IOException {
|
||||
String id = null;
|
||||
String path = null;
|
||||
String mountName = null;
|
||||
String individualMountPath = null;
|
||||
String winDriveLetter = null;
|
||||
boolean unlockAfterStartup = VaultSettings.DEFAULT_UNLOCK_AFTER_STARTUP;
|
||||
boolean revealAfterMount = VaultSettings.DEFAULT_REAVEAL_AFTER_MOUNT;
|
||||
boolean usesIndividualMountPath = VaultSettings.DEFAULT_USES_INDIVIDUAL_MOUNTPATH;
|
||||
boolean usesReadOnlyMode = VaultSettings.DEFAULT_USES_READONLY_MODE;
|
||||
String mountFlags = VaultSettings.DEFAULT_MOUNT_FLAGS;
|
||||
|
||||
in.beginObject();
|
||||
while (in.hasNext()) {
|
||||
String name = in.nextName();
|
||||
switch (name) {
|
||||
case "id":
|
||||
id = in.nextString();
|
||||
break;
|
||||
case "path":
|
||||
path = in.nextString();
|
||||
break;
|
||||
case "mountName":
|
||||
mountName = in.nextString();
|
||||
break;
|
||||
case "winDriveLetter":
|
||||
winDriveLetter = in.nextString();
|
||||
break;
|
||||
case "unlockAfterStartup":
|
||||
unlockAfterStartup = in.nextBoolean();
|
||||
break;
|
||||
case "revealAfterMount":
|
||||
revealAfterMount = in.nextBoolean();
|
||||
break;
|
||||
case "usesIndividualMountPath":
|
||||
usesIndividualMountPath = in.nextBoolean();
|
||||
break;
|
||||
case "individualMountPath":
|
||||
individualMountPath = in.nextString();
|
||||
break;
|
||||
case "usesReadOnlyMode":
|
||||
usesReadOnlyMode = in.nextBoolean();
|
||||
break;
|
||||
case "mountFlags":
|
||||
mountFlags = in.nextString();
|
||||
break;
|
||||
default:
|
||||
LOG.warn("Unsupported vault setting found in JSON: " + name);
|
||||
in.skipValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
in.endObject();
|
||||
|
||||
VaultSettings vaultSettings = (id == null) ? VaultSettings.withRandomId() : new VaultSettings(id);
|
||||
vaultSettings.mountName().set(mountName);
|
||||
vaultSettings.path().set(Paths.get(path));
|
||||
vaultSettings.winDriveLetter().set(winDriveLetter);
|
||||
vaultSettings.unlockAfterStartup().set(unlockAfterStartup);
|
||||
vaultSettings.revealAfterMount().set(revealAfterMount);
|
||||
vaultSettings.usesIndividualMountPath().set(usesIndividualMountPath);
|
||||
vaultSettings.individualMountPath().set(individualMountPath);
|
||||
vaultSettings.usesReadOnlyMode().set(usesReadOnlyMode);
|
||||
vaultSettings.mountFlags().set(mountFlags);
|
||||
return vaultSettings;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package org.cryptomator.common.settings;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public enum VolumeImpl {
|
||||
WEBDAV("WebDAV"),
|
||||
FUSE("FUSE"),
|
||||
DOKANY("Dokany");
|
||||
|
||||
private String displayName;
|
||||
|
||||
VolumeImpl(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a VolumeImpl by display name.
|
||||
*
|
||||
* @param displayName Display name of the VolumeImpl
|
||||
* @return VolumeImpl with the given <code>displayName</code>.
|
||||
* @throws IllegalArgumentException if not volumeImpl with the given <code>displayName</code> was found.
|
||||
*/
|
||||
public static VolumeImpl forDisplayName(String displayName) throws IllegalArgumentException {
|
||||
return Arrays.stream(values()) //
|
||||
.filter(impl -> impl.displayName.equals(displayName)) //
|
||||
.findAny() //
|
||||
.orElseThrow(IllegalArgumentException::new);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package org.cryptomator.common.settings;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public enum WebDavUrlScheme {
|
||||
DAV("dav", "dav:// (Gnome, Nautilus, ...)"),
|
||||
WEBDAV("webdav", "webdav:// (KDE, Dolphin, ...)");
|
||||
|
||||
private final String prefix;
|
||||
private final String displayName;
|
||||
|
||||
WebDavUrlScheme(String prefix, String displayName) {this.prefix = prefix;
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a WebDavUrlScheme by prefix.
|
||||
*
|
||||
* @param prefix Prefix of the WebDavUrlScheme
|
||||
* @return WebDavUrlScheme with the given <code>prefix</code>.
|
||||
* @throws IllegalArgumentException if not WebDavUrlScheme with the given <code>prefix</code> was found.
|
||||
*/
|
||||
public static WebDavUrlScheme forPrefix(String prefix) throws IllegalArgumentException {
|
||||
return Arrays.stream(values()) //
|
||||
.filter(impl -> impl.prefix.equals(prefix)) //
|
||||
.findAny() //
|
||||
.orElseThrow(IllegalArgumentException::new);
|
||||
}
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
package org.cryptomator.common.vaults;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import org.cryptomator.common.settings.VaultSettings;
|
||||
import org.cryptomator.cryptofs.CryptoFileSystem;
|
||||
import org.cryptomator.frontend.dokany.Mount;
|
||||
import org.cryptomator.frontend.dokany.MountFactory;
|
||||
import org.cryptomator.frontend.dokany.MountFailedException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.DirectoryNotEmptyException;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NotDirectoryException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
public class DokanyVolume implements Volume {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DokanyVolume.class);
|
||||
|
||||
private static final String FS_TYPE_NAME = "Cryptomator File System";
|
||||
|
||||
private final VaultSettings vaultSettings;
|
||||
private final MountFactory mountFactory;
|
||||
private final WindowsDriveLetters windowsDriveLetters;
|
||||
private Mount mount;
|
||||
private Path mountPoint;
|
||||
|
||||
@Inject
|
||||
public DokanyVolume(VaultSettings vaultSettings, ExecutorService executorService, WindowsDriveLetters windowsDriveLetters) {
|
||||
this.vaultSettings = vaultSettings;
|
||||
this.mountFactory = new MountFactory(executorService);
|
||||
this.windowsDriveLetters = windowsDriveLetters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
return DokanyVolume.isSupportedStatic();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mount(CryptoFileSystem fs, String mountFlags) throws VolumeException, IOException {
|
||||
this.mountPoint = determineMountPoint();
|
||||
String mountName = vaultSettings.mountName().get();
|
||||
try {
|
||||
this.mount = mountFactory.mount(fs.getPath("/"), mountPoint, mountName, FS_TYPE_NAME, mountFlags.strip());
|
||||
} catch (MountFailedException e) {
|
||||
if (vaultSettings.getIndividualMountPath().isPresent()) {
|
||||
LOG.warn("Failed to mount vault into {}. Is this directory currently accessed by another process (e.g. Windows Explorer)?", mountPoint);
|
||||
}
|
||||
throw new VolumeException("Unable to mount Filesystem", e);
|
||||
}
|
||||
}
|
||||
|
||||
private Path determineMountPoint() throws VolumeException, IOException {
|
||||
Optional<String> optionalCustomMountPoint = vaultSettings.getIndividualMountPath();
|
||||
if (optionalCustomMountPoint.isPresent()) {
|
||||
Path customMountPoint = Paths.get(optionalCustomMountPoint.get());
|
||||
checkProvidedMountPoint(customMountPoint);
|
||||
return customMountPoint;
|
||||
} else if (!Strings.isNullOrEmpty(vaultSettings.winDriveLetter().get())) {
|
||||
return Path.of(vaultSettings.winDriveLetter().get().charAt(0) + ":\\");
|
||||
} else {
|
||||
//auto assign drive letter
|
||||
if (!windowsDriveLetters.getAvailableDriveLetters().isEmpty()) {
|
||||
return Path.of(windowsDriveLetters.getAvailableDriveLetters().iterator().next() + ":\\");
|
||||
} else {
|
||||
//TODO: Error Handling
|
||||
throw new VolumeException("No free drive letter available.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkProvidedMountPoint(Path mountPoint) throws IOException {
|
||||
if (!Files.isDirectory(mountPoint)) {
|
||||
throw new NotDirectoryException(mountPoint.toString());
|
||||
}
|
||||
try (DirectoryStream<Path> ds = Files.newDirectoryStream(mountPoint)) {
|
||||
if (ds.iterator().hasNext()) {
|
||||
throw new DirectoryNotEmptyException(mountPoint.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reveal() throws VolumeException {
|
||||
boolean success = mount.reveal();
|
||||
if (!success) {
|
||||
throw new VolumeException("Reveal failed.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unmount() {
|
||||
mount.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Path> getMountPoint() {
|
||||
return Optional.ofNullable(mountPoint);
|
||||
}
|
||||
|
||||
public static boolean isSupportedStatic() {
|
||||
return MountFactory.isApplicable();
|
||||
}
|
||||
}
|
||||
@@ -1,177 +0,0 @@
|
||||
package org.cryptomator.common.vaults;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.cryptomator.common.settings.VaultSettings;
|
||||
import org.cryptomator.cryptofs.CryptoFileSystem;
|
||||
import org.cryptomator.frontend.fuse.mount.CommandFailedException;
|
||||
import org.cryptomator.frontend.fuse.mount.EnvironmentVariables;
|
||||
import org.cryptomator.frontend.fuse.mount.FuseMountFactory;
|
||||
import org.cryptomator.frontend.fuse.mount.FuseNotSupportedException;
|
||||
import org.cryptomator.frontend.fuse.mount.Mount;
|
||||
import org.cryptomator.frontend.fuse.mount.Mounter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.DirectoryNotEmptyException;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NotDirectoryException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Optional;
|
||||
|
||||
public class FuseVolume implements Volume {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(FuseVolume.class);
|
||||
private static final int MAX_TMPMOUNTPOINT_CREATION_RETRIES = 10;
|
||||
private static final boolean IS_MAC = System.getProperty("os.name").toLowerCase().contains("mac");
|
||||
|
||||
private final VaultSettings vaultSettings;
|
||||
private final Environment environment;
|
||||
|
||||
private Mount fuseMnt;
|
||||
private Path mountPoint;
|
||||
private boolean createdTemporaryMountPoint;
|
||||
|
||||
@Inject
|
||||
public FuseVolume(VaultSettings vaultSettings, Environment environment) {
|
||||
this.vaultSettings = vaultSettings;
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mount(CryptoFileSystem fs, String mountFlags) throws IOException, FuseNotSupportedException, VolumeException {
|
||||
Optional<String> optionalCustomMountPoint = vaultSettings.getIndividualMountPath();
|
||||
if (optionalCustomMountPoint.isPresent()) {
|
||||
Path customMountPoint = Paths.get(optionalCustomMountPoint.get());
|
||||
checkProvidedMountPoint(customMountPoint);
|
||||
this.mountPoint = customMountPoint;
|
||||
LOG.debug("Successfully checked custom mount point: {}", mountPoint);
|
||||
} else {
|
||||
this.mountPoint = prepareTemporaryMountPoint();
|
||||
LOG.debug("Successfully created mount point: {}", mountPoint);
|
||||
}
|
||||
mount(fs.getPath("/"), mountFlags);
|
||||
}
|
||||
|
||||
private void checkProvidedMountPoint(Path mountPoint) throws IOException {
|
||||
if (!Files.isDirectory(mountPoint)) {
|
||||
throw new NotDirectoryException(mountPoint.toString());
|
||||
}
|
||||
try (DirectoryStream<Path> ds = Files.newDirectoryStream(mountPoint)) {
|
||||
if (ds.iterator().hasNext()) {
|
||||
throw new DirectoryNotEmptyException(mountPoint.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Path prepareTemporaryMountPoint() throws IOException, VolumeException {
|
||||
Path mountPoint = chooseNonExistingTemporaryMountPoint();
|
||||
// https://github.com/osxfuse/osxfuse/issues/306#issuecomment-245114592:
|
||||
// In order to allow non-admin users to mount FUSE volumes in `/Volumes`,
|
||||
// starting with version 3.5.0, FUSE will create non-existent mount points automatically.
|
||||
if (IS_MAC && mountPoint.getParent().equals(Paths.get("/Volumes"))) {
|
||||
return mountPoint;
|
||||
} else {
|
||||
Files.createDirectories(mountPoint);
|
||||
this.createdTemporaryMountPoint = true;
|
||||
return mountPoint;
|
||||
}
|
||||
}
|
||||
|
||||
private Path chooseNonExistingTemporaryMountPoint() throws VolumeException {
|
||||
Path parent = environment.getMountPointsDir().orElseThrow();
|
||||
String basename = vaultSettings.getId();
|
||||
for (int i = 0; i < MAX_TMPMOUNTPOINT_CREATION_RETRIES; i++) {
|
||||
Path mountPoint = parent.resolve(basename + "_" + i);
|
||||
if (Files.notExists(mountPoint)) {
|
||||
return mountPoint;
|
||||
}
|
||||
}
|
||||
LOG.error("Failed to find feasible mountpoint at {}/{}_x. Giving up after {} attempts.", parent, basename, MAX_TMPMOUNTPOINT_CREATION_RETRIES);
|
||||
throw new VolumeException("Did not find feasible mount point.");
|
||||
}
|
||||
|
||||
private void mount(Path root, String mountFlags) throws VolumeException {
|
||||
try {
|
||||
Mounter mounter = FuseMountFactory.getMounter();
|
||||
EnvironmentVariables envVars = EnvironmentVariables.create() //
|
||||
.withFlags(splitFlags(mountFlags)).withMountPoint(mountPoint) //
|
||||
.build();
|
||||
this.fuseMnt = mounter.mount(root, envVars);
|
||||
} catch (CommandFailedException e) {
|
||||
throw new VolumeException("Unable to mount Filesystem", e);
|
||||
}
|
||||
}
|
||||
|
||||
private String[] splitFlags(String str) {
|
||||
return Splitter.on(' ').splitToList(str).toArray(String[]::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reveal() throws VolumeException {
|
||||
try {
|
||||
fuseMnt.revealInFileManager();
|
||||
} catch (CommandFailedException e) {
|
||||
LOG.debug("Revealing the vault in file manger failed: " + e.getMessage());
|
||||
throw new VolumeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsForcedUnmount() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void unmountForced() throws VolumeException {
|
||||
try {
|
||||
fuseMnt.unmountForced();
|
||||
fuseMnt.close();
|
||||
} catch (CommandFailedException e) {
|
||||
throw new VolumeException(e);
|
||||
}
|
||||
cleanupTemporaryMountPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void unmount() throws VolumeException {
|
||||
try {
|
||||
fuseMnt.unmount();
|
||||
fuseMnt.close();
|
||||
} catch (CommandFailedException e) {
|
||||
throw new VolumeException(e);
|
||||
}
|
||||
cleanupTemporaryMountPoint();
|
||||
}
|
||||
|
||||
private void cleanupTemporaryMountPoint() {
|
||||
if (createdTemporaryMountPoint) {
|
||||
try {
|
||||
Files.delete(mountPoint);
|
||||
LOG.debug("Successfully deleted mount point: {}", mountPoint);
|
||||
} catch (IOException e) {
|
||||
LOG.warn("Could not delete mount point: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
return FuseVolume.isSupportedStatic();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Path> getMountPoint() {
|
||||
return Optional.ofNullable(mountPoint);
|
||||
}
|
||||
|
||||
public static boolean isSupportedStatic() {
|
||||
return (SystemUtils.IS_OS_MAC_OSX || SystemUtils.IS_OS_LINUX) && FuseMountFactory.isFuseSupported();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2017 Sebastian Stenzel and others.
|
||||
* All rights reserved.
|
||||
* This program and the accompanying materials are made available under the terms of the accompanying LICENSE file.
|
||||
*
|
||||
* Contributors:
|
||||
* Sebastian Stenzel - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.common.vaults;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.common.settings.VaultSettings;
|
||||
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
|
||||
import org.cryptomator.cryptofs.migration.Migrators;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
|
||||
|
||||
@Singleton
|
||||
public class VaultListManager {
|
||||
|
||||
private final VaultComponent.Builder vaultComponentBuilder;
|
||||
private final ObservableList<Vault> vaultList;
|
||||
|
||||
@Inject
|
||||
public VaultListManager(VaultComponent.Builder vaultComponentBuilder, Settings settings) {
|
||||
this.vaultComponentBuilder = vaultComponentBuilder;
|
||||
this.vaultList = FXCollections.observableArrayList(Vault::observables);
|
||||
|
||||
addAll(settings.getDirectories());
|
||||
vaultList.addListener(new VaultListChangeListener(settings.getDirectories()));
|
||||
}
|
||||
|
||||
public ObservableList<Vault> getVaultList() {
|
||||
return vaultList;
|
||||
}
|
||||
|
||||
public Vault add(Path pathToVault) throws NoSuchFileException {
|
||||
if (!CryptoFileSystemProvider.containsVault(pathToVault, MASTERKEY_FILENAME)) {
|
||||
throw new NoSuchFileException(pathToVault.toString(), null, "Not a vault directory");
|
||||
}
|
||||
Optional<Vault> alreadyExistingVault = get(pathToVault);
|
||||
if (alreadyExistingVault.isPresent()) {
|
||||
return alreadyExistingVault.get();
|
||||
} else {
|
||||
VaultSettings vaultSettings = VaultSettings.withRandomId();
|
||||
vaultSettings.path().set(pathToVault);
|
||||
Vault newVault = create(vaultSettings);
|
||||
vaultList.add(newVault);
|
||||
return newVault;
|
||||
}
|
||||
}
|
||||
|
||||
private void addAll(Collection<VaultSettings> vaultSettings) {
|
||||
Collection<Vault> vaults = vaultSettings.stream().map(this::create).collect(Collectors.toList());
|
||||
vaultList.addAll(vaults);
|
||||
}
|
||||
|
||||
private Optional<Vault> get(Path vaultPath) {
|
||||
return vaultList.stream().filter(v -> {
|
||||
try {
|
||||
return Files.isSameFile(vaultPath, v.getPath());
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}).findAny();
|
||||
}
|
||||
|
||||
private Vault create(VaultSettings vaultSettings) {
|
||||
VaultState vaultState = determineVaultState(vaultSettings.path().get());
|
||||
VaultComponent comp = vaultComponentBuilder.vaultSettings(vaultSettings).initialVaultState(vaultState).build();
|
||||
return comp.vault();
|
||||
}
|
||||
|
||||
public static VaultState determineVaultState(Path pathToVault) {
|
||||
try {
|
||||
if (!CryptoFileSystemProvider.containsVault(pathToVault, MASTERKEY_FILENAME)) {
|
||||
return VaultState.MISSING;
|
||||
} else if (Migrators.get().needsMigration(pathToVault, MASTERKEY_FILENAME)) {
|
||||
return VaultState.NEEDS_MIGRATION;
|
||||
} else {
|
||||
return VaultState.LOCKED;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
return VaultState.ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package org.cryptomator.common.vaults;
|
||||
|
||||
public enum VaultState {
|
||||
/**
|
||||
* No vault found at the provided path
|
||||
*/
|
||||
MISSING,
|
||||
|
||||
/**
|
||||
* Vault requires migration to a newer vault format
|
||||
*/
|
||||
NEEDS_MIGRATION,
|
||||
|
||||
/**
|
||||
* Vault ready to be unlocked
|
||||
*/
|
||||
LOCKED,
|
||||
|
||||
/**
|
||||
* Vault in transition between two other states
|
||||
*/
|
||||
PROCESSING,
|
||||
|
||||
/**
|
||||
* Vault is unlocked
|
||||
*/
|
||||
UNLOCKED,
|
||||
|
||||
/**
|
||||
* Unknown state due to preceeding unrecoverable exceptions.
|
||||
*/
|
||||
ERROR;
|
||||
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
package org.cryptomator.common.vaults;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.property.LongProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleLongProperty;
|
||||
import javafx.concurrent.ScheduledService;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.util.Duration;
|
||||
import org.cryptomator.cryptofs.CryptoFileSystem;
|
||||
import org.cryptomator.cryptofs.CryptoFileSystemStats;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@PerVault
|
||||
public class VaultStats {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(VaultStats.class);
|
||||
|
||||
private final AtomicReference<CryptoFileSystem> fs;
|
||||
private final ObjectProperty<VaultState> state;
|
||||
private final ScheduledService<Optional<CryptoFileSystemStats>> updateService;
|
||||
private final LongProperty bytesPerSecondRead = new SimpleLongProperty();
|
||||
private final LongProperty bytesPerSecondWritten = new SimpleLongProperty();
|
||||
|
||||
@Inject
|
||||
VaultStats(AtomicReference<CryptoFileSystem> fs, ObjectProperty<VaultState> state, ExecutorService executor) {
|
||||
this.fs = fs;
|
||||
this.state = state;
|
||||
this.updateService = new UpdateStatsService();
|
||||
updateService.setExecutor(executor);
|
||||
updateService.setPeriod(Duration.seconds(1));
|
||||
|
||||
state.addListener(this::vaultStateChanged);
|
||||
}
|
||||
|
||||
private void vaultStateChanged(@SuppressWarnings("unused") Observable observable) {
|
||||
switch (state.get()) {
|
||||
case UNLOCKED:
|
||||
assert fs.get() != null;
|
||||
LOG.debug("start recording stats");
|
||||
updateService.restart();
|
||||
break;
|
||||
default:
|
||||
LOG.debug("stop recording stats");
|
||||
updateService.cancel();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateStats(Optional<CryptoFileSystemStats> stats) {
|
||||
assert Platform.isFxApplicationThread();
|
||||
bytesPerSecondRead.set(stats.map(CryptoFileSystemStats::pollBytesRead).orElse(0l));
|
||||
bytesPerSecondWritten.set(stats.map(CryptoFileSystemStats::pollBytesWritten).orElse(0l));
|
||||
}
|
||||
|
||||
private class UpdateStatsService extends ScheduledService<Optional<CryptoFileSystemStats>> {
|
||||
|
||||
@Override
|
||||
protected Task<Optional<CryptoFileSystemStats>> createTask() {
|
||||
return new Task<>() {
|
||||
@Override
|
||||
protected Optional<CryptoFileSystemStats> call() {
|
||||
return Optional.ofNullable(fs.get()).map(CryptoFileSystem::getStats);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void succeeded() {
|
||||
assert getValue() != null;
|
||||
updateStats(getValue());
|
||||
super.succeeded();
|
||||
}
|
||||
}
|
||||
|
||||
/* Observables */
|
||||
|
||||
public LongProperty bytesPerSecondReadProperty() {
|
||||
return bytesPerSecondRead;
|
||||
}
|
||||
|
||||
public long getBytesPerSecondRead() {
|
||||
return bytesPerSecondRead.get();
|
||||
}
|
||||
|
||||
public LongProperty bytesPerSecondWrittenProperty() {
|
||||
return bytesPerSecondWritten;
|
||||
}
|
||||
|
||||
public long getBytesPerSecondWritten() {
|
||||
return bytesPerSecondWritten.get();
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
package org.cryptomator.common.vaults;
|
||||
|
||||
import org.cryptomator.common.settings.VolumeImpl;
|
||||
import org.cryptomator.cryptofs.CryptoFileSystem;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Takes a Volume and usess it to mount an unlocked vault
|
||||
*/
|
||||
public interface Volume {
|
||||
|
||||
/**
|
||||
* Checks in constant time whether this volume type is supported on the system running Cryptomator.
|
||||
*
|
||||
* @return true if this volume can be mounted
|
||||
*/
|
||||
boolean isSupported();
|
||||
|
||||
/**
|
||||
* @param fs
|
||||
* @throws IOException
|
||||
*/
|
||||
void mount(CryptoFileSystem fs, String mountFlags) throws IOException, VolumeException;
|
||||
|
||||
void reveal() throws VolumeException;
|
||||
|
||||
void unmount() throws VolumeException;
|
||||
|
||||
Optional<Path> getMountPoint();
|
||||
|
||||
// optional forced unmounting:
|
||||
|
||||
default boolean supportsForcedUnmount() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default void unmountForced() throws VolumeException {
|
||||
throw new VolumeException("Operation not supported.");
|
||||
}
|
||||
|
||||
static VolumeImpl[] getCurrentSupportedAdapters() {
|
||||
return Stream.of(VolumeImpl.values()).filter(impl -> {
|
||||
switch (impl) {
|
||||
case WEBDAV:
|
||||
return WebDavVolume.isSupportedStatic();
|
||||
case DOKANY:
|
||||
return DokanyVolume.isSupportedStatic();
|
||||
case FUSE:
|
||||
return FuseVolume.isSupportedStatic();
|
||||
default:
|
||||
return false;//throw new IllegalStateException("Adapter not implemented.");
|
||||
}
|
||||
}).toArray(VolumeImpl[]::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception thrown when a volume-specific command such as mount/unmount/reveal failed.
|
||||
*/
|
||||
class VolumeException extends Exception {
|
||||
|
||||
public VolumeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public VolumeException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public VolumeException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,63 +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.JsonWriter;
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.hamcrest.MatcherAssert;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class VaultSettingsJsonAdapterTest {
|
||||
|
||||
private final VaultSettingsJsonAdapter adapter = new VaultSettingsJsonAdapter();
|
||||
|
||||
@Test
|
||||
public void testDeserialize() throws IOException {
|
||||
String json = "{\"id\": \"foo\", \"path\": \"/foo/bar\", \"mountName\": \"test\", \"winDriveLetter\": \"X\", \"shouldBeIgnored\": true, \"individualMountPath\": \"/home/test/crypto\", \"mountFlags\":\"--foo --bar\"}";
|
||||
JsonReader jsonReader = new JsonReader(new StringReader(json));
|
||||
|
||||
VaultSettings vaultSettings = adapter.read(jsonReader);
|
||||
Assertions.assertEquals("foo", vaultSettings.getId());
|
||||
Assertions.assertEquals(Paths.get("/foo/bar"), vaultSettings.path().get());
|
||||
Assertions.assertEquals("test", vaultSettings.mountName().get());
|
||||
Assertions.assertEquals("X", vaultSettings.winDriveLetter().get());
|
||||
Assertions.assertEquals("/home/test/crypto", vaultSettings.individualMountPath().get());
|
||||
Assertions.assertEquals("--foo --bar", vaultSettings.mountFlags().get());
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerialize() throws IOException {
|
||||
VaultSettings vaultSettings = new VaultSettings("test");
|
||||
vaultSettings.path().set(Paths.get("/foo/bar"));
|
||||
vaultSettings.mountName().set("mountyMcMountFace");
|
||||
vaultSettings.mountFlags().set("--foo --bar");
|
||||
|
||||
StringWriter buf = new StringWriter();
|
||||
JsonWriter jsonWriter = new JsonWriter(buf);
|
||||
adapter.write(jsonWriter, vaultSettings);
|
||||
String result = buf.toString();
|
||||
|
||||
MatcherAssert.assertThat(result, CoreMatchers.containsString("\"id\":\"test\""));
|
||||
if(System.getProperty("os.name").contains("Windows")){
|
||||
MatcherAssert.assertThat(result, CoreMatchers.containsString("\"path\":\"\\\\foo\\\\bar\""));
|
||||
} else {
|
||||
MatcherAssert.assertThat(result, CoreMatchers.containsString("\"path\":\"/foo/bar\""));
|
||||
}
|
||||
MatcherAssert.assertThat(result, CoreMatchers.containsString("\"mountName\":\"mountyMcMountFace\""));
|
||||
MatcherAssert.assertThat(result, CoreMatchers.containsString("\"mountFlags\":\"--foo --bar\""));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>main</artifactId>
|
||||
<version>1.5.0</version>
|
||||
</parent>
|
||||
<artifactId>keychain</artifactId>
|
||||
<name>System Keychain Access</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>commons</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Google -->
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- DI -->
|
||||
<dependency>
|
||||
<groupId>com.google.dagger</groupId>
|
||||
<artifactId>dagger</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- secret-service lib -->
|
||||
<dependency>
|
||||
<groupId>de.swiesend</groupId>
|
||||
<artifactId>secret-service</artifactId>
|
||||
<version>1.0.0-RC.3</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Logging -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,31 +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.keychain;
|
||||
|
||||
public interface KeychainAccess {
|
||||
|
||||
/**
|
||||
* Associates a passphrase with a given key.
|
||||
*
|
||||
* @param key Key used to retrieve the passphrase via {@link #loadPassphrase(String)}.
|
||||
* @param passphrase The secret to store in this keychain.
|
||||
*/
|
||||
void storePassphrase(String key, CharSequence passphrase) throws KeychainAccessException;
|
||||
|
||||
/**
|
||||
* @param key Unique key previously used while {@link #storePassphrase(String, CharSequence) storing a passphrase}.
|
||||
* @return The stored passphrase for the given key or <code>null</code> if no value for the given key could be found.
|
||||
*/
|
||||
char[] loadPassphrase(String key) throws KeychainAccessException;
|
||||
|
||||
/**
|
||||
* Deletes a passphrase with a given key.
|
||||
*
|
||||
* @param key Unique key previously used while {@link #storePassphrase(String, CharSequence) storing a passphrase}.
|
||||
*/
|
||||
void deletePassphrase(String key) throws KeychainAccessException;
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package org.cryptomator.keychain;
|
||||
|
||||
/**
|
||||
* Indicates an error during communication with the operating system's keychain.
|
||||
*/
|
||||
public class KeychainAccessException extends Exception {
|
||||
|
||||
KeychainAccessException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,17 +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.keychain;
|
||||
|
||||
interface KeychainAccessStrategy extends KeychainAccess {
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if this KeychainAccessStrategy works on the current machine.
|
||||
* @implNote This method must not throw any exceptions and should fail fast
|
||||
* returning <code>false</code> if it can't determine availability of the checked strategy
|
||||
*/
|
||||
boolean isSupported();
|
||||
|
||||
}
|
||||
@@ -1,33 +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.keychain;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.ElementsIntoSet;
|
||||
import org.cryptomator.common.JniModule;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
@Module(includes = {JniModule.class})
|
||||
public class KeychainModule {
|
||||
|
||||
@Provides
|
||||
@ElementsIntoSet
|
||||
Set<KeychainAccessStrategy> provideKeychainAccessStrategies(MacSystemKeychainAccess macKeychain, WindowsProtectedKeychainAccess winKeychain, LinuxSecretServiceKeychainAccess linKeychain) {
|
||||
return Sets.newHashSet(macKeychain, winKeychain, linKeychain);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public Optional<KeychainAccess> provideSupportedKeychain(Set<KeychainAccessStrategy> keychainAccessStrategies) {
|
||||
return keychainAccessStrategies.stream().filter(KeychainAccessStrategy::isSupported).map(KeychainAccess.class::cast).findFirst();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
package org.cryptomator.keychain;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* A facade to LinuxSecretServiceKeychainAccessImpl that doesn't depend on libraries that are unavailable on Mac and Windows.
|
||||
*/
|
||||
public class LinuxSecretServiceKeychainAccess implements KeychainAccessStrategy {
|
||||
|
||||
// the actual implementation is hidden in this delegate object which is loaded via reflection,
|
||||
// as it depends on libraries that aren't necessarily available:
|
||||
private final Optional<KeychainAccessStrategy> delegate;
|
||||
|
||||
@Inject
|
||||
public LinuxSecretServiceKeychainAccess() {
|
||||
this.delegate = constructGnomeKeyringKeychainAccess();
|
||||
}
|
||||
|
||||
private static Optional<KeychainAccessStrategy> constructGnomeKeyringKeychainAccess() {
|
||||
try {
|
||||
Class<?> clazz = Class.forName("org.cryptomator.keychain.LinuxSecretServiceKeychainAccessImpl");
|
||||
KeychainAccessStrategy instance = (KeychainAccessStrategy) clazz.getDeclaredConstructor().newInstance();
|
||||
return Optional.of(instance);
|
||||
} catch (Exception e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
return SystemUtils.IS_OS_LINUX && delegate.map(KeychainAccessStrategy::isSupported).orElse(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storePassphrase(String key, CharSequence passphrase) throws KeychainAccessException {
|
||||
delegate.orElseThrow(IllegalStateException::new).storePassphrase(key, passphrase);
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] loadPassphrase(String key) throws KeychainAccessException {
|
||||
return delegate.orElseThrow(IllegalStateException::new).loadPassphrase(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deletePassphrase(String key) throws KeychainAccessException {
|
||||
delegate.orElseThrow(IllegalStateException::new).deletePassphrase(key);
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package org.cryptomator.keychain;
|
||||
|
||||
import org.freedesktop.secret.simple.SimpleCollection;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
class LinuxSecretServiceKeychainAccessImpl implements KeychainAccessStrategy {
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
try (@SuppressWarnings("unused") SimpleCollection keyring = new SimpleCollection()) {
|
||||
// seems like we're able to access the keyring.
|
||||
return true;
|
||||
} catch (IOException | RuntimeException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storePassphrase(String key, CharSequence passphrase) throws KeychainAccessException {
|
||||
try (SimpleCollection keyring = new SimpleCollection()) {
|
||||
List<String> list = keyring.getItems(createAttributes(key));
|
||||
if (list == null) {
|
||||
keyring.createItem("Cryptomator", passphrase, createAttributes(key));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new KeychainAccessException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] loadPassphrase(String key) throws KeychainAccessException {
|
||||
try (SimpleCollection keyring = new SimpleCollection()) {
|
||||
List<String> list = keyring.getItems(createAttributes(key));
|
||||
if (list != null) {
|
||||
return keyring.getSecret(list.get(0));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new KeychainAccessException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deletePassphrase(String key) throws KeychainAccessException {
|
||||
try (SimpleCollection keyring = new SimpleCollection()) {
|
||||
List<String> list = keyring.getItems(createAttributes(key));
|
||||
if (list != null) {
|
||||
keyring.deleteItem(list.get(0));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new KeychainAccessException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String> createAttributes(String key) {
|
||||
Map<String, String> attributes = new HashMap();
|
||||
attributes.put("Vault", key);
|
||||
return attributes;
|
||||
}
|
||||
}
|
||||
@@ -1,49 +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.keychain;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.jni.MacFunctions;
|
||||
import org.cryptomator.jni.MacKeychainAccess;
|
||||
|
||||
class MacSystemKeychainAccess implements KeychainAccessStrategy {
|
||||
|
||||
private final Optional<MacFunctions> macFunctions;
|
||||
|
||||
@Inject
|
||||
public MacSystemKeychainAccess(Optional<MacFunctions> macFunctions) {
|
||||
this.macFunctions = macFunctions;
|
||||
}
|
||||
|
||||
private MacKeychainAccess keychain() {
|
||||
return macFunctions.orElseThrow(IllegalStateException::new).keychainAccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storePassphrase(String key, CharSequence passphrase) {
|
||||
keychain().storePassword(key, passphrase);
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] loadPassphrase(String key) {
|
||||
return keychain().loadPassword(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
return SystemUtils.IS_OS_MAC_OSX && macFunctions.isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deletePassphrase(String key) {
|
||||
keychain().deletePassword(key);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,199 +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.keychain;
|
||||
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.cryptomator.jni.WinDataProtection;
|
||||
import org.cryptomator.jni.WinFunctions;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
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.UncheckedIOException;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
class WindowsProtectedKeychainAccess implements KeychainAccessStrategy {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(WindowsProtectedKeychainAccess.class);
|
||||
private static final Gson GSON = new GsonBuilder().setPrettyPrinting() //
|
||||
.registerTypeHierarchyAdapter(byte[].class, new ByteArrayJsonAdapter()) //
|
||||
.disableHtmlEscaping().create();
|
||||
|
||||
private final Optional<WinFunctions> winFunctions;
|
||||
private final List<Path> keychainPaths;
|
||||
private Map<String, KeychainEntry> keychainEntries;
|
||||
|
||||
@Inject
|
||||
public WindowsProtectedKeychainAccess(Optional<WinFunctions> winFunctions, Environment environment) {
|
||||
this.winFunctions = winFunctions;
|
||||
this.keychainPaths = environment.getKeychainPath().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private WinDataProtection dataProtection() {
|
||||
return winFunctions.orElseThrow(IllegalStateException::new).dataProtection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storePassphrase(String key, CharSequence passphrase) {
|
||||
loadKeychainEntriesIfNeeded();
|
||||
ByteBuffer buf = UTF_8.encode(CharBuffer.wrap(passphrase));
|
||||
byte[] cleartext = new byte[buf.remaining()];
|
||||
buf.get(cleartext);
|
||||
KeychainEntry entry = new KeychainEntry();
|
||||
entry.salt = generateSalt();
|
||||
entry.ciphertext = dataProtection().protect(cleartext, entry.salt);
|
||||
Arrays.fill(buf.array(), (byte) 0x00);
|
||||
Arrays.fill(cleartext, (byte) 0x00);
|
||||
keychainEntries.put(key, entry);
|
||||
saveKeychainEntries();
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] loadPassphrase(String key) {
|
||||
loadKeychainEntriesIfNeeded();
|
||||
KeychainEntry entry = keychainEntries.get(key);
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
byte[] cleartext = dataProtection().unprotect(entry.ciphertext, entry.salt);
|
||||
if (cleartext == null) {
|
||||
return null;
|
||||
}
|
||||
CharBuffer buf = UTF_8.decode(ByteBuffer.wrap(cleartext));
|
||||
char[] passphrase = new char[buf.remaining()];
|
||||
buf.get(passphrase);
|
||||
Arrays.fill(cleartext, (byte) 0x00);
|
||||
Arrays.fill(buf.array(), (char) 0x00);
|
||||
return passphrase;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deletePassphrase(String key) {
|
||||
loadKeychainEntriesIfNeeded();
|
||||
keychainEntries.remove(key);
|
||||
saveKeychainEntries();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
return SystemUtils.IS_OS_WINDOWS && winFunctions.isPresent() && !keychainPaths.isEmpty();
|
||||
}
|
||||
|
||||
private byte[] generateSalt() {
|
||||
byte[] result = new byte[2 * Long.BYTES];
|
||||
UUID uuid = UUID.randomUUID();
|
||||
ByteBuffer buf = ByteBuffer.wrap(result);
|
||||
buf.putLong(uuid.getMostSignificantBits());
|
||||
buf.putLong(uuid.getLeastSignificantBits());
|
||||
return result;
|
||||
}
|
||||
|
||||
private void loadKeychainEntriesIfNeeded() {
|
||||
if (keychainEntries == null) {
|
||||
for (Path keychainPath : keychainPaths) {
|
||||
Optional<Map<String, KeychainEntry>> keychain = loadKeychainEntries(keychainPath);
|
||||
if (keychain.isPresent()) {
|
||||
keychainEntries = keychain.get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (keychainEntries == null) {
|
||||
LOG.info("Unable to load existing keychain file, creating new keychain.");
|
||||
keychainEntries = new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<Map<String, KeychainEntry>> loadKeychainEntries(Path keychainPath) {
|
||||
LOG.debug("Attempting to load keychain from {}", keychainPath);
|
||||
Type type = new TypeToken<Map<String, KeychainEntry>>() {
|
||||
}.getType();
|
||||
try (InputStream in = Files.newInputStream(keychainPath, StandardOpenOption.READ); //
|
||||
Reader reader = new InputStreamReader(in, UTF_8)) {
|
||||
return Optional.of(GSON.fromJson(reader, type));
|
||||
} catch (NoSuchFileException | JsonParseException e) {
|
||||
return Optional.empty();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Could not read keychain from path " + keychainPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveKeychainEntries() {
|
||||
if (keychainPaths.isEmpty()) {
|
||||
throw new IllegalStateException("Can't save keychain if no keychain path is specified.");
|
||||
}
|
||||
saveKeychainEntries(keychainPaths.get(0));
|
||||
}
|
||||
|
||||
private void saveKeychainEntries(Path keychainPath) {
|
||||
try (OutputStream out = Files.newOutputStream(keychainPath, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); //
|
||||
Writer writer = new OutputStreamWriter(out, UTF_8)) {
|
||||
GSON.toJson(keychainEntries, writer);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Could not read keychain from path " + keychainPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static class KeychainEntry {
|
||||
|
||||
@SerializedName("ciphertext")
|
||||
byte[] ciphertext;
|
||||
@SerializedName("salt")
|
||||
byte[] salt;
|
||||
}
|
||||
|
||||
private static class ByteArrayJsonAdapter implements JsonSerializer<byte[]>, JsonDeserializer<byte[]> {
|
||||
|
||||
private static final BaseEncoding BASE64 = BaseEncoding.base64();
|
||||
|
||||
@Override
|
||||
public byte[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
return BASE64.decode(json.getAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(byte[] src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(BASE64.encode(src));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +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.keychain;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class KeychainModuleTest {
|
||||
|
||||
@Test
|
||||
public void testGetKeychain() throws KeychainAccessException {
|
||||
Optional<KeychainAccess> keychainAccess = DaggerTestKeychainComponent.builder().keychainModule(new TestKeychainModule()).build().keychainAccess();
|
||||
Assertions.assertTrue(keychainAccess.isPresent());
|
||||
Assertions.assertTrue(keychainAccess.get() instanceof MapKeychainAccess);
|
||||
keychainAccess.get().storePassphrase("test", "asd");
|
||||
Assertions.assertArrayEquals("asd".toCharArray(), keychainAccess.get().loadPassphrase("test"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,19 +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.keychain;
|
||||
|
||||
import dagger.Component;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
import java.util.Optional;
|
||||
|
||||
@Singleton
|
||||
@Component(modules = KeychainModule.class)
|
||||
interface TestKeychainComponent {
|
||||
|
||||
Optional<KeychainAccess> keychainAccess();
|
||||
|
||||
}
|
||||
@@ -1,17 +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.keychain;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class TestKeychainModule extends KeychainModule {
|
||||
|
||||
@Override
|
||||
Set<KeychainAccessStrategy> provideKeychainAccessStrategies(MacSystemKeychainAccess macKeychain, WindowsProtectedKeychainAccess winKeychain, LinuxSecretServiceKeychainAccess linKeychain) {
|
||||
return Set.of(new MapKeychainAccess());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,56 +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.keychain;
|
||||
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.cryptomator.jni.WinDataProtection;
|
||||
import org.cryptomator.jni.WinFunctions;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class WindowsProtectedKeychainAccessTest {
|
||||
|
||||
private WindowsProtectedKeychainAccess keychain;
|
||||
|
||||
@BeforeEach
|
||||
public void setup(@TempDir Path tempDir) {
|
||||
Path keychainPath = tempDir.resolve("keychainfile.tmp");
|
||||
Environment env = Mockito.mock(Environment.class);
|
||||
Mockito.when(env.getKeychainPath()).thenReturn(Stream.of(keychainPath));
|
||||
WinFunctions winFunctions = Mockito.mock(WinFunctions.class);
|
||||
WinDataProtection winDataProtection = Mockito.mock(WinDataProtection.class);
|
||||
Mockito.when(winFunctions.dataProtection()).thenReturn(winDataProtection);
|
||||
Answer<byte[]> answerReturningFirstArg = invocation -> ((byte[]) invocation.getArgument(0)).clone();
|
||||
Mockito.when(winDataProtection.protect(Mockito.any(), Mockito.any())).thenAnswer(answerReturningFirstArg);
|
||||
Mockito.when(winDataProtection.unprotect(Mockito.any(), Mockito.any())).thenAnswer(answerReturningFirstArg);
|
||||
keychain = new WindowsProtectedKeychainAccess(Optional.of(winFunctions), env);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStoreAndLoad() {
|
||||
String storedPw1 = "topSecret";
|
||||
String storedPw2 = "bottomSecret";
|
||||
keychain.storePassphrase("myPassword", storedPw1);
|
||||
keychain.storePassphrase("myOtherPassword", storedPw2);
|
||||
String loadedPw1 = new String(keychain.loadPassphrase("myPassword"));
|
||||
String loadedPw2 = new String(keychain.loadPassphrase("myOtherPassword"));
|
||||
Assertions.assertEquals(storedPw1, loadedPw1);
|
||||
Assertions.assertEquals(storedPw2, loadedPw2);
|
||||
keychain.deletePassphrase("myPassword");
|
||||
Assertions.assertNull(keychain.loadPassphrase("myPassword"));
|
||||
Assertions.assertNotNull(keychain.loadPassphrase("myOtherPassword"));
|
||||
Assertions.assertNull(keychain.loadPassphrase("nonExistingPassword"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!--
|
||||
Copyright (c) 2014 Markus Kreusch
|
||||
This file is licensed under the terms of the MIT license.
|
||||
See the LICENSE.txt file for more info.
|
||||
|
||||
Contributors:
|
||||
Sebastian Stenzel - log4j config for WebDAV unit tests
|
||||
-->
|
||||
<Configuration status="WARN">
|
||||
|
||||
<Appenders>
|
||||
<Console name="Console" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="%16d %-5p [%c{1}:%L] %m%n" />
|
||||
<ThresholdFilter level="WARN" onMatch="DENY" onMismatch="ACCEPT" />
|
||||
</Console>
|
||||
<Console name="StdErr" target="SYSTEM_ERR">
|
||||
<PatternLayout pattern="%16d %-5p [%c{1}:%L] %m%n" />
|
||||
<ThresholdFilter level="WARN" onMatch="ACCEPT" onMismatch="DENY" />
|
||||
</Console>
|
||||
</Appenders>
|
||||
|
||||
<Loggers>
|
||||
<!-- show our own debug messages: -->
|
||||
<Logger name="org.cryptomator" level="DEBUG" />
|
||||
<!-- mute dependencies: -->
|
||||
<Root level="INFO">
|
||||
<AppenderRef ref="Console" />
|
||||
<AppenderRef ref="StdErr" />
|
||||
</Root>
|
||||
</Loggers>
|
||||
|
||||
</Configuration>
|
||||
@@ -1,48 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>main</artifactId>
|
||||
<version>1.5.0</version>
|
||||
</parent>
|
||||
<artifactId>launcher</artifactId>
|
||||
<name>Cryptomator Launcher</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>commons</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>ui</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Libs -->
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- DI -->
|
||||
<dependency>
|
||||
<groupId>com.google.dagger</groupId>
|
||||
<artifactId>dagger</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Logging -->
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
352
main/pom.xml
352
main/pom.xml
@@ -1,352 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>main</artifactId>
|
||||
<version>1.5.0</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Cryptomator</name>
|
||||
|
||||
<organization>
|
||||
<name>cryptomator.org</name>
|
||||
<url>https://cryptomator.org</url>
|
||||
</organization>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<name>Sebastian Stenzel</name>
|
||||
<email>sebastian.stenzel@gmail.com</email>
|
||||
<timezone>+1</timezone>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
<!-- cryptomator dependencies -->
|
||||
<cryptomator.cryptofs.version>1.9.3</cryptomator.cryptofs.version>
|
||||
<cryptomator.jni.version>2.2.2</cryptomator.jni.version>
|
||||
<cryptomator.fuse.version>1.2.3</cryptomator.fuse.version>
|
||||
<cryptomator.dokany.version>1.1.13</cryptomator.dokany.version>
|
||||
<cryptomator.webdav.version>1.0.10</cryptomator.webdav.version>
|
||||
|
||||
<!-- 3rd party dependencies -->
|
||||
<javafx.version>14</javafx.version>
|
||||
<commons-lang3.version>3.9</commons-lang3.version>
|
||||
<jwt.version>3.10.0</jwt.version>
|
||||
<easybind.version>1.0.3</easybind.version>
|
||||
<guava.version>28.1-jre</guava.version>
|
||||
<dagger.version>2.26</dagger.version>
|
||||
<gson.version>2.8.6</gson.version>
|
||||
<slf4j.version>1.7.30</slf4j.version>
|
||||
<logback.version>1.2.3</logback.version>
|
||||
|
||||
<!-- test dependencies -->
|
||||
<junit.jupiter.version>5.6.0</junit.jupiter.version>
|
||||
<mockito.version>3.3.0</mockito.version>
|
||||
<hamcrest.version>2.2</hamcrest.version>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jcenter</id>
|
||||
<url>https://jcenter.bintray.com</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<!-- modules -->
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>commons</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>keychain</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>ui</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>launcher</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Cryptomator Libs -->
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>cryptofs</artifactId>
|
||||
<version>${cryptomator.cryptofs.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>fuse-nio-adapter</artifactId>
|
||||
<version>${cryptomator.fuse.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>dokany-nio-adapter</artifactId>
|
||||
<version>${cryptomator.dokany.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>webdav-nio-adapter</artifactId>
|
||||
<version>${cryptomator.webdav.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>jni</artifactId>
|
||||
<version>${cryptomator.jni.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JavaFX -->
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-base</artifactId>
|
||||
<version>${javafx.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-graphics</artifactId>
|
||||
<version>${javafx.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-controls</artifactId>
|
||||
<version>${javafx.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-fxml</artifactId>
|
||||
<version>${javafx.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Logging -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
<version>${logback.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>${logback.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Apache Commons -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>${commons-lang3.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JWT -->
|
||||
<dependency>
|
||||
<groupId>com.auth0</groupId>
|
||||
<artifactId>java-jwt</artifactId>
|
||||
<version>${jwt.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- EasyBind -->
|
||||
<dependency>
|
||||
<groupId>org.fxmisc.easybind</groupId>
|
||||
<artifactId>easybind</artifactId>
|
||||
<version>${easybind.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Google -->
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${guava.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.dagger</groupId>
|
||||
<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>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>${junit.jupiter.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>${mockito.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest</artifactId>
|
||||
<version>${hamcrest.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-swing</artifactId>
|
||||
<version>${javafx.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<!-- common dependencies for all modules -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<modules>
|
||||
<module>commons</module>
|
||||
<module>keychain</module>
|
||||
<module>ui</module>
|
||||
<module>launcher</module>
|
||||
</modules>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release</id>
|
||||
<modules>
|
||||
<module>buildkit</module>
|
||||
</modules>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>coverage</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>3.1.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-libs</id>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/libs</outputDirectory>
|
||||
<includeScope>runtime</includeScope>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<!-- adds Implementation-Version which can be read during runtime -->
|
||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.8.5</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>prepare-agent</id>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>report</id>
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>**/*_*</exclude>
|
||||
<exclude>**/Dagger*</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<release>11</release>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>com.google.dagger</groupId>
|
||||
<artifactId>dagger-compiler</artifactId>
|
||||
<version>${dagger.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.2</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
123
main/ui/pom.xml
123
main/ui/pom.xml
@@ -1,123 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>main</artifactId>
|
||||
<version>1.5.0</version>
|
||||
</parent>
|
||||
<artifactId>ui</artifactId>
|
||||
<name>Cryptomator GUI</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>keychain</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>commons</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>jni</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- JavaFx -->
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-controls</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-fxml</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- EasyBind -->
|
||||
<dependency>
|
||||
<groupId>org.fxmisc.easybind</groupId>
|
||||
<artifactId>easybind</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Google -->
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Apache Commons -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- DI -->
|
||||
<dependency>
|
||||
<groupId>com.google.dagger</groupId>
|
||||
<artifactId>dagger</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Zxcvbn -->
|
||||
<dependency>
|
||||
<groupId>com.nulab-inc</groupId>
|
||||
<artifactId>zxcvbn</artifactId>
|
||||
<version>1.3.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Logging -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Testing -->
|
||||
<dependency>
|
||||
<groupId>com.google.jimfs</groupId>
|
||||
<artifactId>jimfs</artifactId>
|
||||
<version>1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-swing</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-third-party</id>
|
||||
<goals>
|
||||
<goal>add-third-party</goal>
|
||||
</goals>
|
||||
<phase>generate-resources</phase>
|
||||
<configuration>
|
||||
<outputDirectory>${project.basedir}/src/main/resources/license</outputDirectory>
|
||||
<thirdPartyFilename>THIRD-PARTY.txt</thirdPartyFilename>
|
||||
<includedScopes>compile</includedScopes>
|
||||
<excludedGroups>org\.cryptomator</excludedGroups>
|
||||
<licenseMerges>
|
||||
<licenseMerge>Apache License v2.0|Apache License, Version 2.0|The Apache Software License, Version 2.0|Apache 2.0|Apache Software License - Version 2.0</licenseMerge>
|
||||
<licenseMerge>MIT License|The MIT License (MIT)|The MIT License|MIT license</licenseMerge>
|
||||
<licenseMerge>LGPL 2.1|LGPL, version 2.1|GNU Lesser/Library General Public License version 2|GNU Lesser General Public License Version 2.1</licenseMerge>
|
||||
<licenseMerge>GPLv2|GNU General Public License Version 2</licenseMerge>
|
||||
<licenseMerge>GPLv2+CE|CDDL + GPLv2 with classpath exception</licenseMerge>
|
||||
</licenseMerges>
|
||||
<fileTemplate>${project.basedir}/src/license/template.ftl</fileTemplate>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -1,90 +0,0 @@
|
||||
package org.cryptomator.ui.changepassword;
|
||||
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.BooleanBinding;
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.stage.Stage;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
|
||||
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
|
||||
import org.cryptomator.ui.common.Animations;
|
||||
import org.cryptomator.ui.common.ErrorComponent;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.controls.FontAwesome5IconView;
|
||||
import org.cryptomator.ui.controls.NiceSecurePasswordField;
|
||||
import org.cryptomator.ui.common.PasswordStrengthUtil;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import java.io.IOException;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
|
||||
|
||||
@ChangePasswordScoped
|
||||
public class ChangePasswordController implements FxController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ChangePasswordController.class);
|
||||
|
||||
private final Stage window;
|
||||
private final Vault vault;
|
||||
private final ObjectProperty<CharSequence> newPassword;
|
||||
private final ErrorComponent.Builder errorComponent;
|
||||
|
||||
public NiceSecurePasswordField oldPasswordField;
|
||||
public CheckBox finalConfirmationCheckbox;
|
||||
public Button finishButton;
|
||||
|
||||
@Inject
|
||||
public ChangePasswordController(@ChangePasswordWindow Stage window, @ChangePasswordWindow Vault vault, @Named("newPassword") ObjectProperty<CharSequence> newPassword, ErrorComponent.Builder errorComponent) {
|
||||
this.window = window;
|
||||
this.vault = vault;
|
||||
this.newPassword = newPassword;
|
||||
this.errorComponent = errorComponent;
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
BooleanBinding hasNotConfirmedCheckbox = finalConfirmationCheckbox.selectedProperty().not();
|
||||
BooleanBinding isInvalidNewPassword = Bindings.createBooleanBinding(() -> newPassword.get() == null || newPassword.get().length() == 0, newPassword);
|
||||
finishButton.disableProperty().bind(hasNotConfirmedCheckbox.or(isInvalidNewPassword));
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void cancel() {
|
||||
window.close();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void finish() {
|
||||
try {
|
||||
CryptoFileSystemProvider.changePassphrase(vault.getPath(), MASTERKEY_FILENAME, oldPasswordField.getCharacters(), newPassword.get());
|
||||
LOG.info("Successful changed password for {}", vault.getDisplayableName());
|
||||
window.close();
|
||||
} catch (IOException e) {
|
||||
LOG.error("IO error occured during password change. Unable to perform operation.", e);
|
||||
errorComponent.cause(e).window(window).returnToScene(window.getScene()).build().showErrorScene();
|
||||
} catch (InvalidPassphraseException e) {
|
||||
Animations.createShakeWindowAnimation(window).play();
|
||||
oldPasswordField.selectAll();
|
||||
oldPasswordField.requestFocus();
|
||||
}
|
||||
}
|
||||
|
||||
/* Getter/Setter */
|
||||
|
||||
public Vault getVault() {
|
||||
return vault;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,363 +0,0 @@
|
||||
package org.cryptomator.ui.common;
|
||||
|
||||
import javafx.concurrent.Task;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.common.vaults.VaultState;
|
||||
import org.cryptomator.common.vaults.Volume;
|
||||
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
|
||||
import org.cryptomator.keychain.KeychainAccess;
|
||||
import org.cryptomator.ui.fxapp.FxApplicationScoped;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.nio.CharBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@FxApplicationScoped
|
||||
public class VaultService {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(VaultService.class);
|
||||
|
||||
private final ExecutorService executorService;
|
||||
private final Optional<KeychainAccess> keychain;
|
||||
|
||||
@Inject
|
||||
public VaultService(ExecutorService executorService, Optional<KeychainAccess> keychain) {
|
||||
this.executorService = executorService;
|
||||
this.keychain = keychain;
|
||||
}
|
||||
|
||||
public void reveal(Vault vault) {
|
||||
executorService.execute(createRevealTask(vault));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates but doesn't start a reveal task.
|
||||
*
|
||||
* @param vault The vault to reveal
|
||||
*/
|
||||
public Task<Vault> createRevealTask(Vault vault) {
|
||||
Task<Vault> task = new RevealVaultTask(vault);
|
||||
task.setOnSucceeded(evt -> LOG.info("Revealed {}", vault.getDisplayableName()));
|
||||
task.setOnFailed(evt -> LOG.error("Failed to reveal " + vault.getDisplayableName(), evt.getSource().getException()));
|
||||
return task;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to unlock all given vaults in a background thread using passwords stored in the system keychain.
|
||||
*
|
||||
* @param vaults The vaults to unlock
|
||||
* @implNote No-op if no system keychain is present
|
||||
*/
|
||||
public void attemptAutoUnlock(Collection<Vault> vaults) {
|
||||
if (!keychain.isPresent()) {
|
||||
LOG.debug("No system keychain found. Unable to auto unlock without saved passwords.");
|
||||
} else {
|
||||
List<Task<Vault>> unlockTasks = vaults.stream().map(v -> createAutoUnlockTask(v, keychain.get())).collect(Collectors.toList());
|
||||
Task<Collection<Vault>> runSequentiallyTask = new RunSequentiallyTask(unlockTasks);
|
||||
executorService.execute(runSequentiallyTask);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates but doesn't start an auto-unlock task.
|
||||
*
|
||||
* @param vault The vault to unlock
|
||||
* @param keychainAccess The system keychain holding the passphrase for the vault
|
||||
* @return The task
|
||||
*/
|
||||
public Task<Vault> createAutoUnlockTask(Vault vault, KeychainAccess keychainAccess) {
|
||||
Task<Vault> task = new AutoUnlockVaultTask(vault, keychainAccess);
|
||||
task.setOnSucceeded(evt -> LOG.info("Auto-unlocked {}", vault.getDisplayableName()));
|
||||
task.setOnFailed(evt -> LOG.error("Failed to auto-unlock " + vault.getDisplayableName(), evt.getSource().getException()));
|
||||
return task;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks a vault in a background thread
|
||||
*
|
||||
* @param vault The vault to unlock
|
||||
* @param passphrase The password to use - wipe this param asap
|
||||
* @implNote A copy of the passphrase will be made, which is wiped as soon as the task ran.
|
||||
*/
|
||||
public void unlock(Vault vault, CharSequence passphrase) {
|
||||
executorService.execute(createUnlockTask(vault, passphrase));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates but doesn't start an unlock task.
|
||||
*
|
||||
* @param vault The vault to unlock
|
||||
* @param passphrase The password to use - wipe this param asap
|
||||
* @return The task
|
||||
* @implNote A copy of the passphrase will be made, which is wiped as soon as the task ran.
|
||||
*/
|
||||
public Task<Vault> createUnlockTask(Vault vault, CharSequence passphrase) {
|
||||
Task<Vault> task = new UnlockVaultTask(vault, passphrase);
|
||||
task.setOnSucceeded(evt -> LOG.info("Unlocked {}", vault.getDisplayableName()));
|
||||
task.setOnFailed(evt -> LOG.error("Failed to unlock " + vault.getDisplayableName(), evt.getSource().getException()));
|
||||
return task;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks a vault in a background thread.
|
||||
*
|
||||
* @param vault The vault to lock
|
||||
* @param forced Whether to attempt a forced lock
|
||||
*/
|
||||
public void lock(Vault vault, boolean forced) {
|
||||
executorService.execute(createLockTask(vault, forced));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates but doesn't start a lock task.
|
||||
*
|
||||
* @param vault The vault to lock
|
||||
* @param forced Whether to attempt a forced lock
|
||||
* @return The task
|
||||
*/
|
||||
public Task<Vault> createLockTask(Vault vault, boolean forced) {
|
||||
Task<Vault> task = new LockVaultTask(vault, forced);
|
||||
task.setOnSucceeded(evt -> LOG.info("Locked {}", vault.getDisplayableName()));
|
||||
task.setOnFailed(evt -> LOG.error("Failed to lock " + vault.getDisplayableName(), evt.getSource().getException()));
|
||||
return task;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locks all given vaults in a background thread.
|
||||
*
|
||||
* @param vaults The vaults to lock
|
||||
* @param forced Whether to attempt a forced lock
|
||||
*/
|
||||
public void lockAll(Collection<Vault> vaults, boolean forced) {
|
||||
executorService.execute(createLockAllTask(vaults, forced));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates but doesn't start a lock-all task.
|
||||
*
|
||||
* @param vaults The list of vaults to be locked
|
||||
* @param forced Whether to attempt a forced lock
|
||||
* @return Meta-Task that waits until all vaults are locked or fails after the first failure of a subtask
|
||||
*/
|
||||
public Task<Collection<Vault>> createLockAllTask(Collection<Vault> vaults, boolean forced) {
|
||||
List<Task<Vault>> lockTasks = vaults.stream().map(v -> new LockVaultTask(v, forced)).collect(Collectors.toUnmodifiableList());
|
||||
lockTasks.forEach(executorService::execute);
|
||||
Task<Collection<Vault>> task = new WaitForTasksTask(lockTasks);
|
||||
String vaultNames = vaults.stream().map(Vault::getDisplayableName).collect(Collectors.joining(", "));
|
||||
task.setOnSucceeded(evt -> LOG.info("Locked {}", vaultNames));
|
||||
task.setOnFailed(evt -> LOG.error("Failed to lock vaults " + vaultNames, evt.getSource().getException()));
|
||||
return task;
|
||||
}
|
||||
|
||||
private static class RevealVaultTask extends Task<Vault> {
|
||||
|
||||
private final Vault vault;
|
||||
|
||||
/**
|
||||
* @param vault The vault to lock
|
||||
*/
|
||||
public RevealVaultTask(Vault vault) {
|
||||
this.vault = vault;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Vault call() throws Volume.VolumeException {
|
||||
vault.reveal();
|
||||
return vault;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A task that waits for completion of multiple other tasks
|
||||
*/
|
||||
private static class WaitForTasksTask extends Task<Collection<Vault>> {
|
||||
|
||||
private final Collection<Task<Vault>> startedTasks;
|
||||
|
||||
public WaitForTasksTask(Collection<Task<Vault>> tasks) {
|
||||
this.startedTasks = List.copyOf(tasks);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<Vault> call() throws ExecutionException, InterruptedException {
|
||||
Iterator<Task<Vault>> remainingTasks = startedTasks.iterator();
|
||||
Collection<Vault> completed = new ArrayList<>();
|
||||
try {
|
||||
// wait for all tasks:
|
||||
while (remainingTasks.hasNext()) {
|
||||
Vault done = remainingTasks.next().get();
|
||||
completed.add(done);
|
||||
}
|
||||
} catch (ExecutionException e) {
|
||||
// cancel all remaining:
|
||||
while (remainingTasks.hasNext()) {
|
||||
remainingTasks.next().cancel(true);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
return completed;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A task that runs a list of tasks in their given order
|
||||
*/
|
||||
private static class RunSequentiallyTask extends Task<Collection<Vault>> {
|
||||
|
||||
private final List<Task<Vault>> tasks;
|
||||
|
||||
public RunSequentiallyTask(List<Task<Vault>> tasks) {
|
||||
this.tasks = List.copyOf(tasks);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Vault> call() throws ExecutionException, InterruptedException {
|
||||
List<Vault> completed = new ArrayList<>();
|
||||
for (Task<Vault> task : tasks) {
|
||||
task.run();
|
||||
Vault done = task.get();
|
||||
completed.add(done);
|
||||
}
|
||||
return completed;
|
||||
}
|
||||
}
|
||||
|
||||
private static class AutoUnlockVaultTask extends Task<Vault> {
|
||||
|
||||
private final Vault vault;
|
||||
private final KeychainAccess keychain;
|
||||
|
||||
public AutoUnlockVaultTask(Vault vault, KeychainAccess keychain) {
|
||||
this.vault = vault;
|
||||
this.keychain = keychain;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Vault call() throws Exception {
|
||||
char[] storedPw = null;
|
||||
try {
|
||||
storedPw = keychain.loadPassphrase(vault.getId());
|
||||
if (storedPw == null) {
|
||||
throw new InvalidPassphraseException();
|
||||
}
|
||||
vault.unlock(CharBuffer.wrap(storedPw));
|
||||
} finally {
|
||||
if (storedPw != null) {
|
||||
Arrays.fill(storedPw, ' ');
|
||||
}
|
||||
}
|
||||
return vault;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void scheduled() {
|
||||
vault.setState(VaultState.PROCESSING);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void succeeded() {
|
||||
vault.setState(VaultState.UNLOCKED);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void failed() {
|
||||
vault.setState(VaultState.LOCKED);
|
||||
}
|
||||
}
|
||||
|
||||
private static class UnlockVaultTask extends Task<Vault> {
|
||||
|
||||
private final Vault vault;
|
||||
private final CharBuffer passphrase;
|
||||
|
||||
/**
|
||||
* @param vault The vault to unlock
|
||||
* @param passphrase The password to use - wipe this param asap
|
||||
* @implNote A copy of the passphrase will be made, which is wiped as soon as the task ran.
|
||||
*/
|
||||
public UnlockVaultTask(Vault vault, CharSequence passphrase) {
|
||||
this.vault = vault;
|
||||
this.passphrase = CharBuffer.allocate(passphrase.length());
|
||||
for (int i = 0; i < passphrase.length(); i++) {
|
||||
this.passphrase.put(i, passphrase.charAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Vault call() throws Exception {
|
||||
try {
|
||||
vault.unlock(passphrase);
|
||||
} finally {
|
||||
Arrays.fill(passphrase.array(), ' ');
|
||||
}
|
||||
return vault;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void scheduled() {
|
||||
vault.setState(VaultState.PROCESSING);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void succeeded() {
|
||||
vault.setState(VaultState.UNLOCKED);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void failed() {
|
||||
vault.setState(VaultState.LOCKED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A task that locks a vault
|
||||
*/
|
||||
private static class LockVaultTask extends Task<Vault> {
|
||||
|
||||
private final Vault vault;
|
||||
private final boolean forced;
|
||||
|
||||
/**
|
||||
* @param vault The vault to lock
|
||||
* @param forced Whether to attempt a forced lock
|
||||
*/
|
||||
public LockVaultTask(Vault vault, boolean forced) {
|
||||
this.vault = vault;
|
||||
this.forced = forced;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Vault call() throws Volume.VolumeException {
|
||||
vault.lock(forced);
|
||||
return vault;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void scheduled() {
|
||||
vault.setState(VaultState.PROCESSING);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void succeeded() {
|
||||
vault.setState(VaultState.LOCKED);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void failed() {
|
||||
vault.setState(VaultState.UNLOCKED);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
package org.cryptomator.ui.fxapp;
|
||||
|
||||
import dagger.Lazy;
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.BooleanBinding;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableSet;
|
||||
import javafx.stage.Stage;
|
||||
import org.cryptomator.common.LicenseHolder;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.common.settings.UiTheme;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.jni.JniException;
|
||||
import org.cryptomator.jni.MacApplicationUiAppearance;
|
||||
import org.cryptomator.jni.MacApplicationUiState;
|
||||
import org.cryptomator.jni.MacFunctions;
|
||||
import org.cryptomator.ui.common.VaultService;
|
||||
import org.cryptomator.ui.mainwindow.MainWindowComponent;
|
||||
import org.cryptomator.ui.preferences.PreferencesComponent;
|
||||
import org.cryptomator.ui.preferences.SelectedPreferencesTab;
|
||||
import org.cryptomator.ui.quit.QuitComponent;
|
||||
import org.cryptomator.ui.unlock.UnlockComponent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.awt.desktop.QuitResponse;
|
||||
import java.util.Optional;
|
||||
|
||||
@FxApplicationScoped
|
||||
public class FxApplication extends Application {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(FxApplication.class);
|
||||
|
||||
private final Settings settings;
|
||||
private final Lazy<MainWindowComponent> mainWindow;
|
||||
private final Lazy<PreferencesComponent> preferencesWindow;
|
||||
private final UnlockComponent.Builder unlockWindowBuilder;
|
||||
private final QuitComponent.Builder quitWindowBuilder;
|
||||
private final Optional<MacFunctions> macFunctions;
|
||||
private final VaultService vaultService;
|
||||
private final LicenseHolder licenseHolder;
|
||||
private final ObservableSet<Stage> visibleStages = FXCollections.observableSet();
|
||||
private final BooleanBinding hasVisibleStages = Bindings.isNotEmpty(visibleStages);
|
||||
|
||||
@Inject
|
||||
FxApplication(Settings settings, Lazy<MainWindowComponent> mainWindow, Lazy<PreferencesComponent> preferencesWindow, UnlockComponent.Builder unlockWindowBuilder, QuitComponent.Builder quitWindowBuilder, Optional<MacFunctions> macFunctions, VaultService vaultService, LicenseHolder licenseHolder) {
|
||||
this.settings = settings;
|
||||
this.mainWindow = mainWindow;
|
||||
this.preferencesWindow = preferencesWindow;
|
||||
this.unlockWindowBuilder = unlockWindowBuilder;
|
||||
this.quitWindowBuilder = quitWindowBuilder;
|
||||
this.macFunctions = macFunctions;
|
||||
this.vaultService = vaultService;
|
||||
this.licenseHolder = licenseHolder;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
LOG.trace("FxApplication.start()");
|
||||
Platform.setImplicitExit(false);
|
||||
|
||||
hasVisibleStages.addListener(this::hasVisibleStagesChanged);
|
||||
|
||||
settings.theme().addListener(this::themeChanged);
|
||||
loadSelectedStyleSheet(settings.theme().get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(Stage stage) {
|
||||
throw new UnsupportedOperationException("Use start() instead.");
|
||||
}
|
||||
|
||||
private void addVisibleStage(Stage stage) {
|
||||
visibleStages.add(stage);
|
||||
stage.setOnHidden(evt -> visibleStages.remove(stage));
|
||||
}
|
||||
|
||||
private void hasVisibleStagesChanged(@SuppressWarnings("unused") ObservableValue<? extends Boolean> observableValue, @SuppressWarnings("unused") boolean oldValue, boolean newValue) {
|
||||
if (newValue) {
|
||||
macFunctions.map(MacFunctions::uiState).ifPresent(MacApplicationUiState::transformToForegroundApplication);
|
||||
} else {
|
||||
macFunctions.map(MacFunctions::uiState).ifPresent(MacApplicationUiState::transformToAgentApplication);
|
||||
}
|
||||
}
|
||||
|
||||
public void showPreferencesWindow(SelectedPreferencesTab selectedTab) {
|
||||
Platform.runLater(() -> {
|
||||
Stage stage = preferencesWindow.get().showPreferencesWindow(selectedTab);
|
||||
addVisibleStage(stage);
|
||||
LOG.debug("Showing Preferences");
|
||||
});
|
||||
}
|
||||
|
||||
public void showMainWindow() {
|
||||
Platform.runLater(() -> {
|
||||
Stage stage = mainWindow.get().showMainWindow();
|
||||
addVisibleStage(stage);
|
||||
LOG.debug("Showing MainWindow");
|
||||
});
|
||||
}
|
||||
|
||||
public void showUnlockWindow(Vault vault) {
|
||||
Platform.runLater(() -> {
|
||||
Stage stage = unlockWindowBuilder.vault(vault).build().showUnlockWindow();
|
||||
addVisibleStage(stage);
|
||||
LOG.debug("Showing UnlockWindow for {}", vault.getDisplayableName());
|
||||
});
|
||||
}
|
||||
|
||||
public void showQuitWindow(QuitResponse response) {
|
||||
Platform.runLater(() -> {
|
||||
Stage stage = quitWindowBuilder.quitResponse(response).build().showQuitWindow();
|
||||
addVisibleStage(stage);
|
||||
LOG.debug("Showing QuitWindow");
|
||||
});
|
||||
}
|
||||
|
||||
public VaultService getVaultService() {
|
||||
return vaultService;
|
||||
}
|
||||
|
||||
private void themeChanged(@SuppressWarnings("unused") ObservableValue<? extends UiTheme> observable, @SuppressWarnings("unused") UiTheme oldValue, UiTheme newValue) {
|
||||
loadSelectedStyleSheet(newValue);
|
||||
}
|
||||
|
||||
private void loadSelectedStyleSheet(UiTheme desiredTheme) {
|
||||
UiTheme theme = licenseHolder.isValidLicense() ? desiredTheme : UiTheme.LIGHT;
|
||||
switch (theme) {
|
||||
case DARK:
|
||||
Application.setUserAgentStylesheet(getClass().getResource("/css/dark_theme.css").toString());
|
||||
macFunctions.map(MacFunctions::uiAppearance).ifPresent(JniException.ignore(MacApplicationUiAppearance::setToDarkAqua));
|
||||
break;
|
||||
case LIGHT:
|
||||
default:
|
||||
Application.setUserAgentStylesheet(getClass().getResource("/css/light_theme.css").toString());
|
||||
macFunctions.map(MacFunctions::uiAppearance).ifPresent(JniException.ignore(MacApplicationUiAppearance::setToAqua));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
package org.cryptomator.ui.launcher;
|
||||
|
||||
import javafx.collections.ObservableList;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.jni.JniException;
|
||||
import org.cryptomator.jni.MacApplicationUiState;
|
||||
import org.cryptomator.jni.MacFunctions;
|
||||
import org.cryptomator.ui.fxapp.FxApplication;
|
||||
import org.cryptomator.ui.traymenu.TrayMenuComponent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.awt.Desktop;
|
||||
import java.awt.SystemTray;
|
||||
import java.awt.desktop.AppReopenedListener;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
|
||||
@Singleton
|
||||
public class UiLauncher {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(UiLauncher.class);
|
||||
|
||||
private final Settings settings;
|
||||
private final ObservableList<Vault> vaults;
|
||||
private final TrayMenuComponent.Builder trayComponent;
|
||||
private final FxApplicationStarter fxApplicationStarter;
|
||||
private final AppLaunchEventHandler launchEventHandler;
|
||||
private final Optional<MacFunctions> macFunctions;
|
||||
|
||||
@Inject
|
||||
public UiLauncher(Settings settings, ObservableList<Vault> vaults, TrayMenuComponent.Builder trayComponent, FxApplicationStarter fxApplicationStarter, AppLaunchEventHandler launchEventHandler, Optional<MacFunctions> macFunctions) {
|
||||
this.settings = settings;
|
||||
this.vaults = vaults;
|
||||
this.trayComponent = trayComponent;
|
||||
this.fxApplicationStarter = fxApplicationStarter;
|
||||
this.launchEventHandler = launchEventHandler;
|
||||
this.macFunctions = macFunctions;
|
||||
}
|
||||
|
||||
public void launch() {
|
||||
final boolean hasTrayIcon;
|
||||
if (SystemTray.isSupported()) {
|
||||
trayComponent.build().addIconToSystemTray();
|
||||
hasTrayIcon = true;
|
||||
} else {
|
||||
hasTrayIcon = false;
|
||||
}
|
||||
|
||||
// show window on start?
|
||||
if (hasTrayIcon && settings.startHidden().get()) {
|
||||
LOG.debug("Hiding application...");
|
||||
macFunctions.map(MacFunctions::uiState).ifPresent(JniException.ignore(MacApplicationUiState::transformToAgentApplication));
|
||||
} else {
|
||||
showMainWindowAsync(hasTrayIcon);
|
||||
}
|
||||
|
||||
// register app reopen listener
|
||||
Desktop.getDesktop().addAppEventListener((AppReopenedListener) e -> showMainWindowAsync(hasTrayIcon));
|
||||
|
||||
// auto unlock
|
||||
Collection<Vault> vaultsWithAutoUnlockEnabled = vaults.filtered(v -> v.getVaultSettings().unlockAfterStartup().get());
|
||||
if (!vaultsWithAutoUnlockEnabled.isEmpty()) {
|
||||
fxApplicationStarter.get(hasTrayIcon).thenAccept(app -> app.getVaultService().attemptAutoUnlock(vaultsWithAutoUnlockEnabled));
|
||||
}
|
||||
|
||||
launchEventHandler.startHandlingLaunchEvents(hasTrayIcon);
|
||||
}
|
||||
|
||||
private void showMainWindowAsync(boolean hasTrayIcon) {
|
||||
fxApplicationStarter.get(hasTrayIcon).thenAccept(FxApplication::showMainWindow);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package org.cryptomator.ui.launcher;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import org.cryptomator.common.JniModule;
|
||||
import org.cryptomator.keychain.KeychainModule;
|
||||
import org.cryptomator.ui.fxapp.FxApplicationComponent;
|
||||
import org.cryptomator.ui.traymenu.TrayMenuComponent;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.Locale;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
@Module(includes = {JniModule.class, KeychainModule.class}, subcomponents = {TrayMenuComponent.class, FxApplicationComponent.class})
|
||||
public abstract class UiLauncherModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static ResourceBundle provideLocalization() {
|
||||
return ResourceBundle.getBundle("i18n.strings");
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named("launchEventQueue")
|
||||
static BlockingQueue<AppLaunchEvent> provideFileOpenRequests() {
|
||||
return new ArrayBlockingQueue<>(10);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package org.cryptomator.ui.mainwindow;
|
||||
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||
import javafx.fxml.FXML;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.fxapp.FxApplication;
|
||||
import org.cryptomator.ui.vaultoptions.VaultOptionsComponent;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@MainWindowScoped
|
||||
public class VaultDetailLockedController implements FxController {
|
||||
|
||||
private final ReadOnlyObjectProperty<Vault> vault;
|
||||
private final FxApplication application;
|
||||
private final VaultOptionsComponent.Builder vaultOptionsWindow;
|
||||
|
||||
@Inject
|
||||
VaultDetailLockedController(ObjectProperty<Vault> vault, FxApplication application, VaultOptionsComponent.Builder vaultOptionsWindow) {
|
||||
this.vault = vault;
|
||||
this.application = application;
|
||||
this.vaultOptionsWindow = vaultOptionsWindow;
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void unlock() {
|
||||
application.showUnlockWindow(vault.get());
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void showVaultOptions() {
|
||||
vaultOptionsWindow.vault(vault.get()).build().showVaultOptionsWindow();
|
||||
}
|
||||
|
||||
/* Getter/Setter */
|
||||
|
||||
public ReadOnlyObjectProperty<Vault> vaultProperty() {
|
||||
return vault;
|
||||
}
|
||||
|
||||
public Vault getVault() {
|
||||
return vault.get();
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package org.cryptomator.ui.mainwindow;
|
||||
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@MainWindowScoped
|
||||
public class VaultDetailMissingVaultController implements FxController {
|
||||
|
||||
private final ReadOnlyObjectProperty<Vault> vault;
|
||||
|
||||
@Inject
|
||||
public VaultDetailMissingVaultController(ObjectProperty<Vault> vault) {
|
||||
this.vault = vault;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package org.cryptomator.ui.mainwindow;
|
||||
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||
import javafx.fxml.FXML;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.VaultService;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@MainWindowScoped
|
||||
public class VaultDetailUnlockedController implements FxController {
|
||||
|
||||
private final ReadOnlyObjectProperty<Vault> vault;
|
||||
private final VaultService vaultService;
|
||||
|
||||
@Inject
|
||||
public VaultDetailUnlockedController(ObjectProperty<Vault> vault, VaultService vaultService) {
|
||||
this.vault = vault;
|
||||
this.vaultService = vaultService;
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void revealAccessLocation() {
|
||||
vaultService.reveal(vault.get());
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void lock() {
|
||||
vaultService.lock(vault.get(), false);
|
||||
// TODO count lock attempts, and allow forced lock
|
||||
}
|
||||
|
||||
/* Getter/Setter */
|
||||
|
||||
public ReadOnlyObjectProperty<Vault> vaultProperty() {
|
||||
return vault;
|
||||
}
|
||||
|
||||
public Vault getVault() {
|
||||
return vault.get();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
package org.cryptomator.ui.mainwindow;
|
||||
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.BooleanBinding;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.ListView;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.common.vaults.VaultListManager;
|
||||
import org.cryptomator.common.vaults.VaultState;
|
||||
import org.cryptomator.ui.addvaultwizard.AddVaultWizardComponent;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.removevault.RemoveVaultComponent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@MainWindowScoped
|
||||
public class VaultListController implements FxController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(VaultListController.class);
|
||||
|
||||
private final ObservableList<Vault> vaults;
|
||||
private final ObjectProperty<Vault> selectedVault;
|
||||
private final VaultListCellFactory cellFactory;
|
||||
private final AddVaultWizardComponent.Builder addVaultWizard;
|
||||
private final RemoveVaultComponent.Builder removeVault;
|
||||
private final BooleanBinding noVaultSelected;
|
||||
private final BooleanBinding emptyVaultList;
|
||||
public ListView<Vault> vaultList;
|
||||
|
||||
@Inject
|
||||
VaultListController(ObservableList<Vault> vaults, ObjectProperty<Vault> selectedVault, VaultListCellFactory cellFactory, AddVaultWizardComponent.Builder addVaultWizard, RemoveVaultComponent.Builder removeVault) {
|
||||
this.vaults = vaults;
|
||||
this.selectedVault = selectedVault;
|
||||
this.cellFactory = cellFactory;
|
||||
this.addVaultWizard = addVaultWizard;
|
||||
this.removeVault = removeVault;
|
||||
this.noVaultSelected = selectedVault.isNull();
|
||||
this.emptyVaultList = Bindings.isEmpty(vaults);
|
||||
selectedVault.addListener(this::selectedVaultDidChange);
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
vaultList.setItems(vaults);
|
||||
vaultList.setCellFactory(cellFactory);
|
||||
selectedVault.bind(vaultList.getSelectionModel().selectedItemProperty());
|
||||
vaults.addListener((ListChangeListener.Change<? extends Vault> c) -> {
|
||||
while (c.next()) {
|
||||
if (c.wasAdded()) {
|
||||
Vault anyAddedVault = c.getAddedSubList().get(0);
|
||||
vaultList.getSelectionModel().select(anyAddedVault);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void selectedVaultDidChange(@SuppressWarnings("unused") ObservableValue<? extends Vault> observableValue, @SuppressWarnings("unused") Vault oldValue, Vault newValue) {
|
||||
if (newValue == null) {
|
||||
return;
|
||||
}
|
||||
VaultState reportedState = newValue.getState();
|
||||
switch (reportedState) {
|
||||
case LOCKED:
|
||||
case NEEDS_MIGRATION:
|
||||
case MISSING:
|
||||
VaultState determinedState = VaultListManager.determineVaultState(newValue.getPath());
|
||||
newValue.setState(determinedState);
|
||||
break;
|
||||
case ERROR:
|
||||
case UNLOCKED:
|
||||
case PROCESSING:
|
||||
default:
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void didClickAddVault() {
|
||||
addVaultWizard.build().showAddVaultWizard();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void didClickRemoveVault() {
|
||||
Vault v = selectedVault.get();
|
||||
if (v != null) {
|
||||
removeVault.vault(v).build().showRemoveVault();
|
||||
} else {
|
||||
LOG.debug("Cannot remove a vault if none is selected.");
|
||||
}
|
||||
}
|
||||
|
||||
// Getter and Setter
|
||||
|
||||
public BooleanBinding emptyVaultListProperty() {
|
||||
return emptyVaultList;
|
||||
}
|
||||
|
||||
public boolean isEmptyVaultList() {
|
||||
return emptyVaultList.get();
|
||||
}
|
||||
|
||||
public BooleanBinding noVaultSelectedProperty() {
|
||||
return noVaultSelected;
|
||||
}
|
||||
|
||||
public boolean isNoVaultSelected() {
|
||||
return noVaultSelected.get();
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package org.cryptomator.ui.preferences;
|
||||
|
||||
import org.cryptomator.jni.MacFunctions;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
class AutoStartMacStrategy implements AutoStartStrategy {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AutoStartMacStrategy.class);
|
||||
|
||||
private final MacFunctions macFunctions;
|
||||
|
||||
public AutoStartMacStrategy(MacFunctions macFunctions) {
|
||||
this.macFunctions = macFunctions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionStage<Boolean> isAutoStartEnabled() {
|
||||
boolean enabled = macFunctions.launchServices().isLoginItemEnabled();
|
||||
return CompletableFuture.completedFuture(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableAutoStart() throws TogglingAutoStartFailedException {
|
||||
if (macFunctions.launchServices().enableLoginItem()) {
|
||||
LOG.debug("Added login item.");
|
||||
} else {
|
||||
throw new TogglingAutoStartFailedException("Failed to add login item.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableAutoStart() throws TogglingAutoStartFailedException {
|
||||
if (macFunctions.launchServices().disableLoginItem()) {
|
||||
LOG.debug("Removed login item.");
|
||||
} else {
|
||||
throw new TogglingAutoStartFailedException("Failed to remove login item.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package org.cryptomator.ui.preferences;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.jni.MacFunctions;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Module
|
||||
abstract class AutoStartModule {
|
||||
|
||||
@Provides
|
||||
@PreferencesScoped
|
||||
public static Optional<AutoStartStrategy> provideAutoStartStrategy(Optional<MacFunctions> macFunctions) {
|
||||
if (SystemUtils.IS_OS_MAC_OSX && macFunctions.isPresent()) {
|
||||
return Optional.of(new AutoStartMacStrategy(macFunctions.get()));
|
||||
} else if (SystemUtils.IS_OS_WINDOWS) {
|
||||
Optional<String> exeName = ProcessHandle.current().info().command();
|
||||
return exeName.map(AutoStartWinStrategy::new);
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package org.cryptomator.ui.preferences;
|
||||
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
public interface AutoStartStrategy {
|
||||
|
||||
CompletionStage<Boolean> isAutoStartEnabled();
|
||||
|
||||
void enableAutoStart() throws TogglingAutoStartFailedException;
|
||||
|
||||
void disableAutoStart() throws TogglingAutoStartFailedException;
|
||||
|
||||
class TogglingAutoStartFailedException extends Exception {
|
||||
|
||||
public TogglingAutoStartFailedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public TogglingAutoStartFailedException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
package org.cryptomator.ui.preferences;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
class AutoStartWinStrategy implements AutoStartStrategy {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AutoStartWinStrategy.class);
|
||||
private static final String HKCU_AUTOSTART_KEY = "\"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\"";
|
||||
private static final String AUTOSTART_VALUE = "Cryptomator";
|
||||
private final String exePath;
|
||||
|
||||
public AutoStartWinStrategy(String exePath) {
|
||||
this.exePath = exePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletionStage<Boolean> isAutoStartEnabled() {
|
||||
ProcessBuilder regQuery = new ProcessBuilder("reg", "query", HKCU_AUTOSTART_KEY, //
|
||||
"/v", AUTOSTART_VALUE);
|
||||
try {
|
||||
Process proc = regQuery.start();
|
||||
return proc.onExit().thenApply(p -> p.exitValue() == 0);
|
||||
} catch (IOException e) {
|
||||
LOG.warn("Failed to query {} from registry key {}", AUTOSTART_VALUE, HKCU_AUTOSTART_KEY);
|
||||
return CompletableFuture.completedFuture(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableAutoStart() throws TogglingAutoStartFailedException {
|
||||
ProcessBuilder regAdd = new ProcessBuilder("reg", "add", HKCU_AUTOSTART_KEY, //
|
||||
"/v", AUTOSTART_VALUE, //
|
||||
"/t", "REG_SZ", //
|
||||
"/d", "\"" + exePath + "\"", //
|
||||
"/f");
|
||||
String command = regAdd.command().stream().collect(Collectors.joining(" "));
|
||||
try {
|
||||
Process proc = regAdd.start();
|
||||
boolean finishedInTime = waitForProcess(proc, 5, TimeUnit.SECONDS);
|
||||
if (finishedInTime) {
|
||||
LOG.debug("Added {} to registry key {}.", AUTOSTART_VALUE, HKCU_AUTOSTART_KEY);
|
||||
} else {
|
||||
throw new TogglingAutoStartFailedException("Adding registry value failed.");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new TogglingAutoStartFailedException("Adding registry value failed. " + command, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableAutoStart() throws TogglingAutoStartFailedException {
|
||||
ProcessBuilder regRemove = new ProcessBuilder("reg", "delete", HKCU_AUTOSTART_KEY, //
|
||||
"/v", AUTOSTART_VALUE, //
|
||||
"/f");
|
||||
String command = regRemove.command().stream().collect(Collectors.joining(" "));
|
||||
try {
|
||||
Process proc = regRemove.start();
|
||||
boolean finishedInTime = waitForProcess(proc, 5, TimeUnit.SECONDS);
|
||||
if (finishedInTime) {
|
||||
LOG.debug("Removed {} from registry key {}.", AUTOSTART_VALUE, HKCU_AUTOSTART_KEY);
|
||||
} else {
|
||||
throw new TogglingAutoStartFailedException("Removing registry value failed.");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new TogglingAutoStartFailedException("Removing registry value failed. " + command, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean waitForProcess(Process proc, int timeout, TimeUnit timeUnit) {
|
||||
boolean finishedInTime = false;
|
||||
try {
|
||||
finishedInTime = proc.waitFor(timeout, timeUnit);
|
||||
} catch (InterruptedException e) {
|
||||
LOG.error("Timeout while reading registry", e);
|
||||
Thread.currentThread().interrupt();
|
||||
} finally {
|
||||
if (!finishedInTime) {
|
||||
proc.destroyForcibly();
|
||||
}
|
||||
}
|
||||
return finishedInTime;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package org.cryptomator.ui.preferences;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.TextArea;
|
||||
import org.cryptomator.common.LicenseHolder;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@PreferencesScoped
|
||||
public class DonationKeyPreferencesController implements FxController {
|
||||
|
||||
private static final String DONATION_URI = "https://store.cryptomator.org/desktop";
|
||||
|
||||
private final Application application;
|
||||
private final LicenseHolder licenseHolder;
|
||||
public TextArea donationKeyField;
|
||||
|
||||
@Inject
|
||||
DonationKeyPreferencesController(Application application, LicenseHolder licenseHolder) {
|
||||
this.application = application;
|
||||
this.licenseHolder = licenseHolder;
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
donationKeyField.setText(licenseHolder.getLicenseKey().orElse(null));
|
||||
donationKeyField.textProperty().addListener(this::registrationKeyChanged);
|
||||
}
|
||||
|
||||
private void registrationKeyChanged(@SuppressWarnings("unused") ObservableValue<? extends String> observable, @SuppressWarnings("unused") String oldValue, String newValue) {
|
||||
licenseHolder.validateAndStoreLicense(newValue);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void getDonationKey() {
|
||||
application.getHostServices().showDocument(DONATION_URI);
|
||||
}
|
||||
|
||||
public LicenseHolder getLicenseHolder() {
|
||||
return licenseHolder;
|
||||
}
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
package org.cryptomator.ui.preferences;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.geometry.NodeOrientation;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.ChoiceBox;
|
||||
import javafx.scene.control.RadioButton;
|
||||
import javafx.scene.control.Toggle;
|
||||
import javafx.scene.control.ToggleGroup;
|
||||
import javafx.util.StringConverter;
|
||||
import org.cryptomator.common.LicenseHolder;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.common.settings.UiTheme;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
@PreferencesScoped
|
||||
public class GeneralPreferencesController implements FxController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(GeneralPreferencesController.class);
|
||||
|
||||
private final Settings settings;
|
||||
private final boolean trayMenuSupported;
|
||||
private final Optional<AutoStartStrategy> autoStartStrategy;
|
||||
private final ObjectProperty<SelectedPreferencesTab> selectedTabProperty;
|
||||
private final LicenseHolder licenseHolder;
|
||||
private final ExecutorService executor;
|
||||
public ChoiceBox<UiTheme> themeChoiceBox;
|
||||
public CheckBox startHiddenCheckbox;
|
||||
public CheckBox debugModeCheckbox;
|
||||
public CheckBox autoStartCheckbox;
|
||||
public ToggleGroup nodeOrientation;
|
||||
public RadioButton nodeOrientationLtr;
|
||||
public RadioButton nodeOrientationRtl;
|
||||
|
||||
@Inject
|
||||
GeneralPreferencesController(Settings settings, @Named("trayMenuSupported") boolean trayMenuSupported, Optional<AutoStartStrategy> autoStartStrategy, ObjectProperty<SelectedPreferencesTab> selectedTabProperty, LicenseHolder licenseHolder, ExecutorService executor) {
|
||||
this.settings = settings;
|
||||
this.trayMenuSupported = trayMenuSupported;
|
||||
this.autoStartStrategy = autoStartStrategy;
|
||||
this.selectedTabProperty = selectedTabProperty;
|
||||
this.licenseHolder = licenseHolder;
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
themeChoiceBox.getItems().addAll(UiTheme.values());
|
||||
themeChoiceBox.valueProperty().bindBidirectional(settings.theme());
|
||||
themeChoiceBox.setConverter(new UiThemeConverter());
|
||||
|
||||
startHiddenCheckbox.selectedProperty().bindBidirectional(settings.startHidden());
|
||||
|
||||
debugModeCheckbox.selectedProperty().bindBidirectional(settings.debugMode());
|
||||
|
||||
autoStartStrategy.ifPresent(autoStart -> {
|
||||
autoStart.isAutoStartEnabled().thenAccept(enabled -> {
|
||||
Platform.runLater(() -> autoStartCheckbox.setSelected(enabled));
|
||||
});
|
||||
});
|
||||
|
||||
nodeOrientationLtr.setSelected(settings.userInterfaceOrientation().get() == NodeOrientation.LEFT_TO_RIGHT);
|
||||
nodeOrientationRtl.setSelected(settings.userInterfaceOrientation().get() == NodeOrientation.RIGHT_TO_LEFT);
|
||||
nodeOrientation.selectedToggleProperty().addListener(this::toggleNodeOrientation);
|
||||
}
|
||||
|
||||
public boolean isTrayMenuSupported() {
|
||||
return this.trayMenuSupported;
|
||||
}
|
||||
|
||||
public boolean isAutoStartSupported() {
|
||||
return autoStartStrategy.isPresent();
|
||||
}
|
||||
|
||||
private void toggleNodeOrientation(@SuppressWarnings("unused") ObservableValue<? extends Toggle> observable, @SuppressWarnings("unused") Toggle oldValue, Toggle newValue) {
|
||||
if (nodeOrientationLtr.equals(newValue)) {
|
||||
settings.userInterfaceOrientation().set(NodeOrientation.LEFT_TO_RIGHT);
|
||||
} else if (nodeOrientationRtl.equals(newValue)) {
|
||||
settings.userInterfaceOrientation().set(NodeOrientation.RIGHT_TO_LEFT);
|
||||
} else {
|
||||
LOG.warn("Unexpected toggle option {}", newValue);
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void toggleAutoStart() {
|
||||
autoStartStrategy.ifPresent(autoStart -> {
|
||||
boolean enableAutoStart = autoStartCheckbox.isSelected();
|
||||
Task<Void> toggleTask = new ToggleAutoStartTask(autoStart, enableAutoStart);
|
||||
toggleTask.setOnFailed(evt -> autoStartCheckbox.setSelected(!enableAutoStart)); // restore previous state
|
||||
executor.execute(toggleTask);
|
||||
});
|
||||
}
|
||||
|
||||
public LicenseHolder getLicenseHolder() {
|
||||
return licenseHolder;
|
||||
}
|
||||
|
||||
|
||||
@FXML
|
||||
public void showDonationTab() {
|
||||
selectedTabProperty.set(SelectedPreferencesTab.DONATION_KEY);
|
||||
}
|
||||
|
||||
/* Helper classes */
|
||||
|
||||
private static class UiThemeConverter extends StringConverter<UiTheme> {
|
||||
|
||||
@Override
|
||||
public String toString(UiTheme impl) {
|
||||
return impl.getDisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UiTheme fromString(String string) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private static class ToggleAutoStartTask extends Task<Void> {
|
||||
|
||||
private final AutoStartStrategy autoStart;
|
||||
private final boolean enable;
|
||||
|
||||
public ToggleAutoStartTask(AutoStartStrategy autoStart, boolean enable) {
|
||||
this.autoStart = autoStart;
|
||||
this.enable = enable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void call() throws Exception {
|
||||
if (enable) {
|
||||
autoStart.enableAutoStart();
|
||||
} else {
|
||||
autoStart.disableAutoStart();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package org.cryptomator.ui.traymenu;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.jni.MacApplicationUiAppearance;
|
||||
import org.cryptomator.jni.MacApplicationUiInterfaceStyle;
|
||||
import org.cryptomator.jni.MacFunctions;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.awt.Image;
|
||||
import java.awt.Toolkit;
|
||||
import java.util.Optional;
|
||||
|
||||
@TrayMenuScoped
|
||||
class TrayImageFactory {
|
||||
|
||||
private final Optional<MacFunctions> macFunctions;
|
||||
|
||||
@Inject
|
||||
TrayImageFactory(Optional<MacFunctions> macFunctions) {
|
||||
this.macFunctions = macFunctions;
|
||||
}
|
||||
|
||||
public Image loadImage() {
|
||||
String resourceName = SystemUtils.IS_OS_MAC_OSX ? getMacResourceName() : getWinOrLinuxResourceName();
|
||||
return Toolkit.getDefaultToolkit().getImage(getClass().getResource(resourceName));
|
||||
}
|
||||
|
||||
private String getMacResourceName() {
|
||||
MacApplicationUiInterfaceStyle interfaceStyle = macFunctions.map(MacFunctions::uiAppearance) //
|
||||
.map(MacApplicationUiAppearance::getCurrentInterfaceStyle) //
|
||||
.orElse(MacApplicationUiInterfaceStyle.LIGHT);
|
||||
switch (interfaceStyle) {
|
||||
case DARK:
|
||||
return "/tray_icon_mac_white.png";
|
||||
default:
|
||||
return "/tray_icon_mac_black.png";
|
||||
}
|
||||
}
|
||||
|
||||
private String getWinOrLinuxResourceName() {
|
||||
return "/tray_icon.png";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,29 +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.ui.traymenu;
|
||||
|
||||
import dagger.Subcomponent;
|
||||
|
||||
import java.awt.SystemTray;
|
||||
|
||||
@TrayMenuScoped
|
||||
@Subcomponent
|
||||
public interface TrayMenuComponent {
|
||||
|
||||
TrayIconController trayIconController();
|
||||
|
||||
default void addIconToSystemTray() {
|
||||
assert SystemTray.isSupported();
|
||||
trayIconController().initializeTrayIcon();
|
||||
}
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
|
||||
TrayMenuComponent build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
package org.cryptomator.ui.unlock;
|
||||
|
||||
import dagger.Lazy;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.ObjectBinding;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.ReadOnlyBooleanProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.ContentDisplay;
|
||||
import javafx.stage.Stage;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.common.vaults.VaultState;
|
||||
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
|
||||
import org.cryptomator.keychain.KeychainAccess;
|
||||
import org.cryptomator.keychain.KeychainAccessException;
|
||||
import org.cryptomator.ui.common.Animations;
|
||||
import org.cryptomator.ui.common.ErrorComponent;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.common.VaultService;
|
||||
import org.cryptomator.ui.controls.NiceSecurePasswordField;
|
||||
import org.cryptomator.ui.forgetPassword.ForgetPasswordComponent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import java.nio.file.DirectoryNotEmptyException;
|
||||
import java.nio.file.NotDirectoryException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
@UnlockScoped
|
||||
public class UnlockController implements FxController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(UnlockController.class);
|
||||
|
||||
private final Stage window;
|
||||
private final Vault vault;
|
||||
private final ExecutorService executor;
|
||||
private final ObjectBinding<ContentDisplay> unlockButtonState;
|
||||
private final Optional<KeychainAccess> keychainAccess;
|
||||
private final VaultService vaultService;
|
||||
private final Lazy<Scene> successScene;
|
||||
private final Lazy<Scene> invalidMountPointScene;
|
||||
private final ErrorComponent.Builder errorComponent;
|
||||
private final ForgetPasswordComponent.Builder forgetPassword;
|
||||
private final BooleanProperty unlockButtonDisabled;
|
||||
public NiceSecurePasswordField passwordField;
|
||||
public CheckBox savePassword;
|
||||
|
||||
@Inject
|
||||
public UnlockController(@UnlockWindow Stage window, @UnlockWindow Vault vault, ExecutorService executor, Optional<KeychainAccess> keychainAccess, VaultService vaultService, @FxmlScene(FxmlFile.UNLOCK_SUCCESS) Lazy<Scene> successScene, @FxmlScene(FxmlFile.UNLOCK_INVALID_MOUNT_POINT) Lazy<Scene> invalidMountPointScene, ErrorComponent.Builder errorComponent, ForgetPasswordComponent.Builder forgetPassword) {
|
||||
this.window = window;
|
||||
this.vault = vault;
|
||||
this.executor = executor;
|
||||
this.unlockButtonState = Bindings.createObjectBinding(this::getUnlockButtonState, vault.stateProperty());
|
||||
this.keychainAccess = keychainAccess;
|
||||
this.vaultService = vaultService;
|
||||
this.successScene = successScene;
|
||||
this.invalidMountPointScene = invalidMountPointScene;
|
||||
this.errorComponent = errorComponent;
|
||||
this.forgetPassword = forgetPassword;
|
||||
this.unlockButtonDisabled = new SimpleBooleanProperty();
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
if (keychainAccess.isPresent()) {
|
||||
loadStoredPassword();
|
||||
} else {
|
||||
savePassword.setDisable(true);
|
||||
}
|
||||
unlockButtonDisabled.bind(vault.stateProperty().isNotEqualTo(VaultState.LOCKED).or(passwordField.textProperty().isEmpty()));
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void cancel() {
|
||||
LOG.debug("Unlock canceled by user.");
|
||||
window.close();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void unlock() {
|
||||
LOG.trace("UnlockController.unlock()");
|
||||
CharSequence password = passwordField.getCharacters();
|
||||
|
||||
Task<Vault> task = vaultService.createUnlockTask(vault, password);
|
||||
task.setOnSucceeded(event -> {
|
||||
if (keychainAccess.isPresent() && savePassword.isSelected()) {
|
||||
try {
|
||||
keychainAccess.get().storePassphrase(vault.getId(), password);
|
||||
} catch (KeychainAccessException e) {
|
||||
LOG.error("Failed to store passphrase in system keychain.", e);
|
||||
}
|
||||
}
|
||||
passwordField.swipe();
|
||||
LOG.info("Unlock of '{}' succeeded.", vault.getDisplayableName());
|
||||
window.setScene(successScene.get());
|
||||
});
|
||||
task.setOnFailed(event -> {
|
||||
if (task.getException() instanceof InvalidPassphraseException) {
|
||||
Animations.createShakeWindowAnimation(window).play();
|
||||
passwordField.selectAll();
|
||||
passwordField.requestFocus();
|
||||
} else if (task.getException() instanceof NotDirectoryException
|
||||
|| task.getException() instanceof DirectoryNotEmptyException) {
|
||||
LOG.error("Unlock failed. Mount point not an empty directory: {}", task.getException().getMessage());
|
||||
window.setScene(invalidMountPointScene.get());
|
||||
} else {
|
||||
LOG.error("Unlock failed for technical reasons.", task.getException());
|
||||
errorComponent.cause(task.getException()).window(window).returnToScene(window.getScene()).build().showErrorScene();
|
||||
}
|
||||
});
|
||||
executor.execute(task);
|
||||
}
|
||||
|
||||
/* Save Password */
|
||||
|
||||
@FXML
|
||||
private void didClickSavePasswordCheckbox() {
|
||||
if (!savePassword.isSelected() && hasStoredPassword()) {
|
||||
forgetPassword.vault(vault).owner(window).build().showForgetPassword().thenAccept(forgotten -> savePassword.setSelected(!forgotten));
|
||||
}
|
||||
}
|
||||
|
||||
private void loadStoredPassword() {
|
||||
assert keychainAccess.isPresent();
|
||||
char[] storedPw = null;
|
||||
try {
|
||||
storedPw = keychainAccess.get().loadPassphrase(vault.getId());
|
||||
if (storedPw != null) {
|
||||
savePassword.setSelected(true);
|
||||
passwordField.setPassword(storedPw);
|
||||
passwordField.selectRange(storedPw.length, storedPw.length);
|
||||
}
|
||||
} catch (KeychainAccessException e) {
|
||||
LOG.error("Failed to load entry from system keychain.", e);
|
||||
} finally {
|
||||
if (storedPw != null) {
|
||||
Arrays.fill(storedPw, ' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasStoredPassword() {
|
||||
char[] storedPw = null;
|
||||
try {
|
||||
storedPw = keychainAccess.get().loadPassphrase(vault.getId());
|
||||
return storedPw != null;
|
||||
} catch (KeychainAccessException e) {
|
||||
return false;
|
||||
} finally {
|
||||
if (storedPw != null) {
|
||||
Arrays.fill(storedPw, ' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Getter/Setter */
|
||||
|
||||
public Vault getVault() {
|
||||
return vault;
|
||||
}
|
||||
|
||||
public ObjectBinding<ContentDisplay> unlockButtonStateProperty() {
|
||||
return unlockButtonState;
|
||||
}
|
||||
|
||||
public ContentDisplay getUnlockButtonState() {
|
||||
switch (vault.getState()) {
|
||||
case PROCESSING:
|
||||
return ContentDisplay.LEFT;
|
||||
default:
|
||||
return ContentDisplay.TEXT_ONLY;
|
||||
}
|
||||
}
|
||||
|
||||
public ReadOnlyBooleanProperty unlockButtonDisabledProperty() {
|
||||
return unlockButtonDisabled;
|
||||
}
|
||||
|
||||
public boolean isUnlockButtonDisabled() {
|
||||
return unlockButtonDisabled.get();
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package org.cryptomator.ui.unlock;
|
||||
|
||||
import dagger.Lazy;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@UnlockScoped
|
||||
public class UnlockInvalidMountPointController implements FxController {
|
||||
|
||||
private final Stage window;
|
||||
private final Lazy<Scene> unlockScene;
|
||||
private final Vault vault;
|
||||
|
||||
@Inject
|
||||
UnlockInvalidMountPointController(@UnlockWindow Stage window, @FxmlScene(FxmlFile.UNLOCK) Lazy<Scene> unlockScene, @UnlockWindow Vault vault) {
|
||||
this.window = window;
|
||||
this.unlockScene = unlockScene;
|
||||
this.vault = vault;
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void back() {
|
||||
window.setScene(unlockScene.get());
|
||||
}
|
||||
|
||||
/* Getter/Setter */
|
||||
|
||||
public String getMountPoint() {
|
||||
return vault.getVaultSettings().getIndividualMountPath().orElse("AUTO");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package org.cryptomator.ui.vaultoptions;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@VaultOptionsScoped
|
||||
public class GeneralVaultOptionsController implements FxController {
|
||||
|
||||
private final Vault vault;
|
||||
public CheckBox unlockOnStartupCheckbox;
|
||||
|
||||
@Inject
|
||||
GeneralVaultOptionsController(@VaultOptionsWindow Vault vault) {
|
||||
this.vault = vault;
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
unlockOnStartupCheckbox.selectedProperty().bindBidirectional(vault.getVaultSettings().unlockAfterStartup());
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
package org.cryptomator.ui.vaultoptions;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.stage.Stage;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.changepassword.ChangePasswordComponent;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.recoverykey.RecoveryKeyComponent;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@VaultOptionsScoped
|
||||
public class MasterkeyOptionsController implements FxController {
|
||||
|
||||
private final Vault vault;
|
||||
private final Stage window;
|
||||
private final ChangePasswordComponent.Builder changePasswordWindow;
|
||||
private final RecoveryKeyComponent.Builder recoveryKeyWindow;
|
||||
|
||||
@Inject
|
||||
MasterkeyOptionsController(@VaultOptionsWindow Vault vault, @VaultOptionsWindow Stage window, ChangePasswordComponent.Builder changePasswordWindow, RecoveryKeyComponent.Builder recoveryKeyWindow) {
|
||||
this.vault = vault;
|
||||
this.window = window;
|
||||
this.changePasswordWindow = changePasswordWindow;
|
||||
this.recoveryKeyWindow = recoveryKeyWindow;
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void changePassword() {
|
||||
changePasswordWindow.vault(vault).owner(window).build().showChangePasswordWindow();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void showRecoveryKey() {
|
||||
recoveryKeyWindow.vault(vault).owner(window).build().showRecoveryKeyCreationWindow();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void showRecoverVaultDialogue() {
|
||||
recoveryKeyWindow.vault(vault).owner(window).build().showRecoveryKeyRecoverWindow();
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package org.cryptomator.ui.vaultoptions;
|
||||
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@VaultOptionsScoped
|
||||
public class VaultOptionsController implements FxController {
|
||||
|
||||
@Inject
|
||||
VaultOptionsController() {}
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.ButtonBar?>
|
||||
<?import javafx.scene.control.CheckBox?>
|
||||
<?import javafx.scene.control.ProgressIndicator?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import org.cryptomator.ui.controls.FormattedLabel?>
|
||||
<?import org.cryptomator.ui.controls.NiceSecurePasswordField?>
|
||||
<VBox xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
fx:controller="org.cryptomator.ui.unlock.UnlockController"
|
||||
minWidth="400"
|
||||
maxWidth="400"
|
||||
minHeight="145"
|
||||
spacing="12">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<VBox spacing="6">
|
||||
<FormattedLabel format="%unlock.passwordPrompt" arg1="${controller.vault.displayableName}" wrapText="true"/>
|
||||
<NiceSecurePasswordField fx:id="passwordField"/>
|
||||
<CheckBox fx:id="savePassword" text="%unlock.savePassword" onAction="#didClickSavePasswordCheckbox"/>
|
||||
</VBox>
|
||||
|
||||
<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+CI">
|
||||
<buttons>
|
||||
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#cancel"/>
|
||||
<Button text="%unlock.unlockBtn" ButtonBar.buttonData="FINISH" defaultButton="true" onAction="#unlock" contentDisplay="${controller.unlockButtonState}" disable="${controller.unlockButtonDisabled}">
|
||||
<graphic>
|
||||
<ProgressIndicator progress="-1" prefWidth="12" prefHeight="12"/>
|
||||
</graphic>
|
||||
</Button>
|
||||
</buttons>
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
</children>
|
||||
</VBox>
|
||||
@@ -1,28 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.Hyperlink?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
|
||||
<VBox xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
fx:controller="org.cryptomator.ui.mainwindow.VaultDetailLockedController"
|
||||
alignment="TOP_CENTER"
|
||||
spacing="9">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="24"/>
|
||||
</padding>
|
||||
<children>
|
||||
<Button styleClass="button-large" text="%main.vaultDetail.unlockBtn" minWidth="120" onAction="#unlock" defaultButton="${controller.vault.locked}">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="KEY" glyphSize="15"/>
|
||||
</graphic>
|
||||
</Button>
|
||||
<Hyperlink text="%main.vaultDetail.optionsBtn" onAction="#showVaultOptions">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="COG"/>
|
||||
</graphic>
|
||||
</Hyperlink>
|
||||
</children>
|
||||
</VBox>
|
||||
@@ -1,28 +0,0 @@
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.Circle?>
|
||||
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
|
||||
<VBox xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
fx:controller="org.cryptomator.ui.mainwindow.VaultDetailMissingVaultController"
|
||||
alignment="TOP_CENTER"
|
||||
spacing="9">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="24"/>
|
||||
</padding>
|
||||
<children>
|
||||
<StackPane alignment="CENTER">
|
||||
<Circle styleClass="glyph-icon-primary" radius="48"/>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="FILE" glyphSize="48"/>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-primary" glyph="SEARCH" glyphSize="24">
|
||||
<StackPane.margin>
|
||||
<Insets top="12"/>
|
||||
</StackPane.margin>
|
||||
</FontAwesome5IconView>
|
||||
</StackPane>
|
||||
|
||||
<Label text="%main.vaultDetail.missing.info" wrapText="true"/>
|
||||
</children>
|
||||
</VBox>
|
||||
@@ -1,16 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.CheckBox?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<VBox xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
fx:controller="org.cryptomator.ui.vaultoptions.GeneralVaultOptionsController"
|
||||
spacing="6">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<CheckBox text="%vaultOptions.general.unlockAfterStartup" fx:id="unlockOnStartupCheckbox"/>
|
||||
</children>
|
||||
</VBox>
|
||||
@@ -1,122 +0,0 @@
|
||||
# Locale Specific CSS files such as CJK, RTL,...
|
||||
|
||||
# Generics
|
||||
## Button
|
||||
generic.button.apply=طبّق
|
||||
generic.button.back=الى الوراء
|
||||
generic.button.cancel=الغاء
|
||||
generic.button.change=تغيير
|
||||
generic.button.done=تم
|
||||
generic.button.next=التالي
|
||||
## Error
|
||||
|
||||
# Tray Menu
|
||||
traymenu.showMainWindow=اظهار
|
||||
traymenu.showPreferencesWindow=تفضيلات
|
||||
traymenu.quitApplication=انهاء
|
||||
traymenu.vault.unlock=افتح
|
||||
traymenu.vault.lock=قفل
|
||||
traymenu.vault.reveal=إظهار
|
||||
|
||||
# Add Vault Wizard
|
||||
addvaultwizard.title=أضِف مخزنًا
|
||||
## Welcome
|
||||
addvaultwizard.welcome.newButton=إنشاء مخزن جديد
|
||||
addvaultwizard.welcome.existingButton=افتح مخزن موجود
|
||||
## New
|
||||
### Name
|
||||
addvaultwizard.new.nameInstruction=اختر اسم للمخزن
|
||||
addvaultwizard.new.namePrompt=اسم المخزن
|
||||
### Location
|
||||
addvaultwizard.new.locationInstruction=أين يجب على Cryptomator تخزين الملفات المشفرة من قبو الخاص بك؟
|
||||
addvaultwizard.new.locationLabel=موقع التخزين
|
||||
addvaultwizard.new.locationPrompt=…
|
||||
addvaultwizard.new.directoryPickerLabel=موقع مخصص
|
||||
addvaultwizard.new.directoryPickerButton=اختر…
|
||||
addvaultwizard.new.directoryPickerTitle=اختر القاموس
|
||||
addvaultwizard.new.fileAlreadyExists=لا يمكن إنشاء مخزن على هذا المسار لأن بعض الملفات موجودة مسبقا.
|
||||
addvaultwizard.new.invalidName=اسم المخزن غير صالح. يرجى النظر في اسم الدليل المعتاد.
|
||||
### Password
|
||||
addvaultwizard.new.createVaultBtn=انشئ حافظة
|
||||
### Information
|
||||
## Existing
|
||||
addvaultwizard.existing.chooseBtn=اختر…
|
||||
## Success
|
||||
addvaultwizard.success.unlockNow=افتح الان
|
||||
|
||||
# Remove Vault
|
||||
removeVault.title=احذف الحافظة
|
||||
removeVault.confirmBtn=احذف الحافظة
|
||||
|
||||
# Change Password
|
||||
|
||||
# Forget Password
|
||||
forgetPassword.title=نسيت كلمة المرور
|
||||
forgetPassword.confirmBtn=نسيت كلمة المرور
|
||||
|
||||
# Unlock
|
||||
unlock.title=افتح الحافظة
|
||||
unlock.savePassword=احفظ كلمة المرور
|
||||
unlock.unlockBtn=افتح
|
||||
## Success
|
||||
unlock.success.revealBtn=افتح الحافظة
|
||||
## Invalid Mount Point
|
||||
|
||||
# Migration
|
||||
migration.title=ترقية الحافظة
|
||||
## Start
|
||||
migration.start.confirm=نعم, محفظتي متزامنة بالكامل
|
||||
## Run
|
||||
migration.run.startMigrationBtn=ترقية الحافظة
|
||||
## Sucess
|
||||
migration.success.unlockNow=افتح الان
|
||||
## Missing file system capabilities
|
||||
|
||||
# Preferences
|
||||
preferences.title=تفضيلات
|
||||
## General
|
||||
preferences.general=عام
|
||||
## Volume
|
||||
preferences.volume.webdav.port=منفذ WebDav
|
||||
## Updates
|
||||
preferences.updates=تحديثات
|
||||
preferences.updates.autoUpdateCheck=تحقق من التحديثات اوتوماتيكيا
|
||||
preferences.updates.checkNowBtn=تحقق الان
|
||||
## Donation Key
|
||||
## About
|
||||
|
||||
# Main Window
|
||||
main.preferencesBtn.tooltip=تفضيلات
|
||||
## Drag 'n' Drop
|
||||
## Vault List
|
||||
main.vaultlist.contextMenu.remove=احذف الحافظة
|
||||
main.vaultlist.addVaultBtn=أضِف مخزنًا
|
||||
## Vault Detail
|
||||
### Welcome
|
||||
### Locked
|
||||
main.vaultDetail.lockedStatus=مغلق
|
||||
main.vaultDetail.unlockBtn=افتح
|
||||
### Unlocked
|
||||
main.vaultDetail.unlockedStatus=مفتوح
|
||||
main.vaultDetail.lockBtn=قفل
|
||||
### Missing
|
||||
### Needs Migration
|
||||
main.vaultDetail.migrateButton=ترقية الحافظة
|
||||
|
||||
# Wrong File Alert
|
||||
|
||||
# Vault Options
|
||||
## General
|
||||
vaultOptions.general=عام
|
||||
## Mount
|
||||
vaultOptions.mount.mountPoint.directoryPickerButton=اختر…
|
||||
## Master Key
|
||||
|
||||
# Recovery Key
|
||||
|
||||
# New Password
|
||||
newPassword.reenterPassword=تأكيد كلمة المرور الجديدة
|
||||
newPassword.passwordsMatch=كلمات المرور متطابقة!
|
||||
newPassword.passwordsDoNotMatch=كلمات المرور غير متطابقة
|
||||
|
||||
# Quit
|
||||
@@ -1,241 +0,0 @@
|
||||
# Locale Specific CSS files such as CJK, RTL,...
|
||||
|
||||
# Generics
|
||||
## Button
|
||||
generic.button.apply=Übernehmen
|
||||
generic.button.back=Zurück
|
||||
generic.button.cancel=Abbrechen
|
||||
generic.button.change=Ändern
|
||||
generic.button.close=Schließen
|
||||
generic.button.copy=Kopieren
|
||||
generic.button.copied=Kopiert!
|
||||
generic.button.done=Fertig
|
||||
generic.button.next=Weiter
|
||||
generic.button.print=Drucken
|
||||
## Error
|
||||
generic.error.title=Ein unerwarteter Fehler ist aufgetreten
|
||||
generic.error.instruction=Dies hätte nicht passieren dürfen. Bitte melde den Fehlertext unten und füge eine Beschreibung hinzu, welche Schritte zu diesem Fehler geführt haben.
|
||||
|
||||
# Tray Menu
|
||||
traymenu.showMainWindow=Anzeigen
|
||||
traymenu.showPreferencesWindow=Einstellungen
|
||||
traymenu.lockAllVaults=Alle sperren
|
||||
traymenu.quitApplication=Beenden
|
||||
traymenu.vault.unlock=Entsperren
|
||||
traymenu.vault.lock=Sperren
|
||||
traymenu.vault.reveal=Anzeigen
|
||||
|
||||
# Add Vault Wizard
|
||||
addvaultwizard.title=Tresor hinzufügen
|
||||
## Welcome
|
||||
addvaultwizard.welcome.newButton=Neuen Tresor erstellen
|
||||
addvaultwizard.welcome.existingButton=Existierenden Tresor öffnen
|
||||
## New
|
||||
### Name
|
||||
addvaultwizard.new.nameInstruction=Wähle einen Namen für den Tresor
|
||||
addvaultwizard.new.namePrompt=Tresorname
|
||||
### Location
|
||||
addvaultwizard.new.locationInstruction=Wo soll Cryptomator die verschlüsselten Daten deines Tresors ablegen?
|
||||
addvaultwizard.new.locationLabel=Speicherort
|
||||
addvaultwizard.new.locationPrompt=…
|
||||
addvaultwizard.new.directoryPickerLabel=Eigener Ort
|
||||
addvaultwizard.new.directoryPickerButton=Durchsuchen …
|
||||
addvaultwizard.new.directoryPickerTitle=Verzeichnis auswählen
|
||||
addvaultwizard.new.fileAlreadyExists=Der Tresor konnte nicht erstellt werden, da der Speicherort bereits belegt ist.
|
||||
addvaultwizard.new.invalidName=Ungültiger Tresorname. Tresore müssen wie Verzeichnisse benannt werden.
|
||||
### Password
|
||||
addvaultwizard.new.createVaultBtn=Tresor erstellen
|
||||
addvaultwizard.new.generateRecoveryKeyChoice=Ohne dieses Passwort kannst du auf deine Daten nicht mehr zugreifen. Möchtest du für den Fall eines Passwortverlusts einen Wiederherstellungsschlüssel erstellen?
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.yes=Ja bitte, sicher ist sicher
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.no=Nein danke, ich werde mein Passwort nicht verlieren
|
||||
### Information
|
||||
addvault.new.readme.storageLocation.fileName=WICHTIG.rtf
|
||||
addvault.new.readme.storageLocation.1=⚠️ TRESOR-DATEIEN ⚠️
|
||||
addvault.new.readme.storageLocation.2=Dies ist der Speicherort deines Tresors.
|
||||
addvault.new.readme.storageLocation.3=NICHT
|
||||
addvault.new.readme.storageLocation.4=• in diesem Verzeichnis Dateien ändern oder
|
||||
addvault.new.readme.storageLocation.5=• zu verschlüsselnde Dateien in diesem Verzeichnis ablegen.
|
||||
addvault.new.readme.storageLocation.6=Falls du Dateien verschlüsseln und den Inhalt des Tresors anzeigen möchtest, befolge folgende Schritte:
|
||||
addvault.new.readme.storageLocation.7=1. Füge diesen Tresor zu Cryptomator hinzu.
|
||||
addvault.new.readme.storageLocation.8=2. Entsperre den Tresor in Cryptomator.
|
||||
addvault.new.readme.storageLocation.9=3. Öffne den Zugangsort durch Klicken auf die Schaltfläche „Anzeigen“.
|
||||
addvault.new.readme.storageLocation.10=Falls du Hilfe brauchst, lies die Dokumentation: %s
|
||||
addvault.new.readme.accessLocation.fileName=WILLKOMMEN.rtf
|
||||
addvault.new.readme.accessLocation.1=🔐️ VERSCHLÜSSELTES LAUFWERK 🔐️
|
||||
addvault.new.readme.accessLocation.2=Dies ist der Zugangsort deines Tresors.
|
||||
addvault.new.readme.accessLocation.3=Alle zu diesem Laufwerk hinzugefügten Dateien werden von Cryptomator verschlüsselt. Du kannst mit diesem arbeiten wie mit jedem anderen Laufwerk bzw. Ordner. Dies ist lediglich eine unverschlüsselte Ansicht des Laufwerkinhalts; auf deiner Festplatte bleiben deine Dateien weiterhin verschlüsselt.
|
||||
addvault.new.readme.accessLocation.4=Diese Datei kannst du löschen.
|
||||
## Existing
|
||||
addvaultwizard.existing.instruction=Wähle die Datei „masterkey.cryptomator“ deines vorhandenen Tresors aus.
|
||||
addvaultwizard.existing.chooseBtn=Durchsuchen …
|
||||
addvaultwizard.existing.filePickerTitle=Masterkey-Datei auswählen
|
||||
## Success
|
||||
addvaultwizard.success.nextStepsInstructions=Tresor „%s“ hinzugefügt.\nUm auf Inhalte zuzugreifen oder welche hinzuzufügen, musst du den Tresor entsperren. Du kannst ihn aber auch zu jedem späteren Zeitpunkt entsperren.
|
||||
addvaultwizard.success.unlockNow=Jetzt entsperren
|
||||
|
||||
# Remove Vault
|
||||
removeVault.title=Tresor entfernen
|
||||
removeVault.information=Dein Tresor wird nicht gelöscht, sondern lediglich aus Cryptomators Tresorliste entfernt. Du kannst ihn daher später jederzeit wieder hinzufügen.
|
||||
removeVault.confirmBtn=Tresor entfernen
|
||||
|
||||
# Change Password
|
||||
changepassword.title=Password ändern
|
||||
changepassword.enterOldPassword=Gib dein aktuelles Passwort für „%s“ ein
|
||||
changepassword.finalConfirmation=Mir ist bewusst, dass ich den Tresor ohne das Passwort NICHT mehr öffnen kann
|
||||
|
||||
# Forget Password
|
||||
forgetPassword.title=Passwort vergessen
|
||||
forgetPassword.information=Dies löscht das gespeicherte Passwort dieses Tresors aus dem Schlüsselbund deines Betriebssystems.
|
||||
forgetPassword.confirmBtn=Passwort vergessen
|
||||
|
||||
# Unlock
|
||||
unlock.title=Tresor entsperren
|
||||
unlock.passwordPrompt=Gib das Passwort für „%s“ ein:
|
||||
unlock.savePassword=Passwort speichern
|
||||
unlock.unlockBtn=Entsperren
|
||||
## Success
|
||||
unlock.success.message=„%s“ erfolgreich entsperrt! Nun kannst du auf deinen Tresor zugreifen.
|
||||
unlock.success.revealBtn=Tresor anzeigen
|
||||
## Invalid Mount Point
|
||||
unlock.error.invalidMountPoint=Einhängepunkt ist kein leeres Verzeichnis: %s
|
||||
|
||||
# Migration
|
||||
migration.title=Tresor aktualisieren
|
||||
## Start
|
||||
migration.start.prompt=Dein Tresor „%s“ muss auf ein neueres Format aktualisiert werden. Stell bitte zuvor sicher, dass dieser Tresor vollständig synchronisiert ist.
|
||||
migration.start.confirm=Ja, mein Tresor ist vollständig synchronisiert
|
||||
## Run
|
||||
migration.run.enterPassword=Gib das Passwort für „%s“ ein
|
||||
migration.run.startMigrationBtn=Tresor migrieren
|
||||
## Sucess
|
||||
migration.success.nextStepsInstructions=„%s“ erfolgreich migriert.\nDu kannst deinen Tresor jetzt entsperren.
|
||||
migration.success.unlockNow=Jetzt entsperren
|
||||
## Missing file system capabilities
|
||||
migration.error.missingFileSystemCapabilities.title=Nicht unterstütztes Dateisystem
|
||||
migration.error.missingFileSystemCapabilities.description=Die Migration wurde nicht gestartet, da sich dein Tresor auf einem ungeeigneten Dateisystem befindet.
|
||||
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=Das Dateisystem unterstützt keine langen Dateinamen.
|
||||
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=Das Dateisystem unterstützt keine langen Pfadnamen.
|
||||
|
||||
# Preferences
|
||||
preferences.title=Einstellungen
|
||||
## General
|
||||
preferences.general=Allgemein
|
||||
preferences.general.theme=Erscheinungsbild
|
||||
preferences.general.unlockThemes=Dunklen Modus freischalten
|
||||
preferences.general.startHidden=Cryptomator im Hintergrund starten
|
||||
preferences.general.debugLogging=Diagnoseprotokoll aktivieren
|
||||
preferences.general.autoStart=Cryptomator beim Systemstart starten
|
||||
preferences.general.interfaceOrientation=Oberflächenausrichtung
|
||||
preferences.general.interfaceOrientation.ltr=Von links nach rechts
|
||||
preferences.general.interfaceOrientation.rtl=Von rechts nach links
|
||||
## Volume
|
||||
preferences.volume=Tresorlaufwerk
|
||||
preferences.volume.type=Laufwerkstyp
|
||||
preferences.volume.webdav.port=WebDAV-Port
|
||||
preferences.volume.webdav.scheme=WebDAV-Schema
|
||||
## Updates
|
||||
preferences.updates=Updates
|
||||
preferences.updates.currentVersion=Aktuelle Version: %s
|
||||
preferences.updates.autoUpdateCheck=Automatisch nach Updates suchen
|
||||
preferences.updates.checkNowBtn=Jetzt suchen
|
||||
preferences.updates.updateAvailable=Update auf Version %s verfügbar.
|
||||
## Donation Key
|
||||
preferences.donationKey=Spende
|
||||
preferences.donationKey.registeredFor=Registriert für %s
|
||||
preferences.donationKey.noDonationKey=Kein gültiger Spendenschlüssel gefunden. Er ist wie ein Lizenzschlüssel, aber für tolle Leute, die freie Software verwenden. ;-)
|
||||
preferences.donationKey.getDonationKey=Einen Spendenschlüssel erhalten
|
||||
## About
|
||||
preferences.about=Über
|
||||
|
||||
# Main Window
|
||||
main.closeBtn.tooltip=Schließen
|
||||
main.minimizeBtn.tooltip=Minimieren
|
||||
main.preferencesBtn.tooltip=Einstellungen
|
||||
main.donationKeyMissing.tooltip=Bitte denke über eine Spende nach
|
||||
## Drag 'n' Drop
|
||||
main.dropZone.dropVault=Diesen Tresor hinzufügen
|
||||
main.dropZone.unknownDragboardContent=Wenn Sie einen Tresor hinzufügen möchten, ziehen Sie ihn in dieses Fenster
|
||||
## Vault List
|
||||
main.vaultlist.emptyList.onboardingInstruction=Klicke hier, um einen Tresor hinzuzufügen
|
||||
main.vaultlist.contextMenu.remove=Tresor entfernen
|
||||
main.vaultlist.addVaultBtn=Tresor hinzufügen
|
||||
## Vault Detail
|
||||
### Welcome
|
||||
main.vaultDetail.welcomeOnboarding=Danke, dass du zum Schützen deiner Dateien Cryptomator gewählt hast. Falls du Hilfe brauchst, schau dir unsere Anleitungen an:
|
||||
### Locked
|
||||
main.vaultDetail.lockedStatus=GESPERRT
|
||||
main.vaultDetail.unlockBtn=Entsperren
|
||||
main.vaultDetail.optionsBtn=Tresoroptionen
|
||||
### Unlocked
|
||||
main.vaultDetail.unlockedStatus=ENTSPERRT
|
||||
main.vaultDetail.accessLocation=Dein Tresorinhalt ist hier erreichbar:
|
||||
main.vaultDetail.revealBtn=Laufwerk anzeigen
|
||||
main.vaultDetail.lockBtn=Sperren
|
||||
main.vaultDetail.bytesPerSecondRead=gelesen:
|
||||
main.vaultDetail.bytesPerSecondWritten=geschrieben:
|
||||
main.vaultDetail.throughput.idle=Leerlauf
|
||||
main.vaultDetail.throughput.kbps=%.1f kiB/s
|
||||
main.vaultDetail.throughput.mbps=%.1f MiB/s
|
||||
### Missing
|
||||
main.vaultDetail.missing.info=Mit diesem Pfad konnte Cryptomator keinen Tresor finden.
|
||||
### Needs Migration
|
||||
main.vaultDetail.migrateButton=Tresor aktualisieren
|
||||
main.vaultDetail.migratePrompt=Dein Tresor muss auf ein neues Format aktualisiert werden, bevor Du auf ihn zugreifen kannst
|
||||
|
||||
# Wrong File Alert
|
||||
wrongFileAlert.title=Verschlüsseln von Dateien
|
||||
wrongFileAlert.header.title=Hast du versucht, diese Dateien zu verschlüsseln?
|
||||
wrongFileAlert.header.lead=Für diesen Zweck stellt Cryptomator ein Laufwerk in deinem System-Dateimanager zur Verfügung.
|
||||
wrongFileAlert.instruction.0=Folge diesen Schritten, um Dateien zu verschlüsseln:
|
||||
wrongFileAlert.instruction.1=1. Entsperre deinen Tresor.
|
||||
wrongFileAlert.instruction.2=2. Klicke auf „Anzeigen“, um das Laufwerk in deinem Dateimanager zu öffnen.
|
||||
wrongFileAlert.instruction.3=3. Füge deine Dateien diesem Laufwerk hinzu.
|
||||
wrongFileAlert.link=Für weitere Hilfe besuche
|
||||
|
||||
# Vault Options
|
||||
## General
|
||||
vaultOptions.general=Allgemein
|
||||
vaultOptions.general.unlockAfterStartup=Tresor beim Starten von Cryptomator entsperren
|
||||
## Mount
|
||||
vaultOptions.mount=Laufwerk
|
||||
vaultOptions.mount.readonly=Schreibgeschützt
|
||||
vaultOptions.mount.driveName=Laufwerksname
|
||||
vaultOptions.mount.customMountFlags=Benutzerdefinierte Mount-Flags
|
||||
vaultOptions.mount.winDriveLetterOccupied=belegt
|
||||
vaultOptions.mount.mountPoint=Einhängepunkt
|
||||
vaultOptions.mount.mountPoint.auto=Automatisch einen passenden Ort auswählen
|
||||
vaultOptions.mount.mountPoint.driveLetter=Zugewiesenen Laufwerksbuchstaben verwenden
|
||||
vaultOptions.mount.mountPoint.custom=Eigener Pfad
|
||||
vaultOptions.mount.mountPoint.directoryPickerButton=Durchsuchen …
|
||||
vaultOptions.mount.mountPoint.directoryPickerTitle=Wähle ein leeres Verzeichnis
|
||||
## Master Key
|
||||
vaultOptions.masterkey=Passwort
|
||||
vaultOptions.masterkey.changePasswordBtn=Password ändern
|
||||
vaultOptions.masterkey.recoveryKeyExpanation=Bei Verlust deines Passworts ist ein Wiederherstellungsschlüssel deine einzige Möglichkeit, den Zugriff auf einen Tresor wiederherzustellen.
|
||||
vaultOptions.masterkey.showRecoveryKeyBtn=Wiederherstellungsschlüssel anzeigen
|
||||
vaultOptions.masterkey.recoverPasswordBtn=Passwort wiederherstellen
|
||||
|
||||
# Recovery Key
|
||||
recoveryKey.title=Wiederherstellungsschlüssel
|
||||
recoveryKey.enterPassword.prompt=Gib dein Passwort ein, um den Wiederherstellungsschlüssel für „%s“ anzuzeigen:
|
||||
recoveryKey.display.message=Mit folgendem Wiederherstellungsschlüssel kannst du den Zugriff auf „%s“ wiederherstellen:
|
||||
recoveryKey.display.StorageHints=Bewahre ihn möglichst sicher auf, z. B.\n • in einem Passwortmanager\n • auf einem USB-Speicherstick\n • auf Papier ausgedruckt
|
||||
recoveryKey.recover.prompt=Gib deinen Wiederherstellungsschlüssel für „%s“ ein:
|
||||
recoveryKey.recover.validKey=Dies ist ein gültiger Wiederherstellungsschlüssel
|
||||
recoveryKey.printout.heading=Cryptomator-Wiederherstellungsschlüssel\n„%s“\n
|
||||
|
||||
# New Password
|
||||
newPassword.promptText=Gib ein neues Passwort ein
|
||||
newPassword.reenterPassword=Bestätige das neue Passwort
|
||||
newPassword.passwordsMatch=Passwörter stimmen überein!
|
||||
newPassword.passwordsDoNotMatch=Passwörter stimmen nicht überein
|
||||
passwordStrength.messageLabel.tooShort=Verwende mindestens %d Zeichen
|
||||
passwordStrength.messageLabel.0=Sehr schwach
|
||||
passwordStrength.messageLabel.1=Schwach
|
||||
passwordStrength.messageLabel.2=Mittel
|
||||
passwordStrength.messageLabel.3=Stark
|
||||
passwordStrength.messageLabel.4=Sehr stark
|
||||
|
||||
# Quit
|
||||
quit.prompt=Cryptomator beenden? Es sind noch Tresore entsperrt.
|
||||
quit.lockAndQuit=Sperren und beenden
|
||||
@@ -1,241 +0,0 @@
|
||||
# Locale Specific CSS files such as CJK, RTL,...
|
||||
|
||||
# Generics
|
||||
## Button
|
||||
generic.button.apply=Применить
|
||||
generic.button.back=Назад
|
||||
generic.button.cancel=Отмена
|
||||
generic.button.change=Изменить
|
||||
generic.button.close=Закрыть
|
||||
generic.button.copy=Копировать
|
||||
generic.button.copied=Скопировано!
|
||||
generic.button.done=Готово
|
||||
generic.button.next=Далее
|
||||
generic.button.print=Распечатать
|
||||
## Error
|
||||
generic.error.title=Произошла непредвиденная ошибка
|
||||
generic.error.instruction=Этого не должно было произойти. Пожалуйста, создайте отчет об ошибке ниже и опишите, какие шаги к ней привели.
|
||||
|
||||
# Tray Menu
|
||||
traymenu.showMainWindow=Показать
|
||||
traymenu.showPreferencesWindow=Настройки
|
||||
traymenu.lockAllVaults=Заблокировать всё
|
||||
traymenu.quitApplication=Выход
|
||||
traymenu.vault.unlock=Разблокировать
|
||||
traymenu.vault.lock=Заблокировать
|
||||
traymenu.vault.reveal=Показать
|
||||
|
||||
# Add Vault Wizard
|
||||
addvaultwizard.title=Добавить хранилище
|
||||
## Welcome
|
||||
addvaultwizard.welcome.newButton=Создать хранилище
|
||||
addvaultwizard.welcome.existingButton=Открыть имеющееся хранилище
|
||||
## New
|
||||
### Name
|
||||
addvaultwizard.new.nameInstruction=Выберите имя для хранилища
|
||||
addvaultwizard.new.namePrompt=Имя хранилища
|
||||
### Location
|
||||
addvaultwizard.new.locationInstruction=Где Cryptomator должен хранить зашифрованные файлы вашего хранилища?
|
||||
addvaultwizard.new.locationLabel=Место хранения
|
||||
addvaultwizard.new.locationPrompt=…
|
||||
addvaultwizard.new.directoryPickerLabel=Пользовательское расположение
|
||||
addvaultwizard.new.directoryPickerButton=Выбрать…
|
||||
addvaultwizard.new.directoryPickerTitle=Выберите каталог
|
||||
addvaultwizard.new.fileAlreadyExists=Хранилище не может быть создано по этому пути, потому что некоторые объекты уже существуют.
|
||||
addvaultwizard.new.invalidName=Неверное имя хранилища. Укажите корректное имя каталога.
|
||||
### Password
|
||||
addvaultwizard.new.createVaultBtn=Создать хранилище
|
||||
addvaultwizard.new.generateRecoveryKeyChoice=Вы не сможете получить доступ к своим данным без пароля. Хотите создать ключ для восстановления на случай потери пароля?
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.yes=Да, пожалуй, лучше так, чем потом сожалеть
|
||||
addvaultwizard.new.generateRecoveryKeyChoice.no=Нет, спасибо, я не потеряю свой пароль
|
||||
### Information
|
||||
addvault.new.readme.storageLocation.fileName=ВАЖНО.rtf
|
||||
addvault.new.readme.storageLocation.1=⚠️ ФАЙЛЫ ХРАНИЛИЩА ⚠️
|
||||
addvault.new.readme.storageLocation.2=Это место, где находится ваше хранилище.
|
||||
addvault.new.readme.storageLocation.3=НЕТ
|
||||
addvault.new.readme.storageLocation.4=• изменяйте любые файлы в этой папке или
|
||||
addvault.new.readme.storageLocation.5=• добавляйте в эту папку любые файлы для шифрования.
|
||||
addvault.new.readme.storageLocation.6=Если вы хотите зашифровать файлы и просмотреть содержимое хранилища, сделайте следующее:
|
||||
addvault.new.readme.storageLocation.7=1. Добавьте это хранилище в Cryptomator.
|
||||
addvault.new.readme.storageLocation.8=2. Разблокируйте хранилище в Cryptomator.
|
||||
addvault.new.readme.storageLocation.9=3. Откройте место доступа, нажав кнопку "Показать".
|
||||
addvault.new.readme.storageLocation.10=Если вам нужна помощь, ознакомьтесь с документацией: %s
|
||||
addvault.new.readme.accessLocation.fileName=ПРИВЕТСТВИЕ.rtf
|
||||
addvault.new.readme.accessLocation.1=🔐️ ЗАШИФРОВАННЫЙ ТОМ 🔐️
|
||||
addvault.new.readme.accessLocation.2=Это место доступа к вашему хранилищу.
|
||||
addvault.new.readme.accessLocation.3=Любые файлы, добавленные в этот том, будут зашифрованы Cryptomator. Вы можете работать с ним, как с любым другим диском/папкой. Здесь отображается только расшифрованное содержимое тома, ваши файлы остаются зашифрованными на жестком диске постоянно.
|
||||
addvault.new.readme.accessLocation.4=Этот файл можно удалить.
|
||||
## Existing
|
||||
addvaultwizard.existing.instruction=Выберите файл "masterkey.cryptomator" из имеющегося хранилища.
|
||||
addvaultwizard.existing.chooseBtn=Выбрать…
|
||||
addvaultwizard.existing.filePickerTitle=Выберите файл мастер-ключа
|
||||
## Success
|
||||
addvaultwizard.success.nextStepsInstructions=Добавлено хранилище "%s".\nДля добавления данных или доступа к содержимому нужно разблокировать хранилище. Его можно разблокировать и позже.
|
||||
addvaultwizard.success.unlockNow=Разблокировать
|
||||
|
||||
# Remove Vault
|
||||
removeVault.title=Удалить хранилище
|
||||
removeVault.information=Cryptomator просто забудет это хранилище. Позже вы можете добавить его снова. Зашифрованные файлы не будут удалены с жёсткого диска.
|
||||
removeVault.confirmBtn=Удалить хранилище
|
||||
|
||||
# Change Password
|
||||
changepassword.title=Изменить пароль
|
||||
changepassword.enterOldPassword=Введите текущий пароль для "%s"
|
||||
changepassword.finalConfirmation=Я понимаю, что не смогу восстановить свои данные, если забуду пароль
|
||||
|
||||
# Forget Password
|
||||
forgetPassword.title=Не помню пароль
|
||||
forgetPassword.information=Это удалит сохраненный пароль от этого хранилища из вашего хранилища ключей.
|
||||
forgetPassword.confirmBtn=Не помню пароль
|
||||
|
||||
# Unlock
|
||||
unlock.title=Разблокировать хранилище
|
||||
unlock.passwordPrompt=Введите пароль для "%s"
|
||||
unlock.savePassword=Сохранить пароль
|
||||
unlock.unlockBtn=Разблокировать
|
||||
## Success
|
||||
unlock.success.message=Разблокировка "%s" успешно выполнена! Доступ в хранилище открыт.
|
||||
unlock.success.revealBtn=Показать хранилище
|
||||
## Invalid Mount Point
|
||||
unlock.error.invalidMountPoint=Точка монтирования - не пустая папка: %s
|
||||
|
||||
# Migration
|
||||
migration.title=Обновить хранилище
|
||||
## Start
|
||||
migration.start.prompt=Хранилище "%s" нужно обновить до более нового формата. Прежде чем продолжить, убедитесь, что нет отложенной синхронизации, которая может повлиять на хранилище.
|
||||
migration.start.confirm=Да, мое хранилище полностью синхронизировано
|
||||
## Run
|
||||
migration.run.enterPassword=Введите пароль для "%s"
|
||||
migration.run.startMigrationBtn=Перенести хранилище
|
||||
## Sucess
|
||||
migration.success.nextStepsInstructions=Перенос "%s" успешно выполнен.\nТеперь можно разблокировать хранилище.
|
||||
migration.success.unlockNow=Разблокировать
|
||||
## Missing file system capabilities
|
||||
migration.error.missingFileSystemCapabilities.title=Неподдерживаемая файловая система
|
||||
migration.error.missingFileSystemCapabilities.description=Миграция не была запущена, так как хранилище находится в ненадлежащей файловой системе.
|
||||
migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=Файловая система не поддерживает длинные имена файлов.
|
||||
migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=Файловая система не поддерживает длинные пути.
|
||||
|
||||
# Preferences
|
||||
preferences.title=Настройки
|
||||
## General
|
||||
preferences.general=Общие
|
||||
preferences.general.theme=Оформление
|
||||
preferences.general.unlockThemes=Разблокировать тёмный режим
|
||||
preferences.general.startHidden=Скрывать окно при запуске Cryptomator
|
||||
preferences.general.debugLogging=Вести журнал отладки
|
||||
preferences.general.autoStart=Запускать Cryptomator при старте системы
|
||||
preferences.general.interfaceOrientation=Ориентация интерфейса
|
||||
preferences.general.interfaceOrientation.ltr=Слева направо
|
||||
preferences.general.interfaceOrientation.rtl=Справа налево
|
||||
## Volume
|
||||
preferences.volume=Виртуальный диск
|
||||
preferences.volume.type=Тип тома
|
||||
preferences.volume.webdav.port=Порт WebDAV
|
||||
preferences.volume.webdav.scheme=Схема WebDAV
|
||||
## Updates
|
||||
preferences.updates=Обновления
|
||||
preferences.updates.currentVersion=Текущая версия: %s
|
||||
preferences.updates.autoUpdateCheck=Автоматически проверять наличие обновлений
|
||||
preferences.updates.checkNowBtn=Проверить
|
||||
preferences.updates.updateAvailable=Доступно обновление до версии %s.
|
||||
## Donation Key
|
||||
preferences.donationKey=Пожертвование
|
||||
preferences.donationKey.registeredFor=Зарегистрировано: %s
|
||||
preferences.donationKey.noDonationKey=Не найден ключ пожертвования. Он напоминает лицензионный ключ, но для удивительных людей, использующих свободное ПО ;-)
|
||||
preferences.donationKey.getDonationKey=Получить ключ пожертвования
|
||||
## About
|
||||
preferences.about=О программе
|
||||
|
||||
# Main Window
|
||||
main.closeBtn.tooltip=Закрыть
|
||||
main.minimizeBtn.tooltip=Свернуть
|
||||
main.preferencesBtn.tooltip=Настройки
|
||||
main.donationKeyMissing.tooltip=Пожалуйста, обдумайте возможность поддержать приложение
|
||||
## Drag 'n' Drop
|
||||
main.dropZone.dropVault=Добавить это хранилище
|
||||
main.dropZone.unknownDragboardContent=Если вы хотите добавить хранилище, перетащите его в это окно
|
||||
## Vault List
|
||||
main.vaultlist.emptyList.onboardingInstruction=Нажмите здесь, чтобы добавить хранилище
|
||||
main.vaultlist.contextMenu.remove=Удалить хранилище
|
||||
main.vaultlist.addVaultBtn=Добавить хранилище
|
||||
## Vault Detail
|
||||
### Welcome
|
||||
main.vaultDetail.welcomeOnboarding=Спасибо, что выбрали Cryptomator для защиты ваших файлов. Если вам нужна помощь, ознакомьтесь с нашими руководствами по началу работы:
|
||||
### Locked
|
||||
main.vaultDetail.lockedStatus=ЗАБЛОКИРОВАНО
|
||||
main.vaultDetail.unlockBtn=Разблокировать
|
||||
main.vaultDetail.optionsBtn=Параметры хранилища
|
||||
### Unlocked
|
||||
main.vaultDetail.unlockedStatus=РАЗБЛОКИРОВАНО
|
||||
main.vaultDetail.accessLocation=Содержимое хранилища доступно здесь:
|
||||
main.vaultDetail.revealBtn=Показать диск
|
||||
main.vaultDetail.lockBtn=Заблокировать
|
||||
main.vaultDetail.bytesPerSecondRead=чтение:
|
||||
main.vaultDetail.bytesPerSecondWritten=запись:
|
||||
main.vaultDetail.throughput.idle=бездействие
|
||||
main.vaultDetail.throughput.kbps=%.1f КиБ/с
|
||||
main.vaultDetail.throughput.mbps=%.1f МиБ/с
|
||||
### Missing
|
||||
main.vaultDetail.missing.info=Cryptomator не смог найти хранилище по этому пути.
|
||||
### Needs Migration
|
||||
main.vaultDetail.migrateButton=Обновить хранилище
|
||||
main.vaultDetail.migratePrompt=Хранилище должно быть обновлено до нового формата, прежде чем вы сможете получить к нему доступ
|
||||
|
||||
# Wrong File Alert
|
||||
wrongFileAlert.title=Как шифровать файлы
|
||||
wrongFileAlert.header.title=Вы пытались зашифровать эти файлы?
|
||||
wrongFileAlert.header.lead=Для этого Cryptomator создает том в системном файловом менеджере.
|
||||
wrongFileAlert.instruction.0=Чтобы зашифровать файлы, выполните следующие действия:
|
||||
wrongFileAlert.instruction.1=1. Разблокируйте хранилище.
|
||||
wrongFileAlert.instruction.2=2. Нажмите кнопку " Показать", чтобы открыть том в файловом менеджере.
|
||||
wrongFileAlert.instruction.3=3. Добавьте файлы в этот том.
|
||||
wrongFileAlert.link=Если нужна помощь, посетите
|
||||
|
||||
# Vault Options
|
||||
## General
|
||||
vaultOptions.general=Общие
|
||||
vaultOptions.general.unlockAfterStartup=Разблокировать хранилище при запуске Cryptomator
|
||||
## Mount
|
||||
vaultOptions.mount=Монтирование
|
||||
vaultOptions.mount.readonly=Только чтение
|
||||
vaultOptions.mount.driveName=Имя диска
|
||||
vaultOptions.mount.customMountFlags=Свои флаги монтирования
|
||||
vaultOptions.mount.winDriveLetterOccupied=занято
|
||||
vaultOptions.mount.mountPoint=Точка монтирования
|
||||
vaultOptions.mount.mountPoint.auto=Автоматически выбирать подходящую
|
||||
vaultOptions.mount.mountPoint.driveLetter=Использовать назначенную букву диска
|
||||
vaultOptions.mount.mountPoint.custom=Пользовательский путь
|
||||
vaultOptions.mount.mountPoint.directoryPickerButton=Выбрать…
|
||||
vaultOptions.mount.mountPoint.directoryPickerTitle=Выберите пустую папку
|
||||
## Master Key
|
||||
vaultOptions.masterkey=Пароль
|
||||
vaultOptions.masterkey.changePasswordBtn=Изменить пароль
|
||||
vaultOptions.masterkey.recoveryKeyExpanation=Ключ восстановления - это единственный способ восстановить доступ к хранилищу в случае утери пароля.
|
||||
vaultOptions.masterkey.showRecoveryKeyBtn=Показать ключ восстановления
|
||||
vaultOptions.masterkey.recoverPasswordBtn=Восстановить пароль
|
||||
|
||||
# Recovery Key
|
||||
recoveryKey.title=Ключ восстановления
|
||||
recoveryKey.enterPassword.prompt=Введите пароль, чтобы показать ключ для "%s":
|
||||
recoveryKey.display.message=Следующий ключ восстановления можно использовать для восстановления доступа к "%s":
|
||||
recoveryKey.display.StorageHints=Храните его в надёжном месте, например:\n • в диспетчере паролей\n • на флеш-накопителе USB\n • распечатанным на бумаге
|
||||
recoveryKey.recover.prompt=Введите ключ восстановления для "%s":
|
||||
recoveryKey.recover.validKey=Это действительный ключ восстановления
|
||||
recoveryKey.printout.heading=Ключ восстановления Cryptomator\n"%s"\n
|
||||
|
||||
# New Password
|
||||
newPassword.promptText=Введите новый пароль
|
||||
newPassword.reenterPassword=Подтвердите новый пароль
|
||||
newPassword.passwordsMatch=Пароли совпадают!
|
||||
newPassword.passwordsDoNotMatch=Пароли не совпадают
|
||||
passwordStrength.messageLabel.tooShort=Минимум символов: %d
|
||||
passwordStrength.messageLabel.0=Очень слабый
|
||||
passwordStrength.messageLabel.1=Слабый
|
||||
passwordStrength.messageLabel.2=Хороший
|
||||
passwordStrength.messageLabel.3=Сильный
|
||||
passwordStrength.messageLabel.4=Очень сильный
|
||||
|
||||
# Quit
|
||||
quit.prompt=Выйти из приложения? Есть разблокированные хранилища.
|
||||
quit.lockAndQuit=Заблокировать и выйти
|
||||
@@ -1,89 +0,0 @@
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
Cryptomator uses 50 third-party dependencies under the following licenses:
|
||||
Apache License v2.0:
|
||||
• HKDF-RFC5869 (at.favre.lib:hkdf:1.0.2 - https://github.com/patrickfav/hkdf)
|
||||
• jffi (com.github.jnr:jffi:1.2.23 - http://github.com/jnr/jffi)
|
||||
• jnr-a64asm (com.github.jnr:jnr-a64asm:1.0.0 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-a64asm)
|
||||
• jnr-constants (com.github.jnr:jnr-constants:0.9.15 - http://github.com/jnr/jnr-constants)
|
||||
• jnr-ffi (com.github.jnr:jnr-ffi:2.1.12 - http://github.com/jnr/jnr-ffi)
|
||||
• FindBugs-jsr305 (com.google.code.findbugs:jsr305:3.0.2 - http://findbugs.sourceforge.net/)
|
||||
• Gson (com.google.code.gson:gson:2.8.6 - https://github.com/google/gson/gson)
|
||||
• Dagger (com.google.dagger:dagger:2.26 - https://github.com/google/dagger)
|
||||
• error-prone annotations (com.google.errorprone:error_prone_annotations:2.3.2 - http://nexus.sonatype.org/oss-repository-hosting.html/error_prone_parent/error_prone_annotations)
|
||||
• Guava InternalFutureFailureAccess and InternalFutures (com.google.guava:failureaccess:1.0.1 - https://github.com/google/guava/failureaccess)
|
||||
• Guava: Google Core Libraries for Java (com.google.guava:guava:28.1-jre - https://github.com/google/guava/guava)
|
||||
• Guava ListenableFuture only (com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava - https://github.com/google/guava/listenablefuture)
|
||||
• J2ObjC Annotations (com.google.j2objc:j2objc-annotations:1.3 - https://github.com/google/j2objc/)
|
||||
• Apache Commons CLI (commons-cli:commons-cli:1.4 - http://commons.apache.org/proper/commons-cli/)
|
||||
• Apache Commons IO (commons-io:commons-io:2.6 - http://commons.apache.org/proper/commons-io/)
|
||||
• javax.inject (javax.inject:javax.inject:1 - http://code.google.com/p/atinject/)
|
||||
• Java Native Access (net.java.dev.jna:jna:5.1.0 - https://github.com/java-native-access/jna)
|
||||
• Java Native Access Platform (net.java.dev.jna:jna-platform:5.1.0 - https://github.com/java-native-access/jna)
|
||||
• Apache Commons Lang (org.apache.commons:commons-lang3:3.9 - http://commons.apache.org/proper/commons-lang/)
|
||||
• Jackrabbit WebDAV Library (org.apache.jackrabbit:jackrabbit-webdav:2.19.0 - http://jackrabbit.apache.org/jackrabbit-webdav/)
|
||||
• Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.17.v20190418 - http://www.eclipse.org/jetty)
|
||||
• Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.17.v20190418 - http://www.eclipse.org/jetty)
|
||||
• Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.17.v20190418 - http://www.eclipse.org/jetty)
|
||||
• Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.17.v20190418 - http://www.eclipse.org/jetty)
|
||||
• Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.17.v20190418 - http://www.eclipse.org/jetty)
|
||||
• Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.17.v20190418 - http://www.eclipse.org/jetty)
|
||||
• Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.17.v20190418 - http://www.eclipse.org/jetty)
|
||||
• Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.17.v20190418 - http://www.eclipse.org/jetty)
|
||||
BSD:
|
||||
• asm (org.ow2.asm:asm:7.1 - http://asm.ow2.org/)
|
||||
• asm-analysis (org.ow2.asm:asm-analysis:7.1 - http://asm.ow2.org/)
|
||||
• asm-commons (org.ow2.asm:asm-commons:7.1 - http://asm.ow2.org/)
|
||||
• asm-tree (org.ow2.asm:asm-tree:7.1 - http://asm.ow2.org/)
|
||||
• asm-util (org.ow2.asm:asm-util:7.1 - http://asm.ow2.org/)
|
||||
Eclipse Public License - Version 1.0:
|
||||
• Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.17.v20190418 - http://www.eclipse.org/jetty)
|
||||
• Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.17.v20190418 - http://www.eclipse.org/jetty)
|
||||
• Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.17.v20190418 - http://www.eclipse.org/jetty)
|
||||
• Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.17.v20190418 - http://www.eclipse.org/jetty)
|
||||
• Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.17.v20190418 - http://www.eclipse.org/jetty)
|
||||
• Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.17.v20190418 - http://www.eclipse.org/jetty)
|
||||
• Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.17.v20190418 - http://www.eclipse.org/jetty)
|
||||
• Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.17.v20190418 - http://www.eclipse.org/jetty)
|
||||
Eclipse Public License - v 2.0:
|
||||
• jnr-posix (com.github.jnr:jnr-posix:3.0.54 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix)
|
||||
GPLv2:
|
||||
• jnr-posix (com.github.jnr:jnr-posix:3.0.54 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix)
|
||||
GPLv2+CE:
|
||||
• Java Servlet API (javax.servlet:javax.servlet-api:3.1.0 - http://servlet-spec.java.net)
|
||||
• javafx-base (org.openjfx:javafx-base:14 - https://openjdk.java.net/projects/openjfx/javafx-base/)
|
||||
• javafx-controls (org.openjfx:javafx-controls:14 - https://openjdk.java.net/projects/openjfx/javafx-controls/)
|
||||
• javafx-fxml (org.openjfx:javafx-fxml:14 - https://openjdk.java.net/projects/openjfx/javafx-fxml/)
|
||||
• javafx-graphics (org.openjfx:javafx-graphics:14 - https://openjdk.java.net/projects/openjfx/javafx-graphics/)
|
||||
LGPL 2.1:
|
||||
• dbus-java (com.github.hypfvieh:dbus-java:3.0.2 - https://github.com/hypfvieh/dbus-java/dbus-java)
|
||||
• jnr-posix (com.github.jnr:jnr-posix:3.0.54 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix)
|
||||
• Java Native Access (net.java.dev.jna:jna:5.1.0 - https://github.com/java-native-access/jna)
|
||||
• Java Native Access Platform (net.java.dev.jna:jna-platform:5.1.0 - https://github.com/java-native-access/jna)
|
||||
MIT License:
|
||||
• java jwt (com.auth0:java-jwt:3.10.0 - https://github.com/auth0/java-jwt)
|
||||
• java-utils (com.github.hypfvieh:java-utils:1.0.5 - https://github.com/hypfvieh/java-utils)
|
||||
• jnr-x86asm (com.github.jnr:jnr-x86asm:1.0.2 - http://github.com/jnr/jnr-x86asm)
|
||||
• jnr-fuse (com.github.serceman:jnr-fuse:0.5.4 - no url defined)
|
||||
• zxcvbn4j (com.nulab-inc:zxcvbn:1.3.0 - https://github.com/nulab/zxcvbn4j)
|
||||
• secret-service (de.swiesend:secret-service:1.0.0-RC.3 - https://github.com/swiesend/secret-service)
|
||||
• Checker Qual (org.checkerframework:checker-qual:2.8.1 - https://checkerframework.org)
|
||||
• Animal Sniffer Annotations (org.codehaus.mojo:animal-sniffer-annotations:1.18 - http://www.mojohaus.org/animal-sniffer/animal-sniffer-annotations)
|
||||
• SLF4J API Module (org.slf4j:slf4j-api:1.7.30 - http://www.slf4j.org)
|
||||
The BSD 2-Clause License:
|
||||
• EasyBind (org.fxmisc.easybind:easybind:1.0.3 - http://www.fxmisc.org/easybind/)
|
||||
|
||||
Cryptomator uses other third-party assets under the following licenses:
|
||||
SIL OFL 1.1 License:
|
||||
• Font Awesome 5.12.0 (https://fontawesome.com/)
|
||||
601
pom.xml
Normal file
601
pom.xml
Normal file
@@ -0,0 +1,601 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>cryptomator</artifactId>
|
||||
<version>1.6.0-SNAPSHOT</version>
|
||||
<name>Cryptomator Desktop App</name>
|
||||
|
||||
<organization>
|
||||
<name>cryptomator.org</name>
|
||||
<url>https://cryptomator.org</url>
|
||||
</organization>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<name>Sebastian Stenzel</name>
|
||||
<email>sebastian.stenzel@gmail.com</email>
|
||||
<timezone>+1</timezone>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.jdk.version>16</project.jdk.version>
|
||||
|
||||
<!-- cryptomator dependencies -->
|
||||
<cryptomator.cryptofs.version>2.1.0-beta8</cryptomator.cryptofs.version>
|
||||
<cryptomator.integrations.version>1.0.0-rc1</cryptomator.integrations.version>
|
||||
<cryptomator.integrations.win.version>1.0.0-beta2</cryptomator.integrations.win.version>
|
||||
<cryptomator.integrations.mac.version>1.0.0-beta2</cryptomator.integrations.mac.version>
|
||||
<cryptomator.integrations.linux.version>1.0.0-beta1</cryptomator.integrations.linux.version>
|
||||
<cryptomator.fuse.version>1.3.1</cryptomator.fuse.version>
|
||||
<cryptomator.dokany.version>1.3.1</cryptomator.dokany.version>
|
||||
<cryptomator.webdav.version>1.2.4</cryptomator.webdav.version>
|
||||
|
||||
<!-- 3rd party dependencies -->
|
||||
<javafx.version>16</javafx.version>
|
||||
<commons-lang3.version>3.12.0</commons-lang3.version>
|
||||
<jwt.version>3.17.0</jwt.version>
|
||||
<easybind.version>2.2</easybind.version>
|
||||
<guava.version>30.1.1-jre</guava.version>
|
||||
<dagger.version>2.37</dagger.version>
|
||||
<gson.version>2.8.6</gson.version>
|
||||
<slf4j.version>1.7.31</slf4j.version>
|
||||
<logback.version>1.2.3</logback.version>
|
||||
|
||||
<!-- test dependencies -->
|
||||
<junit.jupiter.version>5.7.2</junit.jupiter.version>
|
||||
<mockito.version>3.11.2</mockito.version>
|
||||
<hamcrest.version>2.2</hamcrest.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- Cryptomator Libs -->
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>cryptofs</artifactId>
|
||||
<version>${cryptomator.cryptofs.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>fuse-nio-adapter</artifactId>
|
||||
<version>${cryptomator.fuse.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>dokany-nio-adapter</artifactId>
|
||||
<version>${cryptomator.dokany.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>webdav-nio-adapter</artifactId>
|
||||
<version>${cryptomator.webdav.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>integrations-api</artifactId>
|
||||
<version>${cryptomator.integrations.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JavaFX -->
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-base</artifactId>
|
||||
<version>${javafx.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-graphics</artifactId>
|
||||
<version>${javafx.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-controls</artifactId>
|
||||
<version>${javafx.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-fxml</artifactId>
|
||||
<version>${javafx.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Logging -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${slf4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
<version>${logback.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>${logback.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Apache Commons -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>${commons-lang3.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JWT -->
|
||||
<dependency>
|
||||
<groupId>com.auth0</groupId>
|
||||
<artifactId>java-jwt</artifactId>
|
||||
<version>${jwt.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- EasyBind -->
|
||||
<dependency>
|
||||
<groupId>com.tobiasdiez</groupId>
|
||||
<artifactId>easybind</artifactId>
|
||||
<version>${easybind.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Zxcvbn -->
|
||||
<dependency>
|
||||
<groupId>com.nulab-inc</groupId>
|
||||
<artifactId>zxcvbn</artifactId>
|
||||
<version>1.3.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Google -->
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${guava.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.dagger</groupId>
|
||||
<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>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>${junit.jupiter.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>${mockito.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest</artifactId>
|
||||
<version>${hamcrest.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-swing</artifactId>
|
||||
<version>${javafx.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.jimfs</groupId>
|
||||
<artifactId>jimfs</artifactId>
|
||||
<version>1.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.2.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>3.1.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.2.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.8.6</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<version>6.0.3</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<release>${project.jdk.version}</release>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>com.google.dagger</groupId>
|
||||
<artifactId>dagger-compiler</artifactId>
|
||||
<version>${dagger.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<!-- adds Implementation-Version which can be read during runtime -->
|
||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-resources</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}</outputDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>${project.basedir}/src/package</directory>
|
||||
<includes>
|
||||
<include>version.txt</include>
|
||||
<include>ffi-version.txt</include>
|
||||
<include>launcher-mac.sh</include>
|
||||
<include>launcher-linux.sh</include>
|
||||
<include>launcher-win.bat</include>
|
||||
<include>LICENSE.txt</include>
|
||||
</includes>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-libs</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includeScope>runtime</includeScope>
|
||||
<outputDirectory>${project.build.directory}/libs</outputDirectory>
|
||||
<excludeClassifiers>linux,mac,win</excludeClassifiers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-third-party</id>
|
||||
<goals>
|
||||
<goal>add-third-party</goal>
|
||||
</goals>
|
||||
<phase>generate-resources</phase>
|
||||
<configuration>
|
||||
<outputDirectory>${project.basedir}/src/main/resources/license</outputDirectory>
|
||||
<thirdPartyFilename>THIRD-PARTY.txt</thirdPartyFilename>
|
||||
<includedScopes>compile</includedScopes>
|
||||
<excludedGroups>org\.cryptomator</excludedGroups>
|
||||
<licenseMerges>
|
||||
<licenseMerge>Apache License v2.0|Apache License, Version 2.0|The Apache Software License, Version 2.0|Apache 2.0|Apache Software License - Version 2.0</licenseMerge>
|
||||
<licenseMerge>MIT License|The MIT License (MIT)|The MIT License|MIT license</licenseMerge>
|
||||
<licenseMerge>LGPL 2.1|LGPL, version 2.1|GNU Lesser/Library General Public License version 2|GNU Lesser General Public License Version 2.1</licenseMerge>
|
||||
<licenseMerge>GPLv2|GNU General Public License Version 2</licenseMerge>
|
||||
<licenseMerge>GPLv2+CE|CDDL + GPLv2 with classpath exception</licenseMerge>
|
||||
</licenseMerges>
|
||||
<fileTemplate>${project.basedir}/src/license/template.ftl</fileTemplate>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>coverage</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>prepare-agent</id>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>report</id>
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>**/*_*</exclude>
|
||||
<exclude>**/Dagger*</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>dependency-check</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<configuration>
|
||||
<cveValidForHours>24</cveValidForHours>
|
||||
<failBuildOnCVSS>0</failBuildOnCVSS>
|
||||
<skipTestScope>true</skipTestScope>
|
||||
<detail>true</detail>
|
||||
<suppressionFile>suppression.xml</suppressionFile>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>mac</id>
|
||||
<activation>
|
||||
<os>
|
||||
<family>mac</family>
|
||||
</os>
|
||||
<property>
|
||||
<name>idea.version</name>
|
||||
</property>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>integrations-mac</artifactId>
|
||||
<version>${cryptomator.integrations.mac.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>assemble-mac</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>assembly-mac.xml</descriptor>
|
||||
</descriptors>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<finalName>buildkit-mac</finalName>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-mac-libs</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/libs</outputDirectory>
|
||||
<includeGroupIds>org.openjfx</includeGroupIds>
|
||||
<classifier>mac</classifier>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>linux</id>
|
||||
<activation>
|
||||
<os>
|
||||
<family>unix</family>
|
||||
<name>Linux</name>
|
||||
</os>
|
||||
<property>
|
||||
<name>idea.version</name>
|
||||
</property>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>integrations-linux</artifactId>
|
||||
<version>${cryptomator.integrations.linux.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>assemble-linux</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>assembly-linux.xml</descriptor>
|
||||
</descriptors>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<finalName>buildkit-linux</finalName>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-linux-libs</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/libs</outputDirectory>
|
||||
<includeGroupIds>org.openjfx</includeGroupIds>
|
||||
<classifier>linux</classifier>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>windows</id>
|
||||
<activation>
|
||||
<os>
|
||||
<family>windows</family>
|
||||
</os>
|
||||
<property>
|
||||
<name>idea.version</name>
|
||||
</property>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>integrations-win</artifactId>
|
||||
<version>${cryptomator.integrations.win.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>assemble-win</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>assembly-win.xml</descriptor>
|
||||
</descriptors>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<finalName>buildkit-win</finalName>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-win-libs</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/libs</outputDirectory>
|
||||
<includeGroupIds>org.openjfx</includeGroupIds>
|
||||
<classifier>win</classifier>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
</project>
|
||||
@@ -20,16 +20,16 @@ along with this program. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
Cryptomator uses ${dependencyMap?size} third-party dependencies under the following licenses:
|
||||
<#list licenseMap as e>
|
||||
<#assign license = e.getKey()/>
|
||||
<#assign projects = e.getValue()/>
|
||||
<#if projects?size > 0>
|
||||
${license}:
|
||||
<#list projects as project>
|
||||
• ${artifactFormat(project)}
|
||||
</#list>
|
||||
</#if>
|
||||
<#assign license = e.getKey()/>
|
||||
<#assign projects = e.getValue()/>
|
||||
<#if projects?size > 0>
|
||||
${license}:
|
||||
<#list projects as project>
|
||||
- ${artifactFormat(project)}
|
||||
</#list>
|
||||
</#if>
|
||||
</#list>
|
||||
|
||||
Cryptomator uses other third-party assets under the following licenses:
|
||||
SIL OFL 1.1 License:
|
||||
• Font Awesome 5.12.0 (https://fontawesome.com/)
|
||||
SIL OFL 1.1 License:
|
||||
- Font Awesome 5.12.0 (https://fontawesome.com/)
|
||||
@@ -5,25 +5,30 @@
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.common;
|
||||
|
||||
import com.tobiasdiez.easybind.EasyBind;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import javafx.beans.binding.Binding;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.collections.ObservableList;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.keychain.KeychainModule;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.common.settings.SettingsProvider;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.common.vaults.VaultComponent;
|
||||
import org.cryptomator.common.vaults.VaultListManager;
|
||||
import org.cryptomator.common.vaults.VaultListModule;
|
||||
import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
|
||||
import org.cryptomator.frontend.webdav.WebDavServer;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import javafx.beans.binding.Binding;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.collections.ObservableList;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Comparator;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
@@ -33,7 +38,7 @@ import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@Module(subcomponents = {VaultComponent.class})
|
||||
@Module(subcomponents = {VaultComponent.class}, includes = {VaultListModule.class, KeychainModule.class})
|
||||
public abstract class CommonsModule {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(CommonsModule.class);
|
||||
@@ -41,15 +46,34 @@ public abstract class CommonsModule {
|
||||
private static final int NUM_CORE_BG_THREADS = 6;
|
||||
private static final long BG_THREAD_KEEPALIVE_SECONDS = 60l;
|
||||
|
||||
@SuppressWarnings("SpellCheckingInspection")
|
||||
@Provides
|
||||
@Singleton
|
||||
@Named("licensePublicKey")
|
||||
static String provideLicensePublicKey() {
|
||||
// in PEM format without the dash-escaped begin/end lines
|
||||
return "MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQB7NfnqiZbg2KTmoflmZ71PbXru7oW" //
|
||||
+ "fmnV2yv3eDjlDfGruBrqz9TtXBZV/eYWt31xu1osIqaT12lKBvZ511aaAkIBeOEV" //
|
||||
+ "gwcBIlJr6kUw7NKzeJt7r2rrsOyQoOG2nWc/Of/NBqA3mIZRHk5Aq1YupFdD26QE" //
|
||||
+ "r0DzRyj4ixPIt38CQB8=";
|
||||
return """
|
||||
MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQB7NfnqiZbg2KTmoflmZ71PbXru7oW\
|
||||
fmnV2yv3eDjlDfGruBrqz9TtXBZV/eYWt31xu1osIqaT12lKBvZ511aaAkIBeOEV\
|
||||
gwcBIlJr6kUw7NKzeJt7r2rrsOyQoOG2nWc/Of/NBqA3mIZRHk5Aq1YupFdD26QE\
|
||||
r0DzRyj4ixPIt38CQB8=\
|
||||
""";
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static SecureRandom provideCSPRNG() {
|
||||
try {
|
||||
return SecureRandom.getInstanceStrong();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException("A strong algorithm must exist in every Java platform.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static MasterkeyFileAccess provideMasterkeyFileAccess(SecureRandom csprng) {
|
||||
return new MasterkeyFileAccess(Constants.PEPPER, csprng);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@@ -65,12 +89,6 @@ public abstract class CommonsModule {
|
||||
return settingsProvider.get();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static ObservableList<Vault> provideVaultList(VaultListManager vaultListManager) {
|
||||
return vaultListManager.getVaultList();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static ScheduledExecutorService provideScheduledExecutorService(ShutdownHook shutdownHook) {
|
||||
10
src/main/java/org/cryptomator/common/Constants.java
Normal file
10
src/main/java/org/cryptomator/common/Constants.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package org.cryptomator.common;
|
||||
|
||||
public interface Constants {
|
||||
|
||||
String MASTERKEY_FILENAME = "masterkey.cryptomator";
|
||||
String MASTERKEY_BACKUP_SUFFIX = ".bkup";
|
||||
String VAULTCONFIG_FILENAME = "vault.cryptomator";
|
||||
byte[] PEPPER = new byte[0];
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user