Merge branch 'release/1.2.0'
# Conflicts: # main/ant-kit/pom.xml # main/commons-test/pom.xml # main/commons/pom.xml # main/filesystem-api/pom.xml # main/filesystem-charsets/pom.xml # main/filesystem-crypto-integration-tests/pom.xml # main/filesystem-crypto/pom.xml # main/filesystem-inmemory/pom.xml # main/filesystem-invariants-tests/pom.xml # main/filesystem-nameshortening/pom.xml # main/filesystem-nio/pom.xml # main/filesystem-stats/pom.xml # main/frontend-api/pom.xml # main/frontend-webdav/pom.xml # main/jacoco-report/pom.xml # main/pom.xml # main/uber-jar/pom.xml # main/ui/pom.xml
@@ -8,10 +8,12 @@
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.ui;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.cryptomator.jni.MacFunctions;
|
||||
import org.cryptomator.ui.controllers.MainController;
|
||||
import org.cryptomator.ui.settings.Localization;
|
||||
import org.cryptomator.ui.util.AsyncTaskService;
|
||||
@@ -34,4 +36,7 @@ interface CryptomatorComponent {
|
||||
Localization localization();
|
||||
|
||||
ExitUtil exitUtil();
|
||||
}
|
||||
|
||||
Optional<MacFunctions> nativeMacFunctions();
|
||||
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.ui;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
@@ -16,10 +18,16 @@ import javax.inject.Singleton;
|
||||
|
||||
import org.cryptomator.common.CommonsModule;
|
||||
import org.cryptomator.crypto.engine.impl.CryptoEngineModule;
|
||||
import org.cryptomator.cryptolib.CryptoLibModule;
|
||||
import org.cryptomator.frontend.FrontendFactory;
|
||||
import org.cryptomator.frontend.FrontendId;
|
||||
import org.cryptomator.frontend.webdav.WebDavModule;
|
||||
import org.cryptomator.frontend.webdav.WebDavServer;
|
||||
import org.cryptomator.jni.JniModule;
|
||||
import org.cryptomator.keychain.KeychainModule;
|
||||
import org.cryptomator.ui.model.Vault;
|
||||
import org.cryptomator.ui.model.VaultObjectMapperProvider;
|
||||
import org.cryptomator.ui.model.Vaults;
|
||||
import org.cryptomator.ui.settings.Settings;
|
||||
import org.cryptomator.ui.settings.SettingsProvider;
|
||||
import org.cryptomator.ui.util.DeferredCloser;
|
||||
@@ -31,9 +39,10 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import javafx.application.Application;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
@Module(includes = {CryptoEngineModule.class, CommonsModule.class, WebDavModule.class})
|
||||
@Module(includes = {CryptoEngineModule.class, CommonsModule.class, WebDavModule.class, KeychainModule.class, JniModule.class, CryptoLibModule.class})
|
||||
class CryptomatorModule {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(CryptomatorModule.class);
|
||||
@@ -93,10 +102,17 @@ class CryptomatorModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
FrontendFactory provideFrontendFactory(DeferredCloser closer, WebDavServer webDavServer, Settings settings) {
|
||||
FrontendFactory provideFrontendFactory(DeferredCloser closer, WebDavServer webDavServer, Vaults vaults, Settings settings) {
|
||||
vaults.addListener((Observable o) -> setValidFrontendIds(webDavServer, vaults));
|
||||
setValidFrontendIds(webDavServer, vaults);
|
||||
webDavServer.setPort(settings.getPort());
|
||||
webDavServer.start();
|
||||
return closer.closeLater(webDavServer, WebDavServer::stop).get().orElseThrow(IllegalStateException::new);
|
||||
}
|
||||
|
||||
private void setValidFrontendIds(WebDavServer webDavServer, Vaults vaults) {
|
||||
webDavServer.setValidFrontendIds(vaults.stream() //
|
||||
.map(Vault::getId).map(FrontendId::from).collect(toList()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.awt.event.ActionEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -32,6 +33,9 @@ import javax.script.ScriptException;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.jni.JniException;
|
||||
import org.cryptomator.jni.MacApplicationUiState;
|
||||
import org.cryptomator.jni.MacFunctions;
|
||||
import org.cryptomator.ui.settings.Localization;
|
||||
import org.cryptomator.ui.settings.Settings;
|
||||
import org.slf4j.Logger;
|
||||
@@ -48,12 +52,14 @@ class ExitUtil {
|
||||
private final Stage mainWindow;
|
||||
private final Localization localization;
|
||||
private final Settings settings;
|
||||
private final Optional<MacFunctions> macFunctions;
|
||||
|
||||
@Inject
|
||||
public ExitUtil(@Named("mainWindow") Stage mainWindow, Localization localization, Settings settings) {
|
||||
public ExitUtil(@Named("mainWindow") Stage mainWindow, Localization localization, Settings settings, Optional<MacFunctions> macFunctions) {
|
||||
this.mainWindow = mainWindow;
|
||||
this.localization = localization;
|
||||
this.settings = settings;
|
||||
this.macFunctions = macFunctions;
|
||||
}
|
||||
|
||||
public void initExitHandler(Runnable exitCommand) {
|
||||
@@ -88,6 +94,7 @@ class ExitUtil {
|
||||
if (Platform.isImplicitExit()) {
|
||||
exitCommand.run();
|
||||
} else {
|
||||
macFunctions.map(MacFunctions::uiState).ifPresent(JniException.ignore(MacApplicationUiState::transformToAgentApplication));
|
||||
mainWindow.close();
|
||||
this.showTrayNotification(trayIcon);
|
||||
}
|
||||
@@ -189,6 +196,7 @@ class ExitUtil {
|
||||
|
||||
private void restoreFromTray(ActionEvent event) {
|
||||
Platform.runLater(() -> {
|
||||
macFunctions.map(MacFunctions::uiState).ifPresent(JniException.ignore(MacApplicationUiState::transformToForegroundApplication));
|
||||
mainWindow.show();
|
||||
mainWindow.requestFocus();
|
||||
});
|
||||
|
||||
@@ -12,9 +12,12 @@ import java.io.IOException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.cryptolib.common.SecureRandomModule;
|
||||
import org.cryptomator.ui.controllers.MainController;
|
||||
import org.cryptomator.ui.util.ActiveWindowStyleSupport;
|
||||
import org.cryptomator.ui.util.DeferredCloser;
|
||||
@@ -40,7 +43,15 @@ public class MainApplication extends Application {
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws IOException {
|
||||
LOG.info("JavaFX application started");
|
||||
final CryptomatorComponent comp = DaggerCryptomatorComponent.builder().cryptomatorModule(new CryptomatorModule(this, primaryStage)).build();
|
||||
final CryptomatorComponent comp;
|
||||
try {
|
||||
comp = DaggerCryptomatorComponent.builder() //
|
||||
.cryptomatorModule(new CryptomatorModule(this, primaryStage)) //
|
||||
.secureRandomModule(new SecureRandomModule(SecureRandom.getInstanceStrong())) //
|
||||
.build();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException("Every implementation of the Java platform is required to support at least one strong SecureRandom implementation.", e);
|
||||
}
|
||||
final MainController mainCtrl = comp.mainController();
|
||||
closer = comp.deferredCloser();
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ package org.cryptomator.ui.controllers;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.URL;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -31,9 +32,7 @@ import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.BooleanBinding;
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Button;
|
||||
@@ -49,9 +48,9 @@ public class ChangePasswordController extends LocalizedFXMLViewController {
|
||||
|
||||
private final Application app;
|
||||
private final PasswordStrengthUtil strengthRater;
|
||||
final ObjectProperty<Vault> vault = new SimpleObjectProperty<>();
|
||||
private Optional<ChangePasswordListener> listener = Optional.empty();
|
||||
private final IntegerProperty passwordStrength = new SimpleIntegerProperty(); // 0-4
|
||||
private Optional<ChangePasswordListener> listener = Optional.empty();
|
||||
private Vault vault;
|
||||
|
||||
@Inject
|
||||
public ChangePasswordController(Application app, PasswordStrengthUtil strengthRater, Localization localization) {
|
||||
@@ -101,7 +100,6 @@ public class ChangePasswordController extends LocalizedFXMLViewController {
|
||||
BooleanBinding oldPasswordIsEmpty = oldPasswordField.textProperty().isEmpty();
|
||||
BooleanBinding newPasswordIsEmpty = newPasswordField.textProperty().isEmpty();
|
||||
BooleanBinding passwordsDiffer = newPasswordField.textProperty().isNotEqualTo(retypePasswordField.textProperty());
|
||||
EasyBind.subscribe(vault, this::vaultDidChange);
|
||||
changePasswordButton.disableProperty().bind(oldPasswordIsEmpty.or(newPasswordIsEmpty.or(passwordsDiffer)));
|
||||
passwordStrength.bind(EasyBind.map(newPasswordField.textProperty(), strengthRater::computeRate));
|
||||
|
||||
@@ -118,13 +116,15 @@ public class ChangePasswordController extends LocalizedFXMLViewController {
|
||||
return getClass().getResource("/fxml/change_password.fxml");
|
||||
}
|
||||
|
||||
private void vaultDidChange(Vault newVault) {
|
||||
oldPasswordField.clear();
|
||||
newPasswordField.clear();
|
||||
retypePasswordField.clear();
|
||||
void setVault(Vault vault) {
|
||||
this.vault = Objects.requireNonNull(vault);
|
||||
oldPasswordField.swipe();
|
||||
newPasswordField.swipe();
|
||||
retypePasswordField.swipe();
|
||||
// trigger "default" change to refresh key bindings:
|
||||
changePasswordButton.setDefaultButton(false);
|
||||
changePasswordButton.setDefaultButton(true);
|
||||
messageText.setText(null);
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
@@ -144,8 +144,8 @@ public class ChangePasswordController extends LocalizedFXMLViewController {
|
||||
private void didClickChangePasswordButton(ActionEvent event) {
|
||||
downloadsPageLink.setVisible(false);
|
||||
try {
|
||||
vault.get().changePassphrase(oldPasswordField.getCharacters(), newPasswordField.getCharacters());
|
||||
messageText.setText(localization.getString("changePassword.infoMessage.success"));
|
||||
vault.changePassphrase(oldPasswordField.getCharacters(), newPasswordField.getCharacters());
|
||||
messageText.setText(null);
|
||||
listener.ifPresent(this::invokeListenerLater);
|
||||
} catch (InvalidPassphraseException e) {
|
||||
messageText.setText(localization.getString("changePassword.errorMessage.wrongPassword"));
|
||||
|
||||
@@ -10,9 +10,10 @@
|
||||
package org.cryptomator.ui.controllers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.DirectoryNotEmptyException;
|
||||
import java.nio.file.FileAlreadyExistsException;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -29,9 +30,7 @@ import org.slf4j.LoggerFactory;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.BooleanBinding;
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Button;
|
||||
@@ -44,9 +43,9 @@ public class InitializeController extends LocalizedFXMLViewController {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(InitializeController.class);
|
||||
|
||||
private final PasswordStrengthUtil strengthRater;
|
||||
final ObjectProperty<Vault> vault = new SimpleObjectProperty<>();
|
||||
private Optional<InitializationListener> listener = Optional.empty();
|
||||
private final IntegerProperty passwordStrength = new SimpleIntegerProperty(); // 0-4
|
||||
private Optional<InitializationListener> listener = Optional.empty();
|
||||
private Vault vault;
|
||||
|
||||
@Inject
|
||||
public InitializeController(Localization localization, PasswordStrengthUtil strengthRater) {
|
||||
@@ -88,7 +87,6 @@ public class InitializeController extends LocalizedFXMLViewController {
|
||||
public void initialize() {
|
||||
BooleanBinding passwordIsEmpty = passwordField.textProperty().isEmpty();
|
||||
BooleanBinding passwordsDiffer = passwordField.textProperty().isNotEqualTo(retypePasswordField.textProperty());
|
||||
EasyBind.subscribe(vault, this::vaultDidChange);
|
||||
okButton.disableProperty().bind(passwordIsEmpty.or(passwordsDiffer));
|
||||
passwordStrength.bind(EasyBind.map(passwordField.textProperty(), strengthRater::computeRate));
|
||||
|
||||
@@ -105,9 +103,10 @@ public class InitializeController extends LocalizedFXMLViewController {
|
||||
return getClass().getResource("/fxml/initialize.fxml");
|
||||
}
|
||||
|
||||
private void vaultDidChange(Vault newVault) {
|
||||
passwordField.clear();
|
||||
retypePasswordField.clear();
|
||||
void setVault(Vault vault) {
|
||||
this.vault = Objects.requireNonNull(vault);
|
||||
passwordField.swipe();
|
||||
retypePasswordField.swipe();
|
||||
// trigger "default" change to refresh key bindings:
|
||||
okButton.setDefaultButton(false);
|
||||
okButton.setDefaultButton(true);
|
||||
@@ -121,11 +120,13 @@ public class InitializeController extends LocalizedFXMLViewController {
|
||||
protected void initializeVault(ActionEvent event) {
|
||||
final CharSequence passphrase = passwordField.getCharacters();
|
||||
try {
|
||||
vault.get().create(passphrase);
|
||||
vault.create(passphrase);
|
||||
listener.ifPresent(this::invokeListenerLater);
|
||||
} catch (FileAlreadyExistsException ex) {
|
||||
messageLabel.setText(localization.getString("initialize.messageLabel.alreadyInitialized"));
|
||||
} catch (UncheckedIOException | IOException ex) {
|
||||
} catch (DirectoryNotEmptyException ex) {
|
||||
messageLabel.setText(localization.getString("initialize.messageLabel.notEmpty"));
|
||||
} catch (IOException ex) {
|
||||
LOG.error("I/O Exception", ex);
|
||||
messageLabel.setText(localization.getString("initialize.messageLabel.initializationFailed"));
|
||||
} finally {
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.cryptomator.ui.controls.DirectoryListCell;
|
||||
import org.cryptomator.ui.model.UpgradeStrategies;
|
||||
import org.cryptomator.ui.model.Vault;
|
||||
import org.cryptomator.ui.model.VaultFactory;
|
||||
import org.cryptomator.ui.model.Vaults;
|
||||
import org.cryptomator.ui.settings.Localization;
|
||||
import org.cryptomator.ui.settings.Settings;
|
||||
import org.cryptomator.ui.util.DialogBuilderUtil;
|
||||
@@ -44,9 +45,6 @@ import javafx.beans.binding.BooleanBinding;
|
||||
import javafx.beans.binding.BooleanExpression;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ListChangeListener.Change;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.geometry.Side;
|
||||
@@ -81,7 +79,7 @@ public class MainController extends LocalizedFXMLViewController {
|
||||
private final Lazy<SettingsController> settingsController;
|
||||
private final Lazy<UpgradeStrategies> upgradeStrategies;
|
||||
private final ObjectProperty<AbstractFXMLViewController> activeController = new SimpleObjectProperty<>();
|
||||
private final ObservableList<Vault> vaults;
|
||||
private final Vaults vaults;
|
||||
private final ObjectProperty<Vault> selectedVault = new SimpleObjectProperty<>();
|
||||
private final BooleanExpression isSelectedVaultUnlocked = BooleanBinding.booleanExpression(EasyBind.select(selectedVault).selectObject(Vault::unlockedProperty).orElse(false));
|
||||
private final BooleanExpression isSelectedVaultValid = BooleanBinding.booleanExpression(EasyBind.monadic(selectedVault).map(Vault::isValidVaultDirectory).orElse(false));
|
||||
@@ -92,7 +90,8 @@ public class MainController extends LocalizedFXMLViewController {
|
||||
@Inject
|
||||
public MainController(@Named("mainWindow") Stage mainWindow, Localization localization, Settings settings, VaultFactory vaultFactoy, Lazy<WelcomeController> welcomeController,
|
||||
Lazy<InitializeController> initializeController, Lazy<NotFoundController> notFoundController, Lazy<UpgradeController> upgradeController, Lazy<UnlockController> unlockController,
|
||||
Provider<UnlockedController> unlockedControllerProvider, Lazy<ChangePasswordController> changePasswordController, Lazy<SettingsController> settingsController, Lazy<UpgradeStrategies> upgradeStrategies) {
|
||||
Provider<UnlockedController> unlockedControllerProvider, Lazy<ChangePasswordController> changePasswordController, Lazy<SettingsController> settingsController, Lazy<UpgradeStrategies> upgradeStrategies,
|
||||
Vaults vaults) {
|
||||
super(localization);
|
||||
this.mainWindow = mainWindow;
|
||||
this.vaultFactoy = vaultFactoy;
|
||||
@@ -105,10 +104,7 @@ public class MainController extends LocalizedFXMLViewController {
|
||||
this.changePasswordController = changePasswordController;
|
||||
this.settingsController = settingsController;
|
||||
this.upgradeStrategies = upgradeStrategies;
|
||||
this.vaults = FXCollections.observableList(settings.getDirectories());
|
||||
this.vaults.addListener((Change<? extends Vault> c) -> {
|
||||
settings.save();
|
||||
});
|
||||
this.vaults = vaults;
|
||||
|
||||
// derived bindings:
|
||||
this.isShowingSettings = activeController.isEqualTo(settingsController.get());
|
||||
@@ -319,7 +315,8 @@ public class MainController extends LocalizedFXMLViewController {
|
||||
|
||||
private void showInitializeView() {
|
||||
final InitializeController ctrl = initializeController.get();
|
||||
ctrl.vault.bind(selectedVault);
|
||||
ctrl.loadFxml();
|
||||
ctrl.setVault(selectedVault.get());
|
||||
ctrl.setListener(this::didInitialize);
|
||||
activeController.set(ctrl);
|
||||
}
|
||||
@@ -330,7 +327,8 @@ public class MainController extends LocalizedFXMLViewController {
|
||||
|
||||
private void showUpgradeView() {
|
||||
final UpgradeController ctrl = upgradeController.get();
|
||||
ctrl.vault.bind(selectedVault);
|
||||
ctrl.loadFxml();
|
||||
ctrl.setVault(selectedVault.get());
|
||||
ctrl.setListener(this::didUpgrade);
|
||||
activeController.set(ctrl);
|
||||
}
|
||||
@@ -341,7 +339,8 @@ public class MainController extends LocalizedFXMLViewController {
|
||||
|
||||
private void showUnlockView() {
|
||||
final UnlockController ctrl = unlockController.get();
|
||||
ctrl.vault.bind(selectedVault);
|
||||
ctrl.loadFxml();
|
||||
ctrl.setVault(selectedVault.get());
|
||||
ctrl.setListener(this::didUnlock);
|
||||
activeController.set(ctrl);
|
||||
}
|
||||
@@ -357,6 +356,7 @@ public class MainController extends LocalizedFXMLViewController {
|
||||
final UnlockedController ctrl = unlockedVaults.computeIfAbsent(vault, k -> {
|
||||
return unlockedControllerProvider.get();
|
||||
});
|
||||
ctrl.loadFxml();
|
||||
ctrl.setVault(vault);
|
||||
ctrl.setListener(this::didLock);
|
||||
activeController.set(ctrl);
|
||||
@@ -372,7 +372,8 @@ public class MainController extends LocalizedFXMLViewController {
|
||||
|
||||
private void showChangePasswordView() {
|
||||
final ChangePasswordController ctrl = changePasswordController.get();
|
||||
ctrl.vault.bind(selectedVault);
|
||||
ctrl.loadFxml();
|
||||
ctrl.setVault(selectedVault.get());
|
||||
ctrl.setListener(this::didChangePassword);
|
||||
activeController.set(ctrl);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
package org.cryptomator.ui.controllers;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -22,25 +24,24 @@ import org.cryptomator.frontend.CommandFailedException;
|
||||
import org.cryptomator.frontend.FrontendCreationFailedException;
|
||||
import org.cryptomator.frontend.FrontendFactory;
|
||||
import org.cryptomator.frontend.webdav.mount.WindowsDriveLetters;
|
||||
import org.cryptomator.keychain.KeychainAccess;
|
||||
import org.cryptomator.ui.controls.SecPasswordField;
|
||||
import org.cryptomator.ui.model.Vault;
|
||||
import org.cryptomator.ui.settings.Localization;
|
||||
import org.cryptomator.ui.settings.Settings;
|
||||
import org.cryptomator.ui.util.AsyncTaskService;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import dagger.Lazy;
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.ChoiceBox;
|
||||
import javafx.scene.control.Hyperlink;
|
||||
import javafx.scene.control.Label;
|
||||
@@ -61,22 +62,34 @@ public class UnlockController extends LocalizedFXMLViewController {
|
||||
private final Settings settings;
|
||||
private final WindowsDriveLetters driveLetters;
|
||||
private final ChangeListener<Character> driveLetterChangeListener = this::winDriveLetterDidChange;
|
||||
final ObjectProperty<Vault> vault = new SimpleObjectProperty<>();
|
||||
private final Optional<KeychainAccess> keychainAccess;
|
||||
private Vault vault;
|
||||
private Optional<UnlockListener> listener = Optional.empty();
|
||||
|
||||
@Inject
|
||||
public UnlockController(Application app, Localization localization, AsyncTaskService asyncTaskService, Lazy<FrontendFactory> frontendFactory, Settings settings, WindowsDriveLetters driveLetters) {
|
||||
public UnlockController(Application app, Localization localization, AsyncTaskService asyncTaskService, Lazy<FrontendFactory> frontendFactory, Settings settings, WindowsDriveLetters driveLetters,
|
||||
Optional<KeychainAccess> keychainAccess) {
|
||||
super(localization);
|
||||
this.app = app;
|
||||
this.asyncTaskService = asyncTaskService;
|
||||
this.frontendFactory = frontendFactory;
|
||||
this.settings = settings;
|
||||
this.driveLetters = driveLetters;
|
||||
this.keychainAccess = keychainAccess;
|
||||
}
|
||||
|
||||
@FXML
|
||||
private SecPasswordField passwordField;
|
||||
|
||||
@FXML
|
||||
private Button advancedOptionsButton;
|
||||
|
||||
@FXML
|
||||
private Button unlockButton;
|
||||
|
||||
@FXML
|
||||
private CheckBox savePassword;
|
||||
|
||||
@FXML
|
||||
private TextField mountName;
|
||||
|
||||
@@ -86,12 +99,6 @@ public class UnlockController extends LocalizedFXMLViewController {
|
||||
@FXML
|
||||
private ChoiceBox<Character> winDriveLetter;
|
||||
|
||||
@FXML
|
||||
private Button advancedOptionsButton;
|
||||
|
||||
@FXML
|
||||
private Button unlockButton;
|
||||
|
||||
@FXML
|
||||
private ProgressIndicator progressIndicator;
|
||||
|
||||
@@ -107,8 +114,10 @@ public class UnlockController extends LocalizedFXMLViewController {
|
||||
@Override
|
||||
public void initialize() {
|
||||
advancedOptions.managedProperty().bind(advancedOptions.visibleProperty());
|
||||
unlockButton.disableProperty().bind(passwordField.textProperty().isEmpty());
|
||||
mountName.addEventFilter(KeyEvent.KEY_TYPED, this::filterAlphanumericKeyEvents);
|
||||
mountName.textProperty().addListener(this::mountNameDidChange);
|
||||
savePassword.setDisable(!keychainAccess.isPresent());
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
winDriveLetter.setConverter(new WinDriveLetterLabelConverter());
|
||||
} else {
|
||||
@@ -117,9 +126,6 @@ public class UnlockController extends LocalizedFXMLViewController {
|
||||
winDriveLetter.setVisible(false);
|
||||
winDriveLetter.setManaged(false);
|
||||
}
|
||||
unlockButton.disableProperty().bind(passwordField.textProperty().isEmpty());
|
||||
|
||||
EasyBind.subscribe(vault, this::vaultDidChange);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -127,11 +133,15 @@ public class UnlockController extends LocalizedFXMLViewController {
|
||||
return getClass().getResource("/fxml/unlock.fxml");
|
||||
}
|
||||
|
||||
private void vaultDidChange(Vault newVault) {
|
||||
if (newVault == null) {
|
||||
void setVault(Vault vault) {
|
||||
// trigger "default" change to refresh key bindings:
|
||||
unlockButton.setDefaultButton(false);
|
||||
unlockButton.setDefaultButton(true);
|
||||
if (vault.equals(this.vault)) {
|
||||
return;
|
||||
}
|
||||
passwordField.clear();
|
||||
this.vault = Objects.requireNonNull(vault);
|
||||
passwordField.swipe();
|
||||
advancedOptions.setVisible(false);
|
||||
advancedOptionsButton.setText(localization.getString("unlock.button.advancedOptions.show"));
|
||||
progressIndicator.setVisible(false);
|
||||
@@ -145,13 +155,21 @@ public class UnlockController extends LocalizedFXMLViewController {
|
||||
}
|
||||
downloadsPageLink.setVisible(false);
|
||||
messageText.setText(null);
|
||||
mountName.setText(newVault.getMountName());
|
||||
mountName.setText(vault.getMountName());
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
chooseSelectedDriveLetter();
|
||||
}
|
||||
// trigger "default" change to refresh key bindings:
|
||||
unlockButton.setDefaultButton(false);
|
||||
unlockButton.setDefaultButton(true);
|
||||
savePassword.setSelected(false);
|
||||
// auto-fill pw from keychain:
|
||||
if (keychainAccess.isPresent()) {
|
||||
char[] storedPw = keychainAccess.get().loadPassphrase(vault.getId());
|
||||
if (storedPw != null) {
|
||||
savePassword.setSelected(true);
|
||||
passwordField.setText(new String(storedPw));
|
||||
passwordField.selectRange(storedPw.length, storedPw.length);
|
||||
Arrays.fill(storedPw, ' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
@@ -160,7 +178,7 @@ public class UnlockController extends LocalizedFXMLViewController {
|
||||
|
||||
@FXML
|
||||
public void didClickDownloadsLink(ActionEvent event) {
|
||||
app.getHostServices().showDocument("https://cryptomator.org/downloads/");
|
||||
app.getHostServices().showDocument("https://cryptomator.org/downloads/#allVersions");
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
@@ -188,14 +206,11 @@ public class UnlockController extends LocalizedFXMLViewController {
|
||||
}
|
||||
|
||||
private void mountNameDidChange(ObservableValue<? extends String> property, String oldValue, String newValue) {
|
||||
if (vault.get() == null) {
|
||||
return;
|
||||
}
|
||||
// newValue is guaranteed to be a-z0-9_, see #filterAlphanumericKeyEvents
|
||||
if (newValue.isEmpty()) {
|
||||
mountName.setText(vault.get().getMountName());
|
||||
mountName.setText(vault.getMountName());
|
||||
} else {
|
||||
vault.get().setMountName(newValue);
|
||||
vault.setMountName(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,20 +257,17 @@ public class UnlockController extends LocalizedFXMLViewController {
|
||||
}
|
||||
|
||||
private void winDriveLetterDidChange(ObservableValue<? extends Character> property, Character oldValue, Character newValue) {
|
||||
if (vault.get() == null) {
|
||||
return;
|
||||
}
|
||||
vault.get().setWinDriveLetter(newValue);
|
||||
vault.setWinDriveLetter(newValue);
|
||||
settings.save();
|
||||
}
|
||||
|
||||
private void chooseSelectedDriveLetter() {
|
||||
assert SystemUtils.IS_OS_WINDOWS;
|
||||
// if the vault prefers a drive letter, that is currently occupied, this is our last chance to reset this:
|
||||
if (driveLetters.getOccupiedDriveLetters().contains(vault.get().getWinDriveLetter())) {
|
||||
vault.get().setWinDriveLetter(null);
|
||||
if (driveLetters.getOccupiedDriveLetters().contains(vault.getWinDriveLetter())) {
|
||||
vault.setWinDriveLetter(null);
|
||||
}
|
||||
final Character letter = vault.get().getWinDriveLetter();
|
||||
final Character letter = vault.getWinDriveLetter();
|
||||
if (letter == null) {
|
||||
// first option is known to be 'auto-assign' due to #WinDriveLetterComparator.
|
||||
this.winDriveLetter.getSelectionModel().selectFirst();
|
||||
@@ -275,10 +287,10 @@ public class UnlockController extends LocalizedFXMLViewController {
|
||||
progressIndicator.setVisible(true);
|
||||
downloadsPageLink.setVisible(false);
|
||||
CharSequence password = passwordField.getCharacters();
|
||||
asyncTaskService.asyncTaskOf(() -> this.unlock(vault.get(), password)).run();
|
||||
asyncTaskService.asyncTaskOf(() -> this.unlock(password)).run();
|
||||
}
|
||||
|
||||
private void unlock(Vault vault, CharSequence password) {
|
||||
private void unlock(CharSequence password) {
|
||||
try {
|
||||
vault.activateFrontend(frontendFactory.get(), settings, password);
|
||||
vault.reveal();
|
||||
@@ -286,18 +298,28 @@ public class UnlockController extends LocalizedFXMLViewController {
|
||||
messageText.setText(null);
|
||||
listener.ifPresent(lstnr -> lstnr.didUnlock(vault));
|
||||
});
|
||||
if (keychainAccess.isPresent() && savePassword.isSelected()) {
|
||||
keychainAccess.get().storePassphrase(vault.getId(), password);
|
||||
} else {
|
||||
passwordField.swipe();
|
||||
}
|
||||
} catch (InvalidPassphraseException e) {
|
||||
Platform.runLater(() -> {
|
||||
messageText.setText(localization.getString("unlock.errorMessage.wrongPassword"));
|
||||
passwordField.selectAll();
|
||||
passwordField.requestFocus();
|
||||
});
|
||||
} catch (UnsupportedVaultFormatException e) {
|
||||
Platform.runLater(() -> {
|
||||
downloadsPageLink.setVisible(true);
|
||||
if (e.isVaultOlderThanSoftware()) {
|
||||
// whitespace after localized text used as separator between text and hyperlink
|
||||
messageText.setText(localization.getString("unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware") + " ");
|
||||
downloadsPageLink.setVisible(true);
|
||||
} else if (e.isSoftwareOlderThanVault()) {
|
||||
messageText.setText(localization.getString("unlock.errorMessage.unsupportedVersion.softwareOlderThanVault") + " ");
|
||||
downloadsPageLink.setVisible(true);
|
||||
} else if (e.getDetectedVersion() == Integer.MAX_VALUE) {
|
||||
messageText.setText(localization.getString("unlock.errorMessage.unauthenticVersionMac"));
|
||||
}
|
||||
});
|
||||
} catch (FrontendCreationFailedException | CommandFailedException e) {
|
||||
@@ -307,7 +329,6 @@ public class UnlockController extends LocalizedFXMLViewController {
|
||||
});
|
||||
} finally {
|
||||
Platform.runLater(() -> {
|
||||
passwordField.swipe();
|
||||
mountName.setDisable(false);
|
||||
advancedOptionsButton.setDisable(false);
|
||||
progressIndicator.setVisible(false);
|
||||
|
||||
@@ -15,21 +15,23 @@ import org.cryptomator.ui.settings.Localization;
|
||||
import org.cryptomator.ui.util.AsyncTaskService;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
|
||||
import javafx.beans.binding.BooleanExpression;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ProgressIndicator;
|
||||
|
||||
public class UpgradeController extends LocalizedFXMLViewController {
|
||||
|
||||
final ObjectProperty<Vault> vault = new SimpleObjectProperty<>();
|
||||
final ObjectProperty<Optional<UpgradeStrategy>> strategy = new SimpleObjectProperty<>();
|
||||
private final ObjectProperty<Optional<UpgradeStrategy>> strategy = new SimpleObjectProperty<>();
|
||||
private final UpgradeStrategies strategies;
|
||||
private final AsyncTaskService asyncTaskService;
|
||||
private Optional<UpgradeListener> listener = Optional.empty();
|
||||
private Vault vault;
|
||||
|
||||
@Inject
|
||||
public UpgradeController(Localization localization, UpgradeStrategies strategies, AsyncTaskService asyncTaskService) {
|
||||
@@ -44,6 +46,9 @@ public class UpgradeController extends LocalizedFXMLViewController {
|
||||
@FXML
|
||||
private SecPasswordField passwordField;
|
||||
|
||||
@FXML
|
||||
private CheckBox confirmationCheckbox;
|
||||
|
||||
@FXML
|
||||
private Button upgradeButton;
|
||||
|
||||
@@ -59,9 +64,9 @@ public class UpgradeController extends LocalizedFXMLViewController {
|
||||
return instruction.map(this::upgradeNotification).orElse("");
|
||||
}).orElse(""));
|
||||
|
||||
upgradeButton.disableProperty().bind(passwordField.textProperty().isEmpty().or(passwordField.disabledProperty()));
|
||||
|
||||
EasyBind.subscribe(vault, this::vaultDidChange);
|
||||
BooleanExpression passwordProvided = passwordField.textProperty().isNotEmpty().and(passwordField.disabledProperty().not());
|
||||
BooleanExpression syncFinished = confirmationCheckbox.selectedProperty();
|
||||
upgradeButton.disableProperty().bind(passwordProvided.not().or(syncFinished.not()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,9 +74,10 @@ public class UpgradeController extends LocalizedFXMLViewController {
|
||||
return getClass().getResource("/fxml/upgrade.fxml");
|
||||
}
|
||||
|
||||
private void vaultDidChange(Vault newVault) {
|
||||
void setVault(Vault vault) {
|
||||
this.vault = Objects.requireNonNull(vault);
|
||||
errorLabel.setText(null);
|
||||
strategy.set(strategies.getUpgradeStrategy(newVault));
|
||||
strategy.set(strategies.getUpgradeStrategy(vault));
|
||||
// trigger "default" change to refresh key bindings:
|
||||
upgradeButton.setDefaultButton(false);
|
||||
upgradeButton.setDefaultButton(true);
|
||||
@@ -82,7 +88,7 @@ public class UpgradeController extends LocalizedFXMLViewController {
|
||||
// ****************************************
|
||||
|
||||
private String upgradeNotification(UpgradeStrategy instruction) {
|
||||
return instruction.getNotification(vault.get());
|
||||
return instruction.getNotification(vault);
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
@@ -95,15 +101,14 @@ public class UpgradeController extends LocalizedFXMLViewController {
|
||||
}
|
||||
|
||||
private void upgrade(UpgradeStrategy instruction) {
|
||||
Vault v = Objects.requireNonNull(vault.getValue());
|
||||
passwordField.setDisable(true);
|
||||
progressIndicator.setVisible(true);
|
||||
asyncTaskService //
|
||||
.asyncTaskOf(() -> {
|
||||
if (!instruction.isApplicable(v)) {
|
||||
throw new IllegalStateException("No ugprade needed for " + v.path().getValue());
|
||||
if (!instruction.isApplicable(vault)) {
|
||||
throw new IllegalStateException("No ugprade needed for " + vault.path().getValue());
|
||||
}
|
||||
instruction.upgrade(v, passwordField.getCharacters());
|
||||
instruction.upgrade(vault, passwordField.getCharacters());
|
||||
}) //
|
||||
.onSuccess(this::showNextUpgrade) //
|
||||
.onError(UpgradeFailedException.class, e -> {
|
||||
@@ -118,7 +123,7 @@ public class UpgradeController extends LocalizedFXMLViewController {
|
||||
|
||||
private void showNextUpgrade() {
|
||||
errorLabel.setText(null);
|
||||
Optional<UpgradeStrategy> nextStrategy = strategies.getUpgradeStrategy(vault.getValue());
|
||||
Optional<UpgradeStrategy> nextStrategy = strategies.getUpgradeStrategy(vault);
|
||||
if (nextStrategy.isPresent()) {
|
||||
strategy.set(nextStrategy);
|
||||
} else {
|
||||
|
||||
@@ -19,6 +19,7 @@ import java.util.regex.Pattern;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.apache.logging.log4j.core.Filter;
|
||||
import org.apache.logging.log4j.core.Layout;
|
||||
import org.apache.logging.log4j.core.appender.AbstractAppender;
|
||||
import org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender;
|
||||
import org.apache.logging.log4j.core.appender.FileManager;
|
||||
import org.apache.logging.log4j.core.config.plugins.Plugin;
|
||||
@@ -26,10 +27,11 @@ import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
|
||||
import org.apache.logging.log4j.core.config.plugins.PluginElement;
|
||||
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
|
||||
import org.apache.logging.log4j.core.layout.PatternLayout;
|
||||
import org.apache.logging.log4j.core.util.Booleans;
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
|
||||
/**
|
||||
* A preconfigured FileAppender only relying on a configurable system property, e.g. <code>-DlogPath=/var/log/cryptomator.log</code>.<br/>
|
||||
* A preconfigured FileAppender only relying on a configurable system property, e.g. <code>-Dcryptomator.logPath=/var/log/cryptomator.log</code>.<br/>
|
||||
* Other than the normal {@link org.apache.logging.log4j.core.appender.FileAppender} paths can be resolved relative to the users home directory.
|
||||
*/
|
||||
@Plugin(name = "ConfigurableFile", category = "Core", elementType = "appender", printObject = true)
|
||||
@@ -37,7 +39,6 @@ public class ConfigurableFileAppender extends AbstractOutputStreamAppender<FileM
|
||||
|
||||
private static final long serialVersionUID = -6548221568069606389L;
|
||||
private static final int DEFAULT_BUFFER_SIZE = 8192;
|
||||
private static final String DEFAULT_FILE_NAME = "cryptomator.log";
|
||||
private static final Pattern DRIVE_LETTER_WITH_PRECEEDING_SLASH = Pattern.compile("^/[A-Z]:", Pattern.CASE_INSENSITIVE);
|
||||
|
||||
protected ConfigurableFileAppender(String name, Layout<? extends Serializable> layout, Filter filter, FileManager manager) {
|
||||
@@ -46,9 +47,8 @@ public class ConfigurableFileAppender extends AbstractOutputStreamAppender<FileM
|
||||
}
|
||||
|
||||
@PluginFactory
|
||||
public static ConfigurableFileAppender createAppender(@PluginAttribute("name") final String name, @PluginAttribute("pathPropertyName") final String pathPropertyName,
|
||||
public static AbstractAppender createAppender(@PluginAttribute("name") final String name, @PluginAttribute("pathPropertyName") final String pathPropertyName, @PluginAttribute("append") final String append,
|
||||
@PluginElement("Layout") Layout<? extends Serializable> layout) {
|
||||
|
||||
if (name == null) {
|
||||
LOGGER.error("No name provided for HomeDirectoryAwareFileAppender");
|
||||
return null;
|
||||
@@ -59,41 +59,16 @@ public class ConfigurableFileAppender extends AbstractOutputStreamAppender<FileM
|
||||
return null;
|
||||
}
|
||||
|
||||
String fileName = System.getProperty(pathPropertyName);
|
||||
final String fileName = System.getProperty(pathPropertyName);
|
||||
if (Strings.isEmpty(fileName)) {
|
||||
fileName = DEFAULT_FILE_NAME;
|
||||
LOGGER.warn("No log file location provided in system property \"" + pathPropertyName + "\"");
|
||||
return null;
|
||||
}
|
||||
|
||||
final Path filePath;
|
||||
if (fileName.startsWith("~/")) {
|
||||
// home-dir-relative Path:
|
||||
final Path userHome = FileSystems.getDefault().getPath(SystemUtils.USER_HOME);
|
||||
filePath = userHome.resolve(fileName.substring(2));
|
||||
} else if (fileName.startsWith("/")) {
|
||||
// absolute Path:
|
||||
filePath = FileSystems.getDefault().getPath(fileName);
|
||||
} else if (SystemUtils.IS_OS_WINDOWS && fileName.startsWith("%appdata%/")) {
|
||||
final String appdata = System.getenv("APPDATA");
|
||||
final Path appdataPath = appdata != null ? FileSystems.getDefault().getPath(appdata) : FileSystems.getDefault().getPath(SystemUtils.USER_HOME);
|
||||
filePath = appdataPath.resolve(fileName.substring(10));
|
||||
} else {
|
||||
// relative Path:
|
||||
try {
|
||||
String jarFileLocation = ConfigurableFileAppender.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath();
|
||||
if (SystemUtils.IS_OS_WINDOWS && DRIVE_LETTER_WITH_PRECEEDING_SLASH.matcher(jarFileLocation).find()) {
|
||||
// on windows we need to remove a preceeding slash from "/C:/foo/bar":
|
||||
jarFileLocation = jarFileLocation.substring(1);
|
||||
}
|
||||
final Path workingDir = FileSystems.getDefault().getPath(jarFileLocation).getParent();
|
||||
filePath = workingDir.resolve(fileName);
|
||||
} catch (URISyntaxException e) {
|
||||
LOGGER.error("Unable to resolve working directory ", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (layout == null) {
|
||||
layout = PatternLayout.createDefaultLayout();
|
||||
final Path filePath = parsePath(fileName);
|
||||
if (filePath == null) {
|
||||
LOGGER.warn("Invalid path \"" + fileName + "\"");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!Files.exists(filePath.getParent())) {
|
||||
@@ -105,8 +80,38 @@ public class ConfigurableFileAppender extends AbstractOutputStreamAppender<FileM
|
||||
}
|
||||
}
|
||||
|
||||
final FileManager manager = FileManager.getFileManager(filePath.toString(), false, false, true, null, layout, DEFAULT_BUFFER_SIZE);
|
||||
final boolean shouldAppend = Booleans.parseBoolean(append, true);
|
||||
if (layout == null) {
|
||||
layout = PatternLayout.createDefaultLayout();
|
||||
}
|
||||
|
||||
final FileManager manager = FileManager.getFileManager(filePath.toString(), shouldAppend, false, true, null, layout, DEFAULT_BUFFER_SIZE);
|
||||
return new ConfigurableFileAppender(name, layout, null, manager);
|
||||
}
|
||||
|
||||
private static Path parsePath(String path) {
|
||||
if (path.startsWith("~/")) {
|
||||
// home-dir-relative Path:
|
||||
final Path userHome = FileSystems.getDefault().getPath(SystemUtils.USER_HOME);
|
||||
return userHome.resolve(path.substring(2));
|
||||
} else if (path.startsWith("/")) {
|
||||
// absolute Path:
|
||||
return FileSystems.getDefault().getPath(path);
|
||||
} else {
|
||||
// relative Path:
|
||||
try {
|
||||
String jarFileLocation = ConfigurableFileAppender.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath();
|
||||
if (SystemUtils.IS_OS_WINDOWS && DRIVE_LETTER_WITH_PRECEEDING_SLASH.matcher(jarFileLocation).find()) {
|
||||
// on windows we need to remove a preceeding slash from "/C:/foo/bar":
|
||||
jarFileLocation = jarFileLocation.substring(1);
|
||||
}
|
||||
final Path workingDir = FileSystems.getDefault().getPath(jarFileLocation).getParent();
|
||||
return workingDir.resolve(path);
|
||||
} catch (URISyntaxException e) {
|
||||
LOGGER.error("Unable to resolve working directory ", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ public class UpgradeStrategies {
|
||||
private final Collection<UpgradeStrategy> strategies;
|
||||
|
||||
@Inject
|
||||
public UpgradeStrategies(UpgradeVersion3DropBundleExtension upgrader1, UpgradeVersion3to4 upgrader2) {
|
||||
strategies = Collections.unmodifiableList(Arrays.asList(upgrader1, upgrader2));
|
||||
public UpgradeStrategies(UpgradeVersion3DropBundleExtension upgrader1, UpgradeVersion3to4 upgrader2, UpgradeVersion4to5 upgrader3) {
|
||||
strategies = Collections.unmodifiableList(Arrays.asList(upgrader1, upgrader2, upgrader3));
|
||||
}
|
||||
|
||||
public Optional<UpgradeStrategy> getUpgradeStrategy(Vault vault) {
|
||||
|
||||
@@ -6,11 +6,11 @@ import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
|
||||
import javax.inject.Provider;
|
||||
|
||||
import org.cryptomator.crypto.engine.Cryptor;
|
||||
import org.cryptomator.crypto.engine.InvalidPassphraseException;
|
||||
import org.cryptomator.crypto.engine.UnsupportedVaultFormatException;
|
||||
import org.cryptomator.cryptolib.api.Cryptor;
|
||||
import org.cryptomator.cryptolib.api.CryptorProvider;
|
||||
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
|
||||
import org.cryptomator.cryptolib.api.KeyFile;
|
||||
import org.cryptomator.cryptolib.api.UnsupportedVaultFormatException;
|
||||
import org.cryptomator.filesystem.crypto.Constants;
|
||||
import org.cryptomator.ui.settings.Localization;
|
||||
import org.slf4j.Logger;
|
||||
@@ -20,12 +20,16 @@ public abstract class UpgradeStrategy {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(UpgradeStrategy.class);
|
||||
|
||||
protected final Provider<Cryptor> cryptorProvider;
|
||||
protected final CryptorProvider cryptorProvider;
|
||||
protected final Localization localization;
|
||||
protected final int vaultVersionBeforeUpgrade;
|
||||
protected final int vaultVersionAfterUpgrade;
|
||||
|
||||
UpgradeStrategy(Provider<Cryptor> cryptorProvider, Localization localization) {
|
||||
UpgradeStrategy(CryptorProvider cryptorProvider, Localization localization, int vaultVersionBeforeUpgrade, int vaultVersionAfterUpgrade) {
|
||||
this.cryptorProvider = cryptorProvider;
|
||||
this.localization = localization;
|
||||
this.vaultVersionBeforeUpgrade = vaultVersionBeforeUpgrade;
|
||||
this.vaultVersionAfterUpgrade = vaultVersionAfterUpgrade;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,27 +41,37 @@ public abstract class UpgradeStrategy {
|
||||
* Upgrades a vault. Might take a moment, should be run in a background thread.
|
||||
*/
|
||||
public void upgrade(Vault vault, CharSequence passphrase) throws UpgradeFailedException {
|
||||
final Cryptor cryptor = cryptorProvider.get();
|
||||
Cryptor cryptor = null;
|
||||
try {
|
||||
final Path masterkeyFile = vault.path().getValue().resolve(Constants.MASTERKEY_FILENAME);
|
||||
final byte[] masterkeyFileContents = Files.readAllBytes(masterkeyFile);
|
||||
cryptor.readKeysFromMasterkeyFile(masterkeyFileContents, passphrase);
|
||||
cryptor = cryptorProvider.createFromKeyFile(KeyFile.parse(masterkeyFileContents), passphrase, vaultVersionBeforeUpgrade);
|
||||
// create backup, as soon as we know the password was correct:
|
||||
final Path masterkeyBackupFile = vault.path().getValue().resolve(Constants.MASTERKEY_BACKUP_FILENAME);
|
||||
Files.copy(masterkeyFile, masterkeyBackupFile, StandardCopyOption.REPLACE_EXISTING);
|
||||
// do stuff:
|
||||
upgrade(vault, cryptor);
|
||||
// write updated masterkey file:
|
||||
final byte[] upgradedMasterkeyFileContents = cryptor.writeKeysToMasterkeyFile(passphrase);
|
||||
final Path masterkeyFileAfterUpgrading = vault.path().getValue().resolve(Constants.MASTERKEY_FILENAME); // path may have changed
|
||||
Files.write(masterkeyFileAfterUpgrading, upgradedMasterkeyFileContents, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
final byte[] upgradedMasterkeyFileContents = cryptor.writeKeysToMasterkeyFile(passphrase, vaultVersionAfterUpgrade).serialize();
|
||||
final Path masterkeyFileAfterUpgrade = vault.path().getValue().resolve(Constants.MASTERKEY_FILENAME); // path may have changed
|
||||
Files.write(masterkeyFileAfterUpgrade, upgradedMasterkeyFileContents, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
} catch (InvalidPassphraseException e) {
|
||||
throw new UpgradeFailedException(localization.getString("unlock.errorMessage.wrongPassword"));
|
||||
} catch (IOException | UnsupportedVaultFormatException e) {
|
||||
} catch (UnsupportedVaultFormatException e) {
|
||||
if (e.getDetectedVersion() == Integer.MAX_VALUE) {
|
||||
LOG.warn("Version MAC authentication error in vault {}", vault.path().get());
|
||||
throw new UpgradeFailedException(localization.getString("unlock.errorMessage.unauthenticVersionMac"));
|
||||
} else {
|
||||
LOG.warn("Upgrade failed.", e);
|
||||
throw new UpgradeFailedException("Upgrade failed. Details in log message.");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.warn("Upgrade failed.", e);
|
||||
throw new UpgradeFailedException("Upgrade failed. Details in log message.");
|
||||
} finally {
|
||||
cryptor.destroy();
|
||||
if (cryptor != null) {
|
||||
cryptor.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +82,21 @@ public abstract class UpgradeStrategy {
|
||||
*
|
||||
* @return <code>true</code> if and only if the vault can be migrated to a newer version without the risk of data losses.
|
||||
*/
|
||||
public abstract boolean isApplicable(Vault vault);
|
||||
public boolean isApplicable(Vault vault) {
|
||||
final Path masterkeyFile = vault.path().getValue().resolve(Constants.MASTERKEY_FILENAME);
|
||||
try {
|
||||
if (Files.isRegularFile(masterkeyFile)) {
|
||||
byte[] masterkeyFileContents = Files.readAllBytes(masterkeyFile);
|
||||
return KeyFile.parse(masterkeyFileContents).getVersion() == vaultVersionBeforeUpgrade;
|
||||
} else {
|
||||
LOG.warn("Not a file: {}", masterkeyFile);
|
||||
return false;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.warn("Could not determine, whether upgrade is applicable.", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown when data migration failed.
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
package org.cryptomator.ui.model;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.cryptomator.crypto.engine.Cryptor;
|
||||
import org.cryptomator.crypto.engine.InvalidPassphraseException;
|
||||
import org.cryptomator.crypto.engine.UnsupportedVaultFormatException;
|
||||
import org.cryptomator.filesystem.crypto.Constants;
|
||||
import org.cryptomator.cryptolib.api.CryptoLibVersion;
|
||||
import org.cryptomator.cryptolib.api.CryptoLibVersion.Version;
|
||||
import org.cryptomator.cryptolib.api.Cryptor;
|
||||
import org.cryptomator.cryptolib.api.CryptorProvider;
|
||||
import org.cryptomator.ui.settings.Localization;
|
||||
import org.cryptomator.ui.settings.Settings;
|
||||
import org.slf4j.Logger;
|
||||
@@ -28,8 +26,8 @@ class UpgradeVersion3DropBundleExtension extends UpgradeStrategy {
|
||||
private final Settings settings;
|
||||
|
||||
@Inject
|
||||
public UpgradeVersion3DropBundleExtension(Provider<Cryptor> cryptorProvider, Localization localization, Settings settings) {
|
||||
super(cryptorProvider, localization);
|
||||
public UpgradeVersion3DropBundleExtension(@CryptoLibVersion(Version.ONE) CryptorProvider version1CryptorProvider, Localization localization, Settings settings) {
|
||||
super(version1CryptorProvider, localization, 3, 3);
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
@@ -42,25 +40,6 @@ class UpgradeVersion3DropBundleExtension extends UpgradeStrategy {
|
||||
return String.format(fmt, oldVaultName, newVaultName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upgrade(Vault vault, CharSequence passphrase) throws UpgradeFailedException {
|
||||
final Cryptor cryptor = cryptorProvider.get();
|
||||
try {
|
||||
final Path masterkeyFile = vault.path().getValue().resolve(Constants.MASTERKEY_FILENAME);
|
||||
final byte[] masterkeyFileContents = Files.readAllBytes(masterkeyFile);
|
||||
cryptor.readKeysFromMasterkeyFile(masterkeyFileContents, passphrase);
|
||||
upgrade(vault, cryptor);
|
||||
// don't write new masterkey. this is a special case, as we were stupid and didn't increase the vault version with this upgrade...
|
||||
} catch (InvalidPassphraseException e) {
|
||||
throw new UpgradeFailedException(localization.getString("unlock.errorMessage.wrongPassword"));
|
||||
} catch (IOException | UnsupportedVaultFormatException e) {
|
||||
LOG.warn("Upgrade failed.", e);
|
||||
throw new UpgradeFailedException("Upgrade failed. Details in log message.");
|
||||
} finally {
|
||||
cryptor.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void upgrade(Vault vault, Cryptor cryptor) throws UpgradeFailedException {
|
||||
Path path = vault.path().getValue();
|
||||
@@ -73,6 +52,7 @@ class UpgradeVersion3DropBundleExtension extends UpgradeStrategy {
|
||||
throw new UpgradeFailedException(msg);
|
||||
} else {
|
||||
try {
|
||||
LOG.info("Renaming {} to {}", path, newPath.getFileName());
|
||||
Files.move(path, path.resolveSibling(newVaultName));
|
||||
Platform.runLater(() -> {
|
||||
vault.setPath(newPath);
|
||||
@@ -89,19 +69,7 @@ class UpgradeVersion3DropBundleExtension extends UpgradeStrategy {
|
||||
public boolean isApplicable(Vault vault) {
|
||||
Path vaultPath = vault.path().getValue();
|
||||
if (vaultPath.toString().endsWith(Vault.VAULT_FILE_EXTENSION)) {
|
||||
final Path masterkeyFile = vaultPath.resolve(Constants.MASTERKEY_FILENAME);
|
||||
try {
|
||||
if (Files.isRegularFile(masterkeyFile)) {
|
||||
final String keyContents = new String(Files.readAllBytes(masterkeyFile), StandardCharsets.UTF_8);
|
||||
return keyContents.contains("\"version\":3") || keyContents.contains("\"version\": 3");
|
||||
} else {
|
||||
LOG.warn("Not a file: {}", masterkeyFile);
|
||||
return false;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.warn("Could not determine, whether upgrade is applicable.", e);
|
||||
return false;
|
||||
}
|
||||
return super.isApplicable(vault);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -9,19 +9,20 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.apache.commons.codec.binary.Base32;
|
||||
import org.apache.commons.codec.binary.BaseNCodec;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.cryptomator.crypto.engine.Cryptor;
|
||||
import org.cryptomator.filesystem.crypto.Constants;
|
||||
import org.cryptomator.cryptolib.api.CryptoLibVersion;
|
||||
import org.cryptomator.cryptolib.api.CryptoLibVersion.Version;
|
||||
import org.cryptomator.cryptolib.api.Cryptor;
|
||||
import org.cryptomator.cryptolib.api.CryptorProvider;
|
||||
import org.cryptomator.cryptolib.common.MessageDigestSupplier;
|
||||
import org.cryptomator.ui.settings.Localization;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -40,17 +41,12 @@ class UpgradeVersion3to4 extends UpgradeStrategy {
|
||||
private static final String OLD_FOLDER_SUFFIX = "_";
|
||||
private static final String NEW_FOLDER_PREFIX = "0";
|
||||
|
||||
private final MessageDigest sha1;
|
||||
private final MessageDigest sha1 = MessageDigestSupplier.SHA1.get();
|
||||
private final BaseNCodec base32 = new Base32();
|
||||
|
||||
@Inject
|
||||
public UpgradeVersion3to4(Provider<Cryptor> cryptorProvider, Localization localization) {
|
||||
super(cryptorProvider, localization);
|
||||
try {
|
||||
sha1 = MessageDigest.getInstance("SHA-1");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AssertionError("SHA-1 exists in every JVM");
|
||||
}
|
||||
public UpgradeVersion3to4(@CryptoLibVersion(Version.ONE) CryptorProvider version1CryptorProvider, Localization localization) {
|
||||
super(version1CryptorProvider, localization, 3, 4);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -144,21 +140,4 @@ class UpgradeVersion3to4 extends UpgradeStrategy {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(Vault vault) {
|
||||
final Path masterkeyFile = vault.path().getValue().resolve(Constants.MASTERKEY_FILENAME);
|
||||
try {
|
||||
if (Files.isRegularFile(masterkeyFile)) {
|
||||
final String keyContents = new String(Files.readAllBytes(masterkeyFile), UTF_8);
|
||||
return keyContents.contains("\"version\":3") || keyContents.contains("\"version\": 3");
|
||||
} else {
|
||||
LOG.warn("Not a file: {}", masterkeyFile);
|
||||
return false;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.warn("Could not determine, whether upgrade is applicable.", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
package org.cryptomator.ui.model;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.cryptomator.cryptolib.Cryptors;
|
||||
import org.cryptomator.cryptolib.api.CryptoLibVersion;
|
||||
import org.cryptomator.cryptolib.api.CryptoLibVersion.Version;
|
||||
import org.cryptomator.cryptolib.api.Cryptor;
|
||||
import org.cryptomator.cryptolib.api.CryptorProvider;
|
||||
import org.cryptomator.cryptolib.api.FileHeader;
|
||||
import org.cryptomator.ui.settings.Localization;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Contains the collective knowledge of all creatures who were alive during the development of vault format 3.
|
||||
* This class uses no external classes from the crypto or shortening layer by purpose, so we don't need legacy code inside these.
|
||||
*/
|
||||
@Singleton
|
||||
class UpgradeVersion4to5 extends UpgradeStrategy {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(UpgradeVersion4to5.class);
|
||||
private static final Pattern BASE32_PATTERN = Pattern.compile("^([A-Z2-7]{8})*[A-Z2-7=]{8}");
|
||||
|
||||
@Inject
|
||||
public UpgradeVersion4to5(@CryptoLibVersion(Version.ONE) CryptorProvider version1CryptorProvider, Localization localization) {
|
||||
super(version1CryptorProvider, localization, 4, 5);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNotification(Vault vault) {
|
||||
return localization.getString("upgrade.version3to4.msg");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void upgrade(Vault vault, Cryptor cryptor) throws UpgradeFailedException {
|
||||
Path dataDir = vault.path().get().resolve("d");
|
||||
if (!Files.isDirectory(dataDir)) {
|
||||
return; // empty vault. no migration needed.
|
||||
}
|
||||
try {
|
||||
Files.walkFileTree(dataDir, new SimpleFileVisitor<Path>() {
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
if (BASE32_PATTERN.matcher(file.getFileName().toString()).find() && attrs.size() > cryptor.fileHeaderCryptor().headerSize()) {
|
||||
migrate(file, attrs, cryptor);
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
});
|
||||
} catch (IOException e) {
|
||||
LOG.error("Migration failed.", e);
|
||||
throw new UpgradeFailedException(localization.getString("upgrade.version3to4.err.io"));
|
||||
}
|
||||
LOG.info("Migration finished.");
|
||||
}
|
||||
|
||||
private void migrate(Path file, BasicFileAttributes attrs, Cryptor cryptor) throws IOException {
|
||||
try (FileChannel ch = FileChannel.open(file, StandardOpenOption.READ, StandardOpenOption.WRITE)) {
|
||||
// read header:
|
||||
ByteBuffer headerBuf = ByteBuffer.allocate(cryptor.fileHeaderCryptor().headerSize());
|
||||
ch.read(headerBuf);
|
||||
headerBuf.flip();
|
||||
FileHeader header = cryptor.fileHeaderCryptor().decryptHeader(headerBuf);
|
||||
long cleartextSize = header.getFilesize();
|
||||
if (cleartextSize < 0) {
|
||||
LOG.info("Skipping already migrated file {}.", file);
|
||||
return;
|
||||
} else if (cleartextSize > attrs.size()) {
|
||||
LOG.warn("Skipping file {} with invalid file size {}/{}", file, cleartextSize, attrs.size());
|
||||
return;
|
||||
}
|
||||
int headerSize = cryptor.fileHeaderCryptor().headerSize();
|
||||
int ciphertextChunkSize = cryptor.fileContentCryptor().ciphertextChunkSize();
|
||||
int cleartextChunkSize = cryptor.fileContentCryptor().cleartextChunkSize();
|
||||
long newCiphertextSize = Cryptors.ciphertextSize(cleartextSize, cryptor);
|
||||
long newEOF = headerSize + newCiphertextSize;
|
||||
long newFullChunks = newCiphertextSize / ciphertextChunkSize; // int-truncation
|
||||
long newAdditionalCiphertextBytes = newCiphertextSize % ciphertextChunkSize;
|
||||
if (newAdditionalCiphertextBytes == 0) {
|
||||
// (new) last block is already correct. just truncate:
|
||||
LOG.info("Migrating {} of cleartext size {}: Truncating to new ciphertext size: {}", file, cleartextSize, newEOF);
|
||||
ch.truncate(newEOF);
|
||||
} else {
|
||||
// last block may contain padding and needs to be re-encrypted:
|
||||
long lastChunkIdx = newFullChunks;
|
||||
LOG.info("Migrating {} of cleartext size {}: Re-encrypting chunk {}. New ciphertext size: {}", file, cleartextSize, lastChunkIdx, newEOF);
|
||||
long beginOfLastChunk = headerSize + lastChunkIdx * ciphertextChunkSize;
|
||||
assert beginOfLastChunk < newEOF;
|
||||
int lastCleartextChunkLength = (int) (cleartextSize % cleartextChunkSize);
|
||||
assert lastCleartextChunkLength < cleartextChunkSize;
|
||||
assert lastCleartextChunkLength > 0;
|
||||
ch.position(beginOfLastChunk);
|
||||
ByteBuffer lastCiphertextChunk = ByteBuffer.allocate(ciphertextChunkSize);
|
||||
int read = ch.read(lastCiphertextChunk);
|
||||
if (read != -1) {
|
||||
lastCiphertextChunk.flip();
|
||||
ByteBuffer lastCleartextChunk = cryptor.fileContentCryptor().decryptChunk(lastCiphertextChunk, lastChunkIdx, header, true);
|
||||
lastCleartextChunk.position(0).limit(lastCleartextChunkLength);
|
||||
assert lastCleartextChunk.remaining() == lastCleartextChunkLength;
|
||||
ByteBuffer newLastChunkCiphertext = cryptor.fileContentCryptor().encryptChunk(lastCleartextChunk, lastChunkIdx, header);
|
||||
ch.truncate(beginOfLastChunk);
|
||||
ch.write(newLastChunkCiphertext);
|
||||
} else {
|
||||
LOG.error("Reached EOF at position {}/{}", beginOfLastChunk, newEOF);
|
||||
return; // must exit method before changing header!
|
||||
}
|
||||
}
|
||||
header.setFilesize(-1l);
|
||||
ByteBuffer newHeaderBuf = cryptor.fileHeaderCryptor().encryptHeader(header);
|
||||
ch.position(0);
|
||||
ch.write(newHeaderBuf);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import static org.apache.commons.lang3.StringUtils.stripStart;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.DirectoryNotEmptyException;
|
||||
import java.nio.file.FileAlreadyExistsException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@@ -30,6 +31,7 @@ import org.apache.commons.lang3.SystemUtils;
|
||||
import org.cryptomator.common.LazyInitializer;
|
||||
import org.cryptomator.common.Optionals;
|
||||
import org.cryptomator.crypto.engine.InvalidPassphraseException;
|
||||
import org.cryptomator.filesystem.File;
|
||||
import org.cryptomator.filesystem.FileSystem;
|
||||
import org.cryptomator.filesystem.charsets.NormalizedNameFileSystem;
|
||||
import org.cryptomator.filesystem.crypto.CryptoFileSystemDelegate;
|
||||
@@ -109,8 +111,10 @@ public class Vault implements CryptoFileSystemDelegate {
|
||||
public void create(CharSequence passphrase) throws IOException {
|
||||
try {
|
||||
FileSystem fs = getNioFileSystem();
|
||||
if (fs.children().count() > 0) {
|
||||
throw new FileAlreadyExistsException(null, null, "Vault location not empty.");
|
||||
if (fs.files().map(File::name).filter(s -> s.endsWith(VAULT_FILE_EXTENSION)).count() > 0) {
|
||||
throw new FileAlreadyExistsException("masterkey.cryptomator", null, "Vault location not empty.");
|
||||
} else if (fs.folders().count() > 0) {
|
||||
throw new DirectoryNotEmptyException(fs.toString());
|
||||
}
|
||||
cryptoFileSystemFactory.initializeNew(fs, passphrase);
|
||||
} catch (UncheckedIOException e) {
|
||||
@@ -164,7 +168,7 @@ public class Vault implements CryptoFileSystemDelegate {
|
||||
);
|
||||
}
|
||||
|
||||
public void reveal() throws CommandFailedException {
|
||||
public synchronized void reveal() throws CommandFailedException {
|
||||
Optionals.ifPresent(filesystemFrontend.get(), Frontend::reveal);
|
||||
}
|
||||
|
||||
@@ -186,7 +190,7 @@ public class Vault implements CryptoFileSystemDelegate {
|
||||
// Getter/Setter
|
||||
// *******************************************************************************/
|
||||
|
||||
public String getWebDavUrl() {
|
||||
public synchronized String getWebDavUrl() {
|
||||
return filesystemFrontend.get().map(Frontend::getWebDavUrl).orElseThrow(IllegalStateException::new);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
package org.cryptomator.ui.model;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.cryptomator.ui.settings.Settings;
|
||||
|
||||
import javafx.beans.InvalidationListener;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ListChangeListener.Change;
|
||||
import javafx.collections.ObservableList;
|
||||
|
||||
@Singleton
|
||||
public class Vaults implements ObservableList<Vault> {
|
||||
|
||||
private final ObservableList<Vault> delegate;
|
||||
|
||||
@Inject
|
||||
public Vaults(Settings settings) {
|
||||
this.delegate = FXCollections.observableList(settings.getDirectories());
|
||||
addListener((Change<? extends Vault> change) -> settings.save());
|
||||
}
|
||||
|
||||
public void addListener(ListChangeListener<? super Vault> listener) {
|
||||
delegate.addListener(listener);
|
||||
}
|
||||
|
||||
public void removeListener(ListChangeListener<? super Vault> listener) {
|
||||
delegate.removeListener(listener);
|
||||
}
|
||||
|
||||
public void addListener(InvalidationListener listener) {
|
||||
delegate.addListener(listener);
|
||||
}
|
||||
|
||||
public boolean addAll(Vault... elements) {
|
||||
return delegate.addAll(elements);
|
||||
}
|
||||
|
||||
public boolean setAll(Vault... elements) {
|
||||
return delegate.setAll(elements);
|
||||
}
|
||||
|
||||
public boolean setAll(Collection<? extends Vault> col) {
|
||||
return delegate.setAll(col);
|
||||
}
|
||||
|
||||
public boolean removeAll(Vault... elements) {
|
||||
return delegate.removeAll(elements);
|
||||
}
|
||||
|
||||
public void removeListener(InvalidationListener listener) {
|
||||
delegate.removeListener(listener);
|
||||
}
|
||||
|
||||
public boolean retainAll(Vault... elements) {
|
||||
return delegate.retainAll(elements);
|
||||
}
|
||||
|
||||
public void remove(int from, int to) {
|
||||
delegate.remove(from, to);
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return delegate.size();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return delegate.isEmpty();
|
||||
}
|
||||
|
||||
public boolean contains(Object o) {
|
||||
return delegate.contains(o);
|
||||
}
|
||||
|
||||
public Iterator<Vault> iterator() {
|
||||
return delegate.iterator();
|
||||
}
|
||||
|
||||
public Object[] toArray() {
|
||||
return delegate.toArray();
|
||||
}
|
||||
|
||||
public <T> T[] toArray(T[] a) {
|
||||
return delegate.toArray(a);
|
||||
}
|
||||
|
||||
public boolean add(Vault e) {
|
||||
return delegate.add(e);
|
||||
}
|
||||
|
||||
public boolean remove(Object o) {
|
||||
return delegate.remove(o);
|
||||
}
|
||||
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
return delegate.containsAll(c);
|
||||
}
|
||||
|
||||
public boolean addAll(Collection<? extends Vault> c) {
|
||||
return delegate.addAll(c);
|
||||
}
|
||||
|
||||
public boolean addAll(int index, Collection<? extends Vault> c) {
|
||||
return delegate.addAll(index, c);
|
||||
}
|
||||
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
return delegate.removeAll(c);
|
||||
}
|
||||
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
return delegate.retainAll(c);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
delegate.clear();
|
||||
}
|
||||
|
||||
public Vault get(int index) {
|
||||
return delegate.get(index);
|
||||
}
|
||||
|
||||
public Vault set(int index, Vault element) {
|
||||
return delegate.set(index, element);
|
||||
}
|
||||
|
||||
public void add(int index, Vault element) {
|
||||
delegate.add(index, element);
|
||||
}
|
||||
|
||||
public Vault remove(int index) {
|
||||
return delegate.remove(index);
|
||||
}
|
||||
|
||||
public int indexOf(Object o) {
|
||||
return delegate.indexOf(o);
|
||||
}
|
||||
|
||||
public int lastIndexOf(Object o) {
|
||||
return delegate.lastIndexOf(o);
|
||||
}
|
||||
|
||||
public ListIterator<Vault> listIterator() {
|
||||
return delegate.listIterator();
|
||||
}
|
||||
|
||||
public ListIterator<Vault> listIterator(int index) {
|
||||
return delegate.listIterator(index);
|
||||
}
|
||||
|
||||
public List<Vault> subList(int fromIndex, int toIndex) {
|
||||
return delegate.subList(fromIndex, toIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (obj == null || getClass() != obj.getClass()) return false;
|
||||
return internalEquals((Vaults)obj);
|
||||
}
|
||||
|
||||
private boolean internalEquals(Vaults other) {
|
||||
return delegate.equals(other.delegate);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return delegate.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -39,7 +39,7 @@ public class Localization extends ResourceBundle {
|
||||
Objects.requireNonNull(in);
|
||||
Reader reader = new InputStreamReader(in, StandardCharsets.UTF_8);
|
||||
this.fallback = new PropertyResourceBundle(reader);
|
||||
LOG.info("Loaded localization from {}", LOCALIZATION_FILE);
|
||||
LOG.info("Loaded localization from bundle:{}", LOCALIZATION_FILE);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
@@ -28,6 +29,7 @@ import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -38,23 +40,17 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
public class SettingsProvider implements Provider<Settings> {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SettingsProvider.class);
|
||||
private static final Path SETTINGS_DIR;
|
||||
private static final String SETTINGS_FILE = "settings.json";
|
||||
private static final Path DEFAULT_SETTINGS_PATH;
|
||||
private static final long SAVE_DELAY_MS = 1000;
|
||||
|
||||
static {
|
||||
final String appdata = System.getenv("APPDATA");
|
||||
final FileSystem fs = FileSystems.getDefault();
|
||||
|
||||
if (SystemUtils.IS_OS_WINDOWS && appdata != null) {
|
||||
SETTINGS_DIR = fs.getPath(appdata, "Cryptomator");
|
||||
} else if (SystemUtils.IS_OS_WINDOWS && appdata == null) {
|
||||
SETTINGS_DIR = fs.getPath(SystemUtils.USER_HOME, ".Cryptomator");
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
DEFAULT_SETTINGS_PATH = fs.getPath(SystemUtils.USER_HOME, "AppData/Roaming/Cryptomator/settings.json");
|
||||
} else if (SystemUtils.IS_OS_MAC_OSX) {
|
||||
SETTINGS_DIR = fs.getPath(SystemUtils.USER_HOME, "Library/Application Support/Cryptomator");
|
||||
DEFAULT_SETTINGS_PATH = fs.getPath(SystemUtils.USER_HOME, "Library/Application Support/Cryptomator/settings.json");
|
||||
} else {
|
||||
// (os.contains("solaris") || os.contains("sunos") || os.contains("linux") || os.contains("unix"))
|
||||
SETTINGS_DIR = fs.getPath(SystemUtils.USER_HOME, ".Cryptomator");
|
||||
DEFAULT_SETTINGS_PATH = fs.getPath(SystemUtils.USER_HOME, ".Cryptomator/settings.json");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,11 +64,15 @@ public class SettingsProvider implements Provider<Settings> {
|
||||
}
|
||||
|
||||
private Path getSettingsPath() throws IOException {
|
||||
String settingsPathProperty = System.getProperty("cryptomator.settingsPath");
|
||||
if (settingsPathProperty == null) {
|
||||
return SETTINGS_DIR.resolve(SETTINGS_FILE);
|
||||
final String settingsPathProperty = System.getProperty("cryptomator.settingsPath");
|
||||
return Optional.ofNullable(settingsPathProperty).filter(StringUtils::isNotBlank).map(this::replaceHomeDir).map(FileSystems.getDefault()::getPath).orElse(DEFAULT_SETTINGS_PATH);
|
||||
}
|
||||
|
||||
private String replaceHomeDir(String path) {
|
||||
if (path.startsWith("~/")) {
|
||||
return SystemUtils.USER_HOME + path.substring(1);
|
||||
} else {
|
||||
return FileSystems.getDefault().getPath(settingsPathProperty);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ public class SettingsProvider implements Provider<Settings> {
|
||||
}
|
||||
ScheduledFuture<?> saveCmd = saveScheduler.schedule(() -> {
|
||||
this.save(settings);
|
||||
} , SAVE_DELAY_MS, TimeUnit.MILLISECONDS);
|
||||
}, SAVE_DELAY_MS, TimeUnit.MILLISECONDS);
|
||||
ScheduledFuture<?> previousSaveCmd = scheduledSaveCmd.getAndSet(saveCmd);
|
||||
if (previousSaveCmd != null) {
|
||||
previousSaveCmd.cancel(false);
|
||||
|
||||
@@ -305,17 +305,17 @@
|
||||
****************************************************************************/
|
||||
|
||||
.check-box {
|
||||
-fx-label-padding: 0 0 0 3;
|
||||
-fx-label-padding: 0 0 0 6px;
|
||||
-fx-text-fill: COLOR_TEXT;
|
||||
}
|
||||
.check-box > .box {
|
||||
-fx-padding: 3;
|
||||
-fx-padding: 3px;
|
||||
-fx-background-color: COLOR_BORDER_DARK, #FFF;
|
||||
-fx-background-insets: 0, 1;
|
||||
}
|
||||
.check-box > .box > .mark {
|
||||
-fx-background-color: transparent;
|
||||
-fx-padding: 4;
|
||||
-fx-padding: 4px;
|
||||
-fx-shape: "M-1,4, L-1,5.5 L3.5,8.5 L9,0 L9,-1 L7,-1 L3,6 L1,4 Z";
|
||||
}
|
||||
.check-box:selected > .box {
|
||||
|
||||
@@ -386,7 +386,7 @@
|
||||
******************************************************************************/
|
||||
|
||||
.check-box {
|
||||
-fx-label-padding: 0 0 0 3px;
|
||||
-fx-label-padding: 0 0 0 6px;
|
||||
-fx-text-fill: COLOR_TEXT;
|
||||
}
|
||||
.check-box > .box {
|
||||
|
||||
@@ -354,7 +354,7 @@
|
||||
******************************************************************************/
|
||||
|
||||
.check-box {
|
||||
-fx-label-padding: 0 0 0 3px;
|
||||
-fx-label-padding: 0 0 0 6px;
|
||||
-fx-text-fill: COLOR_TEXT;
|
||||
}
|
||||
.check-box > .box {
|
||||
|
||||
@@ -68,12 +68,16 @@
|
||||
</HBox>
|
||||
|
||||
<!-- Row 3.1 -->
|
||||
<Label text="%unlock.label.mountName" GridPane.rowIndex="1" GridPane.columnIndex="0" cacheShape="true" cache="true" />
|
||||
<TextField fx:id="mountName" GridPane.rowIndex="1" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" maxWidth="Infinity" cacheShape="true" cache="true" />
|
||||
<Label GridPane.rowIndex="1" GridPane.columnIndex="0" text="%unlock.label.savePassword" cacheShape="true" cache="true" />
|
||||
<CheckBox GridPane.rowIndex="1" GridPane.columnIndex="1" fx:id="savePassword" cacheShape="true" cache="true" />
|
||||
|
||||
<!-- Row 3.2 -->
|
||||
<Label fx:id="winDriveLetterLabel" text="%unlock.label.winDriveLetter" GridPane.rowIndex="2" GridPane.columnIndex="0" cacheShape="true" cache="true" />
|
||||
<ChoiceBox fx:id="winDriveLetter" GridPane.rowIndex="2" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" maxWidth="Infinity" cacheShape="true" cache="true" />
|
||||
<Label GridPane.rowIndex="2" GridPane.columnIndex="0" text="%unlock.label.mountName" cacheShape="true" cache="true" />
|
||||
<TextField GridPane.rowIndex="2" GridPane.columnIndex="1" fx:id="mountName" GridPane.hgrow="ALWAYS" maxWidth="Infinity" cacheShape="true" cache="true" />
|
||||
|
||||
<!-- Row 3.3 -->
|
||||
<Label GridPane.rowIndex="3" GridPane.columnIndex="0" fx:id="winDriveLetterLabel" text="%unlock.label.winDriveLetter" cacheShape="true" cache="true" />
|
||||
<ChoiceBox GridPane.rowIndex="3" GridPane.columnIndex="1" fx:id="winDriveLetter" GridPane.hgrow="ALWAYS" maxWidth="Infinity" cacheShape="true" cache="true" />
|
||||
</GridPane>
|
||||
|
||||
<!-- Row 4 -->
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
<?import javafx.scene.layout.ColumnConstraints?>
|
||||
<?import javafx.scene.layout.Pane?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.control.CheckBox?>
|
||||
|
||||
<GridPane vgap="12.0" hgap="12.0" prefWidth="400.0" xmlns:fx="http://javafx.com/fxml" cacheShape="true" cache="true">
|
||||
<padding>
|
||||
@@ -34,15 +36,17 @@
|
||||
<Pane prefHeight="12.0" GridPane.rowIndex="1" GridPane.columnIndex="0" GridPane.columnSpan="2" cacheShape="true" cache="true">
|
||||
</Pane>
|
||||
|
||||
<Label text="%unlock.label.password" cacheShape="true" cache="true" GridPane.rowIndex="2" GridPane.columnIndex="0" />
|
||||
<SecPasswordField fx:id="passwordField" cacheShape="true" cache="true" GridPane.rowIndex="2" GridPane.columnIndex="1" />
|
||||
<Label text="%unlock.label.password" GridPane.rowIndex="2" GridPane.columnIndex="0" cacheShape="true" cache="true" />
|
||||
<SecPasswordField fx:id="passwordField" GridPane.rowIndex="2" GridPane.columnIndex="1" cacheShape="true" cache="true" />
|
||||
|
||||
<CheckBox fx:id="confirmationCheckbox" text="%upgrade.confirmation.label" wrapText="true" GridPane.rowIndex="3" GridPane.columnIndex="0" GridPane.columnSpan="2" cacheShape="true" cache="true" />
|
||||
|
||||
<HBox alignment="CENTER_RIGHT" GridPane.hgrow="ALWAYS" GridPane.rowIndex="3" GridPane.columnIndex="0" GridPane.columnSpan="2" cacheShape="true" cache="true">
|
||||
<HBox alignment="CENTER_RIGHT" GridPane.hgrow="ALWAYS" GridPane.rowIndex="4" GridPane.columnIndex="0" GridPane.columnSpan="2" cacheShape="true" cache="true">
|
||||
<Button fx:id="upgradeButton" text="%upgrade.button" prefWidth="150.0" onAction="#didClickUpgradeButton" cacheShape="true" cache="true" />
|
||||
</HBox>
|
||||
|
||||
<ProgressIndicator progress="-1" fx:id="progressIndicator" visible="false" cacheShape="true" cache="true" cacheHint="SPEED" GridPane.rowIndex="4" GridPane.columnIndex="0" GridPane.columnSpan="2" />
|
||||
<ProgressIndicator progress="-1" fx:id="progressIndicator" visible="false" GridPane.rowIndex="5" GridPane.columnIndex="0" GridPane.columnSpan="2" cacheShape="true" cache="true" cacheHint="SPEED" />
|
||||
|
||||
<Label fx:id="errorLabel" wrapText="true" GridPane.rowIndex="5" GridPane.columnIndex="0" GridPane.columnSpan="2" cacheShape="true" cache="true" />
|
||||
<Label fx:id="errorLabel" wrapText="true" GridPane.rowIndex="6" GridPane.columnIndex="0" GridPane.columnSpan="2" cacheShape="true" cache="true" />
|
||||
</children>
|
||||
</GridPane>
|
||||
|
||||
@@ -82,4 +82,10 @@ main.directoryList.remove.confirmation.title = Tresor entfernen
|
||||
main.directoryList.remove.confirmation.header = Möchten Sie diesen Tresor wirklich entfernen?
|
||||
main.directoryList.remove.confirmation.content = Dieser Tresor wird nur aus der Liste entfernt. Um den Tresor unwiderruflich zu löschen, entfernen Sie bitte die Dateien aus Ihrem Dateisystem.
|
||||
upgrade.version3to4.msg = Dieser Tresor muss auf ein neueres Format aktualisiert werden.\nVerschlüsselte Ordnernamen werden dabei aktualisiert.\nStellen Sie bitte sicher, dass derzeit keine Synchronisation stattfindet.
|
||||
upgrade.version3to4.err.io = Migration aufgrund eines I/O-Fehlers fehlgeschlagen.\nWeitere Informationen in der Log-Datei.
|
||||
upgrade.version3to4.err.io = Migration aufgrund eines I/O-Fehlers fehlgeschlagen.\nWeitere Informationen in der Log-Datei.
|
||||
settings.prefGvfsScheme.label = WebDAV Schema
|
||||
# upgrade.fxml
|
||||
upgrade.confirmation.label = Ja, die Synchronisation ist abgeschlossen
|
||||
initialize.messageLabel.notEmpty = Tresor ist nicht leer
|
||||
unlock.label.savePassword = Passwort speichern
|
||||
unlock.errorMessage.unauthenticVersionMac = Versions-MAC konnte nicht authentifiziert werden.
|
||||
@@ -26,6 +26,7 @@ initialize.label.password=Password
|
||||
initialize.label.retypePassword=Retype password
|
||||
initialize.button.ok=Create vault
|
||||
initialize.messageLabel.alreadyInitialized=Vault already initialized
|
||||
initialize.messageLabel.notEmpty=Vault not empty
|
||||
initialize.messageLabel.initializationFailed=Could not initialize vault. See log file for details.
|
||||
initialize.messageLabel.passwordStrength.0=Very weak
|
||||
initialize.messageLabel.passwordStrength.1=Weak
|
||||
@@ -38,6 +39,7 @@ initialize.label.doNotForget=IMPORTANT: If you forget your password, there is no
|
||||
notfound.label=Vault couldn't be found. Has it been moved?
|
||||
|
||||
# upgrade.fxml
|
||||
upgrade.confirmation.label=Yes, I've made sure that synchronization has finished
|
||||
upgrade.button=Upgrade vault
|
||||
|
||||
upgrade.version3dropBundleExtension.msg=This vault needs to be migrated to a newer format.\n"%1$s" will be renamed to "%2$s".\nPlease make sure synchronization has finished before proceeding.
|
||||
@@ -48,6 +50,7 @@ upgrade.version3to4.err.io=Migration failed due to an I/O Exception. See log fil
|
||||
|
||||
# unlock.fxml
|
||||
unlock.label.password=Password
|
||||
unlock.label.savePassword=Save password
|
||||
unlock.label.mountName=Drive name
|
||||
unlock.label.winDriveLetter=Drive letter
|
||||
unlock.label.downloadsPageLink=All Cryptomator versions
|
||||
@@ -60,6 +63,7 @@ unlock.errorMessage.wrongPassword=Wrong password
|
||||
unlock.errorMessage.mountingFailed=Mounting failed. See log file for details.
|
||||
unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware=Unsupported vault. This vault has been created with an older version of Cryptomator.
|
||||
unlock.errorMessage.unsupportedVersion.softwareOlderThanVault=Unsupported vault. This vault has been created with a newer version of Cryptomator.
|
||||
unlock.errorMessage.unauthenticVersionMac=Could not authenticate version MAC.
|
||||
unlock.messageLabel.startServerFailed=Starting WebDAV server failed.
|
||||
|
||||
# change_password.fxml
|
||||
@@ -70,7 +74,6 @@ changePassword.label.downloadsPageLink=All Cryptomator versions
|
||||
changePassword.button.change=Change password
|
||||
changePassword.errorMessage.wrongPassword=Wrong password
|
||||
changePassword.errorMessage.decryptionFailed=Decryption failed
|
||||
changePassword.infoMessage.success=Password changed
|
||||
|
||||
# unlocked.fxml
|
||||
unlocked.button.lock=Lock vault
|
||||
|
||||
@@ -14,7 +14,7 @@ initialize.label.password = Contraseña
|
||||
initialize.label.retypePassword = Reintroduzca contraseña
|
||||
initialize.button.ok = Crear caja fuerte
|
||||
initialize.messageLabel.alreadyInitialized = Caja fuerte ya está inicializado
|
||||
initialize.messageLabel.initializationFailed = No se pudo inicializar la caja fuerte. Ver archivo de registro para detalles.
|
||||
initialize.messageLabel.initializationFailed = No se pudo inicializar la caja fuerte. Ver archivo de registro para detalles.
|
||||
# notfound.fxml
|
||||
notfound.label = No se pudo encontrar la caja fuerte. Se movió a otro lugar?
|
||||
# upgrade.fxml
|
||||
@@ -83,4 +83,10 @@ main.directoryList.remove.confirmation.title = Borrar caja fuerte
|
||||
main.directoryList.remove.confirmation.header = ¿Quieres de verdad borrar este caja fuerte?
|
||||
main.directoryList.remove.confirmation.content = La caja fuerte solo se borra de la lista. Para eliminarla permanente por favor elimina los datos de tú sistema de archivos.
|
||||
upgrade.version3to4.msg = Este caja fuerte se debe migrar a un formato más reciente.\nLos nombres de las carpetas cifradas se actualizan.\nPor favor asegurarse de que la sincronización ha terminado antes de seguir.
|
||||
upgrade.version3to4.err.io = Migración ha fallado por causa de una excepción I/O. Para detalles revisa el archivo de registro.
|
||||
upgrade.version3to4.err.io = Migración ha fallado por causa de una excepción I/O. Para detalles revisa el archivo de registro.
|
||||
settings.prefGvfsScheme.label = WebDAV scheme
|
||||
# upgrade.fxml
|
||||
upgrade.confirmation.label = Yes, I've made sure that synchronization has finished
|
||||
initialize.messageLabel.notEmpty = Vault not empty
|
||||
unlock.label.savePassword = Save password
|
||||
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
|
||||
@@ -78,10 +78,16 @@ initialize.messageLabel.passwordStrength.0 = Très faible
|
||||
initialize.messageLabel.passwordStrength.1 = Faible
|
||||
initialize.messageLabel.passwordStrength.2 = Raisonnable
|
||||
initialize.messageLabel.passwordStrength.3 = Fort
|
||||
initialize.messageLabel.passwordStrength.4 = Très fort\n
|
||||
initialize.messageLabel.passwordStrength.4 = Très fort
|
||||
initialize.label.doNotForget = ATTENTION \: Si vous oubliez votre mot de passe, il n'y aura aucun moyen de récupérer vos données.
|
||||
main.directoryList.remove.confirmation.title = Retirer un coffre
|
||||
main.directoryList.remove.confirmation.header = Voulez-vous vraiment retirer ce coffre ?
|
||||
main.directoryList.remove.confirmation.content = Le coffre sera simplement retiré de la liste. Pour le supprimer complètement, supprimez les fichiers depuis votre système de fichiers.
|
||||
upgrade.version3to4.msg = Ce coffre doit être converti dans un nouveau format. Les noms de dossiers chiffrés seront mis à jour.\nMerci de vous assurer que la procédure de synchronisation est terminée avant de continuer.
|
||||
upgrade.version3to4.err.io = La migration a échoué à cause d'une erreur d'entrée/sortie. Référez-vous au fichier log pour plus de détails.
|
||||
upgrade.version3to4.err.io = La migration a échoué à cause d'une erreur d'entrée/sortie. Référez-vous au fichier log pour plus de détails.
|
||||
settings.prefGvfsScheme.label = Schéma d'URI WebDAV
|
||||
# upgrade.fxml
|
||||
upgrade.confirmation.label = Oui, je suis certain que la synchronisation est finie
|
||||
initialize.messageLabel.notEmpty = Vault not empty
|
||||
unlock.label.savePassword = Save password
|
||||
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
|
||||
@@ -79,4 +79,12 @@ initialize.messageLabel.passwordStrength.4 = Nagyon erős
|
||||
initialize.label.doNotForget = FONTOS\: Ha elfelejted a jelszavadat, akkor nincs lehetőség az adataid visszaállítására.
|
||||
main.directoryList.remove.confirmation.title = Széf eltávolítása
|
||||
main.directoryList.remove.confirmation.header = Tényleg törölni akarod ezt a széfet?
|
||||
main.directoryList.remove.confirmation.content = A széf csak a listából lesz eltávolítva. Végleges törléshez kérlek töröld a merevlemezen tárolt fájlokat.
|
||||
main.directoryList.remove.confirmation.content = A széf csak a listából lesz eltávolítva. Végleges törléshez kérlek töröld a merevlemezen tárolt fájlokat.
|
||||
upgrade.version3to4.msg = Ennek a széfnek egy újabb formátumra való migrációja szükséges. A titkosított könyvtárnevek frissítve lesznek. Kérlek, győződj meg a szinkronizáció befejeztéről mielőtt továbblépnél.
|
||||
upgrade.version3to4.err.io = Migráció meghíusúlt egy I/O kivétel miatt. Kérlek nézd meg a naplófájlt a további részletekért.
|
||||
settings.prefGvfsScheme.label = WebDAV séma
|
||||
# upgrade.fxml
|
||||
upgrade.confirmation.label = Yes, I've made sure that synchronization has finished
|
||||
initialize.messageLabel.notEmpty = Vault not empty
|
||||
unlock.label.savePassword = Save password
|
||||
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
|
||||
@@ -18,7 +18,7 @@ initialize.messageLabel.initializationFailed = Non è possibile inizializzare il
|
||||
notfound.label = Il vault non può essere trovato. E' stato rimosso?
|
||||
# upgrade.fxml
|
||||
upgrade.button = Aggiorna vault
|
||||
upgrade.version3dropBundleExtension.msg = Questo vault deve essere migrato ad un nuovo formato.\n"%1$s" verrà rinominato in "%2$s".\nPer favore verifica che la sincronizzazione sia finita prima di procedere\n
|
||||
upgrade.version3dropBundleExtension.msg = Questo vault deve essere migrato ad un nuovo formato.\n"%1$s" verrà rinominato in "%2$s".\nPer favore verifica che la sincronizzazione sia finita prima di procedere
|
||||
upgrade.version3dropBundleExtension.err.alreadyExists = Migrazione automatica fallita.\n"%s" esiste già.
|
||||
# unlock.fxml
|
||||
unlock.label.password = Password
|
||||
@@ -45,14 +45,14 @@ changePassword.errorMessage.wrongPassword = Password errata
|
||||
changePassword.errorMessage.decryptionFailed = Decriptaggio fallito
|
||||
changePassword.infoMessage.success = Password cambiata
|
||||
# unlocked.fxml
|
||||
unlocked.button.lock = Blocca vault
|
||||
unlocked.button.lock = Blocca vault
|
||||
unlocked.moreOptions.reveal = Apri il disco
|
||||
unlocked.moreOptions.copyUrl = Copia url WebDAV
|
||||
unlocked.label.revealFailed = Comando fallito
|
||||
unlocked.label.unmountFailed = Espulsione disco fallita
|
||||
unlocked.label.statsEncrypted = criptato
|
||||
unlocked.label.statsDecrypted = decriptato
|
||||
unlocked.ioGraph.yAxis.label = Volume dati (MiB/s)
|
||||
unlocked.ioGraph.yAxis.label = Volume dati (MiB/s)
|
||||
# mac_warnings.fxml
|
||||
macWarnings.windowTitle = Pericolo - File corroto in %s
|
||||
macWarnings.message = Cryptomator ha individuato potenziali pericolose corruzioni nei seguenti file\:
|
||||
@@ -69,8 +69,8 @@ settings.requiresRestartLabel = * Cryptomator deve essere riavviato
|
||||
tray.menu.open = Apri
|
||||
tray.menu.quit = Chiudi
|
||||
tray.infoMsg.title = Ancora in esecuzione
|
||||
tray.infoMsg.msg = Cryptomator è ancora in esecuzione. Chiudilo utilizzando l'icona nel menù di stato.
|
||||
tray.infoMsg.msg.osx = Cryptomator è ancora in esecuzione. Chiudilo utilizzando l'icona nella barra del menù.
|
||||
tray.infoMsg.msg = Cryptomator è ancora in esecuzione. Chiudilo utilizzando l'icona nel menù di stato.
|
||||
tray.infoMsg.msg.osx = Cryptomator è ancora in esecuzione. Chiudilo utilizzando l'icona nella barra del menù.
|
||||
initialize.messageLabel.passwordStrength.0 = Molto debole
|
||||
initialize.messageLabel.passwordStrength.1 = Debole
|
||||
initialize.messageLabel.passwordStrength.2 = Buona
|
||||
@@ -79,4 +79,12 @@ initialize.messageLabel.passwordStrength.4 = Molto sicura
|
||||
initialize.label.doNotForget = IMPORTANTE\: Se dimentichi la password, non c'è modo di recuperare i tuoi dati.
|
||||
main.directoryList.remove.confirmation.title = Rimuovi vault
|
||||
main.directoryList.remove.confirmation.header = Vuoi davvero rimuovere questo vault?
|
||||
main.directoryList.remove.confirmation.content = Il vault sarà rimosso solo dalla lista. Per eliminarlo definitivamente, elimina per favore i file dal tuo hard disk.
|
||||
main.directoryList.remove.confirmation.content = Il vault sarà rimosso solo dalla lista. Per eliminarlo definitivamente, elimina per favore i file dal tuo hard disk.
|
||||
upgrade.version3to4.msg = This vault needs to be migrated to a newer format.\nEncrypted folder names will be updated.\nPlease make sure synchronization has finished before proceeding.
|
||||
upgrade.version3to4.err.io = Migration failed due to an I/O Exception. See log file for details.
|
||||
settings.prefGvfsScheme.label = WebDAV scheme
|
||||
# upgrade.fxml
|
||||
upgrade.confirmation.label = Yes, I've made sure that synchronization has finished
|
||||
initialize.messageLabel.notEmpty = Vault not empty
|
||||
unlock.label.savePassword = Save password
|
||||
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
|
||||
@@ -81,4 +81,10 @@ main.directoryList.remove.confirmation.title = 보관함 삭제
|
||||
main.directoryList.remove.confirmation.header = 정말 이 보관함을 삭제하시겠습니까?
|
||||
main.directoryList.remove.confirmation.content = 보관함이 목록에서만 제거되었습니다. 데이터를 완전히 제거하시려면, 여러분의 파일시스템이서 제거해 주시기 바랍니다.
|
||||
upgrade.version3to4.msg = 이 보관함은 새로운 형식으로 바뀔 필요가 있습니다. 암호화된 폴더 이름이 업데이트 될 것입니다. 진행하기 전에 동기화가 완료되었는지 확인하기 바랍니다.
|
||||
upgrade.version3to4.err.io = 입출력 예외 문제로 마이그레이션이 실패하였습니다. 자세한 사항은 로그 파일을 확인하세요.
|
||||
upgrade.version3to4.err.io = 입출력 예외 문제로 마이그레이션이 실패하였습니다. 자세한 사항은 로그 파일을 확인하세요.
|
||||
settings.prefGvfsScheme.label = WebDAV sceme
|
||||
# upgrade.fxml
|
||||
upgrade.confirmation.label = 네. 동기화가 완료되었음을 확인하였습니다.
|
||||
initialize.messageLabel.notEmpty = Vault not empty
|
||||
unlock.label.savePassword = Save password
|
||||
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
|
||||
@@ -0,0 +1,91 @@
|
||||
app.name = Cryptomator
|
||||
# main.fxml
|
||||
main.emptyListInstructions = Noklikšķiniet šeit, lai pievienotu glabātuvi
|
||||
main.directoryList.contextMenu.remove = Noņemt no saraksta
|
||||
main.directoryList.contextMenu.changePassword = Mainīt paroli
|
||||
main.addDirectory.contextMenu.new = Izveidot jaunu glabātuvi
|
||||
main.addDirectory.contextMenu.open = Atvērt esošu glabātuvi
|
||||
# welcome.fxml
|
||||
welcome.checkForUpdates.label.currentlyChecking = Pārbauda atjauninājumus...
|
||||
welcome.newVersionMessage = Lejupielādei pieejama versija %1$s.\nŠī ir %2$s.
|
||||
# initialize.fxml
|
||||
initialize.label.password = Parole
|
||||
initialize.label.retypePassword = Atkārto paroli
|
||||
initialize.button.ok = Izveidot glabātuvi
|
||||
initialize.messageLabel.alreadyInitialized = Glabātuve jau ir inicializēta
|
||||
initialize.messageLabel.initializationFailed = Nevarēja inicializēt glabātuvi. Sīkākai informācijai skati žurnālu.
|
||||
# notfound.fxml
|
||||
notfound.label = Nevar atrast glabātuvi. Vai tā ir pārvietota?
|
||||
# upgrade.fxml
|
||||
upgrade.button = Atjaunināt glabātuvi
|
||||
upgrade.version3dropBundleExtension.msg = Šī glabātuve ir jāmigrē uz jaunākas versijas formātu.\n"%1$s" tiks pārsaukta par "%2$s".\nPirms palaišanas pārliecinies, ka ir beigusies sinhronizācija.
|
||||
upgrade.version3dropBundleExtension.err.alreadyExists = Automātiskā migrācija neizdevās.\n"%s" jau eksistē.
|
||||
# unlock.fxml
|
||||
unlock.label.password = Parole
|
||||
unlock.label.mountName = Diska nosaukums
|
||||
unlock.label.winDriveLetter = Diska burts
|
||||
unlock.label.downloadsPageLink = Visas Cryptomator versijas
|
||||
unlock.label.advancedHeading = Papildus opcijas
|
||||
unlock.button.unlock = Atslēgt glabātuvi
|
||||
unlock.button.advancedOptions.show = Vairāk opcijas
|
||||
unlock.button.advancedOptions.hide = Mazāk opcijas
|
||||
unlock.choicebox.winDriveLetter.auto = Piešķirt automātiski
|
||||
unlock.errorMessage.wrongPassword = Nepareiza parole
|
||||
unlock.errorMessage.mountingFailed = Montēšana neizdevās. Sīkākai informācijai skati žurnālu.
|
||||
unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware = Neatbastīta glabātuve. Šī glabātuve ir veidota ar vecāku Cryptomator versiju.
|
||||
unlock.errorMessage.unsupportedVersion.softwareOlderThanVault = Neatbastīta glabātuve. Šī glabātuve ir veidota ar jaunāku Cryptomator versiju.
|
||||
unlock.messageLabel.startServerFailed = WebDAV servera palaišana neizdevās.
|
||||
# change_password.fxml
|
||||
changePassword.label.oldPassword = Vecā parole
|
||||
changePassword.label.newPassword = Jaunā parole
|
||||
changePassword.label.retypePassword = Atkārto paroli
|
||||
changePassword.label.downloadsPageLink = Visas Cryptomator versijas
|
||||
changePassword.button.change = Mainīt paroli
|
||||
changePassword.errorMessage.wrongPassword = Nepareiza parole
|
||||
changePassword.errorMessage.decryptionFailed = Atšifrēšana neizdevās
|
||||
changePassword.infoMessage.success = Parole nomainīta
|
||||
# unlocked.fxml
|
||||
unlocked.button.lock = Aizslēgt glabātuvi
|
||||
unlocked.moreOptions.reveal = Atklāt disku
|
||||
unlocked.moreOptions.copyUrl = Kopēt WebDAV saiti
|
||||
unlocked.label.revealFailed = Komunikācija neizdevās
|
||||
unlocked.label.unmountFailed = Diska izgrūšana neizdevās
|
||||
unlocked.label.statsEncrypted = šifrēts
|
||||
unlocked.label.statsDecrypted = atšifrēts
|
||||
unlocked.ioGraph.yAxis.label = Caurlaidība (MiB/s)
|
||||
# mac_warnings.fxml
|
||||
macWarnings.windowTitle = Bīstami - %s satur bojātu datni
|
||||
macWarnings.message = Cryptomator konstatēja potenciāli ļaunprātīgu bojājumu sekojošām datnēm\:
|
||||
macWarnings.moreInformationButton = Skatīt vairāk
|
||||
macWarnings.whitelistButton = Atšifrēt iezīmēto tāpat
|
||||
# settings.fxml
|
||||
settings.version.label = Versija %s
|
||||
settings.checkForUpdates.label = Meklēt atjauninājumus
|
||||
settings.port.label = WebDAV Ports *
|
||||
settings.port.prompt = 0 \= automātiski
|
||||
settings.useipv6.label = Izmantot IPv6
|
||||
settings.requiresRestartLabel = * Cryptomator nepieciešams restarts
|
||||
# tray icon
|
||||
tray.menu.open = Atvērt
|
||||
tray.menu.quit = Iziet
|
||||
tray.infoMsg.title = Joprojām darbojās
|
||||
# Fuzzy
|
||||
tray.infoMsg.msg = Cryptomator joprojām darbojās. Iziet var no ikonas.
|
||||
tray.infoMsg.msg.osx = Cryptomator is still alive. joprojām darbojās. Iziet var no izvēlnes ikonas.
|
||||
initialize.messageLabel.passwordStrength.0 = Ļoti vāja
|
||||
initialize.messageLabel.passwordStrength.1 = Vāja
|
||||
initialize.messageLabel.passwordStrength.2 = Vidēja
|
||||
initialize.messageLabel.passwordStrength.3 = Stipra
|
||||
initialize.messageLabel.passwordStrength.4 = Ļoti stipra
|
||||
initialize.label.doNotForget = SVARĪGI\: Ja tu aizmirsti paroli, nav ceļa datu atjaunošanai
|
||||
main.directoryList.remove.confirmation.title = Noņemt glabātuvi
|
||||
main.directoryList.remove.confirmation.header = Vai tiešām vēlie noņemt šo glabātuvi?
|
||||
main.directoryList.remove.confirmation.content = Glabātuve tiks noņemta tikai no saraksta. Lai to dzēstu pilnībā, lūdzu nodzēs to no datņu sistēmas.
|
||||
upgrade.version3to4.msg = Šī glabātuve ir jāmigrē uz jaunāku formāta versiju. Sifrētie mapju nosaukumi tiks atjaunināti. Pirms palaišanas lūdzu pārliecinies, ka ir pabeigusies sinhronizācija.
|
||||
upgrade.version3to4.err.io = Migrācija neizdevās dēļ I/O izņēmuma. Sīkākai informācijai skati žurnālu.
|
||||
settings.prefGvfsScheme.label = WebDAV shēma
|
||||
# upgrade.fxml
|
||||
upgrade.confirmation.label = Jā, esmu pārliecinājies, ka sinhronizācija ir pabeigta.
|
||||
initialize.messageLabel.notEmpty = Vault not empty
|
||||
unlock.label.savePassword = Save password
|
||||
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
|
||||
@@ -81,4 +81,10 @@ main.directoryList.remove.confirmation.title = Verwijder Kluis
|
||||
main.directoryList.remove.confirmation.header = Weet je zeker dat je deze kluis wilt verwijderen?
|
||||
main.directoryList.remove.confirmation.content = De kluis zal alleen van de lijst worden verwijdert. Verwijder de bestanden van het bestandssysteem voor permanente verwijdering.
|
||||
upgrade.version3to4.msg = Deze kluis dient gemigreerd te worden naar een nieuwer type. \nVersleutelde mapnamen zullen worden geüpdatet. \nZorg ervoor dat de synchronisatie voltooid is alvorens door te gaan.
|
||||
upgrade.version3to4.err.io = Migratie mislukt door een I/O Exception. Zie logbestand voor details.
|
||||
upgrade.version3to4.err.io = Migratie mislukt door een I/O Exception. Zie logbestand voor details.
|
||||
settings.prefGvfsScheme.label = WebDAV scheme
|
||||
# upgrade.fxml
|
||||
upgrade.confirmation.label = Yes, I've made sure that synchronization has finished
|
||||
initialize.messageLabel.notEmpty = Vault not empty
|
||||
unlock.label.savePassword = Save password
|
||||
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
|
||||
@@ -0,0 +1,90 @@
|
||||
app.name = Cryptomator
|
||||
# main.fxml
|
||||
main.emptyListInstructions = Kliknij tutaj aby dodać kryptę
|
||||
main.directoryList.contextMenu.remove = Usuń z listy
|
||||
main.directoryList.contextMenu.changePassword = Zmień hasło
|
||||
main.addDirectory.contextMenu.new = Stwórz nową kryptę
|
||||
main.addDirectory.contextMenu.open = Otwórz istniejącą kryptę
|
||||
# welcome.fxml
|
||||
welcome.checkForUpdates.label.currentlyChecking = Sprawdź aktualizację
|
||||
welcome.newVersionMessage = Wersja %1$s może być pobrana.\nObecna %2$s.
|
||||
# initialize.fxml
|
||||
initialize.label.password = Hasło
|
||||
initialize.label.retypePassword = Ponów hasło
|
||||
initialize.button.ok = Stwórz kryptę
|
||||
initialize.messageLabel.alreadyInitialized = Krypta aktualnie załadowana
|
||||
initialize.messageLabel.initializationFailed = Nie można załadować krypty. Sprawdź logi
|
||||
# notfound.fxml
|
||||
notfound.label = Krypta nie znaleziona. Przeniesiona?
|
||||
# upgrade.fxml
|
||||
upgrade.button = Aktualizuj kryptę
|
||||
upgrade.version3dropBundleExtension.msg = Ta krypta musi zostać przeniesiona do nowego formatu\n"%1$s" zamienione na "%2$s".\nProszę synchronizować przed skończeniem procesu
|
||||
upgrade.version3dropBundleExtension.err.alreadyExists = Błąd automatycznej migracji.\n"%s" już istnieje
|
||||
# unlock.fxml
|
||||
unlock.label.password = Hasło
|
||||
unlock.label.mountName = Nazwa dysku
|
||||
unlock.label.winDriveLetter = Litera dysku
|
||||
unlock.label.downloadsPageLink = Wszystkie wersje Cryptomatora
|
||||
unlock.label.advancedHeading = Zaawansowane opcje
|
||||
unlock.button.unlock = Odblokuj kryptę
|
||||
unlock.button.advancedOptions.show = Więcej opcji
|
||||
unlock.button.advancedOptions.hide = Mniej opcji
|
||||
unlock.choicebox.winDriveLetter.auto = Przydzielone automatycznie
|
||||
unlock.errorMessage.wrongPassword = Złe hasło
|
||||
unlock.errorMessage.mountingFailed = Błąd zamontowania. Sprawdź logi
|
||||
unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware = Niewspierana krypta, utworzona przez starszą wersje Cryptomatora
|
||||
unlock.errorMessage.unsupportedVersion.softwareOlderThanVault = Niewspierana krypta, utworzona przez nowszą wersje Cryptomatora
|
||||
unlock.messageLabel.startServerFailed = Błąd startu serwera WebDAV
|
||||
# change_password.fxml
|
||||
changePassword.label.oldPassword = Stare hasło
|
||||
changePassword.label.newPassword = Nowe hasło
|
||||
changePassword.label.retypePassword = Powtórz hasło
|
||||
changePassword.label.downloadsPageLink = Wszystkie wersje Cryptomatora
|
||||
changePassword.button.change = Zmień hasło
|
||||
changePassword.errorMessage.wrongPassword = Złe hasło
|
||||
changePassword.errorMessage.decryptionFailed = Błąd deszyfracji
|
||||
changePassword.infoMessage.success = Hasło zmienione
|
||||
# unlocked.fxml
|
||||
unlocked.button.lock = Zablokuj kryptę
|
||||
unlocked.moreOptions.reveal = Zwolnij napęd
|
||||
unlocked.moreOptions.copyUrl = Skopiuj url WebDAV
|
||||
unlocked.label.revealFailed = Zła komenda
|
||||
unlocked.label.unmountFailed = Błąd wysuwania napędu
|
||||
unlocked.label.statsEncrypted = Zaszyfrowany
|
||||
unlocked.label.statsDecrypted = Odszyfrowany
|
||||
unlocked.ioGraph.yAxis.label = Wydajność (MiB/s)
|
||||
# mac_warnings.fxml
|
||||
macWarnings.windowTitle = Uwaga - Plik uszkodzony %s
|
||||
macWarnings.message = Wykryto zagrożenie w plikach
|
||||
macWarnings.moreInformationButton = Czytaj więcej
|
||||
macWarnings.whitelistButton = Odszyfruj wszystko
|
||||
# settings.fxml
|
||||
settings.version.label = Wersja %s
|
||||
settings.checkForUpdates.label = Sprawdź aktualizacje
|
||||
settings.port.label = WebDAV port *
|
||||
settings.port.prompt = 0 \= Automatycznie
|
||||
settings.useipv6.label = Użyj IPv6
|
||||
settings.requiresRestartLabel = * Cryptomator wymaga restartu
|
||||
# tray icon
|
||||
tray.menu.open = Otwórz
|
||||
tray.menu.quit = Wyjdź
|
||||
tray.infoMsg.title = Nadal działa
|
||||
tray.infoMsg.msg = Cryptomator działa nadal. Wyjdź z ikony tray
|
||||
tray.infoMsg.msg.osx = Cryptomator działa nadal. Wyjdź z menu programu
|
||||
initialize.messageLabel.passwordStrength.0 = Bardzo słabe
|
||||
initialize.messageLabel.passwordStrength.1 = Słabe
|
||||
initialize.messageLabel.passwordStrength.2 = W porządku
|
||||
initialize.messageLabel.passwordStrength.3 = Mocne
|
||||
initialize.messageLabel.passwordStrength.4 = Bardzo mocne
|
||||
initialize.label.doNotForget = Ważne\! Jeśli zapomnisz hasło stracisz dostęp do danych
|
||||
main.directoryList.remove.confirmation.title = Usuń kryptę
|
||||
main.directoryList.remove.confirmation.header = Czy na pewno chcesz osunąć kryptę?
|
||||
main.directoryList.remove.confirmation.content = Ta krypta zostanie usunięta z listy. Ostatecznie usuń dane z dysku.
|
||||
upgrade.version3to4.msg = Krypta wymaga migracji do nowszej wersji. Nazwa folderu zaszyfrowanego zostanie zaktualizowana. Synchronizuj dane przed procesem.
|
||||
upgrade.version3to4.err.io = Błąd migracji I/O Exception. Sprawdź logi
|
||||
settings.prefGvfsScheme.label = Schemat WebDAV
|
||||
# upgrade.fxml
|
||||
upgrade.confirmation.label = Tak, jestem pewien, że zakończyłem synchronizacje
|
||||
initialize.messageLabel.notEmpty = Vault not empty
|
||||
unlock.label.savePassword = Save password
|
||||
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
|
||||
@@ -1,34 +1,90 @@
|
||||
# Copyright (c) 2016 The Cryptomator Contributors
|
||||
# This file is licensed under the terms of the MIT license.
|
||||
# See the LICENSE.txt file for more info.
|
||||
#
|
||||
# Contributors:
|
||||
# Will
|
||||
# André Di Biasi
|
||||
|
||||
app.name = Cryptomator
|
||||
# main.fxml
|
||||
main.emptyListInstructions = Clique aqui para adicionar uma caixa-forte
|
||||
main.directoryList.contextMenu.remove = Remover da lista
|
||||
main.directoryList.contextMenu.changePassword = Alterar senha
|
||||
main.addDirectory.contextMenu.new = Criar nova caixa-forte
|
||||
main.addDirectory.contextMenu.open = Abrir caixa-forte existente
|
||||
# welcome.fxml
|
||||
welcome.checkForUpdates.label.currentlyChecking = Procurando atualizações...
|
||||
welcome.checkForUpdates.label.currentlyChecking = Buscando por atualizações...
|
||||
welcome.newVersionMessage = Versão %1$s pode ser abaixada. Esta é a versão %2$s.
|
||||
# initialize.fxml
|
||||
initialize.label.password = Senha
|
||||
initialize.label.retypePassword = Digite a senha novamente
|
||||
initialize.label.retypePassword = Redigitar senha
|
||||
initialize.button.ok = Criar caixa-forte
|
||||
initialize.messageLabel.alreadyInitialized = Caixa-forte já inicializada
|
||||
initialize.messageLabel.initializationFailed = Não pôde inicializar a caixa-forte. Ver arquivo de log para mais detalhes.
|
||||
# notfound.fxml
|
||||
notfound.label = A caixa-forte não pode ser encontrada. Ela foi movida?
|
||||
# upgrade.fxml
|
||||
upgrade.button = Atualizar caixa-forte
|
||||
upgrade.version3dropBundleExtension.msg = Esta caixa-forte tem que ser a migrada a um novo formato. "%1$s" será renomeada para "%2$s". Por favor assegure-se de que a sincronização foi finalizada antes de proceder com a migração.
|
||||
upgrade.version3dropBundleExtension.err.alreadyExists = A migração automática falhou. "%s" já existe.
|
||||
# unlock.fxml
|
||||
unlock.label.password = Senha
|
||||
unlock.label.mountName = Nome do drive
|
||||
unlock.label.winDriveLetter = Letra do drive
|
||||
unlock.label.downloadsPageLink = Todas as versões do Cryptomator
|
||||
unlock.label.advancedHeading = Opções avançadas
|
||||
unlock.button.unlock = Abrir caixa-forte
|
||||
unlock.button.advancedOptions.show = Mais opções
|
||||
unlock.button.advancedOptions.hide = Menos opções
|
||||
unlock.choicebox.winDriveLetter.auto = Atribuir automaticamente
|
||||
unlock.errorMessage.wrongPassword = Senha incorreta
|
||||
unlock.errorMessage.mountingFailed = Montagem falhou. Veja o arquivo de log para detalhes
|
||||
unlock.messageLabel.startServerFailed = Inicialização do servidor WEBDAV falhou
|
||||
unlock.errorMessage.wrongPassword = Senha errada
|
||||
unlock.errorMessage.mountingFailed = Falha ao montar. Ver arquivo de log para mais detalhes.
|
||||
unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware = Caixa-forte não suportada. Esta caixa-forte foi criada por uma versão antiga do Cryptomator.
|
||||
unlock.errorMessage.unsupportedVersion.softwareOlderThanVault = Caixa-forte não suportada. Esta caixa-forte foi criada por uma versão mais nova do Cryptomator.
|
||||
unlock.messageLabel.startServerFailed = Falha ao iniciar servidor WebDAV.
|
||||
# change_password.fxml
|
||||
changePassword.label.oldPassword = Senha antiga
|
||||
changePassword.label.oldPassword = Senha anterior
|
||||
changePassword.label.newPassword = Nova senha
|
||||
changePassword.label.retypePassword = Digite a senha novamente
|
||||
changePassword.label.retypePassword = Re-digitar senha
|
||||
changePassword.label.downloadsPageLink = Todas as versões do Cryptomator
|
||||
changePassword.button.change = Alterar senha
|
||||
changePassword.errorMessage.wrongPassword = Senha incorreta
|
||||
changePassword.errorMessage.decryptionFailed = Falha ao desencriptar
|
||||
changePassword.infoMessage.success = Senha alterada
|
||||
unlocked.label.revealFailed = Falha no comando
|
||||
unlocked.label.unmountFailed = Falha ao ejetar o drive
|
||||
# unlocked.fxml
|
||||
unlocked.button.lock = Fechar caixa-forte
|
||||
unlocked.moreOptions.reveal = Mostrar drive
|
||||
unlocked.moreOptions.copyUrl = Copiar URL WebDAV
|
||||
unlocked.label.revealFailed = Falha ao mostrar drive
|
||||
unlocked.label.unmountFailed = Falha ao ejetar drive
|
||||
unlocked.label.statsEncrypted = encriptado
|
||||
unlocked.label.statsDecrypted = desencriptado
|
||||
unlocked.ioGraph.yAxis.label = Taxa de transferência (MiB/s)
|
||||
# mac_warnings.fxml
|
||||
macWarnings.windowTitle = Perigo - Arquivo corrompido na %s
|
||||
macWarnings.message = Cryptomator detectou potenciais corrupções maliciosas nos seguintes arquivos\:
|
||||
macWarnings.moreInformationButton = Saiba mais
|
||||
macWarnings.whitelistButton = Desencriptar selecionado de qualquer modo
|
||||
# settings.fxml
|
||||
settings.version.label = Versão %s
|
||||
settings.checkForUpdates.label = Verificar por atualizações
|
||||
settings.port.label = Port WebDAV *
|
||||
settings.port.prompt = 0 \= Escolher automaticamente
|
||||
settings.useipv6.label = Usar IPv6 literal
|
||||
settings.requiresRestartLabel = * Cryptomator necessita ser reiniciado
|
||||
# tray icon
|
||||
tray.menu.open = Abrir
|
||||
tray.menu.quit = Sair
|
||||
tray.infoMsg.title = Ainda em execução
|
||||
tray.infoMsg.msg = Cryptomator ainda está ativo. Finalize-o a partir do ícone da bandeja.
|
||||
tray.infoMsg.msg.osx = Cryptomator ainda está ativo. Finalize-o a partir do ícone da barra de menu.
|
||||
initialize.messageLabel.passwordStrength.0 = Muito fraca
|
||||
initialize.messageLabel.passwordStrength.1 = Fraca
|
||||
initialize.messageLabel.passwordStrength.2 = Razoável
|
||||
initialize.messageLabel.passwordStrength.3 = Forte
|
||||
initialize.messageLabel.passwordStrength.4 = Muito forte
|
||||
initialize.label.doNotForget = IMPORTANTE\: se você esquecer a sua senha, não haverá como recuperar os seus dados.
|
||||
main.directoryList.remove.confirmation.title = Remover caixa-forte
|
||||
main.directoryList.remove.confirmation.header = Você realmente quer remover esta caixa-forte?
|
||||
main.directoryList.remove.confirmation.content = A caixa-forte somente será removida da lista. Para apagá-la permanentemente, por favor apagar os arquivos do seu sistema de arquivos.
|
||||
upgrade.version3to4.msg = Esta caixa-forte tem que ser migrada a um novo formato. Os nomes das pastas encriptadas serão atualizados. Por favor assegure-se de que a sincronização foi finalizada antes de proceder com a migração.
|
||||
upgrade.version3to4.err.io = Falha na migração devido a um erro de E/S. Ver arquivo de log para mais detalhes.
|
||||
settings.prefGvfsScheme.label = WebDAV scheme
|
||||
# upgrade.fxml
|
||||
upgrade.confirmation.label = Yes, I've made sure that synchronization has finished
|
||||
initialize.messageLabel.notEmpty = Vault not empty
|
||||
unlock.label.savePassword = Save password
|
||||
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
|
||||
@@ -83,4 +83,10 @@ main.directoryList.remove.confirmation.title = Удаление хранилищ
|
||||
main.directoryList.remove.confirmation.header = Вы действительно хотите удалить это хранилище?
|
||||
main.directoryList.remove.confirmation.content = Хранилище будет удалено только из списка. Чтобы стереть его окончательно, удалите файлы из файловой системы.
|
||||
upgrade.version3to4.msg = Это хранилище требуется преобразовать в новый формат. Зашифрованные имена папок будут обновлены. Прежде чем продолжить, выполните синхронизацию.
|
||||
upgrade.version3to4.err.io = Преобразование не выполнено из-за ошибки ввода-вывода. См. подробности в файле-отчёте.
|
||||
upgrade.version3to4.err.io = Преобразование не выполнено из-за ошибки ввода-вывода. См. подробности в файле-отчёте.
|
||||
settings.prefGvfsScheme.label = Схема WebDAV
|
||||
# upgrade.fxml
|
||||
upgrade.confirmation.label = Да, синхронизация точно завершена
|
||||
initialize.messageLabel.notEmpty = Vault not empty
|
||||
unlock.label.savePassword = Save password
|
||||
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
|
||||
@@ -22,7 +22,7 @@ notfound.label = Trezor nemohol byť nenájdený. Bol presunutý?
|
||||
# upgrade.fxml
|
||||
upgrade.button = Upgradnúť trezor
|
||||
upgrade.version3dropBundleExtension.msg = Tento trezor musí byť premigrovaný na nový formát. "%1$s" bude premenovaný na "%2$s". Prosím, uistite sa že je dokončená synchronizácia skôr než budete pokračovať.
|
||||
upgrade.version3dropBundleExtension.err.alreadyExists = Automatická migrácia zlyhala. "%s" už existuje.
|
||||
upgrade.version3dropBundleExtension.err.alreadyExists = Automatická migrácia zlyhala. "%s" už existuje.
|
||||
# unlock.fxml
|
||||
unlock.label.password = Heslo
|
||||
unlock.label.mountName = Názov jednotky
|
||||
@@ -73,4 +73,21 @@ tray.menu.open = Otvoriť
|
||||
tray.menu.quit = Vypnúť
|
||||
tray.infoMsg.title = Stále beží
|
||||
tray.infoMsg.msg = Cryptomator je stále spustený. Vypnite ho pomocou ikony v systémovej lište.
|
||||
tray.infoMsg.msg.osx = Cryptomator je stále sputený. Ukončite ho pomocou ikony v menu.
|
||||
tray.infoMsg.msg.osx = Cryptomator je stále sputený. Ukončite ho pomocou ikony v menu.
|
||||
initialize.messageLabel.passwordStrength.0 = Very weak
|
||||
initialize.messageLabel.passwordStrength.1 = Weak
|
||||
initialize.messageLabel.passwordStrength.2 = Fair
|
||||
initialize.messageLabel.passwordStrength.3 = Strong
|
||||
initialize.messageLabel.passwordStrength.4 = Very strong
|
||||
initialize.label.doNotForget = IMPORTANT\: If you forget your password, there is no way to recover your data.
|
||||
main.directoryList.remove.confirmation.title = Remove Vault
|
||||
main.directoryList.remove.confirmation.header = Do you really want to remove this vault?
|
||||
main.directoryList.remove.confirmation.content = The vault will only be removed from the list. To permanently delete it, please delete the files from your filesystem.
|
||||
upgrade.version3to4.msg = This vault needs to be migrated to a newer format.\nEncrypted folder names will be updated.\nPlease make sure synchronization has finished before proceeding.
|
||||
upgrade.version3to4.err.io = Migration failed due to an I/O Exception. See log file for details.
|
||||
settings.prefGvfsScheme.label = WebDAV scheme
|
||||
# upgrade.fxml
|
||||
upgrade.confirmation.label = Yes, I've made sure that synchronization has finished
|
||||
initialize.messageLabel.notEmpty = Vault not empty
|
||||
unlock.label.savePassword = Save password
|
||||
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
|
||||
@@ -81,4 +81,10 @@ main.directoryList.remove.confirmation.title = Kasayı Sil
|
||||
main.directoryList.remove.confirmation.header = Kasayı silmek istediğinize emin misiniz ?
|
||||
main.directoryList.remove.confirmation.content = Kasa yalnızca listeden silinecek. Tamamen silmek için dosya sisteminizden dosyaları elle siliniz.
|
||||
upgrade.version3to4.msg = Bu kasanın yeni formata geçirilmesi gerekmekte. Şifreli klasör isimleri güncellenecek. Devam etmeden önce senkronizasyonun bittiğine emin olun.
|
||||
upgrade.version3to4.err.io = Format değiştirme işlemi I/O Hatası dolayısı ile başarısız oldu. Detaylar için log dosyasına bakın
|
||||
upgrade.version3to4.err.io = Format değiştirme işlemi I/O Hatası dolayısı ile başarısız oldu. Detaylar için log dosyasına bakın
|
||||
settings.prefGvfsScheme.label = WebDAV scheme
|
||||
# upgrade.fxml
|
||||
upgrade.confirmation.label = Yes, I've made sure that synchronization has finished
|
||||
initialize.messageLabel.notEmpty = Vault not empty
|
||||
unlock.label.savePassword = Save password
|
||||
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
|
||||
@@ -0,0 +1,90 @@
|
||||
app.name = Cryptomator
|
||||
# main.fxml
|
||||
main.emptyListInstructions = Натисніть тут, щоб додати сховище
|
||||
main.directoryList.contextMenu.remove = Видалити зі списку
|
||||
main.directoryList.contextMenu.changePassword = Змінити пароль
|
||||
main.addDirectory.contextMenu.new = Створити нове сховище
|
||||
main.addDirectory.contextMenu.open = Відкрити існуюче сховище
|
||||
# welcome.fxml
|
||||
welcome.checkForUpdates.label.currentlyChecking = Перевірка оновлень...
|
||||
welcome.newVersionMessage = Доступна версія %1$s.\nВаша версія %2$s.
|
||||
# initialize.fxml
|
||||
initialize.label.password = Пароль
|
||||
initialize.label.retypePassword = Повторіть пароль
|
||||
initialize.button.ok = Створити сховище
|
||||
initialize.messageLabel.alreadyInitialized = Сховище вже ініціалізовано
|
||||
initialize.messageLabel.initializationFailed = Неможливо ініціалізувати сховище. Дивіться деталі в файлі-звіті.
|
||||
# notfound.fxml
|
||||
notfound.label = Сховище не знайдене. Воно було переміщене?
|
||||
# upgrade.fxml
|
||||
upgrade.button = Оновити сховище
|
||||
upgrade.version3dropBundleExtension.msg = Це сховище необхідно перетворити в новіший формат.\n"%1$s" буде перейменовано в "%2$s".\nПереконайтеся, що синхронізація завершена, перш ніж продовжити.
|
||||
upgrade.version3dropBundleExtension.err.alreadyExists = Автоматичне перетворення не виконане.\n"%s" вже існує.
|
||||
# unlock.fxml
|
||||
unlock.label.password = Пароль
|
||||
unlock.label.mountName = Ім'я диска
|
||||
unlock.label.winDriveLetter = Літера диска
|
||||
unlock.label.downloadsPageLink = Всі версії Cryptomator
|
||||
unlock.label.advancedHeading = Додаткові налаштування
|
||||
unlock.button.unlock = Розблокувати сховище
|
||||
unlock.button.advancedOptions.show = Більше налаштувань
|
||||
unlock.button.advancedOptions.hide = Менше налаштувань
|
||||
unlock.choicebox.winDriveLetter.auto = Призначити автоматично
|
||||
unlock.errorMessage.wrongPassword = Пароль невірний
|
||||
unlock.errorMessage.mountingFailed = Монтування невдале. Дивіться деталі в файлі-звіті.
|
||||
unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware = Сховище не підтримується. Воно було створене в старішій версії Cryptomator.
|
||||
unlock.errorMessage.unsupportedVersion.softwareOlderThanVault = Сховище не підтримується. Воно було створене в новішій версії Cryptomator.
|
||||
unlock.messageLabel.startServerFailed = Помилка запуску сервера WebDAV.
|
||||
# change_password.fxml
|
||||
changePassword.label.oldPassword = Старий пароль
|
||||
changePassword.label.newPassword = Новий пароль
|
||||
changePassword.label.retypePassword = Повторіть пароль
|
||||
changePassword.label.downloadsPageLink = Всі версії Cryptomator
|
||||
changePassword.button.change = Змінити пароль
|
||||
changePassword.errorMessage.wrongPassword = Пароль невірний
|
||||
changePassword.errorMessage.decryptionFailed = Розшифрування невдале
|
||||
changePassword.infoMessage.success = Пароль змінений
|
||||
# unlocked.fxml
|
||||
unlocked.button.lock = Заблокувати сховище
|
||||
unlocked.moreOptions.reveal = Відкрити накопичувач
|
||||
unlocked.moreOptions.copyUrl = Копіювати URL-адресу WebDAV
|
||||
unlocked.label.revealFailed = Команда невдала
|
||||
unlocked.label.unmountFailed = Вилучення диска невдале
|
||||
unlocked.label.statsEncrypted = зашифровано
|
||||
unlocked.label.statsDecrypted = розшифровано
|
||||
unlocked.ioGraph.yAxis.label = Пропускна спроможність (МіБ/с)
|
||||
# mac_warnings.fxml
|
||||
macWarnings.windowTitle = Небезпека - Пошкоджений файл в %s
|
||||
macWarnings.message = Cryptomator виявив потенційно небезпечні пошкодження в наступних файлах\:
|
||||
macWarnings.moreInformationButton = Докладніше
|
||||
macWarnings.whitelistButton = Розшифрувати обрані все одно
|
||||
# settings.fxml
|
||||
settings.version.label = Версія %s
|
||||
settings.checkForUpdates.label = Перевірити оновлення
|
||||
settings.port.label = Порт WebDAV *
|
||||
settings.port.prompt = 0 \= Обрати автоматично
|
||||
settings.useipv6.label = Використовувати IPv6
|
||||
settings.requiresRestartLabel = * Необхідне перезавантаження Cryptomator
|
||||
# tray icon
|
||||
tray.menu.open = Відкрити
|
||||
tray.menu.quit = Вихід
|
||||
tray.infoMsg.title = Ще працює
|
||||
tray.infoMsg.msg = Cryptomator все ще працює. Вийдіть за допомогою значка в області сповіщень.
|
||||
tray.infoMsg.msg.osx = Cryptomator все ще працює. Вийдіть за допомогою значка в рядку меню.
|
||||
initialize.messageLabel.passwordStrength.0 = Дуже слабкий
|
||||
initialize.messageLabel.passwordStrength.1 = Слабкий
|
||||
initialize.messageLabel.passwordStrength.2 = Прийнятний
|
||||
initialize.messageLabel.passwordStrength.3 = Сильний
|
||||
initialize.messageLabel.passwordStrength.4 = Дуже сильний
|
||||
initialize.label.doNotForget = ВАЖЛИВО\: Якщо ви забудете свій пароль, відновити дані буде неможливо.
|
||||
main.directoryList.remove.confirmation.title = Видалити сховище
|
||||
main.directoryList.remove.confirmation.header = Ви дійсно хочете видалити це сховище?
|
||||
main.directoryList.remove.confirmation.content = Сховище буде видалене тільки зі списку. Щоб стерти його остаточно, видаліть файли із файлової системи.
|
||||
upgrade.version3to4.msg = Це сховище необхідно перетворити в новий формат. Зашифровані імена папок будуть оновлені. Перш ніж продовжити, виконайте синхронізацію.
|
||||
upgrade.version3to4.err.io = Перетворення невдале через помилку введення-виведення. Дивіться деталі в файлі-звіті.
|
||||
settings.prefGvfsScheme.label = WebDAV scheme
|
||||
# upgrade.fxml
|
||||
upgrade.confirmation.label = Yes, I've made sure that synchronization has finished
|
||||
initialize.messageLabel.notEmpty = Vault not empty
|
||||
unlock.label.savePassword = Save password
|
||||
unlock.errorMessage.unauthenticVersionMac = Could not authenticate version MAC.
|
||||
@@ -10,7 +10,7 @@
|
||||
<Configuration status="WARN" packages="org.cryptomator.ui.logging">
|
||||
|
||||
<Appenders>
|
||||
<Console name="Console" target="SYSTEM_OUT">
|
||||
<Console name="StdOut" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="%16d %-5p [%c{1}:%L] %m%n" />
|
||||
<ThresholdFilter level="WARN" onMatch="DENY" onMismatch="ACCEPT" />
|
||||
</Console>
|
||||
@@ -18,21 +18,27 @@
|
||||
<PatternLayout pattern="%16d %-5p [%c{1}:%L] %m%n" />
|
||||
<ThresholdFilter level="WARN" onMatch="ACCEPT" onMismatch="DENY" />
|
||||
</Console>
|
||||
<!-- <File fileName="${sys:logPath}" ...> not feasible for paths like ~/foo/bar -->
|
||||
<ConfigurableFile name="File" pathPropertyName="cryptomator.logPath">
|
||||
<ConfigurableFile name="DefaultLog" pathPropertyName="cryptomator.logPath" append="false">
|
||||
<PatternLayout pattern="%16d %-5p [%c{1}:%L] %m%n" />
|
||||
</ConfigurableFile>
|
||||
<ConfigurableFile name="UpgradeLog" pathPropertyName="cryptomator.upgradeLogPath" append="true">
|
||||
<PatternLayout pattern="%16d %-5p [%c{1}:%L] %m%n" />
|
||||
</ConfigurableFile>
|
||||
</Appenders>
|
||||
|
||||
<Loggers>
|
||||
<!-- show our own debug messages: -->
|
||||
<!-- package-specific config: -->
|
||||
<Logger name="org.cryptomator" level="DEBUG" />
|
||||
<Logger name="org.eclipse.jetty.server.Server" level="DEBUG" />
|
||||
<!-- mute dependencies: -->
|
||||
<Logger name="org.cryptomator.ui.model" level="INFO">
|
||||
<AppenderRef ref="UpgradeLog" />
|
||||
</Logger>
|
||||
|
||||
<!-- defaults: -->
|
||||
<Root level="INFO">
|
||||
<AppenderRef ref="Console" />
|
||||
<AppenderRef ref="StdOut" />
|
||||
<AppenderRef ref="StdErr" />
|
||||
<AppenderRef ref="File" />
|
||||
<AppenderRef ref="DefaultLog" />
|
||||
</Root>
|
||||
</Loggers>
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 369 B After Width: | Height: | Size: 350 B |
|
Before Width: | Height: | Size: 783 B After Width: | Height: | Size: 692 B |
|
Before Width: | Height: | Size: 362 B After Width: | Height: | Size: 359 B |
|
Before Width: | Height: | Size: 792 B After Width: | Height: | Size: 707 B |
@@ -31,7 +31,7 @@ public class LocalizationTest {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(LocalizationTest.class);
|
||||
private static final String RESOURCE_FOLDER_PATH = "/localization/";
|
||||
private static final String REF_FILE_NAME = "en.txt";
|
||||
private static final String[] LANG_FILE_NAMES = {"de.txt", "es.txt", "fr.txt", "hu.txt", "it.txt", "kr.txt", "nl.txt", "pt.txt", "ru.txt", "sk.txt", "tr.txt"};
|
||||
private static final String[] LANG_FILE_NAMES = {"de.txt", "es.txt", "fr.txt", "hu.txt", "it.txt", "kr.txt", "lv.txt", "nl.txt", "pl.txt", "pt.txt", "ru.txt", "sk.txt", "tr.txt", "uk.txt"};
|
||||
|
||||
/*
|
||||
* @see Formatter
|
||||
|
||||