diff --git a/common/src/main/java/haveno/common/app/Log.java b/common/src/main/java/haveno/common/app/Log.java index 67ca2ab9ed..0daf80d439 100644 --- a/common/src/main/java/haveno/common/app/Log.java +++ b/common/src/main/java/haveno/common/app/Log.java @@ -23,6 +23,7 @@ import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.encoder.PatternLayoutEncoder; import ch.qos.logback.classic.filter.ThresholdFilter; import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.FileAppender; import ch.qos.logback.core.rolling.FixedWindowRollingPolicy; import ch.qos.logback.core.rolling.RollingFileAppender; import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy; @@ -108,4 +109,20 @@ public class Log { public static void setCustomLogLevel(String pattern, Level logLevel) { ((Logger) LoggerFactory.getLogger(pattern)).setLevel(logLevel); } + + public static void stop() { + var context = logbackLogger.getLoggerContext(); + + for (Logger logger : context.getLoggerList()) { + + var iteratorForAppenders = logger.iteratorForAppenders(); + while (iteratorForAppenders.hasNext()) { + var appender = iteratorForAppenders.next(); + if (appender instanceof FileAppender) { + appender.stop(); + System.out.println("Released: " + ((FileAppender) appender).getFile()); + } + } + } + } } diff --git a/common/src/main/java/haveno/common/crypto/KeyStorage.java b/common/src/main/java/haveno/common/crypto/KeyStorage.java index 5edfb89575..ce40ce1309 100644 --- a/common/src/main/java/haveno/common/crypto/KeyStorage.java +++ b/common/src/main/java/haveno/common/crypto/KeyStorage.java @@ -28,6 +28,8 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.math.BigInteger; +import java.nio.file.Files; +import java.nio.file.Path; import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; @@ -171,7 +173,11 @@ public class KeyStorage { char[] passwordChars = password == null ? new char[0] : password.toCharArray(); try { KeyStore keyStore = KeyStore.getInstance("PKCS12"); - keyStore.load(new FileInputStream(storageDir + "/" + keyEntry.getFileName()), passwordChars); + + try (FileInputStream fileInputStream = new FileInputStream(storageDir + "/" + keyEntry.getFileName())) { + keyStore.load(fileInputStream, passwordChars); + } + Key key = keyStore.getKey(keyEntry.getAlias(), passwordChars); return (SecretKey) key; } catch (UnrecoverableKeyException e) { // null password when password is required @@ -255,17 +261,22 @@ public class KeyStorage { KeyStore keyStore = KeyStore.getInstance("PKCS12"); // load from existing file or initialize new - try { - keyStore.load(new FileInputStream(path), oldPasswordChars); - } catch (Exception e) { + if (Files.exists(Path.of(path))) { + try (FileInputStream fileInputStream = new FileInputStream(path)) { + keyStore.load(fileInputStream, oldPasswordChars); + } + } + else { keyStore.load(null, null); } // store in the keystore keyStore.setKeyEntry(alias, key, passwordChars, null); - // save the keystore - keyStore.store(new FileOutputStream(path), passwordChars); + try (FileOutputStream fileOutputStream = new FileOutputStream(path)) { + // save the keystore + keyStore.store(fileOutputStream, passwordChars); + } } catch (Exception e) { throw new RuntimeException("Could not save key " + alias, e); } diff --git a/core/src/main/java/haveno/core/api/CoreAccountService.java b/core/src/main/java/haveno/core/api/CoreAccountService.java index 2190e0c4f1..a4a9f1e491 100644 --- a/core/src/main/java/haveno/core/api/CoreAccountService.java +++ b/core/src/main/java/haveno/core/api/CoreAccountService.java @@ -18,8 +18,10 @@ package haveno.core.api; import static com.google.common.base.Preconditions.checkState; +import ch.qos.logback.classic.Level; import com.google.inject.Inject; import com.google.inject.Singleton; +import haveno.common.app.Log; import haveno.common.config.Config; import haveno.common.crypto.IncorrectPasswordException; import haveno.common.crypto.KeyRing; @@ -32,6 +34,7 @@ import java.io.File; import java.io.InputStream; import java.io.PipedInputStream; import java.io.PipedOutputStream; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -145,6 +148,8 @@ public class CoreAccountService { public void backupAccount(int bufferSize, Consumer consume, Consumer error) { if (!accountExists()) throw new IllegalStateException("Cannot backup non existing account"); + var accountWasOpen = isAccountOpen(); + // flush all known persistence objects to disk PersistenceManager.flushAllDataToDiskAtBackup(() -> { try { @@ -159,6 +164,9 @@ public class CoreAccountService { new File(XmrLocalNode.MONEROD_PATH) ); + if (accountWasOpen) + closeAccount(); + new Thread(() -> { try { ZipUtils.zipDirToStream(dataDir, out, bufferSize, excludedFiles); @@ -170,6 +178,13 @@ public class CoreAccountService { } catch (java.io.IOException err) { error.accept(err); } + + try { + if (accountWasOpen) + openAccount(password); + } catch (Exception ex){ + throw new RuntimeException(ex); + } }); } @@ -188,8 +203,17 @@ public class CoreAccountService { synchronized (listeners) { for (AccountServiceListener listener : new ArrayList<>(listeners)) listener.onAccountDeleted(onShutdown); } - File dataDir = new File(config.appDataDir.getPath()); // TODO (woodser): deleting directory after gracefulShutdown() so services don't throw when they try to persist (e.g. XmrTxProofService), but gracefulShutdown() should honor read-only shutdown - FileUtil.deleteDirectory(dataDir, null, false); + + Log.stop(); + + try { + File dataDir = new File(config.appDataDir.getPath()); // TODO (woodser): deleting directory after gracefulShutdown() so services don't throw when they try to persist (e.g. XmrTxProofService), but gracefulShutdown() should honor read-only shutdown + FileUtil.deleteDirectory(dataDir, null, false); + } + finally { + Log.setup(Paths.get(config.appDataDir.getPath(), "haveno").toString()); + Log.setLevel(Level.toLevel(config.logLevel)); + } } catch (Exception err) { throw new RuntimeException(err); }