mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-22 04:31:27 +00:00
Merge branch 'develop' into feature/3233-locationpresets-background
This commit is contained in:
10
.github/workflows/appimage.yml
vendored
10
.github/workflows/appimage.yml
vendored
@@ -29,12 +29,12 @@ jobs:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
appimage-suffix: x86_64
|
||||
openjfx-url: 'https://download2.gluonhq.com/openjfx/20.0.2/openjfx-20.0.2_linux-x64_bin-jmods.zip'
|
||||
openjfx-sha: 'f522ac2ae4bdd61f0219b7b8d2058ff72a22f36a44378453bcfdcd82f8f5e08c'
|
||||
openjfx-url: 'https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_linux-x64_bin-jmods.zip'
|
||||
openjfx-sha: '7baed11ca56d5fee85995fa6612d4299f1e8b7337287228f7f12fd50407c56f8'
|
||||
- os: [self-hosted, Linux, ARM64]
|
||||
appimage-suffix: aarch64
|
||||
openjfx-url: 'https://download2.gluonhq.com/openjfx/20.0.2/openjfx-20.0.2_linux-aarch64_bin-jmods.zip'
|
||||
openjfx-sha: 'c0d80ebbe0aab404ef9ad8b46c05bf533a1e40b39b2720eebd9238d81f6326ca'
|
||||
openjfx-url: 'https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_linux-aarch64_bin-jmods.zip'
|
||||
openjfx-sha: '871e7b9d7af16aef2e55c1b7830d0e0b2503b13dd8641374ba7e55ecb81d2ef9'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Java
|
||||
@@ -74,6 +74,7 @@ jobs:
|
||||
cp LICENSE.txt target
|
||||
cp target/cryptomator-*.jar target/mods
|
||||
- name: Run jlink
|
||||
#Remark: no compression is applied for improved build compression later (here appimage)
|
||||
run: >
|
||||
${JAVA_HOME}/bin/jlink
|
||||
--verbose
|
||||
@@ -84,6 +85,7 @@ jobs:
|
||||
--no-header-files
|
||||
--no-man-pages
|
||||
--strip-debug
|
||||
--compress zip-0
|
||||
- name: Prepare additional launcher
|
||||
run: envsubst '${SEMVER_STR} ${REVISION_NUM}' < dist/linux/launcher-gtk2.properties > launcher-gtk2.properties
|
||||
env:
|
||||
|
||||
8
.github/workflows/debian.yml
vendored
8
.github/workflows/debian.yml
vendored
@@ -20,10 +20,10 @@ env:
|
||||
JAVA_VERSION: '21.0.1+12'
|
||||
COFFEELIBS_JDK: 21
|
||||
COFFEELIBS_JDK_VERSION: '21.0.1+12-0ppa1'
|
||||
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/20.0.2/openjfx-20.0.2_linux-x64_bin-jmods.zip'
|
||||
OPENJFX_JMODS_AMD64_HASH: 'f522ac2ae4bdd61f0219b7b8d2058ff72a22f36a44378453bcfdcd82f8f5e08c'
|
||||
OPENJFX_JMODS_AARCH64: 'https://download2.gluonhq.com/openjfx/20.0.2/openjfx-20.0.2_linux-aarch64_bin-jmods.zip'
|
||||
OPENJFX_JMODS_AARCH64_HASH: 'c0d80ebbe0aab404ef9ad8b46c05bf533a1e40b39b2720eebd9238d81f6326ca'
|
||||
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_linux-x64_bin-jmods.zip'
|
||||
OPENJFX_JMODS_AMD64_HASH: '7baed11ca56d5fee85995fa6612d4299f1e8b7337287228f7f12fd50407c56f8'
|
||||
OPENJFX_JMODS_AARCH64: 'https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_linux-aarch64_bin-jmods.zip'
|
||||
OPENJFX_JMODS_AARCH64_HASH: '871e7b9d7af16aef2e55c1b7830d0e0b2503b13dd8641374ba7e55ecb81d2ef9'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
55
.github/workflows/dependency-check.yml
vendored
55
.github/workflows/dependency-check.yml
vendored
@@ -7,50 +7,11 @@ on:
|
||||
|
||||
jobs:
|
||||
check-dependencies:
|
||||
name: Check dependencies
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
show-progress: false
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 21
|
||||
cache: 'maven'
|
||||
- name: Cache NVD DB
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.m2/repository/org/owasp/dependency-check-data/
|
||||
key: dependency-check-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
dependency-check
|
||||
env:
|
||||
SEGMENT_DOWNLOAD_TIMEOUT_MINS: 5
|
||||
- name: Run org.owasp:dependency-check plugin
|
||||
id: dependency-check
|
||||
continue-on-error: true
|
||||
run: mvn -B validate -Pdependency-check
|
||||
env:
|
||||
NVD_API_KEY: ${{ secrets.NVD_API_KEY }}
|
||||
- name: Upload report on failure
|
||||
if: steps.dependency-check.outcome == 'failure'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: dependency-check-report
|
||||
path: target/dependency-check-report.html
|
||||
if-no-files-found: error
|
||||
- name: Slack Notification on regular check
|
||||
if: github.event_name == 'schedule' && steps.dependency-check.outcome == 'failure'
|
||||
uses: rtCamp/action-slack-notify@v2
|
||||
env:
|
||||
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
SLACK_USERNAME: 'Cryptobot'
|
||||
SLACK_ICON: false
|
||||
SLACK_ICON_EMOJI: ':bot:'
|
||||
SLACK_CHANNEL: 'cryptomator-desktop'
|
||||
SLACK_TITLE: "Vulnerabilities in ${{ github.event.repository.name }} detected."
|
||||
SLACK_MESSAGE: "Download the <https://github.com/${{ github.repository }}/actions/run/${{ github.run_id }}|report> for more details."
|
||||
SLACK_FOOTER: false
|
||||
MSG_MINIMAL: true
|
||||
uses: skymatic/workflows/.github/workflows/run-dependency-check.yml@main
|
||||
with:
|
||||
runner-os: 'ubuntu-latest'
|
||||
java-distribution: 'temurin'
|
||||
java-version: 21
|
||||
secrets:
|
||||
nvd-api-key: ${{ secrets.NVD_API_KEY }}
|
||||
slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
|
||||
10
.github/workflows/mac-dmg.yml
vendored
10
.github/workflows/mac-dmg.yml
vendored
@@ -37,15 +37,15 @@ jobs:
|
||||
output-suffix: x64
|
||||
xcode-path: '/Applications/Xcode_13.2.1.app'
|
||||
fuse-lib: macFUSE
|
||||
openjfx-url: 'https://download2.gluonhq.com/openjfx/20.0.2/openjfx-20.0.2_osx-x64_bin-jmods.zip'
|
||||
openjfx-sha: '55b8ff7453d59c89ae129f6c9c5ad7b09a5d359568811b376ac1766c14d6a17c'
|
||||
openjfx-url: 'https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_osx-x64_bin-jmods.zip'
|
||||
openjfx-sha: 'bd6abab20da73d5a968dcf2fd915d81b5fb919340e3bb84979ee9a888a829939'
|
||||
- os: [self-hosted, macOS, ARM64]
|
||||
architecture: aarch64
|
||||
output-suffix: arm64
|
||||
xcode-path: '/Applications/Xcode_13.2.1.app'
|
||||
fuse-lib: FUSE-T
|
||||
openjfx-url: 'https://download2.gluonhq.com/openjfx/20.0.2/openjfx-20.0.2_osx-aarch64_bin-jmods.zip'
|
||||
openjfx-sha: 'c60f5f19aa847e0e620e0b011e5de68f2c6755641c2141cec27a0b89f612beaf'
|
||||
openjfx-url: 'https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_osx-aarch64_bin-jmods.zip'
|
||||
openjfx-sha: '7afaa1c57a6cc3c384d636e597b9a5364693e2db4aaec0a6e63d2fa964400b58'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Java
|
||||
@@ -85,6 +85,7 @@ jobs:
|
||||
cp LICENSE.txt target
|
||||
cp target/cryptomator-*.jar target/mods
|
||||
- name: Run jlink
|
||||
#Remark: no compression is applied for improved build compression later (here dmg)
|
||||
run: >
|
||||
${JAVA_HOME}/bin/jlink
|
||||
--verbose
|
||||
@@ -95,6 +96,7 @@ jobs:
|
||||
--no-header-files
|
||||
--no-man-pages
|
||||
--strip-debug
|
||||
--compress zip-0
|
||||
- name: Run jpackage
|
||||
run: >
|
||||
${JAVA_HOME}/bin/jpackage
|
||||
|
||||
6
.github/workflows/win-exe.yml
vendored
6
.github/workflows/win-exe.yml
vendored
@@ -16,8 +16,8 @@ on:
|
||||
env:
|
||||
JAVA_DIST: 'zulu'
|
||||
JAVA_VERSION: '21.0.1+12'
|
||||
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/20.0.2/openjfx-20.0.2_windows-x64_bin-jmods.zip'
|
||||
OPENJFX_JMODS_AMD64_HASH: '18625bbc13c57dbf802486564247a8d8cab72ec558c240a401bf6440384ebd77'
|
||||
OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_windows-x64_bin-jmods.zip'
|
||||
OPENJFX_JMODS_AMD64_HASH: 'daf8acae631c016c24cfe23f88469400274d3441dd890615a42dfb501f3eb94a'
|
||||
WINFSP_MSI: 'https://github.com/winfsp/winfsp/releases/download/v2.0/winfsp-2.0.23075.msi'
|
||||
WINFSP_UNINSTALLER: 'https://github.com/cryptomator/winfsp-uninstaller/releases/download/1.0.0/winfsp-uninstaller.exe'
|
||||
|
||||
@@ -79,6 +79,7 @@ jobs:
|
||||
cp LICENSE.txt target
|
||||
cp target/cryptomator-*.jar target/mods
|
||||
- name: Run jlink
|
||||
#Remark: no compression is applied for improved build compression later (here msi)
|
||||
run: >
|
||||
${JAVA_HOME}/bin/jlink
|
||||
--verbose
|
||||
@@ -89,6 +90,7 @@ jobs:
|
||||
--no-header-files
|
||||
--no-man-pages
|
||||
--strip-debug
|
||||
--compress zip-0
|
||||
- name: Change win-console flag if debug is active
|
||||
if: ${{ inputs.isDebug }}
|
||||
run: echo "WIN_CONSOLE_FLAG=--win-console" >> $GITHUB_ENV
|
||||
|
||||
11
dist/linux/appimage/build.sh
vendored
11
dist/linux/appimage/build.sh
vendored
@@ -25,10 +25,10 @@ cp ../../../target/cryptomator-*.jar ../../../target/mods
|
||||
|
||||
|
||||
# download javaFX jmods
|
||||
OPENJFX_URL='https://download2.gluonhq.com/openjfx/20.0.2/openjfx-20.0.2_linux-x64_bin-jmods.zip' #by default we assume x64
|
||||
OPENJFX_SHA='f522ac2ae4bdd61f0219b7b8d2058ff72a22f36a44378453bcfdcd82f8f5e08c'
|
||||
OPENJFX_URL_aarch64='https://download2.gluonhq.com/openjfx/20.0.2/openjfx-20.0.2_linux-aarch64_bin-jmods.zip'
|
||||
OPENJFX_SHA_aarch64='c0d80ebbe0aab404ef9ad8b46c05bf533a1e40b39b2720eebd9238d81f6326ca'
|
||||
OPENJFX_URL='https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_linux-x64_bin-jmods.zip'
|
||||
OPENJFX_SHA='7baed11ca56d5fee85995fa6612d4299f1e8b7337287228f7f12fd50407c56f8'
|
||||
OPENJFX_URL_aarch64='https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_linux-aarch64_bin-jmods.zip'
|
||||
OPENJFX_SHA_aarch64='871e7b9d7af16aef2e55c1b7830d0e0b2503b13dd8641374ba7e55ecb81d2ef9'
|
||||
|
||||
if [[ "${MACHINE_TYPE}" = "aarch64" ]]; then
|
||||
OPENJFX_URL="${OPENJFX_URL_aarch64}";
|
||||
@@ -60,7 +60,8 @@ ${JAVA_HOME}/bin/jlink \
|
||||
--strip-native-commands \
|
||||
--no-header-files \
|
||||
--no-man-pages \
|
||||
--strip-debug
|
||||
--strip-debug \
|
||||
--compress zip-0
|
||||
|
||||
# create app dir
|
||||
envsubst '${SEMVER_STR} ${REVISION_NUM}' < ../launcher-gtk2.properties > launcher-gtk2.properties
|
||||
|
||||
4
dist/linux/debian/rules
vendored
4
dist/linux/debian/rules
vendored
@@ -24,6 +24,7 @@ override_dh_auto_clean:
|
||||
override_dh_auto_build:
|
||||
mkdir resources
|
||||
ln -s ../common/org.cryptomator.Cryptomator512.png resources/cryptomator.png
|
||||
# Remark: no compression is applied for improved build compression later (here deb)
|
||||
$(JAVA_HOME)/bin/jlink \
|
||||
--output runtime \
|
||||
--module-path "${JMODS_PATH}" \
|
||||
@@ -31,7 +32,8 @@ override_dh_auto_build:
|
||||
--strip-native-commands \
|
||||
--no-header-files \
|
||||
--no-man-pages \
|
||||
--strip-debug
|
||||
--strip-debug \
|
||||
--compress zip-0
|
||||
$(JAVA_HOME)/bin/jpackage \
|
||||
--type app-image \
|
||||
--runtime-image runtime \
|
||||
|
||||
4
dist/mac/dmg/build.sh
vendored
4
dist/mac/dmg/build.sh
vendored
@@ -35,7 +35,7 @@ if [ "$(machine)" = "arm64e" ]; then
|
||||
else
|
||||
ARCH="x64"
|
||||
fi
|
||||
OPENJFX_JMODS="https://download2.gluonhq.com/openjfx/20.0.2/openjfx-20.0.2_osx-${ARCH}_bin-jmods.zip"
|
||||
OPENJFX_JMODS="https://download2.gluonhq.com/openjfx/21.0.1/openjfx-21.0.1_osx-${ARCH}_bin-jmods.zip"
|
||||
|
||||
# check preconditions
|
||||
if [ -z "${JAVA_HOME}" ]; then echo "JAVA_HOME not set. Run using JAVA_HOME=/path/to/jdk ./build.sh"; exit 1; fi
|
||||
@@ -76,7 +76,7 @@ ${JAVA_HOME}/bin/jlink \
|
||||
--no-header-files \
|
||||
--no-man-pages \
|
||||
--strip-debug \
|
||||
--compress=1
|
||||
--compress zip-0
|
||||
|
||||
# create app dir
|
||||
${JAVA_HOME}/bin/jpackage \
|
||||
|
||||
9
dist/win/build.ps1
vendored
9
dist/win/build.ps1
vendored
@@ -51,9 +51,9 @@ if ($clean -and (Test-Path -Path $runtimeImagePath)) {
|
||||
}
|
||||
|
||||
## download jfx jmods
|
||||
$jmodsVersion='20.0.2'
|
||||
$jmodsVersion='21.0.1'
|
||||
$jmodsUrl = "https://download2.gluonhq.com/openjfx/${jmodsVersion}/openjfx-${jmodsVersion}_windows-x64_bin-jmods.zip"
|
||||
$jfxJmodsChecksum = '18625bbc13c57dbf802486564247a8d8cab72ec558c240a401bf6440384ebd77'
|
||||
$jfxJmodsChecksum = 'daf8acae631c016c24cfe23f88469400274d3441dd890615a42dfb501f3eb94a'
|
||||
$jfxJmodsZip = '.\resources\jfxJmods.zip'
|
||||
if( !(Test-Path -Path $jfxJmodsZip) ) {
|
||||
Write-Output "Downloading ${jmodsUrl}..."
|
||||
@@ -69,7 +69,7 @@ Expand-Archive -Path $jfxJmodsZip -Force -DestinationPath ".\resources\"
|
||||
Remove-Item -Recurse -Force -Path ".\resources\javafx-jmods"
|
||||
Move-Item -Force -Path ".\resources\javafx-jmods-*" -Destination ".\resources\javafx-jmods" -ErrorAction Stop
|
||||
|
||||
|
||||
## create custom runtime
|
||||
& "$Env:JAVA_HOME\bin\jlink" `
|
||||
--verbose `
|
||||
--output runtime `
|
||||
@@ -78,7 +78,8 @@ Move-Item -Force -Path ".\resources\javafx-jmods-*" -Destination ".\resources\ja
|
||||
--strip-native-commands `
|
||||
--no-header-files `
|
||||
--no-man-pages `
|
||||
--strip-debug
|
||||
--strip-debug `
|
||||
--compress "zip-0" #do not compress to have improved msi compression
|
||||
|
||||
$appPath = ".\$AppName"
|
||||
if ($clean -and (Test-Path -Path $appPath)) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.cryptomator.ui.keyloading.hub;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.net.URI;
|
||||
@@ -19,6 +18,12 @@ public class HubConfig {
|
||||
@Deprecated // use apiBaseUrl + "/devices/"
|
||||
public String devicesResourceUrl;
|
||||
|
||||
/**
|
||||
* Get the URI pointing to the <code>/api/</code> base resource.
|
||||
*
|
||||
* @return <code>/api/</code> URI
|
||||
* @apiNote URI is guaranteed to end on <code>/</code>
|
||||
*/
|
||||
public URI getApiBaseUrl() {
|
||||
if (apiBaseUrl != null) {
|
||||
// make sure to end on "/":
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.cryptomator.ui.keyloading.hub;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.nimbusds.jose.JWEObject;
|
||||
import dagger.Lazy;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
@@ -46,6 +47,7 @@ public class ReceiveKeyController implements FxController {
|
||||
|
||||
private final Stage window;
|
||||
private final HubConfig hubConfig;
|
||||
private final String vaultId;
|
||||
private final String deviceId;
|
||||
private final String bearerToken;
|
||||
private final CompletableFuture<ReceivedKey> result;
|
||||
@@ -53,14 +55,15 @@ public class ReceiveKeyController implements FxController {
|
||||
private final Lazy<Scene> legacyRegisterDeviceScene;
|
||||
private final Lazy<Scene> unauthorizedScene;
|
||||
private final Lazy<Scene> accountInitializationScene;
|
||||
private final URI vaultBaseUri;
|
||||
private final Lazy<Scene> invalidLicenseScene;
|
||||
private final HttpClient httpClient;
|
||||
private final StringTemplate.Processor<URI, RuntimeException> API_BASE = this::resolveRelativeToApiBase;
|
||||
|
||||
@Inject
|
||||
public ReceiveKeyController(@KeyLoading Vault vault, ExecutorService executor, @KeyLoading Stage window, HubConfig hubConfig, @Named("deviceId") String deviceId, @Named("bearerToken") AtomicReference<String> tokenRef, CompletableFuture<ReceivedKey> result, @FxmlScene(FxmlFile.HUB_REGISTER_DEVICE) Lazy<Scene> registerDeviceScene, @FxmlScene(FxmlFile.HUB_LEGACY_REGISTER_DEVICE) Lazy<Scene> legacyRegisterDeviceScene, @FxmlScene(FxmlFile.HUB_UNAUTHORIZED_DEVICE) Lazy<Scene> unauthorizedScene, @FxmlScene(FxmlFile.HUB_REQUIRE_ACCOUNT_INIT) Lazy<Scene> accountInitializationScene, @FxmlScene(FxmlFile.HUB_INVALID_LICENSE) Lazy<Scene> invalidLicenseScene) {
|
||||
this.window = window;
|
||||
this.hubConfig = hubConfig;
|
||||
this.vaultId = extractVaultId(vault.getVaultConfigCache().getUnchecked().getKeyId()); // TODO: access vault config's JTI directly (requires changes in cryptofs)
|
||||
this.deviceId = deviceId;
|
||||
this.bearerToken = Objects.requireNonNull(tokenRef.get());
|
||||
this.result = result;
|
||||
@@ -68,7 +71,6 @@ public class ReceiveKeyController implements FxController {
|
||||
this.legacyRegisterDeviceScene = legacyRegisterDeviceScene;
|
||||
this.unauthorizedScene = unauthorizedScene;
|
||||
this.accountInitializationScene = accountInitializationScene;
|
||||
this.vaultBaseUri = getVaultBaseUri(vault);
|
||||
this.invalidLicenseScene = invalidLicenseScene;
|
||||
this.window.addEventHandler(WindowEvent.WINDOW_HIDING, this::windowClosed);
|
||||
this.httpClient = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).executor(executor).build();
|
||||
@@ -76,70 +78,76 @@ public class ReceiveKeyController implements FxController {
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
requestVaultMasterkey();
|
||||
receiveKey();
|
||||
}
|
||||
|
||||
public void receiveKey() {
|
||||
requestApiConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* STEP 1 (Request): GET vault key for this user
|
||||
* STEP 0 (Request): GET /api/config
|
||||
*/
|
||||
private void requestVaultMasterkey() {
|
||||
var accessTokenUri = appendPath(vaultBaseUri, "/access-token");
|
||||
var request = HttpRequest.newBuilder(accessTokenUri) //
|
||||
.header("Authorization", "Bearer " + bearerToken) //
|
||||
private void requestApiConfig() {
|
||||
var configUri = API_BASE."config";
|
||||
var request = HttpRequest.newBuilder(configUri) //
|
||||
.GET() //
|
||||
.timeout(REQ_TIMEOUT) //
|
||||
.build();
|
||||
httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.US_ASCII)) //
|
||||
.thenAcceptAsync(this::receivedVaultMasterkey, Platform::runLater) //
|
||||
.thenAcceptAsync(this::receivedApiConfig, Platform::runLater) //
|
||||
.exceptionally(this::retrievalFailed);
|
||||
}
|
||||
|
||||
/**
|
||||
* STEP 1 (Response): GET vault key for this user
|
||||
* STEP 0 (Response): GET /api/config
|
||||
*
|
||||
* @param response Response
|
||||
*/
|
||||
private void receivedVaultMasterkey(HttpResponse<String> response) {
|
||||
private void receivedApiConfig(HttpResponse<String> response) {
|
||||
LOG.debug("GET {} -> Status Code {}", response.request().uri(), response.statusCode());
|
||||
switch (response.statusCode()) {
|
||||
case 200 -> requestUserKey(response.body());
|
||||
case 402 -> licenseExceeded();
|
||||
case 403, 410 -> accessNotGranted(); // or vault has been archived, effectively disallowing access - TODO: add specific dialog?
|
||||
case 449 -> accountInitializationRequired();
|
||||
case 404 -> requestLegacyAccessToken();
|
||||
default -> throw new IllegalStateException("Unexpected response " + response.statusCode());
|
||||
Preconditions.checkState(response.statusCode() == 200, "Unexpected response " + response.statusCode());
|
||||
try {
|
||||
var config = JSON.reader().readValue(response.body(), ConfigDto.class);
|
||||
if (config.apiLevel >= 1) {
|
||||
requestDeviceData();
|
||||
} else {
|
||||
requestLegacyAccessToken();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* STEP 2 (Request): GET user key for this device
|
||||
* STEP 1 (Request): GET user key for this device
|
||||
*/
|
||||
private void requestUserKey(String encryptedVaultKey) {
|
||||
var deviceTokenUri = URI.create(hubConfig.getApiBaseUrl() + "/devices/" + deviceId);
|
||||
var request = HttpRequest.newBuilder(deviceTokenUri) //
|
||||
private void requestDeviceData() {
|
||||
var deviceUri = API_BASE."devices/\{deviceId}";
|
||||
var request = HttpRequest.newBuilder(deviceUri) //
|
||||
.header("Authorization", "Bearer " + bearerToken) //
|
||||
.GET() //
|
||||
.timeout(REQ_TIMEOUT) //
|
||||
.build();
|
||||
httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)) //
|
||||
.thenAcceptAsync(response -> receivedUserKey(encryptedVaultKey, response), Platform::runLater) //
|
||||
.thenAcceptAsync(this::receivedDeviceData) //
|
||||
.exceptionally(this::retrievalFailed);
|
||||
}
|
||||
|
||||
/**
|
||||
* STEP 2 (Response): GET user key for this device
|
||||
* STEP 1 (Response): GET user key for this device
|
||||
*
|
||||
* @param response Response
|
||||
*/
|
||||
private void receivedUserKey(String encryptedVaultKey, HttpResponse<String> response) {
|
||||
private void receivedDeviceData(HttpResponse<String> response) {
|
||||
LOG.debug("GET {} -> Status Code {}", response.request().uri(), response.statusCode());
|
||||
try {
|
||||
switch (response.statusCode()) {
|
||||
case 200 -> {
|
||||
var device = JSON.reader().readValue(response.body(), DeviceDto.class);
|
||||
receivedBothEncryptedKeys(encryptedVaultKey, device.userPrivateKey);
|
||||
requestVaultMasterkey(device.userPrivateKey);
|
||||
}
|
||||
case 404 -> needsDeviceRegistration(); // TODO: using the setup code, we can theoretically immediately unlock
|
||||
case 404 -> Platform.runLater(this::needsDeviceRegistration);
|
||||
default -> throw new IllegalStateException("Unexpected response " + response.statusCode());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
@@ -151,14 +159,45 @@ public class ReceiveKeyController implements FxController {
|
||||
window.setScene(registerDeviceScene.get());
|
||||
}
|
||||
|
||||
private void receivedBothEncryptedKeys(String encryptedVaultKey, String encryptedUserKey) throws IOException {
|
||||
/**
|
||||
* STEP 2 (Request): GET vault key for this user
|
||||
*/
|
||||
private void requestVaultMasterkey(String encryptedUserKey) {
|
||||
var vaultKeyUri = API_BASE."vaults/\{vaultId}/access-token";
|
||||
var request = HttpRequest.newBuilder(vaultKeyUri) //
|
||||
.header("Authorization", "Bearer " + bearerToken) //
|
||||
.GET() //
|
||||
.timeout(REQ_TIMEOUT) //
|
||||
.build();
|
||||
httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.US_ASCII)) //
|
||||
.thenAcceptAsync(response -> receivedVaultMasterkey(encryptedUserKey, response), Platform::runLater) //
|
||||
.exceptionally(this::retrievalFailed);
|
||||
}
|
||||
|
||||
/**
|
||||
* STEP 2 (Response): GET vault key for this user
|
||||
*
|
||||
* @param response Response
|
||||
*/
|
||||
private void receivedVaultMasterkey(String encryptedUserKey, HttpResponse<String> response) {
|
||||
LOG.debug("GET {} -> Status Code {}", response.request().uri(), response.statusCode());
|
||||
switch (response.statusCode()) {
|
||||
case 200 -> receivedBothEncryptedKeys(response.body(), encryptedUserKey);
|
||||
case 402 -> licenseExceeded();
|
||||
case 403, 410 -> accessNotGranted(); // or vault has been archived, effectively disallowing access - TODO: add specific dialog?
|
||||
case 449 -> accountInitializationRequired();
|
||||
default -> throw new IllegalStateException("Unexpected response " + response.statusCode());
|
||||
}
|
||||
}
|
||||
|
||||
private void receivedBothEncryptedKeys(String encryptedVaultKey, String encryptedUserKey) {
|
||||
try {
|
||||
var vaultKeyJwe = JWEObject.parse(encryptedVaultKey);
|
||||
var userKeyJwe = JWEObject.parse(encryptedUserKey);
|
||||
result.complete(ReceivedKey.vaultKeyAndUserKey(vaultKeyJwe, userKeyJwe));
|
||||
window.close();
|
||||
} catch (ParseException e) {
|
||||
throw new IOException("Failed to parse JWE", e);
|
||||
retrievalFailed(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +206,7 @@ public class ReceiveKeyController implements FxController {
|
||||
*/
|
||||
@Deprecated
|
||||
private void requestLegacyAccessToken() {
|
||||
var legacyAccessTokenUri = appendPath(vaultBaseUri, "/keys/" + deviceId);
|
||||
var legacyAccessTokenUri = API_BASE."vaults/\{vaultId}/keys/\{deviceId}";
|
||||
var request = HttpRequest.newBuilder(legacyAccessTokenUri) //
|
||||
.header("Authorization", "Bearer " + bearerToken) //
|
||||
.GET() //
|
||||
@@ -249,19 +288,21 @@ public class ReceiveKeyController implements FxController {
|
||||
}
|
||||
}
|
||||
|
||||
private static URI getVaultBaseUri(Vault vault) {
|
||||
try {
|
||||
var url = vault.getVaultConfigCache().get().getKeyId();
|
||||
assert url.getScheme().startsWith(SCHEME_PREFIX);
|
||||
var correctedScheme = url.getScheme().substring(SCHEME_PREFIX.length());
|
||||
return new URI(correctedScheme, url.getSchemeSpecificPart(), url.getFragment());
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
} catch (URISyntaxException e) {
|
||||
throw new IllegalStateException("URI constructed from params known to be valid", e);
|
||||
}
|
||||
private URI resolveRelativeToApiBase(StringTemplate template) {
|
||||
var path = template.interpolate();
|
||||
var relPath = path.startsWith("/") ? path.substring(1) : path;
|
||||
return hubConfig.getApiBaseUrl().resolve(relPath);
|
||||
}
|
||||
|
||||
private static String extractVaultId(URI vaultKeyUri) {
|
||||
assert vaultKeyUri.getScheme().startsWith(SCHEME_PREFIX);
|
||||
var path = vaultKeyUri.getPath();
|
||||
return path.substring(path.lastIndexOf('/') + 1);
|
||||
}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
private record DeviceDto(@JsonProperty(value = "userPrivateKey", required = true) String userPrivateKey) {}
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
private record ConfigDto(@JsonProperty(value = "apiLevel") int apiLevel) {}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,43 @@
|
||||
package org.cryptomator.ui.keyloading.hub;
|
||||
|
||||
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 javax.inject.Inject;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.WindowEvent;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class RegisterSuccessController implements FxController {
|
||||
|
||||
private final Stage window;
|
||||
private final CompletableFuture<ReceivedKey> result;
|
||||
private final Lazy<Scene> receiveKeyScene;
|
||||
private final ReceiveKeyController receiveKeyController;
|
||||
|
||||
@Inject
|
||||
public RegisterSuccessController(@KeyLoading Stage window) {
|
||||
public RegisterSuccessController(@KeyLoading Stage window, CompletableFuture<ReceivedKey> result, @FxmlScene(FxmlFile.HUB_RECEIVE_KEY) Lazy<Scene> receiveKeyScene, ReceiveKeyController receiveKeyController) {
|
||||
this.window = window;
|
||||
this.result = result;
|
||||
this.receiveKeyScene = receiveKeyScene;
|
||||
this.receiveKeyController = receiveKeyController;
|
||||
this.window.addEventHandler(WindowEvent.WINDOW_HIDING, this::windowClosed);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void close() {
|
||||
window.close();
|
||||
public void complete() {
|
||||
window.setScene(receiveKeyScene.get());
|
||||
receiveKeyController.receiveKey();
|
||||
}
|
||||
|
||||
private void windowClosed(WindowEvent windowEvent) {
|
||||
result.cancel(true);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.cryptomator.ui.vaultoptions;
|
||||
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.common.vaults.VaultState;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.keyloading.hub.HubKeyLoadingStrategy;
|
||||
import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingStrategy;
|
||||
@@ -48,6 +49,10 @@ public class VaultOptionsController implements FxController {
|
||||
if(!(vaultScheme.equals(HubKeyLoadingStrategy.SCHEME_HUB_HTTP) || vaultScheme.equals(HubKeyLoadingStrategy.SCHEME_HUB_HTTPS))){
|
||||
tabPane.getTabs().remove(hubTab);
|
||||
}
|
||||
|
||||
vault.stateProperty().addListener(observable -> {
|
||||
tabPane.setDisable(vault.getState().equals(VaultState.Value.UNLOCKED));
|
||||
});
|
||||
}
|
||||
|
||||
private void selectChosenTab() {
|
||||
|
||||
@@ -41,9 +41,9 @@
|
||||
<Label text="%hub.registerSuccess.description" wrapText="true"/>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS" minHeight="18"/>
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+C">
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+X">
|
||||
<buttons>
|
||||
<Button text="%generic.button.close" ButtonBar.buttonData="CANCEL_CLOSE" defaultButton="true" onAction="#close"/>
|
||||
<Button text="%generic.button.next" ButtonBar.buttonData="NEXT_FORWARD" defaultButton="true" onAction="#complete"/>
|
||||
<!-- TODO: add request access button -->
|
||||
</buttons>
|
||||
</ButtonBar>
|
||||
|
||||
@@ -163,6 +163,8 @@ hub.register.description=This is the first Hub access from this device. Please a
|
||||
hub.register.nameLabel=Device Name
|
||||
hub.register.invalidAccountKeyLabel=Invalid Account Key
|
||||
hub.register.registerBtn=Authorize
|
||||
### Register Device Legacy
|
||||
hub.register.occupiedMsg=Name already in use
|
||||
### Registration Success
|
||||
hub.registerSuccess.message=Device registered
|
||||
hub.registerSuccess.description=To access the vault, your device needs to be authorized by the vault owner.
|
||||
|
||||
Reference in New Issue
Block a user