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.
- package/README.md +320 -391
- package/android/src/main/cpp/AndroidStorageAdapterCpp.cpp +101 -0
- package/android/src/main/cpp/AndroidStorageAdapterCpp.hpp +6 -41
- package/android/src/main/java/com/nitrostorage/AndroidStorageAdapter.kt +58 -3
- package/app.plugin.js +9 -7
- package/cpp/bindings/HybridStorage.cpp +128 -8
- package/cpp/core/NativeStorageAdapter.hpp +7 -0
- package/ios/IOSStorageAdapterCpp.hpp +6 -0
- package/ios/IOSStorageAdapterCpp.mm +88 -7
- package/lib/commonjs/index.js +537 -66
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +558 -130
- package/lib/commonjs/index.web.js.map +1 -1
- package/lib/commonjs/internal.js +102 -0
- package/lib/commonjs/internal.js.map +1 -0
- package/lib/module/index.js +528 -67
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +536 -122
- package/lib/module/index.web.js.map +1 -1
- package/lib/module/internal.js +92 -0
- package/lib/module/internal.js.map +1 -0
- package/lib/typescript/index.d.ts +42 -6
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/index.web.d.ts +45 -12
- package/lib/typescript/index.web.d.ts.map +1 -1
- package/lib/typescript/internal.d.ts +19 -0
- package/lib/typescript/internal.d.ts.map +1 -0
- package/lib/typescript/migration.d.ts +2 -3
- package/lib/typescript/migration.d.ts.map +1 -1
- package/package.json +19 -8
- package/src/index.ts +734 -74
- package/src/index.web.ts +732 -128
- package/src/internal.ts +134 -0
- package/src/migration.ts +2 -2
|
@@ -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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
15
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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
|
-
|
|
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
|
-
|
|
14
|
-
|
|
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*
|
|
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
|
-
|
|
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
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|
|