@tokamakdev/plugin-secure-storage 0.1.0-beta.49 → 0.1.0-beta.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,5 @@
1
1
  package com.tokamak.plugins.securestorage
2
2
 
3
- import android.app.Activity
4
3
  import android.hardware.biometrics.BiometricManager
5
4
  import android.hardware.biometrics.BiometricManager.Authenticators
6
5
  import android.hardware.biometrics.BiometricPrompt
@@ -12,6 +11,7 @@ import android.security.keystore.KeyProperties
12
11
  import android.security.keystore.StrongBoxUnavailableException
13
12
  import android.security.keystore.UserNotAuthenticatedException
14
13
  import android.util.AtomicFile
14
+ import com.tokamak.runtime.TokamakHost
15
15
  import com.tokamak.runtime.TokamakPlugin
16
16
  import com.tokamak.runtime.TokamakPluginError
17
17
  import com.tokamak.runtime.TokamakPluginReply
@@ -46,15 +46,16 @@ import org.json.JSONObject
46
46
  * carries the value's unlock and authentication requirements. Every write uses a new key
47
47
  * pair, identified in the value's file, so a failed write leaves the previous value readable.
48
48
  */
49
- internal class TokamakSecureStoragePlugin(
50
- private val activity: Activity,
49
+ class TokamakSecureStoragePlugin(
50
+ private val host: TokamakHost,
51
51
  ) : TokamakPlugin {
52
52
  override val id = "secure-storage"
53
53
 
54
+ private val context = host.context
54
55
  private val worker = Executors.newSingleThreadExecutor()
55
- private val directory = File(activity.noBackupFilesDir, "tokamak-secure-storage")
56
+ private val directory = File(context.noBackupFilesDir, "tokamak-secure-storage")
56
57
  private val keyStore = KeyStore.getInstance(KEYSTORE).apply { load(null) }
57
- private val biometrics = activity.getSystemService(BiometricManager::class.java)
58
+ private val biometrics = context.getSystemService(BiometricManager::class.java)
58
59
  private val random = SecureRandom()
59
60
 
60
61
  override fun call(method: String, arguments: Any?, reply: TokamakPluginReply) {
@@ -83,7 +84,7 @@ internal class TokamakSecureStoragePlugin(
83
84
  }
84
85
 
85
86
  private fun onUiThread(reply: TokamakPluginReply, operation: () -> Unit) =
86
- activity.runOnUiThread {
87
+ context.mainExecutor.execute {
87
88
  runCatching(operation).onFailure { reply(Result.failure(pluginError(it))) }
88
89
  }
89
90
 
@@ -200,8 +201,9 @@ internal class TokamakSecureStoragePlugin(
200
201
  stored: StoredValue,
201
202
  reply: TokamakPluginReply,
202
203
  ) {
204
+ val activity = host.activity ?: throw notVisible()
203
205
  val callback = PromptCallback(reply) { execute(reply) { reply(Result.success(open(stored, unwrap))) } }
204
- val title = prompt?.takeIf { it.isNotEmpty() } ?: activity.applicationInfo.loadLabel(activity.packageManager)
206
+ val title = prompt?.takeIf { it.isNotEmpty() } ?: context.applicationInfo.loadLabel(context.packageManager)
205
207
  val dialog =
206
208
  BiometricPrompt.Builder(activity)
207
209
  .setTitle(title)
@@ -346,6 +348,9 @@ internal class TokamakSecureStoragePlugin(
346
348
  fun notSetUp() =
347
349
  TokamakPluginError("InvalidStateError", "The requested authentication is not set up on this device")
348
350
 
351
+ fun notVisible() =
352
+ TokamakPluginError("InvalidStateError", "The app has no activity to show the authentication prompt in")
353
+
349
354
  fun pluginError(error: Throwable): TokamakPluginError =
350
355
  when (error) {
351
356
  is TokamakPluginError -> error
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>NSFaceIDUsageDescription</key>
6
+ <string>This app uses Face ID to confirm your identity.</string>
7
+ </dict>
8
+ </plist>
@@ -9,6 +9,8 @@ final class TokamakSecureStoragePlugin: TokamakPlugin {
9
9
  /// Keychain calls block while the system authentication prompt is shown.
10
10
  private let queue = DispatchQueue(label: "tokamak.secure-storage")
11
11
 
12
+ init(host: TokamakHost) {}
13
+
12
14
  private static let teamSigningRequired = TokamakPluginError.notSupported(
13
15
  "Secure storage requires a team-signed build"
14
16
  )
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokamakdev/plugin-secure-storage",
3
- "version": "0.1.0-beta.49",
3
+ "version": "0.1.0-beta.50",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/mantty/tokamak.git",
@@ -11,7 +11,7 @@
11
11
  ".": "./src/index.ts"
12
12
  },
13
13
  "dependencies": {
14
- "@tokamakdev/plugin": "0.1.0-beta.49"
14
+ "@tokamakdev/plugin": "0.1.0-beta.50"
15
15
  },
16
16
  "files": [
17
17
  "android",
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "id": "secure-storage",
4
- "kind": "frontend",
5
4
  "platforms": {
6
5
  "macos": {
7
6
  "class": "TokamakSecureStoragePlugin",
@@ -12,17 +11,13 @@
12
11
  "class": "TokamakSecureStoragePlugin",
13
12
  "sources": ["apple/SecureStoragePlugin.swift"],
14
13
  "frameworks": ["LocalAuthentication", "Security"],
15
- "plist": {
16
- "NSFaceIDUsageDescription": "This app uses Face ID to confirm your identity."
17
- }
14
+ "plist": "apple/Info.plist"
18
15
  },
19
16
  "ios-simulator": {
20
17
  "class": "TokamakSecureStoragePlugin",
21
18
  "sources": ["apple/SecureStoragePlugin.swift"],
22
19
  "frameworks": ["LocalAuthentication", "Security"],
23
- "plist": {
24
- "NSFaceIDUsageDescription": "This app uses Face ID to confirm your identity."
25
- }
20
+ "plist": "apple/Info.plist"
26
21
  },
27
22
  "android": {
28
23
  "class": "com.tokamak.plugins.securestorage.TokamakSecureStoragePlugin",