strata-storage 2.3.0 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/android/src/main/java/com/strata/storage/EncryptedStorage.java +84 -21
  2. package/android/src/main/java/com/strata/storage/SQLiteStorage.java +140 -58
  3. package/android/src/main/java/com/strata/storage/SharedPreferencesStorage.java +66 -5
  4. package/android/src/main/java/com/stratastorage/StrataStoragePlugin.java +83 -10
  5. package/dist/adapters/web/MemoryAdapter.d.ts.map +1 -1
  6. package/dist/adapters/web/MemoryAdapter.js +7 -1
  7. package/dist/adapters/web/SessionStorageAdapter.d.ts.map +1 -1
  8. package/dist/adapters/web/SessionStorageAdapter.js +3 -2
  9. package/dist/android/src/main/java/com/strata/storage/EncryptedStorage.java +84 -21
  10. package/dist/android/src/main/java/com/strata/storage/SQLiteStorage.java +140 -58
  11. package/dist/android/src/main/java/com/strata/storage/SharedPreferencesStorage.java +66 -5
  12. package/dist/android/src/main/java/com/stratastorage/StrataStoragePlugin.java +83 -10
  13. package/dist/core/Strata.d.ts.map +1 -1
  14. package/dist/core/Strata.js +4 -6
  15. package/dist/firebase.d.ts.map +1 -1
  16. package/dist/firebase.js +75 -13
  17. package/dist/ios/Plugin/SQLiteStorage.swift +100 -30
  18. package/dist/ios/Plugin/UserDefaultsStorage.swift +13 -2
  19. package/dist/package.json +5 -5
  20. package/dist/plugin/index.d.ts.map +1 -1
  21. package/dist/plugin/index.js +31 -6
  22. package/dist/plugin/web.d.ts +5 -1
  23. package/dist/plugin/web.d.ts.map +1 -1
  24. package/dist/plugin/web.js +55 -32
  25. package/dist/utils/index.d.ts.map +1 -1
  26. package/dist/utils/index.js +7 -2
  27. package/ios/Plugin/SQLiteStorage.swift +100 -30
  28. package/ios/Plugin/UserDefaultsStorage.swift +13 -2
  29. package/package.json +17 -19
@@ -8,6 +8,7 @@ import com.getcapacitor.annotation.CapacitorPlugin;
8
8
  import com.strata.storage.SharedPreferencesStorage;
9
9
  import com.strata.storage.EncryptedStorage;
10
10
  import com.strata.storage.SQLiteStorage;
11
+ import android.util.Log;
11
12
  import org.json.JSONArray;
12
13
  import org.json.JSONException;
13
14
  import java.util.List;
@@ -30,7 +31,7 @@ public class StrataStoragePlugin extends Plugin {
30
31
  sqliteStorage = new SQLiteStorage(getContext());
31
32
  } catch (Exception e) {
32
33
  // Log error but don't crash - some storage types may not be available
33
- e.printStackTrace();
34
+ Log.e("StrataStorage", "Failed to initialize storage", e);
34
35
  }
35
36
  }
36
37
 
@@ -68,20 +69,32 @@ public class StrataStoragePlugin extends Plugin {
68
69
 
69
70
  try {
70
71
  Object value = null;
71
-
72
+
72
73
  switch (storage) {
73
74
  case "secure":
75
+ if (encryptedStorage == null) {
76
+ call.reject("Encrypted storage not available");
77
+ return;
78
+ }
74
79
  value = encryptedStorage.get(key);
75
80
  break;
76
81
  case "sqlite":
82
+ if (sqliteStorage == null) {
83
+ call.reject("SQLite storage not available");
84
+ return;
85
+ }
77
86
  value = sqliteStorage.get(key);
78
87
  break;
79
88
  case "preferences":
80
89
  default:
90
+ if (sharedPrefsStorage == null) {
91
+ call.reject("Preferences storage not available");
92
+ return;
93
+ }
81
94
  value = sharedPrefsStorage.get(key);
82
95
  break;
83
96
  }
84
-
97
+
85
98
  JSObject result = new JSObject();
86
99
  result.put("value", value);
87
100
  call.resolve(result);
@@ -107,17 +120,29 @@ public class StrataStoragePlugin extends Plugin {
107
120
  try {
108
121
  switch (storage) {
109
122
  case "secure":
123
+ if (encryptedStorage == null) {
124
+ call.reject("Encrypted storage not available");
125
+ return;
126
+ }
110
127
  encryptedStorage.set(key, value);
111
128
  break;
112
129
  case "sqlite":
130
+ if (sqliteStorage == null) {
131
+ call.reject("SQLite storage not available");
132
+ return;
133
+ }
113
134
  sqliteStorage.set(key, value);
114
135
  break;
115
136
  case "preferences":
116
137
  default:
138
+ if (sharedPrefsStorage == null) {
139
+ call.reject("Preferences storage not available");
140
+ return;
141
+ }
117
142
  sharedPrefsStorage.set(key, value);
118
143
  break;
119
144
  }
120
-
145
+
121
146
  call.resolve();
122
147
  } catch (Exception e) {
123
148
  call.reject("Failed to set value", e);
@@ -140,17 +165,29 @@ public class StrataStoragePlugin extends Plugin {
140
165
  try {
141
166
  switch (storage) {
142
167
  case "secure":
168
+ if (encryptedStorage == null) {
169
+ call.reject("Encrypted storage not available");
170
+ return;
171
+ }
143
172
  encryptedStorage.remove(key);
144
173
  break;
145
174
  case "sqlite":
175
+ if (sqliteStorage == null) {
176
+ call.reject("SQLite storage not available");
177
+ return;
178
+ }
146
179
  sqliteStorage.remove(key);
147
180
  break;
148
181
  case "preferences":
149
182
  default:
183
+ if (sharedPrefsStorage == null) {
184
+ call.reject("Preferences storage not available");
185
+ return;
186
+ }
150
187
  sharedPrefsStorage.remove(key);
151
188
  break;
152
189
  }
153
-
190
+
154
191
  call.resolve();
155
192
  } catch (Exception e) {
156
193
  call.reject("Failed to remove value", e);
@@ -168,17 +205,29 @@ public class StrataStoragePlugin extends Plugin {
168
205
  try {
169
206
  switch (storage) {
170
207
  case "secure":
208
+ if (encryptedStorage == null) {
209
+ call.reject("Encrypted storage not available");
210
+ return;
211
+ }
171
212
  encryptedStorage.clear(prefix);
172
213
  break;
173
214
  case "sqlite":
215
+ if (sqliteStorage == null) {
216
+ call.reject("SQLite storage not available");
217
+ return;
218
+ }
174
219
  sqliteStorage.clear(prefix);
175
220
  break;
176
221
  case "preferences":
177
222
  default:
223
+ if (sharedPrefsStorage == null) {
224
+ call.reject("Preferences storage not available");
225
+ return;
226
+ }
178
227
  sharedPrefsStorage.clear(prefix);
179
228
  break;
180
229
  }
181
-
230
+
182
231
  call.resolve();
183
232
  } catch (Exception e) {
184
233
  call.reject("Failed to clear storage", e);
@@ -195,20 +244,32 @@ public class StrataStoragePlugin extends Plugin {
195
244
 
196
245
  try {
197
246
  List<String> keys = null;
198
-
247
+
199
248
  switch (storage) {
200
249
  case "secure":
250
+ if (encryptedStorage == null) {
251
+ call.reject("Encrypted storage not available");
252
+ return;
253
+ }
201
254
  keys = encryptedStorage.keys(pattern);
202
255
  break;
203
256
  case "sqlite":
257
+ if (sqliteStorage == null) {
258
+ call.reject("SQLite storage not available");
259
+ return;
260
+ }
204
261
  keys = sqliteStorage.keys(pattern);
205
262
  break;
206
263
  case "preferences":
207
264
  default:
265
+ if (sharedPrefsStorage == null) {
266
+ call.reject("Preferences storage not available");
267
+ return;
268
+ }
208
269
  keys = sharedPrefsStorage.keys(pattern);
209
270
  break;
210
271
  }
211
-
272
+
212
273
  JSObject result = new JSObject();
213
274
  result.put("keys", new JSONArray(keys));
214
275
  call.resolve(result);
@@ -226,26 +287,38 @@ public class StrataStoragePlugin extends Plugin {
226
287
 
227
288
  try {
228
289
  JSObject result = new JSObject();
229
-
290
+
230
291
  switch (storage) {
231
292
  case "secure":
293
+ if (encryptedStorage == null) {
294
+ call.reject("Encrypted storage not available");
295
+ return;
296
+ }
232
297
  EncryptedStorage.SizeInfo encryptedSizeInfo = encryptedStorage.size();
233
298
  result.put("total", encryptedSizeInfo.total);
234
299
  result.put("count", encryptedSizeInfo.count);
235
300
  break;
236
301
  case "sqlite":
302
+ if (sqliteStorage == null) {
303
+ call.reject("SQLite storage not available");
304
+ return;
305
+ }
237
306
  SQLiteStorage.SizeInfo sqliteSizeInfo = sqliteStorage.size();
238
307
  result.put("total", sqliteSizeInfo.total);
239
308
  result.put("count", sqliteSizeInfo.count);
240
309
  break;
241
310
  case "preferences":
242
311
  default:
312
+ if (sharedPrefsStorage == null) {
313
+ call.reject("Preferences storage not available");
314
+ return;
315
+ }
243
316
  SharedPreferencesStorage.SizeInfo prefsSizeInfo = sharedPrefsStorage.size();
244
317
  result.put("total", prefsSizeInfo.total);
245
318
  result.put("count", prefsSizeInfo.count);
246
319
  break;
247
320
  }
248
-
321
+
249
322
  call.resolve(result);
250
323
  } catch (Exception e) {
251
324
  call.reject("Failed to get size", e);
@@ -1 +1 @@
1
- {"version":3,"file":"MemoryAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/web/MemoryAdapter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EACV,WAAW,EACX,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,cAAc,EACf,MAAM,SAAS,CAAC;AAGjB;;GAEG;AACH,qBAAa,aAAc,SAAQ,WAAW;IAC5C,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAY;IACtC,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAUxC;IAEF,OAAO,CAAC,OAAO,CAAwC;IACvD,OAAO,CAAC,OAAO,CAAC,CAAS;IACzB,OAAO,CAAC,WAAW,CAAK;IAExB;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAIrC;;OAEG;IACG,UAAU,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAK9D;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAepE;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IA8B1E;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWxC;;OAEG;IACG,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBlD;;OAEG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKxC;;OAEG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAkBxD;;OAEG;IACG,KAAK,CAAC,CAAC,GAAG,OAAO,EAAE,SAAS,EAAE,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,CAAC,CAAA;KAAE,CAAC,CAAC;IAgC9F;;OAEG;IACH,cAAc,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAOlD;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAK7B"}
1
+ {"version":3,"file":"MemoryAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/web/MemoryAdapter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EACV,WAAW,EACX,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,cAAc,EACf,MAAM,SAAS,CAAC;AAIjB;;GAEG;AACH,qBAAa,aAAc,SAAQ,WAAW;IAC5C,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAY;IACtC,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAUxC;IAEF,OAAO,CAAC,OAAO,CAAwC;IACvD,OAAO,CAAC,OAAO,CAAC,CAAS;IACzB,OAAO,CAAC,WAAW,CAAK;IAExB;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAIrC;;OAEG;IACG,UAAU,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAK9D;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAepE;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAiC1E;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWxC;;OAEG;IACG,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBlD;;OAEG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKxC;;OAEG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAkBxD;;OAEG;IACG,KAAK,CAAC,CAAC,GAAG,OAAO,EAAE,SAAS,EAAE,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,CAAC,CAAA;KAAE,CAAC,CAAC;IAgC9F;;OAEG;IACH,cAAc,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAOlD;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAK7B"}
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { BaseAdapter } from "../../core/BaseAdapter.js";
6
6
  import { deepClone } from "../../utils/index.js";
7
+ import { QuotaExceededError } from "../../utils/errors.js";
7
8
  /**
8
9
  * In-memory storage adapter using Map
9
10
  */
@@ -62,7 +63,12 @@ export class MemoryAdapter extends BaseAdapter {
62
63
  const oldSize = oldValue ? this.calculateSize(oldValue) : 0;
63
64
  const projectedSize = this.currentSize - oldSize + newSize;
64
65
  if (projectedSize > this.maxSize) {
65
- throw new Error(`Memory storage size limit exceeded. Limit: ${this.maxSize}, Projected: ${projectedSize}`);
66
+ throw new QuotaExceededError('Memory storage size limit exceeded', {
67
+ limit: this.maxSize,
68
+ current: this.currentSize,
69
+ projected: projectedSize,
70
+ key,
71
+ });
66
72
  }
67
73
  }
68
74
  // Store a deep clone to prevent external modifications
@@ -1 +1 @@
1
- {"version":3,"file":"SessionStorageAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/web/SessionStorageAdapter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEhE;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,mBAAmB;IAC5D,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAoB;IAC9C,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAUxC;gBAEU,MAAM,SAAK;IAIvB;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAgBrC;;OAEG;IACH,SAAS,CAAC,UAAU,IAAI,OAAO;IAI/B;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAoBtF;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB5F;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASxC;;OAEG;IACG,KAAK,CAAC,OAAO,CAAC,EAAE,OAAO,SAAS,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBpE;;OAEG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAmBxD;;OAEG;IACG,IAAI,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,SAAS,EAAE,QAAQ,CAAC;IAwCnE;;;OAGG;IACH,SAAS,CACP,QAAQ,EAAE,OAAO,SAAS,EAAE,oBAAoB,GAC/C,OAAO,SAAS,EAAE,mBAAmB;CAKzC"}
1
+ {"version":3,"file":"SessionStorageAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/web/SessionStorageAdapter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAEhE;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,mBAAmB;IAC5D,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAoB;IAC9C,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAUxC;gBAEU,MAAM,SAAK;IAIvB;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAgBrC;;OAEG;IACH,SAAS,CAAC,UAAU,IAAI,OAAO;IAI/B;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAoBtF;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,SAAS,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB5F;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASxC;;OAEG;IACG,KAAK,CAAC,OAAO,CAAC,EAAE,OAAO,SAAS,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBpE;;OAEG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAmBxD;;OAEG;IACG,IAAI,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,SAAS,EAAE,QAAQ,CAAC;IAwCnE;;;OAGG;IACH,SAAS,CACP,QAAQ,EAAE,OAAO,SAAS,EAAE,oBAAoB,GAC/C,OAAO,SAAS,EAAE,mBAAmB;CAKzC"}
@@ -3,6 +3,7 @@
3
3
  * Provides session-scoped storage with 5-10MB limit
4
4
  */
5
5
  import { LocalStorageAdapter } from "./LocalStorageAdapter.js";
6
+ import { QuotaExceededError, SerializationError } from "../../utils/errors.js";
6
7
  /**
7
8
  * Browser sessionStorage adapter
8
9
  * Extends LocalStorageAdapter as the API is identical
@@ -80,9 +81,9 @@ export class SessionStorageAdapter extends LocalStorageAdapter {
80
81
  }
81
82
  catch (error) {
82
83
  if (this.isQuotaError(error)) {
83
- throw new Error(`SessionStorage quota exceeded for key ${key}`);
84
+ throw new QuotaExceededError('SessionStorage quota exceeded', { key, error });
84
85
  }
85
- throw new Error(`Failed to store key ${key} in sessionStorage: ${error}`);
86
+ throw new SerializationError(`Failed to store key ${key} in sessionStorage`, error);
86
87
  }
87
88
  // Emit change event
88
89
  this.emitChange(key, oldValue?.value, value.value, 'local');
@@ -3,42 +3,52 @@ package com.strata.storage;
3
3
  import android.content.Context;
4
4
  import android.content.SharedPreferences;
5
5
  import android.os.Build;
6
+ import android.util.Log;
6
7
  import androidx.security.crypto.EncryptedSharedPreferences;
7
8
  import androidx.security.crypto.MasterKey;
9
+ import java.security.GeneralSecurityException;
10
+ import java.io.IOException;
8
11
  import java.util.Set;
9
12
  import java.util.HashSet;
10
13
  import java.util.Map;
11
14
  import java.util.List;
12
15
  import java.util.ArrayList;
13
16
  import org.json.JSONObject;
17
+ import org.json.JSONArray;
14
18
 
15
19
  public class EncryptedStorage {
16
20
  private SharedPreferences encryptedPrefs;
17
21
  private SharedPreferences.Editor editor;
18
22
  private static final String DEFAULT_NAME = "StrataSecureStorage";
19
23
 
20
- public EncryptedStorage(Context context) throws Exception {
24
+ public EncryptedStorage(Context context) throws GeneralSecurityException, IOException {
21
25
  this(context, DEFAULT_NAME);
22
26
  }
23
-
24
- public EncryptedStorage(Context context, String name) throws Exception {
27
+
28
+ public EncryptedStorage(Context context, String name) throws GeneralSecurityException, IOException {
25
29
  String fileName = name != null ? name : DEFAULT_NAME;
26
-
30
+
27
31
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
28
- MasterKey masterKey = new MasterKey.Builder(context)
29
- .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
30
- .build();
31
-
32
- encryptedPrefs = EncryptedSharedPreferences.create(
33
- context,
34
- fileName,
35
- masterKey,
36
- EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
37
- EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
38
- );
39
-
40
- editor = encryptedPrefs.edit();
32
+ try {
33
+ MasterKey masterKey = new MasterKey.Builder(context)
34
+ .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
35
+ .build();
36
+
37
+ encryptedPrefs = EncryptedSharedPreferences.create(
38
+ context,
39
+ fileName,
40
+ masterKey,
41
+ EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
42
+ EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
43
+ );
44
+
45
+ editor = encryptedPrefs.edit();
46
+ } catch (GeneralSecurityException | IOException e) {
47
+ Log.e("StrataStorage", "Failed to initialize encrypted storage", e);
48
+ throw e;
49
+ }
41
50
  } else {
51
+ Log.w("StrataStorage", "API < 23, using unencrypted SharedPreferences");
42
52
  // Fallback to regular SharedPreferences for older devices
43
53
  encryptedPrefs = context.getSharedPreferences(fileName, Context.MODE_PRIVATE);
44
54
  editor = encryptedPrefs.edit();
@@ -52,14 +62,22 @@ public class EncryptedStorage {
52
62
  stringValue = (String) value;
53
63
  } else {
54
64
  // Convert complex objects to JSON
55
- stringValue = value instanceof JSONObject ?
56
- ((JSONObject) value).toString() :
57
- new JSONObject(value).toString();
65
+ if (value instanceof JSONObject) {
66
+ stringValue = ((JSONObject) value).toString();
67
+ } else {
68
+ // Use helper method to convert object to JSON string
69
+ try {
70
+ stringValue = objectToJsonString(value);
71
+ } catch (Exception e) {
72
+ // Fallback to string representation
73
+ stringValue = value.toString();
74
+ }
75
+ }
58
76
  }
59
77
  editor.putString(key, stringValue);
60
78
  return editor.commit();
61
79
  } catch (Exception e) {
62
- e.printStackTrace();
80
+ Log.e("StrataStorage", "Failed to set value in encrypted storage", e);
63
81
  return false;
64
82
  }
65
83
  }
@@ -140,6 +158,51 @@ public class EncryptedStorage {
140
158
  return new SizeInfo(totalSize, count);
141
159
  }
142
160
 
161
+ /**
162
+ * Convert an object to JSON string using reflection
163
+ */
164
+ private String objectToJsonString(Object obj) throws Exception {
165
+ if (obj == null) {
166
+ return "null";
167
+ }
168
+
169
+ if (obj instanceof String || obj instanceof Number || obj instanceof Boolean) {
170
+ return obj.toString();
171
+ }
172
+
173
+ if (obj instanceof Map) {
174
+ JSONObject jsonObj = new JSONObject();
175
+ Map<?, ?> map = (Map<?, ?>) obj;
176
+ for (Map.Entry<?, ?> entry : map.entrySet()) {
177
+ String key = entry.getKey().toString();
178
+ jsonObj.put(key, entry.getValue());
179
+ }
180
+ return jsonObj.toString();
181
+ }
182
+
183
+ if (obj instanceof List || obj.getClass().isArray()) {
184
+ JSONArray jsonArray = new JSONArray();
185
+ if (obj instanceof List) {
186
+ List<?> list = (List<?>) obj;
187
+ for (Object item : list) {
188
+ jsonArray.put(item);
189
+ }
190
+ } else {
191
+ Object[] array = (Object[]) obj;
192
+ for (Object item : array) {
193
+ jsonArray.put(item);
194
+ }
195
+ }
196
+ return jsonArray.toString();
197
+ }
198
+
199
+ // For other objects, create a simple JSON object with their string representation
200
+ JSONObject jsonObj = new JSONObject();
201
+ jsonObj.put("value", obj.toString());
202
+ jsonObj.put("type", obj.getClass().getSimpleName());
203
+ return jsonObj.toString();
204
+ }
205
+
143
206
  /**
144
207
  * Size information class
145
208
  */