@onekeyfe/react-native-keychain-module 1.1.19 → 1.1.21

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.
@@ -21,6 +21,7 @@ Pod::Spec.new do |s|
21
21
 
22
22
  s.dependency 'React-jsi'
23
23
  s.dependency 'React-callinvoker'
24
+ s.dependency 'ReactNativeNativeLogger'
24
25
 
25
26
  load 'nitrogen/generated/ios/KeychainModule+autolinking.rb'
26
27
  add_nitrogen_files(s)
@@ -1,13 +1,12 @@
1
1
  import NitroModules
2
2
 
3
3
  class KeychainModule: HybridKeychainModuleSpec {
4
-
4
+
5
5
  private let moduleCore = KeychainModuleCore()
6
-
6
+
7
7
  public func setItem(params: SetItemParams) throws -> Promise<Void> {
8
- let typedParams = params
9
8
  do {
10
- try moduleCore.setItem(params: typedParams)
9
+ try moduleCore.setItem(params: params)
11
10
  return Promise.resolved(withResult: Void())
12
11
  } catch let error as KeychainModuleError {
13
12
  switch error {
@@ -22,11 +21,10 @@ class KeychainModule: HybridKeychainModuleSpec {
22
21
  return Promise.rejected(withError: NSError(domain: "keychain_set_error", code: -1000, userInfo: [NSLocalizedDescriptionKey: "Failed to set keychain item", NSUnderlyingErrorKey: error]))
23
22
  }
24
23
  }
25
-
24
+
26
25
  public func getItem(params : GetItemParams) throws -> Promise<Variant_NullType_GetItemResult> {
27
- let typedParams = params
28
26
  do {
29
- if let result = try moduleCore.getItem(params: typedParams) {
27
+ if let result = try moduleCore.getItem(params: params) {
30
28
  return Promise.resolved(withResult: Variant_NullType_GetItemResult.second(result))
31
29
  } else {
32
30
  return Promise.resolved(withResult: Variant_NullType_GetItemResult.first(NullType.null))
@@ -42,11 +40,10 @@ class KeychainModule: HybridKeychainModuleSpec {
42
40
  return Promise.rejected(withError: NSError(domain: "keychain_get_error", code: -1000, userInfo: [NSLocalizedDescriptionKey: "Failed to get keychain item", NSUnderlyingErrorKey: error]))
43
41
  }
44
42
  }
45
-
43
+
46
44
  public func removeItem(params: RemoveItemParams) throws -> Promise<Void> {
47
- let typedParams = params
48
45
  do {
49
- try moduleCore.removeItem(params: typedParams)
46
+ try moduleCore.removeItem(params: params)
50
47
  return Promise.resolved(withResult: Void())
51
48
  } catch let error as KeychainModuleError {
52
49
  switch error {
@@ -8,6 +8,7 @@
8
8
 
9
9
  import Foundation
10
10
  import Security
11
+ import ReactNativeNativeLogger
11
12
 
12
13
  // MARK: - Constants
13
14
 
@@ -33,10 +34,11 @@ class KeychainModuleCore {
33
34
 
34
35
  func setItem(params: SetItemParams) throws {
35
36
  guard let valueData = params.value.data(using: .utf8) else {
37
+ OneKeyLog.error("Keychain", "setItem: failed to encode value")
36
38
  throw KeychainModuleError.encodingFailed
37
39
  }
38
40
 
39
- let enableSync = params.enableSync ?? true // Default to enabled for iCloud sync
41
+ let enableSync = params.enableSync ?? true // Default to disabled; callers must explicitly opt in to iCloud sync
40
42
 
41
43
  var query: [String: Any] = [
42
44
  kSecClass as String: kSecClassGenericPassword,
@@ -57,14 +59,40 @@ class KeychainModuleCore {
57
59
  query[kSecAttrDescription as String] = description
58
60
  }
59
61
 
60
- // Delete existing item if it exists
61
- SecItemDelete(query as CFDictionary)
62
-
63
- // Add new item
62
+ // Try to add new item first; if it already exists, update it
64
63
  let status = SecItemAdd(query as CFDictionary, nil)
65
64
 
66
- guard status == errSecSuccess else {
67
- throw KeychainModuleError.operationFailed(status)
65
+ if status == errSecDuplicateItem {
66
+ // Item exists - update it instead of delete+add (avoids race condition window)
67
+ let searchQuery: [String: Any] = [
68
+ kSecClass as String: kSecClassGenericPassword,
69
+ kSecAttrService as String: KeychainConstants.serviceIdentifier ?? "",
70
+ kSecAttrAccount as String: params.key,
71
+ kSecAttrSynchronizable as String: kSecAttrSynchronizableAny
72
+ ]
73
+ var updateAttrs: [String: Any] = [
74
+ kSecValueData as String: valueData,
75
+ kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked,
76
+ kSecAttrSynchronizable as String: enableSync
77
+ ]
78
+ if let label = params.label {
79
+ updateAttrs[kSecAttrLabel as String] = label
80
+ }
81
+ if let description = params.description {
82
+ updateAttrs[kSecAttrDescription as String] = description
83
+ }
84
+ let updateStatus = SecItemUpdate(searchQuery as CFDictionary, updateAttrs as CFDictionary)
85
+ guard updateStatus == errSecSuccess else {
86
+ OneKeyLog.error("Keychain", "setItem update: failed, OSStatus: \(updateStatus)")
87
+ throw KeychainModuleError.operationFailed(updateStatus)
88
+ }
89
+ OneKeyLog.info("Keychain", "setItem: updated existing")
90
+ } else {
91
+ guard status == errSecSuccess else {
92
+ OneKeyLog.error("Keychain", "setItem: failed, OSStatus: \(status)")
93
+ throw KeychainModuleError.operationFailed(status)
94
+ }
95
+ OneKeyLog.info("Keychain", "setItem: success")
68
96
  }
69
97
  }
70
98
 
@@ -86,12 +114,15 @@ class KeychainModuleCore {
86
114
  if status == errSecSuccess {
87
115
  if let valueData = result as? Data,
88
116
  let value = String(data: valueData, encoding: .utf8) {
117
+ OneKeyLog.debug("Keychain", "getItem: found")
89
118
  return GetItemResult(key: params.key, value: value)
90
119
  }
91
120
  return nil
92
121
  } else if status == errSecItemNotFound {
122
+ OneKeyLog.debug("Keychain", "getItem: not found")
93
123
  return nil
94
124
  } else {
125
+ OneKeyLog.error("Keychain", "getItem: failed, OSStatus: \(status)")
95
126
  throw KeychainModuleError.operationFailed(status)
96
127
  }
97
128
  }
@@ -110,8 +141,10 @@ class KeychainModuleCore {
110
141
 
111
142
  // Both success and item not found are acceptable for delete
112
143
  guard status == errSecSuccess || status == errSecItemNotFound else {
144
+ OneKeyLog.error("Keychain", "removeItem: failed, OSStatus: \(status)")
113
145
  throw KeychainModuleError.operationFailed(status)
114
146
  }
147
+ OneKeyLog.info("Keychain", "removeItem: success")
115
148
  }
116
149
 
117
150
  // MARK: - Check Item Existence
@@ -126,6 +159,7 @@ class KeychainModuleCore {
126
159
  ]
127
160
 
128
161
  let status = SecItemCopyMatching(query as CFDictionary, nil)
162
+ OneKeyLog.debug("Keychain", "hasItem: \(status == errSecSuccess)")
129
163
  return status == errSecSuccess
130
164
  }
131
165
 
@@ -169,6 +203,8 @@ class KeychainModuleCore {
169
203
  // Common error codes:
170
204
  // errSecMissingEntitlement (-34018): Missing iCloud Keychain entitlement
171
205
  // errSecNotAvailable (-25291): iCloud Keychain not available/signed out
172
- return addStatus == errSecSuccess
206
+ let enabled = addStatus == errSecSuccess
207
+ OneKeyLog.info("Keychain", "iCloud sync check result: \(enabled)")
208
+ return enabled
173
209
  }
174
210
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/react-native-keychain-module",
3
- "version": "1.1.19",
3
+ "version": "1.1.21",
4
4
  "description": "react-native-keychain-module",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",