react-native-nitro-storage 0.1.4 → 0.3.1

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.
Files changed (48) hide show
  1. package/README.md +432 -345
  2. package/android/src/main/cpp/AndroidStorageAdapterCpp.cpp +191 -3
  3. package/android/src/main/cpp/AndroidStorageAdapterCpp.hpp +21 -41
  4. package/android/src/main/java/com/nitrostorage/AndroidStorageAdapter.kt +181 -29
  5. package/android/src/main/java/com/nitrostorage/NitroStoragePackage.kt +2 -2
  6. package/app.plugin.js +9 -7
  7. package/cpp/bindings/HybridStorage.cpp +239 -10
  8. package/cpp/bindings/HybridStorage.hpp +10 -0
  9. package/cpp/core/NativeStorageAdapter.hpp +22 -0
  10. package/ios/IOSStorageAdapterCpp.hpp +25 -0
  11. package/ios/IOSStorageAdapterCpp.mm +315 -33
  12. package/lib/commonjs/Storage.types.js +23 -1
  13. package/lib/commonjs/Storage.types.js.map +1 -1
  14. package/lib/commonjs/index.js +680 -68
  15. package/lib/commonjs/index.js.map +1 -1
  16. package/lib/commonjs/index.web.js +801 -133
  17. package/lib/commonjs/index.web.js.map +1 -1
  18. package/lib/commonjs/internal.js +112 -0
  19. package/lib/commonjs/internal.js.map +1 -0
  20. package/lib/module/Storage.types.js +22 -0
  21. package/lib/module/Storage.types.js.map +1 -1
  22. package/lib/module/index.js +660 -71
  23. package/lib/module/index.js.map +1 -1
  24. package/lib/module/index.web.js +766 -125
  25. package/lib/module/index.web.js.map +1 -1
  26. package/lib/module/internal.js +100 -0
  27. package/lib/module/internal.js.map +1 -0
  28. package/lib/typescript/Storage.nitro.d.ts +10 -0
  29. package/lib/typescript/Storage.nitro.d.ts.map +1 -1
  30. package/lib/typescript/Storage.types.d.ts +20 -0
  31. package/lib/typescript/Storage.types.d.ts.map +1 -1
  32. package/lib/typescript/index.d.ts +68 -9
  33. package/lib/typescript/index.d.ts.map +1 -1
  34. package/lib/typescript/index.web.d.ts +79 -13
  35. package/lib/typescript/index.web.d.ts.map +1 -1
  36. package/lib/typescript/internal.d.ts +21 -0
  37. package/lib/typescript/internal.d.ts.map +1 -0
  38. package/lib/typescript/migration.d.ts +2 -3
  39. package/lib/typescript/migration.d.ts.map +1 -1
  40. package/nitrogen/generated/shared/c++/HybridStorageSpec.cpp +10 -0
  41. package/nitrogen/generated/shared/c++/HybridStorageSpec.hpp +10 -0
  42. package/package.json +22 -8
  43. package/src/Storage.nitro.ts +11 -2
  44. package/src/Storage.types.ts +22 -0
  45. package/src/index.ts +943 -84
  46. package/src/index.web.ts +1082 -137
  47. package/src/internal.ts +144 -0
  48. package/src/migration.ts +3 -3
@@ -1,38 +1,174 @@
1
1
  #import "IOSStorageAdapterCpp.hpp"
2
2
  #import <Foundation/Foundation.h>
3
3
  #import <Security/Security.h>
4
+ #import <LocalAuthentication/LocalAuthentication.h>
5
+ #include <algorithm>
4
6
 
5
7
  namespace NitroStorage {
6
8
 
7
9
  static NSString* const kKeychainService = @"com.nitrostorage.keychain";
10
+ static NSString* const kBiometricKeychainService = @"com.nitrostorage.biometric";
11
+ static NSString* const kDiskSuiteName = @"com.nitrostorage.disk";
12
+
13
+ static NSUserDefaults* NitroDiskDefaults() {
14
+ static NSUserDefaults* defaults = [[NSUserDefaults alloc] initWithSuiteName:kDiskSuiteName];
15
+ return defaults ?: [NSUserDefaults standardUserDefaults];
16
+ }
17
+
18
+ static CFStringRef accessControlAttr(int level) {
19
+ switch (level) {
20
+ case 1: return kSecAttrAccessibleAfterFirstUnlock;
21
+ case 2: return kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly;
22
+ case 3: return kSecAttrAccessibleWhenUnlockedThisDeviceOnly;
23
+ case 4: return kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
24
+ default: return kSecAttrAccessibleWhenUnlocked;
25
+ }
26
+ }
8
27
 
9
28
  IOSStorageAdapterCpp::IOSStorageAdapterCpp() {}
10
29
  IOSStorageAdapterCpp::~IOSStorageAdapterCpp() {}
11
30
 
31
+ // --- Disk ---
32
+
12
33
  void IOSStorageAdapterCpp::setDisk(const std::string& key, const std::string& value) {
13
- [[NSUserDefaults standardUserDefaults] setObject:[NSString stringWithUTF8String:value.c_str()]
14
- forKey:[NSString stringWithUTF8String:key.c_str()]];
34
+ NSString* nsKey = [NSString stringWithUTF8String:key.c_str()];
35
+ NSString* nsValue = [NSString stringWithUTF8String:value.c_str()];
36
+ NSUserDefaults* defaults = NitroDiskDefaults();
37
+ [defaults setObject:nsValue forKey:nsKey];
38
+ [[NSUserDefaults standardUserDefaults] removeObjectForKey:nsKey];
15
39
  }
16
40
 
17
41
  std::optional<std::string> IOSStorageAdapterCpp::getDisk(const std::string& key) {
18
- NSString* result = [[NSUserDefaults standardUserDefaults] stringForKey:[NSString stringWithUTF8String:key.c_str()]];
42
+ NSString* nsKey = [NSString stringWithUTF8String:key.c_str()];
43
+ NSUserDefaults* defaults = NitroDiskDefaults();
44
+ NSString* result = [defaults stringForKey:nsKey];
45
+
46
+ if (!result) {
47
+ NSUserDefaults* legacyDefaults = [NSUserDefaults standardUserDefaults];
48
+ NSString* legacyValue = [legacyDefaults stringForKey:nsKey];
49
+ if (legacyValue) {
50
+ [defaults setObject:legacyValue forKey:nsKey];
51
+ [legacyDefaults removeObjectForKey:nsKey];
52
+ result = legacyValue;
53
+ }
54
+ }
55
+
19
56
  if (!result) return std::nullopt;
20
57
  return std::string([result UTF8String]);
21
58
  }
22
59
 
23
60
  void IOSStorageAdapterCpp::deleteDisk(const std::string& key) {
24
- [[NSUserDefaults standardUserDefaults] removeObjectForKey:[NSString stringWithUTF8String:key.c_str()]];
61
+ NSString* nsKey = [NSString stringWithUTF8String:key.c_str()];
62
+ [NitroDiskDefaults() removeObjectForKey:nsKey];
63
+ [[NSUserDefaults standardUserDefaults] removeObjectForKey:nsKey];
25
64
  }
26
65
 
27
- void IOSStorageAdapterCpp::setSecure(const std::string& key, const std::string& value) {
66
+ bool IOSStorageAdapterCpp::hasDisk(const std::string& key) {
28
67
  NSString* nsKey = [NSString stringWithUTF8String:key.c_str()];
29
- NSData* data = [[NSString stringWithUTF8String:value.c_str()] dataUsingEncoding:NSUTF8StringEncoding];
68
+ return [NitroDiskDefaults() objectForKey:nsKey] != nil;
69
+ }
30
70
 
31
- NSDictionary* query = @{
71
+ std::vector<std::string> IOSStorageAdapterCpp::getAllKeysDisk() {
72
+ NSDictionary<NSString*, id>* entries = [NitroDiskDefaults() dictionaryRepresentation];
73
+ std::vector<std::string> keys;
74
+ keys.reserve(entries.count);
75
+ for (NSString* key in entries) {
76
+ keys.push_back(std::string([key UTF8String]));
77
+ }
78
+ return keys;
79
+ }
80
+
81
+ size_t IOSStorageAdapterCpp::sizeDisk() {
82
+ return [NitroDiskDefaults() dictionaryRepresentation].count;
83
+ }
84
+
85
+ void IOSStorageAdapterCpp::setDiskBatch(
86
+ const std::vector<std::string>& keys,
87
+ const std::vector<std::string>& values
88
+ ) {
89
+ NSUserDefaults* defaults = NitroDiskDefaults();
90
+ for (size_t i = 0; i < keys.size() && i < values.size(); ++i) {
91
+ NSString* nsKey = [NSString stringWithUTF8String:keys[i].c_str()];
92
+ NSString* nsValue = [NSString stringWithUTF8String:values[i].c_str()];
93
+ [defaults setObject:nsValue forKey:nsKey];
94
+ [[NSUserDefaults standardUserDefaults] removeObjectForKey:nsKey];
95
+ }
96
+ }
97
+
98
+ std::vector<std::optional<std::string>> IOSStorageAdapterCpp::getDiskBatch(
99
+ const std::vector<std::string>& keys
100
+ ) {
101
+ std::vector<std::optional<std::string>> results;
102
+ results.reserve(keys.size());
103
+ for (const auto& key : keys) {
104
+ results.push_back(getDisk(key));
105
+ }
106
+ return results;
107
+ }
108
+
109
+ void IOSStorageAdapterCpp::deleteDiskBatch(const std::vector<std::string>& keys) {
110
+ for (const auto& key : keys) {
111
+ deleteDisk(key);
112
+ }
113
+ }
114
+
115
+ void IOSStorageAdapterCpp::clearDisk() {
116
+ NSUserDefaults* defaults = NitroDiskDefaults();
117
+ NSDictionary<NSString*, id>* entries = [defaults dictionaryRepresentation];
118
+ for (NSString* key in entries) {
119
+ [defaults removeObjectForKey:key];
120
+ }
121
+ }
122
+
123
+ // --- Secure (Keychain) ---
124
+
125
+ static NSMutableDictionary* baseKeychainQuery(NSString* key, NSString* service, NSString* accessGroup) {
126
+ NSMutableDictionary* query = [@{
32
127
  (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
33
- (__bridge id)kSecAttrService: kKeychainService,
34
- (__bridge id)kSecAttrAccount: nsKey
35
- };
128
+ (__bridge id)kSecAttrService: service,
129
+ (__bridge id)kSecAttrAccount: key
130
+ } mutableCopy];
131
+ if (accessGroup && accessGroup.length > 0) {
132
+ query[(__bridge id)kSecAttrAccessGroup] = accessGroup;
133
+ }
134
+ return query;
135
+ }
136
+
137
+ static NSMutableDictionary* allAccountsQuery(NSString* service, NSString* accessGroup) {
138
+ NSMutableDictionary* query = [@{
139
+ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
140
+ (__bridge id)kSecAttrService: service,
141
+ (__bridge id)kSecReturnAttributes: @YES,
142
+ (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitAll
143
+ } mutableCopy];
144
+ if (accessGroup && accessGroup.length > 0) {
145
+ query[(__bridge id)kSecAttrAccessGroup] = accessGroup;
146
+ }
147
+ return query;
148
+ }
149
+
150
+ static std::vector<std::string> keychainAccountsForService(NSString* service, NSString* accessGroup) {
151
+ NSMutableDictionary* query = allAccountsQuery(service, accessGroup);
152
+ CFTypeRef result = NULL;
153
+ std::vector<std::string> keys;
154
+ if (SecItemCopyMatching((__bridge CFDictionaryRef)query, &result) == errSecSuccess && result) {
155
+ NSArray* items = (__bridge_transfer NSArray*)result;
156
+ keys.reserve(items.count);
157
+ for (NSDictionary* item in items) {
158
+ NSString* account = item[(__bridge id)kSecAttrAccount];
159
+ if (account) {
160
+ keys.push_back(std::string([account UTF8String]));
161
+ }
162
+ }
163
+ }
164
+ return keys;
165
+ }
166
+
167
+ void IOSStorageAdapterCpp::setSecure(const std::string& key, const std::string& value) {
168
+ NSString* nsKey = [NSString stringWithUTF8String:key.c_str()];
169
+ NSData* data = [[NSString stringWithUTF8String:value.c_str()] dataUsingEncoding:NSUTF8StringEncoding];
170
+ NSString* group = keychainAccessGroup_.empty() ? nil : [NSString stringWithUTF8String:keychainAccessGroup_.c_str()];
171
+ NSMutableDictionary* query = baseKeychainQuery(nsKey, kKeychainService, group);
36
172
 
37
173
  NSDictionary* updateAttributes = @{
38
174
  (__bridge id)kSecValueData: data
@@ -41,21 +177,18 @@ void IOSStorageAdapterCpp::setSecure(const std::string& key, const std::string&
41
177
  OSStatus status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)updateAttributes);
42
178
 
43
179
  if (status == errSecItemNotFound) {
44
- NSMutableDictionary* addQuery = [query mutableCopy];
45
- addQuery[(__bridge id)kSecValueData] = data;
46
- addQuery[(__bridge id)kSecAttrAccessible] = (__bridge id)kSecAttrAccessibleWhenUnlocked;
47
- SecItemAdd((__bridge CFDictionaryRef)addQuery, NULL);
180
+ query[(__bridge id)kSecValueData] = data;
181
+ query[(__bridge id)kSecAttrAccessible] = (__bridge id)accessControlAttr(accessControlLevel_);
182
+ SecItemAdd((__bridge CFDictionaryRef)query, NULL);
48
183
  }
49
184
  }
50
185
 
51
186
  std::optional<std::string> IOSStorageAdapterCpp::getSecure(const std::string& key) {
52
- NSDictionary* query = @{
53
- (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
54
- (__bridge id)kSecAttrService: kKeychainService,
55
- (__bridge id)kSecAttrAccount: [NSString stringWithUTF8String:key.c_str()],
56
- (__bridge id)kSecReturnData: @YES,
57
- (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne
58
- };
187
+ NSString* nsKey = [NSString stringWithUTF8String:key.c_str()];
188
+ NSString* group = keychainAccessGroup_.empty() ? nil : [NSString stringWithUTF8String:keychainAccessGroup_.c_str()];
189
+ NSMutableDictionary* query = baseKeychainQuery(nsKey, kKeychainService, group);
190
+ query[(__bridge id)kSecReturnData] = @YES;
191
+ query[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;
59
192
 
60
193
  CFTypeRef result = NULL;
61
194
  if (SecItemCopyMatching((__bridge CFDictionaryRef)query, &result) == errSecSuccess && result) {
@@ -67,26 +200,175 @@ std::optional<std::string> IOSStorageAdapterCpp::getSecure(const std::string& ke
67
200
  }
68
201
 
69
202
  void IOSStorageAdapterCpp::deleteSecure(const std::string& key) {
70
- NSDictionary* query = @{
71
- (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
72
- (__bridge id)kSecAttrService: kKeychainService,
73
- (__bridge id)kSecAttrAccount: [NSString stringWithUTF8String:key.c_str()]
74
- };
75
- SecItemDelete((__bridge CFDictionaryRef)query);
203
+ NSString* nsKey = [NSString stringWithUTF8String:key.c_str()];
204
+ NSString* group = keychainAccessGroup_.empty() ? nil : [NSString stringWithUTF8String:keychainAccessGroup_.c_str()];
205
+ NSMutableDictionary* secureQuery = baseKeychainQuery(nsKey, kKeychainService, group);
206
+ SecItemDelete((__bridge CFDictionaryRef)secureQuery);
207
+ NSMutableDictionary* biometricQuery = baseKeychainQuery(nsKey, kBiometricKeychainService, group);
208
+ SecItemDelete((__bridge CFDictionaryRef)biometricQuery);
76
209
  }
77
210
 
78
- void IOSStorageAdapterCpp::clearDisk() {
79
- NSString* appDomain = [[NSBundle mainBundle] bundleIdentifier];
80
- if (appDomain) {
81
- [[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];
211
+ bool IOSStorageAdapterCpp::hasSecure(const std::string& key) {
212
+ NSString* nsKey = [NSString stringWithUTF8String:key.c_str()];
213
+ NSString* group = keychainAccessGroup_.empty() ? nil : [NSString stringWithUTF8String:keychainAccessGroup_.c_str()];
214
+ NSMutableDictionary* secureQuery = baseKeychainQuery(nsKey, kKeychainService, group);
215
+ if (SecItemCopyMatching((__bridge CFDictionaryRef)secureQuery, NULL) == errSecSuccess) {
216
+ return true;
217
+ }
218
+ NSMutableDictionary* biometricQuery = baseKeychainQuery(nsKey, kBiometricKeychainService, group);
219
+ return SecItemCopyMatching((__bridge CFDictionaryRef)biometricQuery, NULL) == errSecSuccess;
220
+ }
221
+
222
+ std::vector<std::string> IOSStorageAdapterCpp::getAllKeysSecure() {
223
+ NSString* group = keychainAccessGroup_.empty() ? nil : [NSString stringWithUTF8String:keychainAccessGroup_.c_str()];
224
+ std::vector<std::string> keys = keychainAccountsForService(kKeychainService, group);
225
+ const std::vector<std::string> biometricKeys = keychainAccountsForService(kBiometricKeychainService, group);
226
+ for (const auto& key : biometricKeys) {
227
+ if (std::find(keys.begin(), keys.end(), key) == keys.end()) {
228
+ keys.push_back(key);
229
+ }
230
+ }
231
+ return keys;
232
+ }
233
+
234
+ size_t IOSStorageAdapterCpp::sizeSecure() {
235
+ return getAllKeysSecure().size();
236
+ }
237
+
238
+ void IOSStorageAdapterCpp::setSecureBatch(
239
+ const std::vector<std::string>& keys,
240
+ const std::vector<std::string>& values
241
+ ) {
242
+ for (size_t i = 0; i < keys.size() && i < values.size(); ++i) {
243
+ setSecure(keys[i], values[i]);
244
+ }
245
+ }
246
+
247
+ std::vector<std::optional<std::string>> IOSStorageAdapterCpp::getSecureBatch(
248
+ const std::vector<std::string>& keys
249
+ ) {
250
+ std::vector<std::optional<std::string>> results;
251
+ results.reserve(keys.size());
252
+ for (const auto& key : keys) {
253
+ results.push_back(getSecure(key));
254
+ }
255
+ return results;
256
+ }
257
+
258
+ void IOSStorageAdapterCpp::deleteSecureBatch(const std::vector<std::string>& keys) {
259
+ for (const auto& key : keys) {
260
+ deleteSecure(key);
82
261
  }
83
262
  }
84
263
 
85
264
  void IOSStorageAdapterCpp::clearSecure() {
86
- NSDictionary* query = @{
265
+ NSString* group = keychainAccessGroup_.empty() ? nil : [NSString stringWithUTF8String:keychainAccessGroup_.c_str()];
266
+ NSMutableDictionary* secureQuery = [@{
87
267
  (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
88
268
  (__bridge id)kSecAttrService: kKeychainService
89
- };
269
+ } mutableCopy];
270
+ if (group && group.length > 0) {
271
+ secureQuery[(__bridge id)kSecAttrAccessGroup] = group;
272
+ }
273
+ SecItemDelete((__bridge CFDictionaryRef)secureQuery);
274
+
275
+ NSMutableDictionary* biometricQuery = [@{
276
+ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
277
+ (__bridge id)kSecAttrService: kBiometricKeychainService
278
+ } mutableCopy];
279
+ if (group && group.length > 0) {
280
+ biometricQuery[(__bridge id)kSecAttrAccessGroup] = group;
281
+ }
282
+ SecItemDelete((__bridge CFDictionaryRef)biometricQuery);
283
+ }
284
+
285
+ // --- Configuration ---
286
+
287
+ void IOSStorageAdapterCpp::setSecureAccessControl(int level) {
288
+ accessControlLevel_ = level;
289
+ }
290
+
291
+ void IOSStorageAdapterCpp::setKeychainAccessGroup(const std::string& group) {
292
+ keychainAccessGroup_ = group;
293
+ }
294
+
295
+ // --- Biometric (separate Keychain service with biometric ACL) ---
296
+
297
+ void IOSStorageAdapterCpp::setSecureBiometric(const std::string& key, const std::string& value) {
298
+ NSString* nsKey = [NSString stringWithUTF8String:key.c_str()];
299
+ NSData* data = [[NSString stringWithUTF8String:value.c_str()] dataUsingEncoding:NSUTF8StringEncoding];
300
+ NSString* group = keychainAccessGroup_.empty() ? nil : [NSString stringWithUTF8String:keychainAccessGroup_.c_str()];
301
+
302
+ // Delete existing item first (access control can't be updated in place)
303
+ NSMutableDictionary* deleteQuery = baseKeychainQuery(nsKey, kBiometricKeychainService, group);
304
+ SecItemDelete((__bridge CFDictionaryRef)deleteQuery);
305
+
306
+ CFErrorRef error = NULL;
307
+ SecAccessControlRef access = SecAccessControlCreateWithFlags(
308
+ kCFAllocatorDefault,
309
+ kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
310
+ kSecAccessControlBiometryCurrentSet,
311
+ &error
312
+ );
313
+
314
+ if (error || !access) {
315
+ if (access) CFRelease(access);
316
+ throw std::runtime_error("NitroStorage: Failed to create biometric access control");
317
+ }
318
+
319
+ NSMutableDictionary* attrs = baseKeychainQuery(nsKey, kBiometricKeychainService, group);
320
+ attrs[(__bridge id)kSecValueData] = data;
321
+ attrs[(__bridge id)kSecAttrAccessControl] = (__bridge_transfer id)access;
322
+
323
+ OSStatus status = SecItemAdd((__bridge CFDictionaryRef)attrs, NULL);
324
+ if (status != errSecSuccess) {
325
+ throw std::runtime_error("NitroStorage: Biometric set failed with status " + std::to_string(status));
326
+ }
327
+ }
328
+
329
+ std::optional<std::string> IOSStorageAdapterCpp::getSecureBiometric(const std::string& key) {
330
+ NSString* nsKey = [NSString stringWithUTF8String:key.c_str()];
331
+ NSString* group = keychainAccessGroup_.empty() ? nil : [NSString stringWithUTF8String:keychainAccessGroup_.c_str()];
332
+ NSMutableDictionary* query = baseKeychainQuery(nsKey, kBiometricKeychainService, group);
333
+ query[(__bridge id)kSecReturnData] = @YES;
334
+ query[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;
335
+
336
+ CFTypeRef result = NULL;
337
+ OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
338
+ if (status == errSecSuccess && result) {
339
+ NSData* data = (__bridge_transfer NSData*)result;
340
+ NSString* str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
341
+ if (str) return std::string([str UTF8String]);
342
+ }
343
+ if (status == errSecUserCanceled || status == errSecAuthFailed) {
344
+ throw std::runtime_error("NitroStorage: Biometric authentication failed");
345
+ }
346
+ return std::nullopt;
347
+ }
348
+
349
+ void IOSStorageAdapterCpp::deleteSecureBiometric(const std::string& key) {
350
+ NSString* nsKey = [NSString stringWithUTF8String:key.c_str()];
351
+ NSString* group = keychainAccessGroup_.empty() ? nil : [NSString stringWithUTF8String:keychainAccessGroup_.c_str()];
352
+ NSMutableDictionary* query = baseKeychainQuery(nsKey, kBiometricKeychainService, group);
353
+ SecItemDelete((__bridge CFDictionaryRef)query);
354
+ }
355
+
356
+ bool IOSStorageAdapterCpp::hasSecureBiometric(const std::string& key) {
357
+ NSString* nsKey = [NSString stringWithUTF8String:key.c_str()];
358
+ NSString* group = keychainAccessGroup_.empty() ? nil : [NSString stringWithUTF8String:keychainAccessGroup_.c_str()];
359
+ NSMutableDictionary* query = baseKeychainQuery(nsKey, kBiometricKeychainService, group);
360
+ return SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL) == errSecSuccess;
361
+ }
362
+
363
+ void IOSStorageAdapterCpp::clearSecureBiometric() {
364
+ NSString* group = keychainAccessGroup_.empty() ? nil : [NSString stringWithUTF8String:keychainAccessGroup_.c_str()];
365
+ NSMutableDictionary* query = [@{
366
+ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
367
+ (__bridge id)kSecAttrService: kBiometricKeychainService
368
+ } mutableCopy];
369
+ if (group && group.length > 0) {
370
+ query[(__bridge id)kSecAttrAccessGroup] = group;
371
+ }
90
372
  SecItemDelete((__bridge CFDictionaryRef)query);
91
373
  }
92
374
 
@@ -3,11 +3,33 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.StorageScope = void 0;
6
+ exports.StorageScope = exports.BiometricLevel = exports.AccessControl = void 0;
7
7
  let StorageScope = exports.StorageScope = /*#__PURE__*/function (StorageScope) {
8
8
  StorageScope[StorageScope["Memory"] = 0] = "Memory";
9
9
  StorageScope[StorageScope["Disk"] = 1] = "Disk";
10
10
  StorageScope[StorageScope["Secure"] = 2] = "Secure";
11
11
  return StorageScope;
12
12
  }({});
13
+ let AccessControl = exports.AccessControl = /*#__PURE__*/function (AccessControl) {
14
+ /** Accessible when unlocked (default). */
15
+ AccessControl[AccessControl["WhenUnlocked"] = 0] = "WhenUnlocked";
16
+ /** Accessible after first unlock until restart. Good for background token refresh. */
17
+ AccessControl[AccessControl["AfterFirstUnlock"] = 1] = "AfterFirstUnlock";
18
+ /** Accessible only when passcode is set, non-migratable. */
19
+ AccessControl[AccessControl["WhenPasscodeSetThisDeviceOnly"] = 2] = "WhenPasscodeSetThisDeviceOnly";
20
+ /** Same as WhenUnlocked but non-migratable between devices. */
21
+ AccessControl[AccessControl["WhenUnlockedThisDeviceOnly"] = 3] = "WhenUnlockedThisDeviceOnly";
22
+ /** Same as AfterFirstUnlock but non-migratable. */
23
+ AccessControl[AccessControl["AfterFirstUnlockThisDeviceOnly"] = 4] = "AfterFirstUnlockThisDeviceOnly";
24
+ return AccessControl;
25
+ }({});
26
+ let BiometricLevel = exports.BiometricLevel = /*#__PURE__*/function (BiometricLevel) {
27
+ /** No biometric requirement (default). */
28
+ BiometricLevel[BiometricLevel["None"] = 0] = "None";
29
+ /** Require biometric or passcode for each access. */
30
+ BiometricLevel[BiometricLevel["BiometryOrPasscode"] = 1] = "BiometryOrPasscode";
31
+ /** Require biometric only (no passcode fallback). */
32
+ BiometricLevel[BiometricLevel["BiometryOnly"] = 2] = "BiometryOnly";
33
+ return BiometricLevel;
34
+ }({});
13
35
  //# sourceMappingURL=Storage.types.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["StorageScope","exports"],"sourceRoot":"../../src","sources":["Storage.types.ts"],"mappings":";;;;;;IAAYA,YAAY,GAAAC,OAAA,CAAAD,YAAA,0BAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAA,OAAZA,YAAY;AAAA","ignoreList":[]}
1
+ {"version":3,"names":["StorageScope","exports","AccessControl","BiometricLevel"],"sourceRoot":"../../src","sources":["Storage.types.ts"],"mappings":";;;;;;IAAYA,YAAY,GAAAC,OAAA,CAAAD,YAAA,0BAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAZA,YAAY,CAAZA,YAAY;EAAA,OAAZA,YAAY;AAAA;AAAA,IAMZE,aAAa,GAAAD,OAAA,CAAAC,aAAA,0BAAbA,aAAa;EACvB;EADUA,aAAa,CAAbA,aAAa;EAGvB;EAHUA,aAAa,CAAbA,aAAa;EAKvB;EALUA,aAAa,CAAbA,aAAa;EAOvB;EAPUA,aAAa,CAAbA,aAAa;EASvB;EATUA,aAAa,CAAbA,aAAa;EAAA,OAAbA,aAAa;AAAA;AAAA,IAabC,cAAc,GAAAF,OAAA,CAAAE,cAAA,0BAAdA,cAAc;EACxB;EADUA,cAAc,CAAdA,cAAc;EAGxB;EAHUA,cAAc,CAAdA,cAAc;EAKxB;EALUA,cAAc,CAAdA,cAAc;EAAA,OAAdA,cAAc;AAAA","ignoreList":[]}