diff --git a/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/PretixScan.kt b/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/PretixScan.kt index 88ea59d..43787aa 100644 --- a/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/PretixScan.kt +++ b/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/PretixScan.kt @@ -21,6 +21,9 @@ import io.requery.BlockingEntityStore import io.requery.Persistable import io.requery.android.sqlite.DatabaseSource import io.requery.sql.EntityDataStore +import net.zetetic.database.sqlcipher.SQLiteConnection +import net.zetetic.database.sqlcipher.SQLiteDatabase +import net.zetetic.database.sqlcipher.SQLiteDatabaseHook import java.util.concurrent.locks.ReentrantLock @@ -31,6 +34,23 @@ class PretixScan : MultiDexApplication() { var flipperInit: FlipperInitializer.IntializationResult? = null lateinit var connectivityHelper: ConnectivityHelper + private fun migrateSqlCipher() { + val dbPass = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) KeystoreHelper.secureValue(KEYSTORE_PASSWORD, true) + else KEYSTORE_PASSWORD + + System.loadLibrary("sqlcipher") + + val databaseFile = getDatabasePath(Models.DEFAULT.name) + SQLiteDatabase.openOrCreateDatabase(databaseFile, dbPass, null, null, object: SQLiteDatabaseHook { + override fun preKey(connection: SQLiteConnection) { + } + + override fun postKey(connection: SQLiteConnection) { + connection.execute("PRAGMA cipher_migrate;", emptyArray(), null) + } + }) + } + val data: BlockingEntityStore get() { if (dataStore == null) { @@ -44,18 +64,33 @@ class PretixScan : MultiDexApplication() { val dbPass = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) KeystoreHelper.secureValue(KEYSTORE_PASSWORD, true) else KEYSTORE_PASSWORD - var source = SqlCipherDatabaseSource(this, - Models.DEFAULT, Models.DEFAULT.getName(), dbPass, Migrations.CURRENT_VERSION) + var source = SqlCipherDatabaseSource( + this, + Models.DEFAULT, + Models.DEFAULT.name, + dbPass, + Migrations.CURRENT_VERSION + ) source.setLoggingEnabled(false) try { // check if database has been decrypted - source.readableDatabase.rawQuery("select count(*) from sqlite_master;", emptyArray()) //source.getReadableDatabase().getSyncedTables() ??? + source.readableDatabase.rawQuery("select count(*) from sqlite_master;", emptyArray()) } catch (e: SQLiteException) { - // if not, delete it - this.deleteDatabase(Models.DEFAULT.getName()) - // and create a new one - source = SqlCipherDatabaseSource(this, - Models.DEFAULT, Models.DEFAULT.getName(), dbPass, Migrations.CURRENT_VERSION) + try { + migrateSqlCipher() + source.readableDatabase.rawQuery("select count(*) from sqlite_master;", emptyArray()) + } catch (e: SQLiteException) { + // still not decrypted? then we probably lost the key due to a keystore issue + // let's start fresh, there's no reasonable other way to let the user out of this + this.deleteDatabase(Models.DEFAULT.getName()) + source = SqlCipherDatabaseSource( + this, + Models.DEFAULT, + Models.DEFAULT.name, + dbPass, + Migrations.CURRENT_VERSION + ) + } } val configuration = source.configuration diff --git a/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/db/SqlCipherDatabaseSource.kt b/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/db/SqlCipherDatabaseSource.kt index 4e9fc7b..b364316 100644 --- a/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/db/SqlCipherDatabaseSource.kt +++ b/pretixscan/app/src/main/java/eu/pretix/pretixscan/droid/db/SqlCipherDatabaseSource.kt @@ -38,7 +38,7 @@ import java.sql.Connection open class SqlCipherDatabaseSource(context: Context, private val model: EntityModel, name: String, - private val password: String, + password: String?, version: Int) : SQLiteOpenHelper(context, name, password, null, version, 0, null, null, true), DatabaseProvider {