mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 19:29:06 +01:00
Encrypt logs on disk, store encryption key in DB.
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
package org.briarproject.briar.logging;
|
||||
|
||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.briar.api.logging.PersistentLogManager;
|
||||
|
||||
import java.util.logging.Formatter;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
|
||||
@@ -16,8 +19,11 @@ public class LoggingModule {
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
PersistentLogManager providePersistentLogManager(
|
||||
PersistentLogManagerImpl logManager) {
|
||||
return logManager;
|
||||
LifecycleManager lifecycleManager,
|
||||
PersistentLogManagerImpl persistentLogManager) {
|
||||
lifecycleManager.registerOpenDatabaseHook(persistentLogManager);
|
||||
return persistentLogManager;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,26 @@
|
||||
package org.briarproject.briar.logging;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
import org.briarproject.bramble.api.lifecycle.IoExecutor;
|
||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager.OpenDatabaseHook;
|
||||
import org.briarproject.bramble.api.lifecycle.ShutdownManager;
|
||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||
import org.briarproject.bramble.api.settings.Settings;
|
||||
import org.briarproject.bramble.api.system.Scheduler;
|
||||
import org.briarproject.bramble.api.transport.StreamReaderFactory;
|
||||
import org.briarproject.bramble.api.transport.StreamWriter;
|
||||
import org.briarproject.bramble.api.transport.StreamWriterFactory;
|
||||
import org.briarproject.briar.api.logging.PersistentLogManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -21,16 +33,20 @@ import java.util.logging.Handler;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.logging.StreamHandler;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||
|
||||
@ThreadSafe
|
||||
@NotNullByDefault
|
||||
class PersistentLogManagerImpl implements PersistentLogManager {
|
||||
class PersistentLogManagerImpl implements PersistentLogManager,
|
||||
OpenDatabaseHook {
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(PersistentLogManagerImpl.class.getName());
|
||||
@@ -42,16 +58,47 @@ class PersistentLogManagerImpl implements PersistentLogManager {
|
||||
private final ScheduledExecutorService scheduler;
|
||||
private final Executor ioExecutor;
|
||||
private final ShutdownManager shutdownManager;
|
||||
private final DatabaseComponent db;
|
||||
private final StreamReaderFactory streamReaderFactory;
|
||||
private final StreamWriterFactory streamWriterFactory;
|
||||
private final Formatter formatter;
|
||||
private final SecretKey logKey;
|
||||
|
||||
@Nullable
|
||||
private volatile SecretKey oldLogKey = null;
|
||||
|
||||
@Inject
|
||||
PersistentLogManagerImpl(@Scheduler ScheduledExecutorService scheduler,
|
||||
@IoExecutor Executor ioExecutor, ShutdownManager shutdownManager,
|
||||
Formatter formatter) {
|
||||
PersistentLogManagerImpl(
|
||||
@Scheduler ScheduledExecutorService scheduler,
|
||||
@IoExecutor Executor ioExecutor,
|
||||
ShutdownManager shutdownManager,
|
||||
DatabaseComponent db,
|
||||
StreamReaderFactory streamReaderFactory,
|
||||
StreamWriterFactory streamWriterFactory,
|
||||
Formatter formatter,
|
||||
CryptoComponent crypto) {
|
||||
this.scheduler = scheduler;
|
||||
this.ioExecutor = ioExecutor;
|
||||
this.shutdownManager = shutdownManager;
|
||||
this.db = db;
|
||||
this.streamReaderFactory = streamReaderFactory;
|
||||
this.streamWriterFactory = streamWriterFactory;
|
||||
this.formatter = formatter;
|
||||
logKey = crypto.generateSecretKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDatabaseOpened(Transaction txn) throws DbException {
|
||||
Settings s = db.getSettings(txn, LOG_SETTINGS_NAMESPACE);
|
||||
// Load the old log key, if any
|
||||
byte[] oldKeyBytes = s.getBytes(LOG_KEY_KEY);
|
||||
if (oldKeyBytes != null && oldKeyBytes.length == SecretKey.LENGTH) {
|
||||
LOG.info("Loaded old log key");
|
||||
oldLogKey = new SecretKey(oldKeyBytes);
|
||||
}
|
||||
// Store the current log key
|
||||
s.putBytes(LOG_KEY_KEY, logKey.getBytes());
|
||||
db.mergeSettings(txn, s, LOG_SETTINGS_NAMESPACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -64,11 +111,24 @@ class PersistentLogManagerImpl implements PersistentLogManager {
|
||||
LOG.warning("Failed to rename log file");
|
||||
try {
|
||||
OutputStream out = new FileOutputStream(logFile);
|
||||
StreamHandler handler = new StreamHandler(out, formatter);
|
||||
StreamWriter writer =
|
||||
streamWriterFactory.createLogStreamWriter(out, logKey);
|
||||
StreamHandler handler =
|
||||
new StreamHandler(writer.getOutputStream(), formatter);
|
||||
// Flush the log periodically in case we're killed without getting
|
||||
// the chance to run shutdown hooks
|
||||
scheduler.scheduleWithFixedDelay(() ->
|
||||
ioExecutor.execute(handler::flush),
|
||||
FLUSH_INTERVAL_MS, FLUSH_INTERVAL_MS, MILLISECONDS);
|
||||
shutdownManager.addShutdownHook(handler::flush);
|
||||
// Flush the log and terminate the stream at shutdown
|
||||
shutdownManager.addShutdownHook(() -> {
|
||||
handler.flush();
|
||||
try {
|
||||
writer.sendEndOfStream();
|
||||
} catch (IOException e) {
|
||||
logException(LOG, WARNING, e);
|
||||
}
|
||||
});
|
||||
return handler;
|
||||
} catch (SecurityException e) {
|
||||
throw new IOException(e);
|
||||
@@ -77,14 +137,23 @@ class PersistentLogManagerImpl implements PersistentLogManager {
|
||||
|
||||
@Override
|
||||
public Collection<String> getPersistedLog(File dir) throws IOException {
|
||||
SecretKey oldLogKey = this.oldLogKey;
|
||||
if (oldLogKey == null) {
|
||||
LOG.info("Old log key has not been loaded");
|
||||
return emptyList();
|
||||
}
|
||||
File oldLogFile = new File(dir, OLD_LOG_FILE);
|
||||
if (oldLogFile.exists()) {
|
||||
LOG.info("Reading old log file");
|
||||
List<String> lines = new ArrayList<>();
|
||||
Scanner s = new Scanner(oldLogFile);
|
||||
while (s.hasNextLine()) lines.add(s.nextLine());
|
||||
s.close();
|
||||
return lines;
|
||||
try (InputStream in = new FileInputStream(oldLogFile)) {
|
||||
InputStream reader = streamReaderFactory
|
||||
.createLogStreamReader(in, oldLogKey);
|
||||
Scanner s = new Scanner(reader);
|
||||
while (s.hasNextLine()) lines.add(s.nextLine());
|
||||
s.close();
|
||||
return lines;
|
||||
}
|
||||
} else {
|
||||
LOG.info("Old log file does not exist");
|
||||
return emptyList();
|
||||
|
||||
Reference in New Issue
Block a user