mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-11 18:29:05 +01:00
WIP: Add SQLite DB backend using sqlite-jdbc-crypt.
This commit is contained in:
@@ -104,3 +104,12 @@ mailbox integration test:
|
||||
script:
|
||||
- (cd briar-mailbox; git fetch; git reset --hard origin/main)
|
||||
- MAILBOX_INTEGRATION_TESTS=true ./gradlew --info mailbox-integration-tests:test
|
||||
|
||||
db_performance_comparison_test:
|
||||
extends: .base-test
|
||||
stage: optional_tests
|
||||
script:
|
||||
- OPTIONAL_TESTS=org.briarproject.bramble.db.H2SqliteDatabasePerformanceComparisonTest ./gradlew --info -Djava.security.egd=file:/dev/urandom :bramble-core:test --tests H2SqliteDatabasePerformanceComparisonTest
|
||||
rules:
|
||||
- when: manual
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ dependencies {
|
||||
implementation "org.bouncycastle:bcprov-jdk15to18:$bouncy_castle_version"
|
||||
//noinspection GradleDependency
|
||||
implementation 'com.h2database:h2:1.4.192' // The last version that supports Java 1.6
|
||||
implementation 'io.github.willena:sqlite-jdbc:3.41.2.1'
|
||||
implementation 'org.bitlet:weupnp:0.1.4'
|
||||
implementation 'net.i2p.crypto:eddsa:0.2.0'
|
||||
implementation 'org.whispersystems:curve25519-java:0.5.0'
|
||||
|
||||
@@ -39,7 +39,8 @@ class H2Database extends JdbcDatabase {
|
||||
private static final String HASH_TYPE = "BINARY(32)";
|
||||
private static final String SECRET_TYPE = "BINARY(32)";
|
||||
private static final String BINARY_TYPE = "BINARY";
|
||||
private static final String COUNTER_TYPE = "INT NOT NULL AUTO_INCREMENT";
|
||||
private static final String COUNTER_TYPE =
|
||||
"INT NOT NULL AUTO_INCREMENT PRIMARY KEY";
|
||||
private static final String STRING_TYPE = "VARCHAR";
|
||||
private static final DatabaseTypes dbTypes = new DatabaseTypes(HASH_TYPE,
|
||||
SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE);
|
||||
|
||||
@@ -38,8 +38,8 @@ class HyperSqlDatabase extends JdbcDatabase {
|
||||
private static final String HASH_TYPE = "BINARY(32)";
|
||||
private static final String SECRET_TYPE = "BINARY(32)";
|
||||
private static final String BINARY_TYPE = "BINARY";
|
||||
private static final String COUNTER_TYPE =
|
||||
"INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY(START WITH 1)";
|
||||
private static final String COUNTER_TYPE = "INTEGER NOT NULL"
|
||||
+ " PRIMARY KEY GENERATED ALWAYS AS IDENTITY(START WITH 1)";
|
||||
private static final String STRING_TYPE = "VARCHAR";
|
||||
private static final DatabaseTypes dbTypes = new DatabaseTypes(HASH_TYPE,
|
||||
SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE);
|
||||
|
||||
@@ -143,8 +143,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
+ " handshakePublicKey _BINARY," // Null if key is unknown
|
||||
+ " localAuthorId _HASH NOT NULL,"
|
||||
+ " verified BOOLEAN NOT NULL,"
|
||||
// FIXME: SQLite interprets default '00' as string
|
||||
+ " syncVersions _BINARY DEFAULT '00' NOT NULL,"
|
||||
+ " PRIMARY KEY (contactId),"
|
||||
+ " FOREIGN KEY (localAuthorId)"
|
||||
+ " REFERENCES localAuthors (authorId)"
|
||||
+ " ON DELETE CASCADE)";
|
||||
@@ -295,11 +295,11 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
+ " active BOOLEAN NOT NULL,"
|
||||
+ " rootKey _SECRET," // Null for rotation keys
|
||||
+ " alice BOOLEAN," // Null for rotation keys
|
||||
+ " PRIMARY KEY (transportId, keySetId),"
|
||||
// FIXME: Primary key has changed, migration needed
|
||||
+ " FOREIGN KEY (transportId)"
|
||||
+ " REFERENCES transports (transportId)"
|
||||
+ " ON DELETE CASCADE,"
|
||||
+ " UNIQUE (keySetId),"
|
||||
// FIXME: Unique constraint removed, migration needed
|
||||
+ " FOREIGN KEY (contactId)"
|
||||
+ " REFERENCES contacts (contactId)"
|
||||
+ " ON DELETE CASCADE,"
|
||||
@@ -358,6 +358,11 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
"CREATE INDEX IF NOT EXISTS messagesByCleanupDeadline"
|
||||
+ " ON messages (cleanupDeadline)";
|
||||
|
||||
// FIXME: Migration needs to add new index
|
||||
private static final String INDEX_OUTGOING_KEYS_BY_TRANSPORT_ID_KEYSET_ID =
|
||||
"CREATE INDEX IF NOT EXISTS outgoingKeysByTransportIdKeysetId"
|
||||
+ " ON outgoingKeys (transportId, keySetId)";
|
||||
|
||||
private static final Logger LOG =
|
||||
getLogger(JdbcDatabase.class.getName());
|
||||
|
||||
@@ -564,6 +569,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
s.executeUpdate(INDEX_STATUSES_BY_CONTACT_ID_TIMESTAMP);
|
||||
s.executeUpdate(INDEX_STATUSES_BY_CONTACT_ID_TX_COUNT_TIMESTAMP);
|
||||
s.executeUpdate(INDEX_MESSAGES_BY_CLEANUP_DEADLINE);
|
||||
s.executeUpdate(INDEX_OUTGOING_KEYS_BY_TRANSPORT_ID_KEYSET_ID);
|
||||
s.close();
|
||||
} catch (SQLException e) {
|
||||
tryToClose(s, LOG, WARNING);
|
||||
@@ -2597,6 +2603,9 @@ abstract class JdbcDatabase implements Database<Connection> {
|
||||
PublicKey publicKey = new AgreementPublicKey(rs.getBytes(1));
|
||||
String alias = rs.getString(2);
|
||||
long timestamp = rs.getLong(3);
|
||||
if (rs.next()) throw new DbStateException();
|
||||
rs.close();
|
||||
ps.close();
|
||||
return new PendingContact(p, publicKey, alias, timestamp);
|
||||
} catch (SQLException e) {
|
||||
tryToClose(rs, LOG, WARNING);
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
package org.briarproject.bramble.db;
|
||||
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||
import org.briarproject.bramble.api.db.DbClosedException;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.MigrationListener;
|
||||
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.briarproject.nullsafety.NotNullByDefault;
|
||||
import org.sqlite.mc.SQLiteMCSqlCipherConfig;
|
||||
|
||||
import java.io.File;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
import static java.util.logging.Logger.getLogger;
|
||||
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
|
||||
import static org.briarproject.bramble.util.IoUtils.isNonEmptyDirectory;
|
||||
|
||||
/**
|
||||
* Contains all the SQLite-specific code for the database.
|
||||
*/
|
||||
@NotNullByDefault
|
||||
class SqliteDatabase extends JdbcDatabase {
|
||||
|
||||
private static final Logger LOG = getLogger(SqliteDatabase.class.getName());
|
||||
|
||||
private static final String HASH_TYPE = "BLOB";
|
||||
private static final String SECRET_TYPE = "BLOB";
|
||||
private static final String BINARY_TYPE = "BLOB";
|
||||
private static final String COUNTER_TYPE =
|
||||
"INTEGER PRIMARY KEY AUTOINCREMENT";
|
||||
private static final String STRING_TYPE = "VARCHAR";
|
||||
private static final DatabaseTypes dbTypes = new DatabaseTypes(HASH_TYPE,
|
||||
SECRET_TYPE, BINARY_TYPE, COUNTER_TYPE, STRING_TYPE);
|
||||
|
||||
private final DatabaseConfig config;
|
||||
private final String url;
|
||||
|
||||
@Nullable
|
||||
private volatile Properties properties = null;
|
||||
|
||||
@Inject
|
||||
SqliteDatabase(DatabaseConfig config, MessageFactory messageFactory,
|
||||
Clock clock) {
|
||||
super(dbTypes, messageFactory, clock);
|
||||
this.config = config;
|
||||
File dir = config.getDatabaseDirectory();
|
||||
String path = new File(dir, "db").getAbsolutePath();
|
||||
url = "jdbc:sqlite:" + path + "?cipher=sqlcipher";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean open(SecretKey key, @Nullable MigrationListener listener)
|
||||
throws DbException {
|
||||
properties = SQLiteMCSqlCipherConfig.getDefault()
|
||||
.withHexKey(key.getBytes())
|
||||
.build()
|
||||
.toProperties();
|
||||
File dir = config.getDatabaseDirectory();
|
||||
boolean reopen = isNonEmptyDirectory(dir);
|
||||
if (LOG.isLoggable(INFO)) LOG.info("Reopening DB: " + reopen);
|
||||
if (!reopen && dir.mkdirs()) LOG.info("Created database directory");
|
||||
super.open("org.sqlite.JDBC", reopen, key, listener);
|
||||
return reopen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws DbException {
|
||||
Connection c = null;
|
||||
try {
|
||||
c = createConnection();
|
||||
setDirty(c, false);
|
||||
c.close();
|
||||
closeAllConnections();
|
||||
} catch (SQLException e) {
|
||||
tryToClose(c, LOG, WARNING);
|
||||
throw new DbException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Connection createConnection() throws DbException, SQLException {
|
||||
Properties properties = this.properties;
|
||||
if (properties == null) throw new DbClosedException();
|
||||
Connection c = DriverManager.getConnection(url, properties);
|
||||
Statement s = null;
|
||||
try {
|
||||
s = c.createStatement();
|
||||
s.execute("PRAGMA foreign_keys = ON");
|
||||
s.close();
|
||||
} catch (SQLException e) {
|
||||
tryToClose(s, LOG, WARNING);
|
||||
tryToClose(c, LOG, WARNING);
|
||||
throw new DbException(e);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void compactAndClose() throws DbException {
|
||||
close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.briarproject.bramble.db;
|
||||
|
||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
import static org.briarproject.bramble.test.TestUtils.isOptionalTestEnabled;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
public class H2SqliteDatabasePerformanceComparisonTest
|
||||
extends DatabasePerformanceComparisonTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpClass() {
|
||||
assumeTrue(isOptionalTestEnabled(
|
||||
H2SqliteDatabasePerformanceComparisonTest.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
Database<Connection> createDatabase(boolean conditionA,
|
||||
DatabaseConfig databaseConfig, MessageFactory messageFactory,
|
||||
Clock clock) {
|
||||
if (conditionA) {
|
||||
return new H2Database(databaseConfig, messageFactory, clock);
|
||||
} else {
|
||||
return new SqliteDatabase(databaseConfig, messageFactory, clock);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTestName() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.briarproject.bramble.db;
|
||||
|
||||
import org.briarproject.bramble.api.db.DatabaseConfig;
|
||||
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||
import org.briarproject.bramble.api.system.Clock;
|
||||
import org.junit.Before;
|
||||
|
||||
import static org.briarproject.bramble.test.TestUtils.isCryptoStrengthUnlimited;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
public class SqliteDatabaseTest extends JdbcDatabaseTest {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
assumeTrue(isCryptoStrengthUnlimited());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JdbcDatabase createDatabase(DatabaseConfig config,
|
||||
MessageFactory messageFactory, Clock clock) {
|
||||
return new SqliteDatabase(config, messageFactory, clock);
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ dependencyVerification {
|
||||
'com.squareup.okio:okio-jvm:3.0.0:okio-jvm-3.0.0.jar:be64a0cc1f28ea9cd5c970dd7e7557af72c808d738c495b397bf897c9921e907',
|
||||
'com.squareup:javapoet:1.13.0:javapoet-1.13.0.jar:4c7517e848a71b36d069d12bb3bf46a70fd4cda3105d822b0ed2e19c00b69291',
|
||||
'com.squareup:kotlinpoet:1.11.0:kotlinpoet-1.11.0.jar:2887ada1ca03dd83baa2758640d87e840d1907564db0ef88d2289c868a980492',
|
||||
'io.github.willena:sqlite-jdbc:3.41.2.1:sqlite-jdbc-3.41.2.1.jar:fb60e7137c1791db89240701338d31ca42a0bec5508c1aab1c1131cf885f2309',
|
||||
'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||
'junit:junit:4.13.2:junit-4.13.2.jar:8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3',
|
||||
'net.bytebuddy:byte-buddy:1.9.12:byte-buddy-1.9.12.jar:3688c3d434bebc3edc5516296a2ed0f47b65e451071b4afecad84f902f0efc11',
|
||||
|
||||
Reference in New Issue
Block a user