react-native-nitro-storage 0.1.3 → 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 +125 -37
- package/app.plugin.js +9 -7
- package/cpp/bindings/HybridStorage.cpp +214 -19
- package/cpp/bindings/HybridStorage.hpp +1 -0
- package/cpp/core/NativeStorageAdapter.hpp +7 -0
- package/ios/IOSStorageAdapterCpp.hpp +6 -0
- package/ios/IOSStorageAdapterCpp.mm +90 -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/nitrogen/generated/android/NitroStorage+autolinking.cmake +1 -1
- package/nitrogen/generated/android/NitroStorage+autolinking.gradle +1 -1
- package/nitrogen/generated/android/NitroStorageOnLoad.cpp +1 -1
- package/nitrogen/generated/android/NitroStorageOnLoad.hpp +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/com/nitrostorage/NitroStorageOnLoad.kt +1 -1
- package/nitrogen/generated/ios/NitroStorage+autolinking.rb +1 -1
- package/nitrogen/generated/ios/NitroStorage-Swift-Cxx-Bridge.cpp +1 -1
- package/nitrogen/generated/ios/NitroStorage-Swift-Cxx-Bridge.hpp +1 -1
- package/nitrogen/generated/ios/NitroStorage-Swift-Cxx-Umbrella.hpp +1 -1
- package/nitrogen/generated/ios/NitroStorageAutolinking.mm +1 -1
- package/nitrogen/generated/ios/NitroStorageAutolinking.swift +5 -1
- package/nitrogen/generated/shared/c++/HybridStorageSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridStorageSpec.hpp +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;
|
|
@@ -2,37 +2,83 @@ package com.nitrostorage
|
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
4
|
import android.content.SharedPreferences
|
|
5
|
+
import android.util.Log
|
|
5
6
|
import androidx.security.crypto.EncryptedSharedPreferences
|
|
6
7
|
import androidx.security.crypto.MasterKey
|
|
8
|
+
import java.security.KeyStore
|
|
9
|
+
import javax.crypto.AEADBadTagException
|
|
7
10
|
|
|
8
11
|
class AndroidStorageAdapter private constructor(private val context: Context) {
|
|
9
12
|
private val sharedPreferences: SharedPreferences =
|
|
10
13
|
context.getSharedPreferences("NitroStorage", Context.MODE_PRIVATE)
|
|
11
|
-
|
|
12
|
-
private val
|
|
14
|
+
|
|
15
|
+
private val masterKeyAlias = "${context.packageName}.nitro_storage.master_key"
|
|
16
|
+
private val masterKey: MasterKey = MasterKey.Builder(context, masterKeyAlias)
|
|
13
17
|
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
|
|
14
18
|
.build()
|
|
15
19
|
|
|
16
|
-
private val encryptedPreferences: SharedPreferences =
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
private val encryptedPreferences: SharedPreferences = initializeEncryptedPreferences()
|
|
21
|
+
|
|
22
|
+
private fun initializeEncryptedPreferences(): SharedPreferences {
|
|
23
|
+
return try {
|
|
24
|
+
EncryptedSharedPreferences.create(
|
|
25
|
+
context,
|
|
26
|
+
"NitroStorageSecure",
|
|
27
|
+
masterKey,
|
|
28
|
+
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
|
29
|
+
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
|
30
|
+
)
|
|
31
|
+
} catch (e: Exception) {
|
|
32
|
+
// Handle corrupted keystore keys by clearing and re-initializing
|
|
33
|
+
if (e is AEADBadTagException || e.cause is AEADBadTagException) {
|
|
34
|
+
Log.w("NitroStorage", "Detected corrupted encryption keys, clearing secure storage...")
|
|
35
|
+
clearCorruptedSecureStorage()
|
|
36
|
+
|
|
37
|
+
// Retry initialization
|
|
38
|
+
EncryptedSharedPreferences.create(
|
|
39
|
+
context,
|
|
40
|
+
"NitroStorageSecure",
|
|
41
|
+
masterKey,
|
|
42
|
+
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
|
43
|
+
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
|
44
|
+
)
|
|
45
|
+
} else {
|
|
46
|
+
throw RuntimeException(
|
|
47
|
+
"NitroStorage: Failed to initialize secure storage. " +
|
|
48
|
+
"This may be due to corrupted encryption keys. " +
|
|
49
|
+
"Try clearing app data or reinstalling the app.", e
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private fun clearCorruptedSecureStorage() {
|
|
56
|
+
try {
|
|
57
|
+
// Delete the encrypted shared preferences file
|
|
58
|
+
context.deleteSharedPreferences("NitroStorageSecure")
|
|
59
|
+
|
|
60
|
+
// Delete the master key from Android Keystore
|
|
61
|
+
val keyStore = KeyStore.getInstance("AndroidKeyStore")
|
|
62
|
+
keyStore.load(null)
|
|
63
|
+
keyStore.deleteEntry(masterKeyAlias)
|
|
64
|
+
|
|
65
|
+
Log.i("NitroStorage", "Successfully cleared corrupted secure storage")
|
|
66
|
+
} catch (e: Exception) {
|
|
67
|
+
Log.e("NitroStorage", "Failed to clear corrupted secure storage", e)
|
|
68
|
+
}
|
|
30
69
|
}
|
|
31
70
|
|
|
32
71
|
companion object {
|
|
33
72
|
@Volatile
|
|
34
73
|
private var instance: AndroidStorageAdapter? = null
|
|
35
74
|
|
|
75
|
+
private fun getInstanceOrThrow(): AndroidStorageAdapter {
|
|
76
|
+
return instance ?: throw IllegalStateException(
|
|
77
|
+
"NitroStorage not initialized. Call AndroidStorageAdapter.init(this) in your MainApplication.onCreate(), " +
|
|
78
|
+
"or add 'react-native-nitro-storage' to your Expo plugins array in app.json."
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
36
82
|
@JvmStatic
|
|
37
83
|
fun init(context: Context) {
|
|
38
84
|
if (instance == null) {
|
|
@@ -46,59 +92,101 @@ class AndroidStorageAdapter private constructor(private val context: Context) {
|
|
|
46
92
|
|
|
47
93
|
@JvmStatic
|
|
48
94
|
fun getContext(): Context {
|
|
49
|
-
return
|
|
50
|
-
?: throw IllegalStateException(
|
|
51
|
-
"NitroStorage not initialized. Call AndroidStorageAdapter.init(this) in your MainApplication.onCreate(), " +
|
|
52
|
-
"or add 'react-native-nitro-storage' to your Expo plugins array in app.json."
|
|
53
|
-
)
|
|
95
|
+
return getInstanceOrThrow().context
|
|
54
96
|
}
|
|
55
97
|
|
|
56
98
|
@JvmStatic
|
|
57
99
|
fun setDisk(key: String, value: String) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
100
|
+
getInstanceOrThrow().sharedPreferences.edit().putString(key, value).apply()
|
|
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()
|
|
63
111
|
}
|
|
64
112
|
|
|
65
113
|
@JvmStatic
|
|
66
114
|
fun getDisk(key: String): String? {
|
|
67
|
-
return
|
|
115
|
+
return getInstanceOrThrow().sharedPreferences.getString(key, null)
|
|
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
|
+
}
|
|
68
124
|
}
|
|
69
125
|
|
|
70
126
|
@JvmStatic
|
|
71
127
|
fun deleteDisk(key: String) {
|
|
72
|
-
|
|
128
|
+
getInstanceOrThrow().sharedPreferences.edit().remove(key).apply()
|
|
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()
|
|
73
138
|
}
|
|
74
139
|
|
|
75
140
|
@JvmStatic
|
|
76
141
|
fun setSecure(key: String, value: String) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
142
|
+
getInstanceOrThrow().encryptedPreferences.edit().putString(key, value).apply()
|
|
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()
|
|
82
153
|
}
|
|
83
154
|
|
|
84
155
|
@JvmStatic
|
|
85
156
|
fun getSecure(key: String): String? {
|
|
86
|
-
return
|
|
157
|
+
return getInstanceOrThrow().encryptedPreferences.getString(key, null)
|
|
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
|
+
}
|
|
87
166
|
}
|
|
88
167
|
|
|
89
168
|
@JvmStatic
|
|
90
169
|
fun deleteSecure(key: String) {
|
|
91
|
-
|
|
170
|
+
getInstanceOrThrow().encryptedPreferences.edit().remove(key).apply()
|
|
171
|
+
}
|
|
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()
|
|
92
180
|
}
|
|
93
181
|
|
|
94
182
|
@JvmStatic
|
|
95
183
|
fun clearDisk() {
|
|
96
|
-
|
|
184
|
+
getInstanceOrThrow().sharedPreferences.edit().clear().apply()
|
|
97
185
|
}
|
|
98
186
|
|
|
99
187
|
@JvmStatic
|
|
100
188
|
fun clearSecure() {
|
|
101
|
-
|
|
189
|
+
getInstanceOrThrow().encryptedPreferences.edit().clear().apply()
|
|
102
190
|
}
|
|
103
191
|
}
|
|
104
192
|
}
|
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
|
|