capacitor-community / sqlite

Community plugin for native & electron SQLite databases
MIT License
426 stars 104 forks source link

Keystore accessibility option for iOS based secret #522

Open codepushr opened 2 months ago

codepushr commented 2 months ago

Is your feature request related to a problem? Please describe. We are building an app that heavily relies on keystore access with the accessibility ".afterFirstUnlockThisDeviceOnly". This enables access after first unlock and prevents backups at all times. Using this plugin we can't set this accessibility option and our app can't access the db in closed and locked state (for example when receiving data push notifications).

Describe the solution you'd like Possibility to configure the accessibility option when setting/getting the database secret.

Describe alternatives you've considered Forking and setting it ourselves, however this plugin extension might be helpful for others too.

jepiqueau commented 2 months ago

@codepushr Thanks for this. The plugin provides a biometric login and methods to access the keystore (isSecretStored , setEncryptionSecret, changeEncryptionSecret, clearEncryptionSecret , checkEncryptionSecret)|. As i already explain in issue#480 the plugin cannot provides access to the database by background applications or data push notifications.

I could look at adding secure accessibility options but there are several

i will not provide

is that will sweet you?

jepiqueau commented 2 months ago

@codepushr this will be only for encrypted databases.

codepushr commented 2 months ago

Oh I didn't realize this. In that case accessing the keystore secret is not really necessary. I guess you can close the issue.

jepiqueau commented 2 months ago

@codepushr How you will send push notifications (from the device itself from a server ...) to the database application and what kind of payload will have your notification. I need to understand your scenario. May be it could be at your swift app itself you can manage the push notification.

codepushr commented 2 months ago

Remote push (server) -> launches terminated app in background -> app will get bootstrapped -> db init -> can't access keystore secret due to wrong accessibility.

However, if you say we can't access an encrypted SQLite db anyway from background with lockscreen, then this scenario is obsolete. Can you maybe elaborate what the exact limitations are and why we can't provide access to the db?

jepiqueau commented 2 months ago

@codepushr providing the accessibility mode is quite easy my problem where you can help describe is

codepushr commented 2 months ago

@jepiqueau I'm a bit confused by the response in issue #480 . The issue/author describes pretty much my scenario:

  1. App is terminated
  2. Phone in standby with lock screen
  3. App receives a push notification

In that case the app is being launched by the system for a brief time (30sec). My understanding from your response in #480 is, that due to some reasons access to the database is not possible? Or did I misunderstood?

jepiqueau commented 2 months ago

@codepushr it is but i may look at how to implement this and see the implications

codepushr commented 2 months ago

The data in the push is a simple JSON, later in the processing I'm using TypeORM to write to the underlying SQLite db. But all of this has nothing to do with the actual problem of this issue report.

To get back to my initial post, I encountered an exception when the plugin attempts to retrieve the secret from the iOS keystore when opening the db connection.

const sqliteService = new SQLiteService();
const sqliteConnection = sqliteService.getSqliteConnection(); // returns sqliteConnection

// TypeORM
export const AppDataSource = new DataSource({
  type: 'capacitor',
  driver: sqliteConnection,
  database: environment.get().databaseName,
  mode: 'secret',
  ...
})

This is because when .setEncryptionSecret() is called, the iOS native code is not setting a accessibility attribute and my app requires the kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly flag. The default does not allow access of the keychain without unlock.

// Models/KeychainServices.swift
let query: [String: Any] = [
    // 2
    kSecClass as String: kSecClassGenericPassword,
    // 3
    kSecAttrAccount as String: account, 
    // 4
    kSecAttrService as String: service, // "cap_sec"
    // 5
    kSecValueData as String: passwordData,
    // 6 --> missing 
    // kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
]

As for the explanation in #480 what were you referring to? In what other scenario we can't access the database?