rusttaurirusqlite

Check if SQLCipher database is unlocked and ready


I'm currently connecting my local Tauri project with an SQLite DB via Rusqlite. The database is based on SQLCipher and I can create it without problems. But how to I use it? I want to unlock it and check whether it can be used or not (check integrity, etc...). But I am having problems with Rusqlite, as the docs are not very helpful in my opinion.

I have a command that is supposed to unlock and check the database:

// CRATE 1
pub fn get_connection_pool(pin: String) -> Result<Pool<SqliteConnectionManager>> {
    let db_dir = get_database_file(); // TODO: Use tauri app_handle to manage directories
    let manager = SqliteConnectionManager::file(db_dir.clone());

    let pool = Pool::new(manager).expect("Could not create Connection Pool Manager");
    let conn = pool.get().expect("Could not retrieve Connection from Pool");
    conn.pragma_update(None, "KEY", pin).expect("Could not execute pragma key");
    conn.pragma_update(None, "FOREIGN_KEYS", "ON")
        .expect("Could not execute PRAGMA foreign_keys=ON");

    info!("Retrieved database and prepared pool");

    Ok(pool)
}


// CRATE 2
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UnlockDatabaseData {
    pub pin: String,
}

#[tauri::command]
pub async fn unlock_database<R: Runtime>(
    app: tauri::AppHandle<R>,
    data: CommandValue<UnlockDatabaseData>,
) -> CommandResult<bool> {
    let db = get_connection_pool(data.values.pin);

    match db {
        Ok(database) => {
            let conn = database
                .get()
                .expect("Could not get database connection from pool");

            conn.execute("SELECT * FROM campaigns LIMIT 1", [])
                .expect("Could not perform integrity check on database");

            let state = AppState::new(database);
            app.manage(state);
            Ok(true)
        }
        Err(err) => Err(CommandError::Error(err)),
    }
}

The code above throws an error on this line:

conn.execute("SELECT * FROM campaigns LIMIT 1", [])
            .expect("Could not perform integrity check on database");

Saying: Could not perform integrity check on database: SqliteFailure(Error { code: NotADatabase, extended_code: 26 }, Some("file is not a database")) This means the database is not unlocked as I see it. But as you can see I am using PRAGMA Key when opening the connection.

Also the command still returns true to the frontend instead of an error.

Is there a better way to check for integrity and unlock status? (I know there are pragmas for both, though they did not seem to work as expected)


Solution

  • No, there is no better way.

    According to the documentation, there is no better way than to query the database:

    The only way to determine if the key is correct is to try to read from the database file. An incorrect key will result in a read error.