mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 13:19:52 +01:00
Move encrypted key, account deletion into AccountManager.
This commit is contained in:
@@ -1,6 +1,22 @@
|
|||||||
package org.briarproject.bramble.api.account;
|
package org.briarproject.bramble.api.account;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
@NotNullByDefault
|
||||||
public interface AccountManager {
|
public interface AccountManager {
|
||||||
|
|
||||||
boolean hasDatabaseKey();
|
boolean hasDatabaseKey();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
SecretKey getDatabaseKey();
|
||||||
|
|
||||||
|
void setDatabaseKey(SecretKey k);
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
String getEncryptedDatabaseKey();
|
||||||
|
|
||||||
|
boolean storeEncryptedDatabaseKey(String hex);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.briarproject.bramble.api.db;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.contact.Contact;
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.identity.Author;
|
import org.briarproject.bramble.api.identity.Author;
|
||||||
import org.briarproject.bramble.api.identity.AuthorId;
|
import org.briarproject.bramble.api.identity.AuthorId;
|
||||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||||
@@ -44,7 +45,8 @@ public interface DatabaseComponent {
|
|||||||
* @throws DataTooOldException if the data uses an older schema than the
|
* @throws DataTooOldException if the data uses an older schema than the
|
||||||
* current code and cannot be migrated
|
* current code and cannot be migrated
|
||||||
*/
|
*/
|
||||||
boolean open(@Nullable MigrationListener listener) throws DbException;
|
boolean open(SecretKey key, @Nullable MigrationListener listener)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Waits for any open transactions to finish and closes the database.
|
* Waits for any open transactions to finish and closes the database.
|
||||||
@@ -267,7 +269,7 @@ public interface DatabaseComponent {
|
|||||||
* Read-only.
|
* Read-only.
|
||||||
*/
|
*/
|
||||||
Collection<MessageId> getMessageIds(Transaction txn, GroupId g)
|
Collection<MessageId> getMessageIds(Transaction txn, GroupId g)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the IDs of any messages that need to be validated.
|
* Returns the IDs of any messages that need to be validated.
|
||||||
@@ -487,7 +489,7 @@ public interface DatabaseComponent {
|
|||||||
* Removes the given transport keys from the database.
|
* Removes the given transport keys from the database.
|
||||||
*/
|
*/
|
||||||
void removeTransportKeys(Transaction txn, TransportId t, KeySetId k)
|
void removeTransportKeys(Transaction txn, TransportId t, KeySetId k)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks the given contact as verified.
|
* Marks the given contact as verified.
|
||||||
@@ -534,7 +536,7 @@ public interface DatabaseComponent {
|
|||||||
* Marks the given transport keys as usable for outgoing streams.
|
* Marks the given transport keys as usable for outgoing streams.
|
||||||
*/
|
*/
|
||||||
void setTransportKeysActive(Transaction txn, TransportId t, KeySetId k)
|
void setTransportKeysActive(Transaction txn, TransportId t, KeySetId k)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the given transport keys, deleting any keys they have replaced.
|
* Stores the given transport keys, deleting any keys they have replaced.
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
package org.briarproject.bramble.api.db;
|
package org.briarproject.bramble.api.db;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public interface DatabaseConfig {
|
public interface DatabaseConfig {
|
||||||
|
|
||||||
@@ -16,10 +13,5 @@ public interface DatabaseConfig {
|
|||||||
|
|
||||||
File getDatabaseKeyDirectory();
|
File getDatabaseKeyDirectory();
|
||||||
|
|
||||||
void setEncryptionKey(SecretKey key);
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
SecretKey getEncryptionKey();
|
|
||||||
|
|
||||||
long getMaxSize();
|
long getMaxSize();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,140 @@
|
|||||||
package org.briarproject.bramble.account;
|
package org.briarproject.bramble.account;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.account.AccountManager;
|
import org.briarproject.bramble.api.account.AccountManager;
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
|
||||||
|
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import static java.util.logging.Level.WARNING;
|
||||||
|
import static org.briarproject.bramble.util.LogUtils.logException;
|
||||||
|
|
||||||
|
@MethodsNotNullByDefault
|
||||||
|
@ParametersNotNullByDefault
|
||||||
class AccountManagerImpl implements AccountManager {
|
class AccountManagerImpl implements AccountManager {
|
||||||
|
|
||||||
|
private static final Logger LOG =
|
||||||
|
Logger.getLogger(AccountManagerImpl.class.getName());
|
||||||
|
|
||||||
|
private static final String DB_KEY_FILENAME = "db.key";
|
||||||
|
private static final String DB_KEY_BACKUP_FILENAME = "db.key.bak";
|
||||||
|
|
||||||
private final DatabaseConfig databaseConfig;
|
private final DatabaseConfig databaseConfig;
|
||||||
|
private final File dbKeyFile, dbKeyBackupFile;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private volatile SecretKey databaseKey = null;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
AccountManagerImpl(DatabaseConfig databaseConfig) {
|
AccountManagerImpl(DatabaseConfig databaseConfig) {
|
||||||
this.databaseConfig = databaseConfig;
|
this.databaseConfig = databaseConfig;
|
||||||
|
File keyDir = databaseConfig.getDatabaseKeyDirectory();
|
||||||
|
dbKeyFile = new File(keyDir, DB_KEY_FILENAME);
|
||||||
|
dbKeyBackupFile = new File(keyDir, DB_KEY_BACKUP_FILENAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasDatabaseKey() {
|
public boolean hasDatabaseKey() {
|
||||||
return databaseConfig.getEncryptionKey() != null;
|
return databaseKey != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public SecretKey getDatabaseKey() {
|
||||||
|
return databaseKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDatabaseKey(SecretKey k) {
|
||||||
|
databaseKey = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public String getEncryptedDatabaseKey() {
|
||||||
|
String key = readDbKeyFromFile(dbKeyFile);
|
||||||
|
if (key == null) {
|
||||||
|
LOG.info("No database key in primary file");
|
||||||
|
key = readDbKeyFromFile(dbKeyBackupFile);
|
||||||
|
if (key == null) LOG.info("No database key in backup file");
|
||||||
|
else LOG.warning("Found database key in backup file");
|
||||||
|
} else {
|
||||||
|
LOG.info("Found database key in primary file");
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private String readDbKeyFromFile(File f) {
|
||||||
|
if (!f.exists()) {
|
||||||
|
LOG.info("Key file does not exist");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||||
|
new FileInputStream(f), "UTF-8"));
|
||||||
|
String key = reader.readLine();
|
||||||
|
reader.close();
|
||||||
|
return key;
|
||||||
|
} catch (IOException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean storeEncryptedDatabaseKey(String hex) {
|
||||||
|
LOG.info("Storing database key in file");
|
||||||
|
// Create the directory if necessary
|
||||||
|
if (databaseConfig.getDatabaseKeyDirectory().mkdirs())
|
||||||
|
LOG.info("Created database key directory");
|
||||||
|
// If only the backup file exists, rename it so we don't overwrite it
|
||||||
|
if (dbKeyBackupFile.exists() && !dbKeyFile.exists()) {
|
||||||
|
if (dbKeyBackupFile.renameTo(dbKeyFile))
|
||||||
|
LOG.info("Renamed old backup");
|
||||||
|
else LOG.warning("Failed to rename old backup");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// Write to the backup file
|
||||||
|
writeDbKeyToFile(hex, dbKeyBackupFile);
|
||||||
|
LOG.info("Stored database key in backup file");
|
||||||
|
// Delete the old primary file, if it exists
|
||||||
|
if (dbKeyFile.exists()) {
|
||||||
|
if (dbKeyFile.delete()) LOG.info("Deleted primary file");
|
||||||
|
else LOG.warning("Failed to delete primary file");
|
||||||
|
}
|
||||||
|
// The backup file becomes the new primary
|
||||||
|
if (dbKeyBackupFile.renameTo(dbKeyFile)) {
|
||||||
|
LOG.info("Renamed backup file to primary");
|
||||||
|
} else {
|
||||||
|
LOG.warning("Failed to rename backup file to primary");
|
||||||
|
return false; // Don't overwrite our only copy
|
||||||
|
}
|
||||||
|
// Write a second copy to the backup file
|
||||||
|
writeDbKeyToFile(hex, dbKeyBackupFile);
|
||||||
|
LOG.info("Stored second copy of database key in backup file");
|
||||||
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
logException(LOG, WARNING, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeDbKeyToFile(String key, File f) throws IOException {
|
||||||
|
FileOutputStream out = new FileOutputStream(f);
|
||||||
|
out.write(key.getBytes("UTF-8"));
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package org.briarproject.bramble.db;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.contact.Contact;
|
import org.briarproject.bramble.api.contact.Contact;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DataTooNewException;
|
import org.briarproject.bramble.api.db.DataTooNewException;
|
||||||
import org.briarproject.bramble.api.db.DataTooOldException;
|
import org.briarproject.bramble.api.db.DataTooOldException;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
@@ -48,7 +49,8 @@ interface Database<T> {
|
|||||||
* @throws DataTooOldException if the data uses an older schema than the
|
* @throws DataTooOldException if the data uses an older schema than the
|
||||||
* current code and cannot be migrated
|
* current code and cannot be migrated
|
||||||
*/
|
*/
|
||||||
boolean open(@Nullable MigrationListener listener) throws DbException;
|
boolean open(SecretKey key, @Nullable MigrationListener listener)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prevents new transactions from starting, waits for all current
|
* Prevents new transactions from starting, waits for all current
|
||||||
@@ -641,7 +643,7 @@ interface Database<T> {
|
|||||||
* Marks the given transport keys as usable for outgoing streams.
|
* Marks the given transport keys as usable for outgoing streams.
|
||||||
*/
|
*/
|
||||||
void setTransportKeysActive(T txn, TransportId t, KeySetId k)
|
void setTransportKeysActive(T txn, TransportId t, KeySetId k)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the transmission count and expiry time of the given message
|
* Updates the transmission count and expiry time of the given message
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import org.briarproject.bramble.api.contact.event.ContactAddedEvent;
|
|||||||
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
||||||
import org.briarproject.bramble.api.contact.event.ContactStatusChangedEvent;
|
import org.briarproject.bramble.api.contact.event.ContactStatusChangedEvent;
|
||||||
import org.briarproject.bramble.api.contact.event.ContactVerifiedEvent;
|
import org.briarproject.bramble.api.contact.event.ContactVerifiedEvent;
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.ContactExistsException;
|
import org.briarproject.bramble.api.db.ContactExistsException;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
import org.briarproject.bramble.api.db.DbException;
|
import org.briarproject.bramble.api.db.DbException;
|
||||||
@@ -103,9 +104,9 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean open(@Nullable MigrationListener listener)
|
public boolean open(SecretKey key, @Nullable MigrationListener listener)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
boolean reopened = db.open(listener);
|
boolean reopened = db.open(key, listener);
|
||||||
shutdown.addShutdownHook(() -> {
|
shutdown.addShutdownHook(() -> {
|
||||||
try {
|
try {
|
||||||
close();
|
close();
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ class H2Database extends JdbcDatabase {
|
|||||||
private final DatabaseConfig config;
|
private final DatabaseConfig config;
|
||||||
private final String url;
|
private final String url;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private volatile SecretKey key = null;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
H2Database(DatabaseConfig config, Clock clock) {
|
H2Database(DatabaseConfig config, Clock clock) {
|
||||||
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
|
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
|
||||||
@@ -44,11 +47,12 @@ class H2Database extends JdbcDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean open(@Nullable MigrationListener listener)
|
public boolean open(SecretKey key, @Nullable MigrationListener listener)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
|
this.key = key;
|
||||||
boolean reopen = config.databaseExists();
|
boolean reopen = config.databaseExists();
|
||||||
if (!reopen) config.getDatabaseDirectory().mkdirs();
|
if (!reopen) config.getDatabaseDirectory().mkdirs();
|
||||||
super.open("org.h2.Driver", reopen, listener);
|
super.open("org.h2.Driver", reopen, key, listener);
|
||||||
return reopen;
|
return reopen;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +67,7 @@ class H2Database extends JdbcDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getFreeSpace() throws DbException {
|
public long getFreeSpace() {
|
||||||
File dir = config.getDatabaseDirectory();
|
File dir = config.getDatabaseDirectory();
|
||||||
long maxSize = config.getMaxSize();
|
long maxSize = config.getMaxSize();
|
||||||
long free = dir.getFreeSpace();
|
long free = dir.getFreeSpace();
|
||||||
@@ -88,7 +92,7 @@ class H2Database extends JdbcDatabase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Connection createConnection() throws SQLException {
|
protected Connection createConnection() throws SQLException {
|
||||||
SecretKey key = config.getEncryptionKey();
|
SecretKey key = this.key;
|
||||||
if (key == null) throw new IllegalStateException();
|
if (key == null) throw new IllegalStateException();
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
props.setProperty("user", "user");
|
props.setProperty("user", "user");
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ class HyperSqlDatabase extends JdbcDatabase {
|
|||||||
private final DatabaseConfig config;
|
private final DatabaseConfig config;
|
||||||
private final String url;
|
private final String url;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private volatile SecretKey key = null;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
HyperSqlDatabase(DatabaseConfig config, Clock clock) {
|
HyperSqlDatabase(DatabaseConfig config, Clock clock) {
|
||||||
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
|
super(HASH_TYPE, SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE,
|
||||||
@@ -46,10 +49,12 @@ class HyperSqlDatabase extends JdbcDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean open(@Nullable MigrationListener listener) throws DbException {
|
public boolean open(SecretKey key, @Nullable MigrationListener listener)
|
||||||
|
throws DbException {
|
||||||
|
this.key = key;
|
||||||
boolean reopen = config.databaseExists();
|
boolean reopen = config.databaseExists();
|
||||||
if (!reopen) config.getDatabaseDirectory().mkdirs();
|
if (!reopen) config.getDatabaseDirectory().mkdirs();
|
||||||
super.open("org.hsqldb.jdbc.JDBCDriver", reopen, listener);
|
super.open("org.hsqldb.jdbc.JDBCDriver", reopen, key, listener);
|
||||||
return reopen;
|
return reopen;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +98,7 @@ class HyperSqlDatabase extends JdbcDatabase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Connection createConnection() throws SQLException {
|
protected Connection createConnection() throws SQLException {
|
||||||
SecretKey key = config.getEncryptionKey();
|
SecretKey key = this.key;
|
||||||
if (key == null) throw new IllegalStateException();
|
if (key == null) throw new IllegalStateException();
|
||||||
String hex = StringUtils.toHexString(key.getBytes());
|
String hex = StringUtils.toHexString(key.getBytes());
|
||||||
return DriverManager.getConnection(url + ";crypt_key=" + hex);
|
return DriverManager.getConnection(url + ";crypt_key=" + hex);
|
||||||
|
|||||||
@@ -328,7 +328,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void open(String driverClass, boolean reopen,
|
protected void open(String driverClass, boolean reopen, SecretKey key,
|
||||||
@Nullable MigrationListener listener) throws DbException {
|
@Nullable MigrationListener listener) throws DbException {
|
||||||
// Load the JDBC driver
|
// Load the JDBC driver
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package org.briarproject.bramble.lifecycle;
|
package org.briarproject.bramble.lifecycle;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.account.AccountManager;
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DataTooNewException;
|
import org.briarproject.bramble.api.db.DataTooNewException;
|
||||||
import org.briarproject.bramble.api.db.DataTooOldException;
|
import org.briarproject.bramble.api.db.DataTooOldException;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
@@ -55,6 +57,7 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
private final List<Service> services;
|
private final List<Service> services;
|
||||||
private final List<Client> clients;
|
private final List<Client> clients;
|
||||||
private final List<ExecutorService> executors;
|
private final List<ExecutorService> executors;
|
||||||
|
private final AccountManager accountManager;
|
||||||
private final IdentityManager identityManager;
|
private final IdentityManager identityManager;
|
||||||
private final Semaphore startStopSemaphore = new Semaphore(1);
|
private final Semaphore startStopSemaphore = new Semaphore(1);
|
||||||
private final CountDownLatch dbLatch = new CountDownLatch(1);
|
private final CountDownLatch dbLatch = new CountDownLatch(1);
|
||||||
@@ -65,9 +68,10 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
LifecycleManagerImpl(DatabaseComponent db, EventBus eventBus,
|
LifecycleManagerImpl(DatabaseComponent db, EventBus eventBus,
|
||||||
IdentityManager identityManager) {
|
AccountManager accountManager, IdentityManager identityManager) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
|
this.accountManager = accountManager;
|
||||||
this.identityManager = identityManager;
|
this.identityManager = identityManager;
|
||||||
services = new CopyOnWriteArrayList<>();
|
services = new CopyOnWriteArrayList<>();
|
||||||
clients = new CopyOnWriteArrayList<>();
|
clients = new CopyOnWriteArrayList<>();
|
||||||
@@ -104,7 +108,9 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
|
|||||||
LOG.info("Starting services");
|
LOG.info("Starting services");
|
||||||
long start = now();
|
long start = now();
|
||||||
|
|
||||||
boolean reopened = db.open(this);
|
SecretKey key = accountManager.getDatabaseKey();
|
||||||
|
if (key == null) throw new IllegalStateException();
|
||||||
|
boolean reopened = db.open(key, this);
|
||||||
if (reopened) logDuration(LOG, "Reopening database", start);
|
if (reopened) logDuration(LOG, "Reopening database", start);
|
||||||
else logDuration(LOG, "Creating database", start);
|
else logDuration(LOG, "Creating database", start);
|
||||||
identityManager.storeLocalAuthor();
|
identityManager.storeLocalAuthor();
|
||||||
|
|||||||
@@ -0,0 +1,158 @@
|
|||||||
|
package org.briarproject.bramble.account;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
|
import org.jmock.Expectations;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertFalse;
|
||||||
|
import static junit.framework.Assert.assertNull;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
|
||||||
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class AccountManagerImplTest extends BrambleMockTestCase {
|
||||||
|
|
||||||
|
private final DatabaseConfig databaseConfig =
|
||||||
|
context.mock(DatabaseConfig.class);
|
||||||
|
|
||||||
|
private final byte[] encryptedKey = getRandomBytes(123);
|
||||||
|
private final String encryptedKeyHex = toHexString(encryptedKey);
|
||||||
|
private final String oldEncryptedKeyHex = toHexString(getRandomBytes(123));
|
||||||
|
private final File testDir = getTestDirectory();
|
||||||
|
private final File keyDir = new File(testDir, "key");
|
||||||
|
private final File keyFile = new File(keyDir, "db.key");
|
||||||
|
private final File keyBackupFile = new File(keyDir, "db.key.bak");
|
||||||
|
|
||||||
|
private AccountManagerImpl accountManager;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
allowing(databaseConfig).getDatabaseKeyDirectory();
|
||||||
|
will(returnValue(keyDir));
|
||||||
|
}});
|
||||||
|
accountManager = new AccountManagerImpl(databaseConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDbKeyIsLoadedFromPrimaryFile() throws Exception {
|
||||||
|
assertFalse(keyFile.exists());
|
||||||
|
assertFalse(keyBackupFile.exists());
|
||||||
|
|
||||||
|
storeDatabaseKey(keyFile, encryptedKeyHex);
|
||||||
|
|
||||||
|
assertTrue(keyFile.exists());
|
||||||
|
assertFalse(keyBackupFile.exists());
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
|
||||||
|
|
||||||
|
assertEquals(encryptedKeyHex, accountManager.getEncryptedDatabaseKey());
|
||||||
|
|
||||||
|
assertTrue(keyFile.exists());
|
||||||
|
assertFalse(keyBackupFile.exists());
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDbKeyIsLoadedFromBackupFile() throws Exception {
|
||||||
|
assertFalse(keyFile.exists());
|
||||||
|
assertFalse(keyBackupFile.exists());
|
||||||
|
|
||||||
|
storeDatabaseKey(keyBackupFile, encryptedKeyHex);
|
||||||
|
|
||||||
|
assertFalse(keyFile.exists());
|
||||||
|
assertTrue(keyBackupFile.exists());
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
||||||
|
|
||||||
|
assertEquals(encryptedKeyHex, accountManager.getEncryptedDatabaseKey());
|
||||||
|
|
||||||
|
assertFalse(keyFile.exists());
|
||||||
|
assertTrue(keyBackupFile.exists());
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDbKeyIsNullIfNotFound() {
|
||||||
|
assertFalse(keyFile.exists());
|
||||||
|
assertFalse(keyBackupFile.exists());
|
||||||
|
|
||||||
|
assertNull(accountManager.getEncryptedDatabaseKey());
|
||||||
|
|
||||||
|
assertFalse(keyFile.exists());
|
||||||
|
assertFalse(keyBackupFile.exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStoringDbKeyOverwritesPrimary() throws Exception {
|
||||||
|
assertFalse(keyFile.exists());
|
||||||
|
assertFalse(keyBackupFile.exists());
|
||||||
|
|
||||||
|
storeDatabaseKey(keyFile, oldEncryptedKeyHex);
|
||||||
|
|
||||||
|
assertTrue(keyFile.exists());
|
||||||
|
assertFalse(keyBackupFile.exists());
|
||||||
|
assertEquals(oldEncryptedKeyHex, loadDatabaseKey(keyFile));
|
||||||
|
|
||||||
|
assertTrue(accountManager.storeEncryptedDatabaseKey(encryptedKeyHex));
|
||||||
|
|
||||||
|
assertTrue(keyFile.exists());
|
||||||
|
assertTrue(keyBackupFile.exists());
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStoringDbKeyOverwritesBackup() throws Exception {
|
||||||
|
assertFalse(keyFile.exists());
|
||||||
|
assertFalse(keyBackupFile.exists());
|
||||||
|
|
||||||
|
storeDatabaseKey(keyBackupFile, oldEncryptedKeyHex);
|
||||||
|
|
||||||
|
assertFalse(keyFile.exists());
|
||||||
|
assertTrue(keyBackupFile.exists());
|
||||||
|
assertEquals(oldEncryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
||||||
|
|
||||||
|
assertTrue(accountManager.storeEncryptedDatabaseKey(encryptedKeyHex));
|
||||||
|
|
||||||
|
assertTrue(keyFile.exists());
|
||||||
|
assertTrue(keyBackupFile.exists());
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
|
||||||
|
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
deleteTestDirectory(testDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void storeDatabaseKey(File f, String hex) throws IOException {
|
||||||
|
f.getParentFile().mkdirs();
|
||||||
|
FileOutputStream out = new FileOutputStream(f);
|
||||||
|
out.write(hex.getBytes("UTF-8"));
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private String loadDatabaseKey(File f) throws IOException {
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||||
|
new FileInputStream(f), "UTF-8"));
|
||||||
|
String hex = reader.readLine();
|
||||||
|
reader.close();
|
||||||
|
return hex;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -89,6 +89,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
context.mock(ShutdownManager.class);
|
context.mock(ShutdownManager.class);
|
||||||
private final EventBus eventBus = context.mock(EventBus.class);
|
private final EventBus eventBus = context.mock(EventBus.class);
|
||||||
|
|
||||||
|
private final SecretKey key = getSecretKey();
|
||||||
private final Object txn = new Object();
|
private final Object txn = new Object();
|
||||||
private final ClientId clientId;
|
private final ClientId clientId;
|
||||||
private final int majorVersion;
|
private final int majorVersion;
|
||||||
@@ -141,7 +142,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
int shutdownHandle = 12345;
|
int shutdownHandle = 12345;
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// open()
|
// open()
|
||||||
oneOf(database).open(null);
|
oneOf(database).open(key, null);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
oneOf(shutdown).addShutdownHook(with(any(Runnable.class)));
|
oneOf(shutdown).addShutdownHook(with(any(Runnable.class)));
|
||||||
will(returnValue(shutdownHandle));
|
will(returnValue(shutdownHandle));
|
||||||
@@ -208,7 +209,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
shutdown);
|
shutdown);
|
||||||
|
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open(key, null));
|
||||||
Transaction transaction = db.startTransaction(false);
|
Transaction transaction = db.startTransaction(false);
|
||||||
try {
|
try {
|
||||||
db.addLocalAuthor(transaction, localAuthor);
|
db.addLocalAuthor(transaction, localAuthor);
|
||||||
@@ -1602,7 +1603,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
MessageId messageId2 = new MessageId(getRandomId());
|
MessageId messageId2 = new MessageId(getRandomId());
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// open()
|
// open()
|
||||||
oneOf(database).open(null);
|
oneOf(database).open(key, null);
|
||||||
will(returnValue(false));
|
will(returnValue(false));
|
||||||
oneOf(shutdown).addShutdownHook(with(any(Runnable.class)));
|
oneOf(shutdown).addShutdownHook(with(any(Runnable.class)));
|
||||||
will(returnValue(shutdownHandle));
|
will(returnValue(shutdownHandle));
|
||||||
@@ -1646,7 +1647,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
|
|||||||
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
DatabaseComponent db = createDatabaseComponent(database, eventBus,
|
||||||
shutdown);
|
shutdown);
|
||||||
|
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open(key, null));
|
||||||
Transaction transaction = db.startTransaction(false);
|
Transaction transaction = db.startTransaction(false);
|
||||||
try {
|
try {
|
||||||
db.addLocalMessage(transaction, message, metadata, true);
|
db.addLocalMessage(transaction, message, metadata, true);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.bramble.db;
|
package org.briarproject.bramble.db;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.DataTooNewException;
|
import org.briarproject.bramble.api.db.DataTooNewException;
|
||||||
import org.briarproject.bramble.api.db.DataTooOldException;
|
import org.briarproject.bramble.api.db.DataTooOldException;
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
@@ -26,6 +27,7 @@ import static java.util.Collections.singletonList;
|
|||||||
import static org.briarproject.bramble.db.DatabaseConstants.DB_SETTINGS_NAMESPACE;
|
import static org.briarproject.bramble.db.DatabaseConstants.DB_SETTINGS_NAMESPACE;
|
||||||
import static org.briarproject.bramble.db.DatabaseConstants.SCHEMA_VERSION_KEY;
|
import static org.briarproject.bramble.db.DatabaseConstants.SCHEMA_VERSION_KEY;
|
||||||
import static org.briarproject.bramble.db.JdbcDatabase.CODE_SCHEMA_VERSION;
|
import static org.briarproject.bramble.db.JdbcDatabase.CODE_SCHEMA_VERSION;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
@@ -43,6 +45,7 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
protected final DatabaseConfig config =
|
protected final DatabaseConfig config =
|
||||||
new TestDatabaseConfig(testDir, 1024 * 1024);
|
new TestDatabaseConfig(testDir, 1024 * 1024);
|
||||||
|
protected final SecretKey key = getSecretKey();
|
||||||
protected final Clock clock = new SystemClock();
|
protected final Clock clock = new SystemClock();
|
||||||
|
|
||||||
abstract Database<Connection> createDatabase(
|
abstract Database<Connection> createDatabase(
|
||||||
@@ -62,7 +65,7 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
public void testDoesNotRunMigrationsWhenCreatingDatabase()
|
public void testDoesNotRunMigrationsWhenCreatingDatabase()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
Database<Connection> db = createDatabase(singletonList(migration));
|
Database<Connection> db = createDatabase(singletonList(migration));
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open(key, null));
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
@@ -72,14 +75,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
// Open the DB for the first time
|
// Open the DB for the first time
|
||||||
Database<Connection> db = createDatabase(asList(migration, migration1));
|
Database<Connection> db = createDatabase(asList(migration, migration1));
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open(key, null));
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
// Override the data schema version
|
// Override the data schema version
|
||||||
setDataSchemaVersion(db, -1);
|
setDataSchemaVersion(db, -1);
|
||||||
db.close();
|
db.close();
|
||||||
// Reopen the DB - an exception should be thrown
|
// Reopen the DB - an exception should be thrown
|
||||||
db = createDatabase(asList(migration, migration1));
|
db = createDatabase(asList(migration, migration1));
|
||||||
db.open(null);
|
db.open(key, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -87,12 +90,12 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
// Open the DB for the first time
|
// Open the DB for the first time
|
||||||
Database<Connection> db = createDatabase(asList(migration, migration1));
|
Database<Connection> db = createDatabase(asList(migration, migration1));
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open(key, null));
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
db.close();
|
db.close();
|
||||||
// Reopen the DB - migrations should not be run
|
// Reopen the DB - migrations should not be run
|
||||||
db = createDatabase(asList(migration, migration1));
|
db = createDatabase(asList(migration, migration1));
|
||||||
assertTrue(db.open(null));
|
assertTrue(db.open(key, null));
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
@@ -101,14 +104,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
public void testThrowsExceptionIfDataIsNewerThanCode() throws Exception {
|
public void testThrowsExceptionIfDataIsNewerThanCode() throws Exception {
|
||||||
// Open the DB for the first time
|
// Open the DB for the first time
|
||||||
Database<Connection> db = createDatabase(asList(migration, migration1));
|
Database<Connection> db = createDatabase(asList(migration, migration1));
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open(key, null));
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
// Override the data schema version
|
// Override the data schema version
|
||||||
setDataSchemaVersion(db, CODE_SCHEMA_VERSION + 1);
|
setDataSchemaVersion(db, CODE_SCHEMA_VERSION + 1);
|
||||||
db.close();
|
db.close();
|
||||||
// Reopen the DB - an exception should be thrown
|
// Reopen the DB - an exception should be thrown
|
||||||
db = createDatabase(asList(migration, migration1));
|
db = createDatabase(asList(migration, migration1));
|
||||||
db.open(null);
|
db.open(key, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = DataTooOldException.class)
|
@Test(expected = DataTooOldException.class)
|
||||||
@@ -116,13 +119,13 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
// Open the DB for the first time
|
// Open the DB for the first time
|
||||||
Database<Connection> db = createDatabase(emptyList());
|
Database<Connection> db = createDatabase(emptyList());
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open(key, null));
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 1);
|
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 1);
|
||||||
db.close();
|
db.close();
|
||||||
// Reopen the DB - an exception should be thrown
|
// Reopen the DB - an exception should be thrown
|
||||||
db = createDatabase(emptyList());
|
db = createDatabase(emptyList());
|
||||||
db.open(null);
|
db.open(key, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = DataTooOldException.class)
|
@Test(expected = DataTooOldException.class)
|
||||||
@@ -141,14 +144,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
// Open the DB for the first time
|
// Open the DB for the first time
|
||||||
Database<Connection> db = createDatabase(asList(migration, migration1));
|
Database<Connection> db = createDatabase(asList(migration, migration1));
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open(key, null));
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
// Override the data schema version
|
// Override the data schema version
|
||||||
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 3);
|
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 3);
|
||||||
db.close();
|
db.close();
|
||||||
// Reopen the DB - an exception should be thrown
|
// Reopen the DB - an exception should be thrown
|
||||||
db = createDatabase(asList(migration, migration1));
|
db = createDatabase(asList(migration, migration1));
|
||||||
db.open(null);
|
db.open(key, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -170,14 +173,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
// Open the DB for the first time
|
// Open the DB for the first time
|
||||||
Database<Connection> db = createDatabase(asList(migration, migration1));
|
Database<Connection> db = createDatabase(asList(migration, migration1));
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open(key, null));
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
// Override the data schema version
|
// Override the data schema version
|
||||||
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 2);
|
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 2);
|
||||||
db.close();
|
db.close();
|
||||||
// Reopen the DB - the first migration should be run
|
// Reopen the DB - the first migration should be run
|
||||||
db = createDatabase(asList(migration, migration1));
|
db = createDatabase(asList(migration, migration1));
|
||||||
assertTrue(db.open(null));
|
assertTrue(db.open(key, null));
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
@@ -202,14 +205,14 @@ public abstract class DatabaseMigrationTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
// Open the DB for the first time
|
// Open the DB for the first time
|
||||||
Database<Connection> db = createDatabase(asList(migration, migration1));
|
Database<Connection> db = createDatabase(asList(migration, migration1));
|
||||||
assertFalse(db.open(null));
|
assertFalse(db.open(key, null));
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
// Override the data schema version
|
// Override the data schema version
|
||||||
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 2);
|
setDataSchemaVersion(db, CODE_SCHEMA_VERSION - 2);
|
||||||
db.close();
|
db.close();
|
||||||
// Reopen the DB - both migrations should be run
|
// Reopen the DB - both migrations should be run
|
||||||
db = createDatabase(asList(migration, migration1));
|
db = createDatabase(asList(migration, migration1));
|
||||||
assertTrue(db.open(null));
|
assertTrue(db.open(key, null));
|
||||||
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
assertEquals(CODE_SCHEMA_VERSION, getDataSchemaVersion(db));
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import java.util.List;
|
|||||||
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getMean;
|
import static org.briarproject.bramble.test.TestUtils.getMean;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getMedian;
|
import static org.briarproject.bramble.test.TestUtils.getMedian;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getStandardDeviation;
|
import static org.briarproject.bramble.test.TestUtils.getStandardDeviation;
|
||||||
import static org.briarproject.bramble.test.UTest.Z_CRITICAL_0_01;
|
import static org.briarproject.bramble.test.UTest.Z_CRITICAL_0_01;
|
||||||
|
|
||||||
@@ -71,7 +72,7 @@ public abstract class DatabasePerformanceComparisonTest
|
|||||||
throws DbException {
|
throws DbException {
|
||||||
Database<Connection> db = createDatabase(conditionA,
|
Database<Connection> db = createDatabase(conditionA,
|
||||||
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
||||||
db.open(null);
|
db.open(getSecretKey(), null);
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import java.sql.Connection;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||||
|
|
||||||
public abstract class DatabaseTraceTest extends DatabasePerformanceTest {
|
public abstract class DatabaseTraceTest extends DatabasePerformanceTest {
|
||||||
|
|
||||||
@@ -43,7 +44,7 @@ public abstract class DatabaseTraceTest extends DatabasePerformanceTest {
|
|||||||
private Database<Connection> openDatabase() throws DbException {
|
private Database<Connection> openDatabase() throws DbException {
|
||||||
Database<Connection> db = createDatabase(
|
Database<Connection> db = createDatabase(
|
||||||
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
||||||
db.open(null);
|
db.open(getSecretKey(), null);
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import java.util.List;
|
|||||||
public class H2MigrationTest extends DatabaseMigrationTest {
|
public class H2MigrationTest extends DatabaseMigrationTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Database<Connection> createDatabase(List<Migration<Connection>> migrations)
|
Database<Connection> createDatabase(
|
||||||
throws Exception {
|
List<Migration<Connection>> migrations) {
|
||||||
return new H2Database(config, clock) {
|
return new H2Database(config, clock) {
|
||||||
@Override
|
@Override
|
||||||
List<Migration<Connection>> getMigrations() {
|
List<Migration<Connection>> getMigrations() {
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
|
|||||||
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
import static org.briarproject.bramble.test.TestUtils.getTransportId;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@@ -79,7 +80,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
private static final int ONE_MEGABYTE = 1024 * 1024;
|
private static final int ONE_MEGABYTE = 1024 * 1024;
|
||||||
private static final int MAX_SIZE = 5 * ONE_MEGABYTE;
|
private static final int MAX_SIZE = 5 * ONE_MEGABYTE;
|
||||||
|
|
||||||
private final File testDir = TestUtils.getTestDirectory();
|
private final SecretKey key = getSecretKey();
|
||||||
|
private final File testDir = getTestDirectory();
|
||||||
private final GroupId groupId;
|
private final GroupId groupId;
|
||||||
private final ClientId clientId;
|
private final ClientId clientId;
|
||||||
private final int majorVersion;
|
private final int majorVersion;
|
||||||
@@ -96,7 +98,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
private final KeySetId keySetId, keySetId1;
|
private final KeySetId keySetId, keySetId1;
|
||||||
private final Random random = new Random();
|
private final Random random = new Random();
|
||||||
|
|
||||||
JdbcDatabaseTest() throws Exception {
|
JdbcDatabaseTest() {
|
||||||
clientId = getClientId();
|
clientId = getClientId();
|
||||||
majorVersion = 123;
|
majorVersion = 123;
|
||||||
group = getGroup(clientId, majorVersion);
|
group = getGroup(clientId, majorVersion);
|
||||||
@@ -1819,7 +1821,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
|
|||||||
Database<Connection> db = createDatabase(
|
Database<Connection> db = createDatabase(
|
||||||
new TestDatabaseConfig(testDir, MAX_SIZE), clock);
|
new TestDatabaseConfig(testDir, MAX_SIZE), clock);
|
||||||
if (!resume) TestUtils.deleteTestDirectory(testDir);
|
if (!resume) TestUtils.deleteTestDirectory(testDir);
|
||||||
db.open(null);
|
db.open(key, null);
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import java.util.List;
|
|||||||
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getMean;
|
import static org.briarproject.bramble.test.TestUtils.getMean;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getMedian;
|
import static org.briarproject.bramble.test.TestUtils.getMedian;
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getStandardDeviation;
|
import static org.briarproject.bramble.test.TestUtils.getStandardDeviation;
|
||||||
|
|
||||||
public abstract class SingleDatabasePerformanceTest
|
public abstract class SingleDatabasePerformanceTest
|
||||||
@@ -40,7 +41,7 @@ public abstract class SingleDatabasePerformanceTest
|
|||||||
private Database<Connection> openDatabase() throws DbException {
|
private Database<Connection> openDatabase() throws DbException {
|
||||||
Database<Connection> db = createDatabase(
|
Database<Connection> db = createDatabase(
|
||||||
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
new TestDatabaseConfig(testDir, MAX_SIZE), new SystemClock());
|
||||||
db.open(null);
|
db.open(getSecretKey(), null);
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.briarproject.bramble.test;
|
package org.briarproject.bramble.test;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
@@ -11,7 +10,6 @@ public class TestDatabaseConfig implements DatabaseConfig {
|
|||||||
|
|
||||||
private final File dbDir, keyDir;
|
private final File dbDir, keyDir;
|
||||||
private final long maxSize;
|
private final long maxSize;
|
||||||
private volatile SecretKey key = new SecretKey(new byte[SecretKey.LENGTH]);
|
|
||||||
|
|
||||||
public TestDatabaseConfig(File testDir, long maxSize) {
|
public TestDatabaseConfig(File testDir, long maxSize) {
|
||||||
dbDir = new File(testDir, "db");
|
dbDir = new File(testDir, "db");
|
||||||
@@ -36,16 +34,6 @@ public class TestDatabaseConfig implements DatabaseConfig {
|
|||||||
return keyDir;
|
return keyDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setEncryptionKey(SecretKey key) {
|
|
||||||
this.key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SecretKey getEncryptionKey() {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getMaxSize() {
|
public long getMaxSize() {
|
||||||
return maxSize;
|
return maxSize;
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
package org.briarproject.briar.android;
|
package org.briarproject.briar.android;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
|
||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -19,9 +16,6 @@ class AndroidDatabaseConfig implements DatabaseConfig {
|
|||||||
|
|
||||||
private final File dbDir, keyDir;
|
private final File dbDir, keyDir;
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private volatile SecretKey key = null;
|
|
||||||
|
|
||||||
AndroidDatabaseConfig(File dbDir, File keyDir) {
|
AndroidDatabaseConfig(File dbDir, File keyDir) {
|
||||||
this.dbDir = dbDir;
|
this.dbDir = dbDir;
|
||||||
this.keyDir = keyDir;
|
this.keyDir = keyDir;
|
||||||
@@ -62,21 +56,6 @@ class AndroidDatabaseConfig implements DatabaseConfig {
|
|||||||
return keyDir;
|
return keyDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setEncryptionKey(SecretKey key) {
|
|
||||||
LOG.info("Setting database key");
|
|
||||||
this.key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
public SecretKey getEncryptionKey() {
|
|
||||||
SecretKey key = this.key;
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Database key has been set: " + (key != null));
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getMaxSize() {
|
public long getMaxSize() {
|
||||||
return Long.MAX_VALUE;
|
return Long.MAX_VALUE;
|
||||||
|
|||||||
@@ -9,20 +9,11 @@ import org.briarproject.bramble.api.db.DatabaseConfig;
|
|||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.util.AndroidUtils;
|
import org.briarproject.bramble.util.AndroidUtils;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static java.util.logging.Level.WARNING;
|
|
||||||
import static org.briarproject.bramble.util.LogUtils.logException;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
public class ConfigControllerImpl implements ConfigController {
|
public class ConfigControllerImpl implements ConfigController {
|
||||||
|
|
||||||
@@ -30,12 +21,9 @@ public class ConfigControllerImpl implements ConfigController {
|
|||||||
Logger.getLogger(ConfigControllerImpl.class.getName());
|
Logger.getLogger(ConfigControllerImpl.class.getName());
|
||||||
|
|
||||||
private static final String PREF_DB_KEY = "key";
|
private static final String PREF_DB_KEY = "key";
|
||||||
private static final String DB_KEY_FILENAME = "db.key";
|
|
||||||
private static final String DB_KEY_BACKUP_FILENAME = "db.key.bak";
|
|
||||||
|
|
||||||
private final SharedPreferences briarPrefs;
|
private final SharedPreferences briarPrefs;
|
||||||
private final File dbKeyFile, dbKeyBackupFile;
|
protected final AccountManager accountManager;
|
||||||
private final AccountManager accountManager;
|
|
||||||
protected final DatabaseConfig databaseConfig;
|
protected final DatabaseConfig databaseConfig;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -44,16 +32,13 @@ public class ConfigControllerImpl implements ConfigController {
|
|||||||
this.briarPrefs = briarPrefs;
|
this.briarPrefs = briarPrefs;
|
||||||
this.accountManager = accountManager;
|
this.accountManager = accountManager;
|
||||||
this.databaseConfig = databaseConfig;
|
this.databaseConfig = databaseConfig;
|
||||||
File keyDir = databaseConfig.getDatabaseKeyDirectory();
|
|
||||||
dbKeyFile = new File(keyDir, DB_KEY_FILENAME);
|
|
||||||
dbKeyBackupFile = new File(keyDir, DB_KEY_BACKUP_FILENAME);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public String getEncryptedDatabaseKey() {
|
public String getEncryptedDatabaseKey() {
|
||||||
String key = getDatabaseKeyFromPreferences();
|
String key = getDatabaseKeyFromPreferences();
|
||||||
if (key == null) key = getDatabaseKeyFromFile();
|
if (key == null) key = accountManager.getEncryptedDatabaseKey();
|
||||||
else migrateDatabaseKeyToFile(key);
|
else migrateDatabaseKeyToFile(key);
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
@@ -66,40 +51,8 @@ public class ConfigControllerImpl implements ConfigController {
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private String getDatabaseKeyFromFile() {
|
|
||||||
String key = readDbKeyFromFile(dbKeyFile);
|
|
||||||
if (key == null) {
|
|
||||||
LOG.info("No database key in primary file");
|
|
||||||
key = readDbKeyFromFile(dbKeyBackupFile);
|
|
||||||
if (key == null) LOG.info("No database key in backup file");
|
|
||||||
else LOG.warning("Found database key in backup file");
|
|
||||||
} else {
|
|
||||||
LOG.info("Found database key in primary file");
|
|
||||||
}
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private String readDbKeyFromFile(File f) {
|
|
||||||
if (!f.exists()) {
|
|
||||||
LOG.info("Key file does not exist");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(
|
|
||||||
new FileInputStream(f), "UTF-8"));
|
|
||||||
String key = reader.readLine();
|
|
||||||
reader.close();
|
|
||||||
return key;
|
|
||||||
} catch (IOException e) {
|
|
||||||
logException(LOG, WARNING, e);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void migrateDatabaseKeyToFile(String key) {
|
private void migrateDatabaseKeyToFile(String key) {
|
||||||
if (storeEncryptedDatabaseKey(key)) {
|
if (accountManager.storeEncryptedDatabaseKey(key)) {
|
||||||
if (briarPrefs.edit().remove(PREF_DB_KEY).commit())
|
if (briarPrefs.edit().remove(PREF_DB_KEY).commit())
|
||||||
LOG.info("Database key migrated to file");
|
LOG.info("Database key migrated to file");
|
||||||
else LOG.warning("Database key not removed from preferences");
|
else LOG.warning("Database key not removed from preferences");
|
||||||
@@ -110,47 +63,7 @@ public class ConfigControllerImpl implements ConfigController {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean storeEncryptedDatabaseKey(String hex) {
|
public boolean storeEncryptedDatabaseKey(String hex) {
|
||||||
LOG.info("Storing database key in file");
|
return accountManager.storeEncryptedDatabaseKey(hex);
|
||||||
// Create the directory if necessary
|
|
||||||
if (databaseConfig.getDatabaseKeyDirectory().mkdirs())
|
|
||||||
LOG.info("Created database key directory");
|
|
||||||
// If only the backup file exists, rename it so we don't overwrite it
|
|
||||||
if (dbKeyBackupFile.exists() && !dbKeyFile.exists()) {
|
|
||||||
if (dbKeyBackupFile.renameTo(dbKeyFile))
|
|
||||||
LOG.info("Renamed old backup");
|
|
||||||
else LOG.warning("Failed to rename old backup");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
// Write to the backup file
|
|
||||||
writeDbKeyToFile(hex, dbKeyBackupFile);
|
|
||||||
LOG.info("Stored database key in backup file");
|
|
||||||
// Delete the old primary file, if it exists
|
|
||||||
if (dbKeyFile.exists()) {
|
|
||||||
if (dbKeyFile.delete()) LOG.info("Deleted primary file");
|
|
||||||
else LOG.warning("Failed to delete primary file");
|
|
||||||
}
|
|
||||||
// The backup file becomes the new primary
|
|
||||||
if (dbKeyBackupFile.renameTo(dbKeyFile)) {
|
|
||||||
LOG.info("Renamed backup file to primary");
|
|
||||||
} else {
|
|
||||||
LOG.warning("Failed to rename backup file to primary");
|
|
||||||
return false; // Don't overwrite our only copy
|
|
||||||
}
|
|
||||||
// Write a second copy to the backup file
|
|
||||||
writeDbKeyToFile(hex, dbKeyBackupFile);
|
|
||||||
LOG.info("Stored second copy of database key in backup file");
|
|
||||||
return true;
|
|
||||||
} catch (IOException e) {
|
|
||||||
logException(LOG, WARNING, e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeDbKeyToFile(String key, File f) throws IOException {
|
|
||||||
FileOutputStream out = new FileOutputStream(f);
|
|
||||||
out.write(key.getBytes("UTF-8"));
|
|
||||||
out.flush();
|
|
||||||
out.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ public class PasswordControllerImpl extends ConfigControllerImpl
|
|||||||
if (key == null) {
|
if (key == null) {
|
||||||
resultHandler.onResult(false);
|
resultHandler.onResult(false);
|
||||||
} else {
|
} else {
|
||||||
databaseConfig.setEncryptionKey(new SecretKey(key));
|
accountManager.setDatabaseKey(new SecretKey(key));
|
||||||
resultHandler.onResult(true);
|
resultHandler.onResult(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ public class SetupControllerImpl extends PasswordControllerImpl
|
|||||||
SecretKey key = crypto.generateSecretKey();
|
SecretKey key = crypto.generateSecretKey();
|
||||||
String hex = encryptDatabaseKey(key, password);
|
String hex = encryptDatabaseKey(key, password);
|
||||||
storeEncryptedDatabaseKey(hex);
|
storeEncryptedDatabaseKey(hex);
|
||||||
databaseConfig.setEncryptionKey(key);
|
accountManager.setDatabaseKey(key);
|
||||||
resultHandler.onResult(null);
|
resultHandler.onResult(null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
package org.briarproject.briar.android;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import static junit.framework.Assert.assertTrue;
|
|
||||||
|
|
||||||
@NotNullByDefault
|
|
||||||
public class TestDatabaseKeyUtils {
|
|
||||||
|
|
||||||
public static void storeDatabaseKey(File f, String hex) throws IOException {
|
|
||||||
f.getParentFile().mkdirs();
|
|
||||||
FileOutputStream out = new FileOutputStream(f);
|
|
||||||
out.write(hex.getBytes("UTF-8"));
|
|
||||||
out.flush();
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static String loadDatabaseKey(File f) throws IOException {
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(
|
|
||||||
new FileInputStream(f), "UTF-8"));
|
|
||||||
String hex = reader.readLine();
|
|
||||||
reader.close();
|
|
||||||
return hex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,21 +7,11 @@ import org.briarproject.bramble.api.account.AccountManager;
|
|||||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import static junit.framework.Assert.assertEquals;
|
import static junit.framework.Assert.assertEquals;
|
||||||
import static junit.framework.Assert.assertFalse;
|
|
||||||
import static junit.framework.Assert.assertNull;
|
|
||||||
import static junit.framework.Assert.assertTrue;
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
|
|
||||||
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
import static org.briarproject.briar.android.TestDatabaseKeyUtils.loadDatabaseKey;
|
|
||||||
import static org.briarproject.briar.android.TestDatabaseKeyUtils.storeDatabaseKey;
|
|
||||||
|
|
||||||
public class ConfigControllerImplTest extends BrambleMockTestCase {
|
public class ConfigControllerImplTest extends BrambleMockTestCase {
|
||||||
|
|
||||||
@@ -33,21 +23,15 @@ public class ConfigControllerImplTest extends BrambleMockTestCase {
|
|||||||
context.mock(DatabaseConfig.class);
|
context.mock(DatabaseConfig.class);
|
||||||
private final Editor editor = context.mock(Editor.class);
|
private final Editor editor = context.mock(Editor.class);
|
||||||
|
|
||||||
private final byte[] encryptedKey = getRandomBytes(123);
|
private final String encryptedKeyHex = toHexString(getRandomBytes(123));
|
||||||
private final String encryptedKeyHex = toHexString(encryptedKey);
|
|
||||||
private final String oldEncryptedKeyHex = toHexString(getRandomBytes(123));
|
|
||||||
private final File testDir = getTestDirectory();
|
|
||||||
private final File keyDir = new File(testDir, "key");
|
|
||||||
private final File keyFile = new File(keyDir, "db.key");
|
|
||||||
private final File keyBackupFile = new File(keyDir, "db.key.bak");
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDbKeyIsMigratedFromPreferencesToFile() throws Exception {
|
public void testDbKeyIsMigratedFromPreferencesToFile() {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(prefs).getString("key", null);
|
oneOf(prefs).getString("key", null);
|
||||||
will(returnValue(encryptedKeyHex));
|
will(returnValue(encryptedKeyHex));
|
||||||
allowing(databaseConfig).getDatabaseKeyDirectory();
|
oneOf(accountManager).storeEncryptedDatabaseKey(encryptedKeyHex);
|
||||||
will(returnValue(keyDir));
|
will(returnValue(true));
|
||||||
oneOf(prefs).edit();
|
oneOf(prefs).edit();
|
||||||
will(returnValue(editor));
|
will(returnValue(editor));
|
||||||
oneOf(editor).remove("key");
|
oneOf(editor).remove("key");
|
||||||
@@ -56,153 +40,10 @@ public class ConfigControllerImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(true));
|
will(returnValue(true));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
assertFalse(keyFile.exists());
|
|
||||||
assertFalse(keyBackupFile.exists());
|
|
||||||
|
|
||||||
ConfigControllerImpl c = new ConfigControllerImpl(prefs, accountManager,
|
ConfigControllerImpl c = new ConfigControllerImpl(prefs, accountManager,
|
||||||
databaseConfig);
|
databaseConfig);
|
||||||
|
|
||||||
assertEquals(encryptedKeyHex, c.getEncryptedDatabaseKey());
|
assertEquals(encryptedKeyHex, c.getEncryptedDatabaseKey());
|
||||||
|
|
||||||
assertTrue(keyFile.exists());
|
|
||||||
assertTrue(keyBackupFile.exists());
|
|
||||||
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
|
|
||||||
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDbKeyIsLoadedFromPrimaryFile() throws Exception {
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
oneOf(prefs).getString("key", null);
|
|
||||||
will(returnValue(null));
|
|
||||||
allowing(databaseConfig).getDatabaseKeyDirectory();
|
|
||||||
will(returnValue(keyDir));
|
|
||||||
}});
|
|
||||||
|
|
||||||
assertFalse(keyFile.exists());
|
|
||||||
assertFalse(keyBackupFile.exists());
|
|
||||||
|
|
||||||
storeDatabaseKey(keyFile, encryptedKeyHex);
|
|
||||||
|
|
||||||
assertTrue(keyFile.exists());
|
|
||||||
assertFalse(keyBackupFile.exists());
|
|
||||||
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
|
|
||||||
|
|
||||||
ConfigControllerImpl c = new ConfigControllerImpl(prefs, accountManager,
|
|
||||||
databaseConfig);
|
|
||||||
|
|
||||||
assertEquals(encryptedKeyHex, c.getEncryptedDatabaseKey());
|
|
||||||
|
|
||||||
assertTrue(keyFile.exists());
|
|
||||||
assertFalse(keyBackupFile.exists());
|
|
||||||
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDbKeyIsLoadedFromBackupFile() throws Exception {
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
oneOf(prefs).getString("key", null);
|
|
||||||
will(returnValue(null));
|
|
||||||
allowing(databaseConfig).getDatabaseKeyDirectory();
|
|
||||||
will(returnValue(keyDir));
|
|
||||||
}});
|
|
||||||
|
|
||||||
assertFalse(keyFile.exists());
|
|
||||||
assertFalse(keyBackupFile.exists());
|
|
||||||
|
|
||||||
storeDatabaseKey(keyBackupFile, encryptedKeyHex);
|
|
||||||
|
|
||||||
assertFalse(keyFile.exists());
|
|
||||||
assertTrue(keyBackupFile.exists());
|
|
||||||
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
|
||||||
|
|
||||||
ConfigControllerImpl c = new ConfigControllerImpl(prefs, accountManager,
|
|
||||||
databaseConfig);
|
|
||||||
|
|
||||||
assertEquals(encryptedKeyHex, c.getEncryptedDatabaseKey());
|
|
||||||
|
|
||||||
assertFalse(keyFile.exists());
|
|
||||||
assertTrue(keyBackupFile.exists());
|
|
||||||
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDbKeyIsNullIfNotFound() {
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
oneOf(prefs).getString("key", null);
|
|
||||||
will(returnValue(null));
|
|
||||||
allowing(databaseConfig).getDatabaseKeyDirectory();
|
|
||||||
will(returnValue(keyDir));
|
|
||||||
}});
|
|
||||||
|
|
||||||
assertFalse(keyFile.exists());
|
|
||||||
assertFalse(keyBackupFile.exists());
|
|
||||||
|
|
||||||
ConfigControllerImpl c = new ConfigControllerImpl(prefs, accountManager,
|
|
||||||
databaseConfig);
|
|
||||||
|
|
||||||
assertNull(c.getEncryptedDatabaseKey());
|
|
||||||
|
|
||||||
assertFalse(keyFile.exists());
|
|
||||||
assertFalse(keyBackupFile.exists());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStoringDbKeyOverwritesPrimary() throws Exception {
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
allowing(databaseConfig).getDatabaseKeyDirectory();
|
|
||||||
will(returnValue(keyDir));
|
|
||||||
}});
|
|
||||||
|
|
||||||
assertFalse(keyFile.exists());
|
|
||||||
assertFalse(keyBackupFile.exists());
|
|
||||||
|
|
||||||
storeDatabaseKey(keyFile, oldEncryptedKeyHex);
|
|
||||||
|
|
||||||
assertTrue(keyFile.exists());
|
|
||||||
assertFalse(keyBackupFile.exists());
|
|
||||||
assertEquals(oldEncryptedKeyHex, loadDatabaseKey(keyFile));
|
|
||||||
|
|
||||||
ConfigController c = new ConfigControllerImpl(prefs, accountManager,
|
|
||||||
databaseConfig);
|
|
||||||
|
|
||||||
assertTrue(c.storeEncryptedDatabaseKey(encryptedKeyHex));
|
|
||||||
|
|
||||||
assertTrue(keyFile.exists());
|
|
||||||
assertTrue(keyBackupFile.exists());
|
|
||||||
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
|
|
||||||
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStoringDbKeyOverwritesBackup() throws Exception {
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
allowing(databaseConfig).getDatabaseKeyDirectory();
|
|
||||||
will(returnValue(keyDir));
|
|
||||||
}});
|
|
||||||
|
|
||||||
assertFalse(keyFile.exists());
|
|
||||||
assertFalse(keyBackupFile.exists());
|
|
||||||
|
|
||||||
storeDatabaseKey(keyBackupFile, oldEncryptedKeyHex);
|
|
||||||
|
|
||||||
assertFalse(keyFile.exists());
|
|
||||||
assertTrue(keyBackupFile.exists());
|
|
||||||
assertEquals(oldEncryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
|
||||||
|
|
||||||
ConfigController c = new ConfigControllerImpl(prefs, accountManager,
|
|
||||||
databaseConfig);
|
|
||||||
|
|
||||||
assertTrue(c.storeEncryptedDatabaseKey(encryptedKeyHex));
|
|
||||||
|
|
||||||
assertTrue(keyFile.exists());
|
|
||||||
assertTrue(keyBackupFile.exists());
|
|
||||||
assertEquals(encryptedKeyHex, loadDatabaseKey(keyFile));
|
|
||||||
assertEquals(encryptedKeyHex, loadDatabaseKey(keyBackupFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDown() {
|
|
||||||
deleteTestDirectory(testDir);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,23 +9,16 @@ import org.briarproject.bramble.api.db.DatabaseConfig;
|
|||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
import org.briarproject.bramble.test.ImmediateExecutor;
|
import org.briarproject.bramble.test.ImmediateExecutor;
|
||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import static junit.framework.Assert.assertEquals;
|
|
||||||
import static junit.framework.Assert.assertFalse;
|
import static junit.framework.Assert.assertFalse;
|
||||||
import static junit.framework.Assert.assertTrue;
|
import static junit.framework.Assert.assertTrue;
|
||||||
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
|
|
||||||
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
import static org.briarproject.briar.android.TestDatabaseKeyUtils.loadDatabaseKey;
|
|
||||||
import static org.briarproject.briar.android.TestDatabaseKeyUtils.storeDatabaseKey;
|
|
||||||
|
|
||||||
public class PasswordControllerImplTest extends BrambleMockTestCase {
|
public class PasswordControllerImplTest extends BrambleMockTestCase {
|
||||||
|
|
||||||
@@ -46,32 +39,27 @@ public class PasswordControllerImplTest extends BrambleMockTestCase {
|
|||||||
private final byte[] oldEncryptedKey = getRandomBytes(123);
|
private final byte[] oldEncryptedKey = getRandomBytes(123);
|
||||||
private final byte[] newEncryptedKey = getRandomBytes(123);
|
private final byte[] newEncryptedKey = getRandomBytes(123);
|
||||||
private final byte[] key = getSecretKey().getBytes();
|
private final byte[] key = getSecretKey().getBytes();
|
||||||
private final File testDir = getTestDirectory();
|
private final String oldEncryptedKeyHex = toHexString(oldEncryptedKey);
|
||||||
private final File keyDir = new File(testDir, "key");
|
private final String newEncryptedKeyHex = toHexString(newEncryptedKey);
|
||||||
private final File keyFile = new File(keyDir, "db.key");
|
|
||||||
private final File keyBackupFile = new File(keyDir, "db.key.bak");
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testChangePasswordReturnsTrue() throws Exception {
|
public void testChangePasswordReturnsTrue() {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// Look up the encrypted DB key
|
// Look up the encrypted DB key
|
||||||
oneOf(briarPrefs).getString("key", null);
|
oneOf(briarPrefs).getString("key", null);
|
||||||
will(returnValue(null));
|
will(returnValue(null));
|
||||||
allowing(databaseConfig).getDatabaseKeyDirectory();
|
oneOf(accountManager).getEncryptedDatabaseKey();
|
||||||
will(returnValue(keyDir));
|
will(returnValue(oldEncryptedKeyHex));
|
||||||
// Decrypt and re-encrypt the key
|
// Decrypt and re-encrypt the key
|
||||||
oneOf(crypto).decryptWithPassword(oldEncryptedKey, oldPassword);
|
oneOf(crypto).decryptWithPassword(oldEncryptedKey, oldPassword);
|
||||||
will(returnValue(key));
|
will(returnValue(key));
|
||||||
oneOf(crypto).encryptWithPassword(key, newPassword);
|
oneOf(crypto).encryptWithPassword(key, newPassword);
|
||||||
will(returnValue(newEncryptedKey));
|
will(returnValue(newEncryptedKey));
|
||||||
|
// Store the new key
|
||||||
|
oneOf(accountManager).storeEncryptedDatabaseKey(newEncryptedKeyHex);
|
||||||
|
will(returnValue(true));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
assertFalse(keyFile.exists());
|
|
||||||
assertFalse(keyBackupFile.exists());
|
|
||||||
|
|
||||||
storeDatabaseKey(keyFile, toHexString(oldEncryptedKey));
|
|
||||||
storeDatabaseKey(keyBackupFile, toHexString(oldEncryptedKey));
|
|
||||||
|
|
||||||
PasswordControllerImpl p = new PasswordControllerImpl(briarPrefs,
|
PasswordControllerImpl p = new PasswordControllerImpl(briarPrefs,
|
||||||
accountManager, databaseConfig, cryptoExecutor, crypto,
|
accountManager, databaseConfig, cryptoExecutor, crypto,
|
||||||
estimator);
|
estimator);
|
||||||
@@ -79,34 +67,21 @@ public class PasswordControllerImplTest extends BrambleMockTestCase {
|
|||||||
AtomicBoolean capturedResult = new AtomicBoolean(false);
|
AtomicBoolean capturedResult = new AtomicBoolean(false);
|
||||||
p.changePassword(oldPassword, newPassword, capturedResult::set);
|
p.changePassword(oldPassword, newPassword, capturedResult::set);
|
||||||
assertTrue(capturedResult.get());
|
assertTrue(capturedResult.get());
|
||||||
|
|
||||||
assertTrue(keyFile.exists());
|
|
||||||
assertTrue(keyBackupFile.exists());
|
|
||||||
assertEquals(toHexString(newEncryptedKey), loadDatabaseKey(keyFile));
|
|
||||||
assertEquals(toHexString(newEncryptedKey),
|
|
||||||
loadDatabaseKey(keyBackupFile));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testChangePasswordReturnsFalseIfOldPasswordIsWrong()
|
public void testChangePasswordReturnsFalseIfOldPasswordIsWrong() {
|
||||||
throws Exception {
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// Look up the encrypted DB key
|
// Look up the encrypted DB key
|
||||||
oneOf(briarPrefs).getString("key", null);
|
oneOf(briarPrefs).getString("key", null);
|
||||||
will(returnValue(null));
|
will(returnValue(null));
|
||||||
allowing(databaseConfig).getDatabaseKeyDirectory();
|
oneOf(accountManager).getEncryptedDatabaseKey();
|
||||||
will(returnValue(keyDir));
|
will(returnValue(oldEncryptedKeyHex));
|
||||||
// Try to decrypt the key - the password is wrong
|
// Try to decrypt the key - the password is wrong
|
||||||
oneOf(crypto).decryptWithPassword(oldEncryptedKey, oldPassword);
|
oneOf(crypto).decryptWithPassword(oldEncryptedKey, oldPassword);
|
||||||
will(returnValue(null));
|
will(returnValue(null));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
assertFalse(keyFile.exists());
|
|
||||||
assertFalse(keyBackupFile.exists());
|
|
||||||
|
|
||||||
storeDatabaseKey(keyFile, toHexString(oldEncryptedKey));
|
|
||||||
storeDatabaseKey(keyBackupFile, toHexString(oldEncryptedKey));
|
|
||||||
|
|
||||||
PasswordControllerImpl p = new PasswordControllerImpl(briarPrefs,
|
PasswordControllerImpl p = new PasswordControllerImpl(briarPrefs,
|
||||||
accountManager, databaseConfig, cryptoExecutor, crypto,
|
accountManager, databaseConfig, cryptoExecutor, crypto,
|
||||||
estimator);
|
estimator);
|
||||||
@@ -114,16 +89,5 @@ public class PasswordControllerImplTest extends BrambleMockTestCase {
|
|||||||
AtomicBoolean capturedResult = new AtomicBoolean(true);
|
AtomicBoolean capturedResult = new AtomicBoolean(true);
|
||||||
p.changePassword(oldPassword, newPassword, capturedResult::set);
|
p.changePassword(oldPassword, newPassword, capturedResult::set);
|
||||||
assertFalse(capturedResult.get());
|
assertFalse(capturedResult.get());
|
||||||
|
|
||||||
assertTrue(keyFile.exists());
|
|
||||||
assertTrue(keyBackupFile.exists());
|
|
||||||
assertEquals(toHexString(oldEncryptedKey), loadDatabaseKey(keyFile));
|
|
||||||
assertEquals(toHexString(oldEncryptedKey),
|
|
||||||
loadDatabaseKey(keyBackupFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDown() {
|
|
||||||
deleteTestDirectory(testDir);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.briarproject.briar.android.login;
|
package org.briarproject.briar.android.login;
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.ApplicationInfo;
|
|
||||||
|
|
||||||
import org.briarproject.bramble.api.account.AccountManager;
|
import org.briarproject.bramble.api.account.AccountManager;
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
||||||
@@ -14,25 +13,18 @@ import org.briarproject.bramble.test.BrambleMockTestCase;
|
|||||||
import org.briarproject.bramble.test.ImmediateExecutor;
|
import org.briarproject.bramble.test.ImmediateExecutor;
|
||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
import org.jmock.lib.legacy.ClassImposteriser;
|
import org.jmock.lib.legacy.ClassImposteriser;
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import static junit.framework.Assert.assertEquals;
|
|
||||||
import static junit.framework.Assert.assertFalse;
|
|
||||||
import static junit.framework.Assert.assertTrue;
|
import static junit.framework.Assert.assertTrue;
|
||||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
||||||
import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory;
|
|
||||||
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
|
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
import static org.briarproject.bramble.test.TestUtils.getRandomBytes;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getTestDirectory;
|
|
||||||
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||||
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
import static org.briarproject.bramble.util.StringUtils.toHexString;
|
||||||
import static org.briarproject.briar.android.TestDatabaseKeyUtils.loadDatabaseKey;
|
|
||||||
|
|
||||||
public class SetupControllerImplTest extends BrambleMockTestCase {
|
public class SetupControllerImplTest extends BrambleMockTestCase {
|
||||||
|
|
||||||
@@ -55,11 +47,8 @@ public class SetupControllerImplTest extends BrambleMockTestCase {
|
|||||||
private final String password = "some.strong.pass";
|
private final String password = "some.strong.pass";
|
||||||
private final LocalAuthor localAuthor = getLocalAuthor();
|
private final LocalAuthor localAuthor = getLocalAuthor();
|
||||||
private final byte[] encryptedKey = getRandomBytes(123);
|
private final byte[] encryptedKey = getRandomBytes(123);
|
||||||
|
private final String encryptedKeyHex = toHexString(encryptedKey);
|
||||||
private final SecretKey key = getSecretKey();
|
private final SecretKey key = getSecretKey();
|
||||||
private final File testDir = getTestDirectory();
|
|
||||||
private final File keyDir = new File(testDir, "key");
|
|
||||||
private final File keyFile = new File(keyDir, "db.key");
|
|
||||||
private final File keyBackupFile = new File(keyDir, "db.key.bak");
|
|
||||||
|
|
||||||
public SetupControllerImplTest() {
|
public SetupControllerImplTest() {
|
||||||
context.setImposteriser(ClassImposteriser.INSTANCE);
|
context.setImposteriser(ClassImposteriser.INSTANCE);
|
||||||
@@ -68,13 +57,8 @@ public class SetupControllerImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||||
public void testCreateAccount() throws Exception {
|
public void testCreateAccount() {
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
// Allow the contents of the data directory to be logged
|
|
||||||
allowing(setupActivity).getApplicationInfo();
|
|
||||||
will(returnValue(new ApplicationInfo() {{
|
|
||||||
dataDir = testDir.getAbsolutePath();
|
|
||||||
}}));
|
|
||||||
// Set the author name and password
|
// Set the author name and password
|
||||||
oneOf(setupActivity).setAuthorName(authorName);
|
oneOf(setupActivity).setAuthorName(authorName);
|
||||||
oneOf(setupActivity).setPassword(password);
|
oneOf(setupActivity).setPassword(password);
|
||||||
@@ -94,15 +78,12 @@ public class SetupControllerImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(crypto).encryptWithPassword(key.getBytes(), password);
|
oneOf(crypto).encryptWithPassword(key.getBytes(), password);
|
||||||
will(returnValue(encryptedKey));
|
will(returnValue(encryptedKey));
|
||||||
// Store the encrypted key
|
// Store the encrypted key
|
||||||
allowing(databaseConfig).getDatabaseKeyDirectory();
|
oneOf(accountManager).storeEncryptedDatabaseKey(encryptedKeyHex);
|
||||||
will(returnValue(keyDir));
|
will(returnValue(true));
|
||||||
// Attach the database key to the database config
|
// Pass the database key to the account manager
|
||||||
oneOf(databaseConfig).setEncryptionKey(key);
|
oneOf(accountManager).setDatabaseKey(key);
|
||||||
}});
|
}});
|
||||||
|
|
||||||
assertFalse(keyFile.exists());
|
|
||||||
assertFalse(keyBackupFile.exists());
|
|
||||||
|
|
||||||
SetupControllerImpl s = new SetupControllerImpl(briarPrefs,
|
SetupControllerImpl s = new SetupControllerImpl(briarPrefs,
|
||||||
accountManager, databaseConfig, cryptoExecutor, crypto,
|
accountManager, databaseConfig, cryptoExecutor, crypto,
|
||||||
estimator, identityManager);
|
estimator, identityManager);
|
||||||
@@ -113,17 +94,5 @@ public class SetupControllerImplTest extends BrambleMockTestCase {
|
|||||||
s.setPassword(password);
|
s.setPassword(password);
|
||||||
s.createAccount(result -> called.set(true));
|
s.createAccount(result -> called.set(true));
|
||||||
assertTrue(called.get());
|
assertTrue(called.get());
|
||||||
|
|
||||||
assertTrue(keyFile.exists());
|
|
||||||
assertTrue(keyBackupFile.exists());
|
|
||||||
assertEquals(toHexString(encryptedKey),
|
|
||||||
loadDatabaseKey(keyFile));
|
|
||||||
assertEquals(toHexString(encryptedKey),
|
|
||||||
loadDatabaseKey(keyBackupFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDown() {
|
|
||||||
deleteTestDirectory(testDir);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import org.junit.Test;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
@@ -53,6 +54,8 @@ public class FeedManagerIntegrationTest extends BriarTestCase {
|
|||||||
LocalAuthor localAuthor = identityManager.createLocalAuthor("feedTest");
|
LocalAuthor localAuthor = identityManager.createLocalAuthor("feedTest");
|
||||||
identityManager.registerLocalAuthor(localAuthor);
|
identityManager.registerLocalAuthor(localAuthor);
|
||||||
|
|
||||||
|
component.getAccountManager().setDatabaseKey(getSecretKey());
|
||||||
|
|
||||||
lifecycleManager = component.getLifecycleManager();
|
lifecycleManager = component.getLifecycleManager();
|
||||||
lifecycleManager.startServices();
|
lifecycleManager.startServices();
|
||||||
lifecycleManager.waitForStartup();
|
lifecycleManager.waitForStartup();
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package org.briarproject.briar.feed;
|
package org.briarproject.briar.feed;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.account.AccountModule;
|
||||||
|
import org.briarproject.bramble.api.account.AccountManager;
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
import org.briarproject.bramble.api.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.bramble.client.ClientModule;
|
import org.briarproject.bramble.client.ClientModule;
|
||||||
@@ -36,6 +38,7 @@ import dagger.Component;
|
|||||||
TestSecureRandomModule.class,
|
TestSecureRandomModule.class,
|
||||||
TestSocksModule.class,
|
TestSocksModule.class,
|
||||||
TestDnsModule.class,
|
TestDnsModule.class,
|
||||||
|
AccountModule.class,
|
||||||
BriarClientModule.class,
|
BriarClientModule.class,
|
||||||
ClientModule.class,
|
ClientModule.class,
|
||||||
ContactModule.class,
|
ContactModule.class,
|
||||||
@@ -79,6 +82,8 @@ interface FeedManagerIntegrationTestComponent {
|
|||||||
|
|
||||||
IdentityManager getIdentityManager();
|
IdentityManager getIdentityManager();
|
||||||
|
|
||||||
|
AccountManager getAccountManager();
|
||||||
|
|
||||||
LifecycleManager getLifecycleManager();
|
LifecycleManager getLifecycleManager();
|
||||||
|
|
||||||
FeedManager getFeedManager();
|
FeedManager getFeedManager();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.briar.introduction;
|
package org.briarproject.briar.introduction;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.account.AccountModule;
|
||||||
import org.briarproject.bramble.client.ClientModule;
|
import org.briarproject.bramble.client.ClientModule;
|
||||||
import org.briarproject.bramble.contact.ContactModule;
|
import org.briarproject.bramble.contact.ContactModule;
|
||||||
import org.briarproject.bramble.crypto.CryptoExecutorModule;
|
import org.briarproject.bramble.crypto.CryptoExecutorModule;
|
||||||
@@ -36,6 +37,7 @@ import dagger.Component;
|
|||||||
TestDatabaseModule.class,
|
TestDatabaseModule.class,
|
||||||
TestPluginConfigModule.class,
|
TestPluginConfigModule.class,
|
||||||
TestSecureRandomModule.class,
|
TestSecureRandomModule.class,
|
||||||
|
AccountModule.class,
|
||||||
BlogModule.class,
|
BlogModule.class,
|
||||||
BriarClientModule.class,
|
BriarClientModule.class,
|
||||||
ClientModule.class,
|
ClientModule.class,
|
||||||
|
|||||||
@@ -100,6 +100,8 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
|
|||||||
|
|
||||||
private ContactId setUp(SimplexMessagingIntegrationTestComponent device,
|
private ContactId setUp(SimplexMessagingIntegrationTestComponent device,
|
||||||
LocalAuthor local, Author remote, boolean alice) throws Exception {
|
LocalAuthor local, Author remote, boolean alice) throws Exception {
|
||||||
|
// Create a database key
|
||||||
|
device.getAccountManager().setDatabaseKey(getSecretKey());
|
||||||
// Add an identity for the user
|
// Add an identity for the user
|
||||||
IdentityManager identityManager = device.getIdentityManager();
|
IdentityManager identityManager = device.getIdentityManager();
|
||||||
identityManager.registerLocalAuthor(local);
|
identityManager.registerLocalAuthor(local);
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package org.briarproject.briar.messaging;
|
package org.briarproject.briar.messaging;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.account.AccountModule;
|
||||||
|
import org.briarproject.bramble.api.account.AccountManager;
|
||||||
import org.briarproject.bramble.api.contact.ContactManager;
|
import org.briarproject.bramble.api.contact.ContactManager;
|
||||||
import org.briarproject.bramble.api.event.EventBus;
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||||
@@ -39,6 +41,7 @@ import dagger.Component;
|
|||||||
TestDatabaseModule.class,
|
TestDatabaseModule.class,
|
||||||
TestPluginConfigModule.class,
|
TestPluginConfigModule.class,
|
||||||
TestSecureRandomModule.class,
|
TestSecureRandomModule.class,
|
||||||
|
AccountModule.class,
|
||||||
BriarClientModule.class,
|
BriarClientModule.class,
|
||||||
ClientModule.class,
|
ClientModule.class,
|
||||||
ContactModule.class,
|
ContactModule.class,
|
||||||
@@ -77,6 +80,8 @@ interface SimplexMessagingIntegrationTestComponent {
|
|||||||
|
|
||||||
IdentityManager getIdentityManager();
|
IdentityManager getIdentityManager();
|
||||||
|
|
||||||
|
AccountManager getAccountManager();
|
||||||
|
|
||||||
ContactManager getContactManager();
|
ContactManager getContactManager();
|
||||||
|
|
||||||
MessagingManager getMessagingManager();
|
MessagingManager getMessagingManager();
|
||||||
|
|||||||
@@ -140,6 +140,9 @@ public abstract class BriarIntegrationTest<C extends BriarIntegrationTestCompone
|
|||||||
assertTrue(testDir.mkdirs());
|
assertTrue(testDir.mkdirs());
|
||||||
createComponents();
|
createComponents();
|
||||||
|
|
||||||
|
c0.getAccountManager().setDatabaseKey(getSecretKey());
|
||||||
|
c1.getAccountManager().setDatabaseKey(getSecretKey());
|
||||||
|
c2.getAccountManager().setDatabaseKey(getSecretKey());
|
||||||
identityManager0 = c0.getIdentityManager();
|
identityManager0 = c0.getIdentityManager();
|
||||||
identityManager1 = c1.getIdentityManager();
|
identityManager1 = c1.getIdentityManager();
|
||||||
identityManager2 = c2.getIdentityManager();
|
identityManager2 = c2.getIdentityManager();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.briar.test;
|
package org.briarproject.briar.test;
|
||||||
|
|
||||||
import org.briarproject.bramble.account.AccountModule;
|
import org.briarproject.bramble.account.AccountModule;
|
||||||
|
import org.briarproject.bramble.api.account.AccountManager;
|
||||||
import org.briarproject.bramble.api.client.ClientHelper;
|
import org.briarproject.bramble.api.client.ClientHelper;
|
||||||
import org.briarproject.bramble.api.contact.ContactManager;
|
import org.briarproject.bramble.api.contact.ContactManager;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
@@ -122,6 +123,8 @@ public interface BriarIntegrationTestComponent {
|
|||||||
|
|
||||||
IdentityManager getIdentityManager();
|
IdentityManager getIdentityManager();
|
||||||
|
|
||||||
|
AccountManager getAccountManager();
|
||||||
|
|
||||||
ClientHelper getClientHelper();
|
ClientHelper getClientHelper();
|
||||||
|
|
||||||
ContactManager getContactManager();
|
ContactManager getContactManager();
|
||||||
|
|||||||
Reference in New Issue
Block a user