react-native-nitro-storage 0.1.4 → 0.3.0

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.
@@ -3,6 +3,39 @@
3
3
  namespace NitroStorage {
4
4
 
5
5
  using namespace facebook::jni;
6
+ using JavaStringArray = JArrayClass<jstring>;
7
+
8
+ namespace {
9
+
10
+ local_ref<JavaStringArray> toJavaStringArray(const std::vector<std::string>& values) {
11
+ auto javaArray = JavaStringArray::newArray(static_cast<jsize>(values.size()));
12
+ for (size_t i = 0; i < values.size(); ++i) {
13
+ auto javaValue = make_jstring(values[i]);
14
+ javaArray->setElement(static_cast<jsize>(i), javaValue.get());
15
+ }
16
+ return javaArray;
17
+ }
18
+
19
+ std::vector<std::optional<std::string>> fromJavaStringArray(alias_ref<JavaStringArray> values) {
20
+ std::vector<std::optional<std::string>> parsedValues;
21
+ if (!values) {
22
+ return parsedValues;
23
+ }
24
+
25
+ const auto size = values->size();
26
+ parsedValues.reserve(size);
27
+ for (jsize i = 0; i < size; ++i) {
28
+ auto currentValue = values->getElement(i);
29
+ if (!currentValue) {
30
+ parsedValues.push_back(std::nullopt);
31
+ continue;
32
+ }
33
+ parsedValues.push_back(currentValue->toStdString());
34
+ }
35
+ return parsedValues;
36
+ }
37
+
38
+ } // namespace
6
39
 
7
40
  AndroidStorageAdapterCpp::AndroidStorageAdapterCpp(alias_ref<JObject> context) {
8
41
  if (!context) [[unlikely]] {
@@ -29,6 +62,40 @@ void AndroidStorageAdapterCpp::deleteDisk(const std::string& key) {
29
62
  method(AndroidStorageAdapterJava::javaClassStatic(), key);
30
63
  }
31
64
 
65
+ void AndroidStorageAdapterCpp::setDiskBatch(
66
+ const std::vector<std::string>& keys,
67
+ const std::vector<std::string>& values
68
+ ) {
69
+ auto javaKeys = toJavaStringArray(keys);
70
+ auto javaValues = toJavaStringArray(values);
71
+ static auto method =
72
+ AndroidStorageAdapterJava::javaClassStatic()->getStaticMethod<
73
+ void(alias_ref<JavaStringArray>, alias_ref<JavaStringArray>)
74
+ >("setDiskBatch");
75
+ method(AndroidStorageAdapterJava::javaClassStatic(), javaKeys, javaValues);
76
+ }
77
+
78
+ std::vector<std::optional<std::string>> AndroidStorageAdapterCpp::getDiskBatch(
79
+ const std::vector<std::string>& keys
80
+ ) {
81
+ auto javaKeys = toJavaStringArray(keys);
82
+ static auto method =
83
+ AndroidStorageAdapterJava::javaClassStatic()->getStaticMethod<
84
+ local_ref<JavaStringArray>(alias_ref<JavaStringArray>)
85
+ >("getDiskBatch");
86
+ auto values = method(AndroidStorageAdapterJava::javaClassStatic(), javaKeys);
87
+ return fromJavaStringArray(values);
88
+ }
89
+
90
+ void AndroidStorageAdapterCpp::deleteDiskBatch(const std::vector<std::string>& keys) {
91
+ auto javaKeys = toJavaStringArray(keys);
92
+ static auto method =
93
+ AndroidStorageAdapterJava::javaClassStatic()->getStaticMethod<
94
+ void(alias_ref<JavaStringArray>)
95
+ >("deleteDiskBatch");
96
+ method(AndroidStorageAdapterJava::javaClassStatic(), javaKeys);
97
+ }
98
+
32
99
  void AndroidStorageAdapterCpp::setSecure(const std::string& key, const std::string& value) {
33
100
  static auto method = AndroidStorageAdapterJava::javaClassStatic()->getStaticMethod<void(std::string, std::string)>("setSecure");
34
101
  method(AndroidStorageAdapterJava::javaClassStatic(), key, value);
@@ -46,6 +113,40 @@ void AndroidStorageAdapterCpp::deleteSecure(const std::string& key) {
46
113
  method(AndroidStorageAdapterJava::javaClassStatic(), key);
47
114
  }
48
115
 
116
+ void AndroidStorageAdapterCpp::setSecureBatch(
117
+ const std::vector<std::string>& keys,
118
+ const std::vector<std::string>& values
119
+ ) {
120
+ auto javaKeys = toJavaStringArray(keys);
121
+ auto javaValues = toJavaStringArray(values);
122
+ static auto method =
123
+ AndroidStorageAdapterJava::javaClassStatic()->getStaticMethod<
124
+ void(alias_ref<JavaStringArray>, alias_ref<JavaStringArray>)
125
+ >("setSecureBatch");
126
+ method(AndroidStorageAdapterJava::javaClassStatic(), javaKeys, javaValues);
127
+ }
128
+
129
+ std::vector<std::optional<std::string>> AndroidStorageAdapterCpp::getSecureBatch(
130
+ const std::vector<std::string>& keys
131
+ ) {
132
+ auto javaKeys = toJavaStringArray(keys);
133
+ static auto method =
134
+ AndroidStorageAdapterJava::javaClassStatic()->getStaticMethod<
135
+ local_ref<JavaStringArray>(alias_ref<JavaStringArray>)
136
+ >("getSecureBatch");
137
+ auto values = method(AndroidStorageAdapterJava::javaClassStatic(), javaKeys);
138
+ return fromJavaStringArray(values);
139
+ }
140
+
141
+ void AndroidStorageAdapterCpp::deleteSecureBatch(const std::vector<std::string>& keys) {
142
+ auto javaKeys = toJavaStringArray(keys);
143
+ static auto method =
144
+ AndroidStorageAdapterJava::javaClassStatic()->getStaticMethod<
145
+ void(alias_ref<JavaStringArray>)
146
+ >("deleteSecureBatch");
147
+ method(AndroidStorageAdapterJava::javaClassStatic(), javaKeys);
148
+ }
149
+
49
150
  void AndroidStorageAdapterCpp::clearDisk() {
50
151
  static auto method = AndroidStorageAdapterJava::javaClassStatic()->getStaticMethod<void()>("clearDisk");
51
152
  method(AndroidStorageAdapterJava::javaClassStatic());
@@ -18,47 +18,6 @@ struct AndroidStorageAdapterJava : facebook::jni::JavaClass<AndroidStorageAdapte
18
18
  return method(javaClassStatic());
19
19
  }
20
20
 
21
- void setDisk(std::string key, std::string value) {
22
- static auto method = javaClassStatic()->getMethod<void(std::string, std::string)>("setDisk");
23
- method(self(), key, value);
24
- }
25
-
26
- std::string getDisk(std::string key) {
27
- static auto method = javaClassStatic()->getMethod<jstring(std::string)>("getDisk");
28
- auto result = method(self(), key);
29
- return result ? result->toStdString() : "";
30
- }
31
-
32
- void deleteDisk(std::string key) {
33
- static auto method = javaClassStatic()->getMethod<void(std::string)>("deleteDisk");
34
- method(self(), key);
35
- }
36
-
37
- void setSecure(std::string key, std::string value) {
38
- static auto method = javaClassStatic()->getMethod<void(std::string, std::string)>("setSecure");
39
- method(self(), key, value);
40
- }
41
-
42
- std::string getSecure(std::string key) {
43
- static auto method = javaClassStatic()->getMethod<jstring(std::string)>("getSecure");
44
- auto result = method(self(), key);
45
- return result ? result->toStdString() : "";
46
- }
47
-
48
- void deleteSecure(std::string key) {
49
- static auto method = javaClassStatic()->getMethod<void(std::string)>("deleteSecure");
50
- method(self(), key);
51
- }
52
-
53
- void clearDisk() {
54
- static auto method = javaClassStatic()->getStaticMethod<void()>("clearDisk");
55
- method(javaClassStatic());
56
- }
57
-
58
- void clearSecure() {
59
- static auto method = javaClassStatic()->getStaticMethod<void()>("clearSecure");
60
- method(javaClassStatic());
61
- }
62
21
  };
63
22
 
64
23
  class AndroidStorageAdapterCpp : public NativeStorageAdapter {
@@ -69,10 +28,16 @@ public:
69
28
  void setDisk(const std::string& key, const std::string& value) override;
70
29
  std::optional<std::string> getDisk(const std::string& key) override;
71
30
  void deleteDisk(const std::string& key) override;
31
+ void setDiskBatch(const std::vector<std::string>& keys, const std::vector<std::string>& values) override;
32
+ std::vector<std::optional<std::string>> getDiskBatch(const std::vector<std::string>& keys) override;
33
+ void deleteDiskBatch(const std::vector<std::string>& keys) override;
72
34
 
73
35
  void setSecure(const std::string& key, const std::string& value) override;
74
36
  std::optional<std::string> getSecure(const std::string& key) override;
75
37
  void deleteSecure(const std::string& key) override;
38
+ void setSecureBatch(const std::vector<std::string>& keys, const std::vector<std::string>& values) override;
39
+ std::vector<std::optional<std::string>> getSecureBatch(const std::vector<std::string>& keys) override;
40
+ void deleteSecureBatch(const std::vector<std::string>& keys) override;
76
41
 
77
42
  void clearDisk() override;
78
43
  void clearSecure() override;
@@ -11,8 +11,9 @@ import javax.crypto.AEADBadTagException
11
11
  class AndroidStorageAdapter private constructor(private val context: Context) {
12
12
  private val sharedPreferences: SharedPreferences =
13
13
  context.getSharedPreferences("NitroStorage", Context.MODE_PRIVATE)
14
-
15
- private val masterKey: MasterKey = MasterKey.Builder(context)
14
+
15
+ private val masterKeyAlias = "${context.packageName}.nitro_storage.master_key"
16
+ private val masterKey: MasterKey = MasterKey.Builder(context, masterKeyAlias)
16
17
  .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
17
18
  .build()
18
19
 
@@ -59,7 +60,7 @@ class AndroidStorageAdapter private constructor(private val context: Context) {
59
60
  // Delete the master key from Android Keystore
60
61
  val keyStore = KeyStore.getInstance("AndroidKeyStore")
61
62
  keyStore.load(null)
62
- keyStore.deleteEntry(MasterKey.DEFAULT_MASTER_KEY_ALIAS)
63
+ keyStore.deleteEntry(masterKeyAlias)
63
64
 
64
65
  Log.i("NitroStorage", "Successfully cleared corrupted secure storage")
65
66
  } catch (e: Exception) {
@@ -98,32 +99,86 @@ class AndroidStorageAdapter private constructor(private val context: Context) {
98
99
  fun setDisk(key: String, value: String) {
99
100
  getInstanceOrThrow().sharedPreferences.edit().putString(key, value).apply()
100
101
  }
102
+
103
+ @JvmStatic
104
+ fun setDiskBatch(keys: Array<String>, values: Array<String>) {
105
+ val editor = getInstanceOrThrow().sharedPreferences.edit()
106
+ val count = minOf(keys.size, values.size)
107
+ for (index in 0 until count) {
108
+ editor.putString(keys[index], values[index])
109
+ }
110
+ editor.apply()
111
+ }
101
112
 
102
113
  @JvmStatic
103
114
  fun getDisk(key: String): String? {
104
115
  return getInstanceOrThrow().sharedPreferences.getString(key, null)
105
116
  }
117
+
118
+ @JvmStatic
119
+ fun getDiskBatch(keys: Array<String>): Array<String?> {
120
+ val prefs = getInstanceOrThrow().sharedPreferences
121
+ return Array(keys.size) { index ->
122
+ prefs.getString(keys[index], null)
123
+ }
124
+ }
106
125
 
107
126
  @JvmStatic
108
127
  fun deleteDisk(key: String) {
109
128
  getInstanceOrThrow().sharedPreferences.edit().remove(key).apply()
110
129
  }
130
+
131
+ @JvmStatic
132
+ fun deleteDiskBatch(keys: Array<String>) {
133
+ val editor = getInstanceOrThrow().sharedPreferences.edit()
134
+ for (key in keys) {
135
+ editor.remove(key)
136
+ }
137
+ editor.apply()
138
+ }
111
139
 
112
140
  @JvmStatic
113
141
  fun setSecure(key: String, value: String) {
114
142
  getInstanceOrThrow().encryptedPreferences.edit().putString(key, value).apply()
115
143
  }
144
+
145
+ @JvmStatic
146
+ fun setSecureBatch(keys: Array<String>, values: Array<String>) {
147
+ val editor = getInstanceOrThrow().encryptedPreferences.edit()
148
+ val count = minOf(keys.size, values.size)
149
+ for (index in 0 until count) {
150
+ editor.putString(keys[index], values[index])
151
+ }
152
+ editor.apply()
153
+ }
116
154
 
117
155
  @JvmStatic
118
156
  fun getSecure(key: String): String? {
119
157
  return getInstanceOrThrow().encryptedPreferences.getString(key, null)
120
158
  }
159
+
160
+ @JvmStatic
161
+ fun getSecureBatch(keys: Array<String>): Array<String?> {
162
+ val prefs = getInstanceOrThrow().encryptedPreferences
163
+ return Array(keys.size) { index ->
164
+ prefs.getString(keys[index], null)
165
+ }
166
+ }
121
167
 
122
168
  @JvmStatic
123
169
  fun deleteSecure(key: String) {
124
170
  getInstanceOrThrow().encryptedPreferences.edit().remove(key).apply()
125
171
  }
126
172
 
173
+ @JvmStatic
174
+ fun deleteSecureBatch(keys: Array<String>) {
175
+ val editor = getInstanceOrThrow().encryptedPreferences.edit()
176
+ for (key in keys) {
177
+ editor.remove(key)
178
+ }
179
+ editor.apply()
180
+ }
181
+
127
182
  @JvmStatic
128
183
  fun clearDisk() {
129
184
  getInstanceOrThrow().sharedPreferences.edit().clear().apply()
package/app.plugin.js CHANGED
@@ -6,19 +6,21 @@ const {
6
6
  } = require("@expo/config-plugins");
7
7
 
8
8
  const withNitroStorage = (config, props = {}) => {
9
- const {
10
- faceIDPermission = "Allow $(PRODUCT_NAME) to use Face ID for secure authentication",
11
- } = props;
9
+ const defaultFaceIDPermission =
10
+ "Allow $(PRODUCT_NAME) to use Face ID for secure authentication";
11
+ const { faceIDPermission, addBiometricPermissions = false } = props;
12
12
 
13
13
  config = withInfoPlist(config, (config) => {
14
- config.modResults.NSFaceIDUsageDescription =
15
- faceIDPermission || config.modResults.NSFaceIDUsageDescription;
14
+ if (typeof faceIDPermission === "string" && faceIDPermission.trim() !== "") {
15
+ config.modResults.NSFaceIDUsageDescription = faceIDPermission;
16
+ } else if (!config.modResults.NSFaceIDUsageDescription) {
17
+ config.modResults.NSFaceIDUsageDescription = defaultFaceIDPermission;
18
+ }
16
19
  return config;
17
20
  });
18
21
 
19
22
  config = withAndroidManifest(config, (config) => {
20
- const mainApplication = config.modResults.manifest.application?.[0];
21
- if (!mainApplication) {
23
+ if (!addBiometricPermissions) {
22
24
  return config;
23
25
  }
24
26
 
@@ -10,6 +10,10 @@
10
10
 
11
11
  namespace margelo::nitro::NitroStorage {
12
12
 
13
+ namespace {
14
+ constexpr auto kBatchMissingSentinel = "__nitro_storage_batch_missing__::v1";
15
+ } // namespace
16
+
13
17
  HybridStorage::HybridStorage()
14
18
  : HybridObject(TAG), HybridStorageSpec() {
15
19
  #if __APPLE__
@@ -202,9 +206,41 @@ void HybridStorage::setBatch(const std::vector<std::string>& keys, const std::ve
202
206
  if (keys.size() != values.size()) {
203
207
  throw std::runtime_error("NitroStorage: Keys and values size mismatch in setBatch");
204
208
  }
205
-
209
+
210
+ Scope s = toScope(scope);
211
+
212
+ switch (s) {
213
+ case Scope::Memory: {
214
+ std::lock_guard<std::mutex> lock(memoryMutex_);
215
+ for (size_t i = 0; i < keys.size(); ++i) {
216
+ memoryStore_[keys[i]] = values[i];
217
+ }
218
+ break;
219
+ }
220
+ case Scope::Disk:
221
+ ensureAdapter();
222
+ try {
223
+ nativeAdapter_->setDiskBatch(keys, values);
224
+ } catch (const std::exception& e) {
225
+ throw std::runtime_error(std::string("NitroStorage: Disk setBatch failed: ") + e.what());
226
+ } catch (...) {
227
+ throw std::runtime_error("NitroStorage: Disk setBatch failed");
228
+ }
229
+ break;
230
+ case Scope::Secure:
231
+ ensureAdapter();
232
+ try {
233
+ nativeAdapter_->setSecureBatch(keys, values);
234
+ } catch (const std::exception& e) {
235
+ throw std::runtime_error(std::string("NitroStorage: Secure setBatch failed: ") + e.what());
236
+ } catch (...) {
237
+ throw std::runtime_error("NitroStorage: Secure setBatch failed");
238
+ }
239
+ break;
240
+ }
241
+
206
242
  for (size_t i = 0; i < keys.size(); ++i) {
207
- set(keys[i], values[i], scope);
243
+ notifyListeners(static_cast<int>(s), keys[i], values[i]);
208
244
  }
209
245
  }
210
246
 
@@ -212,19 +248,103 @@ void HybridStorage::setBatch(const std::vector<std::string>& keys, const std::ve
212
248
  std::vector<std::string> HybridStorage::getBatch(const std::vector<std::string>& keys, double scope) {
213
249
  std::vector<std::string> results;
214
250
  results.reserve(keys.size());
215
-
216
- for (const auto& key : keys) {
217
- auto val = get(key, scope);
218
- results.push_back(val.value_or(""));
251
+
252
+ Scope s = toScope(scope);
253
+
254
+ switch (s) {
255
+ case Scope::Memory: {
256
+ std::lock_guard<std::mutex> lock(memoryMutex_);
257
+ for (const auto& key : keys) {
258
+ auto it = memoryStore_.find(key);
259
+ if (it != memoryStore_.end()) {
260
+ results.push_back(it->second);
261
+ } else {
262
+ results.push_back(kBatchMissingSentinel);
263
+ }
264
+ }
265
+ return results;
266
+ }
267
+ case Scope::Disk: {
268
+ ensureAdapter();
269
+ std::vector<std::optional<std::string>> values;
270
+ try {
271
+ values = nativeAdapter_->getDiskBatch(keys);
272
+ } catch (const std::exception& e) {
273
+ throw std::runtime_error(std::string("NitroStorage: Disk getBatch failed: ") + e.what());
274
+ } catch (...) {
275
+ throw std::runtime_error("NitroStorage: Disk getBatch failed");
276
+ }
277
+
278
+ for (const auto& value : values) {
279
+ if (value.has_value()) {
280
+ results.push_back(*value);
281
+ } else {
282
+ results.push_back(kBatchMissingSentinel);
283
+ }
284
+ }
285
+ return results;
286
+ }
287
+ case Scope::Secure: {
288
+ ensureAdapter();
289
+ std::vector<std::optional<std::string>> values;
290
+ try {
291
+ values = nativeAdapter_->getSecureBatch(keys);
292
+ } catch (const std::exception& e) {
293
+ throw std::runtime_error(std::string("NitroStorage: Secure getBatch failed: ") + e.what());
294
+ } catch (...) {
295
+ throw std::runtime_error("NitroStorage: Secure getBatch failed");
296
+ }
297
+
298
+ for (const auto& value : values) {
299
+ if (value.has_value()) {
300
+ results.push_back(*value);
301
+ } else {
302
+ results.push_back(kBatchMissingSentinel);
303
+ }
304
+ }
305
+ return results;
306
+ }
219
307
  }
220
-
308
+
221
309
  return results;
222
310
  }
223
311
 
224
312
 
225
313
  void HybridStorage::removeBatch(const std::vector<std::string>& keys, double scope) {
314
+ Scope s = toScope(scope);
315
+
316
+ switch (s) {
317
+ case Scope::Memory: {
318
+ std::lock_guard<std::mutex> lock(memoryMutex_);
319
+ for (const auto& key : keys) {
320
+ memoryStore_.erase(key);
321
+ }
322
+ break;
323
+ }
324
+ case Scope::Disk:
325
+ ensureAdapter();
326
+ try {
327
+ nativeAdapter_->deleteDiskBatch(keys);
328
+ } catch (const std::exception& e) {
329
+ throw std::runtime_error(std::string("NitroStorage: Disk removeBatch failed: ") + e.what());
330
+ } catch (...) {
331
+ throw std::runtime_error("NitroStorage: Disk removeBatch failed");
332
+ }
333
+ break;
334
+ case Scope::Secure:
335
+ ensureAdapter();
336
+ try {
337
+ nativeAdapter_->deleteSecureBatch(keys);
338
+ } catch (const std::exception& e) {
339
+ throw std::runtime_error(std::string("NitroStorage: Secure removeBatch failed: ") + e.what());
340
+ } catch (...) {
341
+ throw std::runtime_error("NitroStorage: Secure removeBatch failed");
342
+ }
343
+ break;
344
+ }
345
+
226
346
  for (const auto& key : keys) {
227
- remove(key, scope);
347
+ notifyListeners(static_cast<int>(s), key, std::nullopt);
228
348
  }
229
349
  }
230
350
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  #include <string>
4
4
  #include <optional>
5
+ #include <vector>
5
6
 
6
7
  namespace NitroStorage {
7
8
 
@@ -12,10 +13,16 @@ public:
12
13
  virtual void setDisk(const std::string& key, const std::string& value) = 0;
13
14
  virtual std::optional<std::string> getDisk(const std::string& key) = 0;
14
15
  virtual void deleteDisk(const std::string& key) = 0;
16
+ virtual void setDiskBatch(const std::vector<std::string>& keys, const std::vector<std::string>& values) = 0;
17
+ virtual std::vector<std::optional<std::string>> getDiskBatch(const std::vector<std::string>& keys) = 0;
18
+ virtual void deleteDiskBatch(const std::vector<std::string>& keys) = 0;
15
19
 
16
20
  virtual void setSecure(const std::string& key, const std::string& value) = 0;
17
21
  virtual std::optional<std::string> getSecure(const std::string& key) = 0;
18
22
  virtual void deleteSecure(const std::string& key) = 0;
23
+ virtual void setSecureBatch(const std::vector<std::string>& keys, const std::vector<std::string>& values) = 0;
24
+ virtual std::vector<std::optional<std::string>> getSecureBatch(const std::vector<std::string>& keys) = 0;
25
+ virtual void deleteSecureBatch(const std::vector<std::string>& keys) = 0;
19
26
 
20
27
  virtual void clearDisk() = 0;
21
28
  virtual void clearSecure() = 0;
@@ -12,10 +12,16 @@ public:
12
12
  void setDisk(const std::string& key, const std::string& value) override;
13
13
  std::optional<std::string> getDisk(const std::string& key) override;
14
14
  void deleteDisk(const std::string& key) override;
15
+ void setDiskBatch(const std::vector<std::string>& keys, const std::vector<std::string>& values) override;
16
+ std::vector<std::optional<std::string>> getDiskBatch(const std::vector<std::string>& keys) override;
17
+ void deleteDiskBatch(const std::vector<std::string>& keys) override;
15
18
 
16
19
  void setSecure(const std::string& key, const std::string& value) override;
17
20
  std::optional<std::string> getSecure(const std::string& key) override;
18
21
  void deleteSecure(const std::string& key) override;
22
+ void setSecureBatch(const std::vector<std::string>& keys, const std::vector<std::string>& values) override;
23
+ std::vector<std::optional<std::string>> getSecureBatch(const std::vector<std::string>& keys) override;
24
+ void deleteSecureBatch(const std::vector<std::string>& keys) override;
19
25
 
20
26
  void clearDisk() override;
21
27
  void clearSecure() override;
@@ -5,23 +5,77 @@
5
5
  namespace NitroStorage {
6
6
 
7
7
  static NSString* const kKeychainService = @"com.nitrostorage.keychain";
8
+ static NSString* const kDiskSuiteName = @"com.nitrostorage.disk";
9
+
10
+ static NSUserDefaults* NitroDiskDefaults() {
11
+ static NSUserDefaults* defaults = [[NSUserDefaults alloc] initWithSuiteName:kDiskSuiteName];
12
+ return defaults ?: [NSUserDefaults standardUserDefaults];
13
+ }
8
14
 
9
15
  IOSStorageAdapterCpp::IOSStorageAdapterCpp() {}
10
16
  IOSStorageAdapterCpp::~IOSStorageAdapterCpp() {}
11
17
 
12
18
  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()]];
19
+ NSString* nsKey = [NSString stringWithUTF8String:key.c_str()];
20
+ NSString* nsValue = [NSString stringWithUTF8String:value.c_str()];
21
+ NSUserDefaults* defaults = NitroDiskDefaults();
22
+ [defaults setObject:nsValue forKey:nsKey];
23
+ [[NSUserDefaults standardUserDefaults] removeObjectForKey:nsKey];
15
24
  }
16
25
 
17
26
  std::optional<std::string> IOSStorageAdapterCpp::getDisk(const std::string& key) {
18
- NSString* result = [[NSUserDefaults standardUserDefaults] stringForKey:[NSString stringWithUTF8String:key.c_str()]];
27
+ NSString* nsKey = [NSString stringWithUTF8String:key.c_str()];
28
+ NSUserDefaults* defaults = NitroDiskDefaults();
29
+ NSString* result = [defaults stringForKey:nsKey];
30
+
31
+ if (!result) {
32
+ NSUserDefaults* legacyDefaults = [NSUserDefaults standardUserDefaults];
33
+ NSString* legacyValue = [legacyDefaults stringForKey:nsKey];
34
+ if (legacyValue) {
35
+ [defaults setObject:legacyValue forKey:nsKey];
36
+ [legacyDefaults removeObjectForKey:nsKey];
37
+ result = legacyValue;
38
+ }
39
+ }
40
+
19
41
  if (!result) return std::nullopt;
20
42
  return std::string([result UTF8String]);
21
43
  }
22
44
 
23
45
  void IOSStorageAdapterCpp::deleteDisk(const std::string& key) {
24
- [[NSUserDefaults standardUserDefaults] removeObjectForKey:[NSString stringWithUTF8String:key.c_str()]];
46
+ NSString* nsKey = [NSString stringWithUTF8String:key.c_str()];
47
+ [NitroDiskDefaults() removeObjectForKey:nsKey];
48
+ [[NSUserDefaults standardUserDefaults] removeObjectForKey:nsKey];
49
+ }
50
+
51
+ void IOSStorageAdapterCpp::setDiskBatch(
52
+ const std::vector<std::string>& keys,
53
+ const std::vector<std::string>& values
54
+ ) {
55
+ NSUserDefaults* defaults = NitroDiskDefaults();
56
+ for (size_t i = 0; i < keys.size() && i < values.size(); ++i) {
57
+ NSString* nsKey = [NSString stringWithUTF8String:keys[i].c_str()];
58
+ NSString* nsValue = [NSString stringWithUTF8String:values[i].c_str()];
59
+ [defaults setObject:nsValue forKey:nsKey];
60
+ [[NSUserDefaults standardUserDefaults] removeObjectForKey:nsKey];
61
+ }
62
+ }
63
+
64
+ std::vector<std::optional<std::string>> IOSStorageAdapterCpp::getDiskBatch(
65
+ const std::vector<std::string>& keys
66
+ ) {
67
+ std::vector<std::optional<std::string>> results;
68
+ results.reserve(keys.size());
69
+ for (const auto& key : keys) {
70
+ results.push_back(getDisk(key));
71
+ }
72
+ return results;
73
+ }
74
+
75
+ void IOSStorageAdapterCpp::deleteDiskBatch(const std::vector<std::string>& keys) {
76
+ for (const auto& key : keys) {
77
+ deleteDisk(key);
78
+ }
25
79
  }
26
80
 
27
81
  void IOSStorageAdapterCpp::setSecure(const std::string& key, const std::string& value) {
@@ -75,10 +129,37 @@ void IOSStorageAdapterCpp::deleteSecure(const std::string& key) {
75
129
  SecItemDelete((__bridge CFDictionaryRef)query);
76
130
  }
77
131
 
132
+ void IOSStorageAdapterCpp::setSecureBatch(
133
+ const std::vector<std::string>& keys,
134
+ const std::vector<std::string>& values
135
+ ) {
136
+ for (size_t i = 0; i < keys.size() && i < values.size(); ++i) {
137
+ setSecure(keys[i], values[i]);
138
+ }
139
+ }
140
+
141
+ std::vector<std::optional<std::string>> IOSStorageAdapterCpp::getSecureBatch(
142
+ const std::vector<std::string>& keys
143
+ ) {
144
+ std::vector<std::optional<std::string>> results;
145
+ results.reserve(keys.size());
146
+ for (const auto& key : keys) {
147
+ results.push_back(getSecure(key));
148
+ }
149
+ return results;
150
+ }
151
+
152
+ void IOSStorageAdapterCpp::deleteSecureBatch(const std::vector<std::string>& keys) {
153
+ for (const auto& key : keys) {
154
+ deleteSecure(key);
155
+ }
156
+ }
157
+
78
158
  void IOSStorageAdapterCpp::clearDisk() {
79
- NSString* appDomain = [[NSBundle mainBundle] bundleIdentifier];
80
- if (appDomain) {
81
- [[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];
159
+ NSUserDefaults* defaults = NitroDiskDefaults();
160
+ NSDictionary<NSString*, id>* entries = [defaults dictionaryRepresentation];
161
+ for (NSString* key in entries) {
162
+ [defaults removeObjectForKey:key];
82
163
  }
83
164
  }
84
165