@tokamakdev/plugin-secure-storage 0.1.0-beta.84 → 0.1.0-beta.85

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.
@@ -38,18 +38,19 @@ final class TokamakSecureStoragePlugin: TokamakPlugin {
38
38
  reply: @escaping TokamakPluginReply
39
39
  ) {
40
40
  let arguments = arguments as? [String: Any] ?? [:]
41
- let unlocked = Self.isUnlocked
41
+ let prompting =
42
+ isUnlocked ? Result { () throws(TokamakPluginError) in try host.requireUI() } : nil
42
43
  queue.async {
43
44
  reply(
44
45
  Result { () throws(TokamakPluginError) in
45
- try self.perform(method, arguments, unlocked: unlocked)
46
+ try self.perform(method, arguments, prompting: prompting)
46
47
  })
47
48
  }
48
49
  }
49
50
 
50
51
  /// Whether the device's protected data is available, which it is not while
51
52
  /// an iPhone is locked. Read it on the main thread.
52
- private static var isUnlocked: Bool {
53
+ private var isUnlocked: Bool {
53
54
  #if os(iOS)
54
55
  UIApplication.shared.isProtectedDataAvailable
55
56
  #else
@@ -57,10 +58,13 @@ final class TokamakSecureStoragePlugin: TokamakPlugin {
57
58
  #endif
58
59
  }
59
60
 
61
+ /// `prompting` is whether a read that needs authentication may show the
62
+ /// system prompt, decided on the main thread as the call arrives: nil while
63
+ /// the device is locked, where such a read fails without UI anyway.
60
64
  private func perform(
61
65
  _ method: String,
62
66
  _ arguments: [String: Any],
63
- unlocked: Bool
67
+ prompting: Result<Void, TokamakPluginError>?
64
68
  ) throws(TokamakPluginError) -> Any? {
65
69
  #if os(macOS)
66
70
  // Unentitled reads report errSecItemNotFound rather than a missing entitlement.
@@ -82,7 +86,7 @@ final class TokamakSecureStoragePlugin: TokamakPlugin {
82
86
  return try get(
83
87
  requiredString(arguments, "name"),
84
88
  prompt: optionalString(arguments, "prompt"),
85
- unlocked: unlocked
89
+ prompting: prompting
86
90
  )
87
91
  case "delete":
88
92
  try deleteItems(query(requiredString(arguments, "name")))
@@ -121,20 +125,19 @@ final class TokamakSecureStoragePlugin: TokamakPlugin {
121
125
  }
122
126
 
123
127
  /// Reads without UI first, so only a value saved with authentication needs
124
- /// the app able to show the system prompt. While the device is locked, the
125
- /// read fails without UI whatever the value needs.
128
+ /// the app able to show the system prompt.
126
129
  private func get(
127
130
  _ name: String,
128
131
  prompt: String?,
129
- unlocked: Bool
132
+ prompting: Result<Void, TokamakPluginError>?
130
133
  ) throws(TokamakPluginError) -> String? {
131
134
  var item = query(name)
132
135
  item[kSecReturnData] = true
133
136
  item[kSecUseAuthenticationContext] = Self.contextWithoutUI()
134
137
  var data: CFTypeRef?
135
138
  var status = SecItemCopyMatching(item as CFDictionary, &data)
136
- if status == errSecInteractionNotAllowed && unlocked {
137
- try host.requireUI()
139
+ if status == errSecInteractionNotAllowed, let prompting {
140
+ try prompting.get()
138
141
  item[kSecUseAuthenticationContext] = prompt.flatMap { prompt -> LAContext? in
139
142
  guard !prompt.isEmpty else { return nil }
140
143
  let context = LAContext()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokamakdev/plugin-secure-storage",
3
- "version": "0.1.0-beta.84",
3
+ "version": "0.1.0-beta.85",
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
  "peerDependencies": {
14
- "@tokamakdev/plugin": "0.1.0-beta.84"
14
+ "@tokamakdev/plugin": "0.1.0-beta.85"
15
15
  },
16
16
  "files": [
17
17
  "android",