mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-04-19 17:16:53 -04:00
Improved migration from vault version 3 to 4.
This commit is contained in:
@@ -161,7 +161,7 @@ public class WelcomeController extends LocalizedFXMLViewController {
|
||||
|
||||
@FXML
|
||||
public void didClickUpdateLink(ActionEvent event) {
|
||||
app.getHostServices().showDocument("https://cryptomator.org/#download");
|
||||
app.getHostServices().showDocument("https://cryptomator.org/");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
package org.cryptomator.ui.model;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.FileVisitor;
|
||||
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;
|
||||
|
||||
@@ -14,22 +17,40 @@ 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.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 UpgradeVersion3to4 extends UpgradeStrategy {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(UpgradeVersion3to4.class);
|
||||
private static final Pattern BASE32_FOLLOWED_BY_UNDERSCORE_PATTERN = Pattern.compile("^(([A-Z2-7]{8})*[A-Z2-7=]{8})_");
|
||||
private static final int FILE_MIN_SIZE = 88; // vault version 3 files have a header of 88 bytes (assuming no chunks at all)
|
||||
private static final String LONG_FILENAME_SUFFIX = ".lng";
|
||||
private static final String OLD_FOLDER_SUFFIX = "_";
|
||||
private static final String NEW_FOLDER_PREFIX = "0";
|
||||
|
||||
private final MessageDigest sha1;
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -40,6 +61,7 @@ class UpgradeVersion3to4 extends UpgradeStrategy {
|
||||
@Override
|
||||
protected void upgrade(Vault vault, Cryptor cryptor) throws UpgradeFailedException {
|
||||
Path dataDir = vault.path().get().resolve("d");
|
||||
Path metadataDir = vault.path().get().resolve("m");
|
||||
if (!Files.isDirectory(dataDir)) {
|
||||
return; // empty vault. no migration needed.
|
||||
}
|
||||
@@ -53,7 +75,12 @@ class UpgradeVersion3to4 extends UpgradeStrategy {
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
migrate(file, attrs);
|
||||
String name = file.getFileName().toString();
|
||||
if (name.endsWith(LONG_FILENAME_SUFFIX)) {
|
||||
migrateLong(metadataDir, file);
|
||||
} else {
|
||||
migrate(file, attrs);
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@@ -82,7 +109,7 @@ class UpgradeVersion3to4 extends UpgradeStrategy {
|
||||
if (m.find(0) && size < FILE_MIN_SIZE) {
|
||||
String base32 = m.group(1);
|
||||
String suffix = name.substring(m.end());
|
||||
String renamed = "0" + base32 + (suffix.isEmpty() ? "" : " " + suffix);
|
||||
String renamed = NEW_FOLDER_PREFIX + base32 + (suffix.isEmpty() ? "" : " " + suffix);
|
||||
renameWithoutOverwriting(file, renamed);
|
||||
}
|
||||
}
|
||||
@@ -96,12 +123,33 @@ class UpgradeVersion3to4 extends UpgradeStrategy {
|
||||
LOG.info("Renaming {} to {}", path, newPath.getFileName());
|
||||
}
|
||||
|
||||
private void migrateLong(Path metadataDir, Path path) throws IOException {
|
||||
String oldName = path.getFileName().toString();
|
||||
Path oldMetadataFile = metadataDir.resolve(oldName.substring(0, 2)).resolve(oldName.substring(2, 4)).resolve(oldName);
|
||||
if (Files.isRegularFile(oldMetadataFile)) {
|
||||
String oldContent = new String(Files.readAllBytes(oldMetadataFile), UTF_8);
|
||||
if (oldContent.endsWith(OLD_FOLDER_SUFFIX)) {
|
||||
String newContent = NEW_FOLDER_PREFIX + StringUtils.removeEnd(oldContent, OLD_FOLDER_SUFFIX);
|
||||
String newName = base32.encodeAsString(sha1.digest(newContent.getBytes(UTF_8))) + LONG_FILENAME_SUFFIX;
|
||||
Path newPath = path.resolveSibling(newName);
|
||||
Path newMetadataFile = metadataDir.resolve(newName.substring(0, 2)).resolve(newName.substring(2, 4)).resolve(newName);
|
||||
Files.move(path, newPath);
|
||||
Files.createDirectories(newMetadataFile.getParent());
|
||||
Files.write(newMetadataFile, newContent.getBytes(UTF_8));
|
||||
Files.delete(oldMetadataFile);
|
||||
LOG.info("Renaming {} to {}\nDeleting {}\nCreating {}", path, newName, oldMetadataFile, newMetadataFile);
|
||||
}
|
||||
} else {
|
||||
LOG.warn("Found uninflatable long file name. Expected: {}", oldMetadataFile);
|
||||
}
|
||||
}
|
||||
|
||||
@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), StandardCharsets.UTF_8);
|
||||
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);
|
||||
|
||||
@@ -20,18 +20,18 @@
|
||||
|
||||
<VBox prefWidth="400.0" prefHeight="400.0" spacing="24.0" alignment="CENTER" xmlns:fx="http://javafx.com/fxml" cacheShape="true" cache="true">
|
||||
|
||||
<VBox fx:id="checkForUpdatesContainer" spacing="6.0" alignment="CENTER" cacheShape="true" cache="true" prefHeight="50.0">
|
||||
<VBox fx:id="checkForUpdatesContainer" spacing="6.0" alignment="CENTER" cacheShape="true" cache="true" prefHeight="64.0">
|
||||
<HBox alignment="CENTER" spacing="5.0" cacheShape="true" cache="true">
|
||||
<Label fx:id="checkForUpdatesStatus" cacheShape="true" cache="true" />
|
||||
<ProgressIndicator fx:id="checkForUpdatesIndicator" progress="-1" prefWidth="15.0" prefHeight="15.0" cacheShape="true" cache="true" cacheHint="SPEED" />
|
||||
</HBox>
|
||||
<Hyperlink alignment="CENTER" fx:id="updateLink" onAction="#didClickUpdateLink" cacheShape="true" cache="true" disable="true" />
|
||||
<Hyperlink wrapText="true" textAlignment="CENTER" fx:id="updateLink" onAction="#didClickUpdateLink" cacheShape="true" cache="true" disable="true" />
|
||||
</VBox>
|
||||
|
||||
<ImageView fitHeight="200.0" preserveRatio="true" smooth="false" cache="true" style="-fx-background-color: green;">
|
||||
<ImageView fitHeight="200.0" preserveRatio="true" smooth="true" cache="true" style="-fx-background-color: green;">
|
||||
<Image url="/bot_welcome.png"/>
|
||||
</ImageView>
|
||||
|
||||
<VBox prefHeight="50.0"/>
|
||||
<VBox prefHeight="64.0"/>
|
||||
|
||||
</VBox>
|
||||
@@ -7,7 +7,7 @@ main.addDirectory.contextMenu.new = Tresor erstellen
|
||||
main.addDirectory.contextMenu.open = Tresor öffnen
|
||||
# welcome.fxml
|
||||
welcome.checkForUpdates.label.currentlyChecking = Prüfe auf Updates...
|
||||
welcome.newVersionMessage = Version %1$s kann heruntergeladen werden. Momentane Version %2$s.
|
||||
welcome.newVersionMessage = Version %1$s kann heruntergeladen werden.\nMomentane Version %2$s.
|
||||
# initialize.fxml
|
||||
initialize.label.password = Passwort
|
||||
initialize.label.retypePassword = Passwort bestätigen
|
||||
|
||||
@@ -19,7 +19,7 @@ main.directoryList.remove.confirmation.content=The vault will only be removed fr
|
||||
|
||||
# welcome.fxml
|
||||
welcome.checkForUpdates.label.currentlyChecking=Checking for Updates...
|
||||
welcome.newVersionMessage=Version %1$s can be downloaded. This is %2$s.
|
||||
welcome.newVersionMessage=Version %1$s can be downloaded.\nThis is %2$s.
|
||||
|
||||
# initialize.fxml
|
||||
initialize.label.password=Password
|
||||
|
||||
@@ -8,7 +8,7 @@ main.addDirectory.contextMenu.new = Crear una nueva caja fuerte
|
||||
main.addDirectory.contextMenu.open = Abrir una caja fuerte existente
|
||||
# welcome.fxml
|
||||
welcome.checkForUpdates.label.currentlyChecking = Chequando por actualizaciónes...
|
||||
welcome.newVersionMessage = Se puede bajar version %1$s. Este es %2$s.
|
||||
welcome.newVersionMessage = Se puede bajar version %1$s.\nEste es %2$s.
|
||||
# initialize.fxml
|
||||
initialize.label.password = Contraseña
|
||||
initialize.label.retypePassword = Reintroduzca contraseña
|
||||
|
||||
@@ -7,7 +7,7 @@ main.addDirectory.contextMenu.new = Créer un nouveau coffre
|
||||
main.addDirectory.contextMenu.open = Ouvrir un coffre existant
|
||||
# welcome.fxml
|
||||
welcome.checkForUpdates.label.currentlyChecking = Recherche de mise à jour...
|
||||
welcome.newVersionMessage = La version %1$s peut-être téléchargée. Il s'agit de %2$s.
|
||||
welcome.newVersionMessage = La version %1$s peut-être téléchargée.\nIl s'agit de %2$s.
|
||||
# initialize.fxml
|
||||
initialize.label.password = Mot de passe
|
||||
initialize.label.retypePassword = Confirmation
|
||||
|
||||
@@ -7,7 +7,7 @@ main.addDirectory.contextMenu.new = Új széf létrehozása
|
||||
main.addDirectory.contextMenu.open = Létező széf megnyitása
|
||||
# welcome.fxml
|
||||
welcome.checkForUpdates.label.currentlyChecking = Frissítések keresése...
|
||||
welcome.newVersionMessage = Új verzió érhető el\: %1$s. Jelenlegi verzió\: %2$s.
|
||||
welcome.newVersionMessage = Új verzió érhető el\: %1$s.\nJelenlegi verzió\: %2$s.
|
||||
# initialize.fxml
|
||||
initialize.label.password = Jelszó
|
||||
initialize.label.retypePassword = Jelszó ismét
|
||||
|
||||
@@ -7,7 +7,7 @@ main.addDirectory.contextMenu.new = Crea un nuovo vault
|
||||
main.addDirectory.contextMenu.open = Apri un vault
|
||||
# welcome.fxml
|
||||
welcome.checkForUpdates.label.currentlyChecking = Verifica aggiornamenti...
|
||||
welcome.newVersionMessage = La versione %1$s può essere scaricata. Questa è %2$s
|
||||
welcome.newVersionMessage = La versione %1$s può essere scaricata.\nQuesta è %2$s
|
||||
# initialize.fxml
|
||||
initialize.label.password = Password
|
||||
initialize.label.retypePassword = Conferma password
|
||||
|
||||
@@ -7,7 +7,7 @@ main.addDirectory.contextMenu.new = 새 보관함 만들기
|
||||
main.addDirectory.contextMenu.open = 기존 보관함 열기
|
||||
# welcome.fxml
|
||||
welcome.checkForUpdates.label.currentlyChecking = 업데이트 확인 중...
|
||||
welcome.newVersionMessage = %1$s 버전이 새로 다운로드 가능합니다. 지금 버전은 %2$s 입니다.
|
||||
welcome.newVersionMessage = %1$s 버전이 새로 다운로드 가능합니다.\n지금 버전은 %2$s 입니다.
|
||||
# initialize.fxml
|
||||
initialize.label.password = 비밀번호
|
||||
initialize.label.retypePassword = 비밀번호 재입력
|
||||
|
||||
@@ -7,7 +7,7 @@ main.addDirectory.contextMenu.new = Creeer nieuwe kluis
|
||||
main.addDirectory.contextMenu.open = Open bestaande kluis
|
||||
# welcome.fxml
|
||||
welcome.checkForUpdates.label.currentlyChecking = Controleren op Updates...
|
||||
welcome.newVersionMessage = Versie %1$s kan worden gedownload. Dit is %2$s.
|
||||
welcome.newVersionMessage = Versie %1$s kan worden gedownload.\nDit is %2$s.
|
||||
# initialize.fxml
|
||||
initialize.label.password = Wachtwoord
|
||||
initialize.label.retypePassword = Voer wachtwoord opnieuw in
|
||||
|
||||
@@ -8,7 +8,7 @@ main.addDirectory.contextMenu.open = Открыть имеющееся хран
|
||||
# welcome.fxml
|
||||
welcome.checkForUpdates.label.currentlyChecking = Проверка обновлений...
|
||||
# Does the first %s mean the new version number, and the second %s - the current version user has?
|
||||
welcome.newVersionMessage = Доступна версия %1$s. У вас версия %2$s.
|
||||
welcome.newVersionMessage = Доступна версия %1$s.\nУ вас версия %2$s.
|
||||
# initialize.fxml
|
||||
initialize.label.password = Пароль
|
||||
initialize.label.retypePassword = Введите пароль ещё раз
|
||||
|
||||
@@ -10,7 +10,7 @@ main.addDirectory.contextMenu.new = Vytvoriť nový trezor
|
||||
main.addDirectory.contextMenu.open = Otvoriť existujúci trezor
|
||||
# welcome.fxml
|
||||
welcome.checkForUpdates.label.currentlyChecking = Kontrolujú sa aktualizácie...
|
||||
welcome.newVersionMessage = Verzia %1$s je pripravená na stiahnutie. Toto je verzia %2$s.
|
||||
welcome.newVersionMessage = Verzia %1$s je pripravená na stiahnutie.\nToto je verzia %2$s.
|
||||
# initialize.fxml
|
||||
initialize.label.password = Heslo
|
||||
initialize.label.retypePassword = Zadajte heslo znova
|
||||
|
||||
@@ -7,7 +7,7 @@ main.addDirectory.contextMenu.new = Yeni bir kasa yarat
|
||||
main.addDirectory.contextMenu.open = Var olan kasayı aç
|
||||
# welcome.fxml
|
||||
welcome.checkForUpdates.label.currentlyChecking = Güncellemeler kontrol ediliyor...
|
||||
welcome.newVersionMessage = Sürüm %1$s indirilebilir. Şu anki sürüm\: %2$s
|
||||
welcome.newVersionMessage = Sürüm %1$s indirilebilir.\nŞu anki sürüm\: %2$s
|
||||
# initialize.fxml
|
||||
initialize.label.password = Şifre
|
||||
initialize.label.retypePassword = Şifre (tekrar)
|
||||
|
||||
Reference in New Issue
Block a user