mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-19 03:01:27 +00:00
Merge branch 'develop' into feature/improve-health-check
# Conflicts: # src/main/java/org/cryptomator/ui/health/HealthCheckTask.java # src/main/java/org/cryptomator/ui/health/ReportWriter.java # src/main/resources/fxml/health_check_list.fxml # src/main/resources/fxml/vault_options.fxml
This commit is contained in:
56
.github/ISSUE_TEMPLATE/bug.md
vendored
56
.github/ISSUE_TEMPLATE/bug.md
vendored
@@ -1,56 +0,0 @@
|
||||
---
|
||||
name: "Bug Report"
|
||||
about: "Create a report to help us improve"
|
||||
labels: type:bug
|
||||
---
|
||||
|
||||
<!--
|
||||
Please make sure to:
|
||||
- Comply with our code of conduct: https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md
|
||||
- Search for existing similar issues first: https://github.com/cryptomator/cryptomator/issues?q=
|
||||
|
||||
⚠️ IMPORTANT: If you don't stick to this template, the issue will get closed.
|
||||
-->
|
||||
|
||||
### Description
|
||||
|
||||
[Summarize your problem.]
|
||||
|
||||
### System Setup
|
||||
|
||||
* Operating system and version: [Windows/macOS/Linux + Version ( + Desktop Environment, if Linux)]
|
||||
* Cryptomator version: [Shown in the settings]
|
||||
* Volume type: [Dokany/FUSE/WebDAV, shown in the settings]
|
||||
|
||||
### Steps to Reproduce
|
||||
|
||||
1. [First step]
|
||||
2. [Second step]
|
||||
3. [and so on…]
|
||||
|
||||
#### Expected Behavior
|
||||
|
||||
[What you expect to happen.]
|
||||
|
||||
#### Actual Behavior
|
||||
|
||||
[What actually happens.]
|
||||
|
||||
#### Reproducibility
|
||||
|
||||
[Always/Intermittent/Only once]
|
||||
|
||||
### Additional Information
|
||||
|
||||
[Any additional information, log files, screenshots, configuration, or data that might be necessary to reproduce the issue.]
|
||||
|
||||
<!--
|
||||
If you want to add the log file or screenshots, please add them as attachments. If your log file seems empty and doesn't show any errors, you may enable the debug mode first. Here is how to do that: https://community.cryptomator.org/t/how-do-i-enable-debug-mode/36
|
||||
|
||||
Then reproduce the problem to ensure all important information is contained in there. You may use test data or redact sensitive information from the log file.
|
||||
|
||||
Log file location:
|
||||
- Windows: %appdata%/Cryptomator
|
||||
- macOS: ~/Library/Logs/Cryptomator
|
||||
- Linux: ~/.local/share/Cryptomator/logs
|
||||
-->
|
||||
93
.github/ISSUE_TEMPLATE/bug.yml
vendored
Normal file
93
.github/ISSUE_TEMPLATE/bug.yml
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
name: Bug Report
|
||||
description: Create a report to help us improve
|
||||
labels: ["type:bug"]
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: terms
|
||||
attributes:
|
||||
label: Please agree to the following
|
||||
options:
|
||||
- label: I have searched [existing issues](https://github.com/cryptomator/cryptomator/issues?q=) for duplicates
|
||||
required: true
|
||||
- label: I agree to follow this project's [Code of Conduct](https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md)
|
||||
required: true
|
||||
- type: input
|
||||
id: summary
|
||||
attributes:
|
||||
label: Summary
|
||||
placeholder: Please summarize your problem.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: software-versions
|
||||
attributes:
|
||||
label: What software is involved?
|
||||
description: |
|
||||
Examples:
|
||||
- Operating System: Windows 10
|
||||
- Cryptomator: 1.5.16
|
||||
- LibreOffice: 7.1.4
|
||||
value: |
|
||||
- Operating System:
|
||||
- Cryptomator:
|
||||
- …
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: volume-type
|
||||
attributes:
|
||||
label: Volume Type
|
||||
description: What is selected under Settings → Virtual Drive?
|
||||
multiple: true
|
||||
options:
|
||||
- FUSE
|
||||
- Dokany
|
||||
- WebDAV
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: reproduction-steps
|
||||
attributes:
|
||||
label: Steps to Reproduce
|
||||
value: |
|
||||
1. [First Step]
|
||||
2. [Second Step]
|
||||
3. …
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected-behaviour
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
placeholder: What you expect to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: actual-behaviour
|
||||
attributes:
|
||||
label: Actual Behavior
|
||||
placeholder: What actually happens.
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: reproducibility
|
||||
attributes:
|
||||
label: Reproducibility
|
||||
description: How often does the described behaviour occur?
|
||||
options:
|
||||
- Always
|
||||
- Intermittent
|
||||
- Only once
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant Log Output
|
||||
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
||||
- type: textarea
|
||||
id: further-info
|
||||
attributes:
|
||||
label: Anything else?
|
||||
description: Links? References? Screenshots? Configurations? Any data that might be necessary to reproduce the issue?
|
||||
27
.github/ISSUE_TEMPLATE/feature.md
vendored
27
.github/ISSUE_TEMPLATE/feature.md
vendored
@@ -1,27 +0,0 @@
|
||||
---
|
||||
name: "Feature Request"
|
||||
about: "Suggest an idea for this project"
|
||||
labels: type:feature-request
|
||||
---
|
||||
|
||||
<!--
|
||||
Please make sure to:
|
||||
- Comply with our code of conduct: https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md
|
||||
- Search for existing similar issues first: https://github.com/cryptomator/cryptomator/issues?q=
|
||||
-->
|
||||
|
||||
### Summary
|
||||
|
||||
[One paragraph explanation of the feature.]
|
||||
|
||||
### Motivation
|
||||
|
||||
[Why are we doing this? What use cases does it support? What is the expected outcome?]
|
||||
|
||||
### Considered Alternatives
|
||||
|
||||
[A clear and concise description of the alternative solutions you've considered.]
|
||||
|
||||
### Additional Context
|
||||
|
||||
[Add any other context or screenshots about the feature request here.]
|
||||
37
.github/ISSUE_TEMPLATE/feature.yml
vendored
Normal file
37
.github/ISSUE_TEMPLATE/feature.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
name: Feature Request
|
||||
description: Suggest an idea for this project
|
||||
labels: ["type:feature-request"]
|
||||
body:
|
||||
- type: checkboxes
|
||||
id: terms
|
||||
attributes:
|
||||
label: Please agree to the following
|
||||
options:
|
||||
- label: I have searched [existing issues](https://github.com/cryptomator/cryptomator/issues?q=) for duplicates
|
||||
required: true
|
||||
- label: I agree to follow this project's [Code of Conduct](https://github.com/cryptomator/cryptomator/blob/develop/.github/CODE_OF_CONDUCT.md)
|
||||
required: true
|
||||
- type: input
|
||||
id: summary
|
||||
attributes:
|
||||
label: Summary
|
||||
placeholder: Please summarize your feature request.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: motivation
|
||||
attributes:
|
||||
label: Motivation
|
||||
description: Who requires this feature? What problem does the user face? How would this feature solve the problem?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: Considered Alternatives
|
||||
description: What current alternatives or workarounds have you considered? Is there a different way to solve the same problem?
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Anything else?
|
||||
description: Any context, suggestions, screenshots, or concepts you want to share?
|
||||
37
.github/workflows/triageBugs.yml
vendored
37
.github/workflows/triageBugs.yml
vendored
@@ -1,37 +0,0 @@
|
||||
name: Bug Report Triage
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
closeTemplateViolation:
|
||||
name: Validate bug report against issue template
|
||||
runs-on: ubuntu-latest
|
||||
if: contains(github.event.issue.labels.*.name, 'type:bug')
|
||||
steps:
|
||||
- name: Check "Description"
|
||||
if: |
|
||||
!contains(github.event.issue.body, env.MUST_CONTAIN)
|
||||
|| contains(toJson(github.event.issue.body), env.MUST_NOT_CONTAIN)
|
||||
run: exit 1
|
||||
env:
|
||||
MUST_CONTAIN: '### Description'
|
||||
MUST_NOT_CONTAIN: '### Description\r\n\r\n[Summarize your problem.]\r\n\r\n### System Setup'
|
||||
- name: Check "Steps to Reproduce"
|
||||
if: |
|
||||
!contains(github.event.issue.body, env.MUST_CONTAIN)
|
||||
|| contains(toJson(github.event.issue.body), env.MUST_NOT_CONTAIN)
|
||||
run: exit 1
|
||||
env:
|
||||
MUST_CONTAIN: '### Steps to Reproduce'
|
||||
MUST_NOT_CONTAIN: '### Steps to Reproduce\r\n\r\n1. [First step]\r\n2. [Second step]\r\n3. [and so on…]\r\n\r\n#### Expected Behavior'
|
||||
- name: Close issue if one of the checks failed
|
||||
if: ${{ failure() }}
|
||||
uses: peter-evans/close-issue@v1
|
||||
with:
|
||||
comment: |
|
||||
This bug report did ignore our issue template. 😞
|
||||
Auto-closing this issue, since it is most likely not useful.
|
||||
|
||||
_This decision was made by a bot. If you think the bot is wrong, let us know and we'll reopen this issue._
|
||||
2
.idea/runConfigurations/Cryptomator_Linux.xml
generated
2
.idea/runConfigurations/Cryptomator_Linux.xml
generated
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="Cryptomator Linux" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="cryptomator" />
|
||||
<option name="VM_PARAMETERS" value="-Djdk.gtk.version=2 -Duser.language=en -Dcryptomator.settingsPath="~/.config/Cryptomator/settings.json" -Dcryptomator.ipcPortPath="~/.config/Cryptomator/ipcPort.bin" -Dcryptomator.logDir="~/.local/share/Cryptomator/logs" -Dcryptomator.mountPointsDir="~/.local/share/Cryptomator/mnt" -Dcryptomator.showTrayIcon=true -Xss20m -Xmx512m" />
|
||||
<option name="VM_PARAMETERS" value="-Djdk.gtk.version=2 -Duser.language=en -Dcryptomator.settingsPath="~/.config/Cryptomator/settings.json" -Dcryptomator.ipcSocketPath="~/.config/Cryptomator/ipc.socket" -Dcryptomator.logDir="~/.local/share/Cryptomator/logs" -Dcryptomator.mountPointsDir="~/.local/share/Cryptomator/mnt" -Dcryptomator.showTrayIcon=true -Xss20m -Xmx512m" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="Cryptomator Linux Dev" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="cryptomator" />
|
||||
<option name="VM_PARAMETERS" value="-Djdk.gtk.version=2 -Duser.language=en -Dcryptomator.settingsPath="~/.config/Cryptomator-Dev/settings.json" -Dcryptomator.ipcPortPath="~/.config/Cryptomator-Dev/ipcPort.bin" -Dcryptomator.logDir="~/.local/share/Cryptomator-Dev/logs" -Dcryptomator.mountPointsDir="~/.local/share/Cryptomator-Dev/mnt" -Dcryptomator.showTrayIcon=true -Dfuse.experimental="true" -Xss20m -Xmx512m" />
|
||||
<option name="VM_PARAMETERS" value="-Djdk.gtk.version=2 -Duser.language=en -Dcryptomator.settingsPath="~/.config/Cryptomator-Dev/settings.json" -Dcryptomator.ipcSocketPath="~/.config/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="~/.local/share/Cryptomator-Dev/logs" -Dcryptomator.mountPointsDir="~/.local/share/Cryptomator-Dev/mnt" -Dcryptomator.showTrayIcon=true -Dfuse.experimental="true" -Xss20m -Xmx512m" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
2
.idea/runConfigurations/Cryptomator_Windows.xml
generated
2
.idea/runConfigurations/Cryptomator_Windows.xml
generated
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="Cryptomator Windows" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="cryptomator" />
|
||||
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath="~/AppData/Roaming/Cryptomator/settings.json" -Dcryptomator.ipcPortPath="~/AppData/Roaming/Cryptomator/ipcPort.bin" -Dcryptomator.logDir="~/AppData/Roaming/Cryptomator" -Dcryptomator.keychainPath="~/AppData/Roaming/Cryptomator/keychain.json" -Dcryptomator.mountPointsDir="~/Cryptomator" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m" />
|
||||
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath="~/AppData/Roaming/Cryptomator/settings.json" -Dcryptomator.ipcSocketPath="~/AppData/Roaming/Cryptomator/ipc.socket" -Dcryptomator.logDir="~/AppData/Roaming/Cryptomator" -Dcryptomator.keychainPath="~/AppData/Roaming/Cryptomator/keychain.json" -Dcryptomator.mountPointsDir="~/Cryptomator" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="Cryptomator Windows Dev" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="cryptomator" />
|
||||
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath="~/AppData/Roaming/Cryptomator-Dev/settings.json" -Dcryptomator.ipcPortPath="~/AppData/Roaming/Cryptomator-Dev/ipcPort.bin" -Dcryptomator.logDir="~/AppData/Roaming/Cryptomator-Dev" -Dcryptomator.keychainPath="~/AppData/Roaming/Cryptomator-Dev/keychain.json" -Dcryptomator.mountPointsDir="~/Cryptomator-Dev" -Dfuse.experimental="true" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m" />
|
||||
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath="~/AppData/Roaming/Cryptomator-Dev/settings.json" -Dcryptomator.ipcSocketPath="~/AppData/Roaming/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="~/AppData/Roaming/Cryptomator-Dev" -Dcryptomator.keychainPath="~/AppData/Roaming/Cryptomator-Dev/keychain.json" -Dcryptomator.mountPointsDir="~/Cryptomator-Dev" -Dfuse.experimental="true" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
2
.idea/runConfigurations/Cryptomator_macOS.xml
generated
2
.idea/runConfigurations/Cryptomator_macOS.xml
generated
@@ -5,7 +5,7 @@
|
||||
</envs>
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="cryptomator" />
|
||||
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath="~/Library/Application Support/Cryptomator/settings.json" -Dcryptomator.ipcPortPath="~/Library/Application Support/Cryptomator/ipcPort.bin" -Dcryptomator.logDir="~/Library/Logs/Cryptomator" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m -ea" />
|
||||
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath="~/Library/Application Support/Cryptomator/settings.json" -Dcryptomator.ipcSocketPath="~/Library/Application Support/Cryptomator/ipc.socket" -Dcryptomator.logDir="~/Library/Logs/Cryptomator" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m -ea" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
</envs>
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="cryptomator" />
|
||||
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath="~/Library/Application Support/Cryptomator-Dev/settings.json" -Dcryptomator.ipcPortPath="~/Library/Application Support/Cryptomator-Dev/ipcPort.bin" -Dcryptomator.logDir="~/Library/Logs/Cryptomator-Dev" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m -ea" />
|
||||
<option name="VM_PARAMETERS" value="-Duser.language=en -Dcryptomator.settingsPath="~/Library/Application Support/Cryptomator-Dev/settings.json" -Dcryptomator.ipcSocketPath="~/Library/Application Support/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="~/Library/Logs/Cryptomator-Dev" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m -ea" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
10
README.md
10
README.md
@@ -28,14 +28,6 @@ Cryptomator is provided free of charge as an open-source project despite the hig
|
||||
|
||||
### Silver Sponsors
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a href="https://thebestvpn.com/"><img src="https://cryptomator.org/img/sponsors/thebestvpn@2x.png" alt="TheBestVPN" height="64"></a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
- [Jameson Lopp](https://www.lopp.net/)
|
||||
|
||||
---
|
||||
@@ -56,7 +48,7 @@ Download native binaries of Cryptomator on [cryptomator.org](https://cryptomator
|
||||
- File names get encrypted
|
||||
- Folder structure gets obfuscated
|
||||
- Use as many vaults in your Dropbox as you want, each having individual passwords
|
||||
- Two thousand commits for the security of your data!! :tada:
|
||||
- Three thousand commits for the security of your data!! :tada:
|
||||
|
||||
### Privacy
|
||||
|
||||
|
||||
@@ -34,7 +34,14 @@
|
||||
<includes>
|
||||
<include>cryptomator-*.jar</include>
|
||||
</includes>
|
||||
<outputDirectory>libs</outputDirectory>
|
||||
<outputDirectory>mods</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>target/mods</directory>
|
||||
<includes>
|
||||
<include>*.jar</include>
|
||||
</includes>
|
||||
<outputDirectory>mods</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>target/libs</directory>
|
||||
|
||||
@@ -34,7 +34,14 @@
|
||||
<includes>
|
||||
<include>cryptomator-*.jar</include>
|
||||
</includes>
|
||||
<outputDirectory>libs</outputDirectory>
|
||||
<outputDirectory>mods</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>target/mods</directory>
|
||||
<includes>
|
||||
<include>*.jar</include>
|
||||
</includes>
|
||||
<outputDirectory>mods</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>target/libs</directory>
|
||||
|
||||
@@ -34,7 +34,14 @@
|
||||
<includes>
|
||||
<include>cryptomator-*.jar</include>
|
||||
</includes>
|
||||
<outputDirectory>libs</outputDirectory>
|
||||
<outputDirectory>mods</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>target/mods</directory>
|
||||
<includes>
|
||||
<include>*.jar</include>
|
||||
</includes>
|
||||
<outputDirectory>mods</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>target/libs</directory>
|
||||
|
||||
72
pom.xml
72
pom.xml
@@ -23,24 +23,28 @@
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.jdk.version>16</project.jdk.version>
|
||||
|
||||
<!-- Group IDs of jars that need to stay on the class path for now -->
|
||||
<nonModularGroupIds>com.github.serceman,com.github.jnr,org.ow2.asm,net.java.dev.jna,org.apache.jackrabbit,org.apache.httpcomponents</nonModularGroupIds>
|
||||
|
||||
<!-- cryptomator dependencies -->
|
||||
<cryptomator.cryptofs.version>2.1.0-beta8</cryptomator.cryptofs.version>
|
||||
<cryptomator.cryptofs.version>2.1.0-beta9</cryptomator.cryptofs.version>
|
||||
<cryptomator.integrations.version>1.0.0-rc1</cryptomator.integrations.version>
|
||||
<cryptomator.integrations.win.version>1.0.0-beta2</cryptomator.integrations.win.version>
|
||||
<cryptomator.integrations.mac.version>1.0.0-beta2</cryptomator.integrations.mac.version>
|
||||
<cryptomator.integrations.linux.version>1.0.0-beta1</cryptomator.integrations.linux.version>
|
||||
<cryptomator.fuse.version>1.3.1</cryptomator.fuse.version>
|
||||
<cryptomator.dokany.version>1.3.1</cryptomator.dokany.version>
|
||||
<cryptomator.webdav.version>1.2.4</cryptomator.webdav.version>
|
||||
<cryptomator.webdav.version>1.2.5</cryptomator.webdav.version>
|
||||
|
||||
<!-- 3rd party dependencies -->
|
||||
<javafx.version>16</javafx.version>
|
||||
<commons-lang3.version>3.12.0</commons-lang3.version>
|
||||
<jwt.version>3.17.0</jwt.version>
|
||||
<jwt.version>3.18.1</jwt.version>
|
||||
<easybind.version>2.2</easybind.version>
|
||||
<guava.version>30.1.1-jre</guava.version>
|
||||
<dagger.version>2.37</dagger.version>
|
||||
<gson.version>2.8.6</gson.version>
|
||||
<gson.version>2.8.7</gson.version>
|
||||
<zxcvbn.version>1.5.2</zxcvbn.version>
|
||||
<slf4j.version>1.7.31</slf4j.version>
|
||||
<logback.version>1.2.3</logback.version>
|
||||
|
||||
@@ -142,7 +146,7 @@
|
||||
<dependency>
|
||||
<groupId>com.nulab-inc</groupId>
|
||||
<artifactId>zxcvbn</artifactId>
|
||||
<version>1.3.0</version>
|
||||
<version>${zxcvbn.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Google -->
|
||||
@@ -150,6 +154,29 @@
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${guava.version}</version>
|
||||
<exclusions>
|
||||
<!-- see https://github.com/google/guava/wiki/UseGuavaInYourBuild#what-about-guavas-own-dependencies -->
|
||||
<exclusion>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>listenablefuture</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>jsr305</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.checkerframework</groupId>
|
||||
<artifactId>checker-qual</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.google.errorprone</groupId>
|
||||
<artifactId>error_prone_annotations</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.google.j2objc</groupId>
|
||||
<artifactId>j2objc-annotations</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.dagger</groupId>
|
||||
@@ -190,7 +217,7 @@
|
||||
<dependency>
|
||||
<groupId>com.google.jimfs</groupId>
|
||||
<artifactId>jimfs</artifactId>
|
||||
<version>1.1</version>
|
||||
<version>1.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
@@ -211,7 +238,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>3.1.2</version>
|
||||
<version>3.2.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
@@ -221,7 +248,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.2</version>
|
||||
<version>3.0.0-M5</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
@@ -236,12 +263,12 @@
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.8.6</version>
|
||||
<version>0.8.7</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<version>6.0.3</version>
|
||||
<version>6.2.2</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
@@ -258,6 +285,10 @@
|
||||
<version>${dagger.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
<compilerArgs>
|
||||
<arg>-Adagger.fastInit=enabled</arg>
|
||||
<arg>-Adagger.formatGeneratedSource=enabled</arg>
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
@@ -310,6 +341,19 @@
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-mods</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includeScope>runtime</includeScope>
|
||||
<outputDirectory>${project.build.directory}/mods</outputDirectory>
|
||||
<excludeClassifiers>linux,mac,win</excludeClassifiers>
|
||||
<excludeGroupIds>${nonModularGroupIds}</excludeGroupIds>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-libs</id>
|
||||
<phase>prepare-package</phase>
|
||||
@@ -319,7 +363,7 @@
|
||||
<configuration>
|
||||
<includeScope>runtime</includeScope>
|
||||
<outputDirectory>${project.build.directory}/libs</outputDirectory>
|
||||
<excludeClassifiers>linux,mac,win</excludeClassifiers>
|
||||
<includeGroupIds>${nonModularGroupIds}</includeGroupIds>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
@@ -463,7 +507,7 @@
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/libs</outputDirectory>
|
||||
<outputDirectory>${project.build.directory}/mods</outputDirectory>
|
||||
<includeGroupIds>org.openjfx</includeGroupIds>
|
||||
<classifier>mac</classifier>
|
||||
</configuration>
|
||||
@@ -525,7 +569,7 @@
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/libs</outputDirectory>
|
||||
<outputDirectory>${project.build.directory}/mods</outputDirectory>
|
||||
<includeGroupIds>org.openjfx</includeGroupIds>
|
||||
<classifier>linux</classifier>
|
||||
</configuration>
|
||||
@@ -586,7 +630,7 @@
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/libs</outputDirectory>
|
||||
<outputDirectory>${project.build.directory}/mods</outputDirectory>
|
||||
<includeGroupIds>org.openjfx</includeGroupIds>
|
||||
<classifier>win</classifier>
|
||||
</configuration>
|
||||
|
||||
62
src/main/java/module-info.java
Normal file
62
src/main/java/module-info.java
Normal file
@@ -0,0 +1,62 @@
|
||||
import org.cryptomator.integrations.autostart.AutoStartProvider;
|
||||
import org.cryptomator.integrations.keychain.KeychainAccessProvider;
|
||||
import org.cryptomator.integrations.tray.TrayIntegrationProvider;
|
||||
import org.cryptomator.integrations.uiappearance.UiAppearanceProvider;
|
||||
|
||||
module org.cryptomator.desktop {
|
||||
requires org.cryptomator.cryptofs;
|
||||
requires org.cryptomator.frontend.dokany;
|
||||
requires org.cryptomator.frontend.fuse;
|
||||
requires org.cryptomator.frontend.webdav;
|
||||
requires org.cryptomator.integrations.api;
|
||||
requires java.rmi;
|
||||
requires java.desktop;
|
||||
requires java.net.http;
|
||||
requires javafx.base;
|
||||
requires javafx.graphics;
|
||||
requires javafx.controls;
|
||||
requires javafx.fxml;
|
||||
requires com.tobiasdiez.easybind;
|
||||
requires com.google.common;
|
||||
requires com.google.gson;
|
||||
requires com.nulabinc.zxcvbn;
|
||||
requires org.slf4j;
|
||||
requires org.apache.commons.lang3;
|
||||
requires dagger;
|
||||
requires com.auth0.jwt;
|
||||
|
||||
/* TODO: filename-based modules: */
|
||||
requires static javax.inject; /* ugly dagger/guava crap */
|
||||
requires logback.classic;
|
||||
requires logback.core;
|
||||
|
||||
uses AutoStartProvider;
|
||||
uses KeychainAccessProvider;
|
||||
uses TrayIntegrationProvider;
|
||||
uses UiAppearanceProvider;
|
||||
|
||||
opens org.cryptomator.common.settings to com.google.gson;
|
||||
|
||||
opens org.cryptomator.launcher to java.rmi;
|
||||
|
||||
opens org.cryptomator.common to javafx.fxml;
|
||||
opens org.cryptomator.common.vaults to javafx.fxml;
|
||||
opens org.cryptomator.ui.addvaultwizard to javafx.fxml;
|
||||
opens org.cryptomator.ui.changepassword to javafx.fxml;
|
||||
opens org.cryptomator.ui.common to javafx.fxml;
|
||||
opens org.cryptomator.ui.controls to javafx.fxml;
|
||||
opens org.cryptomator.ui.forgetPassword to javafx.fxml;
|
||||
opens org.cryptomator.ui.fxapp to javafx.fxml;
|
||||
opens org.cryptomator.ui.health to javafx.fxml;
|
||||
opens org.cryptomator.ui.keyloading.masterkeyfile to javafx.fxml;
|
||||
opens org.cryptomator.ui.mainwindow to javafx.fxml;
|
||||
opens org.cryptomator.ui.migration to javafx.fxml;
|
||||
opens org.cryptomator.ui.preferences to javafx.fxml;
|
||||
opens org.cryptomator.ui.quit to javafx.fxml;
|
||||
opens org.cryptomator.ui.recoverykey to javafx.fxml;
|
||||
opens org.cryptomator.ui.removevault to javafx.fxml;
|
||||
opens org.cryptomator.ui.stats to javafx.fxml;
|
||||
opens org.cryptomator.ui.unlock to javafx.fxml;
|
||||
opens org.cryptomator.ui.vaultoptions to javafx.fxml;
|
||||
opens org.cryptomator.ui.wrongfilealert to javafx.fxml;
|
||||
}
|
||||
@@ -33,7 +33,7 @@ public class Environment {
|
||||
LOG.debug("user.region: {}", System.getProperty("user.region"));
|
||||
LOG.debug("logback.configurationFile: {}", System.getProperty("logback.configurationFile"));
|
||||
LOG.debug("cryptomator.settingsPath: {}", System.getProperty("cryptomator.settingsPath"));
|
||||
LOG.debug("cryptomator.ipcPortPath: {}", System.getProperty("cryptomator.ipcPortPath"));
|
||||
LOG.debug("cryptomator.ipcSocketPath: {}", System.getProperty("cryptomator.ipcSocketPath"));
|
||||
LOG.debug("cryptomator.keychainPath: {}", System.getProperty("cryptomator.keychainPath"));
|
||||
LOG.debug("cryptomator.logDir: {}", System.getProperty("cryptomator.logDir"));
|
||||
LOG.debug("cryptomator.mountPointsDir: {}", System.getProperty("cryptomator.mountPointsDir"));
|
||||
@@ -51,8 +51,8 @@ public class Environment {
|
||||
return getPaths("cryptomator.settingsPath");
|
||||
}
|
||||
|
||||
public Stream<Path> getIpcPortPath() {
|
||||
return getPaths("cryptomator.ipcPortPath");
|
||||
public Stream<Path> ipcSocketPath() {
|
||||
return getPaths("cryptomator.ipcSocketPath");
|
||||
}
|
||||
|
||||
public Stream<Path> getKeychainPath() {
|
||||
|
||||
8
src/main/java/org/cryptomator/common/Nullable.java
Normal file
8
src/main/java/org/cryptomator/common/Nullable.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package org.cryptomator.common;
|
||||
|
||||
/**
|
||||
* Replacement for JSR-305 to avoid runtime dependencies. Used in Dagger components.
|
||||
*/
|
||||
public @interface Nullable {
|
||||
|
||||
}
|
||||
@@ -43,7 +43,7 @@ public class VaultSettings {
|
||||
private static final Random RNG = new Random();
|
||||
|
||||
private final String id;
|
||||
private final ObjectProperty<Path> path = new SimpleObjectProperty();
|
||||
private final ObjectProperty<Path> path = new SimpleObjectProperty<>();
|
||||
private final StringProperty displayName = new SimpleStringProperty();
|
||||
private final StringProperty winDriveLetter = new SimpleStringProperty();
|
||||
private final BooleanProperty unlockAfterStartup = new SimpleBooleanProperty(DEFAULT_UNLOCK_AFTER_STARTUP);
|
||||
|
||||
@@ -7,10 +7,10 @@ package org.cryptomator.common.vaults;
|
||||
|
||||
import dagger.BindsInstance;
|
||||
import dagger.Subcomponent;
|
||||
import org.cryptomator.common.Nullable;
|
||||
import org.cryptomator.common.mountpoint.MountPointChooserModule;
|
||||
import org.cryptomator.common.settings.VaultSettings;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Named;
|
||||
|
||||
@PerVault
|
||||
|
||||
@@ -8,6 +8,7 @@ package org.cryptomator.common.vaults;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.Nullable;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.common.settings.VaultSettings;
|
||||
import org.cryptomator.common.settings.VolumeImpl;
|
||||
@@ -15,7 +16,6 @@ import org.cryptomator.cryptofs.CryptoFileSystem;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Named;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.StringBinding;
|
||||
|
||||
65
src/main/java/org/cryptomator/ipc/Client.java
Normal file
65
src/main/java/org/cryptomator/ipc/Client.java
Normal file
@@ -0,0 +1,65 @@
|
||||
package org.cryptomator.ipc;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.UnixDomainSocketAddress;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
class Client implements IpcCommunicator {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Client.class);
|
||||
|
||||
private final SocketChannel socketChannel;
|
||||
|
||||
private Client(SocketChannel socketChannel) {
|
||||
this.socketChannel = socketChannel;
|
||||
}
|
||||
|
||||
public static Client create(Path socketPath) throws IOException {
|
||||
var address = UnixDomainSocketAddress.of(socketPath);
|
||||
var socketChannel = SocketChannel.open(address);
|
||||
LOG.info("Connected to IPC server on socket {}", socketPath);
|
||||
return new Client(socketChannel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClient() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void listen(IpcMessageListener listener, Executor executor) {
|
||||
executor.execute(() -> {
|
||||
try {
|
||||
while (socketChannel.isConnected()) {
|
||||
var msg = IpcMessage.receive(socketChannel);
|
||||
listener.handleMessage(msg);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error("Failed to read IPC message", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(IpcMessage message, Executor executor) {
|
||||
executor.execute(() -> {
|
||||
try {
|
||||
message.send(socketChannel);
|
||||
} catch (IOException e) {
|
||||
LOG.error("Failed to send IPC message", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
socketChannel.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.cryptomator.ipc;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Splitter;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
record HandleLaunchArgsMessage(List<String> args) implements IpcMessage {
|
||||
|
||||
private static final char DELIMITER = '\n';
|
||||
|
||||
public static HandleLaunchArgsMessage decode(ByteBuffer encoded) {
|
||||
var str = StandardCharsets.UTF_8.decode(encoded).toString();
|
||||
var args = Splitter.on(DELIMITER).omitEmptyStrings().splitToList(str);
|
||||
return new HandleLaunchArgsMessage(args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType getMessageType() {
|
||||
return MessageType.HANDLE_LAUNCH_ARGS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer encodePayload() {
|
||||
var str = Joiner.on(DELIMITER).join(args);
|
||||
return StandardCharsets.UTF_8.encode(str);
|
||||
}
|
||||
}
|
||||
96
src/main/java/org/cryptomator/ipc/IpcCommunicator.java
Normal file
96
src/main/java/org/cryptomator/ipc/IpcCommunicator.java
Normal file
@@ -0,0 +1,96 @@
|
||||
package org.cryptomator.ipc;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public interface IpcCommunicator extends Closeable {
|
||||
|
||||
Logger LOG = LoggerFactory.getLogger(IpcCommunicator.class);
|
||||
|
||||
/**
|
||||
* Attempts to establish a socket connection via one of the given paths.
|
||||
* <p>
|
||||
* If no connection to an existing sockets can be established, a new socket is created for the first given path.
|
||||
* <p>
|
||||
* If this fails as well, a fallback communicator is returned that allows process-internal communication mocking the API
|
||||
* that would have been used for IPC.
|
||||
*
|
||||
* @param socketPaths The socket path(s)
|
||||
* @return A communicator object that allows sending and receiving messages
|
||||
*/
|
||||
static IpcCommunicator create(Iterable<Path> socketPaths) {
|
||||
Preconditions.checkArgument(socketPaths.iterator().hasNext(), "socketPaths must contain at least one element");
|
||||
for (var p : socketPaths) {
|
||||
try {
|
||||
var attr = Files.readAttributes(p, BasicFileAttributes.class);
|
||||
if (attr.isOther()) {
|
||||
return Client.create(p);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// attempt next socket path
|
||||
}
|
||||
}
|
||||
// Didn't get any connection yet? I.e. we're the first app instance, so let's launch a server:
|
||||
try {
|
||||
return Server.create(socketPaths.iterator().next());
|
||||
} catch (IOException e) {
|
||||
LOG.warn("Failed to create IPC server", e);
|
||||
return new LoopbackCommunicator();
|
||||
}
|
||||
}
|
||||
|
||||
boolean isClient();
|
||||
|
||||
/**
|
||||
* Listens to incoming messages until the connection gets closed.
|
||||
* @param listener The listener that should be notified of incoming messages
|
||||
* @param executor An executor on which to listen. Listening will block, so you might want to use a background thread.
|
||||
* @return
|
||||
*/
|
||||
void listen(IpcMessageListener listener, Executor executor);
|
||||
|
||||
/**
|
||||
* Sends the given message.
|
||||
*
|
||||
* @param message The message to send
|
||||
* @param executor An executor used to send the message. Sending will block, so you might want to use a background thread.
|
||||
*/
|
||||
void send(IpcMessage message, Executor executor);
|
||||
|
||||
default void sendRevealRunningApp() {
|
||||
send(new RevealRunningAppMessage(), MoreExecutors.directExecutor());
|
||||
}
|
||||
|
||||
default void sendHandleLaunchargs(List<String> args) {
|
||||
send(new HandleLaunchArgsMessage(args), MoreExecutors.directExecutor());
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up resources.
|
||||
*
|
||||
* @implSpec Must be idempotent
|
||||
* @throws IOException In case of I/O errors.
|
||||
*/
|
||||
@Override
|
||||
void close() throws IOException;
|
||||
|
||||
default void closeUnchecked() throws UncheckedIOException {
|
||||
try {
|
||||
close();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
68
src/main/java/org/cryptomator/ipc/IpcMessage.java
Normal file
68
src/main/java/org/cryptomator/ipc/IpcMessage.java
Normal file
@@ -0,0 +1,68 @@
|
||||
package org.cryptomator.ipc;
|
||||
|
||||
import org.cryptomator.cryptolib.common.ByteBuffers;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.util.function.Function;
|
||||
|
||||
// TODO make sealed, remove enum
|
||||
interface IpcMessage {
|
||||
|
||||
enum MessageType {
|
||||
REVEAL_RUNNING_APP(RevealRunningAppMessage::decode),
|
||||
HANDLE_LAUNCH_ARGS(HandleLaunchArgsMessage::decode);
|
||||
|
||||
private final Function<ByteBuffer, IpcMessage> decoder;
|
||||
|
||||
MessageType(Function<ByteBuffer, IpcMessage> decoder) {
|
||||
this.decoder = decoder;
|
||||
}
|
||||
|
||||
static MessageType forOrdinal(int ordinal) {
|
||||
try {
|
||||
return values()[ordinal];
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new IllegalArgumentException("No such message type: " + ordinal, e);
|
||||
}
|
||||
}
|
||||
|
||||
IpcMessage decodePayload(ByteBuffer payload) {
|
||||
return decoder.apply(payload);
|
||||
}
|
||||
}
|
||||
|
||||
MessageType getMessageType();
|
||||
|
||||
ByteBuffer encodePayload();
|
||||
|
||||
static IpcMessage receive(ReadableByteChannel channel) throws IOException {
|
||||
var header = ByteBuffer.allocate(2 * Integer.BYTES);
|
||||
if (ByteBuffers.fill(channel, header) < header.capacity()) {
|
||||
throw new EOFException();
|
||||
}
|
||||
header.flip();
|
||||
int typeNo = header.getInt();
|
||||
int length = header.getInt();
|
||||
MessageType type = MessageType.forOrdinal(typeNo);
|
||||
var payload = ByteBuffer.allocate(length);
|
||||
ByteBuffers.fill(channel, payload);
|
||||
payload.flip();
|
||||
return type.decodePayload(payload);
|
||||
}
|
||||
|
||||
default void send(WritableByteChannel channel) throws IOException {
|
||||
var payload = encodePayload();
|
||||
var buf = ByteBuffer.allocate(2 * Integer.BYTES + payload.remaining());
|
||||
buf.putInt(getMessageType().ordinal()); // message type
|
||||
buf.putInt(payload.remaining()); // message length
|
||||
buf.put(payload); // message
|
||||
buf.flip();
|
||||
while (buf.hasRemaining()) {
|
||||
channel.write(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
src/main/java/org/cryptomator/ipc/IpcMessageListener.java
Normal file
19
src/main/java/org/cryptomator/ipc/IpcMessageListener.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package org.cryptomator.ipc;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IpcMessageListener {
|
||||
|
||||
default void handleMessage(IpcMessage message) {
|
||||
if (message instanceof RevealRunningAppMessage) {
|
||||
revealRunningApp();
|
||||
} else if (message instanceof HandleLaunchArgsMessage m) {
|
||||
handleLaunchArgs(m.args());
|
||||
}
|
||||
}
|
||||
|
||||
void revealRunningApp();
|
||||
|
||||
void handleLaunchArgs(List<String> args);
|
||||
|
||||
}
|
||||
50
src/main/java/org/cryptomator/ipc/LoopbackCommunicator.java
Normal file
50
src/main/java/org/cryptomator/ipc/LoopbackCommunicator.java
Normal file
@@ -0,0 +1,50 @@
|
||||
package org.cryptomator.ipc;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.LinkedTransferQueue;
|
||||
import java.util.concurrent.TransferQueue;
|
||||
|
||||
class LoopbackCommunicator implements IpcCommunicator {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LoopbackCommunicator.class);
|
||||
|
||||
private final TransferQueue<IpcMessage> transferQueue = new LinkedTransferQueue<>();
|
||||
|
||||
@Override
|
||||
public boolean isClient() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void listen(IpcMessageListener listener, Executor executor) {
|
||||
executor.execute(() -> {
|
||||
try {
|
||||
var msg = transferQueue.take();
|
||||
listener.handleMessage(msg);
|
||||
} catch (InterruptedException e) {
|
||||
LOG.error("Failed to read IPC message", e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(IpcMessage message, Executor executor) {
|
||||
executor.execute(() -> {
|
||||
try {
|
||||
transferQueue.put(message);
|
||||
} catch (InterruptedException e) {
|
||||
LOG.error("Failed to send IPC message", e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.cryptomator.ipc;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public record RevealRunningAppMessage() implements IpcMessage {
|
||||
|
||||
static RevealRunningAppMessage decode(ByteBuffer ignored) {
|
||||
return new RevealRunningAppMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType getMessageType() {
|
||||
return MessageType.REVEAL_RUNNING_APP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer encodePayload() {
|
||||
return ByteBuffer.allocate(0);
|
||||
}
|
||||
}
|
||||
82
src/main/java/org/cryptomator/ipc/Server.java
Normal file
82
src/main/java/org/cryptomator/ipc/Server.java
Normal file
@@ -0,0 +1,82 @@
|
||||
package org.cryptomator.ipc;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.net.StandardProtocolFamily;
|
||||
import java.net.UnixDomainSocketAddress;
|
||||
import java.nio.channels.AsynchronousCloseException;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
class Server implements IpcCommunicator {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Server.class);
|
||||
|
||||
private final ServerSocketChannel serverSocketChannel;
|
||||
private final Path socketPath;
|
||||
|
||||
private Server(ServerSocketChannel serverSocketChannel, Path socketPath) {
|
||||
this.serverSocketChannel = serverSocketChannel;
|
||||
this.socketPath = socketPath;
|
||||
}
|
||||
|
||||
public static Server create(Path socketPath) throws IOException {
|
||||
var address = UnixDomainSocketAddress.of(socketPath);
|
||||
var serverSocketChannel = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
|
||||
serverSocketChannel.bind(address);
|
||||
LOG.info("Spawning IPC server listening on socket {}", socketPath);
|
||||
return new Server(serverSocketChannel, socketPath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClient() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void listen(IpcMessageListener listener, Executor executor) {
|
||||
executor.execute(() -> {
|
||||
while (serverSocketChannel.isOpen()) {
|
||||
try (var ch = serverSocketChannel.accept()) {
|
||||
while (ch.isConnected()) {
|
||||
var msg = IpcMessage.receive(ch);
|
||||
listener.handleMessage(msg);
|
||||
}
|
||||
} catch (AsynchronousCloseException e) {
|
||||
return; // serverSocketChannel closed or listener interrupted
|
||||
} catch (EOFException | ClosedChannelException e) {
|
||||
// continue with next connected client
|
||||
} catch (IOException e) {
|
||||
LOG.error("Failed to read IPC message", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(IpcMessage message, Executor executor) {
|
||||
executor.execute(() -> {
|
||||
try (var ch = serverSocketChannel.accept()) {
|
||||
message.send(ch);
|
||||
} catch (IOException e) {
|
||||
LOG.error("Failed to send IPC message", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
try {
|
||||
serverSocketChannel.close();
|
||||
} finally {
|
||||
Files.deleteIfExists(socketPath);
|
||||
LOG.debug("IPC server closed");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,12 @@
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.launcher;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import dagger.Lazy;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.cryptomator.common.ShutdownHook;
|
||||
import org.cryptomator.ipc.IpcCommunicator;
|
||||
import org.cryptomator.logging.DebugMode;
|
||||
import org.cryptomator.logging.LoggerConfiguration;
|
||||
import org.cryptomator.ui.launcher.UiLauncher;
|
||||
@@ -16,8 +21,10 @@ import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
@Singleton
|
||||
public class Cryptomator {
|
||||
@@ -29,23 +36,28 @@ public class Cryptomator {
|
||||
|
||||
private final LoggerConfiguration logConfig;
|
||||
private final DebugMode debugMode;
|
||||
private final IpcFactory ipcFactory;
|
||||
private final Environment env;
|
||||
private final Lazy<IpcMessageHandler> ipcMessageHandler;
|
||||
private final Optional<String> applicationVersion;
|
||||
private final CountDownLatch shutdownLatch;
|
||||
private final UiLauncher uiLauncher;
|
||||
private final ShutdownHook shutdownHook;
|
||||
private final Lazy<UiLauncher> uiLauncher;
|
||||
|
||||
@Inject
|
||||
Cryptomator(LoggerConfiguration logConfig, DebugMode debugMode, IpcFactory ipcFactory, @Named("applicationVersion") Optional<String> applicationVersion, @Named("shutdownLatch") CountDownLatch shutdownLatch, UiLauncher uiLauncher) {
|
||||
Cryptomator(LoggerConfiguration logConfig, DebugMode debugMode, Environment env, Lazy<IpcMessageHandler> ipcMessageHandler, @Named("applicationVersion") Optional<String> applicationVersion, @Named("shutdownLatch") CountDownLatch shutdownLatch, ShutdownHook shutdownHook, Lazy<UiLauncher> uiLauncher) {
|
||||
this.logConfig = logConfig;
|
||||
this.debugMode = debugMode;
|
||||
this.ipcFactory = ipcFactory;
|
||||
this.env = env;
|
||||
this.ipcMessageHandler = ipcMessageHandler;
|
||||
this.applicationVersion = applicationVersion;
|
||||
this.shutdownLatch = shutdownLatch;
|
||||
this.shutdownHook = shutdownHook;
|
||||
this.uiLauncher = uiLauncher;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
int exitCode = CRYPTOMATOR_COMPONENT.application().run(args);
|
||||
LOG.info("Exit {}", exitCode);
|
||||
System.exit(exitCode); // end remaining non-daemon threads.
|
||||
}
|
||||
|
||||
@@ -64,19 +76,24 @@ public class Cryptomator {
|
||||
* Attempts to create an IPC connection to a running Cryptomator instance and sends it the given args.
|
||||
* If no external process could be reached, the args will be handled by the loopback IPC endpoint.
|
||||
*/
|
||||
try (IpcFactory.IpcEndpoint endpoint = ipcFactory.create()) {
|
||||
endpoint.getRemote().handleLaunchArgs(args); // if we are the server, getRemote() returns self.
|
||||
if (endpoint.isConnectedToRemote()) {
|
||||
endpoint.getRemote().revealRunningApp();
|
||||
try (var communicator = IpcCommunicator.create(env.ipcSocketPath().toList())) {
|
||||
if (communicator.isClient()) {
|
||||
communicator.sendHandleLaunchargs(List.of(args));
|
||||
communicator.sendRevealRunningApp();
|
||||
LOG.info("Found running application instance. Shutting down...");
|
||||
return 2;
|
||||
} else {
|
||||
shutdownHook.runOnShutdown(communicator::closeUnchecked);
|
||||
var executor = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("IPC-%d").build());
|
||||
var msgHandler = ipcMessageHandler.get();
|
||||
msgHandler.handleLaunchArgs(List.of(args));
|
||||
communicator.listen(msgHandler, executor);
|
||||
LOG.debug("Did not find running application instance. Launching GUI...");
|
||||
return runGuiApplication();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error("Failed to initiate inter-process communication.", e);
|
||||
return runGuiApplication();
|
||||
} catch (Throwable e) {
|
||||
LOG.error("Running application failed", e);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +105,7 @@ public class Cryptomator {
|
||||
*/
|
||||
private int runGuiApplication() {
|
||||
try {
|
||||
uiLauncher.launch();
|
||||
uiLauncher.get().launch();
|
||||
shutdownLatch.await();
|
||||
LOG.info("UI shut down");
|
||||
return 0;
|
||||
@@ -98,5 +115,4 @@ public class Cryptomator {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -46,13 +47,13 @@ class FileOpenRequestHandler {
|
||||
tryToEnqueueFileOpenRequest(launchEvent);
|
||||
}
|
||||
|
||||
public void handleLaunchArgs(String[] args) {
|
||||
public void handleLaunchArgs(List<String> args) {
|
||||
handleLaunchArgs(FileSystems.getDefault(), args);
|
||||
}
|
||||
|
||||
// visible for testing
|
||||
void handleLaunchArgs(FileSystem fs, String[] args) {
|
||||
Collection<Path> pathsToOpen = Arrays.stream(args).map(str -> {
|
||||
void handleLaunchArgs(FileSystem fs, List<String> args) {
|
||||
Collection<Path> pathsToOpen = args.stream().map(str -> {
|
||||
try {
|
||||
return fs.getPath(str);
|
||||
} catch (InvalidPathException e) {
|
||||
|
||||
@@ -1,258 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Skymatic UG (haftungsbeschränkt).
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the accompanying LICENSE file.
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.launcher;
|
||||
|
||||
import com.google.common.io.MoreFiles;
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.rmi.NotBoundException;
|
||||
import java.rmi.registry.LocateRegistry;
|
||||
import java.rmi.registry.Registry;
|
||||
import java.rmi.server.RMIClientSocketFactory;
|
||||
import java.rmi.server.RMIServerSocketFactory;
|
||||
import java.rmi.server.RMISocketFactory;
|
||||
import java.rmi.server.UnicastRemoteObject;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* First running application on a machine opens a server socket. Further processes will connect as clients.
|
||||
*/
|
||||
@Singleton
|
||||
class IpcFactory {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(IpcFactory.class);
|
||||
private static final String RMI_NAME = "Cryptomator";
|
||||
|
||||
private final List<Path> portFilePaths;
|
||||
private final IpcProtocolImpl ipcHandler;
|
||||
|
||||
@Inject
|
||||
public IpcFactory(Environment env, IpcProtocolImpl ipcHandler) {
|
||||
this.portFilePaths = env.getIpcPortPath().collect(Collectors.toUnmodifiableList());
|
||||
this.ipcHandler = ipcHandler;
|
||||
}
|
||||
|
||||
public IpcEndpoint create() {
|
||||
if (portFilePaths.isEmpty()) {
|
||||
LOG.warn("No IPC port file path specified.");
|
||||
return new SelfEndpoint(ipcHandler);
|
||||
} else {
|
||||
System.setProperty("java.rmi.server.hostname", "localhost");
|
||||
return attemptClientConnection().or(this::createServerEndpoint).orElseGet(() -> new SelfEndpoint(ipcHandler));
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<IpcEndpoint> attemptClientConnection() {
|
||||
for (Path portFilePath : portFilePaths) {
|
||||
try {
|
||||
int port = readPort(portFilePath);
|
||||
LOG.debug("[Client] Connecting to port {}...", port);
|
||||
Registry registry = LocateRegistry.getRegistry("localhost", port, new ClientSocketFactory());
|
||||
IpcProtocol remoteInterface = (IpcProtocol) registry.lookup(RMI_NAME);
|
||||
return Optional.of(new ClientEndpoint(remoteInterface));
|
||||
} catch (NotBoundException | IOException e) {
|
||||
LOG.debug("[Client] Failed to connect.");
|
||||
// continue with next portFilePath...
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private int readPort(Path portFilePath) throws IOException {
|
||||
try (ReadableByteChannel ch = Files.newByteChannel(portFilePath, StandardOpenOption.READ)) {
|
||||
LOG.debug("[Client] Reading IPC port from {}", portFilePath);
|
||||
ByteBuffer buf = ByteBuffer.allocate(Integer.BYTES);
|
||||
if (ch.read(buf) == Integer.BYTES) {
|
||||
buf.flip();
|
||||
return buf.getInt();
|
||||
} else {
|
||||
throw new IOException("Invalid IPC port file.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<IpcEndpoint> createServerEndpoint() {
|
||||
assert !portFilePaths.isEmpty();
|
||||
Path portFilePath = portFilePaths.get(0);
|
||||
try {
|
||||
ServerSocket socket = new ServerSocket(0, Byte.MAX_VALUE, InetAddress.getByName("localhost"));
|
||||
RMIClientSocketFactory csf = RMISocketFactory.getDefaultSocketFactory();
|
||||
SingletonServerSocketFactory ssf = new SingletonServerSocketFactory(socket);
|
||||
Registry registry = LocateRegistry.createRegistry(0, csf, ssf);
|
||||
UnicastRemoteObject.exportObject(ipcHandler, 0);
|
||||
registry.rebind(RMI_NAME, ipcHandler);
|
||||
writePort(portFilePath, socket.getLocalPort());
|
||||
return Optional.of(new ServerEndpoint(ipcHandler, socket, registry, portFilePath));
|
||||
} catch (IOException e) {
|
||||
LOG.warn("[Server] Failed to create IPC server.", e);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private void writePort(Path portFilePath, int port) throws IOException {
|
||||
ByteBuffer buf = ByteBuffer.allocate(Integer.BYTES);
|
||||
buf.putInt(port);
|
||||
buf.flip();
|
||||
MoreFiles.createParentDirectories(portFilePath);
|
||||
try (WritableByteChannel ch = Files.newByteChannel(portFilePath, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
|
||||
if (ch.write(buf) != Integer.BYTES) {
|
||||
throw new IOException("Did not write expected number of bytes.");
|
||||
}
|
||||
}
|
||||
LOG.debug("[Server] Wrote IPC port {} to {}", port, portFilePath);
|
||||
}
|
||||
|
||||
interface IpcEndpoint extends Closeable {
|
||||
|
||||
boolean isConnectedToRemote();
|
||||
|
||||
IpcProtocol getRemote();
|
||||
|
||||
}
|
||||
|
||||
static class SelfEndpoint implements IpcEndpoint {
|
||||
|
||||
protected final IpcProtocol remoteObject;
|
||||
|
||||
SelfEndpoint(IpcProtocol remoteObject) {
|
||||
this.remoteObject = remoteObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnectedToRemote() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IpcProtocol getRemote() {
|
||||
return remoteObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
|
||||
static class ClientEndpoint implements IpcEndpoint {
|
||||
|
||||
private final IpcProtocol remoteInterface;
|
||||
|
||||
public ClientEndpoint(IpcProtocol remoteInterface) {
|
||||
this.remoteInterface = remoteInterface;
|
||||
}
|
||||
|
||||
public IpcProtocol getRemote() {
|
||||
return remoteInterface;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnectedToRemote() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ServerEndpoint extends SelfEndpoint {
|
||||
|
||||
private final ServerSocket socket;
|
||||
private final Registry registry;
|
||||
private final Path portFilePath;
|
||||
|
||||
private ServerEndpoint(IpcProtocol remoteObject, ServerSocket socket, Registry registry, Path portFilePath) {
|
||||
super(remoteObject);
|
||||
this.socket = socket;
|
||||
this.registry = registry;
|
||||
this.portFilePath = portFilePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
registry.unbind(RMI_NAME);
|
||||
UnicastRemoteObject.unexportObject(remoteObject, true);
|
||||
socket.close();
|
||||
Files.deleteIfExists(portFilePath);
|
||||
LOG.debug("[Server] Shut down");
|
||||
} catch (NotBoundException | IOException e) {
|
||||
LOG.warn("[Server] Error shutting down:", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns the same pre-constructed server socket.
|
||||
*/
|
||||
private static class SingletonServerSocketFactory implements RMIServerSocketFactory {
|
||||
|
||||
private final ServerSocket socket;
|
||||
|
||||
public SingletonServerSocketFactory(ServerSocket socket) {
|
||||
this.socket = socket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized ServerSocket createServerSocket(int port) throws IOException {
|
||||
if (port != 0) {
|
||||
throw new IllegalArgumentException("This factory doesn't support specific ports.");
|
||||
}
|
||||
return this.socket;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates client sockets with short timeouts.
|
||||
*/
|
||||
private static class ClientSocketFactory implements RMIClientSocketFactory {
|
||||
|
||||
@Override
|
||||
public Socket createSocket(String host, int port) throws IOException {
|
||||
return new SocketWithFixedTimeout(host, port, 1000);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class SocketWithFixedTimeout extends Socket {
|
||||
|
||||
public SocketWithFixedTimeout(String host, int port, int timeoutInMs) throws UnknownHostException, IOException {
|
||||
super(host, port);
|
||||
super.setSoTimeout(timeoutInMs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setSoTimeout(int timeout) throws SocketException {
|
||||
// do nothing, timeout is fixed
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.cryptomator.launcher;
|
||||
|
||||
import org.cryptomator.ipc.IpcMessageListener;
|
||||
import org.cryptomator.ui.launcher.AppLaunchEvent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -7,20 +8,20 @@ import org.slf4j.LoggerFactory;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
@Singleton
|
||||
class IpcProtocolImpl implements IpcProtocol {
|
||||
class IpcMessageHandler implements IpcMessageListener {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(IpcProtocolImpl.class);
|
||||
private static final Logger LOG = LoggerFactory.getLogger(IpcMessageHandler.class);
|
||||
|
||||
private final FileOpenRequestHandler fileOpenRequestHandler;
|
||||
private final BlockingQueue<AppLaunchEvent> launchEventQueue;
|
||||
|
||||
@Inject
|
||||
public IpcProtocolImpl(FileOpenRequestHandler fileOpenRequestHandler, @Named("launchEventQueue") BlockingQueue<AppLaunchEvent> launchEventQueue) {
|
||||
public IpcMessageHandler(FileOpenRequestHandler fileOpenRequestHandler, @Named("launchEventQueue") BlockingQueue<AppLaunchEvent> launchEventQueue) {
|
||||
this.fileOpenRequestHandler = fileOpenRequestHandler;
|
||||
this.launchEventQueue = launchEventQueue;
|
||||
}
|
||||
@@ -31,8 +32,8 @@ class IpcProtocolImpl implements IpcProtocol {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleLaunchArgs(String... args) {
|
||||
LOG.debug("Received launch args: {}", Arrays.stream(args).reduce((a, b) -> a + ", " + b).orElse(""));
|
||||
public void handleLaunchArgs(List<String> args) {
|
||||
LOG.debug("Received launch args: {}", args.stream().reduce((a, b) -> a + ", " + b).orElse(""));
|
||||
fileOpenRequestHandler.handleLaunchArgs(args);
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Skymatic UG (haftungsbeschränkt).
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the accompanying LICENSE file.
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.launcher;
|
||||
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
|
||||
interface IpcProtocol extends Remote {
|
||||
|
||||
void revealRunningApp() throws RemoteException;
|
||||
|
||||
void handleLaunchArgs(String... args) throws RemoteException;
|
||||
|
||||
}
|
||||
@@ -2,8 +2,8 @@ package org.cryptomator.ui.common;
|
||||
|
||||
import dagger.BindsInstance;
|
||||
import dagger.Subcomponent;
|
||||
import org.cryptomator.common.Nullable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.cryptomator.ui.common;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import org.cryptomator.common.Nullable;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javafx.fxml.FXML;
|
||||
|
||||
@@ -5,7 +5,6 @@ import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
@@ -26,11 +25,9 @@ public class FxmlLoaderFactory {
|
||||
/**
|
||||
* @return A new FXMLLoader instance
|
||||
*/
|
||||
public FXMLLoader construct() {
|
||||
FXMLLoader loader = new FXMLLoader();
|
||||
loader.setControllerFactory(this::constructController);
|
||||
loader.setResources(resourceBundle);
|
||||
return loader;
|
||||
private FXMLLoader construct(String fxmlResourceName) {
|
||||
var url = getClass().getResource(fxmlResourceName);
|
||||
return new FXMLLoader(url, resourceBundle, null, this::constructController);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,10 +38,8 @@ public class FxmlLoaderFactory {
|
||||
* @throws IOException if an error occurs while loading the FXML file
|
||||
*/
|
||||
public FXMLLoader load(String fxmlResourceName) throws IOException {
|
||||
FXMLLoader loader = construct();
|
||||
try (InputStream in = getClass().getResourceAsStream(fxmlResourceName)) {
|
||||
loader.load(in);
|
||||
}
|
||||
FXMLLoader loader = construct(fxmlResourceName);
|
||||
loader.load();
|
||||
return loader;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,9 +35,9 @@ public class Check {
|
||||
|
||||
String getLocalizedName() {
|
||||
try {
|
||||
return resourceBundle.getString(LOCALIZE_PREFIX+check.identifier());
|
||||
return resourceBundle.getString(LOCALIZE_PREFIX+check.name());
|
||||
} catch (MissingResourceException e){
|
||||
return check.identifier();
|
||||
return check.name();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ public class ReportWriter {
|
||||
var writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8))) {
|
||||
writer.write(REPORT_HEADER.formatted(vaultConfig.getId(), vault.getDisplayName(), vault.getPath()));
|
||||
for (var check : performedChecks) {
|
||||
writer.write(REPORT_CHECK_HEADER.formatted(check.getHealthCheck().identifier()));
|
||||
writer.write(REPORT_CHECK_HEADER.formatted(check.getHealthCheck().name()));
|
||||
switch (check.getState()) {
|
||||
case SUCCEEDED -> {
|
||||
writer.write("STATUS: SUCCESS\nRESULTS:\n");
|
||||
|
||||
@@ -19,6 +19,7 @@ import java.awt.Desktop;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.desktop.AboutEvent;
|
||||
import java.awt.desktop.QuitResponse;
|
||||
import java.awt.desktop.QuitStrategy;
|
||||
import java.util.EnumSet;
|
||||
import java.util.EventObject;
|
||||
import java.util.Set;
|
||||
@@ -61,6 +62,11 @@ public class AppLifecycleListener {
|
||||
Desktop.getDesktop().setQuitHandler(this::handleQuitRequest);
|
||||
}
|
||||
|
||||
// set quit strategy (cmd+q would call `System.exit(0)` otherwise)
|
||||
if (Desktop.getDesktop().isSupported(Desktop.Action.APP_QUIT_STRATEGY)) {
|
||||
Desktop.getDesktop().setQuitStrategy(QuitStrategy.CLOSE_ALL_WINDOWS);
|
||||
}
|
||||
|
||||
shutdownHook.runOnShutdown(this::forceUnmountRemainingVaults);
|
||||
}
|
||||
|
||||
@@ -71,7 +77,7 @@ public class AppLifecycleListener {
|
||||
handleQuitRequest(null, new QuitResponse() {
|
||||
@Override
|
||||
public void performQuit() {
|
||||
System.exit(0);
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -96,7 +102,7 @@ public class AppLifecycleListener {
|
||||
public void performQuit() {
|
||||
Platform.exit(); // will be no-op, if JavaFX never started.
|
||||
shutdownLatch.countDown(); // main thread is waiting for this latch
|
||||
EventQueue.invokeLater(originalQuitResponse::performQuit); // this will eventually call System.exit(0)
|
||||
originalQuitResponse.performQuit();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<Insets topRightBottomLeft="24"/>
|
||||
</padding>
|
||||
<children>
|
||||
<fx:include fx:id="newPasswordScene" source="/fxml/new_password.fxml"/>
|
||||
<fx:include fx:id="newPasswordScene" source="new_password.fxml"/>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS"/>
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<children>
|
||||
<Region VBox.vgrow="ALWAYS"/>
|
||||
|
||||
<fx:include source="/fxml/recoverykey_display.fxml"/>
|
||||
<fx:include source="recoverykey_display.fxml"/>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS"/>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<Region VBox.vgrow="ALWAYS"/>
|
||||
|
||||
<ImageView VBox.vgrow="ALWAYS" fitHeight="128" preserveRatio="true" smooth="true" cache="true">
|
||||
<Image url="/img/bot/bot.png"/>
|
||||
<Image url="@../img/bot/bot.png"/>
|
||||
</ImageView>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS"/>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
<Region prefHeight="12" VBox.vgrow="NEVER"/>
|
||||
|
||||
<fx:include fx:id="newPassword" source="/fxml/new_password.fxml"/>
|
||||
<fx:include fx:id="newPassword" source="new_password.fxml"/>
|
||||
|
||||
<CheckBox fx:id="finalConfirmationCheckbox" text="%changepassword.finalConfirmation" wrapText="true"/>
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<VBox minWidth="300" alignment="CENTER" visible="${!controller.anyCheckSelected}" managed="${!controller.anyCheckSelected}" >
|
||||
<Label text="%health.check.detail.noSelectedCheck" wrapText="true" alignment="CENTER" />
|
||||
</VBox>
|
||||
<fx:include source="/fxml/health_check_details.fxml" visible="${controller.anyCheckSelected}" managed="${controller.anyCheckSelected}" HBox.hgrow="ALWAYS"/>
|
||||
<fx:include source="health_check_details.fxml" visible="${controller.anyCheckSelected}" managed="${controller.anyCheckSelected}" HBox.hgrow="ALWAYS"/>
|
||||
</StackPane>
|
||||
</HBox>
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+CX">
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<HBox VBox.vgrow="ALWAYS">
|
||||
<VBox alignment="CENTER" minWidth="175" maxWidth="175">
|
||||
<ImageView VBox.vgrow="ALWAYS" fitHeight="128" preserveRatio="true" smooth="true" cache="true">
|
||||
<Image url="/img/bot/bot.png"/>
|
||||
<Image url="@../img/bot/bot.png"/>
|
||||
</ImageView>
|
||||
</VBox>
|
||||
<VBox HBox.hgrow="ALWAYS" alignment="CENTER">
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
fx:controller="org.cryptomator.ui.mainwindow.MainWindowController"
|
||||
styleClass="main-window">
|
||||
<VBox>
|
||||
<fx:include source="/fxml/main_window_title.fxml" VBox.vgrow="NEVER"/>
|
||||
<fx:include source="main_window_title.fxml" VBox.vgrow="NEVER"/>
|
||||
<StackPane VBox.vgrow="ALWAYS">
|
||||
<SplitPane dividerPositions="0.33" orientation="HORIZONTAL">
|
||||
<fx:include source="/fxml/vault_list.fxml" SplitPane.resizableWithParent="false"/>
|
||||
<fx:include source="/fxml/vault_detail.fxml" SplitPane.resizableWithParent="true"/>
|
||||
<fx:include source="vault_list.fxml" SplitPane.resizableWithParent="false"/>
|
||||
<fx:include source="vault_detail.fxml" SplitPane.resizableWithParent="true"/>
|
||||
</SplitPane>
|
||||
|
||||
<VBox styleClass="drag-n-drop-indicator" visible="${controller.draggingOver}" alignment="TOP_CENTER">
|
||||
@@ -33,5 +33,5 @@
|
||||
</VBox>
|
||||
</StackPane>
|
||||
</VBox>
|
||||
<fx:include source="/fxml/main_window_resize.fxml"/>
|
||||
<fx:include source="main_window_resize.fxml"/>
|
||||
</StackPane>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<FontAwesome5IconView glyph="WRENCH"/>
|
||||
</graphic>
|
||||
<content>
|
||||
<fx:include source="/fxml/preferences_general.fxml"/>
|
||||
<fx:include source="preferences_general.fxml"/>
|
||||
</content>
|
||||
</Tab>
|
||||
<Tab fx:id="volumeTab" id="VOLUME" text="%preferences.volume">
|
||||
@@ -27,7 +27,7 @@
|
||||
<FontAwesome5IconView glyph="HDD"/>
|
||||
</graphic>
|
||||
<content>
|
||||
<fx:include source="/fxml/preferences_volume.fxml"/>
|
||||
<fx:include source="preferences_volume.fxml"/>
|
||||
</content>
|
||||
</Tab>
|
||||
<Tab fx:id="updatesTab" id="UPDATES" text="%preferences.updates">
|
||||
@@ -35,7 +35,7 @@
|
||||
<FontAwesome5IconView glyph="SYNC"/>
|
||||
</graphic>
|
||||
<content>
|
||||
<fx:include source="/fxml/preferences_updates.fxml"/>
|
||||
<fx:include source="preferences_updates.fxml"/>
|
||||
</content>
|
||||
</Tab>
|
||||
<Tab fx:id="contributeTab" id="CONTRIBUTE" text="%preferences.contribute">
|
||||
@@ -43,7 +43,7 @@
|
||||
<FontAwesome5IconView glyph="HEART"/>
|
||||
</graphic>
|
||||
<content>
|
||||
<fx:include source="/fxml/preferences_contribute.fxml"/>
|
||||
<fx:include source="preferences_contribute.fxml"/>
|
||||
</content>
|
||||
</Tab>
|
||||
<Tab fx:id="aboutTab" id="ABOUT" text="%preferences.about">
|
||||
@@ -51,7 +51,7 @@
|
||||
<FontAwesome5IconView glyph="INFO_CIRCLE"/>
|
||||
</graphic>
|
||||
<content>
|
||||
<fx:include source="/fxml/preferences_about.fxml"/>
|
||||
<fx:include source="preferences_about.fxml"/>
|
||||
</content>
|
||||
</Tab>
|
||||
</tabs>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<children>
|
||||
<HBox spacing="12" VBox.vgrow="NEVER">
|
||||
<ImageView VBox.vgrow="ALWAYS" fitHeight="64" preserveRatio="true" smooth="true" cache="true">
|
||||
<Image url="/img/bot/bot.png"/>
|
||||
<Image url="@../img/bot/bot.png"/>
|
||||
</ImageView>
|
||||
<VBox spacing="3" HBox.hgrow="ALWAYS" alignment="CENTER_LEFT">
|
||||
<FormattedLabel styleClass="label-large" format="Cryptomator %s" arg1="${controller.applicationVersion}"/>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<fx:include fx:id="newPassword" source="/fxml/new_password.fxml"/>
|
||||
<fx:include fx:id="newPassword" source="new_password.fxml"/>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS"/>
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<fx:include source="/fxml/recoverykey_display.fxml"/>
|
||||
<fx:include source="recoverykey_display.fxml"/>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS"/>
|
||||
|
||||
|
||||
@@ -26,23 +26,23 @@
|
||||
<HBox spacing="12" VBox.vgrow="ALWAYS">
|
||||
<StackPane alignment="CENTER" HBox.hgrow="NEVER">
|
||||
<ImageView VBox.vgrow="ALWAYS" fitWidth="64" preserveRatio="true" smooth="true" cache="true" fx:id="face" visible="false">
|
||||
<Image url="/img/bot/face.png"/>
|
||||
<Image url="@../img/bot/face.png"/>
|
||||
</ImageView>
|
||||
|
||||
<ImageView VBox.vgrow="ALWAYS" fitWidth="64" preserveRatio="true" smooth="true" cache="true" fx:id="leftArm" visible="false">
|
||||
<Image url="/img/bot/arm-l.png"/>
|
||||
<Image url="@../img/bot/arm-l.png"/>
|
||||
</ImageView>
|
||||
|
||||
<ImageView VBox.vgrow="ALWAYS" fitWidth="64" preserveRatio="true" smooth="true" cache="true" fx:id="rightArm" visible="false">
|
||||
<Image url="/img/bot/arm-r.png"/>
|
||||
<Image url="@../img/bot/arm-r.png"/>
|
||||
</ImageView>
|
||||
|
||||
<ImageView VBox.vgrow="ALWAYS" fitWidth="64" preserveRatio="true" smooth="true" cache="true" fx:id="legs" visible="false">
|
||||
<Image url="/img/bot/legs.png"/>
|
||||
<Image url="@../img/bot/legs.png"/>
|
||||
</ImageView>
|
||||
|
||||
<ImageView VBox.vgrow="ALWAYS" fitWidth="64" preserveRatio="true" smooth="true" cache="true" fx:id="body">
|
||||
<Image url="/img/bot/body.png"/>
|
||||
<Image url="@../img/bot/body.png"/>
|
||||
</ImageView>
|
||||
</StackPane>
|
||||
<VBox spacing="6" HBox.hgrow="ALWAYS">
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
spacing="24">
|
||||
<children>
|
||||
<ImageView VBox.vgrow="ALWAYS" fitHeight="128" preserveRatio="true" smooth="true" cache="true">
|
||||
<Image url="/img/bot/bot.png"/>
|
||||
<Image url="@../img/bot/bot.png"/>
|
||||
</ImageView>
|
||||
|
||||
<TextFlow styleClass="text-flow" prefWidth="-Infinity" visible="${controller.noVaultPresent}" managed="${controller.noVaultPresent}">
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<FontAwesome5IconView glyph="WRENCH"/>
|
||||
</graphic>
|
||||
<content>
|
||||
<fx:include source="/fxml/vault_options_general.fxml"/>
|
||||
<fx:include source="vault_options_general.fxml"/>
|
||||
</content>
|
||||
</Tab>
|
||||
<Tab fx:id="mountTab" id="MOUNT" text="%vaultOptions.mount">
|
||||
@@ -25,7 +25,7 @@
|
||||
<FontAwesome5IconView glyph="HDD"/>
|
||||
</graphic>
|
||||
<content>
|
||||
<fx:include source="/fxml/vault_options_mount.fxml"/>
|
||||
<fx:include source="vault_options_mount.fxml"/>
|
||||
</content>
|
||||
</Tab>
|
||||
<Tab fx:id="keyTab" id="KEY" text="%vaultOptions.masterkey">
|
||||
@@ -33,7 +33,7 @@
|
||||
<FontAwesome5IconView glyph="KEY"/>
|
||||
</graphic>
|
||||
<content>
|
||||
<fx:include source="/fxml/vault_options_masterkey.fxml"/>
|
||||
<fx:include source="vault_options_masterkey.fxml"/>
|
||||
</content>
|
||||
</Tab>
|
||||
</tabs>
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
<?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.general.startBtn" disable="${!affirmationBox.selected}" onAction="#startHealthCheck"/>
|
||||
</children>
|
||||
</VBox>
|
||||
@@ -11,20 +11,16 @@ GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see http://www.gnu.org/licenses/.
|
||||
|
||||
Cryptomator uses 45 third-party dependencies under the following licenses:
|
||||
Cryptomator uses 40 third-party dependencies under the following licenses:
|
||||
Apache License v2.0:
|
||||
- jffi (com.github.jnr:jffi:1.2.23 - http://github.com/jnr/jffi)
|
||||
- jnr-a64asm (com.github.jnr:jnr-a64asm:1.0.0 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-a64asm)
|
||||
- jnr-constants (com.github.jnr:jnr-constants:0.9.15 - http://github.com/jnr/jnr-constants)
|
||||
- jnr-ffi (com.github.jnr:jnr-ffi:2.1.12 - http://github.com/jnr/jnr-ffi)
|
||||
- FindBugs-jsr305 (com.google.code.findbugs:jsr305:3.0.2 - http://findbugs.sourceforge.net/)
|
||||
- Gson (com.google.code.gson:gson:2.8.6 - https://github.com/google/gson/gson)
|
||||
- Gson (com.google.code.gson:gson:2.8.7 - https://github.com/google/gson/gson)
|
||||
- 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)
|
||||
- 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 ListenableFuture only (com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava - https://github.com/google/guava/listenablefuture)
|
||||
- J2ObjC Annotations (com.google.j2objc:j2objc-annotations:1.3 - https://github.com/google/j2objc/)
|
||||
- Apache Commons CLI (commons-cli:commons-cli:1.4 - http://commons.apache.org/proper/commons-cli/)
|
||||
- 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)
|
||||
@@ -32,12 +28,12 @@ Cryptomator uses 45 third-party dependencies under the following licenses:
|
||||
- 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)
|
||||
- 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.3 - https://eclipse.org/jetty/jetty-http)
|
||||
- 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.3 - https://eclipse.org/jetty/jetty-security)
|
||||
- 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.3 - https://eclipse.org/jetty/jetty-servlet)
|
||||
- Jetty :: Utilities (org.eclipse.jetty:jetty-util:10.0.3 - https://eclipse.org/jetty/jetty-util)
|
||||
- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:10.0.6 - https://eclipse.org/jetty/jetty-http)
|
||||
- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:10.0.6 - https://eclipse.org/jetty/jetty-io)
|
||||
- Jetty :: Security (org.eclipse.jetty:jetty-security:10.0.6 - https://eclipse.org/jetty/jetty-security)
|
||||
- Jetty :: Server Core (org.eclipse.jetty:jetty-server:10.0.6 - https://eclipse.org/jetty/jetty-server)
|
||||
- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:10.0.6 - https://eclipse.org/jetty/jetty-servlet)
|
||||
- Jetty :: Utilities (org.eclipse.jetty:jetty-util:10.0.6 - https://eclipse.org/jetty/jetty-util)
|
||||
- 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:
|
||||
- asm (org.ow2.asm:asm:7.1 - http://asm.ow2.org/)
|
||||
@@ -48,12 +44,12 @@ Cryptomator uses 45 third-party dependencies under the following licenses:
|
||||
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)
|
||||
Eclipse Public License - Version 2.0:
|
||||
- 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.3 - https://eclipse.org/jetty/jetty-io)
|
||||
- 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.3 - https://eclipse.org/jetty/jetty-server)
|
||||
- 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.3 - https://eclipse.org/jetty/jetty-util)
|
||||
- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:10.0.6 - https://eclipse.org/jetty/jetty-http)
|
||||
- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:10.0.6 - https://eclipse.org/jetty/jetty-io)
|
||||
- Jetty :: Security (org.eclipse.jetty:jetty-security:10.0.6 - https://eclipse.org/jetty/jetty-security)
|
||||
- Jetty :: Server Core (org.eclipse.jetty:jetty-server:10.0.6 - https://eclipse.org/jetty/jetty-server)
|
||||
- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:10.0.6 - https://eclipse.org/jetty/jetty-servlet)
|
||||
- Jetty :: Utilities (org.eclipse.jetty:jetty-util:10.0.6 - https://eclipse.org/jetty/jetty-util)
|
||||
Eclipse Public License - v 1.0:
|
||||
- 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)
|
||||
@@ -74,11 +70,10 @@ Cryptomator uses 45 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 Platform (net.java.dev.jna:jna-platform:5.7.0 - https://github.com/java-native-access/jna)
|
||||
MIT License:
|
||||
- java jwt (com.auth0:java-jwt:3.17.0 - https://github.com/auth0/java-jwt)
|
||||
- java jwt (com.auth0:java-jwt:3.18.1 - https://github.com/auth0/java-jwt)
|
||||
- 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)
|
||||
- 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)
|
||||
- zxcvbn4j (com.nulab-inc:zxcvbn:1.5.2 - https://github.com/nulab/zxcvbn4j)
|
||||
- SLF4J API Module (org.slf4j:slf4j-api:1.7.31 - http://www.slf4j.org)
|
||||
The BSD 2-Clause License:
|
||||
- EasyBind (com.tobiasdiez:easybind:2.2 - https://github.com/tobiasdiez/EasyBind)
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#!/bin/sh
|
||||
cd $(dirname $0)
|
||||
java \
|
||||
-p "mods" \
|
||||
-cp "libs/*" \
|
||||
-Dcryptomator.settingsPath="~/.config/Cryptomator/settings.json" \
|
||||
-Dcryptomator.ipcPortPath="~/.config/Cryptomator/ipcPort.bin" \
|
||||
-Dcryptomator.ipcSocketPath="~/.config/Cryptomator/ipc.socket" \
|
||||
-Dcryptomator.logDir="~/.local/share/Cryptomator/logs" \
|
||||
-Dcryptomator.mountPointsDir="~/.local/share/Cryptomator/mnt" \
|
||||
-Djdk.gtk.version=2 \
|
||||
-Xss2m \
|
||||
-Xmx512m \
|
||||
org.cryptomator.launcher.Cryptomator
|
||||
-m org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#!/bin/sh
|
||||
cd $(dirname $0)
|
||||
java \
|
||||
-p "mods" \
|
||||
-cp "libs/*" \
|
||||
-Dcryptomator.settingsPath="~/Library/Application Support/Cryptomator/settings.json" \
|
||||
-Dcryptomator.ipcPortPath="~/Library/Application Support/Cryptomator/ipcPort.bin" \
|
||||
-Dcryptomator.ipcSocketPath="~/Library/Application Support/Cryptomator/ipc.socket" \
|
||||
-Dcryptomator.logDir="~/Library/Logs/Cryptomator" \
|
||||
-Dcryptomator.mountPointsDir="/Volumes" \
|
||||
-Xss20m \
|
||||
-Xmx512m \
|
||||
org.cryptomator.launcher.Cryptomator
|
||||
-m org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator
|
||||
@@ -1,11 +1,12 @@
|
||||
@echo off
|
||||
java ^
|
||||
-p "mods" ^
|
||||
-cp "libs/*" ^
|
||||
-Dcryptomator.settingsPath="~/AppData/Roaming/Cryptomator/settings.json" ^
|
||||
-Dcryptomator.ipcPortPath="~/AppData/Roaming/Cryptomator/ipcPort.bin" ^
|
||||
-Dcryptomator.ipcSocketPath="~/AppData/Roaming/Cryptomator/ipc.socket" ^
|
||||
-Dcryptomator.logDir="~/AppData/Roaming/Cryptomator" ^
|
||||
-Dcryptomator.mountPointsDir="~/Cryptomator" ^
|
||||
-Dcryptomator.keychainPath="~/AppData/Roaming/Cryptomator/keychain.json" ^
|
||||
-Xss20m ^
|
||||
-Xmx512m ^
|
||||
org.cryptomator.launcher.Cryptomator
|
||||
-m org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator
|
||||
@@ -3,7 +3,6 @@ package org.cryptomator.common;
|
||||
import org.hamcrest.MatcherAssert;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
@@ -14,7 +13,6 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@DisplayName("Environment Variables Test")
|
||||
public class EnvironmentTest {
|
||||
@@ -39,14 +37,14 @@ public class EnvironmentTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("cryptomator.ipcPortPath=~/.config/Cryptomator/ipcPort.bin:~/.Cryptomator/ipcPort.bin")
|
||||
public void testIpcPortPath() {
|
||||
System.setProperty("cryptomator.ipcPortPath", "~/.config/Cryptomator/ipcPort.bin:~/.Cryptomator/ipcPort.bin");
|
||||
@DisplayName("cryptomator.ipcSocketPath=~/.config/Cryptomator/ipc.socket:~/.Cryptomator/ipc.socket")
|
||||
public void testIpcSocketPath() {
|
||||
System.setProperty("cryptomator.ipcSocketPath", "~/.config/Cryptomator/ipc.socket:~/.Cryptomator/ipc.socket");
|
||||
|
||||
List<Path> result = env.getIpcPortPath().toList();
|
||||
List<Path> result = env.ipcSocketPath().toList();
|
||||
MatcherAssert.assertThat(result, Matchers.hasSize(2));
|
||||
MatcherAssert.assertThat(result, Matchers.contains(Paths.get("/home/testuser/.config/Cryptomator/ipcPort.bin"), //
|
||||
Paths.get("/home/testuser/.Cryptomator/ipcPort.bin")));
|
||||
MatcherAssert.assertThat(result, Matchers.contains(Paths.get("/home/testuser/.config/Cryptomator/ipc.socket"), //
|
||||
Paths.get("/home/testuser/.Cryptomator/ipc.socket")));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.cryptomator.ipc;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.List;
|
||||
|
||||
public class HandleLaunchArgsMessageTest {
|
||||
|
||||
@Test
|
||||
public void testSendAndReceive(@TempDir Path tmpDir) throws IOException {
|
||||
var message = new HandleLaunchArgsMessage(List.of("hello world", "foo bar"));
|
||||
|
||||
var file = tmpDir.resolve("tmp.file");
|
||||
try (var ch = FileChannel.open(file, StandardOpenOption.CREATE_NEW, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
|
||||
message.send(ch);
|
||||
ch.position(0);
|
||||
if (IpcMessage.receive(ch) instanceof HandleLaunchArgsMessage received) {
|
||||
Assertions.assertArrayEquals(message.args().toArray(), received.args().toArray());
|
||||
} else {
|
||||
Assertions.fail("Received message of unexpected class");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendAndReceiveEmpty(@TempDir Path tmpDir) throws IOException {
|
||||
var message = new HandleLaunchArgsMessage(List.of());
|
||||
|
||||
var file = tmpDir.resolve("tmp.file");
|
||||
try (var ch = FileChannel.open(file, StandardOpenOption.CREATE_NEW, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
|
||||
message.send(ch);
|
||||
ch.position(0);
|
||||
if (IpcMessage.receive(ch) instanceof HandleLaunchArgsMessage received) {
|
||||
Assertions.assertArrayEquals(message.args().toArray(), received.args().toArray());
|
||||
} else {
|
||||
Assertions.fail("Received message of unexpected class");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
44
src/test/java/org/cryptomator/ipc/IpcCommunicatorTest.java
Normal file
44
src/test/java/org/cryptomator/ipc/IpcCommunicatorTest.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package org.cryptomator.ipc;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.function.Executable;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class IpcCommunicatorTest {
|
||||
|
||||
@Test
|
||||
public void testSendAndReceive(@TempDir Path tmpDir) throws IOException, InterruptedException {
|
||||
var socketPath = tmpDir.resolve("foo.sock");
|
||||
try (var server = IpcCommunicator.create(List.of(socketPath));
|
||||
var client = IpcCommunicator.create(List.of(socketPath))) {
|
||||
Assertions.assertNotSame(server, client);
|
||||
|
||||
var cdl = new CountDownLatch(1);
|
||||
var executor = Executors.newSingleThreadExecutor();
|
||||
server.listen(new IpcMessageListener() {
|
||||
@Override
|
||||
public void revealRunningApp() {
|
||||
cdl.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleLaunchArgs(List<String> args) {
|
||||
|
||||
}
|
||||
}, executor);
|
||||
client.sendRevealRunningApp();
|
||||
|
||||
Assertions.assertTimeoutPreemptively(Duration.ofMillis(300), (Executable) cdl::await);
|
||||
executor.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.cryptomator.ipc;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.function.Executable;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class LoopbackCommunicatorTest {
|
||||
|
||||
@Test
|
||||
public void testSendAndReceive() {
|
||||
try (var communicator = new LoopbackCommunicator()) {
|
||||
var cdl = new CountDownLatch(1);
|
||||
var executor = Executors.newSingleThreadExecutor();
|
||||
communicator.listen(new IpcMessageListener() {
|
||||
@Override
|
||||
public void revealRunningApp() {
|
||||
cdl.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleLaunchArgs(List<String> args) {
|
||||
|
||||
}
|
||||
}, executor);
|
||||
communicator.sendRevealRunningApp();
|
||||
|
||||
Assertions.assertTimeoutPreemptively(Duration.ofMillis(300), (Executable) cdl::await);
|
||||
executor.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.cryptomator.ipc;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.List;
|
||||
|
||||
public class RevealRunningAppMessageTest {
|
||||
|
||||
@Test
|
||||
public void testSendAndReceive(@TempDir Path tmpDir) throws IOException {
|
||||
var message = new RevealRunningAppMessage();
|
||||
|
||||
var file = tmpDir.resolve("tmp.file");
|
||||
try (var ch = FileChannel.open(file, StandardOpenOption.CREATE_NEW, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
|
||||
message.send(ch);
|
||||
ch.position(0);
|
||||
if (IpcMessage.receive(ch) instanceof RevealRunningAppMessage received) {
|
||||
Assertions.assertNotNull(received);
|
||||
} else {
|
||||
Assertions.fail("Received message of unexpected class");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
@@ -38,7 +39,7 @@ public class FileOpenRequestHandlerTest {
|
||||
@Test
|
||||
@DisplayName("./cryptomator.exe foo bar")
|
||||
public void testOpenArgsWithCorrectPaths() {
|
||||
inTest.handleLaunchArgs(new String[]{"foo", "bar"});
|
||||
inTest.handleLaunchArgs(List.of("foo", "bar"));
|
||||
|
||||
AppLaunchEvent evt = queue.poll();
|
||||
Assertions.assertNotNull(evt);
|
||||
@@ -51,7 +52,7 @@ public class FileOpenRequestHandlerTest {
|
||||
public void testOpenArgsWithIncorrectPaths() {
|
||||
FileSystem fs = Mockito.mock(FileSystem.class);
|
||||
Mockito.when(fs.getPath("foo")).thenThrow(new InvalidPathException("foo", "foo is not a path"));
|
||||
inTest.handleLaunchArgs(fs, new String[]{"foo"});
|
||||
inTest.handleLaunchArgs(fs, List.of("foo"));
|
||||
|
||||
AppLaunchEvent evt = queue.poll();
|
||||
Assertions.assertNull(evt);
|
||||
@@ -63,7 +64,7 @@ public class FileOpenRequestHandlerTest {
|
||||
queue.add(new AppLaunchEvent(AppLaunchEvent.EventType.OPEN_FILE, Collections.emptyList()));
|
||||
Assumptions.assumeTrue(queue.remainingCapacity() == 0);
|
||||
|
||||
inTest.handleLaunchArgs(new String[]{"foo"});
|
||||
inTest.handleLaunchArgs(List.of("foo"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Skymatic UG (haftungsbeschränkt).
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the accompanying LICENSE file.
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.launcher;
|
||||
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.cryptomator.launcher.IpcFactory.IpcEndpoint;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class IpcFactoryTest {
|
||||
|
||||
private Environment environment = Mockito.mock(Environment.class);
|
||||
private IpcProtocolImpl protocolHandler = Mockito.mock(IpcProtocolImpl.class);
|
||||
|
||||
@Test
|
||||
@DisplayName("Without IPC port files")
|
||||
public void testNoIpcWithoutPortFile() throws IOException {
|
||||
IpcFactory inTest = new IpcFactory(environment, protocolHandler);
|
||||
|
||||
Mockito.when(environment.getIpcPortPath()).thenReturn(Stream.empty());
|
||||
try (IpcEndpoint endpoint1 = inTest.create()) {
|
||||
Assertions.assertEquals(IpcFactory.SelfEndpoint.class, endpoint1.getClass());
|
||||
Assertions.assertFalse(endpoint1.isConnectedToRemote());
|
||||
Assertions.assertSame(protocolHandler, endpoint1.getRemote());
|
||||
try (IpcEndpoint endpoint2 = inTest.create()) {
|
||||
Assertions.assertEquals(IpcFactory.SelfEndpoint.class, endpoint2.getClass());
|
||||
Assertions.assertNotSame(endpoint1, endpoint2);
|
||||
Assertions.assertFalse(endpoint2.isConnectedToRemote());
|
||||
Assertions.assertSame(protocolHandler, endpoint2.getRemote());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Start server and client with port shared via file")
|
||||
public void testInterProcessCommunication(@TempDir Path tmpDir) throws IOException {
|
||||
Path portFile = tmpDir.resolve("testPortFile");
|
||||
Mockito.when(environment.getIpcPortPath()).thenReturn(Stream.of(portFile));
|
||||
IpcFactory inTest = new IpcFactory(environment, protocolHandler);
|
||||
|
||||
Assertions.assertFalse(Files.exists(portFile));
|
||||
try (IpcEndpoint endpoint1 = inTest.create()) {
|
||||
Assertions.assertEquals(IpcFactory.ServerEndpoint.class, endpoint1.getClass());
|
||||
Assertions.assertFalse(endpoint1.isConnectedToRemote());
|
||||
Assertions.assertTrue(Files.exists(portFile));
|
||||
Assertions.assertSame(protocolHandler, endpoint1.getRemote());
|
||||
Mockito.verifyZeroInteractions(protocolHandler);
|
||||
try (IpcEndpoint endpoint2 = inTest.create()) {
|
||||
Assertions.assertEquals(IpcFactory.ClientEndpoint.class, endpoint2.getClass());
|
||||
Assertions.assertNotSame(endpoint1, endpoint2);
|
||||
Assertions.assertTrue(endpoint2.isConnectedToRemote());
|
||||
Assertions.assertNotSame(protocolHandler, endpoint2.getRemote());
|
||||
Mockito.verifyZeroInteractions(protocolHandler);
|
||||
endpoint2.getRemote().handleLaunchArgs(new String[]{"foo"});
|
||||
Mockito.verify(protocolHandler).handleLaunchArgs(new String[]{"foo"});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user