mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-09-21 23:44:42 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0dca0d6f1c |
@@ -60,7 +60,7 @@ jobs:
|
||||
--verbose
|
||||
--output runtime
|
||||
--module-path "${JAVA_HOME}/jmods"
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr
|
||||
--add-modules java.base,java.desktop,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr
|
||||
--strip-native-commands
|
||||
--no-header-files
|
||||
--no-man-pages
|
||||
@@ -92,7 +92,6 @@ jobs:
|
||||
--java-options "-Dcryptomator.logDir=\"~/.local/share/Cryptomator/logs\""
|
||||
--java-options "-Dcryptomator.pluginDir=\"~/.local/share/Cryptomator/plugins\""
|
||||
--java-options "-Dcryptomator.settingsPath=\"~/.config/Cryptomator/settings.json:~/.Cryptomator/settings.json\""
|
||||
--java-options "-Dcryptomator.p12Path=\"~/.config/Cryptomator/key.p12\""
|
||||
--java-options "-Dcryptomator.ipcSocketPath=\"~/.config/Cryptomator/ipc.socket\""
|
||||
--java-options "-Dcryptomator.mountPointsDir=\"~/.local/share/Cryptomator/mnt\""
|
||||
--java-options "-Dcryptomator.showTrayIcon=false"
|
||||
|
||||
@@ -111,7 +111,7 @@ jobs:
|
||||
cryptomator_*_amd64.deb
|
||||
cryptomator_*.asc
|
||||
- name: Publish on PPA
|
||||
if: startsWith(github.ref, 'refs/tags/') || inputs.dput
|
||||
if: startsWith(github.ref, 'refs/tags/') || github.event.inputs.dput == 'true'
|
||||
run: dput ppa:sebastian-stenzel/cryptomator-beta cryptomator_*_source.changes
|
||||
- name: Publish Debian package on GitHub Releases
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
name: Update Error Database
|
||||
|
||||
on:
|
||||
discussion:
|
||||
types: [created, edited, category_changed, answered, unanswered]
|
||||
discussion_comment:
|
||||
types: [created, edited, deleted]
|
||||
|
||||
jobs:
|
||||
update-error-db:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.discussion.category.name == 'Errors'
|
||||
steps:
|
||||
- name: Query Discussion Data
|
||||
id: query-data
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
const query = `query ($owner: String!, $name: String!, $discussionNumber: Int!) {
|
||||
repository(owner: $owner, name: $name) {
|
||||
discussion(number: $discussionNumber) {
|
||||
id
|
||||
upvoteCount
|
||||
title
|
||||
url
|
||||
answer {
|
||||
url
|
||||
upvoteCount
|
||||
}
|
||||
comments {
|
||||
totalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
}`;
|
||||
const variables = {
|
||||
owner: context.repo.owner,
|
||||
name: context.repo.repo,
|
||||
discussionNumber: context.payload.discussion.number
|
||||
}
|
||||
return await github.graphql(query, variables)
|
||||
- name: Get Gist
|
||||
id: get-gist
|
||||
uses: andymckay/get-gist-action@master
|
||||
with:
|
||||
gistURL: https://gist.github.com/cryptobot/accba9fb9555e7192271b85606f97230
|
||||
- name: Merge Error Code Data
|
||||
run: |
|
||||
jq -c '.' ${{ steps.get-gist.outputs.file }} > original.json
|
||||
echo $DISCUSSION | jq -c '.repository.discussion | .comments = .comments.totalCount | {(.id|tostring) : .}' > new.json
|
||||
jq -s '.[0] * .[1]' original.json new.json > merged.json
|
||||
env:
|
||||
DISCUSSION: ${{ steps.query-data.outputs.result }}
|
||||
- name: Patch Gist
|
||||
uses: exuanbo/actions-deploy-gist@v1
|
||||
with:
|
||||
token: ${{ secrets.CRYPTOBOT_GIST_TOKEN }}
|
||||
gist_id: accba9fb9555e7192271b85606f97230
|
||||
gist_file_name: errorcodes.json
|
||||
file_path: merged.json
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
--verbose
|
||||
--output runtime
|
||||
--module-path "${JAVA_HOME}/jmods"
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr
|
||||
--add-modules java.base,java.desktop,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr
|
||||
--strip-native-commands
|
||||
--no-header-files
|
||||
--no-man-pages
|
||||
@@ -89,7 +89,6 @@ jobs:
|
||||
--java-options "-Dcryptomator.logDir=\"~/Library/Logs/Cryptomator\""
|
||||
--java-options "-Dcryptomator.pluginDir=\"~/Library/Application Support/Cryptomator/Plugins\""
|
||||
--java-options "-Dcryptomator.settingsPath=\"~/Library/Application Support/Cryptomator/settings.json\""
|
||||
--java-options "-Dcryptomator.p12Path=\"~/Library/Application Support/Cryptomator/key.p12\""
|
||||
--java-options "-Dcryptomator.ipcSocketPath=\"~/Library/Application Support/Cryptomator/ipc.socket\""
|
||||
--java-options "-Dcryptomator.integrationsMac.keychainServiceName=\"Cryptomator\""
|
||||
--java-options "-Dcryptomator.showTrayIcon=true"
|
||||
|
||||
@@ -8,14 +8,10 @@ on:
|
||||
version:
|
||||
description: 'Version'
|
||||
required: false
|
||||
winget-release:
|
||||
description: 'Release artifacts to winget'
|
||||
required: true
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
env:
|
||||
JAVA_VERSION: 17
|
||||
WINFSP_MSI: https://github.com/winfsp/winfsp/releases/download/v1.10/winfsp-1.10.22006.msi
|
||||
|
||||
defaults:
|
||||
run:
|
||||
@@ -69,7 +65,7 @@ jobs:
|
||||
--verbose
|
||||
--output runtime
|
||||
--module-path "${JAVA_HOME}/jmods"
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr
|
||||
--add-modules java.base,java.desktop,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr
|
||||
--strip-native-commands
|
||||
--no-header-files
|
||||
--no-man-pages
|
||||
@@ -96,13 +92,12 @@ jobs:
|
||||
--java-options "-Dcryptomator.logDir=\"~/AppData/Roaming/Cryptomator\""
|
||||
--java-options "-Dcryptomator.pluginDir=\"~/AppData/Roaming/Cryptomator/Plugins\""
|
||||
--java-options "-Dcryptomator.settingsPath=\"~/AppData/Roaming/Cryptomator/settings.json\""
|
||||
--java-options "-Dcryptomator.p12Path=\"~/AppData/Roaming/Cryptomator/key.p12\""
|
||||
--java-options "-Dcryptomator.ipcSocketPath=\"~/AppData/Roaming/Cryptomator/ipc.socket\""
|
||||
--java-options "-Dcryptomator.keychainPath=\"~/AppData/Roaming/Cryptomator/keychain.json\""
|
||||
--java-options "-Dcryptomator.mountPointsDir=\"~/Cryptomator\""
|
||||
--java-options "-Dcryptomator.showTrayIcon=true"
|
||||
--java-options "-Dcryptomator.buildNumber=\"msi-${{ steps.versions.outputs.revNum }}\""
|
||||
--java-options "-Dcryptomator.integrationsWin.autoStartShellLinkName=\"Cryptomator\""
|
||||
--java-options "-Dcryptomator.integrationsWin.keychainPaths=\"~/AppData/Roaming/Cryptomator/keychain.json\""
|
||||
--resource-dir dist/win/resources
|
||||
--icon dist/win/resources/Cryptomator.ico
|
||||
- name: Patch Application Directory
|
||||
@@ -116,7 +111,7 @@ jobs:
|
||||
with:
|
||||
certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
|
||||
password: ${{ secrets.WIN_CODESIGN_P12_PW }}
|
||||
certificatesha1: 5FC94CE149E5B511E621F53A060AC67CBD446B3A
|
||||
certificatesha1: FF52240075AD7D14AF25629FDF69635357C7D14B
|
||||
description: Cryptomator
|
||||
timestampUrl: 'http://timestamp.digicert.com'
|
||||
folder: appdir/Cryptomator
|
||||
@@ -159,7 +154,7 @@ jobs:
|
||||
with:
|
||||
certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
|
||||
password: ${{ secrets.WIN_CODESIGN_P12_PW }}
|
||||
certificatesha1: 5FC94CE149E5B511E621F53A060AC67CBD446B3A
|
||||
certificatesha1: FF52240075AD7D14AF25629FDF69635357C7D14B
|
||||
description: Cryptomator Installer
|
||||
timestampUrl: 'http://timestamp.digicert.com'
|
||||
folder: installer
|
||||
@@ -198,7 +193,6 @@ jobs:
|
||||
name: Publish on winget repo
|
||||
runs-on: windows-latest
|
||||
needs: [build-msi]
|
||||
if: github.event.action == 'release' || inputs.winget-release
|
||||
steps:
|
||||
- name: Submit package to Windows Package Manager Community Repository
|
||||
run: |
|
||||
@@ -238,10 +232,8 @@ jobs:
|
||||
"-Dlicense.licenseMergesUrl=file:///${{ github.workspace }}/license/merges"
|
||||
shell: pwsh
|
||||
- name: Download WinFsp
|
||||
run: |
|
||||
$winfspUrl= (Select-String -Path ".\dist\win\bundle\resources\winfsp-download.url" -Pattern 'https:.*').Matches.Value
|
||||
curl --output dist/win/bundle/resources/winfsp.msi -L $winfspUrl
|
||||
shell: pwsh
|
||||
run:
|
||||
curl --output dist/win/bundle/resources/winfsp.msi -L ${{ env.WINFSP_MSI }}
|
||||
- name: Compile to wixObj file
|
||||
run: >
|
||||
"${WIX}/bin/candle.exe" dist/win/bundle/bundleWithWinfsp.wxs
|
||||
@@ -268,7 +260,7 @@ jobs:
|
||||
with:
|
||||
certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
|
||||
password: ${{ secrets.WIN_CODESIGN_P12_PW }}
|
||||
certificatesha1: 5FC94CE149E5B511E621F53A060AC67CBD446B3A
|
||||
certificatesha1: FF52240075AD7D14AF25629FDF69635357C7D14B
|
||||
description: Cryptomator Installer
|
||||
timestampUrl: 'http://timestamp.digicert.com'
|
||||
folder: tmp
|
||||
@@ -282,7 +274,7 @@ jobs:
|
||||
with:
|
||||
certificate: ${{ secrets.WIN_CODESIGN_P12_BASE64 }}
|
||||
password: ${{ secrets.WIN_CODESIGN_P12_PW }}
|
||||
certificatesha1: 5FC94CE149E5B511E621F53A060AC67CBD446B3A
|
||||
certificatesha1: FF52240075AD7D14AF25629FDF69635357C7D14B
|
||||
description: Cryptomator Installer
|
||||
timestampUrl: 'http://timestamp.digicert.com'
|
||||
folder: installer
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="Cryptomator Linux" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="cryptomator" />
|
||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="~/.config/Cryptomator/settings.json" -Dcryptomator.p12Path="~/.config/Cryptomator/key.p12" -Dcryptomator.ipcSocketPath="~/.config/Cryptomator/ipc.socket" -Dcryptomator.logDir="~/.local/share/Cryptomator/logs" -Dcryptomator.pluginDir="~/.local/share/Cryptomator/plugins" -Dcryptomator.mountPointsDir="~/.local/share/Cryptomator/mnt" -Dcryptomator.showTrayIcon=true -Xss20m -Xmx512m" />
|
||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="~/.config/Cryptomator/settings.json" -Dcryptomator.ipcSocketPath="~/.config/Cryptomator/ipc.socket" -Dcryptomator.logDir="~/.local/share/Cryptomator/logs" -Dcryptomator.pluginDir="~/.local/share/Cryptomator/plugins" -Dcryptomator.mountPointsDir="~/.local/share/Cryptomator/mnt" -Dcryptomator.showTrayIcon=true -Xss20m -Xmx512m" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="Cryptomator Linux Dev" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="cryptomator" />
|
||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="~/.config/Cryptomator-Dev/settings.json" -Dcryptomator.p12Path="~/.config/Cryptomator-Dev/key.p12" -Dcryptomator.ipcSocketPath="~/.config/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="~/.local/share/Cryptomator-Dev/logs" -Dcryptomator.pluginDir="~/.local/share/Cryptomator-Dev/plugins" -Dcryptomator.mountPointsDir="~/.local/share/Cryptomator-Dev/mnt" -Dcryptomator.showTrayIcon=true -Dfuse.experimental="true" -Xss20m -Xmx512m" />
|
||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="~/.config/Cryptomator-Dev/settings.json" -Dcryptomator.ipcSocketPath="~/.config/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="~/.local/share/Cryptomator-Dev/logs" -Dcryptomator.pluginDir="~/.local/share/Cryptomator-Dev/plugins" -Dcryptomator.mountPointsDir="~/.local/share/Cryptomator-Dev/mnt" -Dcryptomator.showTrayIcon=true -Dfuse.experimental="true" -Xss20m -Xmx512m" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="Cryptomator Windows" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="cryptomator" />
|
||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="~/AppData/Roaming/Cryptomator/settings.json" -Dcryptomator.ipcSocketPath="~/AppData/Roaming/Cryptomator/ipc.socket" -Dcryptomator.logDir="~/AppData/Roaming/Cryptomator" -Dcryptomator.pluginDir="~/AppData/Roaming/Cryptomator/Plugins" -Dcryptomator.integrationsWin.keychainPaths="~/AppData/Roaming/Cryptomator/keychain.json" -Dcryptomator.p12Path="~/AppData/Roaming/Cryptomator/key.p12" -Dcryptomator.mountPointsDir="~/Cryptomator" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m" />
|
||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="~/AppData/Roaming/Cryptomator/settings.json" -Dcryptomator.ipcSocketPath="~/AppData/Roaming/Cryptomator/ipc.socket" -Dcryptomator.logDir="~/AppData/Roaming/Cryptomator" -Dcryptomator.pluginDir="~/AppData/Roaming/Cryptomator/Plugins" -Dcryptomator.keychainPath="~/AppData/Roaming/Cryptomator/keychain.json" -Dcryptomator.mountPointsDir="~/Cryptomator" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
<configuration default="false" name="Cryptomator Windows Dev" type="Application" factoryName="Application">
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="cryptomator" />
|
||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="~/AppData/Roaming/Cryptomator-Dev/settings.json" -Dcryptomator.ipcSocketPath="~/AppData/Roaming/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="~/AppData/Roaming/Cryptomator-Dev" -Dcryptomator.pluginDir="~/AppData/Roaming/Cryptomator-Dev/Plugins" -Dcryptomator.integrationsWin.keychainPaths="~/AppData/Roaming/Cryptomator-Dev/keychain.json" -Dcryptomator.p12Path="~/AppData/Roaming/Cryptomator-Dev/key.p12" -Dcryptomator.mountPointsDir="~/Cryptomator-Dev" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m" />
|
||||
<option name="VM_PARAMETERS" value="-Dcryptomator.settingsPath="~/AppData/Roaming/Cryptomator-Dev/settings.json" -Dcryptomator.ipcSocketPath="~/AppData/Roaming/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="~/AppData/Roaming/Cryptomator-Dev" -Dcryptomator.pluginDir="~/AppData/Roaming/Cryptomator-Dev/Plugins" -Dcryptomator.keychainPath="~/AppData/Roaming/Cryptomator-Dev/keychain.json" -Dcryptomator.mountPointsDir="~/Cryptomator-Dev" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
</envs>
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="cryptomator" />
|
||||
<option name="VM_PARAMETERS" value="-Dapple.awt.enableTemplateImages=true -Dcryptomator.settingsPath="~/Library/Application Support/Cryptomator/settings.json" -Dcryptomator.p12Path="~/Library/Application Support/Cryptomator/key.p12" -Dcryptomator.ipcSocketPath="~/Library/Application Support/Cryptomator/ipc.socket" -Dcryptomator.logDir="~/Library/Logs/Cryptomator" -Dcryptomator.pluginDir="~/Library/Application Support/Cryptomator/Plugins" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m -ea" />
|
||||
<option name="VM_PARAMETERS" value="-Dapple.awt.enableTemplateImages=true -Dcryptomator.settingsPath="~/Library/Application Support/Cryptomator/settings.json" -Dcryptomator.ipcSocketPath="~/Library/Application Support/Cryptomator/ipc.socket" -Dcryptomator.logDir="~/Library/Logs/Cryptomator" -Dcryptomator.pluginDir="~/Library/Application Support/Cryptomator/Plugins" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m -ea" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
</envs>
|
||||
<option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
|
||||
<module name="cryptomator" />
|
||||
<option name="VM_PARAMETERS" value="-Dapple.awt.enableTemplateImages=true -Dcryptomator.settingsPath="~/Library/Application Support/Cryptomator-Dev/settings.json" -Dcryptomator.p12Path="~/Library/Application Support/Cryptomator-Dev/key.p12" -Dcryptomator.ipcSocketPath="~/Library/Application Support/Cryptomator-Dev/ipc.socket" -Dcryptomator.logDir="~/Library/Logs/Cryptomator-Dev" -Dcryptomator.pluginDir="~/Library/Application Support/Cryptomator-Dev/Plugins" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m -ea" />
|
||||
<option name="VM_PARAMETERS" value="-Dapple.awt.enableTemplateImages=true -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.pluginDir="~/Library/Application Support/Cryptomator-Dev/Plugins" -Dcryptomator.showTrayIcon=true -Xss2m -Xmx512m -ea" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
|
||||
Vendored
+1
-1
@@ -19,7 +19,7 @@ cp ../../../target/cryptomator-*.jar ../../../target/mods
|
||||
${JAVA_HOME}/bin/jlink \
|
||||
--output runtime \
|
||||
--module-path "${JAVA_HOME}/jmods" \
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr \
|
||||
--add-modules java.base,java.desktop,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr \
|
||||
--strip-native-commands \
|
||||
--no-header-files \
|
||||
--no-man-pages \
|
||||
|
||||
@@ -66,7 +66,6 @@
|
||||
</content_rating>
|
||||
|
||||
<releases>
|
||||
<release date="2022-07-26" version="1.6.11"/>
|
||||
<release date="2022-05-03" version="1.6.10"/>
|
||||
<release date="2022-04-27" version="1.6.9"/>
|
||||
<release date="2022-03-30" version="1.6.8"/>
|
||||
|
||||
Vendored
+1
-2
@@ -18,7 +18,7 @@ override_dh_auto_build:
|
||||
ln -s ../common/org.cryptomator.Cryptomator512.png resources/cryptomator.png
|
||||
jlink \
|
||||
--output runtime \
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr \
|
||||
--add-modules java.base,java.desktop,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr \
|
||||
--strip-native-commands \
|
||||
--no-header-files \
|
||||
--no-man-pages \
|
||||
@@ -40,7 +40,6 @@ override_dh_auto_build:
|
||||
--java-options "-Dcryptomator.logDir=\"~/.local/share/Cryptomator/logs\"" \
|
||||
--java-options "-Dcryptomator.pluginDir=\"~/.local/share/Cryptomator/plugins\"" \
|
||||
--java-options "-Dcryptomator.settingsPath=\"~/.config/Cryptomator/settings.json:~/.Cryptomator/settings.json\"" \
|
||||
--java-options "-Dcryptomator.p12Path=\"~/.config/Cryptomator/key.p12\""
|
||||
--java-options "-Dcryptomator.ipcSocketPath=\"~/.config/Cryptomator/ipc.socket\"" \
|
||||
--java-options "-Dcryptomator.mountPointsDir=\"~/.local/share/Cryptomator/mnt\"" \
|
||||
--java-options "-Dcryptomator.showTrayIcon=false" \
|
||||
|
||||
Vendored
+1
-2
@@ -45,7 +45,7 @@ cp ../../../target/${MAIN_JAR_GLOB} ../../../target/mods
|
||||
${JAVA_HOME}/bin/jlink \
|
||||
--output runtime \
|
||||
--module-path "${JAVA_HOME}/jmods" \
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr \
|
||||
--add-modules java.base,java.desktop,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr \
|
||||
--strip-native-commands \
|
||||
--no-header-files \
|
||||
--no-man-pages \
|
||||
@@ -75,7 +75,6 @@ ${JAVA_HOME}/bin/jpackage \
|
||||
--java-options "-Dcryptomator.pluginDir=\"~/Library/Application Support/${APP_NAME}/Plugins\"" \
|
||||
--java-options "-Dcryptomator.settingsPath=\"~/Library/Application Support/${APP_NAME}/settings.json\"" \
|
||||
--java-options "-Dcryptomator.ipcSocketPath=\"~/Library/Application Support/${APP_NAME}/ipc.socket\"" \
|
||||
--java-options "-Dcryptomator.p12Path=\"~/Library/Application Support/${APP_NAME}/key.p12\"" \
|
||||
--java-options "-Dcryptomator.integrationsMac.keychainServiceName=\"${APP_NAME}\"" \
|
||||
--java-options "-Dcryptomator.showTrayIcon=true" \
|
||||
--java-options "-Dcryptomator.buildNumber=\"dmg-${REVISION_NO}\"" \
|
||||
|
||||
Vendored
+3
-4
@@ -50,7 +50,7 @@ if ($clean -and (Test-Path -Path $runtimeImagePath)) {
|
||||
--verbose `
|
||||
--output runtime `
|
||||
--module-path "$Env:JAVA_HOME/jmods" `
|
||||
--add-modules java.base,java.desktop,java.instrument,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr `
|
||||
--add-modules java.base,java.desktop,java.logging,java.naming,java.net.http,java.scripting,java.sql,java.xml,jdk.unsupported,jdk.crypto.ec,jdk.accessibility,jdk.management.jfr `
|
||||
--strip-native-commands `
|
||||
--no-header-files `
|
||||
--no-man-pages `
|
||||
@@ -83,10 +83,9 @@ if ($clean -and (Test-Path -Path $appPath)) {
|
||||
--java-options "-Dcryptomator.pluginDir=`"~/AppData/Roaming/$AppName/Plugins`"" `
|
||||
--java-options "-Dcryptomator.settingsPath=`"~/AppData/Roaming/$AppName/settings.json`"" `
|
||||
--java-options "-Dcryptomator.ipcSocketPath=`"~/AppData/Roaming/$AppName/ipc.socket`"" `
|
||||
--java-options "-Dcryptomator.p12Path=`"~/AppData/Roaming/$AppName/key.p12`"" `
|
||||
--java-options "-Dcryptomator.keychainPath=`"~/AppData/Roaming/$AppName/keychain.json`"" `
|
||||
--java-options "-Dcryptomator.mountPointsDir=`"~/$AppName`"" `
|
||||
--java-options "-Dcryptomator.integrationsWin.autoStartShellLinkName=`"$AppName`"" `
|
||||
--java-options "-Dcryptomator.integrationsWin.keychainPaths=`"~/AppData/Roaming/$AppName/keychain.json`"" `
|
||||
--java-options "-Dcryptomator.showTrayIcon=true" `
|
||||
--java-options "-Dcryptomator.buildNumber=`"msi-$revisionNo`"" `
|
||||
--resource-dir resources `
|
||||
@@ -141,7 +140,7 @@ $Env:JP_WIXWIZARD_RESOURCES = "$buildDir\resources"
|
||||
# download Winfsp
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
$ProgressPreference = 'SilentlyContinue' # disables Invoke-WebRequest's progress bar, which slows down downloads to a few bytes/s
|
||||
$winfspMsiUrl= (Select-String -Path ".\bundle\resources\winfsp-download.url" -Pattern 'https:.*').Matches.Value
|
||||
$winfspMsiUrl = "https://github.com/winfsp/winfsp/releases/download/v1.10/winfsp-1.10.22006.msi"
|
||||
Write-Output "Downloading ${winfspMsiUrl}..."
|
||||
Invoke-WebRequest $winfspMsiUrl -OutFile ".\bundle\resources\winfsp.msi" # redirects are followed by default
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
[InternetShortcut]
|
||||
URL=https://github.com/winfsp/winfsp/releases/download/v1.11/winfsp-1.11.22176.msi
|
||||
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>cryptomator</artifactId>
|
||||
<version>1.6.11</version>
|
||||
<version>1.7.0-SNAPSHOT</version>
|
||||
<name>Cryptomator Desktop App</name>
|
||||
|
||||
<organization>
|
||||
@@ -27,29 +27,26 @@
|
||||
<nonModularGroupIds>com.github.serceman,com.github.jnr,org.ow2.asm,net.java.dev.jna,org.apache.jackrabbit,org.apache.httpcomponents,de.swiesend,org.purejava,com.github.hypfvieh</nonModularGroupIds>
|
||||
|
||||
<!-- cryptomator dependencies -->
|
||||
<cryptomator.cryptolib.version>2.1.0-beta3</cryptomator.cryptolib.version>
|
||||
<cryptomator.cryptofs.version>2.4.2</cryptomator.cryptofs.version>
|
||||
<cryptomator.integrations.version>1.1.0</cryptomator.integrations.version>
|
||||
<cryptomator.integrations.win.version>1.1.2</cryptomator.integrations.win.version>
|
||||
<cryptomator.integrations.win.version>1.1.1</cryptomator.integrations.win.version>
|
||||
<cryptomator.integrations.mac.version>1.1.1</cryptomator.integrations.mac.version>
|
||||
<cryptomator.integrations.linux.version>1.1.0</cryptomator.integrations.linux.version>
|
||||
<cryptomator.fuse.version>1.3.4</cryptomator.fuse.version>
|
||||
<cryptomator.dokany.version>1.3.3</cryptomator.dokany.version>
|
||||
<cryptomator.webdav.version>1.2.8</cryptomator.webdav.version>
|
||||
<cryptomator.webdav.version>1.2.7</cryptomator.webdav.version>
|
||||
|
||||
<!-- 3rd party dependencies -->
|
||||
<javafx.version>18.0.1</javafx.version>
|
||||
<commons-lang3.version>3.12.0</commons-lang3.version>
|
||||
<dagger.version>2.41</dagger.version>
|
||||
<jwt.version>3.19.1</jwt.version>
|
||||
<easybind.version>2.2</easybind.version>
|
||||
<guava.version>31.1-jre</guava.version>
|
||||
<dagger.version>2.41</dagger.version>
|
||||
<gson.version>2.9.0</gson.version>
|
||||
<javafx.version>18.0.1</javafx.version>
|
||||
<jwt.version>4.0.0</jwt.version>
|
||||
<nimbus-jose.version>9.23</nimbus-jose.version>
|
||||
<logback.version>1.2.11</logback.version>
|
||||
<slf4j.version>1.7.36</slf4j.version>
|
||||
<tinyoauth2.version>0.5.1</tinyoauth2.version>
|
||||
<zxcvbn.version>1.7.0</zxcvbn.version>
|
||||
<slf4j.version>1.7.36</slf4j.version>
|
||||
<logback.version>1.2.11</logback.version>
|
||||
|
||||
<!-- test dependencies -->
|
||||
<junit.jupiter.version>5.8.1</junit.jupiter.version>
|
||||
@@ -64,11 +61,6 @@
|
||||
|
||||
<dependencies>
|
||||
<!-- Cryptomator Libs -->
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>cryptolib</artifactId>
|
||||
<version>${cryptomator.cryptolib.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>cryptofs</artifactId>
|
||||
@@ -141,22 +133,12 @@
|
||||
<version>${commons-lang3.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- OAuth/JWT -->
|
||||
<dependency>
|
||||
<groupId>io.github.coffeelibs</groupId>
|
||||
<artifactId>tiny-oauth2-client</artifactId>
|
||||
<version>${tinyoauth2.version}</version>
|
||||
</dependency>
|
||||
<!-- JWT -->
|
||||
<dependency>
|
||||
<groupId>com.auth0</groupId>
|
||||
<artifactId>java-jwt</artifactId>
|
||||
<version>${jwt.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nimbusds</groupId>
|
||||
<artifactId>nimbus-jose-jwt</artifactId>
|
||||
<version>${nimbus-jose.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- EasyBind -->
|
||||
<dependency>
|
||||
|
||||
@@ -4,45 +4,35 @@ import org.cryptomator.ui.traymenu.AwtTrayMenuController;
|
||||
module org.cryptomator.desktop {
|
||||
requires static org.jetbrains.annotations;
|
||||
|
||||
requires org.cryptomator.cryptolib;
|
||||
|
||||
requires org.cryptomator.cryptofs;
|
||||
requires org.cryptomator.frontend.dokany;
|
||||
requires org.cryptomator.frontend.fuse;
|
||||
requires org.cryptomator.frontend.webdav;
|
||||
requires org.cryptomator.integrations.api;
|
||||
// jdk:
|
||||
requires java.desktop;
|
||||
requires java.net.http;
|
||||
requires javafx.base;
|
||||
requires javafx.graphics;
|
||||
requires javafx.controls;
|
||||
requires javafx.fxml;
|
||||
requires jdk.crypto.ec;
|
||||
// 3rd party:
|
||||
requires com.auth0.jwt;
|
||||
requires com.tobiasdiez.easybind;
|
||||
requires com.google.common;
|
||||
requires com.google.gson;
|
||||
requires com.nulabinc.zxcvbn;
|
||||
requires com.tobiasdiez.easybind;
|
||||
requires dagger;
|
||||
requires io.github.coffeelibs.tinyoauth2client;
|
||||
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;
|
||||
requires com.nimbusds.jose.jwt;
|
||||
|
||||
exports org.cryptomator.ui.traymenu to org.cryptomator.integrations.api;
|
||||
provides TrayMenuController with AwtTrayMenuController;
|
||||
|
||||
exports org.cryptomator.ui.keyloading.hub to com.fasterxml.jackson.databind;
|
||||
|
||||
opens org.cryptomator.common.settings to com.google.gson;
|
||||
opens org.cryptomator.ui.keyloading.hub to com.google.gson, javafx.fxml;
|
||||
|
||||
opens org.cryptomator.launcher to javafx.graphics;
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ public final class CatchingExecutors {
|
||||
callHandler(Thread.currentThread(), throwable);
|
||||
} else if (runnable instanceof Task<?> t) {
|
||||
afterExecuteTask(t);
|
||||
} else if (runnable instanceof Future<?> f) {
|
||||
} else if (runnable instanceof Future<?> f && f.isDone()) {
|
||||
afterExecuteFuture(f);
|
||||
}
|
||||
//Errors in this method are delegated to the UncaughtExceptionHandler of the current thread
|
||||
@@ -77,10 +77,11 @@ public final class CatchingExecutors {
|
||||
}
|
||||
|
||||
private static void afterExecuteFuture(Future<?> future) {
|
||||
assert future.isDone();
|
||||
try {
|
||||
future.get();
|
||||
} catch (CancellationException ce) {
|
||||
//Ignore
|
||||
callHandler(Thread.currentThread(), ce);
|
||||
} catch (ExecutionException ee) {
|
||||
callHandler(Thread.currentThread(), ee.getCause());
|
||||
} catch (InterruptedException ie) {
|
||||
|
||||
@@ -24,17 +24,6 @@ public class Environment {
|
||||
private static final Path RELATIVE_HOME_DIR = Paths.get("~");
|
||||
private static final char PATH_LIST_SEP = ':';
|
||||
private static final int DEFAULT_MIN_PW_LENGTH = 8;
|
||||
private static final String SETTINGS_PATH_PROP_NAME = "cryptomator.settingsPath";
|
||||
private static final String IPC_SOCKET_PATH_PROP_NAME = "cryptomator.ipcSocketPath";
|
||||
private static final String KEYCHAIN_PATHS_PROP_NAME = "cryptomator.integrationsWin.keychainPaths";
|
||||
private static final String P12_PATH_PROP_NAME = "cryptomator.p12Path";
|
||||
private static final String LOG_DIR_PROP_NAME = "cryptomator.logDir";
|
||||
private static final String MOUNTPOINT_DIR_PROP_NAME = "cryptomator.mountPointsDir";
|
||||
private static final String MIN_PW_LENGTH_PROP_NAME = "cryptomator.minPwLength";
|
||||
private static final String APP_VERSION_PROP_NAME = "cryptomator.appVersion";
|
||||
private static final String BUILD_NUMBER_PROP_NAME = "cryptomator.buildNumber";
|
||||
private static final String PLUGIN_DIR_PROP_NAME = "cryptomator.pluginDir";
|
||||
private static final String TRAY_ICON_PROP_NAME = "cryptomator.showTrayIcon";
|
||||
|
||||
@Inject
|
||||
public Environment() {
|
||||
@@ -43,17 +32,16 @@ public class Environment {
|
||||
LOG.debug("user.language: {}", System.getProperty("user.language"));
|
||||
LOG.debug("user.region: {}", System.getProperty("user.region"));
|
||||
LOG.debug("logback.configurationFile: {}", System.getProperty("logback.configurationFile"));
|
||||
LOG.debug("{}: {}", SETTINGS_PATH_PROP_NAME, System.getProperty(SETTINGS_PATH_PROP_NAME));
|
||||
LOG.debug("{}: {}", IPC_SOCKET_PATH_PROP_NAME, System.getProperty(IPC_SOCKET_PATH_PROP_NAME));
|
||||
LOG.debug("{}: {}", KEYCHAIN_PATHS_PROP_NAME, System.getProperty(KEYCHAIN_PATHS_PROP_NAME));
|
||||
LOG.debug("{}: {}", LOG_DIR_PROP_NAME, System.getProperty(LOG_DIR_PROP_NAME));
|
||||
LOG.debug("{}: {}", PLUGIN_DIR_PROP_NAME, System.getProperty(PLUGIN_DIR_PROP_NAME));
|
||||
LOG.debug("{}: {}", MOUNTPOINT_DIR_PROP_NAME, System.getProperty(MOUNTPOINT_DIR_PROP_NAME));
|
||||
LOG.debug("{}: {}", MIN_PW_LENGTH_PROP_NAME, System.getProperty(MIN_PW_LENGTH_PROP_NAME));
|
||||
LOG.debug("{}: {}", APP_VERSION_PROP_NAME, System.getProperty(APP_VERSION_PROP_NAME));
|
||||
LOG.debug("{}: {}", BUILD_NUMBER_PROP_NAME, System.getProperty(BUILD_NUMBER_PROP_NAME));
|
||||
LOG.debug("{}: {}", TRAY_ICON_PROP_NAME, System.getProperty(TRAY_ICON_PROP_NAME));
|
||||
LOG.debug("{}: {}", P12_PATH_PROP_NAME, System.getProperty(P12_PATH_PROP_NAME));
|
||||
LOG.debug("cryptomator.settingsPath: {}", System.getProperty("cryptomator.settingsPath"));
|
||||
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.pluginDir: {}", System.getProperty("cryptomator.pluginDir"));
|
||||
LOG.debug("cryptomator.mountPointsDir: {}", System.getProperty("cryptomator.mountPointsDir"));
|
||||
LOG.debug("cryptomator.minPwLength: {}", System.getProperty("cryptomator.minPwLength"));
|
||||
LOG.debug("cryptomator.appVersion: {}", System.getProperty("cryptomator.appVersion"));
|
||||
LOG.debug("cryptomator.buildNumber: {}", System.getProperty("cryptomator.buildNumber"));
|
||||
LOG.debug("cryptomator.showTrayIcon: {}", System.getProperty("cryptomator.showTrayIcon"));
|
||||
}
|
||||
|
||||
public boolean useCustomLogbackConfig() {
|
||||
@@ -61,47 +49,43 @@ public class Environment {
|
||||
}
|
||||
|
||||
public Stream<Path> getSettingsPath() {
|
||||
return getPaths(SETTINGS_PATH_PROP_NAME);
|
||||
}
|
||||
|
||||
public Stream<Path> getP12Path() {
|
||||
return getPaths(P12_PATH_PROP_NAME);
|
||||
return getPaths("cryptomator.settingsPath");
|
||||
}
|
||||
|
||||
public Stream<Path> ipcSocketPath() {
|
||||
return getPaths(IPC_SOCKET_PATH_PROP_NAME);
|
||||
return getPaths("cryptomator.ipcSocketPath");
|
||||
}
|
||||
|
||||
public Stream<Path> getKeychainPath() {
|
||||
return getPaths(KEYCHAIN_PATHS_PROP_NAME);
|
||||
return getPaths("cryptomator.keychainPath");
|
||||
}
|
||||
|
||||
public Optional<Path> getLogDir() {
|
||||
return getPath(LOG_DIR_PROP_NAME).map(this::replaceHomeDir);
|
||||
return getPath("cryptomator.logDir").map(this::replaceHomeDir);
|
||||
}
|
||||
|
||||
public Optional<Path> getPluginDir() {
|
||||
return getPath(PLUGIN_DIR_PROP_NAME).map(this::replaceHomeDir);
|
||||
return getPath("cryptomator.pluginDir").map(this::replaceHomeDir);
|
||||
}
|
||||
|
||||
public Optional<Path> getMountPointsDir() {
|
||||
return getPath(MOUNTPOINT_DIR_PROP_NAME).map(this::replaceHomeDir);
|
||||
return getPath("cryptomator.mountPointsDir").map(this::replaceHomeDir);
|
||||
}
|
||||
|
||||
public Optional<String> getAppVersion() {
|
||||
return Optional.ofNullable(System.getProperty(APP_VERSION_PROP_NAME));
|
||||
return Optional.ofNullable(System.getProperty("cryptomator.appVersion"));
|
||||
}
|
||||
|
||||
public Optional<String> getBuildNumber() {
|
||||
return Optional.ofNullable(System.getProperty(BUILD_NUMBER_PROP_NAME));
|
||||
return Optional.ofNullable(System.getProperty("cryptomator.buildNumber"));
|
||||
}
|
||||
|
||||
public int getMinPwLength() {
|
||||
return getInt(MIN_PW_LENGTH_PROP_NAME, DEFAULT_MIN_PW_LENGTH);
|
||||
return getInt("cryptomator.minPwLength", DEFAULT_MIN_PW_LENGTH);
|
||||
}
|
||||
|
||||
public boolean showTrayIcon() {
|
||||
return Boolean.getBoolean(TRAY_ICON_PROP_NAME);
|
||||
return Boolean.getBoolean("cryptomator.showTrayIcon");
|
||||
}
|
||||
|
||||
private int getInt(String propertyName, int defaultValue) {
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
package org.cryptomator.common.settings;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.cryptomator.common.keychain.KeychainManager;
|
||||
import org.cryptomator.cryptolib.common.P384KeyPair;
|
||||
import org.cryptomator.cryptolib.common.Pkcs12Exception;
|
||||
import org.cryptomator.integrations.keychain.KeychainAccessException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.io.IOException;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@Singleton
|
||||
public class DeviceKey {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DeviceKey.class);
|
||||
private static final String KEYCHAIN_KEY = "cryptomator-device-p12";
|
||||
|
||||
private final KeychainManager keychainManager;
|
||||
private final Environment env;
|
||||
private final SecureRandom csprng;
|
||||
private final Supplier<P384KeyPair> keyPairSupplier;
|
||||
|
||||
@Inject
|
||||
public DeviceKey(KeychainManager keychainManager, Environment env, SecureRandom csprng) {
|
||||
this.keychainManager = keychainManager;
|
||||
this.env = env;
|
||||
this.csprng = csprng;
|
||||
this.keyPairSupplier = Suppliers.memoize(this::loadOrCreate);
|
||||
}
|
||||
|
||||
public P384KeyPair get() throws DeviceKeyRetrievalException {
|
||||
Preconditions.checkState(keychainManager.isSupported());
|
||||
return keyPairSupplier.get();
|
||||
}
|
||||
|
||||
private P384KeyPair loadOrCreate() throws DeviceKeyRetrievalException {
|
||||
char[] passphrase = null;
|
||||
try {
|
||||
passphrase = keychainManager.loadPassphrase(KEYCHAIN_KEY);
|
||||
if (passphrase != null) {
|
||||
return loadExistingKeyPair(passphrase);
|
||||
} else {
|
||||
passphrase = randomPassword();
|
||||
keychainManager.storePassphrase(KEYCHAIN_KEY, CharBuffer.wrap(passphrase));
|
||||
return createAndStoreNewKeyPair(passphrase);
|
||||
}
|
||||
} catch (KeychainAccessException e) {
|
||||
throw new DeviceKeyRetrievalException("Failed to access system keychain", e);
|
||||
} catch (Pkcs12Exception | IOException e) {
|
||||
throw new DeviceKeyRetrievalException("Failed to access .p12 file", e);
|
||||
} finally {
|
||||
if (passphrase != null) {
|
||||
Arrays.fill(passphrase, '\0');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private P384KeyPair loadExistingKeyPair(char[] passphrase) throws IOException {
|
||||
var p12File = env.getP12Path() //
|
||||
.filter(Files::isRegularFile) //
|
||||
.findFirst() //
|
||||
.orElseThrow(() -> new DeviceKeyRetrievalException("Missing .p12 file"));
|
||||
LOG.debug("Loading existing device key from {}", p12File);
|
||||
return P384KeyPair.load(p12File, passphrase);
|
||||
}
|
||||
|
||||
private P384KeyPair createAndStoreNewKeyPair(char[] passphrase) throws IOException {
|
||||
var p12File = env.getP12Path() //
|
||||
.findFirst() //
|
||||
.orElseThrow(() -> new DeviceKeyRetrievalException("No path for .p12 file configured"));
|
||||
var keyPair = P384KeyPair.generate();
|
||||
LOG.debug("Store new device key to {}", p12File);
|
||||
keyPair.store(p12File, passphrase);
|
||||
return keyPair;
|
||||
}
|
||||
|
||||
private char[] randomPassword() {
|
||||
// this is a fast & easy attempt to create a random string:
|
||||
var uuid = new UUID(csprng.nextLong(), csprng.nextLong());
|
||||
return uuid.toString().toCharArray();
|
||||
}
|
||||
|
||||
public static class DeviceKeyRetrievalException extends RuntimeException {
|
||||
private DeviceKeyRetrievalException(String message) {
|
||||
super(message);
|
||||
}
|
||||
private DeviceKeyRetrievalException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,7 +32,6 @@ public class Settings {
|
||||
public static final boolean DEFAULT_ASKED_FOR_UPDATE_CHECK = false;
|
||||
public static final boolean DEFAULT_CHECK_FOR_UPDATES = false;
|
||||
public static final boolean DEFAULT_START_HIDDEN = false;
|
||||
public static final boolean DEFAULT_AUTO_CLOSE_VAULTS = false;
|
||||
public static final int DEFAULT_PORT = 42427;
|
||||
public static final int DEFAULT_NUM_TRAY_NOTIFICATIONS = 3;
|
||||
public static final WebDavUrlScheme DEFAULT_GVFS_SCHEME = WebDavUrlScheme.DAV;
|
||||
@@ -52,7 +51,6 @@ public class Settings {
|
||||
private final BooleanProperty askedForUpdateCheck = new SimpleBooleanProperty(DEFAULT_ASKED_FOR_UPDATE_CHECK);
|
||||
private final BooleanProperty checkForUpdates = new SimpleBooleanProperty(DEFAULT_CHECK_FOR_UPDATES);
|
||||
private final BooleanProperty startHidden = new SimpleBooleanProperty(DEFAULT_START_HIDDEN);
|
||||
private final BooleanProperty autoCloseVaults = new SimpleBooleanProperty(DEFAULT_AUTO_CLOSE_VAULTS);
|
||||
private final IntegerProperty port = new SimpleIntegerProperty(DEFAULT_PORT);
|
||||
private final IntegerProperty numTrayNotifications = new SimpleIntegerProperty(DEFAULT_NUM_TRAY_NOTIFICATIONS);
|
||||
private final ObjectProperty<WebDavUrlScheme> preferredGvfsScheme = new SimpleObjectProperty<>(DEFAULT_GVFS_SCHEME);
|
||||
@@ -84,7 +82,6 @@ public class Settings {
|
||||
askedForUpdateCheck.addListener(this::somethingChanged);
|
||||
checkForUpdates.addListener(this::somethingChanged);
|
||||
startHidden.addListener(this::somethingChanged);
|
||||
autoCloseVaults.addListener(this::somethingChanged);
|
||||
port.addListener(this::somethingChanged);
|
||||
numTrayNotifications.addListener(this::somethingChanged);
|
||||
preferredGvfsScheme.addListener(this::somethingChanged);
|
||||
@@ -136,10 +133,6 @@ public class Settings {
|
||||
return startHidden;
|
||||
}
|
||||
|
||||
public BooleanProperty autoCloseVaults() {
|
||||
return autoCloseVaults;
|
||||
}
|
||||
|
||||
public IntegerProperty port() {
|
||||
return port;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,6 @@ public class SettingsJsonAdapter extends TypeAdapter<Settings> {
|
||||
out.name("askedForUpdateCheck").value(value.askedForUpdateCheck().get());
|
||||
out.name("checkForUpdatesEnabled").value(value.checkForUpdates().get());
|
||||
out.name("startHidden").value(value.startHidden().get());
|
||||
out.name("autoCloseVaults").value(value.autoCloseVaults().get());
|
||||
out.name("port").value(value.port().get());
|
||||
out.name("numTrayNotifications").value(value.numTrayNotifications().get());
|
||||
out.name("preferredGvfsScheme").value(value.preferredGvfsScheme().get().name());
|
||||
@@ -83,7 +82,6 @@ public class SettingsJsonAdapter extends TypeAdapter<Settings> {
|
||||
case "askedForUpdateCheck" -> settings.askedForUpdateCheck().set(in.nextBoolean());
|
||||
case "checkForUpdatesEnabled" -> settings.checkForUpdates().set(in.nextBoolean());
|
||||
case "startHidden" -> settings.startHidden().set(in.nextBoolean());
|
||||
case "autoCloseVaults" -> settings.autoCloseVaults().set(in.nextBoolean());
|
||||
case "port" -> settings.port().set(in.nextInt());
|
||||
case "numTrayNotifications" -> settings.numTrayNotifications().set(in.nextInt());
|
||||
case "preferredGvfsScheme" -> settings.preferredGvfsScheme().set(parseWebDavUrlSchemePrefix(in.nextString()));
|
||||
|
||||
@@ -49,12 +49,14 @@ public class SettingsProvider implements Supplier<Settings> {
|
||||
|
||||
private final AtomicReference<ScheduledFuture<?>> scheduledSaveCmd = new AtomicReference<>();
|
||||
private final Supplier<Settings> settings = Suppliers.memoize(this::load);
|
||||
private final SettingsJsonAdapter settingsJsonAdapter;
|
||||
private final Environment env;
|
||||
private final ScheduledExecutorService scheduler;
|
||||
private final Gson gson;
|
||||
|
||||
@Inject
|
||||
public SettingsProvider(SettingsJsonAdapter settingsJsonAdapter, Environment env, ScheduledExecutorService scheduler) {
|
||||
this.settingsJsonAdapter = settingsJsonAdapter;
|
||||
this.env = env;
|
||||
this.scheduler = scheduler;
|
||||
this.gson = new GsonBuilder() //
|
||||
@@ -116,7 +118,7 @@ public class SettingsProvider implements Supplier<Settings> {
|
||||
try {
|
||||
Files.createDirectories(settingsPath.getParent());
|
||||
Path tmpPath = settingsPath.resolveSibling(settingsPath.getFileName().toString() + ".tmp");
|
||||
try (OutputStream out = Files.newOutputStream(tmpPath, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE); //
|
||||
try (OutputStream out = Files.newOutputStream(tmpPath, StandardOpenOption.CREATE_NEW); //
|
||||
Writer writer = new OutputStreamWriter(out, StandardCharsets.UTF_8)) {
|
||||
gson.toJson(settings, writer);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import javax.inject.Named;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.BooleanBinding;
|
||||
import javafx.beans.binding.StringBinding;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.fxml.FXML;
|
||||
@@ -32,6 +33,8 @@ public class CreateNewVaultNameController implements FxController {
|
||||
private final ObjectProperty<Path> vaultPath;
|
||||
private final StringProperty vaultName;
|
||||
private final BooleanBinding validVaultName;
|
||||
private final BooleanBinding invalidVaultName;
|
||||
private final StringBinding warningText;
|
||||
|
||||
@Inject
|
||||
CreateNewVaultNameController(@AddVaultWizardWindow Stage window, @FxmlScene(FxmlFile.ADDVAULT_WELCOME) Lazy<Scene> welcomeScene, @FxmlScene(FxmlFile.ADDVAULT_NEW_LOCATION) Lazy<Scene> chooseLocationScene, ObjectProperty<Path> vaultPath, @Named("vaultName") StringProperty vaultName, ResourceBundle resourceBundle) {
|
||||
@@ -40,7 +43,9 @@ public class CreateNewVaultNameController implements FxController {
|
||||
this.chooseLocationScene = chooseLocationScene;
|
||||
this.vaultPath = vaultPath;
|
||||
this.vaultName = vaultName;
|
||||
this.validVaultName = Bindings.createBooleanBinding(this::isValidVaultNameInternal, vaultName);
|
||||
this.validVaultName = Bindings.createBooleanBinding(this::isValidVaultName, vaultName);
|
||||
this.invalidVaultName = validVaultName.not();
|
||||
this.warningText = Bindings.when(vaultName.isNotEmpty().and(invalidVaultName)).then(resourceBundle.getString("addvaultwizard.new.invalidName")).otherwise((String) null);
|
||||
}
|
||||
|
||||
@FXML
|
||||
@@ -49,7 +54,7 @@ public class CreateNewVaultNameController implements FxController {
|
||||
vaultName.addListener(this::vaultNameChanged);
|
||||
}
|
||||
|
||||
private boolean isValidVaultNameInternal() {
|
||||
public boolean isValidVaultName() {
|
||||
return vaultName.get() != null && VALID_NAME_PATTERN.matcher(vaultName.get().trim()).matches();
|
||||
}
|
||||
|
||||
@@ -74,12 +79,28 @@ public class CreateNewVaultNameController implements FxController {
|
||||
|
||||
/* Getter/Setter */
|
||||
|
||||
public BooleanBinding validVaultNameProperty() {
|
||||
return validVaultName;
|
||||
public BooleanBinding invalidVaultNameProperty() {
|
||||
return invalidVaultName;
|
||||
}
|
||||
|
||||
public boolean isValidVaultName() {
|
||||
return validVaultName.get();
|
||||
public boolean isInvalidVaultName() {
|
||||
return invalidVaultName.get();
|
||||
}
|
||||
|
||||
public StringBinding warningTextProperty() {
|
||||
return warningText;
|
||||
}
|
||||
|
||||
public String getWarningText() {
|
||||
return warningText.get();
|
||||
}
|
||||
|
||||
public BooleanBinding showWarningProperty() {
|
||||
return warningText.isNotEmpty();
|
||||
}
|
||||
|
||||
public boolean isShowWarning() {
|
||||
return showWarningProperty().get();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,12 +13,6 @@ public enum FxmlFile {
|
||||
FORGET_PASSWORD("/fxml/forget_password.fxml"), //
|
||||
HEALTH_START("/fxml/health_start.fxml"), //
|
||||
HEALTH_CHECK_LIST("/fxml/health_check_list.fxml"), //
|
||||
HUB_AUTH_FLOW("/fxml/hub_auth_flow.fxml"), //
|
||||
HUB_RECEIVE_KEY("/fxml/hub_receive_key.fxml"), //
|
||||
HUB_REGISTER_DEVICE("/fxml/hub_register_device.fxml"), //
|
||||
HUB_REGISTER_SUCCESS("/fxml/hub_register_success.fxml"), //
|
||||
HUB_REGISTER_FAILED("/fxml/hub_register_failed.fxml"),
|
||||
HUB_UNAUTHORIZED_DEVICE("/fxml/hub_unauthorized_device.fxml"), //
|
||||
LOCK_FORCED("/fxml/lock_forced.fxml"), //
|
||||
LOCK_FAILED("/fxml/lock_failed.fxml"), //
|
||||
MAIN_WINDOW("/fxml/main_window.fxml"), //
|
||||
@@ -29,11 +23,9 @@ public enum FxmlFile {
|
||||
MIGRATION_SUCCESS("/fxml/migration_success.fxml"), //
|
||||
PREFERENCES("/fxml/preferences.fxml"), //
|
||||
QUIT("/fxml/quit.fxml"), //
|
||||
QUIT_FORCED("/fxml/quit_forced.fxml"), //
|
||||
RECOVERYKEY_CREATE("/fxml/recoverykey_create.fxml"), //
|
||||
RECOVERYKEY_RECOVER("/fxml/recoverykey_recover.fxml"), //
|
||||
RECOVERYKEY_RESET_PASSWORD("/fxml/recoverykey_reset_password.fxml"), //
|
||||
RECOVERYKEY_RESET_PASSWORD_SUCCESS("/fxml/recoverykey_reset_password_success.fxml"), //
|
||||
RECOVERYKEY_SUCCESS("/fxml/recoverykey_success.fxml"), //
|
||||
REMOVE_VAULT("/fxml/remove_vault.fxml"), //
|
||||
UNLOCK_ENTER_PASSWORD("/fxml/unlock_enter_password.fxml"),
|
||||
|
||||
@@ -86,8 +86,7 @@ public class VaultService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a lock-all task.
|
||||
* This task itself is _not started_, but its subtasks locking each vault will be already executed.
|
||||
* Creates but doesn't start a lock-all task.
|
||||
*
|
||||
* @param vaults The list of vaults to be locked
|
||||
* @param forced Whether to attempt a forced lock
|
||||
|
||||
@@ -43,11 +43,9 @@ public class ForgetPasswordController implements FxController {
|
||||
LOG.debug("Forgot password for vault {}.", vault.getDisplayName());
|
||||
confirmedResult.setValue(true);
|
||||
} catch (KeychainAccessException e) {
|
||||
LOG.error("Failed to delete passphrase from system keychain.", e);
|
||||
LOG.error("Failed to remove entry from system keychain.", e);
|
||||
confirmedResult.setValue(false);
|
||||
}
|
||||
} else {
|
||||
LOG.warn("Keychain not supported. Doing nothing.");
|
||||
}
|
||||
window.close();
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ import org.cryptomator.common.vaults.Vault;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.collections.ObservableList;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
@FxApplicationScoped
|
||||
public class AutoUnlocker {
|
||||
@@ -20,11 +18,9 @@ public class AutoUnlocker {
|
||||
}
|
||||
|
||||
public void unlock() {
|
||||
vaults.stream().filter(Vault::isLocked) //
|
||||
.filter(v -> v.getVaultSettings().unlockAfterStartup().get()) //
|
||||
.<CompletionStage<Void>>reduce(CompletableFuture.completedFuture(null), //
|
||||
(unlockFlow, v) -> unlockFlow.handle((voit, ex) -> appWindows.startUnlockWorkflow(v, null)).thenCompose(stage -> stage), //we don't care here about the exception, logged elsewhere
|
||||
(unlockChain1, unlockChain2) -> unlockChain1.handle((voit, ex) -> unlockChain2).thenCompose(stage -> stage));
|
||||
vaults.stream().filter(Vault::isLocked).filter(v -> v.getVaultSettings().unlockAfterStartup().get()).forEach(v -> {
|
||||
appWindows.startUnlockWorkflow(v, null);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ import org.cryptomator.ui.lock.LockComponent;
|
||||
import org.cryptomator.ui.mainwindow.MainWindowComponent;
|
||||
import org.cryptomator.ui.preferences.PreferencesComponent;
|
||||
import org.cryptomator.ui.quit.QuitComponent;
|
||||
|
||||
import org.cryptomator.ui.traymenu.TrayMenuComponent;
|
||||
import org.cryptomator.ui.unlock.UnlockComponent;
|
||||
|
||||
@@ -58,4 +57,4 @@ abstract class FxApplicationModule {
|
||||
static QuitComponent provideQuitComponent(QuitComponent.Builder builder) {
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,10 @@ package org.cryptomator.ui.fxapp;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.cryptomator.common.ShutdownHook;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.common.vaults.LockNotCompletedException;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.common.vaults.VaultState;
|
||||
import org.cryptomator.common.vaults.Volume;
|
||||
import org.cryptomator.ui.common.VaultService;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -29,24 +27,18 @@ import static org.cryptomator.common.vaults.VaultState.Value.*;
|
||||
public class FxApplicationTerminator {
|
||||
|
||||
private static final Set<VaultState.Value> STATES_ALLOWING_TERMINATION = EnumSet.of(LOCKED, NEEDS_MIGRATION, MISSING, ERROR);
|
||||
private static final Set<VaultState.Value> STATES_PREVENT_TERMINATION = EnumSet.of(PROCESSING);
|
||||
private static final Logger LOG = LoggerFactory.getLogger(FxApplicationTerminator.class);
|
||||
|
||||
private final ObservableList<Vault> vaults;
|
||||
private final ShutdownHook shutdownHook;
|
||||
private final FxApplicationWindows appWindows;
|
||||
private final AtomicBoolean allowQuitWithoutPrompt = new AtomicBoolean();
|
||||
private final AtomicBoolean preventQuitWithGracefulLock = new AtomicBoolean();
|
||||
private final Settings settings;
|
||||
private final VaultService vaultService;
|
||||
|
||||
@Inject
|
||||
public FxApplicationTerminator(ObservableList<Vault> vaults, ShutdownHook shutdownHook, FxApplicationWindows appWindows, Settings settings, VaultService vaultService) {
|
||||
public FxApplicationTerminator(ObservableList<Vault> vaults, ShutdownHook shutdownHook, FxApplicationWindows appWindows) {
|
||||
this.vaults = vaults;
|
||||
this.shutdownHook = shutdownHook;
|
||||
this.appWindows = appWindows;
|
||||
this.settings = settings;
|
||||
this.vaultService = vaultService;
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
@@ -80,10 +72,6 @@ public class FxApplicationTerminator {
|
||||
private void vaultListChanged(@SuppressWarnings("unused") Observable observable) {
|
||||
boolean allowSuddenTermination = vaults.stream().map(Vault::getState).allMatch(STATES_ALLOWING_TERMINATION::contains);
|
||||
boolean stateChanged = allowQuitWithoutPrompt.compareAndSet(!allowSuddenTermination, allowSuddenTermination);
|
||||
|
||||
boolean preventGracefulTermination = vaults.stream().map(Vault::getState).anyMatch(STATES_PREVENT_TERMINATION::contains);
|
||||
preventQuitWithGracefulLock.set(preventGracefulTermination);
|
||||
|
||||
Desktop desktop = Desktop.getDesktop();
|
||||
if (stateChanged && desktop.isSupported(Desktop.Action.APP_SUDDEN_TERMINATION)) {
|
||||
if (allowSuddenTermination) {
|
||||
@@ -104,22 +92,10 @@ public class FxApplicationTerminator {
|
||||
*/
|
||||
private void handleQuitRequest(@SuppressWarnings("unused") @Nullable EventObject e, QuitResponse response) {
|
||||
var exitingResponse = new ExitingQuitResponse(response);
|
||||
|
||||
if (allowQuitWithoutPrompt.get()) {
|
||||
exitingResponse.performQuit();
|
||||
} else if (settings.autoCloseVaults().get() && !preventQuitWithGracefulLock.get()) {
|
||||
var lockAllTask = vaultService.createLockAllTask(vaults.filtered(Vault::isUnlocked), false);
|
||||
lockAllTask.setOnSucceeded(event -> {
|
||||
LOG.info("Locked remaining vaults was succesful.");
|
||||
exitingResponse.performQuit();
|
||||
});
|
||||
lockAllTask.setOnFailed(event -> {
|
||||
LOG.warn("Unable to lock all vaults.");
|
||||
appWindows.showQuitWindow(exitingResponse, true);
|
||||
});
|
||||
lockAllTask.run();
|
||||
} else {
|
||||
appWindows.showQuitWindow(exitingResponse, false);
|
||||
appWindows.showQuitWindow(exitingResponse);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +115,7 @@ public class FxApplicationTerminator {
|
||||
|
||||
/**
|
||||
* A dummy QuitResponse that ignores the response.
|
||||
* <p>
|
||||
*
|
||||
* To be used with {@link #handleQuitRequest(EventObject, QuitResponse)} if the invoking method is not interested in the response.
|
||||
*/
|
||||
private static class NoopQuitResponse implements QuitResponse {
|
||||
|
||||
@@ -40,7 +40,7 @@ public class FxApplicationWindows {
|
||||
private final Optional<TrayIntegrationProvider> trayIntegration;
|
||||
private final Lazy<MainWindowComponent> mainWindow;
|
||||
private final Lazy<PreferencesComponent> preferencesWindow;
|
||||
private final QuitComponent.Builder quitWindowBuilder;
|
||||
private final Lazy<QuitComponent> quitWindow;
|
||||
private final UnlockComponent.Factory unlockWorkflowFactory;
|
||||
private final LockComponent.Factory lockWorkflowFactory;
|
||||
private final ErrorComponent.Factory errorWindowFactory;
|
||||
@@ -48,12 +48,12 @@ public class FxApplicationWindows {
|
||||
private final FilteredList<Window> visibleWindows;
|
||||
|
||||
@Inject
|
||||
public FxApplicationWindows(@PrimaryStage Stage primaryStage, Optional<TrayIntegrationProvider> trayIntegration, Lazy<MainWindowComponent> mainWindow, Lazy<PreferencesComponent> preferencesWindow, QuitComponent.Builder quitWindowBuilder, UnlockComponent.Factory unlockWorkflowFactory, LockComponent.Factory lockWorkflowFactory, ErrorComponent.Factory errorWindowFactory, ExecutorService executor) {
|
||||
public FxApplicationWindows(@PrimaryStage Stage primaryStage, Optional<TrayIntegrationProvider> trayIntegration, Lazy<MainWindowComponent> mainWindow, Lazy<PreferencesComponent> preferencesWindow, Lazy<QuitComponent> quitWindow, UnlockComponent.Factory unlockWorkflowFactory, LockComponent.Factory lockWorkflowFactory, ErrorComponent.Factory errorWindowFactory, ExecutorService executor) {
|
||||
this.primaryStage = primaryStage;
|
||||
this.trayIntegration = trayIntegration;
|
||||
this.mainWindow = mainWindow;
|
||||
this.preferencesWindow = preferencesWindow;
|
||||
this.quitWindowBuilder = quitWindowBuilder;
|
||||
this.quitWindow = quitWindow;
|
||||
this.unlockWorkflowFactory = unlockWorkflowFactory;
|
||||
this.lockWorkflowFactory = lockWorkflowFactory;
|
||||
this.errorWindowFactory = errorWindowFactory;
|
||||
@@ -104,8 +104,8 @@ public class FxApplicationWindows {
|
||||
return CompletableFuture.supplyAsync(() -> preferencesWindow.get().showPreferencesWindow(selectedTab), Platform::runLater).whenComplete(this::reportErrors);
|
||||
}
|
||||
|
||||
public void showQuitWindow(QuitResponse response, boolean forced) {
|
||||
CompletableFuture.runAsync(() -> quitWindowBuilder.build().showQuitWindow(response,forced), Platform::runLater);
|
||||
public CompletionStage<Stage> showQuitWindow(QuitResponse response) {
|
||||
return CompletableFuture.supplyAsync(() -> quitWindow.get().showQuitWindow(response), Platform::runLater).whenComplete(this::reportErrors);
|
||||
}
|
||||
|
||||
public CompletionStage<Void> startUnlockWorkflow(Vault vault, @Nullable Stage owner) {
|
||||
|
||||
@@ -6,7 +6,6 @@ import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.keyloading.hub.HubKeyLoadingModule;
|
||||
import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingModule;
|
||||
|
||||
import javax.inject.Provider;
|
||||
@@ -14,7 +13,7 @@ import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
@Module(includes = {MasterkeyFileLoadingModule.class, HubKeyLoadingModule.class})
|
||||
@Module(includes = {MasterkeyFileLoadingModule.class})
|
||||
abstract class KeyLoadingModule {
|
||||
|
||||
@Provides
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
package org.cryptomator.ui.keyloading.hub;
|
||||
|
||||
record AuthFlowContext(String deviceId) {
|
||||
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
package org.cryptomator.ui.keyloading.hub;
|
||||
|
||||
import com.nimbusds.jose.JWEObject;
|
||||
import dagger.Lazy;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.keyloading.KeyLoading;
|
||||
import org.cryptomator.ui.keyloading.KeyLoadingScoped;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.StringBinding;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.concurrent.WorkerStateEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.WindowEvent;
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@KeyLoadingScoped
|
||||
public class AuthFlowController implements FxController {
|
||||
|
||||
private final Application application;
|
||||
private final Stage window;
|
||||
private final ExecutorService executor;
|
||||
private final String deviceId;
|
||||
private final HubConfig hubConfig;
|
||||
private final AtomicReference<String> tokenRef;
|
||||
private final CompletableFuture<JWEObject> result;
|
||||
private final Lazy<Scene> receiveKeyScene;
|
||||
private final ObjectProperty<URI> authUri;
|
||||
private AuthFlowTask task;
|
||||
|
||||
@Inject
|
||||
public AuthFlowController(Application application, @KeyLoading Stage window, ExecutorService executor, @Named("deviceId") String deviceId, HubConfig hubConfig, @Named("bearerToken") AtomicReference<String> tokenRef, CompletableFuture<JWEObject> result, @FxmlScene(FxmlFile.HUB_RECEIVE_KEY) Lazy<Scene> receiveKeyScene) {
|
||||
this.application = application;
|
||||
this.window = window;
|
||||
this.executor = executor;
|
||||
this.deviceId = deviceId;
|
||||
this.hubConfig = hubConfig;
|
||||
this.tokenRef = tokenRef;
|
||||
this.result = result;
|
||||
this.receiveKeyScene = receiveKeyScene;
|
||||
this.authUri = new SimpleObjectProperty<>();
|
||||
this.window.addEventHandler(WindowEvent.WINDOW_HIDING, this::windowClosed);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
assert task == null;
|
||||
task = new AuthFlowTask(hubConfig, new AuthFlowContext(deviceId), this::setAuthUri);
|
||||
task.setOnFailed(this::authFailed);
|
||||
task.setOnSucceeded(this::authSucceeded);
|
||||
executor.submit(task);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void browse() {
|
||||
application.getHostServices().showDocument(authUri.get().toString());
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void cancel() {
|
||||
window.close();
|
||||
}
|
||||
|
||||
private void setAuthUri(URI uri) {
|
||||
Platform.runLater(() -> {
|
||||
authUri.set(uri);
|
||||
browse();
|
||||
});
|
||||
}
|
||||
|
||||
private void windowClosed(WindowEvent windowEvent) {
|
||||
// stop server, if it is still running
|
||||
task.cancel();
|
||||
result.cancel(true);
|
||||
}
|
||||
|
||||
private void authSucceeded(WorkerStateEvent workerStateEvent) {
|
||||
tokenRef.set(task.getValue());
|
||||
window.requestFocus();
|
||||
window.setScene(receiveKeyScene.get());
|
||||
}
|
||||
|
||||
private void authFailed(WorkerStateEvent workerStateEvent) {
|
||||
window.requestFocus();
|
||||
var exception = workerStateEvent.getSource().getException();
|
||||
result.completeExceptionally(exception);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package org.cryptomator.ui.keyloading.hub;
|
||||
|
||||
import com.google.gson.JsonParser;
|
||||
import io.github.coffeelibs.tinyoauth2client.AuthFlow;
|
||||
import io.github.coffeelibs.tinyoauth2client.TinyOAuth2;
|
||||
import io.github.coffeelibs.tinyoauth2client.http.response.Response;
|
||||
|
||||
import javafx.concurrent.Task;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
class AuthFlowTask extends Task<String> {
|
||||
|
||||
private final HubConfig hubConfig;
|
||||
private final AuthFlowContext authFlowContext;
|
||||
private final Consumer<URI> redirectUriConsumer;
|
||||
|
||||
/**
|
||||
* Spawns a server and waits for the redirectUri to be called.
|
||||
*
|
||||
* @param hubConfig Configuration object holding parameters required by {@link AuthFlow}
|
||||
* @param redirectUriConsumer A callback invoked with the redirectUri, as soon as the server has started
|
||||
*/
|
||||
public AuthFlowTask(HubConfig hubConfig, AuthFlowContext authFlowContext, Consumer<URI> redirectUriConsumer) {
|
||||
this.hubConfig = hubConfig;
|
||||
this.authFlowContext = authFlowContext;
|
||||
this.redirectUriConsumer = redirectUriConsumer;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String call() throws IOException, InterruptedException {
|
||||
var response = TinyOAuth2.client(hubConfig.clientId) //
|
||||
.withTokenEndpoint(URI.create(hubConfig.tokenEndpoint)) //
|
||||
.authFlow(URI.create(hubConfig.authEndpoint)) //
|
||||
.setSuccessResponse(Response.redirect(URI.create(hubConfig.authSuccessUrl + "&device=" + authFlowContext.deviceId()))) //
|
||||
.setErrorResponse(Response.redirect(URI.create(hubConfig.authErrorUrl + "&device=" + authFlowContext.deviceId()))) //
|
||||
.authorize(redirectUriConsumer);
|
||||
if (response.statusCode() != 200) {
|
||||
throw new NotOkResponseException("Authorization returned status code " + response.statusCode());
|
||||
}
|
||||
var json = JsonParser.parseString(response.body());
|
||||
return json.getAsJsonObject().get("access_token").getAsString();
|
||||
}
|
||||
|
||||
public static class NotOkResponseException extends RuntimeException {
|
||||
|
||||
NotOkResponseException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package org.cryptomator.ui.keyloading.hub;
|
||||
|
||||
class CreateDeviceDto {
|
||||
|
||||
public String id;
|
||||
public String name;
|
||||
public String publicKey;
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package org.cryptomator.ui.keyloading.hub;
|
||||
|
||||
import com.google.common.io.CharStreams;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
class HttpHelper {
|
||||
|
||||
public static String readBody(HttpResponse<InputStream> response) throws IOException {
|
||||
try (var in = response.body(); var reader = new InputStreamReader(in, StandardCharsets.UTF_8)) {
|
||||
return CharStreams.toString(reader);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package org.cryptomator.ui.keyloading.hub;
|
||||
|
||||
// needs to be accessible by JSON decoder
|
||||
public class HubConfig {
|
||||
|
||||
public String clientId;
|
||||
public String authEndpoint;
|
||||
public String tokenEndpoint;
|
||||
public String devicesResourceUrl;
|
||||
public String authSuccessUrl;
|
||||
public String authErrorUrl;
|
||||
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
package org.cryptomator.ui.keyloading.hub;
|
||||
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import com.nimbusds.jose.JWEObject;
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import dagger.multibindings.StringKey;
|
||||
import org.cryptomator.common.settings.DeviceKey;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.cryptolib.common.MessageDigestSupplier;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.common.NewPasswordController;
|
||||
import org.cryptomator.ui.common.PasswordStrengthUtil;
|
||||
import org.cryptomator.ui.keyloading.KeyLoading;
|
||||
import org.cryptomator.ui.keyloading.KeyLoadingScoped;
|
||||
import org.cryptomator.ui.keyloading.KeyLoadingStrategy;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javafx.scene.Scene;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.Objects;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@Module
|
||||
public abstract class HubKeyLoadingModule {
|
||||
|
||||
@Provides
|
||||
@KeyLoadingScoped
|
||||
static HubConfig provideHubConfig(@KeyLoading Vault vault) {
|
||||
try {
|
||||
return vault.getVaultConfigCache().get().getHeader("hub", HubConfig.class);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Provides
|
||||
@KeyLoadingScoped
|
||||
@Named("windowTitle")
|
||||
static String provideWindowTitle(@KeyLoading Vault vault, ResourceBundle resourceBundle) {
|
||||
return String.format(resourceBundle.getString("unlock.title"), vault.getDisplayName());
|
||||
}
|
||||
|
||||
|
||||
@Provides
|
||||
@KeyLoadingScoped
|
||||
@Named("deviceId")
|
||||
static String provideDeviceId(DeviceKey deviceKey) {
|
||||
var publicKey = Objects.requireNonNull(deviceKey.get()).getPublic().getEncoded();
|
||||
var hashedKey = MessageDigestSupplier.SHA256.get().digest(publicKey);
|
||||
return BaseEncoding.base16().encode(hashedKey);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Named("bearerToken")
|
||||
@KeyLoadingScoped
|
||||
static AtomicReference<String> provideBearerTokenRef() {
|
||||
return new AtomicReference<>();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@KeyLoadingScoped
|
||||
static CompletableFuture<JWEObject> provideResult() {
|
||||
return new CompletableFuture<>();
|
||||
}
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@KeyLoadingScoped
|
||||
@StringKey(HubKeyLoadingStrategy.SCHEME_HUB_HTTP)
|
||||
abstract KeyLoadingStrategy bindHubKeyLoadingStrategyToHubHttp(HubKeyLoadingStrategy strategy);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@KeyLoadingScoped
|
||||
@StringKey(HubKeyLoadingStrategy.SCHEME_HUB_HTTPS)
|
||||
abstract KeyLoadingStrategy bindHubKeyLoadingStrategyToHubHttps(HubKeyLoadingStrategy strategy);
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.HUB_AUTH_FLOW)
|
||||
@KeyLoadingScoped
|
||||
static Scene provideHubAuthFlowScene(@KeyLoading FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.HUB_AUTH_FLOW);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.HUB_RECEIVE_KEY)
|
||||
@KeyLoadingScoped
|
||||
static Scene provideHubReceiveKeyScene(@KeyLoading FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.HUB_RECEIVE_KEY);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.HUB_REGISTER_DEVICE)
|
||||
@KeyLoadingScoped
|
||||
static Scene provideHubRegisterDeviceScene(@KeyLoading FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.HUB_REGISTER_DEVICE);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.HUB_REGISTER_SUCCESS)
|
||||
@KeyLoadingScoped
|
||||
static Scene provideHubRegisterSuccessScene(@KeyLoading FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.HUB_REGISTER_SUCCESS);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.HUB_REGISTER_FAILED)
|
||||
@KeyLoadingScoped
|
||||
static Scene provideHubRegisterFailedScene(@KeyLoading FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.HUB_REGISTER_FAILED);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.HUB_UNAUTHORIZED_DEVICE)
|
||||
@KeyLoadingScoped
|
||||
static Scene provideHubUnauthorizedDeviceScene(@KeyLoading FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.HUB_UNAUTHORIZED_DEVICE);
|
||||
}
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(AuthFlowController.class)
|
||||
abstract FxController bindAuthFlowController(AuthFlowController controller);
|
||||
|
||||
@Provides
|
||||
@IntoMap
|
||||
@FxControllerKey(NewPasswordController.class)
|
||||
static FxController provideNewPasswordController(ResourceBundle resourceBundle, PasswordStrengthUtil strengthRater) {
|
||||
return new NewPasswordController(resourceBundle, strengthRater);
|
||||
}
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(ReceiveKeyController.class)
|
||||
abstract FxController bindReceiveKeyController(ReceiveKeyController controller);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(RegisterDeviceController.class)
|
||||
abstract FxController bindRegisterDeviceController(RegisterDeviceController controller);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(RegisterSuccessController.class)
|
||||
abstract FxController bindRegisterSuccessController(RegisterSuccessController controller);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(RegisterFailedController.class)
|
||||
abstract FxController bindRegisterFailedController(RegisterFailedController controller);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(UnauthorizedDeviceController.class)
|
||||
abstract FxController bindUnauthorizedDeviceController(UnauthorizedDeviceController controller);
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
package org.cryptomator.ui.keyloading.hub;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.nimbusds.jose.JWEObject;
|
||||
import dagger.Lazy;
|
||||
import org.cryptomator.common.settings.DeviceKey;
|
||||
import org.cryptomator.cryptolib.api.Masterkey;
|
||||
import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.keyloading.KeyLoading;
|
||||
import org.cryptomator.ui.keyloading.KeyLoadingStrategy;
|
||||
import org.cryptomator.ui.unlock.UnlockCancelledException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.Window;
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
@KeyLoading
|
||||
public class HubKeyLoadingStrategy implements KeyLoadingStrategy {
|
||||
|
||||
private static final String SCHEME_PREFIX = "hub+";
|
||||
static final String SCHEME_HUB_HTTP = SCHEME_PREFIX + "http";
|
||||
static final String SCHEME_HUB_HTTPS = SCHEME_PREFIX + "https";
|
||||
|
||||
private final Stage window;
|
||||
private final Lazy<Scene> authFlowScene;
|
||||
private final CompletableFuture<JWEObject> result;
|
||||
private final DeviceKey deviceKey;
|
||||
|
||||
@Inject
|
||||
public HubKeyLoadingStrategy(@KeyLoading Stage window, @FxmlScene(FxmlFile.HUB_AUTH_FLOW) Lazy<Scene> authFlowScene, CompletableFuture<JWEObject> result, DeviceKey deviceKey, @Named("windowTitle") String windowTitle) {
|
||||
this.window = window;
|
||||
window.setTitle(windowTitle);
|
||||
this.authFlowScene = authFlowScene;
|
||||
this.result = result;
|
||||
this.deviceKey = deviceKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Masterkey loadKey(URI keyId) throws MasterkeyLoadingFailedException {
|
||||
Preconditions.checkArgument(keyId.getScheme().startsWith(SCHEME_PREFIX));
|
||||
try {
|
||||
startAuthFlow();
|
||||
var jwe = result.get();
|
||||
return JWEHelper.decrypt(jwe, deviceKey.get().getPrivate());
|
||||
} catch (DeviceKey.DeviceKeyRetrievalException e) {
|
||||
throw new MasterkeyLoadingFailedException("Failed to load keypair", e);
|
||||
} catch (CancellationException e) {
|
||||
throw new UnlockCancelledException("User cancelled auth workflow", e);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new UnlockCancelledException("Loading interrupted", e);
|
||||
} catch (ExecutionException e) {
|
||||
throw new MasterkeyLoadingFailedException("Failed to retrieve key", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void startAuthFlow() {
|
||||
Platform.runLater(() -> {
|
||||
window.setScene(authFlowScene.get());
|
||||
window.show();
|
||||
Window owner = window.getOwner();
|
||||
if (owner != null) {
|
||||
window.setX(owner.getX() + (owner.getWidth() - window.getWidth()) / 2);
|
||||
window.setY(owner.getY() + (owner.getHeight() - window.getHeight()) / 2);
|
||||
} else {
|
||||
window.centerOnScreen();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package org.cryptomator.ui.keyloading.hub;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import com.nimbusds.jose.JOSEException;
|
||||
import com.nimbusds.jose.JWEObject;
|
||||
import com.nimbusds.jose.crypto.ECDHDecrypter;
|
||||
import org.cryptomator.cryptolib.api.Masterkey;
|
||||
import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.security.interfaces.ECPrivateKey;
|
||||
import java.util.Arrays;
|
||||
|
||||
class JWEHelper {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JWEHelper.class);
|
||||
private static final String JWE_PAYLOAD_MASTERKEY_FIELD = "key";
|
||||
|
||||
private JWEHelper(){}
|
||||
|
||||
public static Masterkey decrypt(JWEObject jwe, ECPrivateKey privateKey) throws MasterkeyLoadingFailedException {
|
||||
try {
|
||||
jwe.decrypt(new ECDHDecrypter(privateKey));
|
||||
return readKey(jwe);
|
||||
} catch (JOSEException e) {
|
||||
LOG.warn("Failed to decrypt JWE: {}", jwe);
|
||||
throw new MasterkeyLoadingFailedException("Failed to decrypt JWE", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static Masterkey readKey(JWEObject jwe) throws MasterkeyLoadingFailedException {
|
||||
Preconditions.checkArgument(jwe.getState() == JWEObject.State.DECRYPTED);
|
||||
var fields = jwe.getPayload().toJSONObject();
|
||||
if (fields == null) {
|
||||
LOG.error("Expected JWE payload to be JSON: {}", jwe.getPayload());
|
||||
throw new MasterkeyLoadingFailedException("Expected JWE payload to be JSON");
|
||||
}
|
||||
var keyBytes = new byte[0];
|
||||
try {
|
||||
if (fields.get(JWE_PAYLOAD_MASTERKEY_FIELD) instanceof String key) {
|
||||
keyBytes = BaseEncoding.base64().decode(key);
|
||||
return new Masterkey(keyBytes);
|
||||
} else {
|
||||
throw new IllegalArgumentException("JWE payload doesn't contain field " + JWE_PAYLOAD_MASTERKEY_FIELD);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.error("Unexpected JWE payload: {}", jwe.getPayload());
|
||||
throw new MasterkeyLoadingFailedException("Unexpected JWE payload", e);
|
||||
} finally {
|
||||
Arrays.fill(keyBytes, (byte) 0x00);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
package org.cryptomator.ui.keyloading.hub;
|
||||
|
||||
import com.nimbusds.jose.JWEObject;
|
||||
import dagger.Lazy;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.keyloading.KeyLoading;
|
||||
import org.cryptomator.ui.keyloading.KeyLoadingScoped;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javafx.application.Platform;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.WindowEvent;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.text.ParseException;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@KeyLoadingScoped
|
||||
public class ReceiveKeyController implements FxController {
|
||||
|
||||
private static final String SCHEME_PREFIX = "hub+";
|
||||
|
||||
private final Stage window;
|
||||
private final String deviceId;
|
||||
private final String bearerToken;
|
||||
private final CompletableFuture<JWEObject> result;
|
||||
private final Lazy<Scene> registerDeviceScene;
|
||||
private final Lazy<Scene> unauthorizedScene;
|
||||
private final URI vaultBaseUri;
|
||||
private final HttpClient httpClient;
|
||||
|
||||
@Inject
|
||||
public ReceiveKeyController(@KeyLoading Vault vault, ExecutorService executor, @KeyLoading Stage window, @Named("deviceId") String deviceId, @Named("bearerToken") AtomicReference<String> tokenRef, CompletableFuture<JWEObject> result, @FxmlScene(FxmlFile.HUB_REGISTER_DEVICE) Lazy<Scene> registerDeviceScene, @FxmlScene(FxmlFile.HUB_UNAUTHORIZED_DEVICE) Lazy<Scene> unauthorizedScene) {
|
||||
this.window = window;
|
||||
this.deviceId = deviceId;
|
||||
this.bearerToken = Objects.requireNonNull(tokenRef.get());
|
||||
this.result = result;
|
||||
this.registerDeviceScene = registerDeviceScene;
|
||||
this.unauthorizedScene = unauthorizedScene;
|
||||
this.vaultBaseUri = getVaultBaseUri(vault);
|
||||
this.window.addEventHandler(WindowEvent.WINDOW_HIDING, this::windowClosed);
|
||||
this.httpClient = HttpClient.newBuilder().executor(executor).build();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
var keyUri = appendPath(vaultBaseUri, "/keys/" + deviceId);
|
||||
var request = HttpRequest.newBuilder(keyUri) //
|
||||
.header("Authorization", "Bearer " + bearerToken) //
|
||||
.GET() //
|
||||
.build();
|
||||
httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofInputStream()) //
|
||||
.thenAcceptAsync(this::loadedExistingKey, Platform::runLater) //
|
||||
.exceptionally(this::retrievalFailed);
|
||||
}
|
||||
|
||||
private void loadedExistingKey(HttpResponse<InputStream> response) {
|
||||
try {
|
||||
switch (response.statusCode()) {
|
||||
case 200 -> retrievalSucceeded(response);
|
||||
case 403 -> accessNotGranted();
|
||||
case 404 -> needsDeviceRegistration();
|
||||
default -> throw new IOException("Unexpected response " + response.statusCode());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void retrievalSucceeded(HttpResponse<InputStream> response) throws IOException {
|
||||
try {
|
||||
var string = HttpHelper.readBody(response);
|
||||
result.complete(JWEObject.parse(string));
|
||||
window.close();
|
||||
} catch (ParseException e) {
|
||||
throw new IOException("Failed to parse JWE", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void needsDeviceRegistration() {
|
||||
window.setScene(registerDeviceScene.get());
|
||||
}
|
||||
|
||||
private void accessNotGranted() {
|
||||
window.setScene(unauthorizedScene.get());
|
||||
}
|
||||
|
||||
private Void retrievalFailed(Throwable cause) {
|
||||
result.completeExceptionally(cause);
|
||||
return null;
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void cancel() {
|
||||
window.close();
|
||||
}
|
||||
|
||||
private void windowClosed(WindowEvent windowEvent) {
|
||||
result.cancel(true);
|
||||
}
|
||||
|
||||
private static URI appendPath(URI base, String path) {
|
||||
try {
|
||||
var newPath = base.getPath() + path;
|
||||
return new URI(base.getScheme(), base.getAuthority(), newPath, base.getQuery(), base.getFragment());
|
||||
} catch (URISyntaxException e) {
|
||||
throw new IllegalArgumentException("Can't append '" + path + "' to URI: " + base, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static URI getVaultBaseUri(Vault vault) {
|
||||
try {
|
||||
var kid = vault.getVaultConfigCache().get().getKeyId();
|
||||
assert kid.getScheme().startsWith(SCHEME_PREFIX);
|
||||
var hubUriScheme = kid.getScheme().substring(SCHEME_PREFIX.length());
|
||||
return new URI(hubUriScheme, kid.getSchemeSpecificPart(), kid.getFragment());
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
} catch (URISyntaxException e) {
|
||||
throw new IllegalStateException("URI constructed from params known to be valid", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
package org.cryptomator.ui.keyloading.hub;
|
||||
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.nimbusds.jose.JWEObject;
|
||||
import dagger.Lazy;
|
||||
import org.cryptomator.common.settings.DeviceKey;
|
||||
import org.cryptomator.cryptolib.common.P384KeyPair;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.keyloading.KeyLoading;
|
||||
import org.cryptomator.ui.keyloading.KeyLoadingScoped;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ContentDisplay;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.WindowEvent;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@KeyLoadingScoped
|
||||
public class RegisterDeviceController implements FxController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(RegisterDeviceController.class);
|
||||
private static final Gson GSON = new GsonBuilder().setLenient().create();
|
||||
private static final List<Integer> EXPECTED_RESPONSE_CODES = List.of(201, 409);
|
||||
|
||||
private final Stage window;
|
||||
private final HubConfig hubConfig;
|
||||
private final String bearerToken;
|
||||
private final Lazy<Scene> registerSuccessScene;
|
||||
private final Lazy<Scene> registerFailedScene;
|
||||
private final String deviceId;
|
||||
private final P384KeyPair keyPair;
|
||||
private final CompletableFuture<JWEObject> result;
|
||||
private final DecodedJWT jwt;
|
||||
private final HttpClient httpClient;
|
||||
private final BooleanProperty deviceNameAlreadyExists = new SimpleBooleanProperty(false);
|
||||
|
||||
public TextField deviceNameField;
|
||||
public Button registerBtn;
|
||||
|
||||
@Inject
|
||||
public RegisterDeviceController(@KeyLoading Stage window, ExecutorService executor, HubConfig hubConfig, @Named("deviceId") String deviceId, DeviceKey deviceKey, CompletableFuture<JWEObject> result, @Named("bearerToken") AtomicReference<String> bearerToken, @FxmlScene(FxmlFile.HUB_REGISTER_SUCCESS) Lazy<Scene> registerSuccessScene, @FxmlScene(FxmlFile.HUB_REGISTER_FAILED) Lazy<Scene> registerFailedScene) {
|
||||
this.window = window;
|
||||
this.hubConfig = hubConfig;
|
||||
this.deviceId = deviceId;
|
||||
this.keyPair = Objects.requireNonNull(deviceKey.get());
|
||||
this.result = result;
|
||||
this.bearerToken = Objects.requireNonNull(bearerToken.get());
|
||||
this.registerSuccessScene = registerSuccessScene;
|
||||
this.registerFailedScene = registerFailedScene;
|
||||
this.jwt = JWT.decode(this.bearerToken);
|
||||
this.window.addEventHandler(WindowEvent.WINDOW_HIDING, this::windowClosed);
|
||||
this.httpClient = HttpClient.newBuilder().executor(executor).build();
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
deviceNameField.setText(determineHostname());
|
||||
deviceNameField.textProperty().addListener(observable -> deviceNameAlreadyExists.set(false));
|
||||
}
|
||||
|
||||
private String determineHostname() {
|
||||
try {
|
||||
var hostName = InetAddress.getLocalHost().getHostName();
|
||||
return Objects.requireNonNullElse(hostName, "");
|
||||
} catch (IOException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void register() {
|
||||
deviceNameAlreadyExists.set(false);
|
||||
registerBtn.setContentDisplay(ContentDisplay.LEFT);
|
||||
registerBtn.setDisable(true);
|
||||
|
||||
var keyUri = URI.create(hubConfig.devicesResourceUrl + deviceId);
|
||||
var deviceKey = keyPair.getPublic().getEncoded();
|
||||
var dto = new CreateDeviceDto();
|
||||
dto.id = deviceId;
|
||||
dto.name = deviceNameField.getText();
|
||||
dto.publicKey = BaseEncoding.base64Url().omitPadding().encode(deviceKey);
|
||||
var json = GSON.toJson(dto); // TODO: do we want to keep GSON? doesn't support records -.-
|
||||
var request = HttpRequest.newBuilder(keyUri) //
|
||||
.header("Authorization", "Bearer " + bearerToken) //
|
||||
.header("Content-Type", "application/json").PUT(HttpRequest.BodyPublishers.ofString(json, StandardCharsets.UTF_8)) //
|
||||
.build();
|
||||
httpClient.sendAsync(request, HttpResponse.BodyHandlers.discarding()) //
|
||||
.thenApply(response -> {
|
||||
if (EXPECTED_RESPONSE_CODES.contains(response.statusCode())) {
|
||||
return response;
|
||||
} else {
|
||||
throw new RuntimeException("Server answered with unexpected status code " + response.statusCode());
|
||||
}
|
||||
}).handleAsync((response, throwable) -> {
|
||||
if (response != null) {
|
||||
this.handleResponse(response);
|
||||
} else {
|
||||
this.registrationFailed(throwable);
|
||||
}
|
||||
return null;
|
||||
}, Platform::runLater);
|
||||
}
|
||||
|
||||
private void handleResponse(HttpResponse<Void> voidHttpResponse) {
|
||||
assert EXPECTED_RESPONSE_CODES.contains(voidHttpResponse.statusCode());
|
||||
|
||||
if (voidHttpResponse.statusCode() == 409) {
|
||||
deviceNameAlreadyExists.set(true);
|
||||
registerBtn.setContentDisplay(ContentDisplay.TEXT_ONLY);
|
||||
registerBtn.setDisable(false);
|
||||
} else {
|
||||
LOG.debug("Device registration for hub instance {} successful.", hubConfig.authSuccessUrl);
|
||||
window.setScene(registerSuccessScene.get());
|
||||
}
|
||||
}
|
||||
|
||||
private void registrationFailed(Throwable cause) {
|
||||
LOG.warn("Device registration failed.", cause);
|
||||
window.setScene(registerFailedScene.get());
|
||||
result.completeExceptionally(cause);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void close() {
|
||||
window.close();
|
||||
}
|
||||
|
||||
private void windowClosed(WindowEvent windowEvent) {
|
||||
result.cancel(true);
|
||||
}
|
||||
|
||||
/* Getter */
|
||||
|
||||
public String getUserName() {
|
||||
return jwt.getClaim("email").asString();
|
||||
}
|
||||
|
||||
|
||||
//--- Getters & Setters
|
||||
|
||||
public BooleanProperty deviceNameAlreadyExistsProperty() {
|
||||
return deviceNameAlreadyExists;
|
||||
}
|
||||
|
||||
public boolean getDeviceNameAlreadyExists() {
|
||||
return deviceNameAlreadyExists.get();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package org.cryptomator.ui.keyloading.hub;
|
||||
|
||||
import com.nimbusds.jose.JWEObject;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.keyloading.KeyLoading;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.stage.Stage;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class RegisterFailedController implements FxController {
|
||||
|
||||
private final Stage window;
|
||||
private final CompletableFuture<JWEObject> result;
|
||||
|
||||
@Inject
|
||||
public RegisterFailedController(@KeyLoading Stage window, CompletableFuture<JWEObject> result) {
|
||||
this.window = window;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void close() {
|
||||
window.close();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package org.cryptomator.ui.keyloading.hub;
|
||||
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.keyloading.KeyLoading;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
public class RegisterSuccessController implements FxController {
|
||||
|
||||
private final Stage window;
|
||||
|
||||
@Inject
|
||||
public RegisterSuccessController(@KeyLoading Stage window) {
|
||||
this.window = window;
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void close() {
|
||||
window.close();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package org.cryptomator.ui.keyloading.hub;
|
||||
|
||||
import com.nimbusds.jose.JWEObject;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.keyloading.KeyLoading;
|
||||
import org.cryptomator.ui.keyloading.KeyLoadingScoped;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.WindowEvent;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@KeyLoadingScoped
|
||||
public class UnauthorizedDeviceController implements FxController {
|
||||
|
||||
private final Stage window;
|
||||
private final CompletableFuture<JWEObject> result;
|
||||
|
||||
@Inject
|
||||
public UnauthorizedDeviceController(@KeyLoading Stage window, CompletableFuture<JWEObject> result) {
|
||||
this.window = window;
|
||||
this.result = result;
|
||||
this.window.addEventHandler(WindowEvent.WINDOW_HIDING, this::windowClosed);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void close() {
|
||||
window.close();
|
||||
}
|
||||
|
||||
private void windowClosed(WindowEvent windowEvent) {
|
||||
result.cancel(true);
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/**
|
||||
* This {@link org.cryptomator.ui.keyloading.KeyLoadingStrategy strategy} retrieves the vault key from a web application, similar to
|
||||
* <a href="https://datatracker.ietf.org/doc/html/rfc8252#section-7.3">RFC 8252</a> but with an encrypted masterkey instead of an authorization code.
|
||||
* <p>
|
||||
* If the <code>kid</code> of the vault config starts with either {@value org.cryptomator.ui.keyloading.hub.HubKeyLoadingStrategy#SCHEME_HUB_HTTP}
|
||||
* or {@value org.cryptomator.ui.keyloading.hub.HubKeyLoadingStrategy#SCHEME_HUB_HTTPS}, the included http address is amended by three parameters and opened
|
||||
* in a browser. These parameters are:
|
||||
* <ul>
|
||||
* <li>A device-specific public key (generated by this application and stored among its settings</li>
|
||||
* <li>A unique device ID (stored in settings)</li>
|
||||
* <li>A loopback callback address</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* The callback address points to a embedded web server waiting to receive the masterkey encrypted specifically for this device, using the device-specific public key.
|
||||
* <p>
|
||||
* The vault key can be decrypted using this ECIES:
|
||||
* <ol>
|
||||
* <li>Generate shared secret using ECDH without cofactor</li>
|
||||
* <li>Derive 44 bytes using ANSI X9.63 KDF with SHA256</li>
|
||||
* <li>Decrypt payload via AES-GCM, using first 32 bytes as key, last 12 bytes as IV</li>
|
||||
* <li>No MAC check required, as AES-GCM includes a tag already</li>
|
||||
* </ol>
|
||||
*/
|
||||
package org.cryptomator.ui.keyloading.hub;
|
||||
+1
-11
@@ -1,13 +1,11 @@
|
||||
package org.cryptomator.ui.keyloading.masterkeyfile;
|
||||
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.keyloading.KeyLoading;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.beans.binding.StringBinding;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.stage.FileChooser;
|
||||
import javafx.stage.Stage;
|
||||
@@ -25,14 +23,12 @@ public class ChooseMasterkeyFileController implements FxController {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ChooseMasterkeyFileController.class);
|
||||
|
||||
private final Stage window;
|
||||
private final Vault vault;
|
||||
private final CompletableFuture<Path> result;
|
||||
private final ResourceBundle resourceBundle;
|
||||
|
||||
@Inject
|
||||
public ChooseMasterkeyFileController(@KeyLoading Stage window, @KeyLoading Vault vault, CompletableFuture<Path> result, ResourceBundle resourceBundle) {
|
||||
public ChooseMasterkeyFileController(@KeyLoading Stage window, CompletableFuture<Path> result, ResourceBundle resourceBundle) {
|
||||
this.window = window;
|
||||
this.vault = vault;
|
||||
this.result = result;
|
||||
this.resourceBundle = resourceBundle;
|
||||
this.window.setOnHiding(this::windowClosed);
|
||||
@@ -60,10 +56,4 @@ public class ChooseMasterkeyFileController implements FxController {
|
||||
}
|
||||
}
|
||||
|
||||
//--- Setter & Getter ---
|
||||
|
||||
public String getDisplayName(){
|
||||
return vault.getDisplayName();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-1
@@ -61,7 +61,6 @@ public class MasterkeyFileLoadingStrategy implements KeyLoadingStrategy {
|
||||
|
||||
@Override
|
||||
public Masterkey loadKey(URI keyId) throws MasterkeyLoadingFailedException {
|
||||
window.setTitle(resourceBundle.getString("unlock.title").formatted(vault.getDisplayName()));
|
||||
Preconditions.checkArgument(SCHEME.equalsIgnoreCase(keyId.getScheme()), "Only supports keys with scheme " + SCHEME);
|
||||
try {
|
||||
Path filePath = vault.getPath().resolve(keyId.getSchemeSpecificPart());
|
||||
@@ -125,6 +124,7 @@ public class MasterkeyFileLoadingStrategy implements KeyLoadingStrategy {
|
||||
var comp = masterkeyFileChoice.build();
|
||||
Platform.runLater(() -> {
|
||||
window.setScene(comp.chooseMasterkeyScene());
|
||||
window.setTitle(resourceBundle.getString("unlock.chooseMasterkey.title").formatted(vault.getDisplayName()));
|
||||
window.show();
|
||||
Window owner = window.getOwner();
|
||||
if (owner != null) {
|
||||
@@ -147,6 +147,7 @@ public class MasterkeyFileLoadingStrategy implements KeyLoadingStrategy {
|
||||
var comp = passphraseEntry.savedPassword(passphrase).build();
|
||||
Platform.runLater(() -> {
|
||||
window.setScene(comp.passphraseEntryScene());
|
||||
window.setTitle(resourceBundle.getString("unlock.title").formatted(vault.getDisplayName()));
|
||||
window.show();
|
||||
Window owner = window.getOwner();
|
||||
if (owner != null) {
|
||||
|
||||
+1
-1
@@ -1,10 +1,10 @@
|
||||
package org.cryptomator.ui.keyloading.masterkeyfile;
|
||||
|
||||
import org.cryptomator.common.Nullable;
|
||||
import org.cryptomator.common.Passphrase;
|
||||
import org.cryptomator.common.keychain.KeychainManager;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.common.Passphrase;
|
||||
import org.cryptomator.ui.common.WeakBindings;
|
||||
import org.cryptomator.ui.controls.NiceSecurePasswordField;
|
||||
import org.cryptomator.ui.forgetPassword.ForgetPasswordComponent;
|
||||
|
||||
@@ -16,7 +16,7 @@ import javafx.fxml.FXML;
|
||||
public class WelcomeController implements FxController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(WelcomeController.class);
|
||||
private static final String GETTING_STARTED_URI = "https://docs.cryptomator.org/en/1.6/desktop/getting-started/";
|
||||
private static final String GETTING_STARTED_URI = "https://docs.cryptomator.org/en/1.5/desktop/getting-started/";
|
||||
|
||||
private final Application application;
|
||||
private final BooleanBinding noVaultPresent;
|
||||
|
||||
@@ -10,7 +10,7 @@ import javafx.stage.Stage;
|
||||
|
||||
public class MigrationImpossibleController implements FxController {
|
||||
|
||||
private static final String HELP_URI = "https://docs.cryptomator.org/en/1.6/help/manual-migration/";
|
||||
private static final String HELP_URI = "https://docs.cryptomator.org/en/1.5/help/manual-migration/";
|
||||
|
||||
private final Application application;
|
||||
private final Stage window;
|
||||
|
||||
@@ -36,7 +36,6 @@ public class GeneralPreferencesController implements FxController {
|
||||
private final FxApplicationWindows appWindows;
|
||||
public ChoiceBox<KeychainAccessProvider> keychainBackendChoiceBox;
|
||||
public CheckBox startHiddenCheckbox;
|
||||
public CheckBox autoCloseVaultsCheckbox;
|
||||
public CheckBox debugModeCheckbox;
|
||||
public CheckBox autoStartCheckbox;
|
||||
public ToggleGroup nodeOrientation;
|
||||
@@ -55,8 +54,9 @@ public class GeneralPreferencesController implements FxController {
|
||||
@FXML
|
||||
public void initialize() {
|
||||
startHiddenCheckbox.selectedProperty().bindBidirectional(settings.startHidden());
|
||||
autoCloseVaultsCheckbox.selectedProperty().bindBidirectional(settings.autoCloseVaults());
|
||||
|
||||
debugModeCheckbox.selectedProperty().bindBidirectional(settings.debugMode());
|
||||
|
||||
autoStartProvider.ifPresent(autoStart -> autoStartCheckbox.setSelected(autoStart.isEnabled()));
|
||||
|
||||
var keychainSettingsConverter = new KeychainProviderClassNameConverter(keychainAccessProviders);
|
||||
|
||||
@@ -13,7 +13,6 @@ import org.cryptomator.ui.common.FxmlScene;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
import java.awt.desktop.QuitResponse;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@QuitScoped
|
||||
@Subcomponent(modules = {QuitModule.class})
|
||||
@@ -23,28 +22,23 @@ public interface QuitComponent {
|
||||
Stage window();
|
||||
|
||||
@FxmlScene(FxmlFile.QUIT)
|
||||
Lazy<Scene> quitScene();
|
||||
Lazy<Scene> scene();
|
||||
|
||||
@FxmlScene(FxmlFile.QUIT_FORCED)
|
||||
Lazy<Scene> quitForcedScene();
|
||||
QuitController controller();
|
||||
|
||||
@QuitWindow
|
||||
AtomicReference<QuitResponse> quitResponse();
|
||||
|
||||
default void showQuitWindow(QuitResponse response, boolean forced) {
|
||||
default Stage showQuitWindow(QuitResponse response) {
|
||||
controller().updateQuitRequest(response);
|
||||
Stage stage = window();
|
||||
quitResponse().set(response);
|
||||
if(forced){
|
||||
stage.setScene(quitForcedScene().get());
|
||||
} else{
|
||||
stage.setScene(quitScene().get());
|
||||
}
|
||||
stage.sizeToScene();
|
||||
stage.setScene(scene().get());
|
||||
stage.show();
|
||||
stage.requestFocus();
|
||||
return stage;
|
||||
}
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
|
||||
QuitComponent build();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
package org.cryptomator.ui.quit;
|
||||
|
||||
import dagger.Lazy;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.common.VaultService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -13,7 +10,6 @@ import javax.inject.Inject;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ContentDisplay;
|
||||
import javafx.stage.Stage;
|
||||
@@ -33,22 +29,27 @@ public class QuitController implements FxController {
|
||||
private final ObservableList<Vault> unlockedVaults;
|
||||
private final ExecutorService executorService;
|
||||
private final VaultService vaultService;
|
||||
private final AtomicReference<QuitResponse> quitResponse;
|
||||
private final Lazy<Scene> quitForcedScene;
|
||||
private final AtomicReference<QuitResponse> quitResponse = new AtomicReference<>();
|
||||
|
||||
/* FXML */
|
||||
public Button lockAndQuitButton;
|
||||
|
||||
@Inject
|
||||
QuitController(@QuitWindow Stage window, ObservableList<Vault> vaults, ExecutorService executorService, VaultService vaultService, @FxmlScene(FxmlFile.QUIT_FORCED) Lazy<Scene> quitForcedScene, @QuitWindow AtomicReference<QuitResponse> quitResponse) {
|
||||
QuitController(@QuitWindow Stage window, ObservableList<Vault> vaults, ExecutorService executorService, VaultService vaultService) {
|
||||
this.window = window;
|
||||
this.unlockedVaults = vaults.filtered(Vault::isUnlocked);
|
||||
this.executorService = executorService;
|
||||
this.vaultService = vaultService;
|
||||
this.quitForcedScene = quitForcedScene;
|
||||
this.quitResponse = quitResponse;
|
||||
window.setOnCloseRequest(windowEvent -> cancel());
|
||||
}
|
||||
|
||||
public void updateQuitRequest(QuitResponse newResponse) {
|
||||
var oldResponse = quitResponse.getAndSet(newResponse);
|
||||
if (oldResponse != null) {
|
||||
oldResponse.cancelQuit();
|
||||
}
|
||||
}
|
||||
|
||||
private void respondToQuitRequest(Consumer<QuitResponse> action) {
|
||||
var response = quitResponse.getAndSet(null);
|
||||
if (response != null) {
|
||||
@@ -78,8 +79,13 @@ public class QuitController implements FxController {
|
||||
});
|
||||
lockAllTask.setOnFailed(evt -> {
|
||||
LOG.warn("Locking failed", lockAllTask.getException());
|
||||
window.setScene(quitForcedScene.get());
|
||||
lockAndQuitButton.setDisable(false);
|
||||
lockAndQuitButton.setContentDisplay(ContentDisplay.TEXT_ONLY);
|
||||
// TODO: show force lock or force quit scene (and DO NOT cancelQuit() here!) (see https://github.com/cryptomator/cryptomator/pull/1416)
|
||||
window.close();
|
||||
respondToQuitRequest(QuitResponse::cancelQuit);
|
||||
});
|
||||
executorService.execute(lockAllTask);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
package org.cryptomator.ui.quit;
|
||||
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.VaultService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.ContentDisplay;
|
||||
import javafx.stage.Stage;
|
||||
import java.awt.desktop.QuitResponse;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class QuitForcedController implements FxController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(QuitForcedController.class);
|
||||
|
||||
private final Stage window;
|
||||
private final ObservableList<Vault> unlockedVaults;
|
||||
private final ExecutorService executorService;
|
||||
private final VaultService vaultService;
|
||||
private final AtomicReference<QuitResponse> quitResponse;
|
||||
|
||||
/* FXML */
|
||||
public Button forceLockAndQuitButton;
|
||||
|
||||
@Inject
|
||||
QuitForcedController(@QuitWindow Stage window, ObservableList<Vault> vaults, ExecutorService executorService, VaultService vaultService, @QuitWindow AtomicReference<QuitResponse> quitResponse) {
|
||||
this.window = window;
|
||||
this.unlockedVaults = vaults.filtered(Vault::isUnlocked);
|
||||
this.executorService = executorService;
|
||||
this.vaultService = vaultService;
|
||||
this.quitResponse = quitResponse;
|
||||
window.setOnCloseRequest(windowEvent -> cancel());
|
||||
}
|
||||
|
||||
private void respondToQuitRequest(Consumer<QuitResponse> action) {
|
||||
var response = quitResponse.getAndSet(null);
|
||||
if (response != null) {
|
||||
action.accept(response);
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void cancel() {
|
||||
LOG.info("Quitting application forced canceled by user.");
|
||||
window.close();
|
||||
respondToQuitRequest(QuitResponse::cancelQuit);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void forceLockAndQuit() {
|
||||
forceLockAndQuitButton.setDisable(true);
|
||||
forceLockAndQuitButton.setContentDisplay(ContentDisplay.LEFT);
|
||||
|
||||
Task<Collection<Vault>> lockAllTask = vaultService.createLockAllTask(unlockedVaults, true); // forced set to true
|
||||
lockAllTask.setOnSucceeded(evt -> {
|
||||
LOG.info("Locked {}", lockAllTask.getValue().stream().map(Vault::getDisplayName).collect(Collectors.joining(", ")));
|
||||
if (unlockedVaults.isEmpty()) {
|
||||
window.close();
|
||||
respondToQuitRequest(QuitResponse::performQuit);
|
||||
}
|
||||
});
|
||||
lockAllTask.setOnFailed(evt -> {
|
||||
//TODO: what will happen if force lock and quit app fails?
|
||||
|
||||
LOG.error("Forced locking failed", lockAllTask.getException());
|
||||
forceLockAndQuitButton.setDisable(false);
|
||||
forceLockAndQuitButton.setContentDisplay(ContentDisplay.TEXT_ONLY);
|
||||
|
||||
window.close();
|
||||
respondToQuitRequest(QuitResponse::cancelQuit);
|
||||
});
|
||||
executorService.execute(lockAllTask);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,10 +5,10 @@ import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.common.StageFactory;
|
||||
|
||||
@@ -16,10 +16,8 @@ import javax.inject.Provider;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import java.awt.desktop.QuitResponse;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@Module
|
||||
abstract class QuitModule {
|
||||
@@ -34,23 +32,14 @@ abstract class QuitModule {
|
||||
@Provides
|
||||
@QuitWindow
|
||||
@QuitScoped
|
||||
static Stage provideStage(StageFactory factory, ResourceBundle resourceBundle) {
|
||||
static Stage provideStage(StageFactory factory) {
|
||||
Stage stage = factory.create();
|
||||
stage.setTitle(resourceBundle.getString("quit.title"));
|
||||
stage.setMinWidth(300);
|
||||
stage.setMinHeight(100);
|
||||
stage.initModality(Modality.APPLICATION_MODAL);
|
||||
return stage;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@QuitWindow
|
||||
@QuitScoped
|
||||
static AtomicReference<QuitResponse> provideQuitResponse() {
|
||||
return new AtomicReference<QuitResponse>();
|
||||
}
|
||||
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.QUIT)
|
||||
@QuitScoped
|
||||
@@ -58,14 +47,6 @@ abstract class QuitModule {
|
||||
return fxmlLoaders.createScene(FxmlFile.QUIT);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.QUIT_FORCED)
|
||||
@QuitScoped
|
||||
static Scene provideQuitForcedScene(@QuitWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.QUIT_FORCED);
|
||||
}
|
||||
|
||||
|
||||
// ------------------
|
||||
|
||||
@Binds
|
||||
@@ -73,9 +54,4 @@ abstract class QuitModule {
|
||||
@FxControllerKey(QuitController.class)
|
||||
abstract FxController bindQuitController(QuitController controller);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(QuitForcedController.class)
|
||||
abstract FxController bindQuitForcedController(QuitForcedController controller);
|
||||
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ import javafx.fxml.FXML;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
import java.io.IOException;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
@RecoveryKeyScoped
|
||||
@@ -38,9 +37,8 @@ public class RecoveryKeyCreationController implements FxController {
|
||||
public NiceSecurePasswordField passwordField;
|
||||
|
||||
@Inject
|
||||
public RecoveryKeyCreationController(@RecoveryKeyWindow Stage window, @FxmlScene(FxmlFile.RECOVERYKEY_SUCCESS) Lazy<Scene> successScene, @RecoveryKeyWindow Vault vault, RecoveryKeyFactory recoveryKeyFactory, ExecutorService executor, @RecoveryKeyWindow StringProperty recoveryKey, FxApplicationWindows appWindows, ResourceBundle resourceBundle) {
|
||||
public RecoveryKeyCreationController(@RecoveryKeyWindow Stage window, @FxmlScene(FxmlFile.RECOVERYKEY_SUCCESS) Lazy<Scene> successScene, @RecoveryKeyWindow Vault vault, RecoveryKeyFactory recoveryKeyFactory, ExecutorService executor, @RecoveryKeyWindow StringProperty recoveryKey, FxApplicationWindows appWindows) {
|
||||
this.window = window;
|
||||
window.setTitle(resourceBundle.getString("recoveryKey.display.title"));
|
||||
this.successScene = successScene;
|
||||
this.vault = vault;
|
||||
this.executor = executor;
|
||||
|
||||
@@ -53,8 +53,9 @@ abstract class RecoveryKeyModule {
|
||||
@Provides
|
||||
@RecoveryKeyWindow
|
||||
@RecoveryKeyScoped
|
||||
static Stage provideStage(StageFactory factory, @Named("keyRecoveryOwner") Stage owner) {
|
||||
static Stage provideStage(StageFactory factory, ResourceBundle resourceBundle, @Named("keyRecoveryOwner") Stage owner) {
|
||||
Stage stage = factory.create();
|
||||
stage.setTitle(resourceBundle.getString("recoveryKey.title"));
|
||||
stage.setResizable(false);
|
||||
stage.initModality(Modality.WINDOW_MODAL);
|
||||
stage.initOwner(owner);
|
||||
@@ -98,14 +99,6 @@ abstract class RecoveryKeyModule {
|
||||
return fxmlLoaders.createScene(FxmlFile.RECOVERYKEY_RESET_PASSWORD);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.RECOVERYKEY_RESET_PASSWORD_SUCCESS)
|
||||
@RecoveryKeyScoped
|
||||
static Scene provideRecoveryKeyResetPasswordSuccessScene(@RecoveryKeyWindow FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.RECOVERYKEY_RESET_PASSWORD_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
// ------------------
|
||||
|
||||
@Binds
|
||||
@@ -135,11 +128,6 @@ abstract class RecoveryKeyModule {
|
||||
@FxControllerKey(RecoveryKeyResetPasswordController.class)
|
||||
abstract FxController bindRecoveryKeyResetPasswordController(RecoveryKeyResetPasswordController controller);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(RecoveryKeyResetPasswordSuccessController.class)
|
||||
abstract FxController bindRecoveryKeyResetPasswordSuccessController(RecoveryKeyResetPasswordSuccessController controller);
|
||||
|
||||
@Provides
|
||||
@IntoMap
|
||||
@FxControllerKey(NewPasswordController.class)
|
||||
|
||||
@@ -26,7 +26,6 @@ import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.stage.Stage;
|
||||
import java.util.Optional;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
@RecoveryKeyScoped
|
||||
public class RecoveryKeyRecoverController implements FxController {
|
||||
@@ -46,9 +45,8 @@ public class RecoveryKeyRecoverController implements FxController {
|
||||
public TextArea textarea;
|
||||
|
||||
@Inject
|
||||
public RecoveryKeyRecoverController(@RecoveryKeyWindow Stage window, @RecoveryKeyWindow Vault vault, @RecoveryKeyWindow @Nullable VaultConfig.UnverifiedVaultConfig unverifiedVaultConfig, @RecoveryKeyWindow StringProperty recoveryKey, RecoveryKeyFactory recoveryKeyFactory, @FxmlScene(FxmlFile.RECOVERYKEY_RESET_PASSWORD) Lazy<Scene> resetPasswordScene, ResourceBundle resourceBundle) {
|
||||
public RecoveryKeyRecoverController(@RecoveryKeyWindow Stage window, @RecoveryKeyWindow Vault vault, @RecoveryKeyWindow @Nullable VaultConfig.UnverifiedVaultConfig unverifiedVaultConfig, @RecoveryKeyWindow StringProperty recoveryKey, RecoveryKeyFactory recoveryKeyFactory, @FxmlScene(FxmlFile.RECOVERYKEY_RESET_PASSWORD) Lazy<Scene> resetPasswordScene) {
|
||||
this.window = window;
|
||||
window.setTitle(resourceBundle.getString("recoveryKey.recover.title"));
|
||||
this.vault = vault;
|
||||
this.unverifiedVaultConfig = unverifiedVaultConfig;
|
||||
this.recoveryKey = recoveryKey;
|
||||
|
||||
+11
-10
@@ -30,40 +30,41 @@ public class RecoveryKeyResetPasswordController implements FxController {
|
||||
private final RecoveryKeyFactory recoveryKeyFactory;
|
||||
private final ExecutorService executor;
|
||||
private final StringProperty recoveryKey;
|
||||
private final Lazy<Scene> recoverResetPasswordSuccessScene;
|
||||
private final Lazy<Scene> recoverScene;
|
||||
private final FxApplicationWindows appWindows;
|
||||
|
||||
public NewPasswordController newPasswordController;
|
||||
|
||||
@Inject
|
||||
public RecoveryKeyResetPasswordController(@RecoveryKeyWindow Stage window, @RecoveryKeyWindow Vault vault, RecoveryKeyFactory recoveryKeyFactory, ExecutorService executor, @RecoveryKeyWindow StringProperty recoveryKey, @FxmlScene(FxmlFile.RECOVERYKEY_RESET_PASSWORD_SUCCESS) Lazy<Scene> recoverResetPasswordSuccessScene, FxApplicationWindows appWindows) {
|
||||
public RecoveryKeyResetPasswordController(@RecoveryKeyWindow Stage window, @RecoveryKeyWindow Vault vault, RecoveryKeyFactory recoveryKeyFactory, ExecutorService executor, @RecoveryKeyWindow StringProperty recoveryKey, @FxmlScene(FxmlFile.RECOVERYKEY_RECOVER) Lazy<Scene> recoverScene, FxApplicationWindows appWindows) {
|
||||
this.window = window;
|
||||
this.vault = vault;
|
||||
this.recoveryKeyFactory = recoveryKeyFactory;
|
||||
this.executor = executor;
|
||||
this.recoveryKey = recoveryKey;
|
||||
this.recoverResetPasswordSuccessScene = recoverResetPasswordSuccessScene;
|
||||
this.recoverScene = recoverScene;
|
||||
this.appWindows = appWindows;
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void close() {
|
||||
window.close();
|
||||
public void back() {
|
||||
window.setScene(recoverScene.get());
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void resetPassword() {
|
||||
public void done() {
|
||||
Task<Void> task = new ResetPasswordTask();
|
||||
task.setOnScheduled(event -> {
|
||||
LOG.debug("Using recovery key to reset password for {}.", vault.getDisplayablePath());
|
||||
});
|
||||
task.setOnSucceeded(event -> {
|
||||
LOG.info("Used recovery key to reset password for {}.", vault.getDisplayablePath());
|
||||
window.setScene(recoverResetPasswordSuccessScene.get());
|
||||
// TODO show success screen
|
||||
window.close();
|
||||
});
|
||||
task.setOnFailed(event -> {
|
||||
LOG.error("Resetting password failed.", task.getException());
|
||||
appWindows.showErrorWindow(task.getException(), window, null);
|
||||
appWindows.showErrorWindow(task.getException(), window, recoverScene.get());
|
||||
});
|
||||
executor.submit(task);
|
||||
}
|
||||
@@ -84,11 +85,11 @@ public class RecoveryKeyResetPasswordController implements FxController {
|
||||
|
||||
/* Getter/Setter */
|
||||
|
||||
public ReadOnlyBooleanProperty passwordSufficientAndMatchingProperty() {
|
||||
public ReadOnlyBooleanProperty validPasswordProperty() {
|
||||
return newPasswordController.goodPasswordProperty();
|
||||
}
|
||||
|
||||
public boolean isPasswordSufficientAndMatching() {
|
||||
public boolean isValidPassword() {
|
||||
return newPasswordController.isGoodPassword();
|
||||
}
|
||||
|
||||
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
package org.cryptomator.ui.recoverykey;
|
||||
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
@RecoveryKeyScoped
|
||||
public class RecoveryKeyResetPasswordSuccessController implements FxController {
|
||||
|
||||
private final Stage window;
|
||||
|
||||
@Inject
|
||||
public RecoveryKeyResetPasswordSuccessController(@RecoveryKeyWindow Stage window) {
|
||||
this.window = window;
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void close() {
|
||||
window.close();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.DefaultSceneFactory;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxControllerKey;
|
||||
@@ -34,9 +33,9 @@ abstract class RemoveVaultModule {
|
||||
@Provides
|
||||
@RemoveVaultWindow
|
||||
@RemoveVaultScoped
|
||||
static Stage provideStage(StageFactory factory, @PrimaryStage Stage primaryStage, @RemoveVaultWindow Vault vault, ResourceBundle resourceBundle) {
|
||||
static Stage provideStage(StageFactory factory, @PrimaryStage Stage primaryStage, ResourceBundle resourceBundle) {
|
||||
Stage stage = factory.create();
|
||||
stage.setTitle(String.format(resourceBundle.getString("removeVault.title"), vault.getDisplayName()));
|
||||
stage.setTitle(resourceBundle.getString("removeVault.title"));
|
||||
stage.setResizable(false);
|
||||
stage.initModality(Modality.WINDOW_MODAL);
|
||||
stage.initOwner(primaryStage);
|
||||
|
||||
@@ -5,7 +5,6 @@ import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.integrations.keychain.KeychainAccessException;
|
||||
import org.cryptomator.ui.changepassword.ChangePasswordComponent;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.forgetPassword.ForgetPasswordComponent;
|
||||
import org.cryptomator.ui.recoverykey.RecoveryKeyComponent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -26,18 +25,16 @@ public class MasterkeyOptionsController implements FxController {
|
||||
private final Stage window;
|
||||
private final ChangePasswordComponent.Builder changePasswordWindow;
|
||||
private final RecoveryKeyComponent.Builder recoveryKeyWindow;
|
||||
private final ForgetPasswordComponent.Builder forgetPasswordWindow;
|
||||
private final KeychainManager keychain;
|
||||
private final BooleanExpression passwordSaved;
|
||||
|
||||
|
||||
@Inject
|
||||
MasterkeyOptionsController(@VaultOptionsWindow Vault vault, @VaultOptionsWindow Stage window, ChangePasswordComponent.Builder changePasswordWindow, RecoveryKeyComponent.Builder recoveryKeyWindow, ForgetPasswordComponent.Builder forgetPasswordWindow, KeychainManager keychain) {
|
||||
MasterkeyOptionsController(@VaultOptionsWindow Vault vault, @VaultOptionsWindow Stage window, ChangePasswordComponent.Builder changePasswordWindow, RecoveryKeyComponent.Builder recoveryKeyWindow, KeychainManager keychain) {
|
||||
this.vault = vault;
|
||||
this.window = window;
|
||||
this.changePasswordWindow = changePasswordWindow;
|
||||
this.recoveryKeyWindow = recoveryKeyWindow;
|
||||
this.forgetPasswordWindow = forgetPasswordWindow;
|
||||
this.keychain = keychain;
|
||||
if (keychain.isSupported() && !keychain.isLocked()) {
|
||||
this.passwordSaved = Bindings.createBooleanBinding(this::isPasswordSaved, keychain.getPassphraseStoredProperty(vault.getId()));
|
||||
@@ -57,14 +54,19 @@ public class MasterkeyOptionsController implements FxController {
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void showRecoverVaultDialog() {
|
||||
public void showRecoverVaultDialogue() {
|
||||
recoveryKeyWindow.vault(vault).owner(window).build().showRecoveryKeyRecoverWindow();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void showForgetPasswordDialog() {
|
||||
public void removePasswordFromKeychain() {
|
||||
assert keychain.isSupported();
|
||||
forgetPasswordWindow.vault(vault).owner(window).build().showForgetPassword();
|
||||
try {
|
||||
keychain.deletePassphrase(vault.getId());
|
||||
} catch (KeychainAccessException e) {
|
||||
LOG.error("Failed to delete passphrase from system keychain.", e);
|
||||
}
|
||||
window.close();
|
||||
}
|
||||
|
||||
public BooleanExpression passwordSavedProperty() {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.cryptomator.ui.vaultoptions;
|
||||
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -19,7 +18,6 @@ public class VaultOptionsController implements FxController {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(VaultOptionsController.class);
|
||||
|
||||
private final Stage window;
|
||||
private final Vault vault;
|
||||
private final ObjectProperty<SelectedVaultOptionsTab> selectedTabProperty;
|
||||
public TabPane tabPane;
|
||||
public Tab generalTab;
|
||||
@@ -27,9 +25,8 @@ public class VaultOptionsController implements FxController {
|
||||
public Tab keyTab;
|
||||
|
||||
@Inject
|
||||
VaultOptionsController(@VaultOptionsWindow Stage window, @VaultOptionsWindow Vault vault, ObjectProperty<SelectedVaultOptionsTab> selectedTabProperty) {
|
||||
VaultOptionsController(@VaultOptionsWindow Stage window, ObjectProperty<SelectedVaultOptionsTab> selectedTabProperty) {
|
||||
this.window = window;
|
||||
this.vault = vault;
|
||||
this.selectedTabProperty = selectedTabProperty;
|
||||
}
|
||||
|
||||
@@ -38,9 +35,6 @@ public class VaultOptionsController implements FxController {
|
||||
window.setOnShowing(this::windowWillAppear);
|
||||
selectedTabProperty.addListener(observable -> this.selectChosenTab());
|
||||
tabPane.getSelectionModel().selectedItemProperty().addListener(observable -> this.selectedTabChanged());
|
||||
if(!vault.getVaultConfigCache().getUnchecked().getKeyId().getScheme().equals("masterkeyfile")){
|
||||
tabPane.getTabs().remove(keyTab);
|
||||
}
|
||||
}
|
||||
|
||||
private void selectChosenTab() {
|
||||
|
||||
@@ -13,7 +13,6 @@ import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlLoaderFactory;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.common.StageFactory;
|
||||
import org.cryptomator.ui.forgetPassword.ForgetPasswordComponent;
|
||||
import org.cryptomator.ui.fxapp.PrimaryStage;
|
||||
import org.cryptomator.ui.recoverykey.RecoveryKeyComponent;
|
||||
|
||||
@@ -26,7 +25,7 @@ import javafx.stage.Stage;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
@Module(subcomponents = {ChangePasswordComponent.class, RecoveryKeyComponent.class, ForgetPasswordComponent.class})
|
||||
@Module(subcomponents = {ChangePasswordComponent.class, RecoveryKeyComponent.class})
|
||||
abstract class VaultOptionsModule {
|
||||
|
||||
@Provides
|
||||
|
||||
@@ -15,7 +15,7 @@ import java.io.UncheckedIOException;
|
||||
@WrongFileAlertScoped
|
||||
public class WrongFileAlertController implements FxController {
|
||||
|
||||
private static final String DOCUMENTATION_URI = "https://docs.cryptomator.org/en/1.6/desktop/accessing-vaults/";
|
||||
private static final String DOCUMENTATION_URI = "https://docs.cryptomator.org/en/1.5/desktop/accessing-vaults/";
|
||||
|
||||
private final Application app;
|
||||
private final Stage window;
|
||||
@@ -30,7 +30,6 @@ public class WrongFileAlertController implements FxController {
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
//TODO: add dark-mode screens
|
||||
final String resource = SystemUtils.IS_OS_MAC ? "/img/vault-volume-mac.png" : "/img/vault-volume-win.png";
|
||||
try (InputStream in = getClass().getResourceAsStream(resource)) {
|
||||
this.screenshot = new Image(in);
|
||||
|
||||
@@ -98,14 +98,9 @@
|
||||
-fx-text-fill: TEXT_FILL_MUTED;
|
||||
}
|
||||
|
||||
.label-extra-large {
|
||||
-fx-font-family: 'Open Sans SemiBold';
|
||||
-fx-font-size: 1.5em;
|
||||
}
|
||||
|
||||
.label-large {
|
||||
-fx-font-family: 'Open Sans SemiBold';
|
||||
-fx-font-size: 1.2em;
|
||||
-fx-font-size: 1.5em;
|
||||
}
|
||||
|
||||
.label-small {
|
||||
|
||||
@@ -98,14 +98,9 @@
|
||||
-fx-text-fill: TEXT_FILL_MUTED;
|
||||
}
|
||||
|
||||
.label-extra-large {
|
||||
-fx-font-family: 'Open Sans SemiBold';
|
||||
-fx-font-size: 1.5em;
|
||||
}
|
||||
|
||||
.label-large {
|
||||
-fx-font-family: 'Open Sans SemiBold';
|
||||
-fx-font-size: 1.2em;
|
||||
-fx-font-size: 1.5em;
|
||||
}
|
||||
|
||||
.label-small {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
|
||||
<?import org.cryptomator.ui.controls.FormattedLabel?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.ButtonBar?>
|
||||
@@ -9,7 +8,6 @@
|
||||
<?import javafx.scene.control.TextField?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<VBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
@@ -27,43 +25,11 @@
|
||||
<VBox spacing="6">
|
||||
<Label text="%addvaultwizard.new.nameInstruction" labelFor="$textField"/>
|
||||
<TextField fx:id="textField" promptText="%addvaultwizard.new.namePrompt" HBox.hgrow="ALWAYS"/>
|
||||
<HBox alignment="TOP_RIGHT">
|
||||
<StackPane visible="${!textField.text.empty}">
|
||||
<Label styleClass="label-muted" text="%addvaultwizard.new.invalidName" textAlignment="RIGHT" alignment="CENTER_RIGHT" visible="${!controller.validVaultName}" graphicTextGap="6">
|
||||
<graphic>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-red" glyph="TIMES" />
|
||||
</graphic>
|
||||
</Label>
|
||||
<Label styleClass="label-muted" text="%addvaultwizard.new.validName" textAlignment="RIGHT" alignment="CENTER_RIGHT" visible="${controller.validVaultName}" graphicTextGap="6">
|
||||
<graphic>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-primary" glyph="CHECK" />
|
||||
</graphic>
|
||||
</Label>
|
||||
</StackPane>
|
||||
</HBox>
|
||||
|
||||
<Label text="%addvaultwizard.new.validCharacters.message"/>
|
||||
<VBox>
|
||||
<padding>
|
||||
<Insets left="6"/>
|
||||
</padding>
|
||||
<Label text="%addvaultwizard.new.validCharacters.chars">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="CHECK" />
|
||||
</graphic>
|
||||
</Label>
|
||||
<Label text="%addvaultwizard.new.validCharacters.numbers">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="CHECK" />
|
||||
</graphic>
|
||||
</Label>
|
||||
<FormattedLabel format="%addvaultwizard.new.validCharacters.dashes" arg1="-" arg2="_">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="CHECK" />
|
||||
</graphic>
|
||||
</FormattedLabel>
|
||||
</VBox>
|
||||
|
||||
<Label text="${controller.warningText}" wrapText="true" visible="${controller.showWarning}">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="EXCLAMATION_TRIANGLE"/>
|
||||
</graphic>
|
||||
</Label>
|
||||
</VBox>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS"/>
|
||||
|
||||
@@ -30,14 +30,14 @@
|
||||
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="EXCLAMATION" glyphSize="24"/>
|
||||
</StackPane>
|
||||
<VBox spacing="6" HBox.hgrow="ALWAYS">
|
||||
<FormattedLabel styleClass="label-extra-large" format="%error.message" arg1="${controller.errorCode}"/>
|
||||
<Label text="%error.description" wrapText="true"/>
|
||||
<Hyperlink styleClass="hyperlink-underline" text="%error.hyperlink.lookup" onAction="#searchError" contentDisplay="LEFT">
|
||||
<FormattedLabel styleClass="label-large" format="%generic.error.title" arg1="${controller.errorCode}"/>
|
||||
<Label text="%generic.error.instruction" wrapText="true"/>
|
||||
<Hyperlink styleClass="hyperlink-underline" text="%generic.error.hyperlink.lookup" onAction="#searchError" contentDisplay="LEFT">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="LINK" glyphSize="12"/>
|
||||
</graphic>
|
||||
</Hyperlink>
|
||||
<Hyperlink styleClass="hyperlink-underline" text="%error.hyperlink.report" onAction="#reportError" contentDisplay="LEFT">
|
||||
<Hyperlink styleClass="hyperlink-underline" text="%generic.error.hyperlink.report" onAction="#reportError" contentDisplay="LEFT">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="LINK" glyphSize="12"/>
|
||||
</graphic>
|
||||
@@ -47,7 +47,7 @@
|
||||
|
||||
<VBox spacing="6" VBox.vgrow="ALWAYS">
|
||||
<HBox>
|
||||
<Label text="%error.technicalDetails"/>
|
||||
<Label text="%generic.error.technicalDetails"/>
|
||||
<Region HBox.hgrow="ALWAYS"/>
|
||||
<Hyperlink styleClass="hyperlink-underline" text="%generic.button.copy" onAction="#copyDetails" contentDisplay="LEFT" visible="${!controller.copiedDetails}" managed="${!controller.copiedDetails}">
|
||||
<graphic>
|
||||
|
||||
@@ -9,38 +9,26 @@
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.Circle?>
|
||||
<?import javafx.scene.Group?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<HBox xmlns:fx="http://javafx.com/fxml"
|
||||
<VBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.forgetPassword.ForgetPasswordController"
|
||||
minWidth="400"
|
||||
maxWidth="400"
|
||||
minHeight="145"
|
||||
spacing="12"
|
||||
alignment="TOP_LEFT">
|
||||
spacing="12">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<Group>
|
||||
<StackPane>
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="6"/>
|
||||
</padding>
|
||||
<HBox spacing="12" alignment="CENTER_LEFT" VBox.vgrow="ALWAYS">
|
||||
<StackPane alignment="CENTER" HBox.hgrow="NEVER">
|
||||
<Circle styleClass="glyph-icon-primary" radius="24"/>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="QUESTION" glyphSize="24"/>
|
||||
</StackPane>
|
||||
</Group>
|
||||
<VBox HBox.hgrow="ALWAYS">
|
||||
<Label styleClass="label-large" text="%forgetPassword.message" wrapText="true" textAlignment="LEFT">
|
||||
<padding>
|
||||
<Insets bottom="6" top="6"/>
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="%forgetPassword.description" wrapText="true" textAlignment="LEFT" HBox.hgrow="ALWAYS"/>
|
||||
<Label text="%forgetPassword.information" wrapText="true" textAlignment="LEFT" HBox.hgrow="ALWAYS"/>
|
||||
</HBox>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
|
||||
<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+CI">
|
||||
<buttons>
|
||||
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" defaultButton="true" cancelButton="true" onAction="#close"/>
|
||||
@@ -49,4 +37,4 @@
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
</children>
|
||||
</HBox>
|
||||
</VBox>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.health.CheckDetailController"
|
||||
spacing="6">
|
||||
<Label fx:id="detailHeader" styleClass="label-extra-large" text="${controller.checkName}" contentDisplay="LEFT">
|
||||
<Label fx:id="detailHeader" styleClass="label-large" text="${controller.checkName}" contentDisplay="LEFT">
|
||||
<graphic>
|
||||
<HBox alignment="CENTER" minWidth="25" maxWidth="25">
|
||||
<CheckStateIconView fx:id="checkStateIconView" check="${controller.check}" glyphSize="20"/>
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<Label text="%health.intro.header" styleClass="label-extra-large"/>
|
||||
<Label text="%health.intro.header" styleClass="label-large"/>
|
||||
<Region minHeight="15"/>
|
||||
<VBox>
|
||||
<Label text="%health.intro.text" wrapText="true"/>
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import org.cryptomator.ui.controls.FontAwesome5Spinner?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.ButtonBar?>
|
||||
<?import javafx.scene.control.Hyperlink?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.Group?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.Circle?>
|
||||
<?import javafx.scene.text.TextFlow?>
|
||||
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
|
||||
<HBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.keyloading.hub.AuthFlowController"
|
||||
minWidth="400"
|
||||
maxWidth="400"
|
||||
minHeight="145"
|
||||
spacing="12"
|
||||
alignment="TOP_LEFT">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<Group>
|
||||
<StackPane>
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="6"/>
|
||||
</padding>
|
||||
<Circle styleClass="glyph-icon-primary" radius="24"/>
|
||||
<FontAwesome5Spinner styleClass="glyph-icon-white" glyphSize="24"/>
|
||||
</StackPane>
|
||||
</Group>
|
||||
|
||||
<VBox HBox.hgrow="ALWAYS">
|
||||
<Label styleClass="label-large" text="%hub.auth.message" wrapText="true" textAlignment="LEFT">
|
||||
<padding>
|
||||
<Insets bottom="6" top="6"/>
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="%hub.auth.description" wrapText="true"/>
|
||||
<Hyperlink styleClass="hyperlink-underline" text="%hub.auth.loginLink" onAction="#browse">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="LINK" glyphSize="12"/>
|
||||
</graphic>
|
||||
<padding>
|
||||
<Insets top="12"/>
|
||||
</padding>
|
||||
</Hyperlink>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+C">
|
||||
<buttons>
|
||||
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#cancel"/>
|
||||
</buttons>
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
</children>
|
||||
</HBox>
|
||||
@@ -1,52 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import org.cryptomator.ui.controls.FontAwesome5Spinner?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.ButtonBar?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.Group?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.Circle?>
|
||||
<HBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.keyloading.hub.ReceiveKeyController"
|
||||
minWidth="400"
|
||||
maxWidth="400"
|
||||
minHeight="145"
|
||||
spacing="12"
|
||||
alignment="TOP_LEFT">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<Group>
|
||||
<StackPane>
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="6"/>
|
||||
</padding>
|
||||
<Circle styleClass="glyph-icon-primary" radius="24"/>
|
||||
<FontAwesome5Spinner styleClass="glyph-icon-white" glyphSize="24"/>
|
||||
</StackPane>
|
||||
</Group>
|
||||
|
||||
<VBox HBox.hgrow="ALWAYS">
|
||||
<Label styleClass="label-large" text="%hub.receive.message" wrapText="true" textAlignment="LEFT">
|
||||
<padding>
|
||||
<Insets bottom="6" top="6"/>
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="%hub.receive.description" wrapText="true"/>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+C">
|
||||
<buttons>
|
||||
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#cancel"/>
|
||||
</buttons>
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
</children>
|
||||
</HBox>
|
||||
@@ -1,76 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.ButtonBar?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.TextField?>
|
||||
<?import javafx.scene.Group?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.Circle?>
|
||||
<?import org.cryptomator.ui.controls.FontAwesome5Spinner?>
|
||||
<HBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.keyloading.hub.RegisterDeviceController"
|
||||
minWidth="400"
|
||||
maxWidth="400"
|
||||
minHeight="145"
|
||||
spacing="12"
|
||||
alignment="TOP_LEFT">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<Group>
|
||||
<StackPane>
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="6"/>
|
||||
</padding>
|
||||
<Circle styleClass="glyph-icon-primary" radius="24"/>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="INFO" glyphSize="24"/>
|
||||
</StackPane>
|
||||
</Group>
|
||||
|
||||
<VBox HBox.hgrow="ALWAYS">
|
||||
<Label styleClass="label-large" text="%hub.register.message" wrapText="true" textAlignment="LEFT">
|
||||
<padding>
|
||||
<Insets bottom="6" top="6"/>
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="%hub.register.description" wrapText="true"/>
|
||||
<HBox spacing="6" alignment="CENTER_LEFT">
|
||||
<padding>
|
||||
<Insets top="12"/>
|
||||
</padding>
|
||||
<Label text="%hub.register.nameLabel" labelFor="$deviceNameField"/>
|
||||
<TextField fx:id="deviceNameField" HBox.hgrow="ALWAYS"/>
|
||||
</HBox>
|
||||
<HBox alignment="TOP_RIGHT">
|
||||
<Label text="%hub.register.occupiedMsg" textAlignment="RIGHT" alignment="CENTER_RIGHT" visible="${controller.deviceNameAlreadyExists}" graphicTextGap="6">
|
||||
<padding>
|
||||
<Insets top="6"/>
|
||||
</padding>
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="TIMES" styleClass="glyph-icon-red"/>
|
||||
</graphic>
|
||||
</Label>
|
||||
</HBox>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+CU">
|
||||
<buttons>
|
||||
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#close"/>
|
||||
<Button fx:id="registerBtn" text="%hub.register.registerBtn" ButtonBar.buttonData="OTHER" defaultButton="true" onAction="#register" contentDisplay="TEXT_ONLY" >
|
||||
<graphic>
|
||||
<FontAwesome5Spinner glyphSize="12" />
|
||||
</graphic>
|
||||
</Button>
|
||||
</buttons>
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
</children>
|
||||
</HBox>
|
||||
@@ -1,51 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.ButtonBar?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.Group?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.Circle?>
|
||||
<HBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.keyloading.hub.RegisterFailedController"
|
||||
minWidth="400"
|
||||
maxWidth="400"
|
||||
minHeight="145"
|
||||
spacing="12"
|
||||
alignment="TOP_LEFT">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<Group>
|
||||
<StackPane>
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="6"/>
|
||||
</padding>
|
||||
<Circle styleClass="glyph-icon-primary" radius="24"/>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="EXCLAMATION" glyphSize="24"/>
|
||||
</StackPane>
|
||||
</Group>
|
||||
<VBox HBox.hgrow="ALWAYS">
|
||||
<Label styleClass="label-large" text="%hub.registerFailed.message" wrapText="true" textAlignment="LEFT">
|
||||
<padding>
|
||||
<Insets bottom="6" top="6"/>
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="%hub.registerFailed.description" wrapText="true"/>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+C">
|
||||
<buttons>
|
||||
<Button text="%generic.button.close" ButtonBar.buttonData="CANCEL_CLOSE" defaultButton="true" onAction="#close"/>
|
||||
</buttons>
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
</children>
|
||||
</HBox>
|
||||
@@ -1,52 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.ButtonBar?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.Group?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.Circle?>
|
||||
<HBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.keyloading.hub.RegisterSuccessController"
|
||||
minWidth="400"
|
||||
maxWidth="400"
|
||||
minHeight="145"
|
||||
spacing="12"
|
||||
alignment="TOP_LEFT">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<Group>
|
||||
<StackPane>
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="6"/>
|
||||
</padding>
|
||||
<Circle styleClass="glyph-icon-primary" radius="24"/>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="CHECK" glyphSize="24"/>
|
||||
</StackPane>
|
||||
</Group>
|
||||
<VBox HBox.hgrow="ALWAYS">
|
||||
<Label styleClass="label-large" text="%hub.registerSuccess.message" wrapText="true" textAlignment="LEFT">
|
||||
<padding>
|
||||
<Insets bottom="6" top="6"/>
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="%hub.registerSuccess.description" wrapText="true"/>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+C">
|
||||
<buttons>
|
||||
<Button text="%generic.button.close" ButtonBar.buttonData="CANCEL_CLOSE" defaultButton="true" onAction="#close"/>
|
||||
<!-- TODO: add request access button -->
|
||||
</buttons>
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
</children>
|
||||
</HBox>
|
||||
@@ -1,53 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.ButtonBar?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.Group?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.Circle?>
|
||||
<HBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.keyloading.hub.UnauthorizedDeviceController"
|
||||
minWidth="400"
|
||||
maxWidth="400"
|
||||
minHeight="145"
|
||||
spacing="12"
|
||||
alignment="TOP_LEFT">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<Group>
|
||||
<StackPane>
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="6"/>
|
||||
</padding>
|
||||
<Circle styleClass="glyph-icon-primary" radius="24"/>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="BAN" glyphSize="24"/>
|
||||
</StackPane>
|
||||
</Group>
|
||||
<VBox HBox.hgrow="ALWAYS">
|
||||
<Label styleClass="label-large" text="%hub.unauthorized.message" wrapText="true" textAlignment="LEFT">
|
||||
<padding>
|
||||
<Insets bottom="6" top="6"/>
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="%hub.unauthorized.description" wrapText="true"/>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+C">
|
||||
<buttons>
|
||||
<Button text="%generic.button.close" ButtonBar.buttonData="CANCEL_CLOSE" defaultButton="true" onAction="#close"/>
|
||||
<!-- TODO: add request access button -->
|
||||
<!--Button text="%generic.button.close" ButtonBar.buttonData="CANCEL_CLOSE" defaultButton="true" onAction="#close"/-->
|
||||
</buttons>
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
</children>
|
||||
</HBox>
|
||||
@@ -4,49 +4,34 @@
|
||||
<?import org.cryptomator.ui.controls.FormattedLabel?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.ButtonBar?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.Group?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.Circle?>
|
||||
<HBox xmlns:fx="http://javafx.com/fxml"
|
||||
<VBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.lock.LockFailedController"
|
||||
minWidth="400"
|
||||
maxWidth="400"
|
||||
minHeight="145"
|
||||
spacing="12"
|
||||
alignment="TOP_LEFT">
|
||||
spacing="12">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<Group>
|
||||
<StackPane>
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="6"/>
|
||||
</padding>
|
||||
<HBox spacing="12" alignment="CENTER_LEFT" VBox.vgrow="ALWAYS">
|
||||
<StackPane alignment="CENTER" HBox.hgrow="NEVER">
|
||||
<Circle styleClass="glyph-icon-red" radius="24"/>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="TIMES" glyphSize="24"/>
|
||||
</StackPane>
|
||||
</Group>
|
||||
<VBox HBox.hgrow="ALWAYS">
|
||||
<Label styleClass="label-large" text="%lock.fail.message" wrapText="true" textAlignment="LEFT">
|
||||
<padding>
|
||||
<Insets bottom="6" top="6"/>
|
||||
</padding>
|
||||
</Label>
|
||||
<FormattedLabel format="%lock.fail.description" arg1="${controller.vaultName}" wrapText="true"/>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+C">
|
||||
<buttons>
|
||||
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#close"/>
|
||||
</buttons>
|
||||
</ButtonBar>
|
||||
<VBox spacing="6">
|
||||
<Label styleClass="label-large" text="%lock.fail.heading"/>
|
||||
<FormattedLabel format="%lock.fail.message" arg1="${controller.vaultName}" wrapText="true"/>
|
||||
</VBox>
|
||||
</HBox>
|
||||
<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
|
||||
<Button text="OK" defaultButton="false" VBox.vgrow="ALWAYS" cancelButton="true" onAction="#close"/>
|
||||
</VBox>
|
||||
</children>
|
||||
</HBox>
|
||||
</VBox>
|
||||
|
||||
@@ -10,39 +10,30 @@
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.Circle?>
|
||||
<?import javafx.scene.Group?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<HBox xmlns:fx="http://javafx.com/fxml"
|
||||
<VBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.lock.LockForcedController"
|
||||
minWidth="400"
|
||||
maxWidth="500"
|
||||
maxWidth="400"
|
||||
minHeight="145"
|
||||
spacing="12"
|
||||
alignment="TOP_LEFT">
|
||||
spacing="12">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<Group>
|
||||
<StackPane>
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="6"/>
|
||||
</padding>
|
||||
<HBox spacing="12" alignment="CENTER_LEFT" VBox.vgrow="ALWAYS">
|
||||
<StackPane alignment="CENTER" HBox.hgrow="NEVER">
|
||||
<Circle styleClass="glyph-icon-orange" radius="24"/>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="EXCLAMATION" glyphSize="24"/>
|
||||
</StackPane>
|
||||
</Group>
|
||||
<VBox HBox.hgrow="ALWAYS">
|
||||
<Label styleClass="label-large" text="%lock.forced.message" wrapText="true" textAlignment="LEFT">
|
||||
<padding>
|
||||
<Insets bottom="6" top="6"/>
|
||||
</padding>
|
||||
</Label>
|
||||
<FormattedLabel format="%lock.forced.description" arg1="${controller.vaultName}" wrapText="true"/>
|
||||
<VBox spacing="6">
|
||||
<Label styleClass="label-large" text="%lock.forced.heading"/>
|
||||
<FormattedLabel format="%lock.forced.message" arg1="${controller.vaultName}" wrapText="true"/>
|
||||
</VBox>
|
||||
</HBox>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="U+CI">
|
||||
<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
|
||||
<ButtonBar buttonMinWidth="100" buttonOrder="+CIU">
|
||||
<buttons>
|
||||
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" defaultButton="true" cancelButton="true" onAction="#cancel"/>
|
||||
<Button text="%lock.forced.retryBtn" ButtonBar.buttonData="FINISH" onAction="#retry"/>
|
||||
@@ -51,4 +42,4 @@
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
</children>
|
||||
</HBox>
|
||||
</VBox>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="TIMES" glyphSize="24"/>
|
||||
</StackPane>
|
||||
<VBox spacing="6">
|
||||
<Label styleClass="label-extra-large" text="%migration.impossible.heading"/>
|
||||
<Label styleClass="label-large" text="%migration.impossible.heading"/>
|
||||
<Label text="%migration.impossible.reason" wrapText="true" HBox.hgrow="ALWAYS"/>
|
||||
<TextFlow>
|
||||
<Text text="%migration.impossible.moreInfo"/>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<Image url="@../img/logo.png"/>
|
||||
</ImageView>
|
||||
<VBox spacing="3" HBox.hgrow="ALWAYS" alignment="CENTER_LEFT">
|
||||
<FormattedLabel styleClass="label-extra-large" format="Cryptomator %s" arg1="${controller.applicationVersion}"/>
|
||||
<FormattedLabel styleClass="label-large" format="Cryptomator %s" arg1="${controller.applicationVersion}"/>
|
||||
<Label text="© 2016 – 2022 Skymatic GmbH"/>
|
||||
</VBox>
|
||||
</HBox>
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
|
||||
<CheckBox fx:id="startHiddenCheckbox" text="%preferences.general.startHidden" />
|
||||
|
||||
<CheckBox fx:id="autoCloseVaultsCheckbox" text="%preferences.general.autoCloseVaults" />
|
||||
|
||||
<HBox spacing="12" alignment="CENTER_LEFT">
|
||||
<Label text="%preferences.general.keychainBackend"/>
|
||||
<ChoiceBox fx:id="keychainBackendChoiceBox"/>
|
||||
|
||||
@@ -6,48 +6,34 @@
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.ButtonBar?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.Group?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.Circle?>
|
||||
<HBox xmlns:fx="http://javafx.com/fxml"
|
||||
<VBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.quit.QuitController"
|
||||
minWidth="400"
|
||||
maxWidth="400"
|
||||
minHeight="145"
|
||||
spacing="12"
|
||||
alignment="TOP_LEFT">
|
||||
spacing="12">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<Group>
|
||||
<StackPane>
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="6"/>
|
||||
</padding>
|
||||
<HBox spacing="12" alignment="CENTER_LEFT" VBox.vgrow="ALWAYS">
|
||||
<StackPane alignment="CENTER" HBox.hgrow="NEVER">
|
||||
<Circle styleClass="glyph-icon-primary" radius="24"/>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="EXCLAMATION" glyphSize="24"/>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="QUESTION" glyphSize="24"/>
|
||||
</StackPane>
|
||||
</Group>
|
||||
<Label text="%quit.prompt" wrapText="true" textAlignment="LEFT" HBox.hgrow="ALWAYS"/>
|
||||
</HBox>
|
||||
|
||||
<VBox HBox.hgrow="ALWAYS">
|
||||
<Label styleClass="label-large" text="%quit.message" wrapText="true" textAlignment="LEFT">
|
||||
<padding>
|
||||
<Insets bottom="6" top="6"/>
|
||||
</padding>
|
||||
</Label>
|
||||
|
||||
<Label text="%quit.description" wrapText="true" textAlignment="LEFT"/>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
|
||||
<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+CI">
|
||||
<buttons>
|
||||
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" defaultButton="true" cancelButton="true" onAction="#cancel"/>
|
||||
<Button fx:id="lockAndQuitButton" text="%quit.lockAndQuitBtn" ButtonBar.buttonData="FINISH" onAction="#lockAndQuit" contentDisplay="TEXT_ONLY">
|
||||
<Button fx:id="lockAndQuitButton" text="%quit.lockAndQuit" ButtonBar.buttonData="FINISH" onAction="#lockAndQuit" contentDisplay="TEXT_ONLY">
|
||||
<graphic>
|
||||
<FontAwesome5Spinner glyphSize="12"/>
|
||||
</graphic>
|
||||
@@ -56,4 +42,4 @@
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
</children>
|
||||
</HBox>
|
||||
</VBox>
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
|
||||
<?import org.cryptomator.ui.controls.FontAwesome5Spinner?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.ButtonBar?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.Circle?>
|
||||
<?import javafx.scene.Group?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<HBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.quit.QuitForcedController"
|
||||
minWidth="400"
|
||||
maxWidth="400"
|
||||
minHeight="145"
|
||||
spacing="12"
|
||||
alignment="TOP_LEFT">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<Group>
|
||||
<StackPane>
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="6"/>
|
||||
</padding>
|
||||
<Circle styleClass="glyph-icon-orange" radius="24"/>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="EXCLAMATION" glyphSize="24"/>
|
||||
</StackPane>
|
||||
</Group>
|
||||
|
||||
<VBox HBox.hgrow="ALWAYS">
|
||||
<Label styleClass="label-large" text="%quit.forced.message" wrapText="true" textAlignment="LEFT">
|
||||
<padding>
|
||||
<Insets bottom="6" top="6"/>
|
||||
</padding>
|
||||
</Label>
|
||||
|
||||
<Label text="%quit.forced.description" wrapText="true" textAlignment="LEFT"/>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+CI">
|
||||
<buttons>
|
||||
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" defaultButton="true" cancelButton="true" onAction="#cancel"/>
|
||||
<Button fx:id="forceLockAndQuitButton" text="%quit.forced.forceAndQuitBtn" ButtonBar.buttonData="FINISH" onAction="#forceLockAndQuit" contentDisplay="TEXT_ONLY">
|
||||
<graphic>
|
||||
<FontAwesome5Spinner glyphSize="12"/>
|
||||
</graphic>
|
||||
</Button>
|
||||
</buttons>
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
</children>
|
||||
</HBox>
|
||||
@@ -7,47 +7,25 @@
|
||||
<?import javafx.scene.control.ButtonBar?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.Group?>
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.shape.Circle?>
|
||||
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<HBox xmlns:fx="http://javafx.com/fxml"
|
||||
<VBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.recoverykey.RecoveryKeyCreationController"
|
||||
minWidth="400"
|
||||
maxWidth="400"
|
||||
minHeight="175"
|
||||
minHeight="145"
|
||||
spacing="12"
|
||||
alignment="TOP_LEFT">
|
||||
alignment="TOP_CENTER">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<Group>
|
||||
<StackPane>
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="6"/>
|
||||
</padding>
|
||||
<Circle styleClass="glyph-icon-primary" radius="24"/>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="LOCK" glyphSize="24"/>
|
||||
</StackPane>
|
||||
</Group>
|
||||
<VBox HBox.hgrow="ALWAYS">
|
||||
<Label styleClass="label-large" text="%recoveryKey.create.message" wrapText="true" textAlignment="LEFT">
|
||||
<padding>
|
||||
<Insets bottom="6" top="6"/>
|
||||
</padding>
|
||||
</Label>
|
||||
<FormattedLabel format="%recoveryKey.create.description" arg1="${controller.vault.displayName}" wrapText="true">
|
||||
<padding>
|
||||
<Insets bottom="6"/>
|
||||
</padding>
|
||||
</FormattedLabel>
|
||||
<VBox spacing="6">
|
||||
<FormattedLabel format="%recoveryKey.enterPassword.prompt" arg1="${controller.vault.displayName}" wrapText="true"/>
|
||||
<NiceSecurePasswordField fx:id="passwordField" HBox.hgrow="ALWAYS"/>
|
||||
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+CX">
|
||||
</VBox>
|
||||
|
||||
<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="C+X">
|
||||
<buttons>
|
||||
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#close"/>
|
||||
<Button text="%generic.button.next" ButtonBar.buttonData="NEXT_FORWARD" defaultButton="true" onAction="#createRecoveryKey" disable="${passwordField.text.empty}"/>
|
||||
@@ -55,4 +33,4 @@
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
</children>
|
||||
</HBox>
|
||||
</VBox>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
spacing="12"
|
||||
alignment="TOP_LEFT">
|
||||
<children>
|
||||
<FormattedLabel format="%recoveryKey.display.description" arg1="${controller.vaultName}" wrapText="true"/>
|
||||
<FormattedLabel format="%recoveryKey.display.message" arg1="${controller.vaultName}" wrapText="true"/>
|
||||
|
||||
<TextArea editable="false" text="${controller.recoveryKey}" wrapText="true" prefRowCount="4" fx:id="textarea"/>
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+R">
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
<TextArea wrapText="true" prefRowCount="4" fx:id="textarea" textFormatter="${controller.recoveryKeyTextFormatter}" onKeyPressed="#onKeyPressed"/>
|
||||
|
||||
<!-- TODO: add Label when the recovery key is not valid -->
|
||||
<Label text="%recoveryKey.recover.validKey" graphicTextGap="6" contentDisplay="LEFT" visible="${controller.validRecoveryKey}">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="CHECK"/>
|
||||
@@ -35,7 +34,7 @@
|
||||
<Region VBox.vgrow="ALWAYS"/>
|
||||
|
||||
<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+CX">
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="C+X">
|
||||
<buttons>
|
||||
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#close"/>
|
||||
<Button text="%generic.button.next" ButtonBar.buttonData="NEXT_FORWARD" defaultButton="true" onAction="#recover" disable="${!controller.validRecoveryKey}"/>
|
||||
|
||||
@@ -22,10 +22,10 @@
|
||||
<Region VBox.vgrow="ALWAYS"/>
|
||||
|
||||
<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+CI">
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="B+I">
|
||||
<buttons>
|
||||
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#close"/>
|
||||
<Button text="%recoveryKey.recover.resetBtn" ButtonBar.buttonData="FINISH" defaultButton="true" onAction="#resetPassword" disable="${!controller.passwordSufficientAndMatching}"/>
|
||||
<Button text="%generic.button.back" ButtonBar.buttonData="BACK_PREVIOUS" cancelButton="true" onAction="#back"/>
|
||||
<Button text="%generic.button.done" ButtonBar.buttonData="FINISH" defaultButton="true" onAction="#done" disable="${!controller.validPassword}"/>
|
||||
</buttons>
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.ButtonBar?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.Circle?>
|
||||
<?import javafx.scene.Group?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<HBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.recoverykey.RecoveryKeyResetPasswordSuccessController"
|
||||
minWidth="400"
|
||||
maxWidth="400"
|
||||
minHeight="145"
|
||||
spacing="12"
|
||||
alignment="TOP_LEFT">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<Group>
|
||||
<StackPane>
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="6"/>
|
||||
</padding>
|
||||
<Circle styleClass="glyph-icon-primary" radius="24"/>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="CHECK" glyphSize="24"/>
|
||||
</StackPane>
|
||||
</Group>
|
||||
|
||||
<VBox HBox.hgrow="ALWAYS">
|
||||
<Label styleClass="label-large" text="%recoveryKey.recover.resetSuccess.message" wrapText="true" textAlignment="LEFT">
|
||||
<padding>
|
||||
<Insets bottom="6" top="6"/>
|
||||
</padding>
|
||||
</Label>
|
||||
|
||||
<Label text="%recoveryKey.recover.resetSuccess.description" wrapText="true" textAlignment="LEFT"/>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+C">
|
||||
<buttons>
|
||||
<Button text="%generic.button.close" ButtonBar.buttonData="CANCEL_CLOSE" defaultButton="true" cancelButton="true" onAction="#close"/>
|
||||
</buttons>
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
</children>
|
||||
</HBox>
|
||||
@@ -24,7 +24,7 @@
|
||||
<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+C">
|
||||
<buttons>
|
||||
<Button text="%generic.button.close" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#close"/>
|
||||
<Button text="%generic.button.done" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#close"/>
|
||||
</buttons>
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
|
||||
@@ -9,38 +9,26 @@
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.Circle?>
|
||||
<?import javafx.scene.Group?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<HBox xmlns:fx="http://javafx.com/fxml"
|
||||
<VBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.removevault.RemoveVaultController"
|
||||
minWidth="400"
|
||||
maxWidth="400"
|
||||
minHeight="145"
|
||||
spacing="12"
|
||||
alignment="TOP_LEFT">
|
||||
spacing="12">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<Group>
|
||||
<StackPane>
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="6"/>
|
||||
</padding>
|
||||
<HBox spacing="12" alignment="CENTER_LEFT" VBox.vgrow="ALWAYS">
|
||||
<StackPane alignment="CENTER" HBox.hgrow="NEVER">
|
||||
<Circle styleClass="glyph-icon-primary" radius="24"/>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="QUESTION" glyphSize="24"/>
|
||||
</StackPane>
|
||||
</Group>
|
||||
<VBox HBox.hgrow="ALWAYS">
|
||||
<Label styleClass="label-large" text="%removeVault.message" wrapText="true" textAlignment="LEFT">
|
||||
<padding>
|
||||
<Insets bottom="6" top="6"/>
|
||||
</padding>
|
||||
</Label>
|
||||
<Label text="%removeVault.description" wrapText="true" textAlignment="LEFT" />
|
||||
<Label text="%removeVault.information" wrapText="true" textAlignment="LEFT" HBox.hgrow="ALWAYS"/>
|
||||
</HBox>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
|
||||
<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+CI">
|
||||
<buttons>
|
||||
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" defaultButton="true" cancelButton="true" onAction="#close"/>
|
||||
@@ -49,4 +37,4 @@
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
</children>
|
||||
</HBox>
|
||||
</VBox>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<Arc styleClass="cache-arc-foreground" centerX="100" centerY="100" radiusX="100" radiusY="100" startAngle="225" length="${controller.cacheHitDegrees}"/>
|
||||
</Group>
|
||||
<VBox StackPane.alignment="CENTER" alignment="CENTER">
|
||||
<FormattedLabel styleClass="label-extra-large" format="\%1.0f %%" arg1="${controller.cacheHitPercentage}"/>
|
||||
<FormattedLabel styleClass="label-large" format="\%1.0f %%" arg1="${controller.cacheHitPercentage}"/>
|
||||
<Label text="%stats.cacheHitRate"/>
|
||||
</VBox>
|
||||
</StackPane>
|
||||
|
||||
@@ -5,50 +5,45 @@
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.ButtonBar?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.Group?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.Circle?>
|
||||
<HBox xmlns:fx="http://javafx.com/fxml"
|
||||
<?import javafx.scene.text.Text?>
|
||||
<VBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.unlock.UnlockInvalidMountPointController"
|
||||
minWidth="400"
|
||||
maxWidth="400"
|
||||
minHeight="145"
|
||||
spacing="12"
|
||||
alignment="TOP_LEFT">
|
||||
spacing="12">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<Group>
|
||||
<StackPane>
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="6"/>
|
||||
</padding>
|
||||
<HBox spacing="12" VBox.vgrow="ALWAYS">
|
||||
<StackPane alignment="CENTER" HBox.hgrow="NEVER">
|
||||
<Circle styleClass="glyph-icon-red" radius="24"/>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="TIMES" glyphSize="24"/>
|
||||
</StackPane>
|
||||
</Group>
|
||||
<VBox HBox.hgrow="ALWAYS">
|
||||
<Label styleClass="label-large" text="%unlock.error.message" wrapText="true" textAlignment="LEFT">
|
||||
<padding>
|
||||
<Insets bottom="6" top="6"/>
|
||||
</padding>
|
||||
</Label>
|
||||
<FormattedLabel visible="${controller.notExisting}" managed="${controller.notExisting}" format="%unlock.error.invalidMountPoint.notExisting" arg1="${controller.mountPoint}" wrapText="true"/>
|
||||
<FormattedLabel visible="${controller.existing}" managed="${controller.existing}" format="%unlock.error.invalidMountPoint.existing" arg1="${controller.mountPoint}" wrapText="true"/>
|
||||
<FormattedLabel visible="${controller.driveLetterOccupied}" managed="${controller.driveLetterOccupied}" format="%unlock.error.invalidMountPoint.driveLetterOccupied" arg1="${controller.mountPoint}" wrapText="true"/>
|
||||
<VBox spacing="6" HBox.hgrow="ALWAYS">
|
||||
<Text text="%unlock.error.heading" styleClass="label-large"/>
|
||||
<FormattedLabel visible="${controller.notExisting}" managed="${controller.notExisting}" format="%unlock.error.invalidMountPoint.notExisting" arg1="${controller.mountPoint}" wrapText="true"/>
|
||||
<FormattedLabel visible="${controller.existing}" managed="${controller.existing}" format="%unlock.error.invalidMountPoint.existing" arg1="${controller.mountPoint}" wrapText="true"/>
|
||||
<FormattedLabel visible="${controller.driveLetterOccupied}" managed="${controller.driveLetterOccupied}" format="%unlock.error.invalidMountPoint.driveLetterOccupied" arg1="${controller.mountPoint}" wrapText="true"/>
|
||||
</VBox>
|
||||
</HBox>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+C">
|
||||
<Region VBox.vgrow="ALWAYS"/>
|
||||
|
||||
<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="U+C">
|
||||
<buttons>
|
||||
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#close"/>
|
||||
<Region ButtonBar.buttonData="OTHER"/>
|
||||
<Button text="%generic.button.back" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#close"/>
|
||||
</buttons>
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
</children>
|
||||
</HBox>
|
||||
</VBox>
|
||||
|
||||
@@ -9,45 +9,34 @@
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.Circle?>
|
||||
<?import javafx.scene.Group?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import org.cryptomator.ui.controls.FormattedLabel?>
|
||||
<HBox xmlns:fx="http://javafx.com/fxml"
|
||||
<VBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.keyloading.masterkeyfile.ChooseMasterkeyFileController"
|
||||
minWidth="400"
|
||||
maxWidth="400"
|
||||
minHeight="145"
|
||||
spacing="12"
|
||||
alignment="TOP_LEFT">
|
||||
spacing="12">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<Group>
|
||||
<StackPane>
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="6"/>
|
||||
</padding>
|
||||
<HBox spacing="12" alignment="CENTER_LEFT" VBox.vgrow="ALWAYS">
|
||||
<StackPane alignment="CENTER" HBox.hgrow="NEVER">
|
||||
<Circle styleClass="glyph-icon-primary" radius="24"/>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="SEARCH" glyphSize="24"/>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="FILE" glyphSize="24"/>
|
||||
</StackPane>
|
||||
</Group>
|
||||
<VBox HBox.hgrow="ALWAYS">
|
||||
<Label styleClass="label-large" text="%unlock.chooseMasterkey.message" wrapText="true" textAlignment="LEFT">
|
||||
<padding>
|
||||
<Insets bottom="6" top="6"/>
|
||||
</padding>
|
||||
</Label>
|
||||
<FormattedLabel format="%unlock.chooseMasterkey.description" arg1="${controller.displayName}" wrapText="true"/>
|
||||
<VBox spacing="6">
|
||||
<Label text="%unlock.chooseMasterkey.prompt" wrapText="true" HBox.hgrow="ALWAYS"/>
|
||||
</VBox>
|
||||
</HBox>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
|
||||
<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+CX">
|
||||
<buttons>
|
||||
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#cancel"/>
|
||||
<Button text="%generic.button.choose" ButtonBar.buttonData="NEXT_FORWARD" defaultButton="true" onAction="#proceed"/>
|
||||
<Button text="%unlock.chooseMasterkey.chooseBtn" ButtonBar.buttonData="NEXT_FORWARD" defaultButton="true" onAction="#proceed"/>
|
||||
</buttons>
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
</children>
|
||||
</HBox>
|
||||
</VBox>
|
||||
|
||||
@@ -11,47 +11,29 @@
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.Circle?>
|
||||
<?import javafx.scene.Group?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<HBox xmlns:fx="http://javafx.com/fxml"
|
||||
<VBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.unlock.UnlockSuccessController"
|
||||
minWidth="400"
|
||||
maxWidth="400"
|
||||
minHeight="145"
|
||||
spacing="12"
|
||||
alignment="TOP_LEFT">
|
||||
spacing="12">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<Group>
|
||||
<StackPane>
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="6"/>
|
||||
</padding>
|
||||
<HBox spacing="12" alignment="CENTER_LEFT" VBox.vgrow="ALWAYS">
|
||||
<StackPane alignment="CENTER" HBox.hgrow="NEVER">
|
||||
<Circle styleClass="glyph-icon-primary" radius="24"/>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="CHECK" glyphSize="24"/>
|
||||
</StackPane>
|
||||
</Group>
|
||||
<VBox spacing="6">
|
||||
<FormattedLabel format="%unlock.success.message" arg1="${controller.vault.displayName}" wrapText="true" HBox.hgrow="ALWAYS"/>
|
||||
<CheckBox text="%unlock.success.rememberChoice" fx:id="rememberChoiceCheckbox"/>
|
||||
</VBox>
|
||||
</HBox>
|
||||
|
||||
<VBox HBox.hgrow="ALWAYS">
|
||||
<Label styleClass="label-large" text="%unlock.success.message" wrapText="true" textAlignment="LEFT">
|
||||
<padding>
|
||||
<Insets bottom="6" top="6"/>
|
||||
</padding>
|
||||
</Label>
|
||||
|
||||
<FormattedLabel format="%unlock.success.description" arg1="${controller.vault.displayName}" wrapText="true"/>
|
||||
|
||||
<CheckBox text="%unlock.success.rememberChoice" fx:id="rememberChoiceCheckbox">
|
||||
<padding>
|
||||
<Insets top="18"/>
|
||||
</padding>
|
||||
</CheckBox>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
|
||||
<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+CI">
|
||||
<buttons>
|
||||
<Button text="%generic.button.done" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#close"/>
|
||||
@@ -64,4 +46,4 @@
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
</children>
|
||||
</HBox>
|
||||
</VBox>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user