Is there any tutorial or a recent working example ...
# squarelibraries
j
Is there any tutorial or a recent working example of SQLDelight and SqlCipher encryption in KMM application (or at least for Android)? I've seen NoteDelight on GitHub as an example, but they use outdated CWAC-SafeRoom library to connect Room to SQLDelight together with SqlCipher. When I try using it I get
file is encrypted or is not a database
error. The outdated library itself uses outdated
SqlCipher
version. Thanks.
👀 1
e
I've been using it with Android for 3+ years and it works fine. I'll see if there's anything I can share.
🙏 1
👀 1
j
@eygraber, is there still anything you could share? Thanks.
e
Copy code
private val configuration = SupportSQLiteOpenHelper
    .Configuration
    .builder(context)
    .callback(
      object : AndroidSqliteDriver.Callback(MyDatabase.Schema) {
        override fun onConfigure(db: SupportSQLiteDatabase) {
          super.onConfigure(db)

          db.enableWriteAheadLogging()

          // set it to false so migrations don't have to worry about it
          // we'll set it to true in onOpen
          db.setForeignKeyConstraintsEnabled(false)
        }

        override fun onOpen(db: SupportSQLiteDatabase) {
          super.onOpen(db)

          db.setForeignKeyConstraintsEnabled(true)
        }
      }
    )
    .name(MyDatabaseHelper.DATABASE_NAME)
    .build()
Copy code
private val standardHelper = object : net.sqlcipher.database.SQLiteOpenHelper(
    configuration.context,
    configuration.name,
    null,
    configuration.callback.version,
    null
  ) {
    override fun onCreate(db: SQLiteDatabase) {
      configuration.callback.onCreate(db)
    }

    override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
      configuration.callback.onUpgrade(db, oldVersion, newVersion)
    }

    override fun onDowngrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
      configuration.callback.onDowngrade(db, oldVersion, newVersion)
    }

    override fun onOpen(db: SQLiteDatabase) {
      configuration.callback.onOpen(db)
    }

    override fun onConfigure(db: SQLiteDatabase) {
      configuration.callback.onConfigure(db)
    }
  }

  init {
    SQLiteDatabase.loadLibs(configuration.context)
  }

  private var isPassphraseCleared = false

  private val passphrase = ...

  override val databaseName: String? = standardHelper.databaseName

  override fun setWriteAheadLoggingEnabled(enabled: Boolean) {
    standardHelper.setWriteAheadLoggingEnabled(enabled)
  }

  override val writableDatabase: SupportSQLiteDatabase = try {
    standardHelper.getWritableDatabase(passphrase).also {
      if(!isPassphraseCleared) {
        passphrase.fill(0.toByte())
        isPassphraseCleared = true
      }
    }
  }
  catch(ex: SQLiteException) {
    // we have some custom handling here
    throw ex
  }

  override val readableDatabase: SupportSQLiteDatabase = writableDatabase

  override fun close() {
    standardHelper.close()
  }
}
Copy code
app.cash.sqldelight.driver.android.AndroidSqliteDriver(standardHelper)
Some of that might be a little extra because I pulled this out of our DI glue, but that's the basic idea.
passphrase
is a
ByteArray