mirror of
https://github.com/cryptomator/cryptomator.git
synced 2024-11-23 03:59:51 +00:00
Merge branch 'develop' into feature/1690-invalid-config-handling
This commit is contained in:
commit
3b4ff4d3a2
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:
|
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
|
advances
|
||||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||||
* Public or private harassment
|
* Public or private harassment
|
||||||
|
2
.github/SUPPORT.md
vendored
2
.github/SUPPORT.md
vendored
@ -14,5 +14,5 @@ For _everything else_, please visit our official [Cryptomator Community](https:/
|
|||||||
- Discussions about the apps
|
- Discussions about the apps
|
||||||
- [Development discussions](https://community.cryptomator.org/c/development)
|
- [Development discussions](https://community.cryptomator.org/c/development)
|
||||||
- General questions
|
- General questions
|
||||||
- Discussions regarding our design decissions
|
- Discussions regarding our design decisions
|
||||||
- Our roadmap
|
- Our roadmap
|
||||||
|
23
.github/workflows/build.yml
vendored
23
.github/workflows/build.yml
vendored
@ -52,13 +52,14 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: buildkit-win.zip
|
name: buildkit-win.zip
|
||||||
path: target/buildkit-win.zip
|
path: target/buildkit-win.zip
|
||||||
|
|
||||||
release:
|
release:
|
||||||
name: Draft a Release on GitHub Releases
|
name: Draft a Release on GitHub Releases
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: build
|
needs: build
|
||||||
if: startsWith(github.ref, 'refs/tags/') && github.repository == 'cryptomator/cryptomator'
|
if: startsWith(github.ref, 'refs/tags/') && github.repository == 'cryptomator/cryptomator'
|
||||||
steps:
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
- name: Download buildkit-linux.zip
|
- name: Download buildkit-linux.zip
|
||||||
uses: actions/download-artifact@v1
|
uses: actions/download-artifact@v1
|
||||||
with:
|
with:
|
||||||
@ -74,6 +75,15 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: buildkit-win.zip
|
name: buildkit-win.zip
|
||||||
path: .
|
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
|
- name: Create Release
|
||||||
id: create_release
|
id: create_release
|
||||||
uses: actions/create-release@v1
|
uses: actions/create-release@v1
|
||||||
@ -127,4 +137,13 @@ jobs:
|
|||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
asset_path: buildkit-win.zip
|
asset_path: buildkit-win.zip
|
||||||
asset_name: buildkit-win.zip
|
asset_name: buildkit-win.zip
|
||||||
asset_content_type: application/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
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -18,7 +18,8 @@ pom.xml.versionsBackup
|
|||||||
.idea/**/workspace.xml
|
.idea/**/workspace.xml
|
||||||
.idea/**/tasks.xml
|
.idea/**/tasks.xml
|
||||||
.idea/**/shelf
|
.idea/**/shelf
|
||||||
.idea/dictionaries
|
.idea/dictionaries/**
|
||||||
|
!.idea/dictionaries/dict_*
|
||||||
.idea/compiler.xml
|
.idea/compiler.xml
|
||||||
.idea/encodings.xml
|
.idea/encodings.xml
|
||||||
.idea/jarRepositories.xml
|
.idea/jarRepositories.xml
|
||||||
|
15
.idea/dictionaries/dict_de.xml
Normal file
15
.idea/dictionaries/dict_de.xml
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
Normal file
106
.idea/dictionaries/dict_project.xml
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>
|
@ -1,7 +1,7 @@
|
|||||||
<component name="InspectionProjectProfileManager">
|
<component name="InspectionProjectProfileManager">
|
||||||
<profile version="1.0">
|
<profile version="1.0">
|
||||||
<option name="myName" value="Project Default" />
|
<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="processCode" value="true" />
|
||||||
<option name="processLiterals" value="true" />
|
<option name="processLiterals" value="true" />
|
||||||
<option name="processComments" value="true" />
|
<option name="processComments" value="true" />
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
[![cryptomator](cryptomator.png)](https://cryptomator.org/)
|
[![cryptomator](cryptomator.png)](https://cryptomator.org/)
|
||||||
|
|
||||||
[![Build](https://github.com/cryptomator/cryptomator/workflows/Build/badge.svg)](https://github.com/cryptomator/cryptomator/actions?query=workflow%3ABuild)
|
[![Build](https://github.com/cryptomator/cryptomator/workflows/Build/badge.svg)](https://github.com/cryptomator/cryptomator/actions?query=workflow%3ABuild)
|
||||||
[![Known Vulnerabilities](https://snyk.io/test/github/cryptomator/cryptomator/badge.svg?targetFile=main%2Fpom.xml)](https://snyk.io/test/github/cryptomator/cryptomator?targetFile=main%2Fpom.xml)
|
[![Known Vulnerabilities](https://snyk.io/test/github/cryptomator/cryptomator/badge.svg)](https://snyk.io/test/github/cryptomator/cryptomator)
|
||||||
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/2a0adf3cec6a4143b91035d3924178f1)](https://www.codacy.com/gh/cryptomator/cryptomator/dashboard)
|
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/2a0adf3cec6a4143b91035d3924178f1)](https://www.codacy.com/gh/cryptomator/cryptomator/dashboard)
|
||||||
[![Twitter](https://img.shields.io/badge/twitter-@Cryptomator-blue.svg?style=flat)](http://twitter.com/Cryptomator)
|
[![Twitter](https://img.shields.io/badge/twitter-@Cryptomator-blue.svg?style=flat)](http://twitter.com/Cryptomator)
|
||||||
[![Crowdin](https://badges.crowdin.net/cryptomator/localized.svg)](https://translate.cryptomator.org/)
|
[![Crowdin](https://badges.crowdin.net/cryptomator/localized.svg)](https://translate.cryptomator.org/)
|
||||||
@ -56,7 +56,7 @@ Download native binaries of Cryptomator on [cryptomator.org](https://cryptomator
|
|||||||
- File names get encrypted
|
- File names get encrypted
|
||||||
- Folder structure gets obfuscated
|
- Folder structure gets obfuscated
|
||||||
- Use as many vaults in your Dropbox as you want, each having individual passwords
|
- Use as many vaults in your Dropbox as you want, each having individual passwords
|
||||||
- Two thousand commits for the security of your data!! :tada:
|
- Three thousand commits for the security of your data!! :tada:
|
||||||
|
|
||||||
### Privacy
|
### Privacy
|
||||||
|
|
||||||
|
18
pom.xml
18
pom.xml
@ -24,29 +24,29 @@
|
|||||||
<project.jdk.version>16</project.jdk.version>
|
<project.jdk.version>16</project.jdk.version>
|
||||||
|
|
||||||
<!-- cryptomator dependencies -->
|
<!-- cryptomator dependencies -->
|
||||||
<cryptomator.cryptofs.version>2.1.0-beta6</cryptomator.cryptofs.version>
|
<cryptomator.cryptofs.version>2.1.0-beta8</cryptomator.cryptofs.version>
|
||||||
<cryptomator.integrations.version>1.0.0-rc1</cryptomator.integrations.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.win.version>1.0.0-beta2</cryptomator.integrations.win.version>
|
||||||
<cryptomator.integrations.mac.version>1.0.0-beta2</cryptomator.integrations.mac.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.integrations.linux.version>1.0.0-beta1</cryptomator.integrations.linux.version>
|
||||||
<cryptomator.fuse.version>1.3.1</cryptomator.fuse.version>
|
<cryptomator.fuse.version>1.3.1</cryptomator.fuse.version>
|
||||||
<cryptomator.dokany.version>1.3.1</cryptomator.dokany.version>
|
<cryptomator.dokany.version>1.3.1</cryptomator.dokany.version>
|
||||||
<cryptomator.webdav.version>1.2.2</cryptomator.webdav.version>
|
<cryptomator.webdav.version>1.2.4</cryptomator.webdav.version>
|
||||||
|
|
||||||
<!-- 3rd party dependencies -->
|
<!-- 3rd party dependencies -->
|
||||||
<javafx.version>16</javafx.version>
|
<javafx.version>16</javafx.version>
|
||||||
<commons-lang3.version>3.11</commons-lang3.version>
|
<commons-lang3.version>3.12.0</commons-lang3.version>
|
||||||
<jwt.version>3.15.0</jwt.version>
|
<jwt.version>3.17.0</jwt.version>
|
||||||
<easybind.version>2.1.0</easybind.version>
|
<easybind.version>2.2</easybind.version>
|
||||||
<guava.version>30.1.1-jre</guava.version>
|
<guava.version>30.1.1-jre</guava.version>
|
||||||
<dagger.version>2.35.1</dagger.version>
|
<dagger.version>2.37</dagger.version>
|
||||||
<gson.version>2.8.6</gson.version>
|
<gson.version>2.8.6</gson.version>
|
||||||
<slf4j.version>1.7.30</slf4j.version>
|
<slf4j.version>1.7.31</slf4j.version>
|
||||||
<logback.version>1.2.3</logback.version>
|
<logback.version>1.2.3</logback.version>
|
||||||
|
|
||||||
<!-- test dependencies -->
|
<!-- test dependencies -->
|
||||||
<junit.jupiter.version>5.7.1</junit.jupiter.version>
|
<junit.jupiter.version>5.7.2</junit.jupiter.version>
|
||||||
<mockito.version>3.9.0</mockito.version>
|
<mockito.version>3.11.2</mockito.version>
|
||||||
<hamcrest.version>2.2</hamcrest.version>
|
<hamcrest.version>2.2</hamcrest.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@ public abstract class CommonsModule {
|
|||||||
private static final int NUM_CORE_BG_THREADS = 6;
|
private static final int NUM_CORE_BG_THREADS = 6;
|
||||||
private static final long BG_THREAD_KEEPALIVE_SECONDS = 60l;
|
private static final long BG_THREAD_KEEPALIVE_SECONDS = 60l;
|
||||||
|
|
||||||
|
@SuppressWarnings("SpellCheckingInspection")
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
@Named("licensePublicKey")
|
@Named("licensePublicKey")
|
||||||
|
@ -123,8 +123,8 @@ public class Environment {
|
|||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
} else {
|
} else {
|
||||||
Iterable<String> iter = Splitter.on(separator).split(value);
|
Iterable<String> iter = Splitter.on(separator).split(value);
|
||||||
Spliterator<String> spliter = Spliterators.spliteratorUnknownSize(iter.iterator(), Spliterator.ORDERED | Spliterator.IMMUTABLE);
|
Spliterator<String> spliterator = Spliterators.spliteratorUnknownSize(iter.iterator(), Spliterator.ORDERED | Spliterator.IMMUTABLE);
|
||||||
return StreamSupport.stream(spliter, false);
|
return StreamSupport.stream(spliterator, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,17 +60,17 @@ public class SemVerComparator implements Comparator<String> {
|
|||||||
final int commonCompCount = Math.min(vComps1.length, vComps2.length);
|
final int commonCompCount = Math.min(vComps1.length, vComps2.length);
|
||||||
|
|
||||||
for (int i = 0; i < commonCompCount; i++) {
|
for (int i = 0; i < commonCompCount; i++) {
|
||||||
int subversionComparisionResult = 0;
|
int subversionComparisonResult = 0;
|
||||||
try {
|
try {
|
||||||
final int v1 = Integer.parseInt(vComps1[i]);
|
final int v1 = Integer.parseInt(vComps1[i]);
|
||||||
final int v2 = Integer.parseInt(vComps2[i]);
|
final int v2 = Integer.parseInt(vComps2[i]);
|
||||||
subversionComparisionResult = v1 - v2;
|
subversionComparisonResult = v1 - v2;
|
||||||
} catch (NumberFormatException ex) {
|
} catch (NumberFormatException ex) {
|
||||||
// ok, lets compare this fragment lexicographically
|
// ok, lets compare this fragment lexicographically
|
||||||
subversionComparisionResult = vComps1[i].compareTo(vComps2[i]);
|
subversionComparisonResult = vComps1[i].compareTo(vComps2[i]);
|
||||||
}
|
}
|
||||||
if (subversionComparisionResult != 0) {
|
if (subversionComparisonResult != 0) {
|
||||||
return subversionComparisionResult;
|
return subversionComparisonResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,8 +59,10 @@ public class KeychainManager implements KeychainAccessProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void changePassphrase(String key, CharSequence passphrase) throws KeychainAccessException {
|
public void changePassphrase(String key, CharSequence passphrase) throws KeychainAccessException {
|
||||||
getKeychainOrFail().changePassphrase(key, passphrase);
|
if (isPassphraseStored(key)) {
|
||||||
setPassphraseStored(key, true);
|
getKeychainOrFail().changePassphrase(key, passphrase);
|
||||||
|
setPassphraseStored(key, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -30,7 +30,7 @@ public class Settings {
|
|||||||
public static final int MIN_PORT = 1024;
|
public static final int MIN_PORT = 1024;
|
||||||
public static final int MAX_PORT = 65535;
|
public static final int MAX_PORT = 65535;
|
||||||
public static final boolean DEFAULT_ASKED_FOR_UPDATE_CHECK = false;
|
public static final boolean DEFAULT_ASKED_FOR_UPDATE_CHECK = false;
|
||||||
public static final boolean DEFAULT_CHECK_FOR_UDPATES = false;
|
public static final boolean DEFAULT_CHECK_FOR_UPDATES = false;
|
||||||
public static final boolean DEFAULT_START_HIDDEN = false;
|
public static final boolean DEFAULT_START_HIDDEN = false;
|
||||||
public static final int DEFAULT_PORT = 42427;
|
public static final int DEFAULT_PORT = 42427;
|
||||||
public static final int DEFAULT_NUM_TRAY_NOTIFICATIONS = 3;
|
public static final int DEFAULT_NUM_TRAY_NOTIFICATIONS = 3;
|
||||||
@ -46,7 +46,7 @@ public class Settings {
|
|||||||
|
|
||||||
private final ObservableList<VaultSettings> directories = FXCollections.observableArrayList(VaultSettings::observables);
|
private final ObservableList<VaultSettings> directories = FXCollections.observableArrayList(VaultSettings::observables);
|
||||||
private final BooleanProperty askedForUpdateCheck = new SimpleBooleanProperty(DEFAULT_ASKED_FOR_UPDATE_CHECK);
|
private final BooleanProperty askedForUpdateCheck = new SimpleBooleanProperty(DEFAULT_ASKED_FOR_UPDATE_CHECK);
|
||||||
private final BooleanProperty checkForUpdates = new SimpleBooleanProperty(DEFAULT_CHECK_FOR_UDPATES);
|
private final BooleanProperty checkForUpdates = new SimpleBooleanProperty(DEFAULT_CHECK_FOR_UPDATES);
|
||||||
private final BooleanProperty startHidden = new SimpleBooleanProperty(DEFAULT_START_HIDDEN);
|
private final BooleanProperty startHidden = new SimpleBooleanProperty(DEFAULT_START_HIDDEN);
|
||||||
private final IntegerProperty port = new SimpleIntegerProperty(DEFAULT_PORT);
|
private final IntegerProperty port = new SimpleIntegerProperty(DEFAULT_PORT);
|
||||||
private final IntegerProperty numTrayNotifications = new SimpleIntegerProperty(DEFAULT_NUM_TRAY_NOTIFICATIONS);
|
private final IntegerProperty numTrayNotifications = new SimpleIntegerProperty(DEFAULT_NUM_TRAY_NOTIFICATIONS);
|
||||||
|
@ -101,7 +101,7 @@ public class SettingsProvider implements Supplier<Settings> {
|
|||||||
if (settings == null) {
|
if (settings == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final Optional<Path> settingsPath = env.getSettingsPath().findFirst(); // alway save to preferred (first) path
|
final Optional<Path> settingsPath = env.getSettingsPath().findFirst(); // always save to preferred (first) path
|
||||||
settingsPath.ifPresent(path -> {
|
settingsPath.ifPresent(path -> {
|
||||||
Runnable saveCommand = () -> this.save(settings, path);
|
Runnable saveCommand = () -> this.save(settings, path);
|
||||||
ScheduledFuture<?> scheduledTask = scheduler.schedule(saveCommand, SAVE_DELAY_MS, TimeUnit.MILLISECONDS);
|
ScheduledFuture<?> scheduledTask = scheduler.schedule(saveCommand, SAVE_DELAY_MS, TimeUnit.MILLISECONDS);
|
||||||
|
@ -31,7 +31,7 @@ import java.util.Random;
|
|||||||
public class VaultSettings {
|
public class VaultSettings {
|
||||||
|
|
||||||
public static final boolean DEFAULT_UNLOCK_AFTER_STARTUP = false;
|
public static final boolean DEFAULT_UNLOCK_AFTER_STARTUP = false;
|
||||||
public static final boolean DEFAULT_REAVEAL_AFTER_MOUNT = true;
|
public static final boolean DEFAULT_REVEAL_AFTER_MOUNT = true;
|
||||||
public static final boolean DEFAULT_USES_INDIVIDUAL_MOUNTPATH = false;
|
public static final boolean DEFAULT_USES_INDIVIDUAL_MOUNTPATH = false;
|
||||||
public static final boolean DEFAULT_USES_READONLY_MODE = false;
|
public static final boolean DEFAULT_USES_READONLY_MODE = false;
|
||||||
public static final String DEFAULT_MOUNT_FLAGS = "";
|
public static final String DEFAULT_MOUNT_FLAGS = "";
|
||||||
@ -47,7 +47,7 @@ public class VaultSettings {
|
|||||||
private final StringProperty displayName = new SimpleStringProperty();
|
private final StringProperty displayName = new SimpleStringProperty();
|
||||||
private final StringProperty winDriveLetter = new SimpleStringProperty();
|
private final StringProperty winDriveLetter = new SimpleStringProperty();
|
||||||
private final BooleanProperty unlockAfterStartup = new SimpleBooleanProperty(DEFAULT_UNLOCK_AFTER_STARTUP);
|
private final BooleanProperty unlockAfterStartup = new SimpleBooleanProperty(DEFAULT_UNLOCK_AFTER_STARTUP);
|
||||||
private final BooleanProperty revealAfterMount = new SimpleBooleanProperty(DEFAULT_REAVEAL_AFTER_MOUNT);
|
private final BooleanProperty revealAfterMount = new SimpleBooleanProperty(DEFAULT_REVEAL_AFTER_MOUNT);
|
||||||
private final BooleanProperty useCustomMountPath = new SimpleBooleanProperty(DEFAULT_USES_INDIVIDUAL_MOUNTPATH);
|
private final BooleanProperty useCustomMountPath = new SimpleBooleanProperty(DEFAULT_USES_INDIVIDUAL_MOUNTPATH);
|
||||||
private final StringProperty customMountPath = new SimpleStringProperty();
|
private final StringProperty customMountPath = new SimpleStringProperty();
|
||||||
private final BooleanProperty usesReadOnlyMode = new SimpleBooleanProperty(DEFAULT_USES_READONLY_MODE);
|
private final BooleanProperty usesReadOnlyMode = new SimpleBooleanProperty(DEFAULT_USES_READONLY_MODE);
|
||||||
|
@ -44,7 +44,7 @@ class VaultSettingsJsonAdapter {
|
|||||||
String customMountPath = null;
|
String customMountPath = null;
|
||||||
String winDriveLetter = null;
|
String winDriveLetter = null;
|
||||||
boolean unlockAfterStartup = VaultSettings.DEFAULT_UNLOCK_AFTER_STARTUP;
|
boolean unlockAfterStartup = VaultSettings.DEFAULT_UNLOCK_AFTER_STARTUP;
|
||||||
boolean revealAfterMount = VaultSettings.DEFAULT_REAVEAL_AFTER_MOUNT;
|
boolean revealAfterMount = VaultSettings.DEFAULT_REVEAL_AFTER_MOUNT;
|
||||||
boolean useCustomMountPath = VaultSettings.DEFAULT_USES_INDIVIDUAL_MOUNTPATH;
|
boolean useCustomMountPath = VaultSettings.DEFAULT_USES_INDIVIDUAL_MOUNTPATH;
|
||||||
boolean usesReadOnlyMode = VaultSettings.DEFAULT_USES_READONLY_MODE;
|
boolean usesReadOnlyMode = VaultSettings.DEFAULT_USES_READONLY_MODE;
|
||||||
String mountFlags = VaultSettings.DEFAULT_MOUNT_FLAGS;
|
String mountFlags = VaultSettings.DEFAULT_MOUNT_FLAGS;
|
||||||
|
@ -138,7 +138,7 @@ public class VaultModule {
|
|||||||
|
|
||||||
// see https://github.com/billziss-gh/winfsp/blob/5d0b10d0b643652c00ebb4704dc2bb28e7244973/src/dll/fuse/fuse_main.c#L53-L62 for syntax guide
|
// see https://github.com/billziss-gh/winfsp/blob/5d0b10d0b643652c00ebb4704dc2bb28e7244973/src/dll/fuse/fuse_main.c#L53-L62 for syntax guide
|
||||||
// see https://github.com/billziss-gh/winfsp/blob/5d0b10d0b643652c00ebb4704dc2bb28e7244973/src/dll/fuse/fuse.c#L295-L319 for options (-o <...>)
|
// see https://github.com/billziss-gh/winfsp/blob/5d0b10d0b643652c00ebb4704dc2bb28e7244973/src/dll/fuse/fuse.c#L295-L319 for options (-o <...>)
|
||||||
// see https://github.com/billziss-gh/winfsp/wiki/Frequently-Asked-Questions/5ba00e4be4f5e938eaae6ef1500b331de12dee77 (FUSE 4.) on why the given defaults were choosen
|
// see https://github.com/billziss-gh/winfsp/wiki/Frequently-Asked-Questions/5ba00e4be4f5e938eaae6ef1500b331de12dee77 (FUSE 4.) on why the given defaults were chosen
|
||||||
private String getWindowsFuseDefaultMountFlags(StringBinding mountName, ReadOnlyBooleanProperty readOnly) {
|
private String getWindowsFuseDefaultMountFlags(StringBinding mountName, ReadOnlyBooleanProperty readOnly) {
|
||||||
assert SystemUtils.IS_OS_WINDOWS;
|
assert SystemUtils.IS_OS_WINDOWS;
|
||||||
StringBuilder flags = new StringBuilder();
|
StringBuilder flags = new StringBuilder();
|
||||||
|
@ -46,7 +46,7 @@ public class VaultState extends ObservableValueBase<VaultState.Value> implements
|
|||||||
UNLOCKED,
|
UNLOCKED,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unknown state due to preceeding unrecoverable exceptions.
|
* Unknown state due to preceding unrecoverable exceptions.
|
||||||
*/
|
*/
|
||||||
ERROR;
|
ERROR;
|
||||||
}
|
}
|
||||||
|
@ -35,8 +35,8 @@ public class VaultStats {
|
|||||||
private final LongProperty bytesPerSecondEncrypted = new SimpleLongProperty();
|
private final LongProperty bytesPerSecondEncrypted = new SimpleLongProperty();
|
||||||
private final LongProperty bytesPerSecondDecrypted = new SimpleLongProperty();
|
private final LongProperty bytesPerSecondDecrypted = new SimpleLongProperty();
|
||||||
private final DoubleProperty cacheHitRate = new SimpleDoubleProperty();
|
private final DoubleProperty cacheHitRate = new SimpleDoubleProperty();
|
||||||
private final LongProperty toalBytesRead = new SimpleLongProperty();
|
private final LongProperty totalBytesRead = new SimpleLongProperty();
|
||||||
private final LongProperty toalBytesWritten = new SimpleLongProperty();
|
private final LongProperty totalBytesWritten = new SimpleLongProperty();
|
||||||
private final LongProperty totalBytesEncrypted = new SimpleLongProperty();
|
private final LongProperty totalBytesEncrypted = new SimpleLongProperty();
|
||||||
private final LongProperty totalBytesDecrypted = new SimpleLongProperty();
|
private final LongProperty totalBytesDecrypted = new SimpleLongProperty();
|
||||||
private final LongProperty filesRead = new SimpleLongProperty();
|
private final LongProperty filesRead = new SimpleLongProperty();
|
||||||
@ -75,8 +75,8 @@ public class VaultStats {
|
|||||||
cacheHitRate.set(stats.map(this::getCacheHitRate).orElse(0.0));
|
cacheHitRate.set(stats.map(this::getCacheHitRate).orElse(0.0));
|
||||||
bytesPerSecondDecrypted.set(stats.map(CryptoFileSystemStats::pollBytesDecrypted).orElse(0L));
|
bytesPerSecondDecrypted.set(stats.map(CryptoFileSystemStats::pollBytesDecrypted).orElse(0L));
|
||||||
bytesPerSecondEncrypted.set(stats.map(CryptoFileSystemStats::pollBytesEncrypted).orElse(0L));
|
bytesPerSecondEncrypted.set(stats.map(CryptoFileSystemStats::pollBytesEncrypted).orElse(0L));
|
||||||
toalBytesRead.set(stats.map(CryptoFileSystemStats::pollTotalBytesRead).orElse(0L));
|
totalBytesRead.set(stats.map(CryptoFileSystemStats::pollTotalBytesRead).orElse(0L));
|
||||||
toalBytesWritten.set(stats.map(CryptoFileSystemStats::pollTotalBytesWritten).orElse(0L));
|
totalBytesWritten.set(stats.map(CryptoFileSystemStats::pollTotalBytesWritten).orElse(0L));
|
||||||
totalBytesEncrypted.set(stats.map(CryptoFileSystemStats::pollTotalBytesEncrypted).orElse(0L));
|
totalBytesEncrypted.set(stats.map(CryptoFileSystemStats::pollTotalBytesEncrypted).orElse(0L));
|
||||||
totalBytesDecrypted.set(stats.map(CryptoFileSystemStats::pollTotalBytesDecrypted).orElse(0L));
|
totalBytesDecrypted.set(stats.map(CryptoFileSystemStats::pollTotalBytesDecrypted).orElse(0L));
|
||||||
var oldAccessCount = filesRead.get() + filesWritten.get();
|
var oldAccessCount = filesRead.get() + filesWritten.get();
|
||||||
@ -146,7 +146,7 @@ public class VaultStats {
|
|||||||
return bytesPerSecondEncrypted;
|
return bytesPerSecondEncrypted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getBytesPerSecondEnrypted() {
|
public long getBytesPerSecondEncrypted() {
|
||||||
return bytesPerSecondEncrypted.get();
|
return bytesPerSecondEncrypted.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,13 +164,13 @@ public class VaultStats {
|
|||||||
return cacheHitRate.get();
|
return cacheHitRate.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public LongProperty toalBytesReadProperty() {return toalBytesRead;}
|
public LongProperty totalBytesReadProperty() {return totalBytesRead;}
|
||||||
|
|
||||||
public long getTotalBytesRead() { return toalBytesRead.get();}
|
public long getTotalBytesRead() { return totalBytesRead.get();}
|
||||||
|
|
||||||
public LongProperty toalBytesWrittenProperty() {return toalBytesWritten;}
|
public LongProperty totalBytesWrittenProperty() {return totalBytesWritten;}
|
||||||
|
|
||||||
public long getTotalBytesWritten() { return toalBytesWritten.get();}
|
public long getTotalBytesWritten() { return totalBytesWritten.get();}
|
||||||
|
|
||||||
public LongProperty totalBytesEncryptedProperty() {return totalBytesEncrypted;}
|
public LongProperty totalBytesEncryptedProperty() {return totalBytesEncrypted;}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import java.util.function.Consumer;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes a Volume and usess it to mount an unlocked vault
|
* Takes a Volume and uses it to mount an unlocked vault
|
||||||
*/
|
*/
|
||||||
public interface Volume {
|
public interface Volume {
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ public interface Volume {
|
|||||||
boolean isSupported();
|
boolean isSupported();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the coresponding enum type of the {@link VolumeImpl volume implementation ("VolumeImpl")} that is implemented by this Volume.
|
* Gets the corresponding enum type of the {@link VolumeImpl volume implementation ("VolumeImpl")} that is implemented by this Volume.
|
||||||
*
|
*
|
||||||
* @return the type of implementation as defined by the {@link VolumeImpl VolumeImpl enum}
|
* @return the type of implementation as defined by the {@link VolumeImpl VolumeImpl enum}
|
||||||
*/
|
*/
|
||||||
|
@ -67,7 +67,7 @@ public class WebDavVolume implements Volume {
|
|||||||
throw new IllegalStateException("Mounting requires unlocked WebDAV servlet.");
|
throw new IllegalStateException("Mounting requires unlocked WebDAV servlet.");
|
||||||
}
|
}
|
||||||
|
|
||||||
//on windows, prevent an automatic drive letter selection in the upstream library. Either we choose already a specifc one or there is no free.
|
//on windows, prevent an automatic drive letter selection in the upstream library. Either we choose already a specific one or there is no free.
|
||||||
Supplier<String> driveLetterSupplier;
|
Supplier<String> driveLetterSupplier;
|
||||||
if (System.getProperty("os.name").toLowerCase().contains("windows") && vaultSettings.winDriveLetter().isEmpty().get()) {
|
if (System.getProperty("os.name").toLowerCase().contains("windows") && vaultSettings.winDriveLetter().isEmpty().get()) {
|
||||||
driveLetterSupplier = () -> windowsDriveLetters.getAvailableDriveLetter().orElse(null);
|
driveLetterSupplier = () -> windowsDriveLetters.getAvailableDriveLetter().orElse(null);
|
||||||
|
@ -11,12 +11,12 @@ import java.io.File;
|
|||||||
*
|
*
|
||||||
* @param <E> Event type the policy possibly reacts to
|
* @param <E> Event type the policy possibly reacts to
|
||||||
*/
|
*/
|
||||||
public class LaunchAndSizeBasedTriggerinPolicy<E> extends TriggeringPolicyBase<E> {
|
public class LaunchAndSizeBasedTriggeringPolicy<E> extends TriggeringPolicyBase<E> {
|
||||||
|
|
||||||
LaunchBasedTriggeringPolicy<E> launchBasedTriggeringPolicy;
|
LaunchBasedTriggeringPolicy<E> launchBasedTriggeringPolicy;
|
||||||
SizeBasedTriggeringPolicy<E> sizeBasedTriggeringPolicy;
|
SizeBasedTriggeringPolicy<E> sizeBasedTriggeringPolicy;
|
||||||
|
|
||||||
public LaunchAndSizeBasedTriggerinPolicy(FileSize threshold) {
|
public LaunchAndSizeBasedTriggeringPolicy(FileSize threshold) {
|
||||||
this.launchBasedTriggeringPolicy = new LaunchBasedTriggeringPolicy<>();
|
this.launchBasedTriggeringPolicy = new LaunchBasedTriggeringPolicy<>();
|
||||||
this.sizeBasedTriggeringPolicy = new SizeBasedTriggeringPolicy<>();
|
this.sizeBasedTriggeringPolicy = new SizeBasedTriggeringPolicy<>();
|
||||||
sizeBasedTriggeringPolicy.setMaxFileSize(threshold);
|
sizeBasedTriggeringPolicy.setMaxFileSize(threshold);
|
@ -85,7 +85,7 @@ public class LoggerModule {
|
|||||||
appender.setContext(context);
|
appender.setContext(context);
|
||||||
appender.setFile(logDir.resolve(LOGFILE_NAME).toString());
|
appender.setFile(logDir.resolve(LOGFILE_NAME).toString());
|
||||||
appender.setEncoder(encoder);
|
appender.setEncoder(encoder);
|
||||||
LaunchAndSizeBasedTriggerinPolicy triggeringPolicy = new LaunchAndSizeBasedTriggerinPolicy(FileSize.valueOf(LOG_MAX_SIZE));
|
LaunchAndSizeBasedTriggeringPolicy triggeringPolicy = new LaunchAndSizeBasedTriggeringPolicy(FileSize.valueOf(LOG_MAX_SIZE));
|
||||||
triggeringPolicy.setContext(context);
|
triggeringPolicy.setContext(context);
|
||||||
triggeringPolicy.start();
|
triggeringPolicy.start();
|
||||||
appender.setTriggeringPolicy(triggeringPolicy);
|
appender.setTriggeringPolicy(triggeringPolicy);
|
||||||
|
@ -5,8 +5,8 @@ import org.cryptomator.common.vaults.Vault;
|
|||||||
import org.cryptomator.common.vaults.VaultListManager;
|
import org.cryptomator.common.vaults.VaultListManager;
|
||||||
import org.cryptomator.cryptofs.CryptoFileSystemProperties;
|
import org.cryptomator.cryptofs.CryptoFileSystemProperties;
|
||||||
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
|
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
|
||||||
import org.cryptomator.cryptofs.VaultCipherCombo;
|
|
||||||
import org.cryptomator.cryptolib.api.CryptoException;
|
import org.cryptomator.cryptolib.api.CryptoException;
|
||||||
|
import org.cryptomator.cryptolib.api.CryptorProvider;
|
||||||
import org.cryptomator.cryptolib.api.Masterkey;
|
import org.cryptomator.cryptolib.api.Masterkey;
|
||||||
import org.cryptomator.cryptolib.api.MasterkeyLoader;
|
import org.cryptomator.cryptolib.api.MasterkeyLoader;
|
||||||
import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
|
import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
|
||||||
@ -182,7 +182,7 @@ public class CreateNewVaultPasswordController implements FxController {
|
|||||||
// 2. initialize vault:
|
// 2. initialize vault:
|
||||||
try {
|
try {
|
||||||
MasterkeyLoader loader = ignored -> masterkey.clone();
|
MasterkeyLoader loader = ignored -> masterkey.clone();
|
||||||
CryptoFileSystemProperties fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties().withCipherCombo(VaultCipherCombo.SIV_CTRMAC).withKeyLoader(loader).build();
|
CryptoFileSystemProperties fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties().withCipherCombo(CryptorProvider.Scheme.SIV_CTRMAC).withKeyLoader(loader).build();
|
||||||
CryptoFileSystemProvider.initialize(path, fsProps, DEFAULT_KEY_ID);
|
CryptoFileSystemProvider.initialize(path, fsProps, DEFAULT_KEY_ID);
|
||||||
|
|
||||||
// 3. write vault-internal readme file:
|
// 3. write vault-internal readme file:
|
||||||
|
@ -67,8 +67,8 @@ public class FxmlLoaderFactory {
|
|||||||
}
|
}
|
||||||
Parent root = loader.getRoot();
|
Parent root = loader.getRoot();
|
||||||
// TODO: discuss if we can remove language-specific stylesheets
|
// TODO: discuss if we can remove language-specific stylesheets
|
||||||
// List<String> addtionalStyleSheets = Splitter.on(',').omitEmptyStrings().splitToList(resourceBundle.getString("additionalStyleSheets"));
|
// List<String> additionalStyleSheets = Splitter.on(',').omitEmptyStrings().splitToList(resourceBundle.getString("additionalStyleSheets"));
|
||||||
// addtionalStyleSheets.forEach(styleSheet -> root.getStylesheets().add("/css/" + styleSheet));
|
// additionalStyleSheets.forEach(styleSheet -> root.getStylesheets().add("/css/" + styleSheet));
|
||||||
return sceneFactory.apply(root);
|
return sceneFactory.apply(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ public final class WeakBindings {
|
|||||||
* @param observable The observable
|
* @param observable The observable
|
||||||
* @return a IntegerBinding weakly referenced from the given observable
|
* @return a IntegerBinding weakly referenced from the given observable
|
||||||
*/
|
*/
|
||||||
public static IntegerBinding bindInterger(ObservableValue<Number> observable) {
|
public static IntegerBinding bindInteger(ObservableValue<Number> observable) {
|
||||||
return new IntegerBinding() {
|
return new IntegerBinding() {
|
||||||
{
|
{
|
||||||
bind(observable);
|
bind(observable);
|
||||||
|
@ -39,7 +39,7 @@ public enum FontAwesome5Icon {
|
|||||||
REDO("\uF01E"), //
|
REDO("\uF01E"), //
|
||||||
SEARCH("\uF002"), //
|
SEARCH("\uF002"), //
|
||||||
SPINNER("\uF110"), //
|
SPINNER("\uF110"), //
|
||||||
STOPWATCH("\uF2F2"), //
|
STETHOSCOPE("\uF0f1"), //
|
||||||
SYNC("\uF021"), //
|
SYNC("\uF021"), //
|
||||||
TIMES("\uF00D"), //
|
TIMES("\uF00D"), //
|
||||||
TRASH("\uF1F8"), //
|
TRASH("\uF1F8"), //
|
||||||
|
@ -21,8 +21,8 @@ public class FontAwesome5IconView extends Text {
|
|||||||
private static final String FONT_PATH = "/css/fontawesome5-free-solid.otf";
|
private static final String FONT_PATH = "/css/fontawesome5-free-solid.otf";
|
||||||
private static final Font FONT;
|
private static final Font FONT;
|
||||||
|
|
||||||
private ObjectProperty<FontAwesome5Icon> glyph = new SimpleObjectProperty<>(this, "glyph", DEFAULT_GLYPH);
|
private final ObjectProperty<FontAwesome5Icon> glyph = new SimpleObjectProperty<>(this, "glyph", DEFAULT_GLYPH);
|
||||||
private DoubleProperty glyphSize = new SimpleDoubleProperty(this, "glyphSize", DEFAULT_GLYPH_SIZE);
|
private final DoubleProperty glyphSize = new SimpleDoubleProperty(this, "glyphSize", DEFAULT_GLYPH_SIZE);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
@ -42,7 +42,7 @@ public class FontAwesome5IconView extends Text {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void glyphChanged(@SuppressWarnings("unused") ObservableValue<? extends FontAwesome5Icon> observable, @SuppressWarnings("unused") FontAwesome5Icon oldValue, FontAwesome5Icon newValue) {
|
private void glyphChanged(@SuppressWarnings("unused") ObservableValue<? extends FontAwesome5Icon> observable, @SuppressWarnings("unused") FontAwesome5Icon oldValue, FontAwesome5Icon newValue) {
|
||||||
setText(newValue.unicode());
|
setText(newValue == null ? null : newValue.unicode());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void glyphSizeChanged(@SuppressWarnings("unused") ObservableValue<? extends Number> observable, @SuppressWarnings("unused") Number oldValue, Number newValue) {
|
private void glyphSizeChanged(@SuppressWarnings("unused") ObservableValue<? extends Number> observable, @SuppressWarnings("unused") Number oldValue, Number newValue) {
|
||||||
|
@ -12,8 +12,8 @@ import javafx.scene.layout.StackPane;
|
|||||||
public class NiceSecurePasswordField extends StackPane {
|
public class NiceSecurePasswordField extends StackPane {
|
||||||
|
|
||||||
private static final String STYLE_CLASS = "nice-secure-password-field";
|
private static final String STYLE_CLASS = "nice-secure-password-field";
|
||||||
private static final String ICONS_STLYE_CLASS = "icons";
|
private static final String ICONS_STYLE_CLASS = "icons";
|
||||||
private static final String REVEAL_BUTTON_STLYE_CLASS = "reveal-button";
|
private static final String REVEAL_BUTTON_STYLE_CLASS = "reveal-button";
|
||||||
private static final int ICON_SPACING = 6;
|
private static final int ICON_SPACING = 6;
|
||||||
private static final double ICON_SIZE = 14.0;
|
private static final double ICON_SIZE = 14.0;
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ public class NiceSecurePasswordField extends StackPane {
|
|||||||
iconContainer.setAlignment(Pos.CENTER_RIGHT);
|
iconContainer.setAlignment(Pos.CENTER_RIGHT);
|
||||||
iconContainer.setMaxWidth(Double.NEGATIVE_INFINITY);
|
iconContainer.setMaxWidth(Double.NEGATIVE_INFINITY);
|
||||||
iconContainer.setPrefWidth(42); // TODO
|
iconContainer.setPrefWidth(42); // TODO
|
||||||
iconContainer.getStyleClass().add(ICONS_STLYE_CLASS);
|
iconContainer.getStyleClass().add(ICONS_STYLE_CLASS);
|
||||||
StackPane.setAlignment(iconContainer, Pos.CENTER_RIGHT);
|
StackPane.setAlignment(iconContainer, Pos.CENTER_RIGHT);
|
||||||
|
|
||||||
capsLockedIcon.setGlyph(FontAwesome5Icon.ARROW_UP);
|
capsLockedIcon.setGlyph(FontAwesome5Icon.ARROW_UP);
|
||||||
@ -51,7 +51,7 @@ public class NiceSecurePasswordField extends StackPane {
|
|||||||
revealPasswordButton.setFocusTraversable(false);
|
revealPasswordButton.setFocusTraversable(false);
|
||||||
revealPasswordButton.visibleProperty().bind(passwordField.focusedProperty());
|
revealPasswordButton.visibleProperty().bind(passwordField.focusedProperty());
|
||||||
revealPasswordButton.managedProperty().bind(passwordField.focusedProperty());
|
revealPasswordButton.managedProperty().bind(passwordField.focusedProperty());
|
||||||
revealPasswordButton.getStyleClass().add(REVEAL_BUTTON_STLYE_CLASS);
|
revealPasswordButton.getStyleClass().add(REVEAL_BUTTON_STYLE_CLASS);
|
||||||
|
|
||||||
passwordField.revealPasswordProperty().bind(revealPasswordButton.selectedProperty());
|
passwordField.revealPasswordProperty().bind(revealPasswordButton.selectedProperty());
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import javafx.beans.property.SimpleStringProperty;
|
|||||||
import javafx.beans.property.StringProperty;
|
import javafx.beans.property.StringProperty;
|
||||||
import javafx.scene.control.Label;
|
import javafx.scene.control.Label;
|
||||||
|
|
||||||
public class ThrougputLabel extends Label {
|
public class ThroughputLabel extends Label {
|
||||||
|
|
||||||
private static final long KIBS_THRESHOLD = 1l << 7; // 0.128 kiB/s
|
private static final long KIBS_THRESHOLD = 1l << 7; // 0.128 kiB/s
|
||||||
private static final long MIBS_THRESHOLD = 1l << 19; // 0.512 MiB/s
|
private static final long MIBS_THRESHOLD = 1l << 19; // 0.512 MiB/s
|
||||||
@ -18,7 +18,7 @@ public class ThrougputLabel extends Label {
|
|||||||
private final StringProperty mibsFormat = new SimpleStringProperty("%.3f");
|
private final StringProperty mibsFormat = new SimpleStringProperty("%.3f");
|
||||||
private final LongProperty bytesPerSecond = new SimpleLongProperty();
|
private final LongProperty bytesPerSecond = new SimpleLongProperty();
|
||||||
|
|
||||||
public ThrougputLabel() {
|
public ThroughputLabel() {
|
||||||
textProperty().bind(createStringBinding());
|
textProperty().bind(createStringBinding());
|
||||||
}
|
}
|
||||||
|
|
@ -16,7 +16,6 @@ public class BatchService extends Service<Void> {
|
|||||||
|
|
||||||
private final Iterator<HealthCheckTask> remainingTasks;
|
private final Iterator<HealthCheckTask> remainingTasks;
|
||||||
|
|
||||||
@Inject
|
|
||||||
public BatchService(Iterable<HealthCheckTask> tasks) {
|
public BatchService(Iterable<HealthCheckTask> tasks) {
|
||||||
this.remainingTasks = tasks.iterator();
|
this.remainingTasks = tasks.iterator();
|
||||||
}
|
}
|
||||||
|
@ -15,17 +15,18 @@ import javafx.collections.FXCollections;
|
|||||||
import javafx.concurrent.Worker;
|
import javafx.concurrent.Worker;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.control.ListView;
|
import javafx.scene.control.ListView;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@HealthCheckScoped
|
@HealthCheckScoped
|
||||||
public class CheckDetailController implements FxController {
|
public class CheckDetailController implements FxController {
|
||||||
|
|
||||||
private final EasyObservableList<DiagnosticResult> results;
|
private final EasyObservableList<Result> results;
|
||||||
private final OptionalBinding<Worker.State> taskState;
|
private final OptionalBinding<Worker.State> taskState;
|
||||||
private final Binding<String> taskName;
|
private final Binding<String> taskName;
|
||||||
private final Binding<Number> taskDuration;
|
private final Binding<String> taskDuration;
|
||||||
private final ResultListCellFactory resultListCellFactory;
|
|
||||||
private final Binding<Boolean> taskRunning;
|
private final Binding<Boolean> taskRunning;
|
||||||
private final Binding<Boolean> taskScheduled;
|
private final Binding<Boolean> taskScheduled;
|
||||||
private final Binding<Boolean> taskFinished;
|
private final Binding<Boolean> taskFinished;
|
||||||
@ -35,17 +36,20 @@ public class CheckDetailController implements FxController {
|
|||||||
private final Binding<Boolean> taskCancelled;
|
private final Binding<Boolean> taskCancelled;
|
||||||
private final Binding<Number> countOfWarnSeverity;
|
private final Binding<Number> countOfWarnSeverity;
|
||||||
private final Binding<Number> countOfCritSeverity;
|
private final Binding<Number> countOfCritSeverity;
|
||||||
|
private final ResultListCellFactory resultListCellFactory;
|
||||||
|
private final ResourceBundle resourceBundle;
|
||||||
|
|
||||||
public ListView<DiagnosticResult> resultsListView;
|
public ListView<Result> resultsListView;
|
||||||
private Subscription resultSubscription;
|
private Subscription resultSubscription;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public CheckDetailController(ObjectProperty<HealthCheckTask> selectedTask, ResultListCellFactory resultListCellFactory) {
|
public CheckDetailController(ObjectProperty<HealthCheckTask> selectedTask, ResultListCellFactory resultListCellFactory, ResourceBundle resourceBundle) {
|
||||||
|
this.resultListCellFactory = resultListCellFactory;
|
||||||
|
this.resourceBundle = resourceBundle;
|
||||||
this.results = EasyBind.wrapList(FXCollections.observableArrayList());
|
this.results = EasyBind.wrapList(FXCollections.observableArrayList());
|
||||||
this.taskState = EasyBind.wrapNullable(selectedTask).mapObservable(HealthCheckTask::stateProperty);
|
this.taskState = EasyBind.wrapNullable(selectedTask).mapObservable(HealthCheckTask::stateProperty);
|
||||||
this.taskName = EasyBind.wrapNullable(selectedTask).map(HealthCheckTask::getTitle).orElse("");
|
this.taskName = EasyBind.wrapNullable(selectedTask).map(HealthCheckTask::getTitle).orElse("");
|
||||||
this.taskDuration = EasyBind.wrapNullable(selectedTask).mapObservable(HealthCheckTask::durationInMillisProperty).orElse(-1L);
|
this.taskDuration = EasyBind.wrapNullable(selectedTask).mapObservable(HealthCheckTask::durationInMillisProperty).orElse(-1L).map(this::millisToReadAbleDuration);
|
||||||
this.resultListCellFactory = resultListCellFactory;
|
|
||||||
this.taskRunning = EasyBind.wrapNullable(selectedTask).mapObservable(HealthCheckTask::runningProperty).orElse(false); //TODO: DOES NOT WORK
|
this.taskRunning = EasyBind.wrapNullable(selectedTask).mapObservable(HealthCheckTask::runningProperty).orElse(false); //TODO: DOES NOT WORK
|
||||||
this.taskScheduled = taskState.map(Worker.State.SCHEDULED::equals).orElse(false);
|
this.taskScheduled = taskState.map(Worker.State.SCHEDULED::equals).orElse(false);
|
||||||
this.taskNotStarted = taskState.map(Worker.State.READY::equals).orElse(false);
|
this.taskNotStarted = taskState.map(Worker.State.READY::equals).orElse(false);
|
||||||
@ -67,8 +71,8 @@ public class CheckDetailController implements FxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Function<Stream<? extends DiagnosticResult>, Long> countSeverity(DiagnosticResult.Severity severity) {
|
private Function<Stream<? extends Result>, Long> countSeverity(DiagnosticResult.Severity severity) {
|
||||||
return stream -> stream.filter(item -> severity.equals(item.getSeverity())).count();
|
return stream -> stream.filter(item -> severity.equals(item.diagnosis().getSeverity())).count();
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
@ -87,11 +91,11 @@ public class CheckDetailController implements FxController {
|
|||||||
return taskName;
|
return taskName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Number getTaskDuration() {
|
public String getTaskDuration() {
|
||||||
return taskDuration.getValue();
|
return taskDuration.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Binding<Number> taskDurationProperty() {
|
public Binding<String> taskDurationProperty() {
|
||||||
return taskDuration;
|
return taskDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,4 +171,21 @@ public class CheckDetailController implements FxController {
|
|||||||
return taskCancelled;
|
return taskCancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String millisToReadAbleDuration(Number millis) {
|
||||||
|
Duration tmp = Duration.ofMillis(millis.longValue());
|
||||||
|
long hours = tmp.toHoursPart();
|
||||||
|
long minutes = tmp.toMinutesPart();
|
||||||
|
long seconds = tmp.toSecondsPart();
|
||||||
|
if (hours != 0) {
|
||||||
|
String hms_format = resourceBundle.getString("health.check.detail.hmsFormat");
|
||||||
|
return String.format(hms_format, hours, minutes, seconds);
|
||||||
|
} else if (minutes != 0) {
|
||||||
|
String ms_format = resourceBundle.getString("health.check.detail.msFormat");
|
||||||
|
return String.format(ms_format, minutes, seconds);
|
||||||
|
} else {
|
||||||
|
String s_format = resourceBundle.getString("health.check.detail.sFormat");
|
||||||
|
return String.format(s_format, seconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,64 +1,71 @@
|
|||||||
package org.cryptomator.ui.health;
|
package org.cryptomator.ui.health;
|
||||||
|
|
||||||
|
import org.cryptomator.cryptofs.health.api.DiagnosticResult;
|
||||||
import org.cryptomator.ui.controls.FontAwesome5Icon;
|
import org.cryptomator.ui.controls.FontAwesome5Icon;
|
||||||
import org.cryptomator.ui.controls.FontAwesome5IconView;
|
import org.cryptomator.ui.controls.FontAwesome5IconView;
|
||||||
|
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.value.ObservableValue;
|
|
||||||
import javafx.concurrent.Worker;
|
import javafx.concurrent.Worker;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
|
import javafx.scene.control.CheckBox;
|
||||||
import javafx.scene.control.ContentDisplay;
|
import javafx.scene.control.ContentDisplay;
|
||||||
import javafx.scene.control.ListCell;
|
import javafx.scene.control.ListCell;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
class CheckListCell extends ListCell<HealthCheckTask> {
|
class CheckListCell extends ListCell<HealthCheckTask> {
|
||||||
|
|
||||||
private final FontAwesome5IconView stateIcon = new FontAwesome5IconView();
|
private final FontAwesome5IconView stateIcon = new FontAwesome5IconView();
|
||||||
|
private CheckBox checkBox = new CheckBox();
|
||||||
|
|
||||||
CheckListCell() {
|
CheckListCell() {
|
||||||
setPadding(new Insets(6));
|
setPadding(new Insets(6));
|
||||||
setAlignment(Pos.CENTER_LEFT);
|
setAlignment(Pos.CENTER_LEFT);
|
||||||
setContentDisplay(ContentDisplay.LEFT);
|
setContentDisplay(ContentDisplay.LEFT);
|
||||||
|
getStyleClass().add("label");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateItem(HealthCheckTask item, boolean empty) {
|
protected void updateItem(HealthCheckTask item, boolean empty) {
|
||||||
super.updateItem(item, empty);
|
super.updateItem(item, empty);
|
||||||
|
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
textProperty().bind(item.titleProperty());
|
setText(item.getTitle());
|
||||||
item.stateProperty().addListener(this::stateChanged);
|
graphicProperty().bind(Bindings.createObjectBinding(() -> graphicForState(item.getState()), item.stateProperty()));
|
||||||
graphicProperty().bind(Bindings.createObjectBinding(() -> graphicForState(item.getState()),item.stateProperty()));
|
stateIcon.glyphProperty().bind(Bindings.createObjectBinding(() -> glyphForState(item), item.stateProperty()));
|
||||||
stateIcon.setGlyph(glyphForState(item.getState()));
|
checkBox.selectedProperty().bindBidirectional(item.chosenForExecutionProperty());
|
||||||
} else {
|
} else {
|
||||||
textProperty().unbind();
|
|
||||||
graphicProperty().unbind();
|
graphicProperty().unbind();
|
||||||
setGraphic(null);
|
setGraphic(null);
|
||||||
setText(null);
|
setText(null);
|
||||||
|
checkBox.selectedProperty().unbind();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stateChanged(ObservableValue<? extends Worker.State> observable, Worker.State oldState, Worker.State newState) {
|
|
||||||
stateIcon.setGlyph(glyphForState(newState));
|
|
||||||
stateIcon.setVisible(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Node graphicForState(Worker.State state) {
|
private Node graphicForState(Worker.State state) {
|
||||||
return switch (state) {
|
return switch (state) {
|
||||||
case READY -> null;
|
case READY -> checkBox;
|
||||||
case SCHEDULED, RUNNING, FAILED, CANCELLED, SUCCEEDED -> stateIcon;
|
case SCHEDULED, RUNNING, FAILED, CANCELLED, SUCCEEDED -> stateIcon;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private FontAwesome5Icon glyphForState(Worker.State state) {
|
private FontAwesome5Icon glyphForState(HealthCheckTask item) {
|
||||||
return switch (state) {
|
return switch (item.getState()) {
|
||||||
case READY -> FontAwesome5Icon.COG; //just a placeholder
|
case READY -> FontAwesome5Icon.COG; //just a placeholder
|
||||||
case SCHEDULED -> FontAwesome5Icon.CLOCK;
|
case SCHEDULED -> FontAwesome5Icon.CLOCK;
|
||||||
case RUNNING -> FontAwesome5Icon.SPINNER;
|
case RUNNING -> FontAwesome5Icon.SPINNER;
|
||||||
case FAILED -> FontAwesome5Icon.EXCLAMATION_TRIANGLE;
|
case FAILED -> FontAwesome5Icon.EXCLAMATION_TRIANGLE;
|
||||||
case CANCELLED -> FontAwesome5Icon.BAN;
|
case CANCELLED -> FontAwesome5Icon.BAN;
|
||||||
case SUCCEEDED -> FontAwesome5Icon.CHECK;
|
case SUCCEEDED -> checkFoundProblems(item) ? FontAwesome5Icon.EXCLAMATION_TRIANGLE : FontAwesome5Icon.CHECK;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean checkFoundProblems(HealthCheckTask item) {
|
||||||
|
Predicate<DiagnosticResult.Severity> isProblem = severity -> switch (severity) {
|
||||||
|
case WARN, CRITICAL -> true;
|
||||||
|
case INFO, GOOD -> false;
|
||||||
|
};
|
||||||
|
return item.results().stream().map(Result::diagnosis).map(DiagnosticResult::getSeverity).anyMatch(isProblem);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package org.cryptomator.ui.health;
|
package org.cryptomator.ui.health;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.google.common.base.Predicates;
|
||||||
import com.tobiasdiez.easybind.EasyBind;
|
import com.tobiasdiez.easybind.EasyBind;
|
||||||
import dagger.Lazy;
|
import dagger.Lazy;
|
||||||
import org.cryptomator.ui.common.ErrorComponent;
|
import org.cryptomator.ui.common.ErrorComponent;
|
||||||
@ -10,28 +11,24 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javafx.beans.binding.Binding;
|
import javafx.beans.binding.Binding;
|
||||||
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.beans.binding.BooleanBinding;
|
import javafx.beans.binding.BooleanBinding;
|
||||||
|
import javafx.beans.binding.IntegerBinding;
|
||||||
import javafx.beans.property.BooleanProperty;
|
import javafx.beans.property.BooleanProperty;
|
||||||
import javafx.beans.property.IntegerProperty;
|
|
||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
import javafx.beans.property.SimpleBooleanProperty;
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
import javafx.beans.property.SimpleIntegerProperty;
|
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import javafx.beans.value.ObservableValue;
|
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.collections.transformation.FilteredList;
|
||||||
import javafx.concurrent.Worker;
|
import javafx.concurrent.Worker;
|
||||||
import javafx.event.ActionEvent;
|
import javafx.event.ActionEvent;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.control.CheckBox;
|
import javafx.scene.control.CheckBox;
|
||||||
import javafx.scene.control.ListView;
|
import javafx.scene.control.ListView;
|
||||||
import javafx.scene.control.cell.CheckBoxListCell;
|
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import javafx.util.StringConverter;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.List;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
@ -43,40 +40,34 @@ public class CheckListController implements FxController {
|
|||||||
|
|
||||||
private final Stage window;
|
private final Stage window;
|
||||||
private final ObservableList<HealthCheckTask> tasks;
|
private final ObservableList<HealthCheckTask> tasks;
|
||||||
|
private final FilteredList<HealthCheckTask> chosenTasks;
|
||||||
private final ReportWriter reportWriter;
|
private final ReportWriter reportWriter;
|
||||||
private final ExecutorService executorService;
|
private final ExecutorService executorService;
|
||||||
private final ObjectProperty<HealthCheckTask> selectedTask;
|
private final ObjectProperty<HealthCheckTask> selectedTask;
|
||||||
private final Lazy<ErrorComponent.Builder> errorComponenBuilder;
|
private final Lazy<ErrorComponent.Builder> errorComponentBuilder;
|
||||||
private final SimpleObjectProperty<Worker<?>> runningTask;
|
private final SimpleObjectProperty<Worker<?>> runningTask;
|
||||||
private final Binding<Boolean> running;
|
private final Binding<Boolean> running;
|
||||||
private final Binding<Boolean> finished;
|
private final Binding<Boolean> finished;
|
||||||
private final Map<HealthCheckTask, BooleanProperty> listPickIndicators;
|
private final IntegerBinding chosenTaskCount;
|
||||||
private final IntegerProperty numberOfPickedChecks;
|
|
||||||
private final BooleanBinding anyCheckSelected;
|
private final BooleanBinding anyCheckSelected;
|
||||||
private final BooleanProperty showResultScreen;
|
private final BooleanProperty showResultScreen;
|
||||||
|
|
||||||
/* FXML */
|
/* FXML */
|
||||||
public ListView<HealthCheckTask> checksListView;
|
public ListView<HealthCheckTask> checksListView;
|
||||||
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public CheckListController(@HealthCheckWindow Stage window, Lazy<Collection<HealthCheckTask>> tasks, ReportWriter reportWriteTask, ObjectProperty<HealthCheckTask> selectedTask, ExecutorService executorService, Lazy<ErrorComponent.Builder> errorComponenBuilder) {
|
public CheckListController(@HealthCheckWindow Stage window, Lazy<List<HealthCheckTask>> tasks, ReportWriter reportWriteTask, ObjectProperty<HealthCheckTask> selectedTask, ExecutorService executorService, Lazy<ErrorComponent.Builder> errorComponentBuilder) {
|
||||||
this.window = window;
|
this.window = window;
|
||||||
this.tasks = FXCollections.observableArrayList(tasks.get());
|
this.tasks = FXCollections.observableList(tasks.get(), HealthCheckTask::observables);
|
||||||
|
this.chosenTasks = this.tasks.filtered(HealthCheckTask::isChosenForExecution);
|
||||||
this.reportWriter = reportWriteTask;
|
this.reportWriter = reportWriteTask;
|
||||||
this.executorService = executorService;
|
this.executorService = executorService;
|
||||||
this.selectedTask = selectedTask;
|
this.selectedTask = selectedTask;
|
||||||
this.errorComponenBuilder = errorComponenBuilder;
|
this.errorComponentBuilder = errorComponentBuilder;
|
||||||
this.runningTask = new SimpleObjectProperty<>();
|
this.runningTask = new SimpleObjectProperty<>();
|
||||||
this.running = EasyBind.wrapNullable(runningTask).mapObservable(Worker::runningProperty).orElse(false);
|
this.running = EasyBind.wrapNullable(runningTask).mapObservable(Worker::runningProperty).orElse(false);
|
||||||
this.finished = EasyBind.wrapNullable(runningTask).mapObservable(Worker::stateProperty).map(END_STATES::contains).orElse(false);
|
this.finished = EasyBind.wrapNullable(runningTask).mapObservable(Worker::stateProperty).map(END_STATES::contains).orElse(false);
|
||||||
this.listPickIndicators = new HashMap<>();
|
this.chosenTaskCount = Bindings.size(this.chosenTasks);
|
||||||
this.numberOfPickedChecks = new SimpleIntegerProperty(0);
|
|
||||||
this.tasks.forEach(task -> {
|
|
||||||
var entrySelectedProp = new SimpleBooleanProperty(false);
|
|
||||||
entrySelectedProp.addListener((observable, oldValue, newValue) -> numberOfPickedChecks.set(numberOfPickedChecks.get() + (newValue ? 1 : -1)));
|
|
||||||
listPickIndicators.put(task, entrySelectedProp);
|
|
||||||
});
|
|
||||||
this.anyCheckSelected = selectedTask.isNotNull();
|
this.anyCheckSelected = selectedTask.isNotNull();
|
||||||
this.showResultScreen = new SimpleBooleanProperty(false);
|
this.showResultScreen = new SimpleBooleanProperty(false);
|
||||||
}
|
}
|
||||||
@ -84,38 +75,32 @@ public class CheckListController implements FxController {
|
|||||||
@FXML
|
@FXML
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
checksListView.setItems(tasks);
|
checksListView.setItems(tasks);
|
||||||
checksListView.setCellFactory(CheckBoxListCell.forListView(listPickIndicators::get, new StringConverter<HealthCheckTask>() {
|
checksListView.setCellFactory(view -> new CheckListCell());
|
||||||
@Override
|
|
||||||
public String toString(HealthCheckTask object) {
|
|
||||||
return object.getTitle();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HealthCheckTask fromString(String string) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
selectedTask.bind(checksListView.getSelectionModel().selectedItemProperty());
|
selectedTask.bind(checksListView.getSelectionModel().selectedItemProperty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void toggleSelectAll(ActionEvent event) {
|
public void toggleSelectAll(ActionEvent event) {
|
||||||
if (event.getSource() instanceof CheckBox c) {
|
if (event.getSource() instanceof CheckBox c) {
|
||||||
listPickIndicators.forEach( (task, pickProperty) -> pickProperty.set(c.isSelected()));
|
tasks.forEach(t -> t.chosenForExecutionProperty().set(c.isSelected()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void runSelectedChecks() {
|
public void runSelectedChecks() {
|
||||||
Preconditions.checkState(runningTask.get() == null);
|
Preconditions.checkState(runningTask.get() == null);
|
||||||
var batch = checksListView.getItems().filtered(item -> listPickIndicators.get(item).get());
|
|
||||||
var batchService = new BatchService(batch);
|
// prevent further interaction by cancelling non-chosen tasks:
|
||||||
|
tasks.filtered(Predicates.not(chosenTasks::contains)).forEach(HealthCheckTask::cancel);
|
||||||
|
|
||||||
|
// run chosen tasks:
|
||||||
|
var batchService = new BatchService(chosenTasks);
|
||||||
batchService.setExecutor(executorService);
|
batchService.setExecutor(executorService);
|
||||||
batchService.start();
|
batchService.start();
|
||||||
runningTask.set(batchService);
|
runningTask.set(batchService);
|
||||||
showResultScreen.set(true);
|
showResultScreen.set(true);
|
||||||
checksListView.getSelectionModel().select(batch.get(0));
|
checksListView.getSelectionModel().select(chosenTasks.get(0));
|
||||||
checksListView.setCellFactory(view -> new CheckListCell());
|
checksListView.refresh();
|
||||||
window.sizeToScene();
|
window.sizeToScene();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,7 +116,7 @@ public class CheckListController implements FxController {
|
|||||||
reportWriter.writeReport(tasks);
|
reportWriter.writeReport(tasks);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOG.error("Failed to write health check report.", e);
|
LOG.error("Failed to write health check report.", e);
|
||||||
errorComponenBuilder.get().cause(e).window(window).returnToScene(window.getScene()).build().showErrorScene();
|
errorComponentBuilder.get().cause(e).window(window).returnToScene(window.getScene()).build().showErrorScene();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,13 +153,12 @@ public class CheckListController implements FxController {
|
|||||||
return showResultScreen;
|
return showResultScreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNumberOfPickedChecks() {
|
public int getChosenTaskCount() {
|
||||||
return numberOfPickedChecks.get();
|
return chosenTaskCount.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IntegerProperty numberOfPickedChecksProperty() {
|
public IntegerBinding chosenTaskCountProperty() {
|
||||||
return numberOfPickedChecks;
|
return chosenTaskCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
package org.cryptomator.ui.health;
|
||||||
|
|
||||||
|
import org.cryptomator.cryptofs.VaultConfig;
|
||||||
|
import org.cryptomator.cryptofs.health.api.DiagnosticResult;
|
||||||
|
import org.cryptomator.cryptofs.health.api.HealthCheck;
|
||||||
|
import org.cryptomator.cryptolib.api.Cryptor;
|
||||||
|
import org.cryptomator.cryptolib.api.Masterkey;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FIXME: Remove in production release
|
||||||
|
*/
|
||||||
|
public class DummyHealthChecks {
|
||||||
|
|
||||||
|
public static class DummyCheck1 implements HealthCheck {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void check(Path path, VaultConfig vaultConfig, Masterkey masterkey, Cryptor cryptor, Consumer<DiagnosticResult> consumer) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DummyCheck2 implements HealthCheck {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void check(Path path, VaultConfig vaultConfig, Masterkey masterkey, Cryptor cryptor, Consumer<DiagnosticResult> consumer) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DummyCheck3 implements HealthCheck {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void check(Path path, VaultConfig vaultConfig, Masterkey masterkey, Cryptor cryptor, Consumer<DiagnosticResult> consumer) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -7,6 +7,7 @@ import org.cryptomator.common.vaults.Vault;
|
|||||||
import org.cryptomator.ui.common.FxmlFile;
|
import org.cryptomator.ui.common.FxmlFile;
|
||||||
import org.cryptomator.ui.common.FxmlScene;
|
import org.cryptomator.ui.common.FxmlScene;
|
||||||
|
|
||||||
|
import javax.inject.Named;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
@ -17,6 +18,9 @@ public interface HealthCheckComponent {
|
|||||||
@HealthCheckWindow
|
@HealthCheckWindow
|
||||||
Stage window();
|
Stage window();
|
||||||
|
|
||||||
|
@Named("windowToClose")
|
||||||
|
Stage windowToClose();
|
||||||
|
|
||||||
@FxmlScene(FxmlFile.HEALTH_START)
|
@FxmlScene(FxmlFile.HEALTH_START)
|
||||||
Lazy<Scene> scene();
|
Lazy<Scene> scene();
|
||||||
|
|
||||||
@ -24,6 +28,7 @@ public interface HealthCheckComponent {
|
|||||||
Stage stage = window();
|
Stage stage = window();
|
||||||
stage.setScene(scene().get());
|
stage.setScene(scene().get());
|
||||||
stage.show();
|
stage.show();
|
||||||
|
windowToClose().close();
|
||||||
return stage;
|
return stage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,6 +38,9 @@ public interface HealthCheckComponent {
|
|||||||
@BindsInstance
|
@BindsInstance
|
||||||
Builder vault(@HealthCheckWindow Vault vault);
|
Builder vault(@HealthCheckWindow Vault vault);
|
||||||
|
|
||||||
|
@BindsInstance
|
||||||
|
Builder windowToClose(@Named("windowToClose") Stage window);
|
||||||
|
|
||||||
HealthCheckComponent build();
|
HealthCheckComponent build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ import javafx.stage.Modality;
|
|||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
@ -63,7 +64,7 @@ abstract class HealthCheckModule {
|
|||||||
/* Only inject with Lazy-Wrapper!*/
|
/* Only inject with Lazy-Wrapper!*/
|
||||||
@Provides
|
@Provides
|
||||||
@HealthCheckScoped
|
@HealthCheckScoped
|
||||||
static Collection<HealthCheckTask> provideAvailableHealthCheckTasks(Collection<HealthCheck> availableHealthChecks, @HealthCheckWindow Vault vault, AtomicReference<Masterkey> masterkeyRef, AtomicReference<VaultConfig> vaultConfigRef, SecureRandom csprng, ResourceBundle resourceBundle) {
|
static List<HealthCheckTask> provideAvailableHealthCheckTasks(Collection<HealthCheck> availableHealthChecks, @HealthCheckWindow Vault vault, AtomicReference<Masterkey> masterkeyRef, AtomicReference<VaultConfig> vaultConfigRef, SecureRandom csprng, ResourceBundle resourceBundle) {
|
||||||
return availableHealthChecks.stream().map(check -> new HealthCheckTask(vault.getPath(), vaultConfigRef.get(), masterkeyRef.get(), csprng, check, resourceBundle)).toList();
|
return availableHealthChecks.stream().map(check -> new HealthCheckTask(vault.getPath(), vaultConfigRef.get(), masterkeyRef.get(), csprng, check, resourceBundle)).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,10 +87,10 @@ abstract class HealthCheckModule {
|
|||||||
@HealthCheckScoped
|
@HealthCheckScoped
|
||||||
static Stage provideStage(StageFactory factory, @MainWindow Stage owner, ResourceBundle resourceBundle, ChangeListener<Boolean> showingListener) {
|
static Stage provideStage(StageFactory factory, @MainWindow Stage owner, ResourceBundle resourceBundle, ChangeListener<Boolean> showingListener) {
|
||||||
Stage stage = factory.create();
|
Stage stage = factory.create();
|
||||||
stage.setTitle(resourceBundle.getString("health.title"));
|
|
||||||
stage.setResizable(true);
|
|
||||||
stage.initModality(Modality.WINDOW_MODAL);
|
stage.initModality(Modality.WINDOW_MODAL);
|
||||||
stage.initOwner(owner);
|
stage.initOwner(owner);
|
||||||
|
stage.setTitle(resourceBundle.getString("health.title"));
|
||||||
|
stage.setResizable(true);
|
||||||
stage.showingProperty().addListener(showingListener); // bind masterkey lifecycle to window
|
stage.showingProperty().addListener(showingListener); // bind masterkey lifecycle to window
|
||||||
return stage;
|
return stage;
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,16 @@ package org.cryptomator.ui.health;
|
|||||||
import org.cryptomator.cryptofs.VaultConfig;
|
import org.cryptomator.cryptofs.VaultConfig;
|
||||||
import org.cryptomator.cryptofs.health.api.DiagnosticResult;
|
import org.cryptomator.cryptofs.health.api.DiagnosticResult;
|
||||||
import org.cryptomator.cryptofs.health.api.HealthCheck;
|
import org.cryptomator.cryptofs.health.api.HealthCheck;
|
||||||
|
import org.cryptomator.cryptolib.api.CryptorProvider;
|
||||||
import org.cryptomator.cryptolib.api.Masterkey;
|
import org.cryptomator.cryptolib.api.Masterkey;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.Observable;
|
||||||
|
import javafx.beans.property.BooleanProperty;
|
||||||
import javafx.beans.property.LongProperty;
|
import javafx.beans.property.LongProperty;
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
import javafx.beans.property.SimpleLongProperty;
|
import javafx.beans.property.SimpleLongProperty;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
@ -31,8 +35,9 @@ class HealthCheckTask extends Task<Void> {
|
|||||||
private final Masterkey masterkey;
|
private final Masterkey masterkey;
|
||||||
private final SecureRandom csprng;
|
private final SecureRandom csprng;
|
||||||
private final HealthCheck check;
|
private final HealthCheck check;
|
||||||
private final ObservableList<DiagnosticResult> results;
|
private final ObservableList<Result> results;
|
||||||
private final LongProperty durationInMillis;
|
private final LongProperty durationInMillis;
|
||||||
|
private final BooleanProperty chosenForExecution;
|
||||||
|
|
||||||
public HealthCheckTask(Path vaultPath, VaultConfig vaultConfig, Masterkey masterkey, SecureRandom csprng, HealthCheck check, ResourceBundle resourceBundle) {
|
public HealthCheckTask(Path vaultPath, VaultConfig vaultConfig, Masterkey masterkey, SecureRandom csprng, HealthCheck check, ResourceBundle resourceBundle) {
|
||||||
this.vaultPath = Objects.requireNonNull(vaultPath);
|
this.vaultPath = Objects.requireNonNull(vaultPath);
|
||||||
@ -40,7 +45,7 @@ class HealthCheckTask extends Task<Void> {
|
|||||||
this.masterkey = Objects.requireNonNull(masterkey);
|
this.masterkey = Objects.requireNonNull(masterkey);
|
||||||
this.csprng = Objects.requireNonNull(csprng);
|
this.csprng = Objects.requireNonNull(csprng);
|
||||||
this.check = Objects.requireNonNull(check);
|
this.check = Objects.requireNonNull(check);
|
||||||
this.results = FXCollections.observableArrayList();
|
this.results = FXCollections.observableArrayList(Result::observables);
|
||||||
try {
|
try {
|
||||||
updateTitle(resourceBundle.getString("health." + check.identifier()));
|
updateTitle(resourceBundle.getString("health." + check.identifier()));
|
||||||
} catch (MissingResourceException e) {
|
} catch (MissingResourceException e) {
|
||||||
@ -48,32 +53,22 @@ class HealthCheckTask extends Task<Void> {
|
|||||||
updateTitle(check.identifier());
|
updateTitle(check.identifier());
|
||||||
}
|
}
|
||||||
this.durationInMillis = new SimpleLongProperty(-1);
|
this.durationInMillis = new SimpleLongProperty(-1);
|
||||||
|
this.chosenForExecution = new SimpleBooleanProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Void call() {
|
protected Void call() {
|
||||||
Instant start = Instant.now();
|
Instant start = Instant.now();
|
||||||
try (var masterkeyClone = masterkey.clone(); //
|
try (var masterkeyClone = masterkey.clone(); //
|
||||||
var cryptor = vaultConfig.getCipherCombo().getCryptorProvider(csprng).withKey(masterkeyClone)) {
|
var cryptor = CryptorProvider.forScheme(vaultConfig.getCipherCombo()).provide(masterkeyClone, csprng)) {
|
||||||
check.check(vaultPath, vaultConfig, masterkeyClone, cryptor, result -> {
|
check.check(vaultPath, vaultConfig, masterkeyClone, cryptor, diagnosis -> {
|
||||||
if (isCancelled()) {
|
if (isCancelled()) {
|
||||||
throw new CancellationException();
|
throw new CancellationException();
|
||||||
}
|
}
|
||||||
// FIXME: slowdown for demonstration purposes only:
|
Platform.runLater(() -> results.add(Result.create(diagnosis)));
|
||||||
try {
|
|
||||||
Thread.sleep(2000);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
if (isCancelled()) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Platform.runLater(() -> results.add(result));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Platform.runLater(() ->durationInMillis.set(Duration.between(start, Instant.now()).toMillis()));
|
Platform.runLater(() -> durationInMillis.set(Duration.between(start, Instant.now()).toMillis()));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +84,11 @@ class HealthCheckTask extends Task<Void> {
|
|||||||
|
|
||||||
/* Getter */
|
/* Getter */
|
||||||
|
|
||||||
public ObservableList<DiagnosticResult> results() {
|
Observable[] observables() {
|
||||||
|
return new Observable[]{results, chosenForExecution};
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableList<Result> results() {
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,4 +104,11 @@ class HealthCheckTask extends Task<Void> {
|
|||||||
return durationInMillis.get();
|
return durationInMillis.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BooleanProperty chosenForExecutionProperty() {
|
||||||
|
return chosenForExecution;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isChosenForExecution() {
|
||||||
|
return chosenForExecution.get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ public class ReportWriter {
|
|||||||
case SUCCEEDED -> {
|
case SUCCEEDED -> {
|
||||||
writer.write("STATUS: SUCCESS\nRESULTS:\n");
|
writer.write("STATUS: SUCCESS\nRESULTS:\n");
|
||||||
for (var result : task.results()) {
|
for (var result : task.results()) {
|
||||||
writer.write(REPORT_CHECK_RESULT.formatted(result.getSeverity(), result.toString()));
|
writer.write(REPORT_CHECK_RESULT.formatted(result.diagnosis().getSeverity(), result.getDescription()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case CANCELLED -> writer.write("STATUS: CANCELED\n");
|
case CANCELLED -> writer.write("STATUS: CANCELED\n");
|
||||||
|
43
src/main/java/org/cryptomator/ui/health/Result.java
Normal file
43
src/main/java/org/cryptomator/ui/health/Result.java
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package org.cryptomator.ui.health;
|
||||||
|
|
||||||
|
import org.cryptomator.cryptofs.health.api.DiagnosticResult;
|
||||||
|
|
||||||
|
import javafx.beans.Observable;
|
||||||
|
import javafx.beans.property.ObjectProperty;
|
||||||
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
|
|
||||||
|
record Result(DiagnosticResult diagnosis, ObjectProperty<FixState> fixState) {
|
||||||
|
|
||||||
|
enum FixState {
|
||||||
|
NOT_FIXABLE,
|
||||||
|
FIXABLE,
|
||||||
|
FIXING,
|
||||||
|
FIXED,
|
||||||
|
FIX_FAILED
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result create(DiagnosticResult diagnosis) {
|
||||||
|
FixState initialState = switch (diagnosis.getSeverity()) {
|
||||||
|
case WARN -> FixState.FIXABLE;
|
||||||
|
default -> FixState.NOT_FIXABLE;
|
||||||
|
};
|
||||||
|
return new Result(diagnosis, new SimpleObjectProperty<>(initialState));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Observable[] observables() {
|
||||||
|
return new Observable[]{fixState};
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return diagnosis.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public FixState getState() {
|
||||||
|
return fixState.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setState(FixState state) {
|
||||||
|
this.fixState.set(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -4,25 +4,30 @@ import com.google.common.base.Preconditions;
|
|||||||
import org.cryptomator.common.vaults.Vault;
|
import org.cryptomator.common.vaults.Vault;
|
||||||
import org.cryptomator.cryptofs.VaultConfig;
|
import org.cryptomator.cryptofs.VaultConfig;
|
||||||
import org.cryptomator.cryptofs.health.api.DiagnosticResult;
|
import org.cryptomator.cryptofs.health.api.DiagnosticResult;
|
||||||
|
import org.cryptomator.cryptolib.api.CryptorProvider;
|
||||||
import org.cryptomator.cryptolib.api.Masterkey;
|
import org.cryptomator.cryptolib.api.Masterkey;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javafx.scene.control.Alert;
|
import javafx.application.Platform;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.CompletionException;
|
||||||
|
import java.util.concurrent.CompletionStage;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
@HealthCheckScoped
|
@HealthCheckScoped
|
||||||
class ResultFixApplier {
|
class ResultFixApplier {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(ResultFixApplier.class);
|
|
||||||
|
|
||||||
private final Path vaultPath;
|
private final Path vaultPath;
|
||||||
private final SecureRandom csprng;
|
private final SecureRandom csprng;
|
||||||
private final Masterkey masterkey;
|
private final Masterkey masterkey;
|
||||||
private final VaultConfig vaultConfig;
|
private final VaultConfig vaultConfig;
|
||||||
|
private final ExecutorService sequentialExecutor;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public ResultFixApplier(@HealthCheckWindow Vault vault, AtomicReference<Masterkey> masterkeyRef, AtomicReference<VaultConfig> vaultConfigRef, SecureRandom csprng) {
|
public ResultFixApplier(@HealthCheckWindow Vault vault, AtomicReference<Masterkey> masterkeyRef, AtomicReference<VaultConfig> vaultConfigRef, SecureRandom csprng) {
|
||||||
@ -30,18 +35,32 @@ class ResultFixApplier {
|
|||||||
this.masterkey = masterkeyRef.get();
|
this.masterkey = masterkeyRef.get();
|
||||||
this.vaultConfig = vaultConfigRef.get();
|
this.vaultConfig = vaultConfigRef.get();
|
||||||
this.csprng = csprng;
|
this.csprng = csprng;
|
||||||
|
this.sequentialExecutor = Executors.newSingleThreadExecutor();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fix(DiagnosticResult result) {
|
public CompletionStage<Void> fix(Result result) {
|
||||||
Preconditions.checkArgument(result.getSeverity() == DiagnosticResult.Severity.WARN, "Unfixable result");
|
Preconditions.checkArgument(result.getState() == Result.FixState.FIXABLE);
|
||||||
|
result.setState(Result.FixState.FIXING);
|
||||||
|
return CompletableFuture.runAsync(() -> fix(result.diagnosis()), sequentialExecutor)
|
||||||
|
.whenCompleteAsync((unused, throwable) -> {
|
||||||
|
var fixed = throwable == null ? Result.FixState.FIXED : Result.FixState.FIX_FAILED;
|
||||||
|
result.setState(fixed);
|
||||||
|
}, Platform::runLater);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fix(DiagnosticResult diagnosis) {
|
||||||
|
Preconditions.checkArgument(diagnosis.getSeverity() == DiagnosticResult.Severity.WARN, "Unfixable result");
|
||||||
try (var masterkeyClone = masterkey.clone(); //
|
try (var masterkeyClone = masterkey.clone(); //
|
||||||
var cryptor = vaultConfig.getCipherCombo().getCryptorProvider(csprng).withKey(masterkeyClone)) {
|
var cryptor = CryptorProvider.forScheme(vaultConfig.getCipherCombo()).provide(masterkeyClone, csprng)) {
|
||||||
result.fix(vaultPath, vaultConfig, masterkeyClone, cryptor);
|
diagnosis.fix(vaultPath, vaultConfig, masterkeyClone, cryptor);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error("Failed to apply fix", e);
|
throw new FixFailedException(e);
|
||||||
Alert alert = new Alert(Alert.AlertType.ERROR, e.getMessage());
|
}
|
||||||
alert.showAndWait();
|
}
|
||||||
//TODO: real error/not supported handling
|
|
||||||
|
public static class FixFailedException extends CompletionException {
|
||||||
|
private FixFailedException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,84 +1,89 @@
|
|||||||
package org.cryptomator.ui.health;
|
package org.cryptomator.ui.health;
|
||||||
|
|
||||||
import com.tobiasdiez.easybind.EasyBind;
|
import com.tobiasdiez.easybind.EasyBind;
|
||||||
import org.cryptomator.cryptofs.health.api.DiagnosticResult;
|
import com.tobiasdiez.easybind.optional.OptionalBinding;
|
||||||
import org.cryptomator.ui.common.FxController;
|
import org.cryptomator.ui.common.FxController;
|
||||||
import org.cryptomator.ui.controls.FontAwesome5Icon;
|
import org.cryptomator.ui.controls.FontAwesome5Icon;
|
||||||
import org.cryptomator.ui.controls.FontAwesome5IconView;
|
import org.cryptomator.ui.controls.FontAwesome5IconView;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
import javafx.application.Platform;
|
||||||
import javafx.beans.binding.Binding;
|
import javafx.beans.binding.Binding;
|
||||||
|
import javafx.beans.binding.Bindings;
|
||||||
|
import javafx.beans.binding.BooleanBinding;
|
||||||
|
import javafx.beans.binding.ObjectBinding;
|
||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import javafx.beans.value.ObservableValue;
|
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
|
|
||||||
// unscoped because each cell needs its own controller
|
// unscoped because each cell needs its own controller
|
||||||
public class ResultListCellController implements FxController {
|
public class ResultListCellController implements FxController {
|
||||||
|
|
||||||
private final ResultFixApplier fixApplier;
|
private final Logger LOG = LoggerFactory.getLogger(ResultListCellController.class);
|
||||||
private final ObjectProperty<DiagnosticResult> result;
|
|
||||||
|
private final ObjectProperty<Result> result;
|
||||||
private final Binding<String> description;
|
private final Binding<String> description;
|
||||||
|
private final ResultFixApplier fixApplier;
|
||||||
|
private final OptionalBinding<Result.FixState> fixState;
|
||||||
|
private final ObjectBinding<FontAwesome5Icon> glyph;
|
||||||
|
private final BooleanBinding fixable;
|
||||||
|
private final BooleanBinding fixing;
|
||||||
|
private final BooleanBinding fixed;
|
||||||
|
|
||||||
public FontAwesome5IconView iconView;
|
public FontAwesome5IconView iconView;
|
||||||
public Button actionButton;
|
public Button fixButton;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public ResultListCellController(ResultFixApplier fixApplier) {
|
public ResultListCellController(ResultFixApplier fixApplier) {
|
||||||
this.result = new SimpleObjectProperty<>(null);
|
this.result = new SimpleObjectProperty<>(null);
|
||||||
this.description = EasyBind.wrapNullable(result).map(DiagnosticResult::toString).orElse("");
|
this.description = EasyBind.wrapNullable(result).map(Result::getDescription).orElse("");
|
||||||
this.fixApplier = fixApplier;
|
this.fixApplier = fixApplier;
|
||||||
result.addListener(this::updateCellContent);
|
this.fixState = EasyBind.wrapNullable(result).mapObservable(Result::fixState);
|
||||||
}
|
this.glyph = Bindings.createObjectBinding(this::getGlyph, result);
|
||||||
|
this.fixable = Bindings.createBooleanBinding(this::isFixable, fixState);
|
||||||
private void updateCellContent(ObservableValue<? extends DiagnosticResult> observable, DiagnosticResult oldVal, DiagnosticResult newVal) {
|
this.fixing = Bindings.createBooleanBinding(this::isFixing, fixState);
|
||||||
iconView.getStyleClass().clear();
|
this.fixed = Bindings.createBooleanBinding(this::isFixed, fixState);
|
||||||
actionButton.setVisible(false);
|
|
||||||
//TODO: see comment in case WARN
|
|
||||||
actionButton.setManaged(false);
|
|
||||||
switch (newVal.getSeverity()) {
|
|
||||||
case INFO -> {
|
|
||||||
iconView.setGlyph(FontAwesome5Icon.INFO_CIRCLE);
|
|
||||||
iconView.getStyleClass().add("glyph-icon-muted");
|
|
||||||
}
|
|
||||||
case GOOD -> {
|
|
||||||
iconView.setGlyph(FontAwesome5Icon.CHECK);
|
|
||||||
iconView.getStyleClass().add("glyph-icon-primary");
|
|
||||||
}
|
|
||||||
case WARN -> {
|
|
||||||
iconView.setGlyph(FontAwesome5Icon.EXCLAMATION_TRIANGLE);
|
|
||||||
iconView.getStyleClass().add("glyph-icon-orange");
|
|
||||||
//TODO: Neither is any fix implemented, nor it is ensured, that only fix is executed at a time with good ui indication
|
|
||||||
// before both are not fix, do not show the button
|
|
||||||
//actionButton.setVisible(true);
|
|
||||||
}
|
|
||||||
case CRITICAL -> {
|
|
||||||
iconView.setGlyph(FontAwesome5Icon.TIMES);
|
|
||||||
iconView.getStyleClass().add("glyph-icon-red");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public void runResultAction() {
|
public void initialize() {
|
||||||
final var realResult = result.get();
|
// see getGlyph() for relevant glyphs:
|
||||||
if (realResult != null) {
|
EasyBind.includeWhen(iconView.getStyleClass(), "glyph-icon-muted", iconView.glyphProperty().isEqualTo(FontAwesome5Icon.INFO_CIRCLE));
|
||||||
fixApplier.fix(realResult);
|
EasyBind.includeWhen(iconView.getStyleClass(), "glyph-icon-primary", iconView.glyphProperty().isEqualTo(FontAwesome5Icon.CHECK));
|
||||||
|
EasyBind.includeWhen(iconView.getStyleClass(), "glyph-icon-orange", iconView.glyphProperty().isEqualTo(FontAwesome5Icon.EXCLAMATION_TRIANGLE));
|
||||||
|
EasyBind.includeWhen(iconView.getStyleClass(), "glyph-icon-red", iconView.glyphProperty().isEqualTo(FontAwesome5Icon.TIMES));
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void fix() {
|
||||||
|
Result r = result.get();
|
||||||
|
if (r != null) {
|
||||||
|
fixApplier.fix(r).whenCompleteAsync(this::fixFinished, Platform::runLater);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fixFinished(Void unused, Throwable exception) {
|
||||||
|
if (exception != null) {
|
||||||
|
LOG.error("Failed to apply fix", exception);
|
||||||
|
// TODO ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Getter & Setter */
|
/* Getter & Setter */
|
||||||
|
|
||||||
|
public Result getResult() {
|
||||||
public DiagnosticResult getResult() {
|
|
||||||
return result.get();
|
return result.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setResult(DiagnosticResult result) {
|
public void setResult(Result result) {
|
||||||
this.result.set(result);
|
this.result.set(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObjectProperty<DiagnosticResult> resultProperty() {
|
public ObjectProperty<Result> resultProperty() {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +91,49 @@ public class ResultListCellController implements FxController {
|
|||||||
return description.getValue();
|
return description.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ObjectBinding<FontAwesome5Icon> glyphProperty() {
|
||||||
|
return glyph;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FontAwesome5Icon getGlyph() {
|
||||||
|
var r = result.get();
|
||||||
|
if (r == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return switch (r.diagnosis().getSeverity()) {
|
||||||
|
case INFO -> FontAwesome5Icon.INFO_CIRCLE;
|
||||||
|
case GOOD -> FontAwesome5Icon.CHECK;
|
||||||
|
case WARN -> FontAwesome5Icon.EXCLAMATION_TRIANGLE;
|
||||||
|
case CRITICAL -> FontAwesome5Icon.TIMES;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public Binding<String> descriptionProperty() {
|
public Binding<String> descriptionProperty() {
|
||||||
return description;
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BooleanBinding fixableProperty() {
|
||||||
|
return fixable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFixable() {
|
||||||
|
return fixState.get().map(Result.FixState.FIXABLE::equals).orElse(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BooleanBinding fixingProperty() {
|
||||||
|
return fixing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFixing() {
|
||||||
|
return fixState.get().map(Result.FixState.FIXING::equals).orElse(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BooleanBinding fixedProperty() {
|
||||||
|
return fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFixed() {
|
||||||
|
return fixState.get().map(Result.FixState.FIXED::equals).orElse(false);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package org.cryptomator.ui.health;
|
package org.cryptomator.ui.health;
|
||||||
|
|
||||||
|
|
||||||
import org.cryptomator.cryptofs.health.api.DiagnosticResult;
|
|
||||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@ -15,7 +14,7 @@ import java.io.IOException;
|
|||||||
import java.io.UncheckedIOException;
|
import java.io.UncheckedIOException;
|
||||||
|
|
||||||
@HealthCheckScoped
|
@HealthCheckScoped
|
||||||
public class ResultListCellFactory implements Callback<ListView<DiagnosticResult>, ListCell<DiagnosticResult>> {
|
public class ResultListCellFactory implements Callback<ListView<Result>, ListCell<Result>> {
|
||||||
|
|
||||||
private final FxmlLoaderFactory fxmlLoaders;
|
private final FxmlLoaderFactory fxmlLoaders;
|
||||||
|
|
||||||
@ -25,7 +24,7 @@ public class ResultListCellFactory implements Callback<ListView<DiagnosticResult
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListCell<DiagnosticResult> call(ListView<DiagnosticResult> param) {
|
public ListCell<Result> call(ListView<Result> param) {
|
||||||
try {
|
try {
|
||||||
FXMLLoader fxmlLoader = fxmlLoaders.load("/fxml/health_result_listcell.fxml");
|
FXMLLoader fxmlLoader = fxmlLoaders.load("/fxml/health_result_listcell.fxml");
|
||||||
return new ResultListCellFactory.Cell(fxmlLoader.getRoot(), fxmlLoader.getController());
|
return new ResultListCellFactory.Cell(fxmlLoader.getRoot(), fxmlLoader.getController());
|
||||||
@ -34,7 +33,7 @@ public class ResultListCellFactory implements Callback<ListView<DiagnosticResult
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Cell extends ListCell<DiagnosticResult> {
|
private static class Cell extends ListCell<Result> {
|
||||||
|
|
||||||
private final Parent node;
|
private final Parent node;
|
||||||
private final ResultListCellController controller;
|
private final ResultListCellController controller;
|
||||||
@ -45,7 +44,7 @@ public class ResultListCellFactory implements Callback<ListView<DiagnosticResult
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void updateItem(DiagnosticResult item, boolean empty) {
|
protected void updateItem(Result item, boolean empty) {
|
||||||
super.updateItem(item, empty);
|
super.updateItem(item, empty);
|
||||||
if (item == null || empty) {
|
if (item == null || empty) {
|
||||||
setText(null);
|
setText(null);
|
||||||
|
@ -18,11 +18,16 @@ import org.slf4j.LoggerFactory;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.binding.BooleanBinding;
|
||||||
|
import javafx.beans.property.ObjectProperty;
|
||||||
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Optional;
|
import java.io.UncheckedIOException;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.CompletionException;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
@ -31,38 +36,40 @@ public class StartController implements FxController {
|
|||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(StartController.class);
|
private static final Logger LOG = LoggerFactory.getLogger(StartController.class);
|
||||||
|
|
||||||
|
private final Vault vault;
|
||||||
private final Stage window;
|
private final Stage window;
|
||||||
private final Optional<VaultConfig.UnverifiedVaultConfig> unverifiedVaultConfig;
|
private final CompletableFuture<VaultConfig.UnverifiedVaultConfig> unverifiedVaultConfig;
|
||||||
private final KeyLoadingStrategy keyLoadingStrategy;
|
private final KeyLoadingStrategy keyLoadingStrategy;
|
||||||
private final ExecutorService executor;
|
private final ExecutorService executor;
|
||||||
private final AtomicReference<Masterkey> masterkeyRef;
|
private final AtomicReference<Masterkey> masterkeyRef;
|
||||||
private final AtomicReference<VaultConfig> vaultConfigRef;
|
private final AtomicReference<VaultConfig> vaultConfigRef;
|
||||||
private final Lazy<Scene> checkScene;
|
private final Lazy<Scene> checkScene;
|
||||||
private final Lazy<ErrorComponent.Builder> errorComponent;
|
private final Lazy<ErrorComponent.Builder> errorComponent;
|
||||||
|
private final ObjectProperty<State> state = new SimpleObjectProperty<>(State.LOADING);
|
||||||
|
private final BooleanBinding loading = state.isEqualTo(State.LOADING);
|
||||||
|
private final BooleanBinding failed = state.isEqualTo(State.FAILED);
|
||||||
|
private final BooleanBinding loaded = state.isEqualTo(State.LOADED);
|
||||||
|
|
||||||
|
public enum State {
|
||||||
|
LOADING,
|
||||||
|
FAILED,
|
||||||
|
LOADED
|
||||||
|
}
|
||||||
|
|
||||||
/* FXML */
|
/* FXML */
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public StartController(@HealthCheckWindow Vault vault, @HealthCheckWindow Stage window, @HealthCheckWindow KeyLoadingStrategy keyLoadingStrategy, ExecutorService executor, AtomicReference<Masterkey> masterkeyRef, AtomicReference<VaultConfig> vaultConfigRef, @FxmlScene(FxmlFile.HEALTH_CHECK_LIST) Lazy<Scene> checkScene, Lazy<ErrorComponent.Builder> errorComponent) {
|
public StartController(@HealthCheckWindow Vault vault, @HealthCheckWindow Stage window, @HealthCheckWindow KeyLoadingStrategy keyLoadingStrategy, ExecutorService executor, AtomicReference<Masterkey> masterkeyRef, AtomicReference<VaultConfig> vaultConfigRef, @FxmlScene(FxmlFile.HEALTH_CHECK_LIST) Lazy<Scene> checkScene, Lazy<ErrorComponent.Builder> errorComponent) {
|
||||||
|
this.vault = vault;
|
||||||
this.window = window;
|
this.window = window;
|
||||||
|
this.unverifiedVaultConfig = CompletableFuture.supplyAsync(this::loadConfig, executor);
|
||||||
this.keyLoadingStrategy = keyLoadingStrategy;
|
this.keyLoadingStrategy = keyLoadingStrategy;
|
||||||
this.executor = executor;
|
this.executor = executor;
|
||||||
this.masterkeyRef = masterkeyRef;
|
this.masterkeyRef = masterkeyRef;
|
||||||
this.vaultConfigRef = vaultConfigRef;
|
this.vaultConfigRef = vaultConfigRef;
|
||||||
this.checkScene = checkScene;
|
this.checkScene = checkScene;
|
||||||
this.errorComponent = errorComponent;
|
this.errorComponent = errorComponent;
|
||||||
|
this.unverifiedVaultConfig.whenCompleteAsync(this::loadedConfig, Platform::runLater);
|
||||||
//TODO: this is ugly
|
|
||||||
//idea: delay the loading of the vault config and show a spinner (something like "check/load config") and react to the result of the loading
|
|
||||||
//or: load vault config in a previous step to see if it is loadable.
|
|
||||||
VaultConfig.UnverifiedVaultConfig tmp;
|
|
||||||
try {
|
|
||||||
tmp = vault.getUnverifiedVaultConfig();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
tmp = null;
|
|
||||||
}
|
|
||||||
this.unverifiedVaultConfig = Optional.ofNullable(tmp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
@ -74,41 +81,64 @@ public class StartController implements FxController {
|
|||||||
@FXML
|
@FXML
|
||||||
public void next() {
|
public void next() {
|
||||||
LOG.trace("StartController.next()");
|
LOG.trace("StartController.next()");
|
||||||
executor.submit(this::loadKey);
|
CompletableFuture.runAsync(this::loadKey, executor).whenCompleteAsync(this::loadedKey, Platform::runLater);
|
||||||
|
}
|
||||||
|
|
||||||
|
private VaultConfig.UnverifiedVaultConfig loadConfig() {
|
||||||
|
assert !Platform.isFxApplicationThread();
|
||||||
|
try {
|
||||||
|
return this.vault.getUnverifiedVaultConfig();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new UncheckedIOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadedConfig(VaultConfig.UnverifiedVaultConfig cfg, Throwable exception) {
|
||||||
|
assert Platform.isFxApplicationThread();
|
||||||
|
if (exception != null) {
|
||||||
|
state.set(State.FAILED);
|
||||||
|
} else {
|
||||||
|
assert cfg != null;
|
||||||
|
state.set(State.LOADED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadKey() {
|
private void loadKey() {
|
||||||
assert !Platform.isFxApplicationThread();
|
assert !Platform.isFxApplicationThread();
|
||||||
assert unverifiedVaultConfig.isPresent();
|
assert unverifiedVaultConfig.isDone();
|
||||||
try (var masterkey = keyLoadingStrategy.loadKey(unverifiedVaultConfig.orElseThrow().getKeyId())) {
|
var unverifiedCfg = unverifiedVaultConfig.join();
|
||||||
var unverifiedCfg = unverifiedVaultConfig.get();
|
try (var masterkey = keyLoadingStrategy.loadKey(unverifiedCfg.getKeyId())) {
|
||||||
var verifiedCfg = unverifiedCfg.verify(masterkey.getEncoded(), unverifiedCfg.allegedVaultVersion());
|
var verifiedCfg = unverifiedCfg.verify(masterkey.getEncoded(), unverifiedCfg.allegedVaultVersion());
|
||||||
vaultConfigRef.set(verifiedCfg);
|
vaultConfigRef.set(verifiedCfg);
|
||||||
var old = masterkeyRef.getAndSet(masterkey.clone());
|
var old = masterkeyRef.getAndSet(masterkey.clone());
|
||||||
if (old != null) {
|
if (old != null) {
|
||||||
old.destroy();
|
old.destroy();
|
||||||
}
|
}
|
||||||
Platform.runLater(this::loadedKey);
|
|
||||||
} catch (MasterkeyLoadingFailedException e) {
|
} catch (MasterkeyLoadingFailedException e) {
|
||||||
if (keyLoadingStrategy.recoverFromException(e)) {
|
if (keyLoadingStrategy.recoverFromException(e)) {
|
||||||
// retry
|
// retry
|
||||||
loadKey();
|
loadKey();
|
||||||
} else {
|
} else {
|
||||||
Platform.runLater(() -> loadingKeyFailed(e));
|
throw new LoadingFailedException(e);
|
||||||
}
|
}
|
||||||
} catch (VaultKeyInvalidException e) {
|
|
||||||
Platform.runLater(() -> loadingKeyFailed(e));
|
|
||||||
} catch (VaultConfigLoadException e) {
|
} catch (VaultConfigLoadException e) {
|
||||||
Platform.runLater(() -> loadingKeyFailed(e));
|
throw new LoadingFailedException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadedKey() {
|
private void loadedKey(Void unused, Throwable exception) {
|
||||||
LOG.debug("Loaded valid key");
|
assert Platform.isFxApplicationThread();
|
||||||
window.setScene(checkScene.get());
|
if (exception instanceof LoadingFailedException) {
|
||||||
|
loadingKeyFailed(exception.getCause());
|
||||||
|
} else if (exception != null) {
|
||||||
|
loadingKeyFailed(exception);
|
||||||
|
} else {
|
||||||
|
LOG.debug("Loaded valid key");
|
||||||
|
window.setScene(checkScene.get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadingKeyFailed(Exception e) {
|
private void loadingKeyFailed(Throwable e) {
|
||||||
if (e instanceof UnlockCancelledException) {
|
if (e instanceof UnlockCancelledException) {
|
||||||
// ok
|
// ok
|
||||||
} else if (e instanceof VaultKeyInvalidException) {
|
} else if (e instanceof VaultKeyInvalidException) {
|
||||||
@ -120,8 +150,37 @@ public class StartController implements FxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isInvalidConfig() {
|
/* Getter */
|
||||||
return unverifiedVaultConfig.isEmpty();
|
|
||||||
|
public BooleanBinding loadingProperty() {
|
||||||
|
return loading;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isLoading() {
|
||||||
|
return loading.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BooleanBinding failedProperty() {
|
||||||
|
return failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFailed() {
|
||||||
|
return failed.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public BooleanBinding loadedProperty() {
|
||||||
|
return loaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLoaded() {
|
||||||
|
return loaded.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* internal types */
|
||||||
|
|
||||||
|
private static class LoadingFailedException extends CompletionException {
|
||||||
|
LoadingFailedException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ public interface KeyLoadingStrategy extends MasterkeyLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Release any ressources or do follow-up tasks after loading a key.
|
* Release any resources or do follow-up tasks after loading a key.
|
||||||
*
|
*
|
||||||
* @param unlockedSuccessfully <code>true</code> if successfully unlocked a vault with the loaded key
|
* @param unlockedSuccessfully <code>true</code> if successfully unlocked a vault with the loaded key
|
||||||
* @implNote This method might be invoked multiple times, depending on whether multiple attempts to load a key are started.
|
* @implNote This method might be invoked multiple times, depending on whether multiple attempts to load a key are started.
|
||||||
@ -47,7 +47,7 @@ public interface KeyLoadingStrategy extends MasterkeyLoader {
|
|||||||
/**
|
/**
|
||||||
* A key loading strategy that will always fail by throwing a {@link MasterkeyLoadingFailedException}.
|
* A key loading strategy that will always fail by throwing a {@link MasterkeyLoadingFailedException}.
|
||||||
*
|
*
|
||||||
* @param exception The cause of the failure. If not alreay an {@link MasterkeyLoadingFailedException}, it will get wrapped.
|
* @param exception The cause of the failure. If not already an {@link MasterkeyLoadingFailedException}, it will get wrapped.
|
||||||
* @return A new KeyLoadingStrategy that will always fail with an {@link MasterkeyLoadingFailedException}.
|
* @return A new KeyLoadingStrategy that will always fail with an {@link MasterkeyLoadingFailedException}.
|
||||||
*/
|
*/
|
||||||
static KeyLoadingStrategy failed(Exception exception) {
|
static KeyLoadingStrategy failed(Exception exception) {
|
||||||
|
@ -32,7 +32,7 @@ public class MasterkeyFileLoadingStrategy implements KeyLoadingStrategy {
|
|||||||
public static final String SCHEME = "masterkeyfile";
|
public static final String SCHEME = "masterkeyfile";
|
||||||
|
|
||||||
private final Vault vault;
|
private final Vault vault;
|
||||||
private final MasterkeyFileAccess masterkeyFileAcccess;
|
private final MasterkeyFileAccess masterkeyFileAccess;
|
||||||
private final Stage window;
|
private final Stage window;
|
||||||
private final Lazy<Scene> passphraseEntryScene;
|
private final Lazy<Scene> passphraseEntryScene;
|
||||||
private final Lazy<Scene> selectMasterkeyFileScene;
|
private final Lazy<Scene> selectMasterkeyFileScene;
|
||||||
@ -45,9 +45,9 @@ public class MasterkeyFileLoadingStrategy implements KeyLoadingStrategy {
|
|||||||
private boolean wrongPassword;
|
private boolean wrongPassword;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public MasterkeyFileLoadingStrategy(@KeyLoading Vault vault, MasterkeyFileAccess masterkeyFileAcccess, @KeyLoading Stage window, @FxmlScene(FxmlFile.UNLOCK_ENTER_PASSWORD) Lazy<Scene> passphraseEntryScene, @FxmlScene(FxmlFile.UNLOCK_SELECT_MASTERKEYFILE) Lazy<Scene> selectMasterkeyFileScene, UserInteractionLock<MasterkeyFileLoadingModule.PasswordEntry> passwordEntryLock, UserInteractionLock<MasterkeyFileLoadingModule.MasterkeyFileProvision> masterkeyFileProvisionLock, AtomicReference<char[]> password, AtomicReference<Path> filePath, MasterkeyFileLoadingFinisher finisher) {
|
public MasterkeyFileLoadingStrategy(@KeyLoading Vault vault, MasterkeyFileAccess masterkeyFileAccess, @KeyLoading Stage window, @FxmlScene(FxmlFile.UNLOCK_ENTER_PASSWORD) Lazy<Scene> passphraseEntryScene, @FxmlScene(FxmlFile.UNLOCK_SELECT_MASTERKEYFILE) Lazy<Scene> selectMasterkeyFileScene, UserInteractionLock<MasterkeyFileLoadingModule.PasswordEntry> passwordEntryLock, UserInteractionLock<MasterkeyFileLoadingModule.MasterkeyFileProvision> masterkeyFileProvisionLock, AtomicReference<char[]> password, AtomicReference<Path> filePath, MasterkeyFileLoadingFinisher finisher) {
|
||||||
this.vault = vault;
|
this.vault = vault;
|
||||||
this.masterkeyFileAcccess = masterkeyFileAcccess;
|
this.masterkeyFileAccess = masterkeyFileAccess;
|
||||||
this.window = window;
|
this.window = window;
|
||||||
this.passphraseEntryScene = passphraseEntryScene;
|
this.passphraseEntryScene = passphraseEntryScene;
|
||||||
this.selectMasterkeyFileScene = selectMasterkeyFileScene;
|
this.selectMasterkeyFileScene = selectMasterkeyFileScene;
|
||||||
@ -68,7 +68,7 @@ public class MasterkeyFileLoadingStrategy implements KeyLoadingStrategy {
|
|||||||
filePath = getAlternateMasterkeyFilePath();
|
filePath = getAlternateMasterkeyFilePath();
|
||||||
}
|
}
|
||||||
CharSequence passphrase = getPassphrase();
|
CharSequence passphrase = getPassphrase();
|
||||||
return masterkeyFileAcccess.load(filePath, passphrase);
|
return masterkeyFileAccess.load(filePath, passphrase);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
throw new UnlockCancelledException("Unlock interrupted", e);
|
throw new UnlockCancelledException("Unlock interrupted", e);
|
||||||
|
@ -64,7 +64,7 @@ class AppLaunchEventHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO dedup MainWindowController...
|
// TODO deduplicate MainWindowController...
|
||||||
private void addOrRevealVault(Path potentialVaultPath) {
|
private void addOrRevealVault(Path potentialVaultPath) {
|
||||||
assert Platform.isFxApplicationThread();
|
assert Platform.isFxApplicationThread();
|
||||||
try {
|
try {
|
||||||
|
@ -22,7 +22,7 @@ import javafx.stage.Window;
|
|||||||
/**
|
/**
|
||||||
* The sequence of actions performed and checked during lock of a vault.
|
* The sequence of actions performed and checked during lock of a vault.
|
||||||
* <p>
|
* <p>
|
||||||
* This class implements the Task interface, sucht that it can run in the background with some possible forground operations/requests to the ui, without blocking the main app.
|
* This class implements the Task interface, sucht that it can run in the background with some possible foreground operations/requests to the ui, without blocking the main app.
|
||||||
* If the task state is
|
* If the task state is
|
||||||
* <li>succeeded, the vault was successfully locked;</li>
|
* <li>succeeded, the vault was successfully locked;</li>
|
||||||
* <li>canceled, the lock was canceled;</li>
|
* <li>canceled, the lock was canceled;</li>
|
||||||
|
@ -129,7 +129,7 @@ public class MainWindowTitleController implements FxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isShowMinimizeButton() {
|
public boolean isShowMinimizeButton() {
|
||||||
// always show the minimize button if no tray icon is present OR it is explicitily enabled
|
// always show the minimize button if no tray icon is present OR it is explicitly enabled
|
||||||
return !trayMenuInitialized || settings.showMinimizeButton().get();
|
return !trayMenuInitialized || settings.showMinimizeButton().get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ public class AutoCompleter {
|
|||||||
if (Strings.isNullOrEmpty(prefix)) {
|
if (Strings.isNullOrEmpty(prefix)) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
int potentialMatchIdx = findIndexOfLexicographicallyPreceeding(0, dictionary.size(), prefix);
|
int potentialMatchIdx = findIndexOfLexicographicallyPreceding(0, dictionary.size(), prefix);
|
||||||
if (potentialMatchIdx < dictionary.size()) {
|
if (potentialMatchIdx < dictionary.size()) {
|
||||||
String potentialMatch = dictionary.get(potentialMatchIdx);
|
String potentialMatch = dictionary.get(potentialMatchIdx);
|
||||||
return potentialMatch.startsWith(prefix) ? Optional.of(potentialMatch) : Optional.empty();
|
return potentialMatch.startsWith(prefix) ? Optional.of(potentialMatch) : Optional.empty();
|
||||||
@ -48,21 +48,21 @@ public class AutoCompleter {
|
|||||||
* @param prefix
|
* @param prefix
|
||||||
* @return index between [0, dictLen], i.e. index can exceed the upper bounds of {@link #dictionary}.
|
* @return index between [0, dictLen], i.e. index can exceed the upper bounds of {@link #dictionary}.
|
||||||
*/
|
*/
|
||||||
private int findIndexOfLexicographicallyPreceeding(int begin, int end, String prefix) {
|
private int findIndexOfLexicographicallyPreceding(int begin, int end, String prefix) {
|
||||||
if (begin >= end) {
|
if (begin >= end) {
|
||||||
return begin; // this is usually where a binary search ends "unsuccessful"
|
return begin; // this is usually where a binary search ends "unsuccessful"
|
||||||
}
|
}
|
||||||
|
|
||||||
int mid = (begin + end) / 2;
|
int mid = (begin + end) / 2;
|
||||||
String word = dictionary.get(mid);
|
String word = dictionary.get(mid);
|
||||||
if (prefix.compareTo(word) <= 0) { // prefix preceeds or matches word
|
if (prefix.compareTo(word) <= 0) { // prefix precedes or matches word
|
||||||
// proceed in left half
|
// proceed in left half
|
||||||
assert mid < end;
|
assert mid < end;
|
||||||
return findIndexOfLexicographicallyPreceeding(0, mid, prefix);
|
return findIndexOfLexicographicallyPreceding(0, mid, prefix);
|
||||||
} else {
|
} else {
|
||||||
// proceed in right half
|
// proceed in right half
|
||||||
assert mid >= begin;
|
assert mid >= begin;
|
||||||
return findIndexOfLexicographicallyPreceeding(mid + 1, end, prefix);
|
return findIndexOfLexicographicallyPreceding(mid + 1, end, prefix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ class WordEncoder {
|
|||||||
* @throws IllegalArgumentException If input is not a multiple of three bytes
|
* @throws IllegalArgumentException If input is not a multiple of three bytes
|
||||||
*/
|
*/
|
||||||
public String encodePadded(byte[] input) {
|
public String encodePadded(byte[] input) {
|
||||||
Preconditions.checkArgument(input.length % 3 == 0, "input needs to be padded to a multipe of three");
|
Preconditions.checkArgument(input.length % 3 == 0, "input needs to be padded to a multiple of three");
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
for (int i = 0; i < input.length; i += 3) {
|
for (int i = 0; i < input.length; i += 3) {
|
||||||
byte b1 = input[i];
|
byte b1 = input[i];
|
||||||
@ -85,12 +85,12 @@ class WordEncoder {
|
|||||||
* @throws IllegalArgumentException If the encoded string doesn't consist of a multiple of two words or one of the words is unknown to this encoder.
|
* @throws IllegalArgumentException If the encoded string doesn't consist of a multiple of two words or one of the words is unknown to this encoder.
|
||||||
*/
|
*/
|
||||||
public byte[] decode(String encoded) {
|
public byte[] decode(String encoded) {
|
||||||
List<String> splitted = Splitter.on(DELIMITER).omitEmptyStrings().splitToList(Strings.nullToEmpty(encoded));
|
List<String> split = Splitter.on(DELIMITER).omitEmptyStrings().splitToList(Strings.nullToEmpty(encoded));
|
||||||
Preconditions.checkArgument(splitted.size() % 2 == 0, "%s needs to be a multiple of two words", encoded);
|
Preconditions.checkArgument(split.size() % 2 == 0, "%s needs to be a multiple of two words", encoded);
|
||||||
byte[] result = new byte[splitted.size() / 2 * 3];
|
byte[] result = new byte[split.size() / 2 * 3];
|
||||||
for (int i = 0; i < splitted.size(); i += 2) {
|
for (int i = 0; i < split.size(); i += 2) {
|
||||||
String w1 = splitted.get(i);
|
String w1 = split.get(i);
|
||||||
String w2 = splitted.get(i + 1);
|
String w2 = split.get(i + 1);
|
||||||
int firstWordIndex = indices.getOrDefault(w1, -1);
|
int firstWordIndex = indices.getOrDefault(w1, -1);
|
||||||
int secondWordIndex = indices.getOrDefault(w2, -1);
|
int secondWordIndex = indices.getOrDefault(w2, -1);
|
||||||
Preconditions.checkArgument(firstWordIndex != -1, "%s not in dictionary", w1);
|
Preconditions.checkArgument(firstWordIndex != -1, "%s not in dictionary", w1);
|
||||||
|
@ -65,8 +65,8 @@ public class VaultStatisticsController implements FxController {
|
|||||||
this.cacheHitRate = WeakBindings.bindDouble(stats.cacheHitRateProperty());
|
this.cacheHitRate = WeakBindings.bindDouble(stats.cacheHitRateProperty());
|
||||||
this.cacheHitDegrees = cacheHitRate.multiply(-270);
|
this.cacheHitDegrees = cacheHitRate.multiply(-270);
|
||||||
this.cacheHitPercentage = cacheHitRate.multiply(100);
|
this.cacheHitPercentage = cacheHitRate.multiply(100);
|
||||||
this.totalBytesRead = WeakBindings.bindLong(stats.toalBytesReadProperty());
|
this.totalBytesRead = WeakBindings.bindLong(stats.totalBytesReadProperty());
|
||||||
this.totalBytesWritten = WeakBindings.bindLong(stats.toalBytesWrittenProperty());
|
this.totalBytesWritten = WeakBindings.bindLong(stats.totalBytesWrittenProperty());
|
||||||
this.totalBytesDecrypted = WeakBindings.bindLong(stats.totalBytesDecryptedProperty());
|
this.totalBytesDecrypted = WeakBindings.bindLong(stats.totalBytesDecryptedProperty());
|
||||||
this.totalBytesEncrypted = WeakBindings.bindLong(stats.totalBytesEncryptedProperty());
|
this.totalBytesEncrypted = WeakBindings.bindLong(stats.totalBytesEncryptedProperty());
|
||||||
this.filesRead = WeakBindings.bindLong(stats.filesRead());
|
this.filesRead = WeakBindings.bindLong(stats.filesRead());
|
||||||
@ -102,7 +102,7 @@ public class VaultStatisticsController implements FxController {
|
|||||||
this.decryptedBytesRead = readData;
|
this.decryptedBytesRead = readData;
|
||||||
this.encryptedBytesWrite = writeData;
|
this.encryptedBytesWrite = writeData;
|
||||||
|
|
||||||
// initialize data once and change value of datapoints later:
|
// initialize data once and change value of data points later:
|
||||||
for (int i = 0; i < IO_SAMPLING_STEPS; i++) {
|
for (int i = 0; i < IO_SAMPLING_STEPS; i++) {
|
||||||
decryptedBytesRead.getData().add(new Data<>(i, 0));
|
decryptedBytesRead.getData().add(new Data<>(i, 0));
|
||||||
encryptedBytesWrite.getData().add(new Data<>(i, 0));
|
encryptedBytesWrite.getData().add(new Data<>(i, 0));
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
package org.cryptomator.ui.vaultoptions;
|
|
||||||
|
|
||||||
import org.cryptomator.common.vaults.Vault;
|
|
||||||
import org.cryptomator.ui.common.FxController;
|
|
||||||
import org.cryptomator.ui.controls.NumericTextField;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javafx.beans.binding.Bindings;
|
|
||||||
import javafx.fxml.FXML;
|
|
||||||
import javafx.scene.control.CheckBox;
|
|
||||||
import javafx.util.StringConverter;
|
|
||||||
|
|
||||||
@VaultOptionsScoped
|
|
||||||
public class AutoLockVaultOptionsController implements FxController {
|
|
||||||
|
|
||||||
private final Vault vault;
|
|
||||||
|
|
||||||
public CheckBox lockAfterTimeCheckbox;
|
|
||||||
public NumericTextField lockTimeInMinutesTextField;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
AutoLockVaultOptionsController(@VaultOptionsWindow Vault vault) {
|
|
||||||
this.vault = vault;
|
|
||||||
}
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
public void initialize() {
|
|
||||||
lockAfterTimeCheckbox.selectedProperty().bindBidirectional(vault.getVaultSettings().autoLockWhenIdle());
|
|
||||||
Bindings.bindBidirectional(lockTimeInMinutesTextField.textProperty(), vault.getVaultSettings().autoLockIdleSeconds(), new IdleTimeSecondsConverter());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class IdleTimeSecondsConverter extends StringConverter<Number> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString(Number seconds) {
|
|
||||||
int minutes = seconds.intValue() / 60; // int-truncate
|
|
||||||
return Integer.toString(minutes);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Number fromString(String string) {
|
|
||||||
try {
|
|
||||||
int minutes = Integer.valueOf(string);
|
|
||||||
return minutes * 60;
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -3,10 +3,11 @@ package org.cryptomator.ui.vaultoptions;
|
|||||||
import org.cryptomator.common.settings.WhenUnlocked;
|
import org.cryptomator.common.settings.WhenUnlocked;
|
||||||
import org.cryptomator.common.vaults.Vault;
|
import org.cryptomator.common.vaults.Vault;
|
||||||
import org.cryptomator.ui.common.FxController;
|
import org.cryptomator.ui.common.FxController;
|
||||||
import org.cryptomator.ui.health.HealthCheckComponent;
|
import org.cryptomator.ui.controls.NumericTextField;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javafx.beans.Observable;
|
import javafx.beans.Observable;
|
||||||
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.control.CheckBox;
|
import javafx.scene.control.CheckBox;
|
||||||
import javafx.scene.control.ChoiceBox;
|
import javafx.scene.control.ChoiceBox;
|
||||||
@ -23,18 +24,18 @@ public class GeneralVaultOptionsController implements FxController {
|
|||||||
|
|
||||||
private final Stage window;
|
private final Stage window;
|
||||||
private final Vault vault;
|
private final Vault vault;
|
||||||
private final HealthCheckComponent.Builder healthCheckWindow;
|
|
||||||
private final ResourceBundle resourceBundle;
|
private final ResourceBundle resourceBundle;
|
||||||
|
|
||||||
public TextField vaultName;
|
public TextField vaultName;
|
||||||
public CheckBox unlockOnStartupCheckbox;
|
public CheckBox unlockOnStartupCheckbox;
|
||||||
public ChoiceBox<WhenUnlocked> actionAfterUnlockChoiceBox;
|
public ChoiceBox<WhenUnlocked> actionAfterUnlockChoiceBox;
|
||||||
|
public CheckBox lockAfterTimeCheckbox;
|
||||||
|
public NumericTextField lockTimeInMinutesTextField;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
GeneralVaultOptionsController(@VaultOptionsWindow Stage window, @VaultOptionsWindow Vault vault, HealthCheckComponent.Builder healthCheckWindow, ResourceBundle resourceBundle) {
|
GeneralVaultOptionsController(@VaultOptionsWindow Stage window, @VaultOptionsWindow Vault vault, ResourceBundle resourceBundle) {
|
||||||
this.window = window;
|
this.window = window;
|
||||||
this.vault = vault;
|
this.vault = vault;
|
||||||
this.healthCheckWindow = healthCheckWindow;
|
|
||||||
this.resourceBundle = resourceBundle;
|
this.resourceBundle = resourceBundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,6 +48,8 @@ public class GeneralVaultOptionsController implements FxController {
|
|||||||
actionAfterUnlockChoiceBox.getItems().addAll(WhenUnlocked.values());
|
actionAfterUnlockChoiceBox.getItems().addAll(WhenUnlocked.values());
|
||||||
actionAfterUnlockChoiceBox.valueProperty().bindBidirectional(vault.getVaultSettings().actionAfterUnlock());
|
actionAfterUnlockChoiceBox.valueProperty().bindBidirectional(vault.getVaultSettings().actionAfterUnlock());
|
||||||
actionAfterUnlockChoiceBox.setConverter(new WhenUnlockedConverter(resourceBundle));
|
actionAfterUnlockChoiceBox.setConverter(new WhenUnlockedConverter(resourceBundle));
|
||||||
|
lockAfterTimeCheckbox.selectedProperty().bindBidirectional(vault.getVaultSettings().autoLockWhenIdle());
|
||||||
|
Bindings.bindBidirectional(lockTimeInMinutesTextField.textProperty(), vault.getVaultSettings().autoLockIdleSeconds(), new IdleTimeSecondsConverter());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void trimVaultNameOnFocusLoss(Observable observable, Boolean wasFocussed, Boolean isFocussed) {
|
private void trimVaultNameOnFocusLoss(Observable observable, Boolean wasFocussed, Boolean isFocussed) {
|
||||||
@ -64,12 +67,6 @@ public class GeneralVaultOptionsController implements FxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
|
||||||
public void showHealthCheck() {
|
|
||||||
healthCheckWindow.vault(vault).build().showHealthCheckWindow();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static class WhenUnlockedConverter extends StringConverter<WhenUnlocked> {
|
private static class WhenUnlockedConverter extends StringConverter<WhenUnlocked> {
|
||||||
|
|
||||||
private final ResourceBundle resourceBundle;
|
private final ResourceBundle resourceBundle;
|
||||||
@ -89,4 +86,22 @@ public class GeneralVaultOptionsController implements FxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class IdleTimeSecondsConverter extends StringConverter<Number> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(Number seconds) {
|
||||||
|
int minutes = seconds.intValue() / 60; // int-truncate
|
||||||
|
return Integer.toString(minutes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Number fromString(String string) {
|
||||||
|
try {
|
||||||
|
int minutes = Integer.valueOf(string);
|
||||||
|
return minutes * 60;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
package org.cryptomator.ui.vaultoptions;
|
||||||
|
|
||||||
|
import org.cryptomator.common.vaults.Vault;
|
||||||
|
import org.cryptomator.ui.common.FxController;
|
||||||
|
import org.cryptomator.ui.health.HealthCheckComponent;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javafx.event.ActionEvent;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
@VaultOptionsScoped
|
||||||
|
public class HealthVaultOptionsController implements FxController {
|
||||||
|
|
||||||
|
private final Stage window;
|
||||||
|
private final Vault vault;
|
||||||
|
private final HealthCheckComponent.Builder healthCheckWindow;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public HealthVaultOptionsController(@VaultOptionsWindow Stage window, @VaultOptionsWindow Vault vault, HealthCheckComponent.Builder healthCheckWindow) {
|
||||||
|
this.window = window;
|
||||||
|
this.vault = vault;
|
||||||
|
this.healthCheckWindow = healthCheckWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public void startHealthCheck(ActionEvent event) {
|
||||||
|
healthCheckWindow.vault(vault).windowToClose(window).build().showHealthCheckWindow();
|
||||||
|
}
|
||||||
|
}
|
@ -23,7 +23,11 @@ public enum SelectedVaultOptionsTab {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Show Auto-Lock tab
|
* Show Auto-Lock tab
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
AUTOLOCK,
|
AUTOLOCK,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show health tab
|
||||||
|
*/
|
||||||
|
HEALTH;
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ public class VaultOptionsController implements FxController {
|
|||||||
public Tab mountTab;
|
public Tab mountTab;
|
||||||
public Tab keyTab;
|
public Tab keyTab;
|
||||||
public Tab autoLockTab;
|
public Tab autoLockTab;
|
||||||
|
public Tab healthTab;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
VaultOptionsController(@VaultOptionsWindow Stage window, ObjectProperty<SelectedVaultOptionsTab> selectedTabProperty) {
|
VaultOptionsController(@VaultOptionsWindow Stage window, ObjectProperty<SelectedVaultOptionsTab> selectedTabProperty) {
|
||||||
@ -49,6 +50,7 @@ public class VaultOptionsController implements FxController {
|
|||||||
case MOUNT -> mountTab;
|
case MOUNT -> mountTab;
|
||||||
case KEY -> keyTab;
|
case KEY -> keyTab;
|
||||||
case AUTOLOCK -> autoLockTab;
|
case AUTOLOCK -> autoLockTab;
|
||||||
|
case HEALTH -> healthTab;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,6 @@ abstract class VaultOptionsModule {
|
|||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@IntoMap
|
@IntoMap
|
||||||
@FxControllerKey(AutoLockVaultOptionsController.class)
|
@FxControllerKey(HealthVaultOptionsController.class)
|
||||||
abstract FxController bindAutoLockVaultOptionsController(AutoLockVaultOptionsController controller);
|
abstract FxController bindHealthOptionsController(HealthVaultOptionsController controller);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
org.cryptomator.ui.health.DummyHealthChecks$DummyCheck1
|
||||||
|
org.cryptomator.ui.health.DummyHealthChecks$DummyCheck2
|
||||||
|
org.cryptomator.ui.health.DummyHealthChecks$DummyCheck3
|
@ -3,17 +3,18 @@
|
|||||||
<?import javafx.geometry.Insets?>
|
<?import javafx.geometry.Insets?>
|
||||||
<?import javafx.scene.control.Button?>
|
<?import javafx.scene.control.Button?>
|
||||||
<?import javafx.scene.control.ButtonBar?>
|
<?import javafx.scene.control.ButtonBar?>
|
||||||
|
<?import javafx.scene.control.CheckBox?>
|
||||||
<?import javafx.scene.control.Label?>
|
<?import javafx.scene.control.Label?>
|
||||||
<?import javafx.scene.control.ListView?>
|
<?import javafx.scene.control.ListView?>
|
||||||
<?import javafx.scene.layout.HBox?>
|
<?import javafx.scene.layout.HBox?>
|
||||||
|
<?import javafx.scene.layout.StackPane?>
|
||||||
<?import javafx.scene.layout.VBox?>
|
<?import javafx.scene.layout.VBox?>
|
||||||
<?import java.lang.Integer?>
|
<?import java.lang.Integer?>
|
||||||
<?import javafx.scene.layout.StackPane?>
|
|
||||||
<?import javafx.scene.control.CheckBox?>
|
|
||||||
<VBox xmlns:fx="http://javafx.com/fxml"
|
<VBox xmlns:fx="http://javafx.com/fxml"
|
||||||
xmlns="http://javafx.com/javafx"
|
xmlns="http://javafx.com/javafx"
|
||||||
fx:controller="org.cryptomator.ui.health.CheckListController"
|
fx:controller="org.cryptomator.ui.health.CheckListController"
|
||||||
minHeight="145"
|
prefWidth="600"
|
||||||
|
prefHeight="400"
|
||||||
spacing="12">
|
spacing="12">
|
||||||
<padding>
|
<padding>
|
||||||
<Insets topRightBottomLeft="12"/>
|
<Insets topRightBottomLeft="12"/>
|
||||||
@ -28,7 +29,7 @@
|
|||||||
<CheckBox onAction="#toggleSelectAll" text="%health.checkList.selectAllBox" visible="${!controller.showResultScreen}" managed="${!controller.showResultScreen}" />
|
<CheckBox onAction="#toggleSelectAll" text="%health.checkList.selectAllBox" visible="${!controller.showResultScreen}" managed="${!controller.showResultScreen}" />
|
||||||
<ListView fx:id="checksListView" VBox.vgrow="ALWAYS"/>
|
<ListView fx:id="checksListView" VBox.vgrow="ALWAYS"/>
|
||||||
</VBox>
|
</VBox>
|
||||||
<StackPane visible="${controller.showResultScreen}" managed="${controller.showResultScreen}" HBox.hgrow="ALWAYS" >
|
<StackPane visible="${controller.showResultScreen}" HBox.hgrow="ALWAYS" >
|
||||||
<VBox minWidth="300" alignment="CENTER" visible="${!controller.anyCheckSelected}" managed="${!controller.anyCheckSelected}" >
|
<VBox minWidth="300" alignment="CENTER" visible="${!controller.anyCheckSelected}" managed="${!controller.anyCheckSelected}" >
|
||||||
<Label text="%health.check.detail.noSelectedCheck" wrapText="true" alignment="CENTER" />
|
<Label text="%health.check.detail.noSelectedCheck" wrapText="true" alignment="CENTER" />
|
||||||
</VBox>
|
</VBox>
|
||||||
@ -39,7 +40,7 @@
|
|||||||
<buttons>
|
<buttons>
|
||||||
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" onAction="#cancelCheck" disable="${!controller.running}" visible="${controller.showResultScreen}" managed="${controller.showResultScreen}" />
|
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" onAction="#cancelCheck" disable="${!controller.running}" visible="${controller.showResultScreen}" managed="${controller.showResultScreen}" />
|
||||||
<Button text="%health.check.exportBtn" ButtonBar.buttonData="NEXT_FORWARD" defaultButton="true" disable="${!controller.finished}" visible="${controller.showResultScreen}" managed="${controller.showResultScreen}" onAction="#exportResults"/>
|
<Button text="%health.check.exportBtn" ButtonBar.buttonData="NEXT_FORWARD" defaultButton="true" disable="${!controller.finished}" visible="${controller.showResultScreen}" managed="${controller.showResultScreen}" onAction="#exportResults"/>
|
||||||
<Button text="%health.check.runBatchBtn" ButtonBar.buttonData="NEXT_FORWARD" defaultButton="true" onAction="#runSelectedChecks" disable="${controller.numberOfPickedChecks == ZERO}" visible="${!controller.showResultScreen}" managed="${!controller.showResultScreen}"/>
|
<Button text="%health.check.runBatchBtn" ButtonBar.buttonData="NEXT_FORWARD" defaultButton="true" onAction="#runSelectedChecks" disable="${controller.chosenTaskCount == ZERO}" visible="${!controller.showResultScreen}" managed="${!controller.showResultScreen}"/>
|
||||||
</buttons>
|
</buttons>
|
||||||
</ButtonBar>
|
</ButtonBar>
|
||||||
</children>
|
</children>
|
||||||
|
@ -6,6 +6,10 @@
|
|||||||
<?import javafx.scene.control.Label?>
|
<?import javafx.scene.control.Label?>
|
||||||
<?import javafx.scene.layout.HBox?>
|
<?import javafx.scene.layout.HBox?>
|
||||||
<?import javafx.scene.layout.Region?>
|
<?import javafx.scene.layout.Region?>
|
||||||
|
<?import javafx.scene.control.ProgressIndicator?>
|
||||||
|
<?import javafx.scene.text.Text?>
|
||||||
|
<?import javafx.scene.layout.Pane?>
|
||||||
|
<?import javafx.scene.layout.StackPane?>
|
||||||
<HBox xmlns:fx="http://javafx.com/fxml"
|
<HBox xmlns:fx="http://javafx.com/fxml"
|
||||||
xmlns="http://javafx.com/javafx"
|
xmlns="http://javafx.com/javafx"
|
||||||
fx:controller="org.cryptomator.ui.health.ResultListCellController"
|
fx:controller="org.cryptomator.ui.health.ResultListCellController"
|
||||||
@ -18,12 +22,18 @@
|
|||||||
<Insets topRightBottomLeft="6"/>
|
<Insets topRightBottomLeft="6"/>
|
||||||
</padding>
|
</padding>
|
||||||
<children>
|
<children>
|
||||||
<FontAwesome5IconView fx:id="iconView" HBox.hgrow="NEVER" glyphSize="16"/>
|
<FontAwesome5IconView fx:id="iconView" HBox.hgrow="NEVER" glyphSize="16" glyph="${controller.glyph}"/>
|
||||||
<Label text="${controller.description}"/>
|
<Label text="${controller.description}"/>
|
||||||
<Region HBox.hgrow="ALWAYS"/>
|
<Region HBox.hgrow="ALWAYS"/>
|
||||||
<!-- TODO: setting the minWidth of the button is just a workaround.
|
<!-- TODO: setting the minWidth of the button is just a workaround.
|
||||||
What we actually want to do is to prevent shrinking the button more than the text
|
What we actually want to do is to prevent shrinking the button more than the text
|
||||||
-> own subclass of HBox is needed -->
|
-> own subclass of HBox is needed -->
|
||||||
<Button fx:id="actionButton" text="%health.check.fixBtn" onAction="#runResultAction" alignment="CENTER" visible="false" minWidth="-Infinity"/>
|
<StackPane HBox.hgrow="NEVER">
|
||||||
|
<children>
|
||||||
|
<Button fx:id="fixButton" text="%health.check.fixBtn" visible="${controller.fixable}" managed="${controller.fixable}" onAction="#fix" alignment="CENTER" minWidth="-Infinity"/>
|
||||||
|
<ProgressIndicator progress="-1" prefWidth="12" prefHeight="12" visible="${controller.fixing}" managed="${controller.fixing}"/>
|
||||||
|
<FontAwesome5IconView glyph="CHECK" glyphSize="16" visible="${controller.fixed}" managed="${controller.fixed}"/>
|
||||||
|
</children>
|
||||||
|
</StackPane>
|
||||||
</children>
|
</children>
|
||||||
</HBox>
|
</HBox>
|
||||||
|
@ -17,23 +17,25 @@
|
|||||||
<Insets topRightBottomLeft="12"/>
|
<Insets topRightBottomLeft="12"/>
|
||||||
</padding>
|
</padding>
|
||||||
<children>
|
<children>
|
||||||
<Label text="%health.start.introduction" wrapText="true"/>
|
<Label text="TODO loading config..." visible="${controller.loading}" managed="${controller.loading}" wrapText="true" contentDisplay="LEFT">
|
||||||
|
|
||||||
<!-- TODO: combine the two below labels to one and bind the properties accordingly or, preferably think about a new flow -->
|
|
||||||
<Label text="%health.start.configInvalid" visible="${controller.invalidConfig}" managed="${controller.invalidConfig}" wrapText="true" contentDisplay="LEFT">
|
|
||||||
<graphic>
|
<graphic>
|
||||||
<FontAwesome5IconView glyph="TIMES" styleClass="glyph-icon-red" />
|
<FontAwesome5IconView glyph="SPINNER"/>
|
||||||
</graphic>
|
</graphic>
|
||||||
</Label>
|
</Label>
|
||||||
<Label text="%health.start.configValid" visible="${!controller.invalidConfig}" managed="${!controller.invalidConfig}" wrapText="true" contentDisplay="LEFT">
|
<Label text="%health.start.configInvalid" visible="${controller.failed}" managed="${controller.failed}" wrapText="true" contentDisplay="LEFT">
|
||||||
<graphic>
|
<graphic>
|
||||||
<FontAwesome5IconView glyph="CHECK" styleClass="glyph-icon-primary" />
|
<FontAwesome5IconView glyph="TIMES" styleClass="glyph-icon-red"/>
|
||||||
|
</graphic>
|
||||||
|
</Label>
|
||||||
|
<Label text="%health.start.configValid" visible="${controller.loaded}" managed="${controller.loaded}" wrapText="true" contentDisplay="LEFT">
|
||||||
|
<graphic>
|
||||||
|
<FontAwesome5IconView glyph="CHECK" styleClass="glyph-icon-primary"/>
|
||||||
</graphic>
|
</graphic>
|
||||||
</Label>
|
</Label>
|
||||||
<ButtonBar buttonMinWidth="120" buttonOrder="+CX">
|
<ButtonBar buttonMinWidth="120" buttonOrder="+CX">
|
||||||
<buttons>
|
<buttons>
|
||||||
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#close"/>
|
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#close"/>
|
||||||
<Button text="%generic.button.next" ButtonBar.buttonData="NEXT_FORWARD" disable="${controller.invalidConfig}" defaultButton="true" onAction="#next"/>
|
<Button text="%generic.button.next" ButtonBar.buttonData="NEXT_FORWARD" disable="${!controller.loaded}" defaultButton="true" onAction="#next"/>
|
||||||
</buttons>
|
</buttons>
|
||||||
</ButtonBar>
|
</ButtonBar>
|
||||||
</children>
|
</children>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<?import org.cryptomator.ui.controls.DataLabel?>
|
<?import org.cryptomator.ui.controls.DataLabel?>
|
||||||
<?import org.cryptomator.ui.controls.FormattedLabel?>
|
<?import org.cryptomator.ui.controls.FormattedLabel?>
|
||||||
<?import org.cryptomator.ui.controls.ThrougputLabel?>
|
<?import org.cryptomator.ui.controls.ThroughputLabel?>
|
||||||
<?import javafx.geometry.Insets?>
|
<?import javafx.geometry.Insets?>
|
||||||
<?import javafx.scene.chart.AreaChart?>
|
<?import javafx.scene.chart.AreaChart?>
|
||||||
<?import javafx.scene.chart.NumberAxis?>
|
<?import javafx.scene.chart.NumberAxis?>
|
||||||
@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
<!-- Read -->
|
<!-- Read -->
|
||||||
<VBox prefWidth="300" prefHeight="300" spacing="6" alignment="CENTER">
|
<VBox prefWidth="300" prefHeight="300" spacing="6" alignment="CENTER">
|
||||||
<ThrougputLabel styleClass="label-large" idleFormat="%stats.read.throughput.idle" kibsFormat="%stats.read.throughput.kibs" mibsFormat="%stats.read.throughput.mibs" bytesPerSecond="${controller.bpsRead}"/>
|
<ThroughputLabel styleClass="label-large" idleFormat="%stats.read.throughput.idle" kibsFormat="%stats.read.throughput.kibs" mibsFormat="%stats.read.throughput.mibs" bytesPerSecond="${controller.bpsRead}"/>
|
||||||
<AreaChart fx:id="readChart" styleClass="io-stats" createSymbols="false" animated="false">
|
<AreaChart fx:id="readChart" styleClass="io-stats" createSymbols="false" animated="false">
|
||||||
<xAxis>
|
<xAxis>
|
||||||
<NumberAxis fx:id="readChartXAxis" styleClass="io-stats" autoRanging="false" forceZeroInRange="false" side="BOTTOM"/>
|
<NumberAxis fx:id="readChartXAxis" styleClass="io-stats" autoRanging="false" forceZeroInRange="false" side="BOTTOM"/>
|
||||||
@ -56,7 +56,7 @@
|
|||||||
|
|
||||||
<!-- Write -->
|
<!-- Write -->
|
||||||
<VBox prefWidth="300" prefHeight="300" spacing="6" alignment="CENTER">
|
<VBox prefWidth="300" prefHeight="300" spacing="6" alignment="CENTER">
|
||||||
<ThrougputLabel styleClass="label-large" idleFormat="%stats.write.throughput.idle" kibsFormat="%stats.write.throughput.kibs" mibsFormat="%stats.write.throughput.mibs" bytesPerSecond="${controller.bpsWritten}"/>
|
<ThroughputLabel styleClass="label-large" idleFormat="%stats.write.throughput.idle" kibsFormat="%stats.write.throughput.kibs" mibsFormat="%stats.write.throughput.mibs" bytesPerSecond="${controller.bpsWritten}"/>
|
||||||
<AreaChart fx:id="writeChart" styleClass="io-stats" createSymbols="false" animated="false">
|
<AreaChart fx:id="writeChart" styleClass="io-stats" createSymbols="false" animated="false">
|
||||||
<xAxis>
|
<xAxis>
|
||||||
<NumberAxis fx:id="writeChartXAxis" styleClass="io-stats" autoRanging="false" forceZeroInRange="false" side="BOTTOM"/>
|
<NumberAxis fx:id="writeChartXAxis" styleClass="io-stats" autoRanging="false" forceZeroInRange="false" side="BOTTOM"/>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
|
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
|
||||||
<?import org.cryptomator.ui.controls.ThrougputLabel?>
|
<?import org.cryptomator.ui.controls.ThroughputLabel?>
|
||||||
<?import javafx.scene.control.Button?>
|
<?import javafx.scene.control.Button?>
|
||||||
<?import javafx.scene.control.Label?>
|
<?import javafx.scene.control.Label?>
|
||||||
<?import javafx.scene.control.Tooltip?>
|
<?import javafx.scene.control.Tooltip?>
|
||||||
@ -41,11 +41,11 @@
|
|||||||
<VBox spacing="6">
|
<VBox spacing="6">
|
||||||
<HBox alignment="CENTER_RIGHT" spacing="6">
|
<HBox alignment="CENTER_RIGHT" spacing="6">
|
||||||
<Label styleClass="label-small,label-muted" text="%main.vaultDetail.bytesPerSecondRead"/>
|
<Label styleClass="label-small,label-muted" text="%main.vaultDetail.bytesPerSecondRead"/>
|
||||||
<ThrougputLabel styleClass="label-small,label-muted" alignment="CENTER_RIGHT" minWidth="60" idleFormat="%main.vaultDetail.throughput.idle" kibsFormat="%main.vaultDetail.throughput.kbps" mibsFormat="%main.vaultDetail.throughput.mbps" bytesPerSecond="${controller.vault.stats.bytesPerSecondRead}"/>
|
<ThroughputLabel styleClass="label-small,label-muted" alignment="CENTER_RIGHT" minWidth="60" idleFormat="%main.vaultDetail.throughput.idle" kibsFormat="%main.vaultDetail.throughput.kbps" mibsFormat="%main.vaultDetail.throughput.mbps" bytesPerSecond="${controller.vault.stats.bytesPerSecondRead}"/>
|
||||||
</HBox>
|
</HBox>
|
||||||
<HBox alignment="CENTER_RIGHT" spacing="6">
|
<HBox alignment="CENTER_RIGHT" spacing="6">
|
||||||
<Label styleClass="label-small,label-muted" text="%main.vaultDetail.bytesPerSecondWritten"/>
|
<Label styleClass="label-small,label-muted" text="%main.vaultDetail.bytesPerSecondWritten"/>
|
||||||
<ThrougputLabel styleClass="label-small,label-muted" alignment="CENTER_RIGHT" minWidth="60" idleFormat="%main.vaultDetail.throughput.idle" kibsFormat="%main.vaultDetail.throughput.kbps" mibsFormat="%main.vaultDetail.throughput.mbps" bytesPerSecond="${controller.vault.stats.bytesPerSecondWritten}"/>
|
<ThroughputLabel styleClass="label-small,label-muted" alignment="CENTER_RIGHT" minWidth="60" idleFormat="%main.vaultDetail.throughput.idle" kibsFormat="%main.vaultDetail.throughput.kbps" mibsFormat="%main.vaultDetail.throughput.mbps" bytesPerSecond="${controller.vault.stats.bytesPerSecondWritten}"/>
|
||||||
</HBox>
|
</HBox>
|
||||||
</VBox>
|
</VBox>
|
||||||
</graphic>
|
</graphic>
|
||||||
|
@ -36,12 +36,12 @@
|
|||||||
<fx:include source="/fxml/vault_options_masterkey.fxml"/>
|
<fx:include source="/fxml/vault_options_masterkey.fxml"/>
|
||||||
</content>
|
</content>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab fx:id="autoLockTab" id="AUTOLOCK" text="%vaultOptions.autoLock">
|
<Tab fx:id="healthTab" id="HEALTH" text="%vaultOptions.health">
|
||||||
<graphic>
|
<graphic>
|
||||||
<FontAwesome5IconView glyph="STOPWATCH"/>
|
<FontAwesome5IconView glyph="STETHOSCOPE"/>
|
||||||
</graphic>
|
</graphic>
|
||||||
<content>
|
<content>
|
||||||
<fx:include source="/fxml/vault_options_autolock.fxml"/>
|
<fx:include source="/fxml/vault_options_health.fxml"/>
|
||||||
</content>
|
</content>
|
||||||
</Tab>
|
</Tab>
|
||||||
</tabs>
|
</tabs>
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<?import org.cryptomator.ui.controls.FormattedLabel?>
|
|
||||||
<?import org.cryptomator.ui.controls.NumericTextField?>
|
|
||||||
<?import javafx.geometry.Insets?>
|
|
||||||
<?import javafx.scene.control.CheckBox?>
|
|
||||||
<?import javafx.scene.layout.VBox?>
|
|
||||||
<?import javafx.scene.text.Text?>
|
|
||||||
<?import javafx.scene.text.TextFlow?>
|
|
||||||
<VBox xmlns:fx="http://javafx.com/fxml"
|
|
||||||
xmlns="http://javafx.com/javafx"
|
|
||||||
fx:controller="org.cryptomator.ui.vaultoptions.AutoLockVaultOptionsController"
|
|
||||||
spacing="6">
|
|
||||||
<padding>
|
|
||||||
<Insets topRightBottomLeft="12"/>
|
|
||||||
</padding>
|
|
||||||
<children>
|
|
||||||
<TextFlow styleClass="text-flow" prefWidth="-Infinity">
|
|
||||||
<CheckBox text="%vaultOptions.autoLock.lockAfterTimePart1" fx:id="lockAfterTimeCheckbox"/>
|
|
||||||
<Text text=" "/>
|
|
||||||
<NumericTextField fx:id="lockTimeInMinutesTextField" prefWidth="50"/>
|
|
||||||
<Text text=" "/>
|
|
||||||
<FormattedLabel format="%vaultOptions.autoLock.lockAfterTimePart2"/>
|
|
||||||
</TextFlow>
|
|
||||||
</children>
|
|
||||||
</VBox>
|
|
@ -8,6 +8,10 @@
|
|||||||
<?import javafx.scene.layout.HBox?>
|
<?import javafx.scene.layout.HBox?>
|
||||||
<?import javafx.scene.layout.VBox?>
|
<?import javafx.scene.layout.VBox?>
|
||||||
<?import javafx.scene.control.Button?>
|
<?import javafx.scene.control.Button?>
|
||||||
|
<?import javafx.scene.text.TextFlow?>
|
||||||
|
<?import javafx.scene.text.Text?>
|
||||||
|
<?import org.cryptomator.ui.controls.NumericTextField?>
|
||||||
|
<?import org.cryptomator.ui.controls.FormattedLabel?>
|
||||||
<VBox xmlns:fx="http://javafx.com/fxml"
|
<VBox xmlns:fx="http://javafx.com/fxml"
|
||||||
xmlns="http://javafx.com/javafx"
|
xmlns="http://javafx.com/javafx"
|
||||||
fx:controller="org.cryptomator.ui.vaultoptions.GeneralVaultOptionsController"
|
fx:controller="org.cryptomator.ui.vaultoptions.GeneralVaultOptionsController"
|
||||||
@ -21,12 +25,19 @@
|
|||||||
<TextField fx:id="vaultName"/>
|
<TextField fx:id="vaultName"/>
|
||||||
</HBox>
|
</HBox>
|
||||||
|
|
||||||
|
<TextFlow styleClass="text-flow" prefWidth="-Infinity">
|
||||||
|
<CheckBox text="%vaultOptions.general.autoLock.lockAfterTimePart1" fx:id="lockAfterTimeCheckbox"/>
|
||||||
|
<Text text=" "/>
|
||||||
|
<NumericTextField fx:id="lockTimeInMinutesTextField" prefWidth="50"/>
|
||||||
|
<Text text=" "/>
|
||||||
|
<FormattedLabel format="%vaultOptions.general.autoLock.lockAfterTimePart2"/>
|
||||||
|
</TextFlow>
|
||||||
|
|
||||||
<CheckBox text="%vaultOptions.general.unlockAfterStartup" fx:id="unlockOnStartupCheckbox"/>
|
<CheckBox text="%vaultOptions.general.unlockAfterStartup" fx:id="unlockOnStartupCheckbox"/>
|
||||||
|
|
||||||
<HBox spacing="6" alignment="CENTER_LEFT">
|
<HBox spacing="6" alignment="CENTER_LEFT">
|
||||||
<Label text="%vaultOptions.general.actionAfterUnlock"/>
|
<Label text="%vaultOptions.general.actionAfterUnlock"/>
|
||||||
<ChoiceBox fx:id="actionAfterUnlockChoiceBox"/>
|
<ChoiceBox fx:id="actionAfterUnlockChoiceBox"/>
|
||||||
</HBox>
|
</HBox>
|
||||||
<Button text="%vaultOptions.general.healthBtn" onAction="#showHealthCheck"/>
|
|
||||||
</children>
|
</children>
|
||||||
</VBox>
|
</VBox>
|
||||||
|
49
src/main/resources/fxml/vault_options_health.fxml
Normal file
49
src/main/resources/fxml/vault_options_health.fxml
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?import javafx.geometry.Insets?>
|
||||||
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import javafx.scene.layout.VBox?>
|
||||||
|
<?import javafx.scene.control.Button?>
|
||||||
|
<?import javafx.scene.shape.Box?>
|
||||||
|
<?import javafx.scene.Group?>
|
||||||
|
<?import javafx.scene.layout.GridPane?>
|
||||||
|
<?import javafx.scene.layout.ColumnConstraints?>
|
||||||
|
<?import javafx.collections.ObservableList?>
|
||||||
|
<?import javafx.collections.FXCollections?>
|
||||||
|
<?import javafx.scene.layout.RowConstraints?>
|
||||||
|
<?import javafx.scene.layout.HBox?>
|
||||||
|
<?import javafx.scene.control.CheckBox?>
|
||||||
|
<VBox xmlns:fx="http://javafx.com/fxml"
|
||||||
|
xmlns="http://javafx.com/javafx"
|
||||||
|
fx:controller="org.cryptomator.ui.vaultoptions.HealthVaultOptionsController"
|
||||||
|
spacing="6">
|
||||||
|
<padding>
|
||||||
|
<Insets topRightBottomLeft="12"/>
|
||||||
|
</padding>
|
||||||
|
<children>
|
||||||
|
<Label text="%vaultOptions.health.introduction" wrapText="true"/>
|
||||||
|
<Label text="%vaultOptions.health.remarks" wrapText="true"/>
|
||||||
|
<GridPane >
|
||||||
|
<padding>
|
||||||
|
<Insets left="6"/>
|
||||||
|
</padding>
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints minWidth="20" halignment="LEFT"/>
|
||||||
|
<ColumnConstraints fillWidth="true"/>
|
||||||
|
</columnConstraints>
|
||||||
|
<rowConstraints>
|
||||||
|
<RowConstraints valignment="TOP"/>
|
||||||
|
<RowConstraints valignment="TOP"/>
|
||||||
|
<RowConstraints valignment="TOP"/>
|
||||||
|
</rowConstraints>
|
||||||
|
<Label text="1." GridPane.rowIndex="0" GridPane.columnIndex="0" />
|
||||||
|
<Label text="%vaultOptions.health.remarkSync" wrapText="true" GridPane.rowIndex="0" GridPane.columnIndex="1" />
|
||||||
|
<Label text="2." GridPane.rowIndex="1" GridPane.columnIndex="0" />
|
||||||
|
<Label text="%vaultOptions.health.remarkFix" wrapText="true" GridPane.rowIndex="1" GridPane.columnIndex="1" />
|
||||||
|
<Label text="3." GridPane.rowIndex="2" GridPane.columnIndex="0" />
|
||||||
|
<Label text="%vaultOptions.health.remarkBackup" wrapText="true" GridPane.rowIndex="2" GridPane.columnIndex="1" />
|
||||||
|
</GridPane>
|
||||||
|
<CheckBox text="%vaultOptions.health.affirmation" fx:id="affirmationBox"/>
|
||||||
|
<Button text="%vaultOptions.health.startBtn" disable="${!affirmationBox.selected}" onAction="#startHealthCheck"/>
|
||||||
|
</children>
|
||||||
|
</VBox>
|
@ -29,7 +29,7 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</VBox>
|
</VBox>
|
||||||
<Region VBox.vgrow="ALWAYS"/>
|
<Region VBox.vgrow="ALWAYS"/>
|
||||||
<Label maxWidth="-Infinity" text="%vaultOptions.masterkey.recoveryKeyExpanation" wrapText="true"/>
|
<Label maxWidth="-Infinity" text="%vaultOptions.masterkey.recoveryKeyExplanation" wrapText="true"/>
|
||||||
<VBox spacing="6" alignment="CENTER">
|
<VBox spacing="6" alignment="CENTER">
|
||||||
<Button text="%vaultOptions.masterkey.showRecoveryKeyBtn" onAction="#showRecoveryKey" contentDisplay="LEFT" maxWidth="Infinity">
|
<Button text="%vaultOptions.masterkey.showRecoveryKeyBtn" onAction="#showRecoveryKey" contentDisplay="LEFT" maxWidth="Infinity">
|
||||||
<graphic>
|
<graphic>
|
||||||
|
@ -14,7 +14,7 @@ generic.button.done=Done
|
|||||||
generic.button.next=Next
|
generic.button.next=Next
|
||||||
generic.button.print=Print
|
generic.button.print=Print
|
||||||
## Error
|
## Error
|
||||||
generic.error.title=An unexpected error occured
|
generic.error.title=An unexpected error occurred
|
||||||
generic.error.instruction=This should not have happened. Please report the error text below and include a description of what steps did lead to this error.
|
generic.error.instruction=This should not have happened. Please report the error text below and include a description of what steps did lead to this error.
|
||||||
|
|
||||||
# Defaults
|
# Defaults
|
||||||
@ -131,7 +131,7 @@ migration.start.confirm=Yes, my vault is fully synced
|
|||||||
migration.run.enterPassword=Enter the password for "%s"
|
migration.run.enterPassword=Enter the password for "%s"
|
||||||
migration.run.startMigrationBtn=Migrate Vault
|
migration.run.startMigrationBtn=Migrate Vault
|
||||||
migration.run.progressHint=This might take some time…
|
migration.run.progressHint=This might take some time…
|
||||||
## Sucess
|
## Success
|
||||||
migration.success.nextStepsInstructions=Migrated "%s" successfully.\nYou can now unlock your vault.
|
migration.success.nextStepsInstructions=Migrated "%s" successfully.\nYou can now unlock your vault.
|
||||||
migration.success.unlockNow=Unlock Now
|
migration.success.unlockNow=Unlock Now
|
||||||
## Missing file system capabilities
|
## Missing file system capabilities
|
||||||
@ -148,24 +148,26 @@ migration.impossible.moreInfo=The vault can still be opened with an older versio
|
|||||||
|
|
||||||
# Health Check
|
# Health Check
|
||||||
health.title=Vault Health Check
|
health.title=Vault Health Check
|
||||||
health.start.introduction=The Vault Health Check is a collection of checks to detect and possilby fix problems in the internal structure of your vault. Please note, that not all problems are fixable. You need the vault password to perform the checks.
|
|
||||||
health.start.configValid=Reading and parsing vault configuration file was successful. Proceed to select checks.
|
health.start.configValid=Reading and parsing vault configuration file was successful. Proceed to select checks.
|
||||||
health.start.configInvalid=Error while reading and parsing the vault configuration file.
|
health.start.configInvalid=Error while reading and parsing the vault configuration file.
|
||||||
health.checkList.header=Available Health Checks
|
health.checkList.header=Available Health Checks
|
||||||
health.checkList.selectAllBox=Select All
|
health.checkList.selectAllBox=Select All
|
||||||
health.check.runBatchBtn=Run selected Checks
|
health.check.runBatchBtn=Run Selected Checks
|
||||||
## Detail view
|
## Detail view
|
||||||
health.check.detail.noSelectedCheck=For results select a finished health check in the left list.
|
health.check.detail.noSelectedCheck=For results select a finished health check in the left list.
|
||||||
health.check.detail.header=Results of %s
|
health.check.detail.header=Results of %s
|
||||||
health.check.detail.taskNotStarted=The check was not selected to run.
|
health.check.detail.taskNotStarted=The check was not selected to run.
|
||||||
health.check.detail.taskScheduled=The check is scheduled.
|
health.check.detail.taskScheduled=The check is scheduled.
|
||||||
health.check.detail.taskRunning=The check is currently running…
|
health.check.detail.taskRunning=The check is currently running…
|
||||||
health.check.detail.taskSucceeded=The check finished successfully after %d milliseconds.
|
health.check.detail.taskSucceeded=The check finished successfully after %s.
|
||||||
health.check.detail.taskFailed=The check exited due to an error.
|
health.check.detail.taskFailed=The check exited due to an error.
|
||||||
health.check.detail.taskCancelled=The check was cancelled.
|
health.check.detail.taskCancelled=The check was cancelled.
|
||||||
health.check.detail.problemCount=Found %d problems and %d unfixable errors.
|
health.check.detail.problemCount=Found %d problems and %d unfixable errors.
|
||||||
health.check.exportBtn=Export Report
|
health.check.exportBtn=Export Report
|
||||||
health.check.fixBtn=Fix
|
health.check.fixBtn=Fix
|
||||||
|
health.check.detail.hmsFormat= %d hours, %2d minutes and %2d seconds
|
||||||
|
health.check.detail.msFormat= %d minutes and %2d seconds
|
||||||
|
health.check.detail.sFormat= %d seconds
|
||||||
## Checks
|
## Checks
|
||||||
health.org.cryptomator.cryptofs.health.dirid.DirIdCheck=Directory Check
|
health.org.cryptomator.cryptofs.health.dirid.DirIdCheck=Directory Check
|
||||||
|
|
||||||
@ -301,12 +303,13 @@ wrongFileAlert.link=For further assistance, visit
|
|||||||
## General
|
## General
|
||||||
vaultOptions.general=General
|
vaultOptions.general=General
|
||||||
vaultOptions.general.vaultName=Vault Name
|
vaultOptions.general.vaultName=Vault Name
|
||||||
|
vaultOptions.general.autoLock.lockAfterTimePart1=Lock when idle for
|
||||||
|
vaultOptions.general.autoLock.lockAfterTimePart2=minutes
|
||||||
vaultOptions.general.unlockAfterStartup=Unlock vault when starting Cryptomator
|
vaultOptions.general.unlockAfterStartup=Unlock vault when starting Cryptomator
|
||||||
vaultOptions.general.actionAfterUnlock=After successful unlock
|
vaultOptions.general.actionAfterUnlock=After successful unlock
|
||||||
vaultOptions.general.actionAfterUnlock.ignore=Do nothing
|
vaultOptions.general.actionAfterUnlock.ignore=Do nothing
|
||||||
vaultOptions.general.actionAfterUnlock.reveal=Reveal Drive
|
vaultOptions.general.actionAfterUnlock.reveal=Reveal Drive
|
||||||
vaultOptions.general.actionAfterUnlock.ask=Ask
|
vaultOptions.general.actionAfterUnlock.ask=Ask
|
||||||
vaultOptions.general.healthBtn=Start Health Check
|
|
||||||
## Mount
|
## Mount
|
||||||
vaultOptions.mount=Mounting
|
vaultOptions.mount=Mounting
|
||||||
vaultOptions.mount.readonly=Read-Only
|
vaultOptions.mount.readonly=Read-Only
|
||||||
@ -322,13 +325,19 @@ vaultOptions.mount.mountPoint.directoryPickerTitle=Pick an empty directory
|
|||||||
vaultOptions.masterkey=Password
|
vaultOptions.masterkey=Password
|
||||||
vaultOptions.masterkey.changePasswordBtn=Change Password
|
vaultOptions.masterkey.changePasswordBtn=Change Password
|
||||||
vaultOptions.masterkey.forgetSavedPasswordBtn=Forget Saved Password
|
vaultOptions.masterkey.forgetSavedPasswordBtn=Forget Saved Password
|
||||||
vaultOptions.masterkey.recoveryKeyExpanation=A recovery key is your only means to restore access to a vault if you lose your password.
|
vaultOptions.masterkey.recoveryKeyExplanation=A recovery key is your only means to restore access to a vault if you lose your password.
|
||||||
vaultOptions.masterkey.showRecoveryKeyBtn=Display Recovery Key
|
vaultOptions.masterkey.showRecoveryKeyBtn=Display Recovery Key
|
||||||
vaultOptions.masterkey.recoverPasswordBtn=Recover Password
|
vaultOptions.masterkey.recoverPasswordBtn=Recover Password
|
||||||
## Auto Lock
|
## Health
|
||||||
vaultOptions.autoLock=Auto-Lock
|
vaultOptions.health=Health Check
|
||||||
vaultOptions.autoLock.lockAfterTimePart1=Lock when idle for
|
vaultOptions.health.startBtn=Start Health Check
|
||||||
vaultOptions.autoLock.lockAfterTimePart2=minutes
|
vaultOptions.health.introduction=Health Check is a collection of checks to detect and possibly fix problems in the internal structure of your vault.
|
||||||
|
vaultOptions.health.remarks=Please keep in mind:
|
||||||
|
vaultOptions.health.remarkSync=Incomplete synchronisation causes most problems. Ensure that every device is completely synced.
|
||||||
|
vaultOptions.health.remarkFix=Not all problems can be fixed.
|
||||||
|
vaultOptions.health.remarkBackup=If data is corrupted, only a backup can help.
|
||||||
|
vaultOptions.health.affirmation=I have read and understood the above information.
|
||||||
|
|
||||||
|
|
||||||
# Recovery Key
|
# Recovery Key
|
||||||
recoveryKey.title=Recovery Key
|
recoveryKey.title=Recovery Key
|
||||||
|
@ -11,7 +11,7 @@ GNU General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see http://www.gnu.org/licenses/.
|
along with this program. If not, see http://www.gnu.org/licenses/.
|
||||||
|
|
||||||
Cryptomator uses 47 third-party dependencies under the following licenses:
|
Cryptomator uses 45 third-party dependencies under the following licenses:
|
||||||
Apache License v2.0:
|
Apache License v2.0:
|
||||||
- jffi (com.github.jnr:jffi:1.2.23 - http://github.com/jnr/jffi)
|
- 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-a64asm (com.github.jnr:jnr-a64asm:1.0.0 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-a64asm)
|
||||||
@ -19,7 +19,7 @@ Cryptomator uses 47 third-party dependencies under the following licenses:
|
|||||||
- jnr-ffi (com.github.jnr:jnr-ffi:2.1.12 - http://github.com/jnr/jnr-ffi)
|
- 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/)
|
- 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)
|
- Gson (com.google.code.gson:gson:2.8.6 - https://github.com/google/gson/gson)
|
||||||
- Dagger (com.google.dagger:dagger:2.35.1 - https://github.com/google/dagger)
|
- Dagger (com.google.dagger:dagger:2.37 - https://github.com/google/dagger)
|
||||||
- error-prone annotations (com.google.errorprone:error_prone_annotations:2.5.1 - http://nexus.sonatype.org/oss-repository-hosting.html/error_prone_parent/error_prone_annotations)
|
- error-prone annotations (com.google.errorprone:error_prone_annotations:2.5.1 - 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 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:30.1.1-jre - https://github.com/google/guava/guava)
|
- Guava: Google Core Libraries for Java (com.google.guava:guava:30.1.1-jre - https://github.com/google/guava/guava)
|
||||||
@ -29,17 +29,15 @@ Cryptomator uses 47 third-party dependencies under the following licenses:
|
|||||||
- javax.inject (javax.inject:javax.inject:1 - http://code.google.com/p/atinject/)
|
- javax.inject (javax.inject:javax.inject:1 - http://code.google.com/p/atinject/)
|
||||||
- Java Native Access (net.java.dev.jna:jna:5.7.0 - https://github.com/java-native-access/jna)
|
- Java Native Access (net.java.dev.jna:jna:5.7.0 - https://github.com/java-native-access/jna)
|
||||||
- Java Native Access Platform (net.java.dev.jna:jna-platform:5.7.0 - https://github.com/java-native-access/jna)
|
- Java Native Access Platform (net.java.dev.jna:jna-platform:5.7.0 - https://github.com/java-native-access/jna)
|
||||||
- Apache Commons Lang (org.apache.commons:commons-lang3:3.11 - https://commons.apache.org/proper/commons-lang/)
|
- Apache Commons Lang (org.apache.commons:commons-lang3:3.12.0 - https://commons.apache.org/proper/commons-lang/)
|
||||||
- Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.14 - http://hc.apache.org/httpcomponents-core-ga)
|
- Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.14 - http://hc.apache.org/httpcomponents-core-ga)
|
||||||
- Jackrabbit WebDAV Library (org.apache.jackrabbit:jackrabbit-webdav:2.21.5 - http://jackrabbit.apache.org/jackrabbit-webdav/)
|
- Jackrabbit WebDAV Library (org.apache.jackrabbit:jackrabbit-webdav:2.21.5 - http://jackrabbit.apache.org/jackrabbit-webdav/)
|
||||||
- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:10.0.2 - https://eclipse.org/jetty/jetty-http)
|
- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:10.0.3 - https://eclipse.org/jetty/jetty-http)
|
||||||
- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:10.0.2 - https://eclipse.org/jetty/jetty-io)
|
- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:10.0.3 - https://eclipse.org/jetty/jetty-io)
|
||||||
- Jetty :: Security (org.eclipse.jetty:jetty-security:10.0.2 - https://eclipse.org/jetty/jetty-security)
|
- Jetty :: Security (org.eclipse.jetty:jetty-security:10.0.3 - https://eclipse.org/jetty/jetty-security)
|
||||||
- Jetty :: Server Core (org.eclipse.jetty:jetty-server:10.0.2 - https://eclipse.org/jetty/jetty-server)
|
- Jetty :: Server Core (org.eclipse.jetty:jetty-server:10.0.3 - https://eclipse.org/jetty/jetty-server)
|
||||||
- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:10.0.2 - https://eclipse.org/jetty/jetty-servlet)
|
- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:10.0.3 - https://eclipse.org/jetty/jetty-servlet)
|
||||||
- Jetty :: Utilities (org.eclipse.jetty:jetty-util:10.0.2 - https://eclipse.org/jetty/jetty-util)
|
- Jetty :: Utilities (org.eclipse.jetty:jetty-util:10.0.3 - https://eclipse.org/jetty/jetty-util)
|
||||||
- Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:10.0.2 - https://eclipse.org/jetty/jetty-webapp)
|
|
||||||
- Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:10.0.2 - https://eclipse.org/jetty/jetty-xml)
|
|
||||||
- Jetty :: Servlet API and Schemas for JPMS and OSGi (org.eclipse.jetty.toolchain:jetty-servlet-api:4.0.6 - https://eclipse.org/jetty/jetty-servlet-api)
|
- Jetty :: Servlet API and Schemas for JPMS and OSGi (org.eclipse.jetty.toolchain:jetty-servlet-api:4.0.6 - https://eclipse.org/jetty/jetty-servlet-api)
|
||||||
BSD:
|
BSD:
|
||||||
- asm (org.ow2.asm:asm:7.1 - http://asm.ow2.org/)
|
- asm (org.ow2.asm:asm:7.1 - http://asm.ow2.org/)
|
||||||
@ -50,14 +48,12 @@ Cryptomator uses 47 third-party dependencies under the following licenses:
|
|||||||
Eclipse Public License - Version 1.0:
|
Eclipse Public License - Version 1.0:
|
||||||
- Jetty :: Servlet API and Schemas for JPMS and OSGi (org.eclipse.jetty.toolchain:jetty-servlet-api:4.0.6 - https://eclipse.org/jetty/jetty-servlet-api)
|
- Jetty :: Servlet API and Schemas for JPMS and OSGi (org.eclipse.jetty.toolchain:jetty-servlet-api:4.0.6 - https://eclipse.org/jetty/jetty-servlet-api)
|
||||||
Eclipse Public License - Version 2.0:
|
Eclipse Public License - Version 2.0:
|
||||||
- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:10.0.2 - https://eclipse.org/jetty/jetty-http)
|
- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:10.0.3 - https://eclipse.org/jetty/jetty-http)
|
||||||
- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:10.0.2 - https://eclipse.org/jetty/jetty-io)
|
- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:10.0.3 - https://eclipse.org/jetty/jetty-io)
|
||||||
- Jetty :: Security (org.eclipse.jetty:jetty-security:10.0.2 - https://eclipse.org/jetty/jetty-security)
|
- Jetty :: Security (org.eclipse.jetty:jetty-security:10.0.3 - https://eclipse.org/jetty/jetty-security)
|
||||||
- Jetty :: Server Core (org.eclipse.jetty:jetty-server:10.0.2 - https://eclipse.org/jetty/jetty-server)
|
- Jetty :: Server Core (org.eclipse.jetty:jetty-server:10.0.3 - https://eclipse.org/jetty/jetty-server)
|
||||||
- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:10.0.2 - https://eclipse.org/jetty/jetty-servlet)
|
- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:10.0.3 - https://eclipse.org/jetty/jetty-servlet)
|
||||||
- Jetty :: Utilities (org.eclipse.jetty:jetty-util:10.0.2 - https://eclipse.org/jetty/jetty-util)
|
- Jetty :: Utilities (org.eclipse.jetty:jetty-util:10.0.3 - https://eclipse.org/jetty/jetty-util)
|
||||||
- Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:10.0.2 - https://eclipse.org/jetty/jetty-webapp)
|
|
||||||
- Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:10.0.2 - https://eclipse.org/jetty/jetty-xml)
|
|
||||||
Eclipse Public License - v 1.0:
|
Eclipse Public License - v 1.0:
|
||||||
- Logback Classic Module (ch.qos.logback:logback-classic:1.2.3 - http://logback.qos.ch/logback-classic)
|
- Logback Classic Module (ch.qos.logback:logback-classic:1.2.3 - http://logback.qos.ch/logback-classic)
|
||||||
- Logback Core Module (ch.qos.logback:logback-core:1.2.3 - http://logback.qos.ch/logback-core)
|
- Logback Core Module (ch.qos.logback:logback-core:1.2.3 - http://logback.qos.ch/logback-core)
|
||||||
@ -78,14 +74,14 @@ Cryptomator uses 47 third-party dependencies under the following licenses:
|
|||||||
- Java Native Access (net.java.dev.jna:jna:5.7.0 - https://github.com/java-native-access/jna)
|
- Java Native Access (net.java.dev.jna:jna:5.7.0 - https://github.com/java-native-access/jna)
|
||||||
- Java Native Access Platform (net.java.dev.jna:jna-platform:5.7.0 - https://github.com/java-native-access/jna)
|
- Java Native Access Platform (net.java.dev.jna:jna-platform:5.7.0 - https://github.com/java-native-access/jna)
|
||||||
MIT License:
|
MIT License:
|
||||||
- java jwt (com.auth0:java-jwt:3.15.0 - https://github.com/auth0/java-jwt)
|
- java jwt (com.auth0:java-jwt:3.17.0 - https://github.com/auth0/java-jwt)
|
||||||
- jnr-x86asm (com.github.jnr:jnr-x86asm:1.0.2 - http://github.com/jnr/jnr-x86asm)
|
- 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.5 - https://github.com/SerCeMan/jnr-fuse)
|
- jnr-fuse (com.github.serceman:jnr-fuse:0.5.5 - https://github.com/SerCeMan/jnr-fuse)
|
||||||
- zxcvbn4j (com.nulab-inc:zxcvbn:1.3.0 - https://github.com/nulab/zxcvbn4j)
|
- zxcvbn4j (com.nulab-inc:zxcvbn:1.3.0 - https://github.com/nulab/zxcvbn4j)
|
||||||
- Checker Qual (org.checkerframework:checker-qual:3.8.0 - https://checkerframework.org)
|
- Checker Qual (org.checkerframework:checker-qual:3.8.0 - https://checkerframework.org)
|
||||||
- SLF4J API Module (org.slf4j:slf4j-api:1.7.30 - http://www.slf4j.org)
|
- SLF4J API Module (org.slf4j:slf4j-api:1.7.31 - http://www.slf4j.org)
|
||||||
The BSD 2-Clause License:
|
The BSD 2-Clause License:
|
||||||
- EasyBind (com.tobiasdiez:easybind:2.1.0 - https://github.com/tobiasdiez/EasyBind)
|
- EasyBind (com.tobiasdiez:easybind:2.2 - https://github.com/tobiasdiez/EasyBind)
|
||||||
|
|
||||||
Cryptomator uses other third-party assets under the following licenses:
|
Cryptomator uses other third-party assets under the following licenses:
|
||||||
SIL OFL 1.1 License:
|
SIL OFL 1.1 License:
|
||||||
|
@ -9,6 +9,7 @@ import java.util.Optional;
|
|||||||
|
|
||||||
public class LicenseCheckerTest {
|
public class LicenseCheckerTest {
|
||||||
|
|
||||||
|
@SuppressWarnings("SpellCheckingInspection")
|
||||||
private static final String PUBLIC_KEY = """
|
private static final String PUBLIC_KEY = """
|
||||||
MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBgc4HZz+/fBbC7lmEww0AO3NK9wVZ\
|
MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBgc4HZz+/fBbC7lmEww0AO3NK9wVZ\
|
||||||
PDZ0VEnsaUFLEYpTzb90nITtJUcPUbvOsdZIZ1Q8fnbquAYgxXL5UgHMoywAib47\
|
PDZ0VEnsaUFLEYpTzb90nITtJUcPUbvOsdZIZ1Q8fnbquAYgxXL5UgHMoywAib47\
|
||||||
@ -25,6 +26,7 @@ public class LicenseCheckerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCheckValidLicense() {
|
public void testCheckValidLicense() {
|
||||||
|
@SuppressWarnings("SpellCheckingInspection")
|
||||||
String license = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6InhaRGZacHJ5NFA5dlpQWnlHMmZOQlJqLTdMejVvbVZkbTd0SG9DZ1NOZlkifQ.eyJzdWIiOiJjcnlwdG9ib3RAZXhhbXBsZS5jb20iLCJpYXQiOjE1MTYyMzkwMjJ9.AQaBIKQdNCxmRJi2wLOcbagTgi39WhdWwgdpKTYSPicg-aPr_tst_RjmnqMemx3cBe0Blr4nEbj_lAtSKHz_i61fAUyI1xCIAZYbK9Q3ICHIHQl3AiuCpBwFl-k81OB4QDYiKpEc9gLN5dhW_VymJMsgOvyiC0UjC91f2AM7s46byDNj";
|
String license = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6InhaRGZacHJ5NFA5dlpQWnlHMmZOQlJqLTdMejVvbVZkbTd0SG9DZ1NOZlkifQ.eyJzdWIiOiJjcnlwdG9ib3RAZXhhbXBsZS5jb20iLCJpYXQiOjE1MTYyMzkwMjJ9.AQaBIKQdNCxmRJi2wLOcbagTgi39WhdWwgdpKTYSPicg-aPr_tst_RjmnqMemx3cBe0Blr4nEbj_lAtSKHz_i61fAUyI1xCIAZYbK9Q3ICHIHQl3AiuCpBwFl-k81OB4QDYiKpEc9gLN5dhW_VymJMsgOvyiC0UjC91f2AM7s46byDNj";
|
||||||
|
|
||||||
Optional<DecodedJWT> decoded = licenseChecker.check(license);
|
Optional<DecodedJWT> decoded = licenseChecker.check(license);
|
||||||
@ -35,6 +37,7 @@ public class LicenseCheckerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCheckInvalidLicenseHeader() {
|
public void testCheckInvalidLicenseHeader() {
|
||||||
|
@SuppressWarnings("SpellCheckingInspection")
|
||||||
String license = "EyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6InhaRGZacHJ5NFA5dlpQWnlHMmZOQlJqLTdMejVvbVZkbTd0SG9DZ1NOZlkifQ.eyJzdWIiOiJjcnlwdG9ib3RAZXhhbXBsZS5jb20iLCJpYXQiOjE1MTYyMzkwMjJ9.AQaBIKQdNCxmRJi2wLOcbagTgi39WhdWwgdpKTYSPicg-aPr_tst_RjmnqMemx3cBe0Blr4nEbj_lAtSKHz_i61fAUyI1xCIAZYbK9Q3ICHIHQl3AiuCpBwFl-k81OB4QDYiKpEc9gLN5dhW_VymJMsgOvyiC0UjC91f2AM7s46byDNj";
|
String license = "EyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6InhaRGZacHJ5NFA5dlpQWnlHMmZOQlJqLTdMejVvbVZkbTd0SG9DZ1NOZlkifQ.eyJzdWIiOiJjcnlwdG9ib3RAZXhhbXBsZS5jb20iLCJpYXQiOjE1MTYyMzkwMjJ9.AQaBIKQdNCxmRJi2wLOcbagTgi39WhdWwgdpKTYSPicg-aPr_tst_RjmnqMemx3cBe0Blr4nEbj_lAtSKHz_i61fAUyI1xCIAZYbK9Q3ICHIHQl3AiuCpBwFl-k81OB4QDYiKpEc9gLN5dhW_VymJMsgOvyiC0UjC91f2AM7s46byDNj";
|
||||||
|
|
||||||
Optional<DecodedJWT> decoded = licenseChecker.check(license);
|
Optional<DecodedJWT> decoded = licenseChecker.check(license);
|
||||||
@ -44,6 +47,7 @@ public class LicenseCheckerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCheckInvalidLicensePayload() {
|
public void testCheckInvalidLicensePayload() {
|
||||||
|
@SuppressWarnings("SpellCheckingInspection")
|
||||||
String license = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6InhaRGZacHJ5NFA5dlpQWnlHMmZOQlJqLTdMejVvbVZkbTd0SG9DZ1NOZlkifQ.EyJzdWIiOiJjcnlwdG9ib3RAZXhhbXBsZS5jb20iLCJpYXQiOjE1MTYyMzkwMjJ9.AQaBIKQdNCxmRJi2wLOcbagTgi39WhdWwgdpKTYSPicg-aPr_tst_RjmnqMemx3cBe0Blr4nEbj_lAtSKHz_i61fAUyI1xCIAZYbK9Q3ICHIHQl3AiuCpBwFl-k81OB4QDYiKpEc9gLN5dhW_VymJMsgOvyiC0UjC91f2AM7s46byDNj";
|
String license = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6InhaRGZacHJ5NFA5dlpQWnlHMmZOQlJqLTdMejVvbVZkbTd0SG9DZ1NOZlkifQ.EyJzdWIiOiJjcnlwdG9ib3RAZXhhbXBsZS5jb20iLCJpYXQiOjE1MTYyMzkwMjJ9.AQaBIKQdNCxmRJi2wLOcbagTgi39WhdWwgdpKTYSPicg-aPr_tst_RjmnqMemx3cBe0Blr4nEbj_lAtSKHz_i61fAUyI1xCIAZYbK9Q3ICHIHQl3AiuCpBwFl-k81OB4QDYiKpEc9gLN5dhW_VymJMsgOvyiC0UjC91f2AM7s46byDNj";
|
||||||
|
|
||||||
Optional<DecodedJWT> decoded = licenseChecker.check(license);
|
Optional<DecodedJWT> decoded = licenseChecker.check(license);
|
||||||
@ -53,6 +57,7 @@ public class LicenseCheckerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCheckInvalidLicenseSignature() {
|
public void testCheckInvalidLicenseSignature() {
|
||||||
|
@SuppressWarnings("SpellCheckingInspection")
|
||||||
String license = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6InhaRGZacHJ5NFA5dlpQWnlHMmZOQlJqLTdMejVvbVZkbTd0SG9DZ1NOZlkifQ.eyJzdWIiOiJjcnlwdG9ib3RAZXhhbXBsZS5jb20iLCJpYXQiOjE1MTYyMzkwMjJ9.aQaBIKQdNCxmRJi2wLOcbagTgi39WhdWwgdpKTYSPicg-aPr_tst_RjmnqMemx3cBe0Blr4nEbj_lAtSKHz_i61fAUyI1xCIAZYbK9Q3ICHIHQl3AiuCpBwFl-k81OB4QDYiKpEc9gLN5dhW_VymJMsgOvyiC0UjC91f2AM7s46byDNj";
|
String license = "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6InhaRGZacHJ5NFA5dlpQWnlHMmZOQlJqLTdMejVvbVZkbTd0SG9DZ1NOZlkifQ.eyJzdWIiOiJjcnlwdG9ib3RAZXhhbXBsZS5jb20iLCJpYXQiOjE1MTYyMzkwMjJ9.aQaBIKQdNCxmRJi2wLOcbagTgi39WhdWwgdpKTYSPicg-aPr_tst_RjmnqMemx3cBe0Blr4nEbj_lAtSKHz_i61fAUyI1xCIAZYbK9Q3ICHIHQl3AiuCpBwFl-k81OB4QDYiKpEc9gLN5dhW_VymJMsgOvyiC0UjC91f2AM7s46byDNj";
|
||||||
|
|
||||||
Optional<DecodedJWT> decoded = licenseChecker.check(license);
|
Optional<DecodedJWT> decoded = licenseChecker.check(license);
|
||||||
|
@ -44,6 +44,7 @@ public class SettingsJsonAdapterTest {
|
|||||||
Assertions.assertEquals(VolumeImpl.FUSE, settings.preferredVolumeImpl().get());
|
Assertions.assertEquals(VolumeImpl.FUSE, settings.preferredVolumeImpl().get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("SpellCheckingInspection")
|
||||||
@ParameterizedTest(name = "fromJson() should throw IOException for input: {0}")
|
@ParameterizedTest(name = "fromJson() should throw IOException for input: {0}")
|
||||||
@ValueSource(strings = { //
|
@ValueSource(strings = { //
|
||||||
"", //
|
"", //
|
||||||
|
@ -40,6 +40,7 @@ public class VaultSettingsJsonAdapterTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("SpellCheckingInspection")
|
||||||
@Test
|
@Test
|
||||||
public void testSerialize() throws IOException {
|
public void testSerialize() throws IOException {
|
||||||
VaultSettings vaultSettings = new VaultSettings("test");
|
VaultSettings vaultSettings = new VaultSettings("test");
|
||||||
|
@ -24,7 +24,7 @@ public class IpcFactoryTest {
|
|||||||
private IpcProtocolImpl protocolHandler = Mockito.mock(IpcProtocolImpl.class);
|
private IpcProtocolImpl protocolHandler = Mockito.mock(IpcProtocolImpl.class);
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@DisplayName("Wihout IPC port files")
|
@DisplayName("Without IPC port files")
|
||||||
public void testNoIpcWithoutPortFile() throws IOException {
|
public void testNoIpcWithoutPortFile() throws IOException {
|
||||||
IpcFactory inTest = new IpcFactory(environment, protocolHandler);
|
IpcFactory inTest = new IpcFactory(environment, protocolHandler);
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import java.util.List;
|
|||||||
|
|
||||||
public class ReadMeGeneratorTest {
|
public class ReadMeGeneratorTest {
|
||||||
|
|
||||||
|
@SuppressWarnings("SpellCheckingInspection")
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@CsvSource({ //
|
@CsvSource({ //
|
||||||
"test,test", //
|
"test,test", //
|
||||||
|
@ -49,6 +49,7 @@ public class SecurePasswordFieldTest {
|
|||||||
Assertions.assertEquals("anteater", pwField.getCharacters().toString());
|
Assertions.assertEquals("anteater", pwField.getCharacters().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("SpellCheckingInspection")
|
||||||
@Test
|
@Test
|
||||||
@DisplayName("\"anteater\".insert(3, \"b\")")
|
@DisplayName("\"anteater\".insert(3, \"b\")")
|
||||||
public void insert2() {
|
public void insert2() {
|
||||||
@ -76,6 +77,7 @@ public class SecurePasswordFieldTest {
|
|||||||
Assertions.assertEquals("ant", pwField.getCharacters().toString());
|
Assertions.assertEquals("ant", pwField.getCharacters().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("SpellCheckingInspection")
|
||||||
@Test
|
@Test
|
||||||
@DisplayName("\"anteater\".replace(0, 3, \"hand\")")
|
@DisplayName("\"anteater\".replace(0, 3, \"hand\")")
|
||||||
public void replace1() {
|
public void replace1() {
|
||||||
@ -85,6 +87,7 @@ public class SecurePasswordFieldTest {
|
|||||||
Assertions.assertEquals("handeater", pwField.getCharacters().toString());
|
Assertions.assertEquals("handeater", pwField.getCharacters().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("SpellCheckingInspection")
|
||||||
@Test
|
@Test
|
||||||
@DisplayName("\"anteater\".replace(3, 6, \"keep\")")
|
@DisplayName("\"anteater\".replace(3, 6, \"keep\")")
|
||||||
public void replace2() {
|
public void replace2() {
|
||||||
@ -94,6 +97,7 @@ public class SecurePasswordFieldTest {
|
|||||||
Assertions.assertEquals("antkeeper", pwField.getCharacters().toString());
|
Assertions.assertEquals("antkeeper", pwField.getCharacters().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("SpellCheckingInspection")
|
||||||
@Test
|
@Test
|
||||||
@DisplayName("\"anteater\".replace(0, 3, \"bee\")")
|
@DisplayName("\"anteater\".replace(0, 3, \"bee\")")
|
||||||
public void replace3() {
|
public void replace3() {
|
||||||
@ -105,6 +109,7 @@ public class SecurePasswordFieldTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("SpellCheckingInspection")
|
||||||
@Test
|
@Test
|
||||||
@DisplayName("entering NFC string leads to NFC char[]")
|
@DisplayName("entering NFC string leads to NFC char[]")
|
||||||
public void enterNfcString() {
|
public void enterNfcString() {
|
||||||
@ -125,6 +130,7 @@ public class SecurePasswordFieldTest {
|
|||||||
Assertions.assertEquals('\uDCA9', result.charAt(9));
|
Assertions.assertEquals('\uDCA9', result.charAt(9));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("SpellCheckingInspection")
|
||||||
@Test
|
@Test
|
||||||
@DisplayName("entering NFD string leads to NFC char[]")
|
@DisplayName("entering NFD string leads to NFC char[]")
|
||||||
public void enterNfdString() {
|
public void enterNfdString() {
|
||||||
|
@ -43,6 +43,7 @@ public class AutoCompleterTest {
|
|||||||
Assertions.assertEquals("tame", result.get());
|
Assertions.assertEquals("tame", result.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("SpellCheckingInspection")
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@DisplayName("find 'teach'")
|
@DisplayName("find 'teach'")
|
||||||
@ValueSource(strings = {"te", "tea", "teac", "teach"})
|
@ValueSource(strings = {"te", "tea", "teac", "teach"})
|
||||||
@ -52,6 +53,7 @@ public class AutoCompleterTest {
|
|||||||
Assertions.assertEquals("teach", result.get());
|
Assertions.assertEquals("teach", result.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("SpellCheckingInspection")
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@DisplayName("find 'teacher'")
|
@DisplayName("find 'teacher'")
|
||||||
@ValueSource(strings = {"teache", "teacher"})
|
@ValueSource(strings = {"teache", "teacher"})
|
||||||
|
@ -14,40 +14,15 @@
|
|||||||
|
|
||||||
<!-- Jetty false positives below -->
|
<!-- Jetty false positives below -->
|
||||||
<suppress>
|
<suppress>
|
||||||
<notes><![CDATA[ Affects jetty < 6.1.22 ]]></notes>
|
<notes><![CDATA[
|
||||||
<gav>org.eclipse.jetty.toolchain:jetty-servlet-api:4.0.6</gav>
|
Suppress all for this javax.servlet api package:
|
||||||
<cve>CVE-2009-5045</cve>
|
There are lots of false positives, simply because its version number is way beyond the remaining
|
||||||
</suppress>
|
org.eclipse.jetty jar files. Note, that our actual Jetty version is different.
|
||||||
<suppress>
|
|
||||||
<notes><![CDATA[ Affects jetty < 6.1.22 ]]></notes>
|
|
||||||
<gav>org.eclipse.jetty.toolchain:jetty-servlet-api:4.0.6</gav>
|
|
||||||
<cve>CVE-2009-5046</cve>
|
|
||||||
</suppress>
|
|
||||||
|
|
||||||
<suppress>
|
As long as we don't suppress anything in org.eclipse.jetty:jetty-server or :jetty-servlet,
|
||||||
<notes><![CDATA[ Affects jetty-server 9.x ]]></notes>
|
vulnerabilities will still trigger if we actually use an outdated Jetty version.
|
||||||
|
]]></notes>
|
||||||
<gav>org.eclipse.jetty.toolchain:jetty-servlet-api:4.0.6</gav>
|
<gav>org.eclipse.jetty.toolchain:jetty-servlet-api:4.0.6</gav>
|
||||||
<cve>CVE-2017-9735</cve>
|
<cpe regex="true">.*</cpe>
|
||||||
</suppress>
|
|
||||||
<suppress>
|
|
||||||
<notes><![CDATA[ Affects jetty-server 9.x ]]></notes>
|
|
||||||
<gav>org.eclipse.jetty.toolchain:jetty-servlet-api:4.0.6</gav>
|
|
||||||
<cve>CVE-2017-7656</cve>
|
|
||||||
</suppress>
|
|
||||||
<suppress>
|
|
||||||
<notes><![CDATA[ Affects jetty-server 9.x ]]></notes>
|
|
||||||
<gav>org.eclipse.jetty.toolchain:jetty-servlet-api:4.0.6</gav>
|
|
||||||
<cve>CVE-2017-7657</cve>
|
|
||||||
</suppress>
|
|
||||||
<suppress>
|
|
||||||
<notes><![CDATA[ Affects jetty-server 9.x ]]></notes>
|
|
||||||
<gav>org.eclipse.jetty.toolchain:jetty-servlet-api:4.0.6</gav>
|
|
||||||
<cve>CVE-2017-7658</cve>
|
|
||||||
</suppress>
|
|
||||||
|
|
||||||
<suppress>
|
|
||||||
<notes><![CDATA[ Fixed since jetty-server 10.0.0.beta2 ]]></notes>
|
|
||||||
<gav>org.eclipse.jetty.toolchain:jetty-servlet-api:4.0.6</gav>
|
|
||||||
<cve>CVE-2020-27216</cve>
|
|
||||||
</suppress>
|
</suppress>
|
||||||
</suppressions>
|
</suppressions>
|
Loading…
Reference in New Issue
Block a user