strata-storage 2.2.0 → 2.4.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/android/src/main/java/com/strata/storage/EncryptedStorage.java +110 -7
- package/android/src/main/java/com/strata/storage/SQLiteStorage.java +112 -2
- package/android/src/main/java/com/strata/storage/SharedPreferencesStorage.java +95 -7
- package/android/src/main/java/com/stratastorage/StrataStoragePlugin.java +10 -20
- package/dist/android/src/main/java/com/strata/storage/EncryptedStorage.java +110 -7
- package/dist/android/src/main/java/com/strata/storage/SQLiteStorage.java +112 -2
- package/dist/android/src/main/java/com/strata/storage/SharedPreferencesStorage.java +95 -7
- package/dist/android/src/main/java/com/stratastorage/StrataStoragePlugin.java +10 -20
- package/dist/ios/Plugin/KeychainStorage.swift +44 -9
- package/dist/ios/Plugin/SQLiteStorage.swift +36 -2
- package/dist/ios/Plugin/UserDefaultsStorage.swift +14 -0
- package/dist/package.json +1 -1
- package/ios/Plugin/KeychainStorage.swift +44 -9
- package/ios/Plugin/SQLiteStorage.swift +36 -2
- package/ios/Plugin/UserDefaultsStorage.swift +14 -0
- package/package.json +8 -8
|
@@ -8,6 +8,10 @@ import androidx.security.crypto.MasterKey;
|
|
|
8
8
|
import java.util.Set;
|
|
9
9
|
import java.util.HashSet;
|
|
10
10
|
import java.util.Map;
|
|
11
|
+
import java.util.List;
|
|
12
|
+
import java.util.ArrayList;
|
|
13
|
+
import org.json.JSONObject;
|
|
14
|
+
import org.json.JSONArray;
|
|
11
15
|
|
|
12
16
|
public class EncryptedStorage {
|
|
13
17
|
private SharedPreferences encryptedPrefs;
|
|
@@ -42,9 +46,31 @@ public class EncryptedStorage {
|
|
|
42
46
|
}
|
|
43
47
|
}
|
|
44
48
|
|
|
45
|
-
public boolean set(String key,
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
public boolean set(String key, Object value) {
|
|
50
|
+
try {
|
|
51
|
+
String stringValue;
|
|
52
|
+
if (value instanceof String) {
|
|
53
|
+
stringValue = (String) value;
|
|
54
|
+
} else {
|
|
55
|
+
// Convert complex objects to JSON
|
|
56
|
+
if (value instanceof JSONObject) {
|
|
57
|
+
stringValue = ((JSONObject) value).toString();
|
|
58
|
+
} else {
|
|
59
|
+
// Use helper method to convert object to JSON string
|
|
60
|
+
try {
|
|
61
|
+
stringValue = objectToJsonString(value);
|
|
62
|
+
} catch (Exception e) {
|
|
63
|
+
// Fallback to string representation
|
|
64
|
+
stringValue = value.toString();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
editor.putString(key, stringValue);
|
|
69
|
+
return editor.commit();
|
|
70
|
+
} catch (Exception e) {
|
|
71
|
+
e.printStackTrace();
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
48
74
|
}
|
|
49
75
|
|
|
50
76
|
public String get(String key) {
|
|
@@ -79,19 +105,19 @@ public class EncryptedStorage {
|
|
|
79
105
|
return editor.commit();
|
|
80
106
|
}
|
|
81
107
|
|
|
82
|
-
public
|
|
108
|
+
public List<String> keys() {
|
|
83
109
|
return keys(null);
|
|
84
110
|
}
|
|
85
111
|
|
|
86
|
-
public
|
|
112
|
+
public List<String> keys(String pattern) {
|
|
87
113
|
Set<String> allKeys = encryptedPrefs.getAll().keySet();
|
|
88
114
|
|
|
89
115
|
if (pattern == null) {
|
|
90
|
-
return allKeys;
|
|
116
|
+
return new ArrayList<>(allKeys);
|
|
91
117
|
}
|
|
92
118
|
|
|
93
119
|
// Filter keys by pattern
|
|
94
|
-
|
|
120
|
+
List<String> filteredKeys = new ArrayList<>();
|
|
95
121
|
for (String key : allKeys) {
|
|
96
122
|
if (key.startsWith(pattern) || key.contains(pattern)) {
|
|
97
123
|
filteredKeys.add(key);
|
|
@@ -103,4 +129,81 @@ public class EncryptedStorage {
|
|
|
103
129
|
public boolean has(String key) {
|
|
104
130
|
return encryptedPrefs.contains(key);
|
|
105
131
|
}
|
|
132
|
+
|
|
133
|
+
public SizeInfo size() {
|
|
134
|
+
Map<String, ?> all = encryptedPrefs.getAll();
|
|
135
|
+
long totalSize = 0;
|
|
136
|
+
int count = all.size();
|
|
137
|
+
|
|
138
|
+
for (Map.Entry<String, ?> entry : all.entrySet()) {
|
|
139
|
+
String key = entry.getKey();
|
|
140
|
+
Object value = entry.getValue();
|
|
141
|
+
|
|
142
|
+
// Estimate size (key + value in bytes)
|
|
143
|
+
totalSize += key.getBytes().length;
|
|
144
|
+
if (value != null) {
|
|
145
|
+
totalSize += value.toString().getBytes().length;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return new SizeInfo(totalSize, count);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Convert an object to JSON string using reflection
|
|
154
|
+
*/
|
|
155
|
+
private String objectToJsonString(Object obj) throws Exception {
|
|
156
|
+
if (obj == null) {
|
|
157
|
+
return "null";
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (obj instanceof String || obj instanceof Number || obj instanceof Boolean) {
|
|
161
|
+
return obj.toString();
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (obj instanceof Map) {
|
|
165
|
+
JSONObject jsonObj = new JSONObject();
|
|
166
|
+
Map<?, ?> map = (Map<?, ?>) obj;
|
|
167
|
+
for (Map.Entry<?, ?> entry : map.entrySet()) {
|
|
168
|
+
String key = entry.getKey().toString();
|
|
169
|
+
jsonObj.put(key, entry.getValue());
|
|
170
|
+
}
|
|
171
|
+
return jsonObj.toString();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (obj instanceof List || obj.getClass().isArray()) {
|
|
175
|
+
JSONArray jsonArray = new JSONArray();
|
|
176
|
+
if (obj instanceof List) {
|
|
177
|
+
List<?> list = (List<?>) obj;
|
|
178
|
+
for (Object item : list) {
|
|
179
|
+
jsonArray.put(item);
|
|
180
|
+
}
|
|
181
|
+
} else {
|
|
182
|
+
Object[] array = (Object[]) obj;
|
|
183
|
+
for (Object item : array) {
|
|
184
|
+
jsonArray.put(item);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return jsonArray.toString();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// For other objects, create a simple JSON object with their string representation
|
|
191
|
+
JSONObject jsonObj = new JSONObject();
|
|
192
|
+
jsonObj.put("value", obj.toString());
|
|
193
|
+
jsonObj.put("type", obj.getClass().getSimpleName());
|
|
194
|
+
return jsonObj.toString();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Size information class
|
|
199
|
+
*/
|
|
200
|
+
public static class SizeInfo {
|
|
201
|
+
public final long total;
|
|
202
|
+
public final int count;
|
|
203
|
+
|
|
204
|
+
public SizeInfo(long total, int count) {
|
|
205
|
+
this.total = total;
|
|
206
|
+
this.count = count;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
106
209
|
}
|
|
@@ -9,6 +9,9 @@ import java.util.ArrayList;
|
|
|
9
9
|
import java.util.List;
|
|
10
10
|
import java.util.HashMap;
|
|
11
11
|
import java.util.Map;
|
|
12
|
+
import org.json.JSONObject;
|
|
13
|
+
import org.json.JSONArray;
|
|
14
|
+
import java.nio.charset.StandardCharsets;
|
|
12
15
|
|
|
13
16
|
public class SQLiteStorage extends SQLiteOpenHelper {
|
|
14
17
|
private static final int DATABASE_VERSION = 1;
|
|
@@ -50,13 +53,40 @@ public class SQLiteStorage extends SQLiteOpenHelper {
|
|
|
50
53
|
onCreate(db);
|
|
51
54
|
}
|
|
52
55
|
|
|
53
|
-
public boolean set(String key,
|
|
56
|
+
public boolean set(String key, Object value, Long expires, String tags, String metadata) {
|
|
57
|
+
byte[] valueBytes;
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
if (value instanceof byte[]) {
|
|
61
|
+
valueBytes = (byte[]) value;
|
|
62
|
+
} else if (value instanceof String) {
|
|
63
|
+
valueBytes = ((String) value).getBytes(StandardCharsets.UTF_8);
|
|
64
|
+
} else {
|
|
65
|
+
// Convert complex objects to JSON then to bytes
|
|
66
|
+
String json;
|
|
67
|
+
if (value instanceof JSONObject) {
|
|
68
|
+
json = ((JSONObject) value).toString();
|
|
69
|
+
} else {
|
|
70
|
+
// Use helper method to convert object to JSON string
|
|
71
|
+
try {
|
|
72
|
+
json = objectToJsonString(value);
|
|
73
|
+
} catch (Exception jsonEx) {
|
|
74
|
+
// Fallback to string representation
|
|
75
|
+
json = value.toString();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
valueBytes = json.getBytes(StandardCharsets.UTF_8);
|
|
79
|
+
}
|
|
80
|
+
} catch (Exception e) {
|
|
81
|
+
e.printStackTrace();
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
54
84
|
SQLiteDatabase db = this.getWritableDatabase();
|
|
55
85
|
ContentValues values = new ContentValues();
|
|
56
86
|
|
|
57
87
|
long now = System.currentTimeMillis();
|
|
58
88
|
values.put(KEY_ID, key);
|
|
59
|
-
values.put(KEY_VALUE,
|
|
89
|
+
values.put(KEY_VALUE, valueBytes);
|
|
60
90
|
values.put(KEY_CREATED, now);
|
|
61
91
|
values.put(KEY_UPDATED, now);
|
|
62
92
|
|
|
@@ -75,6 +105,11 @@ public class SQLiteStorage extends SQLiteOpenHelper {
|
|
|
75
105
|
return result != -1;
|
|
76
106
|
}
|
|
77
107
|
|
|
108
|
+
// Convenience method for simple Object values
|
|
109
|
+
public boolean set(String key, Object value) {
|
|
110
|
+
return set(key, value, null, null, null);
|
|
111
|
+
}
|
|
112
|
+
|
|
78
113
|
public Map<String, Object> get(String key) {
|
|
79
114
|
SQLiteDatabase db = this.getReadableDatabase();
|
|
80
115
|
Cursor cursor = db.query(TABLE_NAME, null, KEY_ID + "=?",
|
|
@@ -174,4 +209,79 @@ public class SQLiteStorage extends SQLiteOpenHelper {
|
|
|
174
209
|
db.close();
|
|
175
210
|
return exists;
|
|
176
211
|
}
|
|
212
|
+
|
|
213
|
+
public SizeInfo size() {
|
|
214
|
+
SQLiteDatabase db = this.getReadableDatabase();
|
|
215
|
+
Cursor cursor = db.rawQuery("SELECT COUNT(*), SUM(LENGTH(" + KEY_VALUE + ")) FROM " + TABLE_NAME, null);
|
|
216
|
+
|
|
217
|
+
long totalSize = 0;
|
|
218
|
+
int count = 0;
|
|
219
|
+
|
|
220
|
+
if (cursor != null && cursor.moveToFirst()) {
|
|
221
|
+
count = cursor.getInt(0);
|
|
222
|
+
totalSize = cursor.getLong(1);
|
|
223
|
+
cursor.close();
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
db.close();
|
|
227
|
+
return new SizeInfo(totalSize, count);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Convert an object to JSON string using reflection
|
|
232
|
+
*/
|
|
233
|
+
private String objectToJsonString(Object obj) throws Exception {
|
|
234
|
+
if (obj == null) {
|
|
235
|
+
return "null";
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (obj instanceof String || obj instanceof Number || obj instanceof Boolean) {
|
|
239
|
+
return obj.toString();
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (obj instanceof Map) {
|
|
243
|
+
JSONObject jsonObj = new JSONObject();
|
|
244
|
+
Map<?, ?> map = (Map<?, ?>) obj;
|
|
245
|
+
for (Map.Entry<?, ?> entry : map.entrySet()) {
|
|
246
|
+
String key = entry.getKey().toString();
|
|
247
|
+
jsonObj.put(key, entry.getValue());
|
|
248
|
+
}
|
|
249
|
+
return jsonObj.toString();
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (obj instanceof List || obj.getClass().isArray()) {
|
|
253
|
+
JSONArray jsonArray = new JSONArray();
|
|
254
|
+
if (obj instanceof List) {
|
|
255
|
+
List<?> list = (List<?>) obj;
|
|
256
|
+
for (Object item : list) {
|
|
257
|
+
jsonArray.put(item);
|
|
258
|
+
}
|
|
259
|
+
} else {
|
|
260
|
+
Object[] array = (Object[]) obj;
|
|
261
|
+
for (Object item : array) {
|
|
262
|
+
jsonArray.put(item);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return jsonArray.toString();
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// For other objects, create a simple JSON object with their string representation
|
|
269
|
+
JSONObject jsonObj = new JSONObject();
|
|
270
|
+
jsonObj.put("value", obj.toString());
|
|
271
|
+
jsonObj.put("type", obj.getClass().getSimpleName());
|
|
272
|
+
return jsonObj.toString();
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Size information class
|
|
277
|
+
*/
|
|
278
|
+
public static class SizeInfo {
|
|
279
|
+
public final long total;
|
|
280
|
+
public final int count;
|
|
281
|
+
|
|
282
|
+
public SizeInfo(long total, int count) {
|
|
283
|
+
this.total = total;
|
|
284
|
+
this.count = count;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
177
287
|
}
|
|
@@ -5,6 +5,8 @@ import android.content.SharedPreferences;
|
|
|
5
5
|
import java.util.Map;
|
|
6
6
|
import java.util.Set;
|
|
7
7
|
import java.util.HashSet;
|
|
8
|
+
import java.util.List;
|
|
9
|
+
import java.util.ArrayList;
|
|
8
10
|
import org.json.JSONObject;
|
|
9
11
|
import org.json.JSONArray;
|
|
10
12
|
|
|
@@ -38,9 +40,18 @@ public class SharedPreferencesStorage {
|
|
|
38
40
|
editor.putStringSet(key, (Set<String>) value);
|
|
39
41
|
} else {
|
|
40
42
|
// Convert complex objects to JSON
|
|
41
|
-
String json
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
String json;
|
|
44
|
+
if (value instanceof JSONObject) {
|
|
45
|
+
json = ((JSONObject) value).toString();
|
|
46
|
+
} else {
|
|
47
|
+
// Use reflection to convert object to JSON string
|
|
48
|
+
try {
|
|
49
|
+
json = objectToJsonString(value);
|
|
50
|
+
} catch (Exception e) {
|
|
51
|
+
// Fallback to string representation
|
|
52
|
+
json = value.toString();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
44
55
|
editor.putString(key, json);
|
|
45
56
|
}
|
|
46
57
|
return editor.commit();
|
|
@@ -83,19 +94,19 @@ public class SharedPreferencesStorage {
|
|
|
83
94
|
return editor.commit();
|
|
84
95
|
}
|
|
85
96
|
|
|
86
|
-
public
|
|
97
|
+
public List<String> keys() {
|
|
87
98
|
return keys(null);
|
|
88
99
|
}
|
|
89
100
|
|
|
90
|
-
public
|
|
101
|
+
public List<String> keys(String pattern) {
|
|
91
102
|
Set<String> allKeys = prefs.getAll().keySet();
|
|
92
103
|
|
|
93
104
|
if (pattern == null) {
|
|
94
|
-
return allKeys;
|
|
105
|
+
return new ArrayList<>(allKeys);
|
|
95
106
|
}
|
|
96
107
|
|
|
97
108
|
// Filter keys by pattern
|
|
98
|
-
|
|
109
|
+
List<String> filteredKeys = new ArrayList<>();
|
|
99
110
|
for (String key : allKeys) {
|
|
100
111
|
if (key.startsWith(pattern) || key.contains(pattern)) {
|
|
101
112
|
filteredKeys.add(key);
|
|
@@ -111,4 +122,81 @@ public class SharedPreferencesStorage {
|
|
|
111
122
|
public Map<String, ?> getAll() {
|
|
112
123
|
return prefs.getAll();
|
|
113
124
|
}
|
|
125
|
+
|
|
126
|
+
public SizeInfo size() {
|
|
127
|
+
Map<String, ?> all = prefs.getAll();
|
|
128
|
+
long totalSize = 0;
|
|
129
|
+
int count = all.size();
|
|
130
|
+
|
|
131
|
+
for (Map.Entry<String, ?> entry : all.entrySet()) {
|
|
132
|
+
String key = entry.getKey();
|
|
133
|
+
Object value = entry.getValue();
|
|
134
|
+
|
|
135
|
+
// Estimate size (key + value in bytes)
|
|
136
|
+
totalSize += key.getBytes().length;
|
|
137
|
+
if (value != null) {
|
|
138
|
+
totalSize += value.toString().getBytes().length;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return new SizeInfo(totalSize, count);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Convert an object to JSON string using reflection
|
|
147
|
+
*/
|
|
148
|
+
private String objectToJsonString(Object obj) throws Exception {
|
|
149
|
+
if (obj == null) {
|
|
150
|
+
return "null";
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (obj instanceof String || obj instanceof Number || obj instanceof Boolean) {
|
|
154
|
+
return obj.toString();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (obj instanceof Map) {
|
|
158
|
+
JSONObject jsonObj = new JSONObject();
|
|
159
|
+
Map<?, ?> map = (Map<?, ?>) obj;
|
|
160
|
+
for (Map.Entry<?, ?> entry : map.entrySet()) {
|
|
161
|
+
String key = entry.getKey().toString();
|
|
162
|
+
jsonObj.put(key, entry.getValue());
|
|
163
|
+
}
|
|
164
|
+
return jsonObj.toString();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (obj instanceof List || obj.getClass().isArray()) {
|
|
168
|
+
JSONArray jsonArray = new JSONArray();
|
|
169
|
+
if (obj instanceof List) {
|
|
170
|
+
List<?> list = (List<?>) obj;
|
|
171
|
+
for (Object item : list) {
|
|
172
|
+
jsonArray.put(item);
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
Object[] array = (Object[]) obj;
|
|
176
|
+
for (Object item : array) {
|
|
177
|
+
jsonArray.put(item);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return jsonArray.toString();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// For other objects, create a simple JSON object with their string representation
|
|
184
|
+
JSONObject jsonObj = new JSONObject();
|
|
185
|
+
jsonObj.put("value", obj.toString());
|
|
186
|
+
jsonObj.put("type", obj.getClass().getSimpleName());
|
|
187
|
+
return jsonObj.toString();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Size information class
|
|
192
|
+
*/
|
|
193
|
+
public static class SizeInfo {
|
|
194
|
+
public final long total;
|
|
195
|
+
public final int count;
|
|
196
|
+
|
|
197
|
+
public SizeInfo(long total, int count) {
|
|
198
|
+
this.total = total;
|
|
199
|
+
this.count = count;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
114
202
|
}
|
|
@@ -11,7 +11,6 @@ import com.strata.storage.SQLiteStorage;
|
|
|
11
11
|
import org.json.JSONArray;
|
|
12
12
|
import org.json.JSONException;
|
|
13
13
|
import java.util.List;
|
|
14
|
-
import java.util.Set;
|
|
15
14
|
|
|
16
15
|
/**
|
|
17
16
|
* Main Capacitor plugin for Strata Storage
|
|
@@ -226,40 +225,31 @@ public class StrataStoragePlugin extends Plugin {
|
|
|
226
225
|
String storage = call.getString("storage", "preferences");
|
|
227
226
|
|
|
228
227
|
try {
|
|
229
|
-
|
|
228
|
+
JSObject result = new JSObject();
|
|
230
229
|
|
|
231
230
|
switch (storage) {
|
|
232
231
|
case "secure":
|
|
233
|
-
|
|
232
|
+
EncryptedStorage.SizeInfo encryptedSizeInfo = encryptedStorage.size();
|
|
233
|
+
result.put("total", encryptedSizeInfo.total);
|
|
234
|
+
result.put("count", encryptedSizeInfo.count);
|
|
234
235
|
break;
|
|
235
236
|
case "sqlite":
|
|
236
|
-
|
|
237
|
+
SQLiteStorage.SizeInfo sqliteSizeInfo = sqliteStorage.size();
|
|
238
|
+
result.put("total", sqliteSizeInfo.total);
|
|
239
|
+
result.put("count", sqliteSizeInfo.count);
|
|
237
240
|
break;
|
|
238
241
|
case "preferences":
|
|
239
242
|
default:
|
|
240
|
-
|
|
243
|
+
SharedPreferencesStorage.SizeInfo prefsSizeInfo = sharedPrefsStorage.size();
|
|
244
|
+
result.put("total", prefsSizeInfo.total);
|
|
245
|
+
result.put("count", prefsSizeInfo.count);
|
|
241
246
|
break;
|
|
242
247
|
}
|
|
243
248
|
|
|
244
|
-
JSObject result = new JSObject();
|
|
245
|
-
result.put("total", sizeInfo.total);
|
|
246
|
-
result.put("count", sizeInfo.count);
|
|
247
249
|
call.resolve(result);
|
|
248
250
|
} catch (Exception e) {
|
|
249
251
|
call.reject("Failed to get size", e);
|
|
250
252
|
}
|
|
251
253
|
}
|
|
252
254
|
|
|
253
|
-
/**
|
|
254
|
-
* Size information class
|
|
255
|
-
*/
|
|
256
|
-
static class SizeInfo {
|
|
257
|
-
public final long total;
|
|
258
|
-
public final int count;
|
|
259
|
-
|
|
260
|
-
public SizeInfo(long total, int count) {
|
|
261
|
-
this.total = total;
|
|
262
|
-
this.count = count;
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
255
|
}
|
|
@@ -8,6 +8,10 @@ import androidx.security.crypto.MasterKey;
|
|
|
8
8
|
import java.util.Set;
|
|
9
9
|
import java.util.HashSet;
|
|
10
10
|
import java.util.Map;
|
|
11
|
+
import java.util.List;
|
|
12
|
+
import java.util.ArrayList;
|
|
13
|
+
import org.json.JSONObject;
|
|
14
|
+
import org.json.JSONArray;
|
|
11
15
|
|
|
12
16
|
public class EncryptedStorage {
|
|
13
17
|
private SharedPreferences encryptedPrefs;
|
|
@@ -42,9 +46,31 @@ public class EncryptedStorage {
|
|
|
42
46
|
}
|
|
43
47
|
}
|
|
44
48
|
|
|
45
|
-
public boolean set(String key,
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
public boolean set(String key, Object value) {
|
|
50
|
+
try {
|
|
51
|
+
String stringValue;
|
|
52
|
+
if (value instanceof String) {
|
|
53
|
+
stringValue = (String) value;
|
|
54
|
+
} else {
|
|
55
|
+
// Convert complex objects to JSON
|
|
56
|
+
if (value instanceof JSONObject) {
|
|
57
|
+
stringValue = ((JSONObject) value).toString();
|
|
58
|
+
} else {
|
|
59
|
+
// Use helper method to convert object to JSON string
|
|
60
|
+
try {
|
|
61
|
+
stringValue = objectToJsonString(value);
|
|
62
|
+
} catch (Exception e) {
|
|
63
|
+
// Fallback to string representation
|
|
64
|
+
stringValue = value.toString();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
editor.putString(key, stringValue);
|
|
69
|
+
return editor.commit();
|
|
70
|
+
} catch (Exception e) {
|
|
71
|
+
e.printStackTrace();
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
48
74
|
}
|
|
49
75
|
|
|
50
76
|
public String get(String key) {
|
|
@@ -79,19 +105,19 @@ public class EncryptedStorage {
|
|
|
79
105
|
return editor.commit();
|
|
80
106
|
}
|
|
81
107
|
|
|
82
|
-
public
|
|
108
|
+
public List<String> keys() {
|
|
83
109
|
return keys(null);
|
|
84
110
|
}
|
|
85
111
|
|
|
86
|
-
public
|
|
112
|
+
public List<String> keys(String pattern) {
|
|
87
113
|
Set<String> allKeys = encryptedPrefs.getAll().keySet();
|
|
88
114
|
|
|
89
115
|
if (pattern == null) {
|
|
90
|
-
return allKeys;
|
|
116
|
+
return new ArrayList<>(allKeys);
|
|
91
117
|
}
|
|
92
118
|
|
|
93
119
|
// Filter keys by pattern
|
|
94
|
-
|
|
120
|
+
List<String> filteredKeys = new ArrayList<>();
|
|
95
121
|
for (String key : allKeys) {
|
|
96
122
|
if (key.startsWith(pattern) || key.contains(pattern)) {
|
|
97
123
|
filteredKeys.add(key);
|
|
@@ -103,4 +129,81 @@ public class EncryptedStorage {
|
|
|
103
129
|
public boolean has(String key) {
|
|
104
130
|
return encryptedPrefs.contains(key);
|
|
105
131
|
}
|
|
132
|
+
|
|
133
|
+
public SizeInfo size() {
|
|
134
|
+
Map<String, ?> all = encryptedPrefs.getAll();
|
|
135
|
+
long totalSize = 0;
|
|
136
|
+
int count = all.size();
|
|
137
|
+
|
|
138
|
+
for (Map.Entry<String, ?> entry : all.entrySet()) {
|
|
139
|
+
String key = entry.getKey();
|
|
140
|
+
Object value = entry.getValue();
|
|
141
|
+
|
|
142
|
+
// Estimate size (key + value in bytes)
|
|
143
|
+
totalSize += key.getBytes().length;
|
|
144
|
+
if (value != null) {
|
|
145
|
+
totalSize += value.toString().getBytes().length;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return new SizeInfo(totalSize, count);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Convert an object to JSON string using reflection
|
|
154
|
+
*/
|
|
155
|
+
private String objectToJsonString(Object obj) throws Exception {
|
|
156
|
+
if (obj == null) {
|
|
157
|
+
return "null";
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (obj instanceof String || obj instanceof Number || obj instanceof Boolean) {
|
|
161
|
+
return obj.toString();
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (obj instanceof Map) {
|
|
165
|
+
JSONObject jsonObj = new JSONObject();
|
|
166
|
+
Map<?, ?> map = (Map<?, ?>) obj;
|
|
167
|
+
for (Map.Entry<?, ?> entry : map.entrySet()) {
|
|
168
|
+
String key = entry.getKey().toString();
|
|
169
|
+
jsonObj.put(key, entry.getValue());
|
|
170
|
+
}
|
|
171
|
+
return jsonObj.toString();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (obj instanceof List || obj.getClass().isArray()) {
|
|
175
|
+
JSONArray jsonArray = new JSONArray();
|
|
176
|
+
if (obj instanceof List) {
|
|
177
|
+
List<?> list = (List<?>) obj;
|
|
178
|
+
for (Object item : list) {
|
|
179
|
+
jsonArray.put(item);
|
|
180
|
+
}
|
|
181
|
+
} else {
|
|
182
|
+
Object[] array = (Object[]) obj;
|
|
183
|
+
for (Object item : array) {
|
|
184
|
+
jsonArray.put(item);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return jsonArray.toString();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// For other objects, create a simple JSON object with their string representation
|
|
191
|
+
JSONObject jsonObj = new JSONObject();
|
|
192
|
+
jsonObj.put("value", obj.toString());
|
|
193
|
+
jsonObj.put("type", obj.getClass().getSimpleName());
|
|
194
|
+
return jsonObj.toString();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Size information class
|
|
199
|
+
*/
|
|
200
|
+
public static class SizeInfo {
|
|
201
|
+
public final long total;
|
|
202
|
+
public final int count;
|
|
203
|
+
|
|
204
|
+
public SizeInfo(long total, int count) {
|
|
205
|
+
this.total = total;
|
|
206
|
+
this.count = count;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
106
209
|
}
|