result();
18 |
19 | @Subcomponent.Builder
20 | interface Builder {
21 |
22 | ChooseMasterkeyFileComponent build();
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/common/settings/WhenUnlocked.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.common.settings;
2 |
3 | import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
4 | import com.fasterxml.jackson.annotation.JsonFormat;
5 |
6 | @JsonFormat(shape = JsonFormat.Shape.STRING)
7 | public enum WhenUnlocked {
8 | IGNORE("vaultOptions.general.actionAfterUnlock.ignore"),
9 | REVEAL("vaultOptions.general.actionAfterUnlock.reveal"),
10 | @JsonEnumDefaultValue ASK("vaultOptions.general.actionAfterUnlock.ask");
11 |
12 | private String displayName;
13 |
14 | WhenUnlocked(String displayName) {
15 | this.displayName = displayName;
16 | }
17 |
18 | public String getDisplayName() {
19 | return displayName;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/keyloading/hub/LegacyRegisterSuccessController.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.keyloading.hub;
2 |
3 | import org.cryptomator.ui.common.FxController;
4 | import org.cryptomator.ui.keyloading.KeyLoading;
5 | import org.cryptomator.ui.keyloading.KeyLoadingScoped;
6 |
7 | import javax.inject.Inject;
8 | import javafx.fxml.FXML;
9 | import javafx.stage.Stage;
10 |
11 | @KeyLoadingScoped
12 | public class LegacyRegisterSuccessController implements FxController {
13 | private final Stage window;
14 |
15 | @Inject
16 | public LegacyRegisterSuccessController(@KeyLoading Stage window) {
17 | this.window = window;
18 | }
19 |
20 | @FXML
21 | public void close() {
22 | window.close();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/launcher/CryptomatorComponent.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.launcher;
2 |
3 | import dagger.BindsInstance;
4 | import dagger.Component;
5 | import org.cryptomator.common.CommonsModule;
6 | import org.cryptomator.ui.fxapp.FxApplicationComponent;
7 |
8 | import javax.inject.Named;
9 | import javax.inject.Singleton;
10 |
11 | @Singleton
12 | @Component(modules = {CryptomatorModule.class, CommonsModule.class})
13 | public interface CryptomatorComponent {
14 |
15 | Cryptomator application();
16 |
17 | FxApplicationComponent.Builder fxAppComponentBuilder();
18 |
19 | @Component.Factory
20 | interface Factory {
21 | CryptomatorComponent create(@BindsInstance @Named("startupTime") long startupTime);
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/.github/SUPPORT.md:
--------------------------------------------------------------------------------
1 | # Support for Cryptomator
2 |
3 | For development-related topics, GitHub is the right place.
4 |
5 | For _everything else_, please visit our official [Cryptomator Community](https://community.cryptomator.org) (we are there, too :wink:). Amongst others, you will find:
6 |
7 | - [Knowledge Base](https://community.cryptomator.org/c/kb)
8 | - Installation manuals
9 | - Usage guides
10 | - FAQ
11 | - [Help with problems](https://community.cryptomator.org/c/help)
12 | - Assistance with the setup
13 | - Known issues and workarounds
14 | - Discussions about the apps
15 | - [Development discussions](https://community.cryptomator.org/c/development)
16 | - General questions
17 | - Discussions regarding our design decisions
18 | - Our roadmap
19 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/networking/SSLContextWithWindowsCertStore.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.networking;
2 |
3 | import org.cryptomator.integrations.common.OperatingSystem;
4 |
5 | import java.security.KeyStore;
6 | import java.security.KeyStoreException;
7 |
8 | /**
9 | * SSLContextProvider for Windows using the Windows certificate store as trust store
10 | *
11 | * In order to work, the jdk.crypto.mscapi jmod is needed
12 | */
13 | @OperatingSystem(OperatingSystem.Value.WINDOWS)
14 | public class SSLContextWithWindowsCertStore extends SSLContextDifferentTrustStoreBase implements SSLContextProvider {
15 |
16 | @Override
17 | KeyStore getTruststore() throws KeyStoreException {
18 | return KeyStore.getInstance("WINDOWS-ROOT");
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/networking/SSLContextProvider.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.networking;
2 |
3 | import org.cryptomator.integrations.common.IntegrationsLoader;
4 |
5 | import javax.net.ssl.SSLContext;
6 | import java.security.SecureRandom;
7 | import java.util.ServiceLoader;
8 | import java.util.stream.Stream;
9 |
10 | public interface SSLContextProvider {
11 |
12 | SSLContext getContext(SecureRandom csprng) throws SSLContextBuildException;
13 |
14 | class SSLContextBuildException extends Exception {
15 |
16 | SSLContextBuildException(Throwable t) {
17 | super(t);
18 | }
19 | }
20 |
21 | static Stream loadAll() {
22 | return IntegrationsLoader.loadAll(ServiceLoader.load(SSLContextProvider.class), SSLContextProvider.class);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/.github/workflows/pullrequest.yml:
--------------------------------------------------------------------------------
1 | name: Pull Request
2 |
3 | on:
4 | pull_request:
5 |
6 | env:
7 | JAVA_DIST: 'temurin'
8 | JAVA_VERSION: 23
9 |
10 | defaults:
11 | run:
12 | shell: bash
13 |
14 | jobs:
15 | test:
16 | name: Compile and Test
17 | runs-on: ubuntu-latest
18 | if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]')"
19 | steps:
20 | - uses: actions/checkout@v4
21 | - uses: actions/setup-java@v4
22 | with:
23 | distribution: ${{ env.JAVA_DIST }}
24 | java-version: ${{ env.JAVA_VERSION }}
25 | cache: 'maven'
26 | - name: Build and Test
27 | run: xvfb-run mvn -B clean install jacoco:report -Pcoverage -Djavafx.platform=linux
--------------------------------------------------------------------------------
/src/main/resources/fxml/vault_detail_needsmigration.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
17 |
18 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/lock/LockFailedController.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.lock;
2 |
3 | import org.cryptomator.common.vaults.Vault;
4 | import org.cryptomator.ui.common.FxController;
5 |
6 | import javax.inject.Inject;
7 | import javafx.fxml.FXML;
8 | import javafx.stage.Stage;
9 |
10 | @LockScoped
11 | public class LockFailedController implements FxController {
12 |
13 | private final Stage window;
14 | private final Vault vault;
15 |
16 | @Inject
17 | public LockFailedController(@LockWindow Stage window, @LockWindow Vault vault) {
18 | this.window = window;
19 | this.vault = vault;
20 | }
21 |
22 | @FXML
23 | public void close() {
24 | window.close();
25 | }
26 |
27 | // ----- Getter & Setter -----
28 | public String getVaultName() {
29 | return vault.getDisplayName();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/keyloading/KeyLoadingComponent.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.keyloading;
2 |
3 | import dagger.BindsInstance;
4 | import dagger.Subcomponent;
5 | import org.cryptomator.common.vaults.Vault;
6 | import org.cryptomator.cryptolib.api.MasterkeyLoader;
7 |
8 | import javafx.stage.Stage;
9 | import java.util.Map;
10 | import java.util.function.Supplier;
11 |
12 | @KeyLoadingScoped
13 | @Subcomponent(modules = {KeyLoadingModule.class})
14 | public interface KeyLoadingComponent {
15 |
16 | @KeyLoading
17 | KeyLoadingStrategy keyloadingStrategy();
18 |
19 | @Subcomponent.Builder
20 | interface Builder {
21 |
22 | @BindsInstance
23 | Builder vault(@KeyLoading Vault vault);
24 |
25 | @BindsInstance
26 | Builder window(@KeyLoading Stage window);
27 |
28 | KeyLoadingComponent build();
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/keyloading/hub/RegisterFailedController.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.keyloading.hub;
2 |
3 | import org.cryptomator.ui.common.FxController;
4 | import org.cryptomator.ui.keyloading.KeyLoading;
5 |
6 | import javax.inject.Inject;
7 | import javafx.fxml.FXML;
8 | import javafx.stage.Stage;
9 | import java.util.concurrent.CompletableFuture;
10 |
11 | public class RegisterFailedController implements FxController {
12 |
13 | private final Stage window;
14 | private final CompletableFuture result;
15 |
16 | @Inject
17 | public RegisterFailedController(@KeyLoading Stage window, CompletableFuture result) {
18 | this.window = window;
19 | this.result = result;
20 | }
21 |
22 | @FXML
23 | public void close() {
24 | result.cancel(true);
25 | window.close();
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/.github/workflows/winget.yml:
--------------------------------------------------------------------------------
1 | name: Publish MSI to winget-pkgs
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | tag:
7 | description: 'Release tag'
8 | required: true
9 |
10 | jobs:
11 | winget:
12 | name: Publish winget package
13 | runs-on: windows-latest
14 | steps:
15 | - name: Sync winget-pkgs fork
16 | run: |
17 | gh repo sync cryptomator/winget-pkgs -b master --force
18 | env:
19 | GH_TOKEN: ${{ secrets.CRYPTOBOT_WINGET_TOKEN }}
20 | - name: Submit package
21 | uses: vedantmgoyal2009/winget-releaser@main
22 | with:
23 | identifier: Cryptomator.Cryptomator
24 | version: ${{ inputs.tag }}
25 | release-tag: ${{ inputs.tag }}
26 | installers-regex: '\.msi$'
27 | token: ${{ secrets.CRYPTOBOT_WINGET_TOKEN }}
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/networking/SSLContextWithMacKeychain.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.networking;
2 |
3 | import org.cryptomator.integrations.common.OperatingSystem;
4 |
5 | import java.io.IOException;
6 | import java.security.KeyStore;
7 | import java.security.KeyStoreException;
8 | import java.security.NoSuchAlgorithmException;
9 | import java.security.cert.CertificateException;
10 |
11 | /**
12 | * SSLContextProvider for macOS using the macOS Keychain as truststore
13 | */
14 | @OperatingSystem(OperatingSystem.Value.MAC)
15 | public class SSLContextWithMacKeychain extends SSLContextDifferentTrustStoreBase implements SSLContextProvider {
16 |
17 | @Override
18 | KeyStore getTruststore() throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException {
19 | return KeyStore.getInstance("KeychainStore-ROOT");
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/.github/release.yml:
--------------------------------------------------------------------------------
1 | # .github/release.yml
2 | # see https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes#configuring-automatically-generated-release-notes
3 |
4 | changelog:
5 | exclude:
6 | authors:
7 | - cryptobot
8 | - dependabot
9 | - github-actions
10 | categories:
11 | - title: What's New 🎉
12 | labels:
13 | - type:feature-request
14 | - type:enhancement
15 | - title: Bugfixes 🐛
16 | labels:
17 | - type:security-issue
18 | - type:bug
19 | - type:minor-bug
20 | - title: Other Changes 📎
21 | labels:
22 | - "*"
23 | exclude:
24 | labels:
25 | - type:feature-request
26 | - type:enhancement
27 | - type:security-issue
28 | - type:bug
29 | - type:minor-bug
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/convertvault/HubToPasswordSuccessController.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.convertvault;
2 |
3 | import org.cryptomator.common.vaults.Vault;
4 | import org.cryptomator.ui.common.FxController;
5 |
6 | import javax.inject.Inject;
7 | import javafx.fxml.FXML;
8 | import javafx.stage.Stage;
9 |
10 | public class HubToPasswordSuccessController implements FxController {
11 |
12 | private final Stage window;
13 | private final Vault vault;
14 |
15 | @Inject
16 | HubToPasswordSuccessController(@ConvertVaultWindow Stage window, @ConvertVaultWindow Vault vault) {
17 | this.window = window;
18 | this.vault = vault;
19 | }
20 |
21 | @FXML
22 | public void close() {
23 | window.close();
24 | window.getOwner().hide();
25 | }
26 |
27 | /* Observables */
28 |
29 | public Vault getVault() {
30 | return vault;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/test/java/org/cryptomator/ui/keyloading/hub/HubConfigTest.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.keyloading.hub;
2 |
3 | import com.auth0.jwt.JWT;
4 | import org.junit.jupiter.api.Assertions;
5 | import org.junit.jupiter.api.DisplayName;
6 | import org.junit.jupiter.api.Test;
7 |
8 | public class HubConfigTest {
9 |
10 | @Test
11 | @DisplayName("can parse JWT with unknown fields in header claim \"hub\"")
12 | public void testParseJWTWithUnknownFields() {
13 | var jwt = JWT.decode("eyJraWQiOiIxMjMiLCJ0eXAiOiJqd3QiLCJhbGciOiJIUzI1NiIsImh1YiI6eyJ1bmtub3duRmllbGQiOjQyLCJjbGllbnRJZCI6ImNyeXB0b21hdG9yIn19.eyJqdGkiOiI0NTYifQ.e1CStFf5fdh9ofX_6O8_LfbHfHEJZqUpuYNWz9xZp0I");
14 | var claim = jwt.getHeaderClaim("hub");
15 | var hubConfig = Assertions.assertDoesNotThrow(() -> claim.as(HubConfig.class));
16 | Assertions.assertEquals("cryptomator", hubConfig.clientId);
17 | }
18 |
19 | }
--------------------------------------------------------------------------------
/dist/mac/Cryptomator.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.application-identifier
6 | ###APP_IDENTIFIER_PREFIX###org.cryptomator
7 | com.apple.developer.team-identifier
8 | ###TEAM_IDENTIFIER###
9 | com.apple.security.cs.allow-jit
10 |
11 | com.apple.security.cs.allow-unsigned-executable-memory
12 |
13 | com.apple.security.cs.disable-executable-page-protection
14 |
15 | com.apple.security.cs.disable-library-validation
16 |
17 | keychain-access-groups
18 |
19 | ###APP_IDENTIFIER_PREFIX###org.cryptomator
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/wrongfilealert/WrongFileAlertComponent.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.wrongfilealert;
2 |
3 | import dagger.Lazy;
4 | import dagger.Subcomponent;
5 | import org.cryptomator.ui.common.FxmlFile;
6 | import org.cryptomator.ui.common.FxmlScene;
7 |
8 | import javafx.scene.Scene;
9 | import javafx.stage.Stage;
10 |
11 | @WrongFileAlertScoped
12 | @Subcomponent(modules = {WrongFileAlertModule.class})
13 | public interface WrongFileAlertComponent {
14 |
15 | @WrongFileAlertWindow
16 | Stage window();
17 |
18 | @FxmlScene(FxmlFile.WRONGFILEALERT)
19 | Lazy scene();
20 |
21 | default void showWrongFileAlertWindow() {
22 | Stage stage = window();
23 | stage.setScene(scene().get());
24 | stage.sizeToScene();
25 | stage.show();
26 | }
27 |
28 | @Subcomponent.Builder
29 | interface Builder {
30 |
31 | WrongFileAlertComponent build();
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/updatereminder/UpdateReminderComponent.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.updatereminder;
2 |
3 | import dagger.Lazy;
4 | import dagger.Subcomponent;
5 | import org.cryptomator.ui.common.FxmlFile;
6 | import org.cryptomator.ui.common.FxmlScene;
7 |
8 | import javafx.scene.Scene;
9 | import javafx.stage.Stage;
10 |
11 | @UpdateReminderScoped
12 | @Subcomponent(modules = {UpdateReminderModule.class})
13 | public interface UpdateReminderComponent {
14 |
15 | @UpdateReminderWindow
16 | Stage window();
17 |
18 | @FxmlScene(FxmlFile.UPDATE_REMINDER)
19 | Lazy updateReminderScene();
20 |
21 | default void showUpdateReminderWindow() {
22 | Stage stage = window();
23 | stage.setScene(updateReminderScene().get());
24 | stage.sizeToScene();
25 | stage.show();
26 | }
27 |
28 | @Subcomponent.Factory
29 | interface Factory {
30 |
31 | UpdateReminderComponent create();
32 | }
33 | }
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultRecoveryKeyController.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.addvaultwizard;
2 |
3 | import dagger.Lazy;
4 | import org.cryptomator.ui.common.FxController;
5 | import org.cryptomator.ui.common.FxmlFile;
6 | import org.cryptomator.ui.common.FxmlScene;
7 |
8 | import javax.inject.Inject;
9 | import javafx.fxml.FXML;
10 | import javafx.scene.Scene;
11 | import javafx.stage.Stage;
12 |
13 | public class CreateNewVaultRecoveryKeyController implements FxController {
14 |
15 | private final Stage window;
16 | private final Lazy successScene;
17 |
18 | @Inject
19 | CreateNewVaultRecoveryKeyController(@AddVaultWizardWindow Stage window, @FxmlScene(FxmlFile.ADDVAULT_SUCCESS) Lazy successScene) {
20 | this.window = window;
21 | this.successScene = successScene;
22 | }
23 |
24 | @FXML
25 | public void next() {
26 | window.setScene(successScene.get());
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/common/FxControllerKey.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2017 Skymatic UG (haftungsbeschränkt).
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the accompanying LICENSE file.
5 | *******************************************************************************/
6 | package org.cryptomator.ui.common;
7 |
8 | import dagger.MapKey;
9 |
10 | import java.lang.annotation.Documented;
11 | import java.lang.annotation.Retention;
12 | import java.lang.annotation.Target;
13 |
14 | import static java.lang.annotation.ElementType.METHOD;
15 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
16 |
17 | @Documented
18 | @Target(METHOD)
19 | @Retention(RUNTIME)
20 | @MapKey
21 | public @interface FxControllerKey {
22 |
23 | Class extends FxController> value();
24 | }
25 |
--------------------------------------------------------------------------------
/dist/win/resources/ui.wxf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | 1
10 | 1
11 | NOT Installed
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/sharevault/ShareVaultComponent.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.sharevault;
2 |
3 | import dagger.BindsInstance;
4 | import dagger.Lazy;
5 | import dagger.Subcomponent;
6 | import org.cryptomator.common.vaults.Vault;
7 | import org.cryptomator.ui.common.FxmlFile;
8 | import org.cryptomator.ui.common.FxmlScene;
9 |
10 | import javafx.scene.Scene;
11 | import javafx.stage.Stage;
12 |
13 | @ShareVaultScoped
14 | @Subcomponent(modules = {ShareVaultModule.class})
15 | public interface ShareVaultComponent {
16 |
17 | @ShareVaultWindow
18 | Stage window();
19 |
20 | @FxmlScene(FxmlFile.SHARE_VAULT)
21 | Lazy scene();
22 |
23 | default void showShareVaultWindow(){
24 | Stage stage = window();
25 | stage.setScene(scene().get());
26 | stage.show();
27 | }
28 |
29 | @Subcomponent.Factory
30 | interface Factory {
31 | ShareVaultComponent create(@BindsInstance @ShareVaultWindow Vault vault);
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/common/settings/UiTheme.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.common.settings;
2 |
3 | import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
4 | import com.fasterxml.jackson.annotation.JsonFormat;
5 | import org.apache.commons.lang3.SystemUtils;
6 |
7 | @JsonFormat(shape = JsonFormat.Shape.STRING)
8 | public enum UiTheme {
9 | @JsonEnumDefaultValue LIGHT("preferences.interface.theme.light"), //
10 | DARK("preferences.interface.theme.dark"), //
11 | AUTOMATIC("preferences.interface.theme.automatic");
12 |
13 | public static UiTheme[] applicableValues() {
14 | if (SystemUtils.IS_OS_MAC || SystemUtils.IS_OS_WINDOWS) {
15 | return values();
16 | } else {
17 | return new UiTheme[]{LIGHT, DARK};
18 | }
19 | }
20 |
21 | private final String displayName;
22 |
23 | UiTheme(String displayName) {
24 | this.displayName = displayName;
25 | }
26 |
27 | public String getDisplayName() {
28 | return displayName;
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/error/ErrorComponent.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.error;
2 |
3 | import dagger.BindsInstance;
4 | import dagger.Subcomponent;
5 | import org.cryptomator.common.Nullable;
6 | import org.cryptomator.ui.common.FxmlFile;
7 | import org.cryptomator.ui.common.FxmlScene;
8 |
9 | import javafx.scene.Scene;
10 | import javafx.stage.Stage;
11 |
12 | @Subcomponent(modules = {ErrorModule.class})
13 | public interface ErrorComponent {
14 |
15 | Stage window();
16 |
17 | @FxmlScene(FxmlFile.ERROR)
18 | Scene scene();
19 |
20 | default Stage show() {
21 | Stage stage = window();
22 | stage.setScene(scene());
23 | stage.setMinWidth(420);
24 | stage.setMinHeight(300);
25 | stage.show();
26 | return stage;
27 | }
28 |
29 | @Subcomponent.Factory
30 | interface Factory {
31 |
32 | ErrorComponent create(@BindsInstance Throwable cause, @BindsInstance Stage window, @BindsInstance @Nullable Scene previousScene);
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/keyloading/hub/NoKeychainController.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.keyloading.hub;
2 |
3 | import org.cryptomator.ui.common.FxController;
4 | import org.cryptomator.ui.fxapp.FxApplicationWindows;
5 | import org.cryptomator.ui.keyloading.KeyLoading;
6 | import org.cryptomator.ui.preferences.SelectedPreferencesTab;
7 |
8 | import javax.inject.Inject;
9 | import javafx.stage.Stage;
10 |
11 | public class NoKeychainController implements FxController {
12 |
13 | private final Stage window;
14 | private final FxApplicationWindows appWindows;
15 |
16 | @Inject
17 | public NoKeychainController(@KeyLoading Stage window, FxApplicationWindows appWindows) {
18 | this.window = window;
19 | this.appWindows = appWindows;
20 | }
21 |
22 |
23 | public void cancel() {
24 | window.close();
25 | }
26 |
27 | public void openPreferences() {
28 | appWindows.showPreferencesWindow(SelectedPreferencesTab.GENERAL);
29 | window.close();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/keyloading/masterkeyfile/PassphraseEntryComponent.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.keyloading.masterkeyfile;
2 |
3 | import dagger.BindsInstance;
4 | import dagger.Subcomponent;
5 | import org.cryptomator.common.Nullable;
6 | import org.cryptomator.common.Passphrase;
7 |
8 | import javax.inject.Named;
9 | import javafx.scene.Scene;
10 | import java.util.concurrent.CompletableFuture;
11 |
12 | @PassphraseEntryScoped
13 | @Subcomponent(modules = {PassphraseEntryModule.class})
14 | public interface PassphraseEntryComponent {
15 |
16 | @PassphraseEntryScoped
17 | Scene passphraseEntryScene();
18 |
19 | @PassphraseEntryScoped
20 | CompletableFuture result();
21 |
22 | @Subcomponent.Builder
23 | interface Builder {
24 |
25 | @BindsInstance
26 | PassphraseEntryComponent.Builder savedPassword(@Nullable @Named("savedPassword") Passphrase savedPassword);
27 |
28 | PassphraseEntryComponent build();
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/vaultoptions/HubOptionsController.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.vaultoptions;
2 |
3 | import org.cryptomator.common.vaults.Vault;
4 | import org.cryptomator.ui.common.FxController;
5 | import org.cryptomator.ui.convertvault.ConvertVaultComponent;
6 |
7 | import javax.inject.Inject;
8 | import javafx.stage.Stage;
9 |
10 | public class HubOptionsController implements FxController {
11 |
12 | private final Vault vault;
13 | private final Stage window;
14 | private final ConvertVaultComponent.Factory convertVaultFactory;
15 |
16 |
17 | @Inject
18 | public HubOptionsController(@VaultOptionsWindow Vault vault, @VaultOptionsWindow Stage window, ConvertVaultComponent.Factory convertVaultFactory) {
19 | this.vault = vault;
20 | this.window = window;
21 | this.convertVaultFactory = convertVaultFactory;
22 | }
23 |
24 | public void startConversion() {
25 | convertVaultFactory.create(vault,window).showHubToPasswordWindow();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ipc/HandleLaunchArgsMessage.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ipc;
2 |
3 | import com.google.common.base.Joiner;
4 | import com.google.common.base.Splitter;
5 |
6 | import java.nio.ByteBuffer;
7 | import java.nio.charset.StandardCharsets;
8 | import java.util.List;
9 |
10 | record HandleLaunchArgsMessage(List args) implements IpcMessage {
11 |
12 | private static final char DELIMITER = '\n';
13 |
14 | public static HandleLaunchArgsMessage decode(ByteBuffer encoded) {
15 | var str = StandardCharsets.UTF_8.decode(encoded).toString();
16 | var args = Splitter.on(DELIMITER).omitEmptyStrings().splitToList(str);
17 | return new HandleLaunchArgsMessage(args);
18 | }
19 |
20 | @Override
21 | public MessageType getMessageType() {
22 | return MessageType.HANDLE_LAUNCH_ARGS;
23 | }
24 |
25 | @Override
26 | public ByteBuffer encodePayload() {
27 | var str = Joiner.on(DELIMITER).join(args);
28 | return StandardCharsets.UTF_8.encode(str);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/resources/fxml/vault_options_hub.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/dist/win/build.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | :: Default values for Cryptomator builds
3 | SET APPNAME="Cryptomator"
4 | SET MAIN_JAR_GLOB="cryptomator-*"
5 | SET UPGRADE_UUID="bda45523-42b1-4cae-9354-a45475ed4775"
6 | SET VENDOR="Skymatic GmbH"
7 | SET FIRST_COPYRIGHT_YEAR=2016
8 | SET ABOUT_URL="https://cryptomator.org"
9 | SET UPDATE_URL="https://cryptomator.org/downloads/"
10 | SET HELP_URL="https://cryptomator.org/contact/"
11 | SET MODULE_AND_MAIN_CLASS="org.cryptomator.desktop/org.cryptomator.launcher.Cryptomator"
12 | SET LOOPBACK_ALIAS="cryptomator-vault"
13 |
14 | pwsh -NoLogo -NoProfile -ExecutionPolicy Unrestricted -Command .\build.ps1^
15 | -AppName %APPNAME%^
16 | -MainJarGlob "%MAIN_JAR_GLOB%"^
17 | -ModuleAndMainClass "%MODULE_AND_MAIN_CLASS%"^
18 | -UpgradeUUID "%UPGRADE_UUID%"^
19 | -Vendor ""%VENDOR%""^
20 | -CopyrightStartYear %FIRST_COPYRIGHT_YEAR%^
21 | -AboutUrl "%ABOUT_URL%"^
22 | -HelpUrl "%HELP_URL%"^
23 | -UpdateUrl "%UPDATE_URL%"^
24 | -LoopbackAlias "%LOOPBACK_ALIAS%"^
25 | -Clean 1
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/common/locationpresets/OneDriveLinuxLocationPresetsProvider.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.common.locationpresets;
2 |
3 | import org.cryptomator.integrations.common.CheckAvailability;
4 | import org.cryptomator.integrations.common.OperatingSystem;
5 |
6 | import java.nio.file.Files;
7 | import java.nio.file.Path;
8 | import java.util.stream.Stream;
9 |
10 | import static org.cryptomator.integrations.common.OperatingSystem.Value.LINUX;
11 |
12 | @OperatingSystem(LINUX)
13 | @CheckAvailability
14 | public final class OneDriveLinuxLocationPresetsProvider implements LocationPresetsProvider {
15 |
16 |
17 | private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/OneDrive");
18 |
19 | @CheckAvailability
20 | public static boolean isPresent() {
21 | return Files.isDirectory(LOCATION);
22 | }
23 |
24 | @Override
25 | public Stream getLocations() {
26 | return Stream.of(new LocationPreset("OneDrive", LOCATION));
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/lock/LockComponent.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.lock;
2 |
3 | import dagger.BindsInstance;
4 | import dagger.Subcomponent;
5 | import org.cryptomator.common.Nullable;
6 | import org.cryptomator.common.vaults.Vault;
7 |
8 | import javax.inject.Named;
9 | import javafx.stage.Stage;
10 | import java.util.concurrent.ExecutorService;
11 | import java.util.concurrent.Future;
12 |
13 |
14 | @LockScoped
15 | @Subcomponent(modules = {LockModule.class})
16 | public interface LockComponent {
17 |
18 | ExecutorService defaultExecutorService();
19 |
20 | LockWorkflow lockWorkflow();
21 |
22 | default Future startLockWorkflow() {
23 | LockWorkflow workflow = lockWorkflow();
24 | defaultExecutorService().submit(workflow);
25 | return workflow;
26 | }
27 |
28 | @Subcomponent.Factory
29 | interface Factory {
30 | LockComponent create(@BindsInstance @LockWindow Vault vault, @BindsInstance @Named("lockWindowOwner") @Nullable Stage owner);
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/common/locationpresets/DropboxWindowsLocationPresetsProvider.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.common.locationpresets;
2 |
3 | import org.cryptomator.integrations.common.CheckAvailability;
4 | import org.cryptomator.integrations.common.OperatingSystem;
5 |
6 | import java.nio.file.Files;
7 | import java.nio.file.Path;
8 | import java.util.stream.Stream;
9 |
10 | import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
11 |
12 | @OperatingSystem(WINDOWS)
13 | @CheckAvailability
14 | public final class DropboxWindowsLocationPresetsProvider implements LocationPresetsProvider {
15 |
16 | private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/Dropbox");
17 |
18 |
19 | @CheckAvailability
20 | public static boolean isPresent() {
21 | return Files.isDirectory(LOCATION);
22 | }
23 |
24 | @Override
25 | public Stream getLocations() {
26 | return Stream.of(new LocationPreset("Dropbox", LOCATION));
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/common/locationpresets/ICloudWindowsLocationPresetsProvider.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.common.locationpresets;
2 |
3 | import org.cryptomator.integrations.common.CheckAvailability;
4 | import org.cryptomator.integrations.common.OperatingSystem;
5 |
6 | import java.nio.file.Files;
7 | import java.nio.file.Path;
8 | import java.util.stream.Stream;
9 |
10 | import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
11 |
12 | @OperatingSystem(WINDOWS)
13 | @CheckAvailability
14 | public final class ICloudWindowsLocationPresetsProvider implements LocationPresetsProvider {
15 |
16 | private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/iCloudDrive");
17 |
18 | @CheckAvailability
19 | public static boolean isPresent() {
20 | return Files.isDirectory(LOCATION);
21 | }
22 |
23 | @Override
24 | public Stream getLocations() {
25 | return Stream.of(new LocationPreset("iCloud Drive", LOCATION));
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/common/mount/IllegalMountPointException.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.common.mount;
2 |
3 | import java.nio.file.Path;
4 |
5 | /**
6 | * Indicates that validation or preparation of a mountpoint failed due to a configuration error or an invalid system state.
7 | * Instances of this exception are usually caught and displayed to the user in an appropriate fashion, e.g. by {@link org.cryptomator.ui.unlock.UnlockInvalidMountPointController UnlockInvalidMountPointController.}
8 | */
9 | public class IllegalMountPointException extends IllegalArgumentException {
10 |
11 | private final Path mountpoint;
12 |
13 | public IllegalMountPointException(Path mountpoint) {
14 | this(mountpoint, "The provided mountpoint has a problem: " + mountpoint.toString());
15 | }
16 |
17 | public IllegalMountPointException(Path mountpoint, String msg) {
18 | super(msg);
19 | this.mountpoint = mountpoint;
20 | }
21 |
22 | public Path getMountpoint() {
23 | return mountpoint;
24 | }
25 | }
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/migration/MigrationComponent.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.migration;
2 |
3 | import dagger.BindsInstance;
4 | import dagger.Lazy;
5 | import dagger.Subcomponent;
6 | import org.cryptomator.common.vaults.Vault;
7 | import org.cryptomator.ui.common.FxmlFile;
8 | import org.cryptomator.ui.common.FxmlScene;
9 |
10 | import javafx.scene.Scene;
11 | import javafx.stage.Stage;
12 |
13 | @MigrationScoped
14 | @Subcomponent(modules = {MigrationModule.class})
15 | public interface MigrationComponent {
16 |
17 | @MigrationWindow
18 | Stage window();
19 |
20 | @FxmlScene(FxmlFile.MIGRATION_START)
21 | Lazy scene();
22 |
23 | default Stage showMigrationWindow() {
24 | Stage stage = window();
25 | stage.setScene(scene().get());
26 | stage.show();
27 | return stage;
28 | }
29 |
30 | @Subcomponent.Builder
31 | interface Builder {
32 |
33 | @BindsInstance
34 | Builder vault(@MigrationWindow Vault vault);
35 |
36 | MigrationComponent build();
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/resources/fxml/health_check_listcell.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/.github/workflows/no-response.yml:
--------------------------------------------------------------------------------
1 | # Configuration for close-stale-issues - https://github.com/marketplace/actions/close-stale-issues
2 |
3 | name: 'Close awaiting response issues'
4 | on:
5 | schedule:
6 | - cron: '00 09 * * *'
7 |
8 | jobs:
9 | no-response:
10 | runs-on: ubuntu-latest
11 | permissions:
12 | issues: write
13 | pull-requests: write
14 | steps:
15 | - uses: actions/stale@v9
16 | with:
17 | days-before-stale: 14
18 | days-before-close: 0
19 | days-before-pr-close: -1
20 | stale-issue-label: 'state:stale'
21 | close-issue-message: "This issue has been automatically closed because there has been no response to our request for more information from the original author. With only the information that is currently in the issue, we don't have enough information to take action. Please reach out if you have or find the answers we need so that we can investigate further."
22 | only-labels: 'state:awaiting-response'
23 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/common/locationpresets/ICloudMacLocationPresetsProvider.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.common.locationpresets;
2 |
3 | import org.cryptomator.integrations.common.CheckAvailability;
4 | import org.cryptomator.integrations.common.OperatingSystem;
5 |
6 | import java.nio.file.Files;
7 | import java.nio.file.Path;
8 | import java.util.stream.Stream;
9 |
10 | import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
11 |
12 | @OperatingSystem(MAC)
13 | @CheckAvailability
14 | public final class ICloudMacLocationPresetsProvider implements LocationPresetsProvider {
15 |
16 | private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/Library/Mobile Documents/com~apple~CloudDocs");
17 |
18 | @CheckAvailability
19 | public static boolean isPresent() {
20 | return Files.isDirectory(LOCATION);
21 | }
22 |
23 | @Override
24 | public Stream getLocations() {
25 | return Stream.of(new LocationPreset("iCloud Drive", LOCATION));
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/common/StageInitializer.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.common;
2 |
3 | import org.apache.commons.lang3.SystemUtils;
4 | import org.cryptomator.ui.fxapp.FxApplicationScoped;
5 |
6 | import javax.inject.Inject;
7 | import javafx.scene.image.Image;
8 | import javafx.stage.Stage;
9 | import java.util.List;
10 | import java.util.function.Consumer;
11 |
12 | /**
13 | * Performs common setup for all stages
14 | */
15 | @FxApplicationScoped
16 | public class StageInitializer implements Consumer {
17 |
18 | private final List windowIcons;
19 |
20 | @Inject
21 | public StageInitializer() {
22 | this.windowIcons = SystemUtils.IS_OS_MAC ? List.of() : List.of( //
23 | new Image(StageInitializer.class.getResource("/img/window_icon_32.png").toString()), //
24 | new Image(StageInitializer.class.getResource("/img/window_icon_512.png").toString()) //
25 | );
26 | }
27 |
28 | @Override
29 | public void accept(Stage stage) {
30 | stage.getIcons().setAll(windowIcons);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/dist/linux/appimage/resources/AppDir/bin/cryptomator.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | cd $(dirname $0)
3 |
4 | # determine GTK version
5 | GTK2_PRESENT=1 # initially false
6 | GTK3_PRESENT=0 # initially true
7 | if command -v dpkg &> /dev/null; then # do stuff for debian based things
8 | GTK2_PRESENT=`dpkg -l libgtk* | grep -e '\^ii' | grep -e 'libgtk2-*' &> /dev/null; echo $?`
9 | GTK3_PRESENT=`dpkg -l libgtk* | grep -e '\^ii' | grep -e 'libgtk-3-*' &> /dev/null; echo $?`
10 | elif command -v rpm &> /dev/null; then # do stuff for rpm based things (including yum/dnf)
11 | GTK2_PRESENT=`rpm -qa | grep -e '\^gtk2-[0-9][0-9]*' &> /dev/null; echo $?`
12 | GTK3_PRESENT=`rpm -qa | grep -e '\^gtk3-[0-9][0-9]*' &> /dev/null; echo $?`
13 | elif command -v pacman &> /dev/null; then # don't forget arch
14 | GTK2_PRESENT=`pacman -Qi gtk2 &> /dev/null; echo $?`
15 | GTK3_PRESENT=`pacman -Qi gtk3 &> /dev/null; echo $?`
16 | fi
17 |
18 | if [ "$GTK2_PRESENT" -eq 0 ] && [ "$GTK3_PRESENT" -ne 0 ]; then
19 | bin/Cryptomator-gtk2 $@
20 | else
21 | bin/Cryptomator $@
22 | fi
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/keyloading/masterkeyfile/PassphraseEntryModule.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.keyloading.masterkeyfile;
2 |
3 | import dagger.Module;
4 | import dagger.Provides;
5 | import org.cryptomator.ui.common.DefaultSceneFactory;
6 | import org.cryptomator.ui.common.FxmlFile;
7 | import org.cryptomator.ui.common.FxmlLoaderFactory;
8 |
9 | import javafx.scene.Scene;
10 | import java.util.ResourceBundle;
11 | import java.util.concurrent.CompletableFuture;
12 |
13 | @Module
14 | interface PassphraseEntryModule {
15 |
16 | @Provides
17 | @PassphraseEntryScoped
18 | static CompletableFuture provideResult() {
19 | return new CompletableFuture<>();
20 | }
21 |
22 | @Provides
23 | @PassphraseEntryScoped
24 | static Scene provideUnlockScene(PassphraseEntryController controller, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
25 | return FxmlLoaderFactory.forController(controller, sceneFactory, resourceBundle).createScene(FxmlFile.UNLOCK_ENTER_PASSWORD);
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/resources/fxml/vault_detail_welcome.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/dist/linux/debian/control:
--------------------------------------------------------------------------------
1 | Source: cryptomator
2 | Maintainer: Cryptobot
3 | Section: utils
4 | Priority: optional
5 | Build-Depends: debhelper (>=10), coffeelibs-jdk-23 (>= 23.0.1+11-0ppa1), libgtk-3-0, libxxf86vm1, libgl1
6 | Standards-Version: 4.5.0
7 | Homepage: https://cryptomator.org
8 | Vcs-Git: https://github.com/cryptomator/cryptomator.git
9 | Vcs-browser: https://github.com/cryptomator/cryptomator
10 |
11 | Package: cryptomator
12 | Architecture: any
13 | Section: utils
14 | Priority: optional
15 | Depends: ${shlibs:Depends}, ${misc:Depends}, fuse3
16 | Recommends: gvfs-backends, gvfs-fuse, gnome-keyring
17 | XB-AppName: Cryptomator
18 | XB-Category: Utility;Security;FileTools;
19 | Homepage: https://cryptomator.org
20 | Description: Multi-platform client-side encryption of your cloud files.
21 | Cryptomator provides free client-side AES encryption for your cloud files.
22 | Create encrypted vaults, which get mounted as virtual volumes. Whatever
23 | you save on one of these volumes will end up encrypted inside your vault.
24 |
--------------------------------------------------------------------------------
/src/test/java/org/cryptomator/ipc/RevealRunningAppMessageTest.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ipc;
2 |
3 | import org.junit.jupiter.api.Assertions;
4 | import org.junit.jupiter.api.Test;
5 | import org.junit.jupiter.api.io.TempDir;
6 |
7 | import java.io.IOException;
8 | import java.nio.channels.FileChannel;
9 | import java.nio.file.Path;
10 | import java.nio.file.StandardOpenOption;
11 | import java.util.List;
12 |
13 | public class RevealRunningAppMessageTest {
14 |
15 | @Test
16 | public void testSendAndReceive(@TempDir Path tmpDir) throws IOException {
17 | var message = new RevealRunningAppMessage();
18 |
19 | var file = tmpDir.resolve("tmp.file");
20 | try (var ch = FileChannel.open(file, StandardOpenOption.CREATE_NEW, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
21 | message.send(ch);
22 | ch.position(0);
23 | if (IpcMessage.receive(ch) instanceof RevealRunningAppMessage received) {
24 | Assertions.assertNotNull(received);
25 | } else {
26 | Assertions.fail("Received message of unexpected class");
27 | }
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailNeedsMigrationController.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.mainwindow;
2 |
3 | import org.cryptomator.common.vaults.Vault;
4 | import org.cryptomator.ui.common.FxController;
5 | import org.cryptomator.ui.migration.MigrationComponent;
6 |
7 | import javax.inject.Inject;
8 | import javafx.beans.property.ObjectProperty;
9 | import javafx.beans.property.ReadOnlyObjectProperty;
10 | import javafx.fxml.FXML;
11 |
12 | @MainWindowScoped
13 | public class VaultDetailNeedsMigrationController implements FxController {
14 |
15 | private final ReadOnlyObjectProperty vault;
16 | private final MigrationComponent.Builder vaultMigrationWindow;
17 |
18 | @Inject
19 | public VaultDetailNeedsMigrationController(ObjectProperty vault, MigrationComponent.Builder vaultMigrationWindow) {
20 | this.vault = vault;
21 | this.vaultMigrationWindow = vaultMigrationWindow;
22 | }
23 |
24 | @FXML
25 | public void showVaultMigrator() {
26 | vaultMigrationWindow.vault(vault.get()).build().showMigrationWindow();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/resources/fxml/addvault_new_recoverykey.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/common/locationpresets/MegaLocationPresetsProvider.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.common.locationpresets;
2 |
3 | import org.cryptomator.integrations.common.CheckAvailability;
4 | import org.cryptomator.integrations.common.OperatingSystem;
5 |
6 | import java.nio.file.Files;
7 | import java.nio.file.Path;
8 | import java.util.stream.Stream;
9 |
10 | import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
11 | import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
12 |
13 | @OperatingSystem(WINDOWS)
14 | @OperatingSystem(MAC)
15 | @CheckAvailability
16 | public final class MegaLocationPresetsProvider implements LocationPresetsProvider {
17 |
18 | private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/MEGA");
19 |
20 | @CheckAvailability
21 | public static boolean isPresent() {
22 | return Files.isDirectory(LOCATION);
23 | }
24 |
25 | @Override
26 | public Stream getLocations() {
27 | return Stream.of(new LocationPreset("MEGA", LOCATION));
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/fxapp/FxApplicationComponent.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2017 Skymatic UG (haftungsbeschränkt).
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the accompanying LICENSE file.
5 | *******************************************************************************/
6 | package org.cryptomator.ui.fxapp;
7 |
8 | import dagger.BindsInstance;
9 | import dagger.Subcomponent;
10 |
11 | import javafx.application.Application;
12 | import javafx.stage.Stage;
13 |
14 | @FxApplicationScoped
15 | @Subcomponent(modules = FxApplicationModule.class)
16 | public interface FxApplicationComponent {
17 |
18 | FxApplication application();
19 |
20 | @Subcomponent.Builder
21 | interface Builder {
22 |
23 | @BindsInstance
24 | Builder fxApplication(Application application);
25 |
26 | @BindsInstance
27 | Builder primaryStage(@PrimaryStage Stage primaryStage);
28 |
29 | FxApplicationComponent build();
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/logging/LaunchBasedTriggeringPolicy.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2017 Skymatic UG (haftungsbeschränkt).
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the accompanying LICENSE file.
5 | *******************************************************************************/
6 | package org.cryptomator.logging;
7 |
8 | import ch.qos.logback.core.rolling.TriggeringPolicyBase;
9 |
10 | import java.io.File;
11 | import java.util.concurrent.atomic.AtomicBoolean;
12 |
13 | /**
14 | * Triggers a roll-over on the first log event, so each launched application instance will rotate the log.
15 | */
16 | public class LaunchBasedTriggeringPolicy extends TriggeringPolicyBase {
17 |
18 | private final AtomicBoolean shouldTrigger = new AtomicBoolean(true);
19 |
20 | @Override
21 | public boolean isTriggeringEvent(File activeFile, E event) {
22 | return shouldTrigger.get() && shouldTrigger.getAndSet(false);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/keyloading/masterkeyfile/ChooseMasterkeyFileModule.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.keyloading.masterkeyfile;
2 |
3 | import dagger.Module;
4 | import dagger.Provides;
5 | import org.cryptomator.ui.common.DefaultSceneFactory;
6 | import org.cryptomator.ui.common.FxmlFile;
7 | import org.cryptomator.ui.common.FxmlLoaderFactory;
8 |
9 | import javafx.scene.Scene;
10 | import java.nio.file.Path;
11 | import java.util.ResourceBundle;
12 | import java.util.concurrent.CompletableFuture;
13 |
14 | @Module
15 | interface ChooseMasterkeyFileModule {
16 |
17 | @Provides
18 | @ChooseMasterkeyFileScoped
19 | static CompletableFuture provideResult() {
20 | return new CompletableFuture<>();
21 | }
22 |
23 | @Provides
24 | @ChooseMasterkeyFileScoped
25 | static Scene provideChooseMasterkeyScene(ChooseMasterkeyFileController controller, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
26 | return FxmlLoaderFactory.forController(controller, sceneFactory, resourceBundle).createScene(FxmlFile.UNLOCK_SELECT_MASTERKEYFILE);
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/common/locationpresets/LeitzcloudLocationPresetsProvider.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.common.locationpresets;
2 |
3 | import org.cryptomator.integrations.common.CheckAvailability;
4 | import org.cryptomator.integrations.common.OperatingSystem;
5 |
6 | import java.nio.file.Files;
7 | import java.nio.file.Path;
8 | import java.util.stream.Stream;
9 |
10 | import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
11 | import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
12 |
13 | @OperatingSystem(WINDOWS)
14 | @OperatingSystem(MAC)
15 | @CheckAvailability
16 | public final class LeitzcloudLocationPresetsProvider implements LocationPresetsProvider {
17 |
18 | private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/leitzcloud");
19 |
20 | @CheckAvailability
21 | public static boolean isPresent() {
22 | return Files.isDirectory(LOCATION);
23 | }
24 |
25 | @Override
26 | public Stream getLocations() {
27 | return Stream.of(new LocationPreset("leitzcloud", LOCATION));
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/resources/fxml/recoverykey_success.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/test/java/org/cryptomator/ipc/LoopbackCommunicatorTest.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ipc;
2 |
3 | import org.junit.jupiter.api.Assertions;
4 | import org.junit.jupiter.api.Test;
5 | import org.junit.jupiter.api.function.Executable;
6 |
7 | import java.time.Duration;
8 | import java.util.List;
9 | import java.util.concurrent.CountDownLatch;
10 | import java.util.concurrent.Executors;
11 |
12 | public class LoopbackCommunicatorTest {
13 |
14 | @Test
15 | public void testSendAndReceive() {
16 | try (var communicator = new LoopbackCommunicator()) {
17 | var cdl = new CountDownLatch(1);
18 | var executor = Executors.newSingleThreadExecutor();
19 | communicator.listen(new IpcMessageListener() {
20 | @Override
21 | public void revealRunningApp() {
22 | cdl.countDown();
23 | }
24 |
25 | @Override
26 | public void handleLaunchArgs(List args) {
27 |
28 | }
29 | }, executor);
30 | communicator.sendRevealRunningApp();
31 |
32 | Assertions.assertTimeoutPreemptively(Duration.ofMillis(300), (Executable) cdl::await);
33 | executor.shutdown();
34 | }
35 | }
36 |
37 | }
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/common/ObservableUtil.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.common;
2 |
3 | import javafx.beans.binding.Bindings;
4 | import javafx.beans.value.ObservableValue;
5 | import java.util.Objects;
6 | import java.util.function.Function;
7 | import java.util.function.Supplier;
8 |
9 | public class ObservableUtil {
10 |
11 | public static ObservableValue mapWithDefault(ObservableValue observable, Function super T, ? extends U> mapper, U defaultValue) {
12 | return Bindings.createObjectBinding(() -> {
13 | if (observable.getValue() == null) {
14 | return defaultValue;
15 | } else {
16 | return mapper.apply(observable.getValue());
17 | }
18 | }, observable);
19 | }
20 |
21 | public static ObservableValue mapWithDefault(ObservableValue observable, Function super T, ? extends U> mapper, Supplier defaultValue) {
22 | return Bindings.createObjectBinding(() -> {
23 | if (observable.getValue() == null) {
24 | return defaultValue.get();
25 | } else {
26 | return mapper.apply(observable.getValue());
27 | }
28 | }, observable);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/Cryptomator_Linux.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/keyloading/hub/UnauthorizedDeviceController.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.keyloading.hub;
2 |
3 | import com.nimbusds.jose.JWEObject;
4 | import org.cryptomator.ui.common.FxController;
5 | import org.cryptomator.ui.keyloading.KeyLoading;
6 | import org.cryptomator.ui.keyloading.KeyLoadingScoped;
7 |
8 | import javax.inject.Inject;
9 | import javafx.fxml.FXML;
10 | import javafx.stage.Stage;
11 | import javafx.stage.WindowEvent;
12 | import java.util.concurrent.CompletableFuture;
13 |
14 | @KeyLoadingScoped
15 | public class UnauthorizedDeviceController implements FxController {
16 |
17 | private final Stage window;
18 | private final CompletableFuture result;
19 |
20 | @Inject
21 | public UnauthorizedDeviceController(@KeyLoading Stage window, CompletableFuture result) {
22 | this.window = window;
23 | this.result = result;
24 | this.window.addEventHandler(WindowEvent.WINDOW_HIDING, this::windowClosed);
25 | }
26 |
27 | @FXML
28 | public void close() {
29 | window.close();
30 | }
31 |
32 | private void windowClosed(WindowEvent windowEvent) {
33 | result.cancel(true);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/unlock/UnlockComponent.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2017 Skymatic UG (haftungsbeschränkt).
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the accompanying LICENSE file.
5 | *******************************************************************************/
6 | package org.cryptomator.ui.unlock;
7 |
8 | import dagger.BindsInstance;
9 | import dagger.Subcomponent;
10 | import org.cryptomator.common.Nullable;
11 | import org.cryptomator.common.vaults.Vault;
12 |
13 | import javax.inject.Named;
14 | import javafx.stage.Stage;
15 | import java.util.concurrent.ExecutorService;
16 | import java.util.concurrent.Future;
17 |
18 | @UnlockScoped
19 | @Subcomponent(modules = {UnlockModule.class})
20 | public interface UnlockComponent {
21 |
22 | UnlockWorkflow unlockWorkflow();
23 |
24 | @Subcomponent.Factory
25 | interface Factory {
26 | UnlockComponent create(@BindsInstance @UnlockWindow Vault vault, @BindsInstance @Named("unlockWindowOwner") @Nullable Stage owner);
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordComponent.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.changepassword;
2 |
3 | import dagger.BindsInstance;
4 | import dagger.Lazy;
5 | import dagger.Subcomponent;
6 | import org.cryptomator.common.vaults.Vault;
7 | import org.cryptomator.ui.common.FxmlFile;
8 | import org.cryptomator.ui.common.FxmlScene;
9 |
10 | import javax.inject.Named;
11 | import javafx.scene.Scene;
12 | import javafx.stage.Stage;
13 |
14 | @ChangePasswordScoped
15 | @Subcomponent(modules = {ChangePasswordModule.class})
16 | public interface ChangePasswordComponent {
17 |
18 | @ChangePasswordWindow
19 | Stage window();
20 |
21 | @FxmlScene(FxmlFile.CHANGEPASSWORD)
22 | Lazy scene();
23 |
24 | default void showChangePasswordWindow() {
25 | Stage stage = window();
26 | stage.setScene(scene().get());
27 | stage.show();
28 | }
29 |
30 | @Subcomponent.Builder
31 | interface Builder {
32 |
33 | @BindsInstance
34 | Builder vault(@ChangePasswordWindow Vault vault);
35 |
36 | @BindsInstance
37 | Builder owner(@Named("changePasswordOwner") Stage owner);
38 |
39 | ChangePasswordComponent build();
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/common/vaults/VaultComponent.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2017 Skymatic UG (haftungsbeschränkt).
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the accompanying LICENSE file.
5 | *******************************************************************************/
6 | package org.cryptomator.common.vaults;
7 |
8 | import dagger.BindsInstance;
9 | import dagger.Subcomponent;
10 | import org.cryptomator.common.Nullable;
11 | import org.cryptomator.common.settings.VaultSettings;
12 |
13 | import javax.inject.Named;
14 |
15 | @PerVault
16 | @Subcomponent(modules = {VaultModule.class})
17 | public interface VaultComponent {
18 |
19 | Vault vault();
20 |
21 | @Subcomponent.Factory
22 | interface Factory {
23 |
24 | VaultComponent create(@BindsInstance VaultSettings vaultSettings, //
25 | @BindsInstance VaultConfigCache configCache, //
26 | @BindsInstance VaultState.Value vaultState, //
27 | @BindsInstance @Nullable @Named("lastKnownException") Exception initialErrorCause);
28 |
29 | }
30 | }
--------------------------------------------------------------------------------
/src/test/java/org/cryptomator/common/settings/VaultSettingsTest.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2016, 2017 Sebastian Stenzel and others.
3 | * All rights reserved.
4 | * This program and the accompanying materials are made available under the terms of the accompanying LICENSE file.
5 | *
6 | * Contributors:
7 | * Sebastian Stenzel - initial API and implementation
8 | *******************************************************************************/
9 | package org.cryptomator.common.settings;
10 |
11 | import org.junit.jupiter.params.ParameterizedTest;
12 | import org.junit.jupiter.params.provider.CsvSource;
13 |
14 | import static org.junit.jupiter.api.Assertions.assertEquals;
15 |
16 | public class VaultSettingsTest {
17 |
18 | @ParameterizedTest(name = "VaultSettings.normalizeDisplayName({0}) = {1}")
19 | @CsvSource(value = {
20 | "a\u000Fa,a_a",
21 | ": \\,_ _",
22 | "汉语,汉语",
23 | "..,_",
24 | "a\ta,a\u0020a",
25 | "'\t\n\r',_"
26 | })
27 | public void testNormalize(String test, String expected) {
28 | assertEquals(expected, VaultSettings.normalizeDisplayName(test));
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/.github/workflows/stale.yml:
--------------------------------------------------------------------------------
1 | # Configuration for close-stale-issues - https://github.com/marketplace/actions/close-stale-issues
2 |
3 | name: 'Close stale issues'
4 | on:
5 | schedule:
6 | - cron: '00 09 * * *'
7 |
8 | jobs:
9 | stale:
10 | runs-on: ubuntu-latest
11 | permissions:
12 | issues: write
13 | pull-requests: write
14 | steps:
15 | - uses: actions/stale@v9
16 | with:
17 | days-before-stale: 365
18 | days-before-close: 90
19 | exempt-issue-labels: 'type:security-issue,type:feature-request,type:enhancement,type:upstream-bug,state:awaiting-response,state:blocked,state:confirmed'
20 | exempt-all-milestones: true
21 | stale-issue-label: 'state:stale'
22 | stale-pr-label: 'state:stale'
23 | stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'
24 | stale-pr-message: 'This PR has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'
25 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/Cryptomator_Linux_Dev.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/test/java/org/cryptomator/launcher/SupportedLanguagesTest.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.launcher;
2 |
3 | import org.junit.jupiter.api.Assertions;
4 | import org.junit.jupiter.api.DisplayName;
5 | import org.junit.jupiter.params.ParameterizedTest;
6 | import org.junit.jupiter.params.provider.MethodSource;
7 |
8 | import java.util.Locale;
9 | import java.util.ResourceBundle;
10 | import java.util.stream.Stream;
11 |
12 | public class SupportedLanguagesTest {
13 |
14 | @DisplayName("test if resource bundle is localized")
15 | @ParameterizedTest(name = "{0}")
16 | @MethodSource("languageTags")
17 | public void testResourceBundleExists(String tag) {
18 | var locale = Locale.forLanguageTag(tag);
19 | Assertions.assertNotEquals("und", locale.toLanguageTag(), "Undefined language tag");
20 |
21 | var bundle = Assertions.assertDoesNotThrow(() -> ResourceBundle.getBundle("i18n.strings", locale));
22 |
23 | Assertions.assertEquals(locale, bundle.getLocale());
24 | Assertions.assertFalse(bundle.keySet().isEmpty());
25 | }
26 |
27 | public static Stream languageTags() {
28 | return SupportedLanguages.LANGUAGE_TAGS.stream() //
29 | .filter(tag -> !"en".equals(tag)); // english uses the default bundle
30 | }
31 | }
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/migration/MigrationStartController.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.migration;
2 |
3 | import dagger.Lazy;
4 | import org.cryptomator.common.vaults.Vault;
5 | import org.cryptomator.ui.common.FxController;
6 | import org.cryptomator.ui.common.FxmlFile;
7 | import org.cryptomator.ui.common.FxmlScene;
8 |
9 | import javax.inject.Inject;
10 | import javafx.fxml.FXML;
11 | import javafx.scene.Scene;
12 | import javafx.stage.Stage;
13 |
14 | @MigrationScoped
15 | public class MigrationStartController implements FxController {
16 |
17 | private final Stage window;
18 | private final Vault vault;
19 | private final Lazy runMigrationScene;
20 |
21 | @Inject
22 | public MigrationStartController(@MigrationWindow Stage window, @MigrationWindow Vault vault, @FxmlScene(FxmlFile.MIGRATION_RUN) Lazy runMigrationScene) {
23 | this.window = window;
24 | this.vault = vault;
25 | this.runMigrationScene = runMigrationScene;
26 | }
27 |
28 | @FXML
29 | public void cancel() {
30 | window.close();
31 | }
32 |
33 | @FXML
34 | public void proceed() {
35 | window.setScene(runMigrationScene.get());
36 | }
37 |
38 | /* Getter/Setter */
39 |
40 | public Vault getVault() {
41 | return vault;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/health/HealthCheckComponent.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.health;
2 |
3 | import dagger.BindsInstance;
4 | import dagger.Lazy;
5 | import dagger.Subcomponent;
6 | import org.cryptomator.common.vaults.Vault;
7 | import org.cryptomator.cryptofs.VaultConfig;
8 | import org.cryptomator.ui.common.FxmlFile;
9 | import org.cryptomator.ui.common.FxmlScene;
10 |
11 | import javax.inject.Named;
12 | import javafx.scene.Scene;
13 | import javafx.stage.Stage;
14 |
15 | @HealthCheckScoped
16 | @Subcomponent(modules = {HealthCheckModule.class})
17 | public interface HealthCheckComponent {
18 |
19 | @HealthCheckWindow
20 | Stage window();
21 |
22 | @FxmlScene(FxmlFile.HEALTH_START)
23 | Lazy startScene();
24 |
25 | default Stage showHealthCheckWindow() {
26 | Stage stage = window();
27 | stage.setScene(startScene().get());
28 | stage.setMinWidth(420);
29 | stage.setMinHeight(300);
30 | stage.show();
31 | return stage;
32 | }
33 |
34 | @Subcomponent.Builder
35 | interface Builder {
36 |
37 | @BindsInstance
38 | Builder vault(@HealthCheckWindow Vault vault);
39 |
40 | @BindsInstance
41 | Builder owner(@Named("healthCheckOwner") Stage owner);
42 |
43 | HealthCheckComponent build();
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/logging/LaunchAndSizeBasedTriggeringPolicy.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.logging;
2 |
3 | import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy;
4 | import ch.qos.logback.core.rolling.TriggeringPolicyBase;
5 | import ch.qos.logback.core.util.FileSize;
6 |
7 | import java.io.File;
8 |
9 | /**
10 | * Triggers a roll-over either on the first log event or if watched log file reaches a certain size
11 | *
12 | * @param Event type the policy possibly reacts to
13 | */
14 | public class LaunchAndSizeBasedTriggeringPolicy extends TriggeringPolicyBase {
15 |
16 | LaunchBasedTriggeringPolicy launchBasedTriggeringPolicy;
17 | SizeBasedTriggeringPolicy sizeBasedTriggeringPolicy;
18 |
19 | public LaunchAndSizeBasedTriggeringPolicy(FileSize threshold) {
20 | this.launchBasedTriggeringPolicy = new LaunchBasedTriggeringPolicy<>();
21 | this.sizeBasedTriggeringPolicy = new SizeBasedTriggeringPolicy<>();
22 | sizeBasedTriggeringPolicy.setMaxFileSize(threshold);
23 | }
24 |
25 | @Override
26 | public boolean isTriggeringEvent(File activeFile, E event) {
27 | return launchBasedTriggeringPolicy.isTriggeringEvent(activeFile, event) || sizeBasedTriggeringPolicy.isTriggeringEvent(activeFile, event);
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/migration/MigrationImpossibleController.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.migration;
2 |
3 | import org.cryptomator.common.vaults.Vault;
4 | import org.cryptomator.ui.common.FxController;
5 |
6 | import javax.inject.Inject;
7 | import javafx.application.Application;
8 | import javafx.fxml.FXML;
9 | import javafx.stage.Stage;
10 |
11 | public class MigrationImpossibleController implements FxController {
12 |
13 | private static final String HELP_URI = "https://docs.cryptomator.org/help/manual-migration/";
14 |
15 | private final Application application;
16 | private final Stage window;
17 | private final Vault vault;
18 |
19 | @Inject
20 | MigrationImpossibleController(Application application, @MigrationWindow Stage window, @MigrationWindow Vault vault) {
21 | this.application = application;
22 | this.window = window;
23 | this.vault = vault;
24 | }
25 |
26 | @FXML
27 | public void close() {
28 | window.close();
29 | }
30 |
31 | @FXML
32 | public void getMigrationHelp() {
33 | application.getHostServices().showDocument(HELP_URI);
34 | }
35 |
36 | /* Getter/Setters */
37 |
38 | public Vault getVault() {
39 | return vault;
40 | }
41 |
42 | public String getHelpUri() {
43 | return HELP_URI;
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/resources/fxml/preferences_about.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/common/vaults/VaultListChangeListener.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.common.vaults;
2 |
3 | import org.cryptomator.common.settings.VaultSettings;
4 |
5 | import javafx.collections.ListChangeListener;
6 | import javafx.collections.ObservableList;
7 | import java.util.List;
8 | import java.util.stream.Collectors;
9 |
10 | /**
11 | * This listener makes sure to reflect any changes to the vault list back to the settings.
12 | */
13 | class VaultListChangeListener implements ListChangeListener {
14 |
15 | private final ObservableList vaultSettingsList;
16 |
17 | public VaultListChangeListener(ObservableList vaultSettingsList) {
18 | this.vaultSettingsList = vaultSettingsList;
19 | }
20 |
21 | @Override
22 | public void onChanged(Change extends Vault> c) {
23 | while (c.next()) {
24 | if (c.wasAdded()) {
25 | List addedSettings = c.getAddedSubList().stream().map(Vault::getVaultSettings).toList();
26 | vaultSettingsList.addAll(c.getFrom(), addedSettings);
27 | } else if (c.wasRemoved()) {
28 | List removedSettings = c.getRemoved().stream().map(Vault::getVaultSettings).toList();
29 | vaultSettingsList.removeAll(removedSettings);
30 | }
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/Cryptomator_Windows.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.github/workflows/av-whitelist.yml:
--------------------------------------------------------------------------------
1 | name: AntiVirus Whitelisting
2 |
3 | on:
4 | workflow_call:
5 | inputs:
6 | url:
7 | description: "Url to the file to upload"
8 | required: true
9 | type: string
10 | workflow_dispatch:
11 | inputs:
12 | url:
13 | description: "Url to the file to upload"
14 | required: true
15 | type: string
16 |
17 | jobs:
18 | allowlist:
19 | name: Anti Virus Allowlisting
20 | runs-on: ubuntu-latest
21 | steps:
22 | - name: Download file
23 | run: |
24 | curl --remote-name ${{ inputs.url }} -L
25 | - name: Upload to Kaspersky
26 | uses: SamKirkland/FTP-Deploy-Action@v4.3.5
27 | with:
28 | protocol: ftps
29 | server: allowlist.kaspersky-labs.com
30 | port: 990
31 | username: ${{ secrets.ALLOWLIST_KASPERSKY_USERNAME }}
32 | password: ${{ secrets.ALLOWLIST_KASPERSKY_PASSWORD }}
33 | - name: Upload to Avast
34 | uses: SamKirkland/FTP-Deploy-Action@v4.3.5
35 | with:
36 | protocol: ftp
37 | server: whitelisting.avast.com
38 | port: 21
39 | username: ${{ secrets.ALLOWLIST_AVAST_USERNAME }}
40 | password: ${{ secrets.ALLOWLIST_AVAST_PASSWORD }}
--------------------------------------------------------------------------------
/src/main/resources/fxml/convertvault_hubtopassword_start.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/dist/linux/debian/prerm:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # prerm script for Cryptomator
3 | #
4 | # see: dh_installdeb(1)
5 |
6 | set -e
7 |
8 | # summary of how this script can be called:
9 | # * `remove'
10 | # * `upgrade'
11 | # * `failed-upgrade'
12 | # * `remove' `in-favour'
13 | # * `deconfigure' `in-favour'
14 | # `removing'
15 | #
16 | # for details, see http://www.debian.org/doc/debian-policy/ or
17 | # the debian-policy package
18 |
19 |
20 | case "$1" in
21 | remove|upgrade|deconfigure)
22 | echo Removing shortcut
23 |
24 | xdg-desktop-menu uninstall --novendor /usr/share/applications/org.cryptomator.Cryptomator.desktop
25 | xdg-mime uninstall /usr/share/mime/packages/application-vnd.cryptomator.vault.xml
26 | ;;
27 |
28 | failed-upgrade)
29 | ;;
30 |
31 | *)
32 | echo "prerm called with unknown argument \`$1'" >&2
33 | exit 1
34 | ;;
35 | esac
36 |
37 | # dh_installdeb will replace this with shell code automatically
38 | # generated by other debhelper scripts.
39 |
40 | #DEBHELPER#
41 |
42 | exit 0
43 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/mainwindow/MainWindowComponent.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2017 Skymatic UG (haftungsbeschränkt).
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the accompanying LICENSE file.
5 | *******************************************************************************/
6 | package org.cryptomator.ui.mainwindow;
7 |
8 | import dagger.Lazy;
9 | import dagger.Subcomponent;
10 | import org.cryptomator.ui.common.FxmlFile;
11 | import org.cryptomator.ui.common.FxmlScene;
12 |
13 | import javafx.scene.Scene;
14 | import javafx.stage.Stage;
15 |
16 | @MainWindowScoped
17 | @Subcomponent(modules = {MainWindowModule.class})
18 | public interface MainWindowComponent {
19 |
20 | @MainWindow
21 | Stage window();
22 |
23 | @FxmlScene(FxmlFile.MAIN_WINDOW)
24 | Lazy scene();
25 |
26 | default Stage showMainWindow() {
27 | Stage stage = window();
28 | stage.setScene(scene().get());
29 | stage.setIconified(false);
30 | stage.show();
31 | stage.toFront();
32 | stage.requestFocus();
33 | return stage;
34 | }
35 |
36 | @Subcomponent.Builder
37 | interface Builder {
38 |
39 | MainWindowComponent build();
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/migration/MigrationSuccessController.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.migration;
2 |
3 | import org.cryptomator.common.vaults.Vault;
4 | import org.cryptomator.ui.common.FxController;
5 | import org.cryptomator.ui.fxapp.FxApplicationWindows;
6 | import org.cryptomator.ui.fxapp.PrimaryStage;
7 |
8 | import javax.inject.Inject;
9 | import javafx.fxml.FXML;
10 | import javafx.stage.Stage;
11 |
12 | @MigrationScoped
13 | public class MigrationSuccessController implements FxController {
14 |
15 | private final FxApplicationWindows appWindows;
16 | private final Stage window;
17 | private final Vault vault;
18 | private final Stage mainWindow;
19 |
20 | @Inject
21 | MigrationSuccessController(FxApplicationWindows appWindows, @MigrationWindow Stage window, @MigrationWindow Vault vault, @PrimaryStage Stage mainWindow) {
22 | this.appWindows = appWindows;
23 | this.window = window;
24 | this.vault = vault;
25 | this.mainWindow = mainWindow;
26 | }
27 |
28 | @FXML
29 | public void unlockAndClose() {
30 | close();
31 | appWindows.startUnlockWorkflow(vault, mainWindow);
32 | }
33 |
34 | @FXML
35 | public void close() {
36 | window.close();
37 | }
38 |
39 | /* Getter/Setters */
40 |
41 | public Vault getVault() {
42 | return vault;
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/resources/fxml/addvault_existing.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/Cryptomator_macOS.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/main/resources/fxml/recoverykey_reset_password.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/main/resources/fxml/recoverykey_recover.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/Cryptomator_Windows_Dev.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.github/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | ## Reporting a Vulnerability
4 |
5 | We take security seriously at Cryptomator. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions.
6 |
7 | To report a security vulnerability, please use the [GitHub Security Advisory feature](https://github.com/cryptomator/cryptomator/security/advisories). This feature allows you to privately discuss, fix, and publish information about security vulnerabilities.
8 |
9 | If you prefer to report the vulnerability via email, please send an email to security@cryptomator.org.
10 |
11 | PGP key fingerprint: `3647 9903 B23A E0A5 9359 9A3E 23B5 DBEF 94D4 D81D` ([public key](https://gist.github.com/cryptobot/864300b6b44ae2d2a15abedfe14bd040))
12 |
13 | ## Expectations
14 |
15 | When reporting a vulnerability, please provide us with a detailed report that includes:
16 |
17 | - A description of the vulnerability
18 | - Steps to reproduce the vulnerability
19 | - Possible impact of the vulnerability
20 | - Any additional information that may be helpful
21 |
22 | We ask that you do not publicly disclose the vulnerability until we have had a chance to address it.
23 |
24 | ## Thank You
25 |
26 | We appreciate your help in keeping Cryptomator secure. Thank you for your contributions to the security of our project.
27 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/updatereminder/UpdateReminderController.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.updatereminder;
2 |
3 | import org.cryptomator.common.settings.Settings;
4 | import org.cryptomator.ui.common.FxController;
5 | import org.cryptomator.ui.fxapp.UpdateChecker;
6 |
7 | import javax.inject.Inject;
8 | import javafx.fxml.FXML;
9 | import javafx.stage.Stage;
10 | import java.time.Instant;
11 |
12 | @UpdateReminderScoped
13 | public class UpdateReminderController implements FxController {
14 |
15 | private final Stage window;
16 | private final Settings settings;
17 | private final UpdateChecker updateChecker;
18 |
19 |
20 | @Inject
21 | UpdateReminderController(@UpdateReminderWindow Stage window, Settings settings, UpdateChecker updateChecker) {
22 | this.window = window;
23 | this.settings = settings;
24 | this.updateChecker = updateChecker;
25 | }
26 |
27 | @FXML
28 | public void initialize() {
29 | settings.lastUpdateCheckReminder.set(Instant.now());
30 | }
31 |
32 | @FXML
33 | public void cancel() {
34 | window.close();
35 | }
36 |
37 | @FXML
38 | public void once() {
39 | updateChecker.checkForUpdatesNow();
40 | window.close();
41 | }
42 |
43 | @FXML
44 | public void automatically() {
45 | updateChecker.checkForUpdatesNow();
46 | settings.checkForUpdates.set(true);
47 | window.close();
48 | }
49 |
50 | }
--------------------------------------------------------------------------------
/src/main/resources/fxml/vault_list_cell.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/common/locationpresets/DropboxMacLocationPresetsProvider.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.common.locationpresets;
2 |
3 | import org.cryptomator.integrations.common.CheckAvailability;
4 | import org.cryptomator.integrations.common.OperatingSystem;
5 |
6 | import java.nio.file.Files;
7 | import java.nio.file.Path;
8 | import java.util.stream.Stream;
9 |
10 | import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
11 |
12 | @OperatingSystem(MAC)
13 | @CheckAvailability
14 | public final class DropboxMacLocationPresetsProvider implements LocationPresetsProvider {
15 |
16 | private static final Path LOCATION = LocationPresetsProvider.resolveLocation("~/Library/CloudStorage/Dropbox");
17 | private static final Path FALLBACK_LOCATION = LocationPresetsProvider.resolveLocation("~/Dropbox");
18 |
19 |
20 | @CheckAvailability
21 | public static boolean isPresent() {
22 | return Files.isDirectory(LOCATION) || Files.isDirectory(FALLBACK_LOCATION);
23 | }
24 |
25 | @Override
26 | public Stream getLocations() {
27 | if(Files.isDirectory(LOCATION)) {
28 | return Stream.of(new LocationPreset("Dropbox", LOCATION));
29 | } else if(Files.isDirectory(FALLBACK_LOCATION)) {
30 | return Stream.of(new LocationPreset("Dropbox", FALLBACK_LOCATION));
31 | } else {
32 | return Stream.of();
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/convertvault/HubToPasswordStartController.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.convertvault;
2 |
3 | import dagger.Lazy;
4 | import org.cryptomator.ui.common.FxController;
5 | import org.cryptomator.ui.common.FxmlFile;
6 | import org.cryptomator.ui.common.FxmlScene;
7 | import org.cryptomator.ui.recoverykey.RecoveryKeyValidateController;
8 |
9 | import javax.inject.Inject;
10 | import javafx.fxml.FXML;
11 | import javafx.scene.Scene;
12 | import javafx.stage.Stage;
13 |
14 | public class HubToPasswordStartController implements FxController {
15 |
16 | private final Stage window;
17 | private final Lazy convertScene;
18 |
19 | @FXML
20 | RecoveryKeyValidateController recoveryKeyValidateController;
21 |
22 | @Inject
23 | public HubToPasswordStartController(@ConvertVaultWindow Stage window, @FxmlScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_CONVERT) Lazy convertScene) {
24 | this.window = window;
25 | this.convertScene = convertScene;
26 | }
27 |
28 | @FXML
29 | public void initialize() {
30 | }
31 |
32 | @FXML
33 | public void close() {
34 | window.close();
35 | }
36 |
37 | @FXML
38 | public void next() {
39 | window.setScene(convertScene.get());
40 | }
41 |
42 | /* Getter/Setter */
43 |
44 | public RecoveryKeyValidateController getValidateController() {
45 | return recoveryKeyValidateController;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/.idea/runConfigurations/Cryptomator_macOS_Dev.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyComponent.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.recoverykey;
2 |
3 | import dagger.BindsInstance;
4 | import dagger.Lazy;
5 | import dagger.Subcomponent;
6 | import org.cryptomator.common.vaults.Vault;
7 | import org.cryptomator.ui.common.FxmlFile;
8 | import org.cryptomator.ui.common.FxmlScene;
9 |
10 | import javax.inject.Named;
11 | import javafx.scene.Scene;
12 | import javafx.stage.Stage;
13 |
14 | @RecoveryKeyScoped
15 | @Subcomponent(modules = {RecoveryKeyModule.class})
16 | public interface RecoveryKeyComponent {
17 |
18 | @RecoveryKeyWindow
19 | Stage window();
20 |
21 | @FxmlScene(FxmlFile.RECOVERYKEY_CREATE)
22 | Lazy creationScene();
23 |
24 | @FxmlScene(FxmlFile.RECOVERYKEY_RECOVER)
25 | Lazy recoverScene();
26 |
27 | default void showRecoveryKeyCreationWindow() {
28 | Stage stage = window();
29 | stage.setScene(creationScene().get());
30 | stage.sizeToScene();
31 | stage.show();
32 | }
33 |
34 | default void showRecoveryKeyRecoverWindow() {
35 | Stage stage = window();
36 | stage.setScene(recoverScene().get());
37 | stage.sizeToScene();
38 | stage.show();
39 | }
40 |
41 |
42 | @Subcomponent.Factory
43 | interface Factory {
44 |
45 | RecoveryKeyComponent create(@BindsInstance @RecoveryKeyWindow Vault vault, @BindsInstance @Named("keyRecoveryOwner") Stage owner);
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/common/keychain/KeychainModule.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.common.keychain;
2 |
3 | import dagger.Module;
4 | import dagger.Provides;
5 | import org.cryptomator.common.settings.Settings;
6 | import org.cryptomator.integrations.keychain.KeychainAccessProvider;
7 |
8 | import javax.inject.Singleton;
9 | import javafx.beans.binding.Bindings;
10 | import javafx.beans.binding.ObjectExpression;
11 | import java.util.List;
12 |
13 | @Module
14 | public class KeychainModule {
15 |
16 | @Provides
17 | @Singleton
18 | static List provideSupportedKeychainAccessProviders() {
19 | return KeychainAccessProvider.get().toList();
20 | }
21 |
22 | @Provides
23 | @Singleton
24 | static ObjectExpression provideKeychainAccessProvider(Settings settings, List providers) {
25 | return Bindings.createObjectBinding(() -> {
26 | if (!settings.useKeychain.get()) {
27 | return null;
28 | }
29 | var selectedProviderClass = settings.keychainProvider.get();
30 | var selectedProvider = providers.stream().filter(provider -> provider.getClass().getName().equals(selectedProviderClass)).findAny();
31 | var fallbackProvider = providers.stream().findFirst().orElse(null);
32 | return selectedProvider.orElse(fallbackProvider);
33 | }, settings.keychainProvider, settings.useKeychain);
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/common/locationpresets/PCloudLocationPresetsProvider.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.common.locationpresets;
2 |
3 | import org.cryptomator.integrations.common.CheckAvailability;
4 | import org.cryptomator.integrations.common.OperatingSystem;
5 |
6 | import java.nio.file.Files;
7 | import java.nio.file.Path;
8 | import java.util.Arrays;
9 | import java.util.List;
10 | import java.util.stream.Stream;
11 |
12 | import static org.cryptomator.integrations.common.OperatingSystem.Value.MAC;
13 | import static org.cryptomator.integrations.common.OperatingSystem.Value.WINDOWS;
14 |
15 | @OperatingSystem(WINDOWS)
16 | @OperatingSystem(MAC)
17 | @CheckAvailability
18 | public final class PCloudLocationPresetsProvider implements LocationPresetsProvider {
19 |
20 | private static final List LOCATIONS = Arrays.asList( //
21 | LocationPresetsProvider.resolveLocation("~/pCloudDrive"), //
22 | LocationPresetsProvider.resolveLocation("~/pCloud Drive") //
23 | );
24 |
25 | @CheckAvailability
26 | public static boolean isPresent() {
27 | return LOCATIONS.stream().anyMatch(Files::isDirectory);
28 | }
29 |
30 | @Override
31 | public Stream getLocations() {
32 | return LOCATIONS.stream() //
33 | .filter(Files::isDirectory) //
34 | .map(location -> new LocationPreset("pCloud", location)) //
35 | .findFirst() //
36 | .stream();
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/networking/SSLContextDifferentTrustStoreBase.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.networking;
2 |
3 | import javax.net.ssl.SSLContext;
4 | import javax.net.ssl.TrustManagerFactory;
5 | import java.io.IOException;
6 | import java.security.KeyManagementException;
7 | import java.security.KeyStore;
8 | import java.security.KeyStoreException;
9 | import java.security.NoSuchAlgorithmException;
10 | import java.security.SecureRandom;
11 | import java.security.cert.CertificateException;
12 |
13 | abstract class SSLContextDifferentTrustStoreBase implements SSLContextProvider {
14 |
15 | abstract KeyStore getTruststore() throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException;
16 |
17 | @Override
18 | public SSLContext getContext(SecureRandom csprng) throws SSLContextBuildException {
19 | try {
20 | KeyStore truststore = getTruststore();
21 | truststore.load(null, null);
22 |
23 | TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
24 | tmf.init(truststore);
25 |
26 | SSLContext context = SSLContext.getInstance("TLS");
27 | context.init(null, tmf.getTrustManagers(), csprng);
28 | return context;
29 | } catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | KeyManagementException | IOException e) {
30 | throw new SSLContextBuildException(e);
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultSuccessController.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.addvaultwizard;
2 |
3 | import org.cryptomator.common.vaults.Vault;
4 | import org.cryptomator.ui.common.FxController;
5 | import org.cryptomator.ui.fxapp.FxApplicationWindows;
6 |
7 | import javax.inject.Inject;
8 | import javafx.beans.property.ObjectProperty;
9 | import javafx.beans.property.ReadOnlyObjectProperty;
10 | import javafx.fxml.FXML;
11 | import javafx.stage.Stage;
12 |
13 | @AddVaultWizardScoped
14 | public class AddVaultSuccessController implements FxController {
15 |
16 | private final FxApplicationWindows appWindows;
17 | private final Stage window;
18 | private final ReadOnlyObjectProperty vault;
19 |
20 | @Inject
21 | AddVaultSuccessController(FxApplicationWindows appWindows, @AddVaultWizardWindow Stage window, @AddVaultWizardWindow ObjectProperty vault) {
22 | this.appWindows = appWindows;
23 | this.window = window;
24 | this.vault = vault;
25 | }
26 |
27 | @FXML
28 | public void unlockAndClose() {
29 | close();
30 | appWindows.startUnlockWorkflow(vault.get(), window);
31 | }
32 |
33 | @FXML
34 | public void close() {
35 | window.close();
36 | }
37 |
38 | /* Observables */
39 |
40 | public ReadOnlyObjectProperty vaultProperty() {
41 | return vault;
42 | }
43 |
44 | public Vault getVault() {
45 | return vault.get();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/test/java/org/cryptomator/ui/recoverykey/WordEncoderTest.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.recoverykey;
2 |
3 | import org.junit.jupiter.api.Assertions;
4 | import org.junit.jupiter.api.BeforeAll;
5 | import org.junit.jupiter.api.DisplayName;
6 | import org.junit.jupiter.api.TestInstance;
7 | import org.junit.jupiter.params.ParameterizedTest;
8 | import org.junit.jupiter.params.provider.MethodSource;
9 |
10 | import java.util.Random;
11 | import java.util.stream.IntStream;
12 | import java.util.stream.Stream;
13 |
14 | @TestInstance(TestInstance.Lifecycle.PER_CLASS)
15 | public class WordEncoderTest {
16 |
17 | private static final Random PRNG = new Random(42l);
18 | private WordEncoder encoder;
19 |
20 | @BeforeAll
21 | public void setup() {
22 | encoder = new WordEncoder();
23 | }
24 |
25 | @DisplayName("decode(encode(input)) == input")
26 | @ParameterizedTest(name = "test {index}")
27 | @MethodSource("createRandomByteSequences")
28 | public void encodeAndDecode(byte[] input) {
29 | String encoded = encoder.encodePadded(input);
30 | byte[] decoded = encoder.decode(encoded);
31 | Assertions.assertArrayEquals(input, decoded);
32 | }
33 |
34 | public static Stream createRandomByteSequences() {
35 | return IntStream.range(0, 30).mapToObj(i -> {
36 | byte[] randomBytes = new byte[i * 3];
37 | PRNG.nextBytes(randomBytes);
38 | return randomBytes;
39 | });
40 | }
41 |
42 | }
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ui/health/Result.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.health;
2 |
3 | import org.cryptomator.cryptofs.VaultConfig;
4 | import org.cryptomator.cryptofs.health.api.DiagnosticResult;
5 | import org.cryptomator.cryptolib.api.Cryptor;
6 | import org.cryptomator.cryptolib.api.Masterkey;
7 |
8 | import javafx.beans.Observable;
9 | import javafx.beans.property.ObjectProperty;
10 | import javafx.beans.property.SimpleObjectProperty;
11 | import java.nio.file.Path;
12 |
13 | record Result(DiagnosticResult diagnosis, ObjectProperty fixState) {
14 |
15 | enum FixState {
16 | NOT_FIXABLE,
17 | FIXABLE,
18 | FIXING,
19 | FIXED,
20 | FIX_FAILED
21 | }
22 |
23 | public static Result create(DiagnosticResult diagnosis, Path vaultPath, VaultConfig config, Masterkey masterkey, Cryptor cryptor) {
24 | FixState initialState = diagnosis.getFix(vaultPath, config, masterkey, cryptor).map( _f -> FixState.FIXABLE).orElse(FixState.NOT_FIXABLE);
25 | return new Result(diagnosis, new SimpleObjectProperty<>(initialState));
26 | }
27 |
28 | public Observable[] observables() {
29 | return new Observable[]{fixState};
30 | }
31 |
32 | public String getDescription() {
33 | return diagnosis.toString();
34 | }
35 |
36 | public FixState getState() {
37 | return fixState.get();
38 | }
39 |
40 | public void setState(FixState state) {
41 | this.fixState.set(state);
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/test/java/org/cryptomator/ui/changepassword/PasswordStrengthUtilTest.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ui.changepassword;
2 |
3 | import com.google.common.base.Strings;
4 | import org.cryptomator.common.Environment;
5 | import org.cryptomator.ui.changepassword.PasswordStrengthUtil;
6 | import org.junit.jupiter.api.Assertions;
7 | import org.junit.jupiter.api.Test;
8 | import org.mockito.Mockito;
9 |
10 | import java.time.Duration;
11 | import java.util.ResourceBundle;
12 |
13 | public class PasswordStrengthUtilTest {
14 |
15 | @Test
16 | public void testLongPasswords() {
17 | PasswordStrengthUtil util = new PasswordStrengthUtil(Mockito.mock(ResourceBundle.class), Mockito.mock(Environment.class));
18 | String longPw = Strings.repeat("x", 10_000);
19 | Assertions.assertTimeout(Duration.ofSeconds(5), () -> {
20 | util.computeRate(longPw);
21 | });
22 | }
23 |
24 | @Test
25 | public void testIssue979() {
26 | PasswordStrengthUtil util = new PasswordStrengthUtil(Mockito.mock(ResourceBundle.class), Mockito.mock(Environment.class));
27 | int result1 = util.computeRate("backed derrick buckling mountains glove client procedures desire destination sword hidden ram");
28 | int result2 = util.computeRate("backed derrick buckling mountains glove client procedures desire destination sword hidden ram escalation");
29 | Assertions.assertEquals(4, result1);
30 | Assertions.assertEquals(4, result2);
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/ipc/LoopbackCommunicator.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ipc;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import java.util.concurrent.Executor;
7 | import java.util.concurrent.LinkedTransferQueue;
8 | import java.util.concurrent.TransferQueue;
9 |
10 | class LoopbackCommunicator implements IpcCommunicator {
11 |
12 | private static final Logger LOG = LoggerFactory.getLogger(LoopbackCommunicator.class);
13 |
14 | private final TransferQueue transferQueue = new LinkedTransferQueue<>();
15 |
16 | @Override
17 | public boolean isClient() {
18 | return false;
19 | }
20 |
21 | @Override
22 | public void listen(IpcMessageListener listener, Executor executor) {
23 | executor.execute(() -> {
24 | try {
25 | var msg = transferQueue.take();
26 | listener.handleMessage(msg);
27 | } catch (InterruptedException e) {
28 | LOG.error("Failed to read IPC message", e);
29 | Thread.currentThread().interrupt();
30 | }
31 | });
32 | }
33 |
34 | @Override
35 | public void send(IpcMessage message, Executor executor) {
36 | executor.execute(() -> {
37 | try {
38 | transferQueue.put(message);
39 | } catch (InterruptedException e) {
40 | LOG.error("Failed to send IPC message", e);
41 | Thread.currentThread().interrupt();
42 | }
43 | });
44 | }
45 |
46 | @Override
47 | public void close() {
48 | // no-op
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/test/java/org/cryptomator/ipc/IpcCommunicatorTest.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.ipc;
2 |
3 | import org.junit.jupiter.api.Assertions;
4 | import org.junit.jupiter.api.Test;
5 | import org.junit.jupiter.api.function.Executable;
6 | import org.junit.jupiter.api.io.TempDir;
7 |
8 | import java.io.IOException;
9 | import java.nio.file.Path;
10 | import java.time.Duration;
11 | import java.util.List;
12 | import java.util.concurrent.CountDownLatch;
13 | import java.util.concurrent.Executors;
14 |
15 | public class IpcCommunicatorTest {
16 |
17 | @Test
18 | public void testSendAndReceive(@TempDir Path tmpDir) throws IOException, InterruptedException {
19 | var socketPath = tmpDir.resolve("foo.sock");
20 | try (var server = IpcCommunicator.create(List.of(socketPath));
21 | var client = IpcCommunicator.create(List.of(socketPath))) {
22 | Assertions.assertNotSame(server, client);
23 |
24 | var cdl = new CountDownLatch(1);
25 | var executor = Executors.newSingleThreadExecutor();
26 | server.listen(new IpcMessageListener() {
27 | @Override
28 | public void revealRunningApp() {
29 | cdl.countDown();
30 | }
31 |
32 | @Override
33 | public void handleLaunchArgs(List args) {
34 |
35 | }
36 | }, executor);
37 | client.sendRevealRunningApp();
38 |
39 | Assertions.assertTimeoutPreemptively(Duration.ofMillis(300), (Executable) cdl::await);
40 | executor.shutdown();
41 | }
42 | }
43 |
44 | }
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/launcher/IpcMessageHandler.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.launcher;
2 |
3 | import org.cryptomator.ipc.IpcMessageListener;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 |
7 | import javax.inject.Inject;
8 | import javax.inject.Named;
9 | import javax.inject.Singleton;
10 | import java.util.Collections;
11 | import java.util.List;
12 | import java.util.concurrent.BlockingQueue;
13 |
14 | @Singleton
15 | class IpcMessageHandler implements IpcMessageListener {
16 |
17 | private static final Logger LOG = LoggerFactory.getLogger(IpcMessageHandler.class);
18 |
19 | private final FileOpenRequestHandler fileOpenRequestHandler;
20 | private final BlockingQueue launchEventQueue;
21 |
22 | @Inject
23 | public IpcMessageHandler(FileOpenRequestHandler fileOpenRequestHandler, @Named("launchEventQueue") BlockingQueue launchEventQueue) {
24 | this.fileOpenRequestHandler = fileOpenRequestHandler;
25 | this.launchEventQueue = launchEventQueue;
26 | }
27 |
28 | @Override
29 | public void revealRunningApp() {
30 | launchEventQueue.add(new AppLaunchEvent(AppLaunchEvent.EventType.REVEAL_APP, Collections.emptyList()));
31 | }
32 |
33 | @Override
34 | public void handleLaunchArgs(List args) {
35 | LOG.debug("Received launch args: {}", args.stream().reduce((a, b) -> a + ", " + b).orElse(""));
36 | fileOpenRequestHandler.handleLaunchArgs(args);
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/resources/fxml/vault_list_contextmenu.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/main/java/org/cryptomator/common/mount/MountModule.java:
--------------------------------------------------------------------------------
1 | package org.cryptomator.common.mount;
2 |
3 | import dagger.Module;
4 | import dagger.Provides;
5 | import org.cryptomator.common.ObservableUtil;
6 | import org.cryptomator.common.settings.Settings;
7 | import org.cryptomator.integrations.mount.MountService;
8 |
9 | import javax.inject.Named;
10 | import javax.inject.Singleton;
11 | import javafx.beans.value.ObservableValue;
12 | import java.util.List;
13 | import java.util.Set;
14 | import java.util.concurrent.ConcurrentHashMap;
15 |
16 | @Module
17 | public class MountModule {
18 |
19 | @Provides
20 | @Singleton
21 | static List provideSupportedMountServices() {
22 | return MountService.get().toList();
23 | }
24 |
25 | @Provides
26 | @Singleton
27 | static ObservableValue provideDefaultMountService(List mountProviders, Settings settings) {
28 | var fallbackProvider = mountProviders.stream().findFirst().get(); //there should always be a mount provider, at least webDAV
29 | return ObservableUtil.mapWithDefault(settings.mountService, //
30 | serviceName -> mountProviders.stream().filter(s -> s.getClass().getName().equals(serviceName)).findFirst().orElse(fallbackProvider), //
31 | fallbackProvider);
32 | }
33 |
34 | @Provides
35 | @Singleton
36 | @Named("usedMountServices")
37 | static Set provideSetOfUsedMountServices() {
38 | return ConcurrentHashMap.newKeySet();
39 | }
40 |
41 | }
--------------------------------------------------------------------------------
/src/main/resources/fxml/convertvault_hubtopassword_convert.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/src/test/java/org/cryptomator/logging/LaunchBasedTriggeringPolicyTest.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * Copyright (c) 2017 Skymatic UG (haftungsbeschränkt).
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the accompanying LICENSE file.
5 | *******************************************************************************/
6 | package org.cryptomator.logging;
7 |
8 | import org.junit.jupiter.api.Assertions;
9 | import org.junit.jupiter.api.Test;
10 | import org.mockito.Mockito;
11 |
12 | import java.io.File;
13 |
14 | public class LaunchBasedTriggeringPolicyTest {
15 |
16 | @Test
17 | public void testTriggerOnceAndNeverAgain() {
18 | LaunchBasedTriggeringPolicy