mirror of
https://github.com/cryptomator/cryptomator.git
synced 2025-02-18 17:17:50 +00:00
Merge branch 'develop' into feature/mount-setting-per-vault
This commit is contained in:
commit
fd5aeaf90a
2
.github/workflows/appimage.yml
vendored
2
.github/workflows/appimage.yml
vendored
@ -16,7 +16,7 @@ jobs:
|
||||
get-version:
|
||||
uses: ./.github/workflows/get-version.yml
|
||||
with:
|
||||
version: ${{ github.event.inputs.version }}
|
||||
version: ${{ inputs.version }}
|
||||
|
||||
build:
|
||||
name: Build AppImage
|
||||
|
21
.github/workflows/debian.yml
vendored
21
.github/workflows/debian.yml
vendored
@ -30,11 +30,12 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.events.inputs.ref }}
|
||||
ref: ${{ inputs.ref }}
|
||||
fetch-depth: 0
|
||||
- id: versions
|
||||
name: Get version information
|
||||
run: |
|
||||
SEM_VER_STR="${{ github.events.inputs.semver }}"
|
||||
SEM_VER_STR="${{ inputs.semver }}"
|
||||
SEM_VER_NUM=`echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/'`
|
||||
REVCOUNT=`git rev-list --count HEAD`
|
||||
echo "semVerStr=${SEM_VER_STR}" >> $GITHUB_OUTPUT
|
||||
@ -91,7 +92,7 @@ jobs:
|
||||
cp -r jmods pkgdir
|
||||
cp -r dist/linux/common/ pkgdir
|
||||
cp target/cryptomator-*.jar pkgdir/mods
|
||||
tar -cJf cryptomator_${{ github.event.inputs.ppaver }}.orig.tar.xz -C pkgdir .
|
||||
tar -cJf cryptomator_${{ inputs.ppaver }}.orig.tar.xz -C pkgdir .
|
||||
- name: Patch and rename pkgdir
|
||||
run: |
|
||||
cp -r dist/linux/debian/ pkgdir
|
||||
@ -99,12 +100,12 @@ jobs:
|
||||
envsubst '${SEMVER_STR} ${VERSION_NUM} ${REVISION_NUM}' < dist/linux/debian/rules > pkgdir/debian/rules
|
||||
envsubst '${PPA_VERSION} ${RFC2822_TIMESTAMP}' < dist/linux/debian/changelog > pkgdir/debian/changelog
|
||||
find . -name "*.jar" >> pkgdir/debian/source/include-binaries
|
||||
mv pkgdir cryptomator_${{ github.event.inputs.ppaver }}
|
||||
mv pkgdir cryptomator_${{ inputs.ppaver }}
|
||||
env:
|
||||
SEMVER_STR: ${{ steps.versions.outputs.semVerStr }}
|
||||
VERSION_NUM: ${{ steps.versions.outputs.semVerNum }}
|
||||
REVISION_NUM: ${{ steps.versions.outputs.revNum }}
|
||||
PPA_VERSION: ${{ github.event.inputs.ppaver }}-0ppa1
|
||||
PPA_VERSION: ${{ inputs.ppaver }}-0ppa1
|
||||
- name: Prepare GPG-Agent for signing with key 615D449FE6E6A235
|
||||
run: |
|
||||
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
|
||||
@ -119,7 +120,7 @@ jobs:
|
||||
env:
|
||||
DEBSIGN_PROGRAM: gpg --batch --pinentry-mode loopback
|
||||
DEBSIGN_KEYID: 615D449FE6E6A235
|
||||
working-directory: cryptomator_${{ github.event.inputs.ppaver }}
|
||||
working-directory: cryptomator_${{ inputs.ppaver }}
|
||||
- name: Create detached GPG signatures
|
||||
run: |
|
||||
gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator_*_amd64.deb
|
||||
@ -141,16 +142,16 @@ jobs:
|
||||
|
||||
# If ref is a tag, also upload to GitHub Releases:
|
||||
- name: Determine tag name
|
||||
if: startsWith(github.events.inputs.ref, 'refs/tags/')
|
||||
if: startsWith(inputs.ref, 'refs/tags/')
|
||||
run: |
|
||||
REF=${{ github.events.inputs.ref }}
|
||||
REF=${{ inputs.ref }}
|
||||
echo "TAG_NAME=${REF##*/}" >> $GITHUB_ENV
|
||||
- name: Publish Debian package on GitHub Releases
|
||||
if: startsWith(github.events.inputs.ref, 'refs/tags/')
|
||||
if: startsWith(inputs.ref, 'refs/tags/')
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
fail_on_unmatched_files: true
|
||||
tag_name: ${{ github.env.TAG_NAME }}
|
||||
tag_name: ${{ inputs.ref }}
|
||||
token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }}
|
||||
files: |
|
||||
cryptomator_*_amd64.deb
|
||||
|
8
.github/workflows/get-version.yml
vendored
8
.github/workflows/get-version.yml
vendored
@ -58,13 +58,13 @@ jobs:
|
||||
SEM_VER_NUM=`echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/'`
|
||||
REVCOUNT=`git rev-list --count HEAD`
|
||||
TYPE="unknown"
|
||||
if [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then
|
||||
if [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
TYPE="stable"
|
||||
elif [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+-alpha[1-9] ]]; then
|
||||
elif [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+-alpha[1-9]+$ ]]; then
|
||||
TYPE="alpha"
|
||||
elif [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+-beta[1-9] ]]; then
|
||||
elif [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+-beta[1-9]+$ ]]; then
|
||||
TYPE="beta"
|
||||
elif [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+-rc[1-9] ]]; then
|
||||
elif [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+-rc[1-9]$ ]]; then
|
||||
TYPE="rc"
|
||||
fi
|
||||
echo "semVerStr=${SEM_VER_STR}" >> $GITHUB_OUTPUT
|
||||
|
2
.github/workflows/mac-dmg.yml
vendored
2
.github/workflows/mac-dmg.yml
vendored
@ -16,7 +16,7 @@ jobs:
|
||||
get-version:
|
||||
uses: ./.github/workflows/get-version.yml
|
||||
with:
|
||||
version: ${{ github.event.inputs.version }}
|
||||
version: ${{ inputs.version }}
|
||||
|
||||
build:
|
||||
name: Build Cryptomator.app for ${{ matrix.output-suffix }}
|
||||
|
3
.github/workflows/post-publish.yml
vendored
3
.github/workflows/post-publish.yml
vendored
@ -12,7 +12,6 @@ jobs:
|
||||
run: |
|
||||
curl -L -H "Accept: application/vnd.github+json" ${{ github.event.release.tarball_url }} --output cryptomator-${{ github.event.release.tag_name }}.tar.gz
|
||||
- name: Sign source tarball with key 615D449FE6E6A235
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
run: |
|
||||
echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import
|
||||
echo "${GPG_PASSPHRASE}" | gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator-*.tar.gz
|
||||
@ -35,6 +34,6 @@ jobs:
|
||||
SLACK_ICON_EMOJI: ':bot:'
|
||||
SLACK_CHANNEL: 'cryptomator-desktop'
|
||||
SLACK_TITLE: "Release ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} published."
|
||||
SLACK_MESSAGE: "Ready to <https://github.com/${{ github.repository }}/actions/workflows/debian.yml|deploy to PPA>."
|
||||
SLACK_MESSAGE: "Ready to <https://github.com/${{ github.repository }}/actions/workflows/debian.yml|build deb Package>."
|
||||
SLACK_FOOTER: false
|
||||
MSG_MINIMAL: true
|
23
.github/workflows/win-exe.yml
vendored
23
.github/workflows/win-exe.yml
vendored
@ -22,7 +22,7 @@ jobs:
|
||||
get-version:
|
||||
uses: ./.github/workflows/get-version.yml
|
||||
with:
|
||||
version: ${{ github.event.inputs.version }}
|
||||
version: ${{ inputs.version }}
|
||||
|
||||
build-msi:
|
||||
name: Build .msi Installer
|
||||
@ -197,6 +197,15 @@ jobs:
|
||||
*.msi
|
||||
*.asc
|
||||
|
||||
call-winget-flow:
|
||||
needs: [get-version, build-msi]
|
||||
if: github.event.action == 'published' && needs.get-version.outputs.versionType == 'stable'
|
||||
uses: ./.github/workflows/winget.yml
|
||||
with:
|
||||
releaseTag: ${{ github.event.release.tag_name }}
|
||||
secrets: inherit
|
||||
|
||||
|
||||
build-exe:
|
||||
name: Build .exe installer
|
||||
runs-on: windows-latest
|
||||
@ -301,18 +310,6 @@ jobs:
|
||||
files: |
|
||||
Cryptomator-*.exe
|
||||
Cryptomator-*.asc
|
||||
- name: Slack Notification
|
||||
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: "Windows build of ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} finished."
|
||||
SLACK_MESSAGE: "Ready to <https://github.com/${{ github.repository }}/actions/workflows/winget.yml|deploy to Winget>."
|
||||
SLACK_FOOTER: false
|
||||
MSG_MINIMAL: true
|
||||
|
||||
allowlist:
|
||||
name: Anti Virus Allowlisting
|
||||
|
5
.github/workflows/winget.yml
vendored
5
.github/workflows/winget.yml
vendored
@ -1,6 +1,11 @@
|
||||
name: Release to Winget
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
releaseTag:
|
||||
required: true
|
||||
type: string
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
releaseTag:
|
||||
|
@ -66,6 +66,7 @@
|
||||
</content_rating>
|
||||
|
||||
<releases>
|
||||
<release date="2022-12-14" version="1.6.17"/>
|
||||
<release date="2022-12-06" version="1.6.16"/>
|
||||
<release date="2022-10-06" version="1.6.15"/>
|
||||
<release date="2022-08-31" version="1.6.14"/>
|
||||
|
2
dist/linux/debian/control
vendored
2
dist/linux/debian/control
vendored
@ -12,7 +12,7 @@ Package: cryptomator
|
||||
Architecture: any
|
||||
Section: utils
|
||||
Priority: optional
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, libfuse2, xdg-utils, libjffi-jni
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, libfuse2, xdg-utils, libjffi-jni, libffi7
|
||||
Recommends: gvfs-backends, gvfs-fuse, gnome-keyring
|
||||
XB-AppName: Cryptomator
|
||||
XB-Category: Utility;Security;FileTools;
|
||||
|
2
dist/linux/debian/cryptomator.sh
vendored
2
dist/linux/debian/cryptomator.sh
vendored
@ -1,6 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
# fix for https://github.com/cryptomator/cryptomator/issues/1370
|
||||
export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/jni/libjffi-1.2.so
|
||||
export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/jni/libjffi-1.2.so:/usr/lib/x86_64-linux-gnu/libffi.so.7.1.0
|
||||
|
||||
/usr/lib/cryptomator/bin/cryptomator $@
|
9
pom.xml
9
pom.xml
@ -28,8 +28,9 @@
|
||||
<nonModularGroupIds>com.github.jnr,org.ow2.asm,org.apache.jackrabbit,org.apache.httpcomponents,de.swiesend,org.purejava,com.github.hypfvieh</nonModularGroupIds>
|
||||
|
||||
<!-- cryptomator dependencies -->
|
||||
<cryptomator.cryptolib.version>2.1.1</cryptomator.cryptolib.version>
|
||||
<cryptomator.cryptofs.version>2.5.3</cryptomator.cryptofs.version>
|
||||
<cryptomator.integrations.version>1.2.0-beta2</cryptomator.integrations.version>
|
||||
<cryptomator.integrations.version>1.2.0-beta3</cryptomator.integrations.version>
|
||||
<cryptomator.integrations.win.version>1.1.2</cryptomator.integrations.win.version>
|
||||
<cryptomator.integrations.mac.version>1.1.2</cryptomator.integrations.mac.version>
|
||||
<cryptomator.integrations.linux.version>1.1.0</cryptomator.integrations.linux.version>
|
||||
@ -64,6 +65,12 @@
|
||||
|
||||
<dependencies>
|
||||
<!-- Cryptomator Libs -->
|
||||
<dependency>
|
||||
<!-- needed due to https://github.com/cryptomator/cryptolib/issues/34-->
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>cryptolib</artifactId>
|
||||
<version>${cryptomator.cryptolib.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>cryptofs</artifactId>
|
||||
|
@ -76,6 +76,11 @@ public class DeviceKey {
|
||||
|
||||
private P384KeyPair createAndStoreNewKeyPair(char[] passphrase, Path p12File) throws IOException {
|
||||
var keyPair = P384KeyPair.generate();
|
||||
var tmpFile = p12File.resolveSibling(p12File.getFileName().toString() + ".tmp");
|
||||
if(Files.exists(tmpFile)) {
|
||||
LOG.debug("Leftover from devicekey creation detected. Deleting {}", tmpFile);
|
||||
Files.delete(tmpFile);
|
||||
}
|
||||
LOG.debug("Store new device key to {}", p12File);
|
||||
keyPair.store(p12File, passphrase);
|
||||
return keyPair;
|
||||
|
@ -176,7 +176,7 @@ public class CreateNewVaultPasswordController implements FxController {
|
||||
// 2. initialize vault:
|
||||
try {
|
||||
MasterkeyLoader loader = ignored -> masterkey.copy();
|
||||
CryptoFileSystemProperties fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties().withCipherCombo(CryptorProvider.Scheme.SIV_CTRMAC).withKeyLoader(loader).build();
|
||||
CryptoFileSystemProperties fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties().withCipherCombo(CryptorProvider.Scheme.SIV_GCM).withKeyLoader(loader).build();
|
||||
CryptoFileSystemProvider.initialize(path, fsProps, DEFAULT_KEY_ID);
|
||||
|
||||
// 3. write vault-internal readme file:
|
||||
|
@ -13,6 +13,7 @@ public enum FxmlFile {
|
||||
FORGET_PASSWORD("/fxml/forget_password.fxml"), //
|
||||
HEALTH_START("/fxml/health_start.fxml"), //
|
||||
HEALTH_CHECK_LIST("/fxml/health_check_list.fxml"), //
|
||||
HUB_NO_KEYCHAIN("/fxml/hub_no_keychain.fxml"), //
|
||||
HUB_AUTH_FLOW("/fxml/hub_auth_flow.fxml"), //
|
||||
HUB_LICENSE_EXCEEDED("/fxml/hub_license_exceeded.fxml"), //
|
||||
HUB_RECEIVE_KEY("/fxml/hub_receive_key.fxml"), //
|
||||
|
@ -87,6 +87,13 @@ public abstract class HubKeyLoadingModule {
|
||||
@StringKey(HubKeyLoadingStrategy.SCHEME_HUB_HTTPS)
|
||||
abstract KeyLoadingStrategy bindHubKeyLoadingStrategyToHubHttps(HubKeyLoadingStrategy strategy);
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.HUB_NO_KEYCHAIN)
|
||||
@KeyLoadingScoped
|
||||
static Scene provideHubNoKeychainScene(@KeyLoading FxmlLoaderFactory fxmlLoaders) {
|
||||
return fxmlLoaders.createScene(FxmlFile.HUB_NO_KEYCHAIN);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.HUB_AUTH_FLOW)
|
||||
@KeyLoadingScoped
|
||||
@ -136,6 +143,11 @@ public abstract class HubKeyLoadingModule {
|
||||
return fxmlLoaders.createScene(FxmlFile.HUB_UNAUTHORIZED_DEVICE);
|
||||
}
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(NoKeychainController.class)
|
||||
abstract FxController bindNoKeychainController(NoKeychainController controller);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(AuthFlowController.class)
|
||||
|
@ -3,6 +3,8 @@ package org.cryptomator.ui.keyloading.hub;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.nimbusds.jose.JWEObject;
|
||||
import dagger.Lazy;
|
||||
import org.cryptomator.common.keychain.KeychainManager;
|
||||
import org.cryptomator.common.keychain.NoKeychainAccessProviderException;
|
||||
import org.cryptomator.common.settings.DeviceKey;
|
||||
import org.cryptomator.cryptolib.api.Masterkey;
|
||||
import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
|
||||
@ -31,15 +33,19 @@ public class HubKeyLoadingStrategy implements KeyLoadingStrategy {
|
||||
static final String SCHEME_HUB_HTTPS = SCHEME_PREFIX + "https";
|
||||
|
||||
private final Stage window;
|
||||
private final KeychainManager keychainManager;
|
||||
private final Lazy<Scene> authFlowScene;
|
||||
private final Lazy<Scene> noKeychainScene;
|
||||
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) {
|
||||
public HubKeyLoadingStrategy(@KeyLoading Stage window, @FxmlScene(FxmlFile.HUB_AUTH_FLOW) Lazy<Scene> authFlowScene, @FxmlScene(FxmlFile.HUB_NO_KEYCHAIN) Lazy<Scene> noKeychainScene, CompletableFuture<JWEObject> result, DeviceKey deviceKey, KeychainManager keychainManager, @Named("windowTitle") String windowTitle) {
|
||||
this.window = window;
|
||||
this.keychainManager = keychainManager;
|
||||
window.setTitle(windowTitle);
|
||||
this.authFlowScene = authFlowScene;
|
||||
this.noKeychainScene = noKeychainScene;
|
||||
this.result = result;
|
||||
this.deviceKey = deviceKey;
|
||||
}
|
||||
@ -48,9 +54,16 @@ public class HubKeyLoadingStrategy implements KeyLoadingStrategy {
|
||||
public Masterkey loadKey(URI keyId) throws MasterkeyLoadingFailedException {
|
||||
Preconditions.checkArgument(keyId.getScheme().startsWith(SCHEME_PREFIX));
|
||||
try {
|
||||
startAuthFlow();
|
||||
if (!keychainManager.isSupported()) {
|
||||
throw new NoKeychainAccessProviderException();
|
||||
}
|
||||
var keypair = deviceKey.get();
|
||||
showWindow(authFlowScene);
|
||||
var jwe = result.get();
|
||||
return JWEHelper.decrypt(jwe, deviceKey.get().getPrivate());
|
||||
return JWEHelper.decrypt(jwe, keypair.getPrivate());
|
||||
} catch (NoKeychainAccessProviderException e) {
|
||||
showWindow(noKeychainScene);
|
||||
throw new UnlockCancelledException("Unlock canceled due to missing prerequisites", e);
|
||||
} catch (DeviceKey.DeviceKeyRetrievalException e) {
|
||||
throw new MasterkeyLoadingFailedException("Failed to load keypair", e);
|
||||
} catch (CancellationException e) {
|
||||
@ -63,9 +76,9 @@ public class HubKeyLoadingStrategy implements KeyLoadingStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
private void startAuthFlow() {
|
||||
private void showWindow(Lazy<Scene> scene) {
|
||||
Platform.runLater(() -> {
|
||||
window.setScene(authFlowScene.get());
|
||||
window.setScene(scene.get());
|
||||
window.show();
|
||||
Window owner = window.getOwner();
|
||||
if (owner != null) {
|
||||
|
@ -0,0 +1,31 @@
|
||||
package org.cryptomator.ui.keyloading.hub;
|
||||
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.fxapp.FxApplicationWindows;
|
||||
import org.cryptomator.ui.keyloading.KeyLoading;
|
||||
import org.cryptomator.ui.preferences.SelectedPreferencesTab;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
public class NoKeychainController implements FxController {
|
||||
|
||||
private final Stage window;
|
||||
private final FxApplicationWindows appWindows;
|
||||
|
||||
@Inject
|
||||
public NoKeychainController(@KeyLoading Stage window, FxApplicationWindows appWindows) {
|
||||
this.window = window;
|
||||
this.appWindows = appWindows;
|
||||
}
|
||||
|
||||
|
||||
public void cancel() {
|
||||
window.close();
|
||||
}
|
||||
|
||||
public void openPreferences() {
|
||||
appWindows.showPreferencesWindow(SelectedPreferencesTab.GENERAL);
|
||||
window.close();
|
||||
}
|
||||
}
|
@ -39,8 +39,8 @@ public class AwtTrayMenuController implements TrayMenuController {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showTrayIcon(byte[] rawImageData, Runnable defaultAction, String tooltip) throws TrayMenuException {
|
||||
var image = Toolkit.getDefaultToolkit().createImage(rawImageData);
|
||||
public void showTrayIcon(byte[] imageData, Runnable defaultAction, String tooltip) throws TrayMenuException {
|
||||
var image = Toolkit.getDefaultToolkit().createImage(imageData);
|
||||
trayIcon = new TrayIcon(image, tooltip, menu);
|
||||
|
||||
trayIcon.setImageAutoSize(true);
|
||||
@ -56,6 +56,15 @@ public class AwtTrayMenuController implements TrayMenuController {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTrayIcon(byte[] imageData) {
|
||||
if (trayIcon == null) {
|
||||
throw new IllegalStateException("Failed to update the icon as it has not yet been added");
|
||||
}
|
||||
var image = Toolkit.getDefaultToolkit().createImage(imageData);
|
||||
trayIcon.setImage(image);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTrayMenu(List<TrayMenuItem> items) {
|
||||
menu.removeAll();
|
||||
|
@ -33,7 +33,9 @@ public class TrayMenuBuilder {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(TrayMenuBuilder.class);
|
||||
private static final String TRAY_ICON_MAC = "/img/tray_icon_mac@2x.png";
|
||||
private static final String TRAY_ICON = "/img/window_icon_32.png";
|
||||
private static final String TRAY_ICON_UNLOCKED_MAC = "/img/tray_icon_unlocked_mac@2x.png";
|
||||
private static final String TRAY_ICON = "/img/tray_icon.png";
|
||||
private static final String TRAY_ICON_UNLOCKED = "/img/tray_icon_unlocked.png";
|
||||
|
||||
private final ResourceBundle resourceBundle;
|
||||
private final VaultService vaultService;
|
||||
@ -62,8 +64,8 @@ public class TrayMenuBuilder {
|
||||
v.displayNameProperty().addListener(this::vaultListChanged);
|
||||
});
|
||||
|
||||
try (var image = getClass().getResourceAsStream(SystemUtils.IS_OS_MAC_OSX ? TRAY_ICON_MAC : TRAY_ICON)) {
|
||||
trayMenu.showTrayIcon(image.readAllBytes(), this::showMainWindow, "Cryptomator");
|
||||
try {
|
||||
trayMenu.showTrayIcon(getAppropriateTrayIconImage(), this::showMainWindow, "Cryptomator");
|
||||
trayMenu.onBeforeOpenMenu(() -> {
|
||||
for (Vault vault : vaults) {
|
||||
VaultListManager.redetermineVaultState(vault);
|
||||
@ -71,8 +73,6 @@ public class TrayMenuBuilder {
|
||||
});
|
||||
rebuildMenu();
|
||||
initialized = true;
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to load embedded resource", e);
|
||||
} catch (TrayMenuException e) {
|
||||
LOG.error("Adding tray icon failed", e);
|
||||
}
|
||||
@ -84,6 +84,7 @@ public class TrayMenuBuilder {
|
||||
|
||||
private void vaultListChanged(@SuppressWarnings("unused") Observable observable) {
|
||||
assert Platform.isFxApplicationThread();
|
||||
trayMenu.updateTrayIcon(getAppropriateTrayIconImage());
|
||||
rebuildMenu();
|
||||
}
|
||||
|
||||
@ -154,4 +155,22 @@ public class TrayMenuBuilder {
|
||||
appWindows.showPreferencesWindow(SelectedPreferencesTab.ANY);
|
||||
}
|
||||
|
||||
private byte[] getAppropriateTrayIconImage() {
|
||||
boolean isAnyVaultUnlocked = vaults.stream().anyMatch(Vault::isUnlocked);
|
||||
|
||||
String resourceName;
|
||||
if (SystemUtils.IS_OS_MAC_OSX) {
|
||||
resourceName = isAnyVaultUnlocked ? TRAY_ICON_UNLOCKED_MAC : TRAY_ICON_MAC;
|
||||
} else {
|
||||
resourceName = isAnyVaultUnlocked ? TRAY_ICON_UNLOCKED : TRAY_ICON;
|
||||
}
|
||||
|
||||
try (var image = getClass().getResourceAsStream(resourceName)) {
|
||||
assert image != null;
|
||||
return image.readAllBytes();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to load tray icon image: " + resourceName, e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
56
src/main/resources/fxml/hub_no_keychain.fxml
Normal file
56
src/main/resources/fxml/hub_no_keychain.fxml
Normal file
@ -0,0 +1,56 @@
|
||||
<?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.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.FormattedLabel?>
|
||||
<HBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.keyloading.hub.NoKeychainController"
|
||||
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.noKeychain.message" wrapText="true" textAlignment="LEFT">
|
||||
<padding>
|
||||
<Insets bottom="6" top="6"/>
|
||||
</padding>
|
||||
</Label>
|
||||
|
||||
<FormattedLabel format="%hub.noKeychain.description" arg1="%preferences.general.keychainBackend" 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="false" cancelButton="true" onAction="#cancel"/>
|
||||
<Button text="%hub.noKeychain.openBtn" ButtonBar.buttonData="FINISH" defaultButton="true" onAction="#openPreferences"/>
|
||||
</buttons>
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
</children>
|
||||
</HBox>
|
@ -130,6 +130,9 @@ unlock.error.invalidMountPoint.notExisting=Mount point "%s" is not a directory,
|
||||
unlock.error.invalidMountPoint.existing=Mount point "%s" already exists or parent folder is missing.
|
||||
unlock.error.invalidMountPoint.driveLetterOccupied=Drive Letter "%s" is already in use.
|
||||
## Hub
|
||||
hub.noKeychain.message=Unable to access device key
|
||||
hub.noKeychain.description=In order to unlock Hub vaults, a device key is required, which is secured using a keychain. To proceed, enable “%s” and select a keychain in the preferences.
|
||||
hub.noKeychain.openBtn=Open Preferences
|
||||
### Waiting
|
||||
hub.auth.message=Waiting for authentication…
|
||||
hub.auth.description=You should automatically be redirected to the login page.
|
||||
@ -220,8 +223,6 @@ health.check.detail.checkFinishedAndFound=The check finished running. Please rev
|
||||
health.check.detail.checkFailed=The check exited due to an error.
|
||||
health.check.detail.checkCancelled=The check was cancelled.
|
||||
health.check.detail.listFilters.label=Filter
|
||||
health.check.detail.listFilters.severity=Severity
|
||||
health.check.detail.listFilters.fixState=Fix state
|
||||
health.check.detail.fixAllSpecificBtn=Fix all of type
|
||||
health.check.exportBtn=Export Report
|
||||
## Result view
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 472 B After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 376 B |
BIN
src/main/resources/img/tray_icon_unlocked.png
Normal file
BIN
src/main/resources/img/tray_icon_unlocked.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
BIN
src/main/resources/img/tray_icon_unlocked_mac@2x.png
Normal file
BIN
src/main/resources/img/tray_icon_unlocked_mac@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 732 B |
Loading…
x
Reference in New Issue
Block a user