strata-storage 2.6.1 → 2.7.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.
- package/AI-INTEGRATION-GUIDE.md +129 -11
- package/README.md +42 -64
- package/android/AGENTS.md +18 -3
- package/android/CLAUDE.md +36 -3
- package/android/build.gradle +5 -1
- package/android/src/main/java/com/strata/storage/EncryptedStorage.java +31 -18
- package/android/src/main/java/com/strata/storage/FilesystemStorage.java +62 -10
- package/android/src/main/java/com/strata/storage/SQLiteStorage.java +65 -13
- package/android/src/main/java/com/strata/storage/SharedPreferencesStorage.java +63 -51
- package/android/src/main/java/com/stratastorage/StrataStoragePlugin.java +80 -11
- package/dist/README.md +42 -64
- package/dist/adapters/capacitor/FilesystemAdapter.d.ts +2 -2
- package/dist/adapters/capacitor/FilesystemAdapter.d.ts.map +1 -1
- package/dist/adapters/capacitor/FilesystemAdapter.js +6 -2
- package/dist/adapters/capacitor/PreferencesAdapter.d.ts +2 -2
- package/dist/adapters/capacitor/PreferencesAdapter.d.ts.map +1 -1
- package/dist/adapters/capacitor/PreferencesAdapter.js +6 -2
- package/dist/adapters/capacitor/SecureAdapter.d.ts +3 -3
- package/dist/adapters/capacitor/SecureAdapter.d.ts.map +1 -1
- package/dist/adapters/capacitor/SecureAdapter.js +6 -2
- package/dist/adapters/capacitor/SqliteAdapter.d.ts +24 -3
- package/dist/adapters/capacitor/SqliteAdapter.d.ts.map +1 -1
- package/dist/adapters/capacitor/SqliteAdapter.js +105 -23
- package/dist/adapters/capacitor/index.d.ts +4 -4
- package/dist/adapters/web/CacheAdapter.d.ts +2 -2
- package/dist/adapters/web/CacheAdapter.d.ts.map +1 -1
- package/dist/adapters/web/CacheAdapter.js +20 -5
- package/dist/adapters/web/CookieAdapter.d.ts +2 -2
- package/dist/adapters/web/CookieAdapter.d.ts.map +1 -1
- package/dist/adapters/web/CookieAdapter.js +27 -3
- package/dist/adapters/web/IndexedDBAdapter.d.ts +10 -3
- package/dist/adapters/web/IndexedDBAdapter.d.ts.map +1 -1
- package/dist/adapters/web/IndexedDBAdapter.js +19 -4
- package/dist/adapters/web/LocalStorageAdapter.d.ts +2 -2
- package/dist/adapters/web/LocalStorageAdapter.d.ts.map +1 -1
- package/dist/adapters/web/LocalStorageAdapter.js +15 -1
- package/dist/adapters/web/MemoryAdapter.d.ts +9 -2
- package/dist/adapters/web/MemoryAdapter.d.ts.map +1 -1
- package/dist/adapters/web/MemoryAdapter.js +22 -5
- package/dist/adapters/web/SessionStorageAdapter.d.ts +10 -10
- package/dist/adapters/web/SessionStorageAdapter.d.ts.map +1 -1
- package/dist/adapters/web/SessionStorageAdapter.js +17 -3
- package/dist/adapters/web/URLAdapter.d.ts +2 -2
- package/dist/adapters/web/index.d.ts +7 -7
- package/dist/capacitor.d.ts +6 -6
- package/dist/capacitor.d.ts.map +1 -1
- package/dist/capacitor.js +5 -4
- package/dist/core/AdapterRegistry.d.ts +1 -1
- package/dist/core/BaseAdapter.d.ts +21 -5
- package/dist/core/BaseAdapter.d.ts.map +1 -1
- package/dist/core/BaseAdapter.js +29 -1
- package/dist/core/Strata.d.ts +53 -7
- package/dist/core/Strata.d.ts.map +1 -1
- package/dist/core/Strata.js +581 -125
- package/dist/features/compression/index.d.ts +1 -1
- package/dist/features/compression.d.ts +28 -9
- package/dist/features/compression.d.ts.map +1 -1
- package/dist/features/compression.js +164 -77
- package/dist/features/encryption/index.d.ts +1 -1
- package/dist/features/encryption.d.ts +55 -2
- package/dist/features/encryption.d.ts.map +1 -1
- package/dist/features/encryption.js +139 -26
- package/dist/features/migration.d.ts +1 -1
- package/dist/features/migration.d.ts.map +1 -1
- package/dist/features/migration.js +7 -2
- package/dist/features/observer/index.d.ts +1 -1
- package/dist/features/observer.d.ts +1 -1
- package/dist/features/query/index.d.ts +1 -1
- package/dist/features/query.d.ts +2 -1
- package/dist/features/query.d.ts.map +1 -1
- package/dist/features/query.js +32 -7
- package/dist/features/sync/index.d.ts +1 -1
- package/dist/features/sync.d.ts +19 -3
- package/dist/features/sync.d.ts.map +1 -1
- package/dist/features/sync.js +75 -12
- package/dist/features/ttl/index.d.ts +1 -1
- package/dist/features/ttl.d.ts +2 -2
- package/dist/features/ttl.d.ts.map +1 -1
- package/dist/features/ttl.js +4 -2
- package/dist/firebase.d.ts +1 -1
- package/dist/firebase.d.ts.map +1 -1
- package/dist/firebase.js +72 -10
- package/dist/index.d.ts +24 -22
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/integrations/angular/index.d.ts +2 -2
- package/dist/integrations/angular/index.d.ts.map +1 -1
- package/dist/integrations/angular/index.js +7 -8
- package/dist/integrations/react/index.d.ts +3 -3
- package/dist/integrations/react/index.d.ts.map +1 -1
- package/dist/integrations/react/index.js +16 -4
- package/dist/integrations/vue/index.d.ts +2 -2
- package/dist/integrations/vue/index.d.ts.map +1 -1
- package/dist/integrations/vue/index.js +5 -2
- package/dist/package.json +11 -2
- package/dist/plugin/definitions.d.ts +29 -3
- package/dist/plugin/definitions.d.ts.map +1 -1
- package/dist/plugin/index.d.ts +2 -2
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +3 -0
- package/dist/plugin/web.d.ts +11 -2
- package/dist/plugin/web.d.ts.map +1 -1
- package/dist/plugin/web.js +23 -4
- package/dist/types/index.d.ts +50 -20
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -10
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +7 -0
- package/ios/AGENTS.md +14 -3
- package/ios/CLAUDE.md +25 -3
- package/ios/Plugin/FilesystemStorage.swift +19 -0
- package/ios/Plugin/SQLiteStorage.swift +59 -9
- package/ios/Plugin/StrataStoragePlugin.m +1 -0
- package/ios/Plugin/StrataStoragePlugin.swift +87 -34
- package/ios/Plugin/UserDefaultsStorage.swift +47 -46
- package/package.json +27 -24
- package/scripts/build.js +46 -27
- package/scripts/cli.js +1 -1
- package/scripts/configure.js +2 -2
- package/scripts/postinstall.js +3 -2
- package/dist/android/AGENTS.md +0 -51
- package/dist/android/CLAUDE.md +0 -89
- package/dist/android/build.gradle +0 -58
- package/dist/android/proguard-rules.pro +0 -11
- package/dist/android/settings.gradle +0 -2
- package/dist/android/src/main/AndroidManifest.xml +0 -2
- package/dist/android/src/main/java/com/strata/storage/EncryptedStorage.java +0 -218
- package/dist/android/src/main/java/com/strata/storage/FilesystemStorage.java +0 -287
- package/dist/android/src/main/java/com/strata/storage/SQLiteStorage.java +0 -371
- package/dist/android/src/main/java/com/strata/storage/SharedPreferencesStorage.java +0 -209
- package/dist/android/src/main/java/com/stratastorage/StrataStoragePlugin.java +0 -616
- package/dist/core/StorageStrategy.d.ts +0 -55
- package/dist/core/StorageStrategy.d.ts.map +0 -1
- package/dist/core/StorageStrategy.js +0 -200
- package/dist/ios/AGENTS.md +0 -48
- package/dist/ios/CLAUDE.md +0 -84
- package/dist/ios/Plugin/FilesystemStorage.swift +0 -218
- package/dist/ios/Plugin/KeychainStorage.swift +0 -233
- package/dist/ios/Plugin/SQLiteStorage.swift +0 -426
- package/dist/ios/Plugin/StrataStoragePlugin.m +0 -23
- package/dist/ios/Plugin/StrataStoragePlugin.swift +0 -411
- package/dist/ios/Plugin/UserDefaultsStorage.swift +0 -87
package/dist/android/AGENTS.md
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# AGENTS.md — android/
|
|
2
|
-
|
|
3
|
-
Last Updated: 2026-05-27
|
|
4
|
-
|
|
5
|
-
> Agent instructions for Android native development.
|
|
6
|
-
|
|
7
|
-
## Files
|
|
8
|
-
|
|
9
|
-
| File | Purpose |
|
|
10
|
-
|------|---------|
|
|
11
|
-
| `StrataStoragePlugin.java` | Capacitor plugin entry (`com.stratastorage`) |
|
|
12
|
-
| `SharedPreferencesStorage.java` | General key-value storage (`com.strata.storage`) |
|
|
13
|
-
| `EncryptedStorage.java` | Secure storage via EncryptedSharedPreferences (`com.strata.storage`); requires `androidx.security:security-crypto 1.1.0` (stable, upgraded in v2.6.0) |
|
|
14
|
-
| `SQLiteStorage.java` | SQLite database storage — multi-store (v2.6.0): `database`/`table` options honoured, full `StorageValue` wrapper round-trip, `size(detailed)` supported (`com.strata.storage`) |
|
|
15
|
-
| `FilesystemStorage.java` | File-per-key native storage under `getFilesDir()/strata_storage/` (new in v2.6.0); atomic writes via staging rename; `isAvailable()` returns `true`; no external permissions needed (`com.strata.storage`) |
|
|
16
|
-
|
|
17
|
-
## v2.6.0 Notes
|
|
18
|
-
|
|
19
|
-
- **`androidx.security 1.1.0`:** upgraded from `1.1.0-alpha06`. Requires `compileSdkVersion 34`. If Gradle sync fails, bump `compileSdkVersion` and `targetSdkVersion` to 34 in `android/app/build.gradle`.
|
|
20
|
-
- **SQLite multi-store:** `call.getString("database")` and `call.getString("table")` are now read and used. Each `(database, table)` pair → distinct `.db` file. Previously ignored.
|
|
21
|
-
- **SQLite value shape:** native `get` returns full `StorageValue` wrapper. Corrupt rows → treated as miss (no throw).
|
|
22
|
-
- **FilesystemStorage.java:** new class. Writes are atomic (staging temp → `renameTo`). `keys()` excludes `.staging/` artifacts. `size(detailed)` → `{ keys, values, metadata }`.
|
|
23
|
-
- **Pending on-device verification** — see `docs/guides/platforms/device-verification.md`.
|
|
24
|
-
|
|
25
|
-
## Agent Rules
|
|
26
|
-
|
|
27
|
-
### Security (IRON-SOLID)
|
|
28
|
-
- Sensitive data MUST use `EncryptedStorage`
|
|
29
|
-
- NEVER store secrets in `SharedPreferencesStorage`
|
|
30
|
-
- `androidx.security:security-crypto` version MUST be `1.1.0` (stable) — not alpha
|
|
31
|
-
|
|
32
|
-
### SQL Safety (IRON-SOLID)
|
|
33
|
-
- ALWAYS use parameterized queries
|
|
34
|
-
- NEVER concatenate user input into SQL strings
|
|
35
|
-
|
|
36
|
-
### Filesystem Safety
|
|
37
|
-
- NEVER read from `strata_storage/.staging/` — staging files are transient
|
|
38
|
-
- Key sanitisation must be consistent between `set`, `get`, `remove`, and `keys`
|
|
39
|
-
|
|
40
|
-
### Plugin Architecture
|
|
41
|
-
- Methods exposed through `StrataStoragePlugin.java`
|
|
42
|
-
- Each storage backend is a separate Java class
|
|
43
|
-
- Two package paths: `com.stratastorage` (plugin) and `com.strata.storage` (impl)
|
|
44
|
-
|
|
45
|
-
### Build
|
|
46
|
-
- `compileSdkVersion 34` required for `androidx.security 1.1.0`
|
|
47
|
-
- Verify Gradle build succeeds after any change
|
|
48
|
-
|
|
49
|
-
### Before Modifying
|
|
50
|
-
- Understand Capacitor plugin protocol for Android
|
|
51
|
-
- Test on Android emulator after changes; follow device-verification guide
|
package/dist/android/CLAUDE.md
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
# CLAUDE.md — android/
|
|
2
|
-
|
|
3
|
-
Last Updated: 2026-05-27
|
|
4
|
-
|
|
5
|
-
## Android Native Plugin
|
|
6
|
-
|
|
7
|
-
Java implementation of native storage backends for Capacitor.
|
|
8
|
-
|
|
9
|
-
### Files
|
|
10
|
-
|
|
11
|
-
| File | Path | Purpose |
|
|
12
|
-
|------|------|---------|
|
|
13
|
-
| `StrataStoragePlugin.java` | `src/main/java/com/stratastorage/` | Main Capacitor plugin entry |
|
|
14
|
-
| `SharedPreferencesStorage.java` | `src/main/java/com/strata/storage/` | SharedPreferences general storage |
|
|
15
|
-
| `EncryptedStorage.java` | `src/main/java/com/strata/storage/` | EncryptedSharedPreferences secure storage (`androidx.security 1.1.0`) |
|
|
16
|
-
| `SQLiteStorage.java` | `src/main/java/com/strata/storage/` | SQLite database storage — multi-store (v2.6.0) |
|
|
17
|
-
| `FilesystemStorage.java` | `src/main/java/com/strata/storage/` | File-per-key storage under `Context.getFilesDir()/strata_storage/` (new in v2.6.0) |
|
|
18
|
-
|
|
19
|
-
### Configuration
|
|
20
|
-
|
|
21
|
-
- Build: `build.gradle`
|
|
22
|
-
- Proguard: `proguard-rules.pro`
|
|
23
|
-
- Manifest: `src/main/AndroidManifest.xml`
|
|
24
|
-
|
|
25
|
-
**Note**: There are two Java package paths — `com.stratastorage` (plugin) and `com.strata.storage` (implementations).
|
|
26
|
-
|
|
27
|
-
## v2.6.0 Changes
|
|
28
|
-
|
|
29
|
-
### `androidx.security:security-crypto` 1.1.0 (stable)
|
|
30
|
-
`EncryptedStorage.java` depends on `androidx.security:security-crypto`. The
|
|
31
|
-
dependency was upgraded from `1.1.0-alpha06` to `1.1.0` (stable) in v2.6.0.
|
|
32
|
-
The `EncryptedSharedPreferences` / `MasterKey` API is unchanged. The stable
|
|
33
|
-
version requires `compileSdkVersion 34` — if Gradle sync fails after this
|
|
34
|
-
change, bump `compileSdkVersion` and `targetSdkVersion` in
|
|
35
|
-
`android/app/build.gradle` to 34.
|
|
36
|
-
|
|
37
|
-
### SQLite multi-store
|
|
38
|
-
`SQLiteStorage.java` now accepts `database` and `table` parameters from
|
|
39
|
-
`call.getString("database")` / `call.getString("table")`. Each unique pair
|
|
40
|
-
opens a distinct `.db` file in the app's internal storage. Table identifiers
|
|
41
|
-
are sanitised to `[A-Za-z0-9_]`. The full `StorageValue` wrapper is serialised
|
|
42
|
-
to JSON and stored in a single `value` column; native `get` returns the full
|
|
43
|
-
wrapper so TTL, tags, and metadata survive the round-trip. `size(detailed)`
|
|
44
|
-
returns per-column byte breakdown.
|
|
45
|
-
|
|
46
|
-
### FilesystemStorage.java (new)
|
|
47
|
-
Stores each key as `getFilesDir()/strata_storage/<sanitised-key>.json`. Writes
|
|
48
|
-
are atomic: value is written to `strata_storage/.staging/<key>.tmp`, then
|
|
49
|
-
renamed into place using `renameTo()`. Staging artifacts are excluded from
|
|
50
|
-
`keys()`. No external filesystem permissions are needed (`getFilesDir()` is
|
|
51
|
-
app-private). `isAvailable()` returns `true`. `size(detailed)` supported.
|
|
52
|
-
|
|
53
|
-
> **Pending on-device verification** — native code is complete and reviewed; see
|
|
54
|
-
> `docs/guides/platforms/device-verification.md` for the test matrix.
|
|
55
|
-
|
|
56
|
-
## Rules
|
|
57
|
-
|
|
58
|
-
### Security (IRON-SOLID)
|
|
59
|
-
- Sensitive data MUST use `EncryptedStorage` (EncryptedSharedPreferences)
|
|
60
|
-
- NEVER store credentials, tokens, or secrets in `SharedPreferencesStorage`
|
|
61
|
-
- Follow Android Keystore best practices
|
|
62
|
-
- `androidx.security:security-crypto 1.1.0` (stable) is the required version
|
|
63
|
-
|
|
64
|
-
### SQL Safety (IRON-SOLID)
|
|
65
|
-
- ALWAYS use parameterized queries in `SQLiteStorage`
|
|
66
|
-
- NEVER concatenate user input into SQL strings
|
|
67
|
-
- Use `SQLiteDatabase.query()` or prepared statements
|
|
68
|
-
|
|
69
|
-
### Filesystem Safety
|
|
70
|
-
- NEVER read from `strata_storage/.staging/` — staging files are transient
|
|
71
|
-
- Key sanitisation must be consistent between `set`, `get`, `remove`, and `keys`
|
|
72
|
-
- `getFilesDir()` is app-private; no external storage permissions required
|
|
73
|
-
|
|
74
|
-
### Plugin Architecture
|
|
75
|
-
- All native methods exposed through `StrataStoragePlugin.java`
|
|
76
|
-
- Plugin bridges Capacitor JS calls to Java implementations
|
|
77
|
-
- Each storage backend is a separate Java class
|
|
78
|
-
- Two package paths: `com.stratastorage` (plugin) and `com.strata.storage` (impl)
|
|
79
|
-
|
|
80
|
-
### Build
|
|
81
|
-
- Gradle-based build system
|
|
82
|
-
- `compileSdkVersion 34` required for `androidx.security 1.1.0`
|
|
83
|
-
- Proguard rules configured for release builds
|
|
84
|
-
- Test on Android emulator after changes; follow device-verification guide
|
|
85
|
-
|
|
86
|
-
### Before Modifying
|
|
87
|
-
- Understand the Capacitor plugin protocol for Android
|
|
88
|
-
- Test on Android emulator after changes
|
|
89
|
-
- Verify Gradle build succeeds
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
ext {
|
|
2
|
-
junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
|
|
3
|
-
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.6.1'
|
|
4
|
-
androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.5'
|
|
5
|
-
androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.5.1'
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
buildscript {
|
|
9
|
-
repositories {
|
|
10
|
-
google()
|
|
11
|
-
mavenCentral()
|
|
12
|
-
}
|
|
13
|
-
dependencies {
|
|
14
|
-
classpath 'com.android.tools.build:gradle:8.2.1'
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
apply plugin: 'com.android.library'
|
|
19
|
-
|
|
20
|
-
android {
|
|
21
|
-
namespace "com.stratastorage"
|
|
22
|
-
compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 34
|
|
23
|
-
defaultConfig {
|
|
24
|
-
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22
|
|
25
|
-
targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 34
|
|
26
|
-
versionCode 1
|
|
27
|
-
versionName "1.0"
|
|
28
|
-
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
29
|
-
}
|
|
30
|
-
buildTypes {
|
|
31
|
-
release {
|
|
32
|
-
minifyEnabled false
|
|
33
|
-
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
lintOptions {
|
|
37
|
-
abortOnError false
|
|
38
|
-
}
|
|
39
|
-
compileOptions {
|
|
40
|
-
sourceCompatibility JavaVersion.VERSION_17
|
|
41
|
-
targetCompatibility JavaVersion.VERSION_17
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
repositories {
|
|
46
|
-
google()
|
|
47
|
-
mavenCentral()
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
dependencies {
|
|
51
|
-
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
|
52
|
-
implementation project(':capacitor-android')
|
|
53
|
-
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
|
54
|
-
implementation 'androidx.security:security-crypto:1.1.0'
|
|
55
|
-
testImplementation "junit:junit:$junitVersion"
|
|
56
|
-
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
|
57
|
-
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
|
58
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
# Add project specific ProGuard rules here.
|
|
2
|
-
|
|
3
|
-
# Keep StrataStorage plugin classes
|
|
4
|
-
-keep class com.stratastorage.** { *; }
|
|
5
|
-
-keep class com.strata.storage.** { *; }
|
|
6
|
-
|
|
7
|
-
# Keep Capacitor classes
|
|
8
|
-
-keep class com.getcapacitor.** { *; }
|
|
9
|
-
|
|
10
|
-
# Keep security crypto classes for encrypted storage
|
|
11
|
-
-keep class androidx.security.crypto.** { *; }
|
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
package com.strata.storage;
|
|
2
|
-
|
|
3
|
-
import android.content.Context;
|
|
4
|
-
import android.content.SharedPreferences;
|
|
5
|
-
import android.os.Build;
|
|
6
|
-
import android.util.Log;
|
|
7
|
-
import androidx.security.crypto.EncryptedSharedPreferences;
|
|
8
|
-
import androidx.security.crypto.MasterKey;
|
|
9
|
-
import java.security.GeneralSecurityException;
|
|
10
|
-
import java.io.IOException;
|
|
11
|
-
import java.util.Set;
|
|
12
|
-
import java.util.HashSet;
|
|
13
|
-
import java.util.Map;
|
|
14
|
-
import java.util.List;
|
|
15
|
-
import java.util.ArrayList;
|
|
16
|
-
import org.json.JSONObject;
|
|
17
|
-
import org.json.JSONArray;
|
|
18
|
-
|
|
19
|
-
public class EncryptedStorage {
|
|
20
|
-
private SharedPreferences encryptedPrefs;
|
|
21
|
-
private SharedPreferences.Editor editor;
|
|
22
|
-
private static final String DEFAULT_NAME = "StrataSecureStorage";
|
|
23
|
-
|
|
24
|
-
public EncryptedStorage(Context context) throws GeneralSecurityException, IOException {
|
|
25
|
-
this(context, DEFAULT_NAME);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
public EncryptedStorage(Context context, String name) throws GeneralSecurityException, IOException {
|
|
29
|
-
String fileName = name != null ? name : DEFAULT_NAME;
|
|
30
|
-
|
|
31
|
-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
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
|
-
}
|
|
50
|
-
} else {
|
|
51
|
-
Log.w("StrataStorage", "API < 23, using unencrypted SharedPreferences");
|
|
52
|
-
// Fallback to regular SharedPreferences for older devices
|
|
53
|
-
encryptedPrefs = context.getSharedPreferences(fileName, Context.MODE_PRIVATE);
|
|
54
|
-
editor = encryptedPrefs.edit();
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
public boolean set(String key, Object value) {
|
|
59
|
-
try {
|
|
60
|
-
String stringValue;
|
|
61
|
-
if (value instanceof String) {
|
|
62
|
-
stringValue = (String) value;
|
|
63
|
-
} else {
|
|
64
|
-
// Convert complex objects to JSON
|
|
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
|
-
}
|
|
76
|
-
}
|
|
77
|
-
editor.putString(key, stringValue);
|
|
78
|
-
return editor.commit();
|
|
79
|
-
} catch (Exception e) {
|
|
80
|
-
Log.e("StrataStorage", "Failed to set value in encrypted storage", e);
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
public String get(String key) {
|
|
86
|
-
return encryptedPrefs.getString(key, null);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
public boolean remove(String key) {
|
|
90
|
-
editor.remove(key);
|
|
91
|
-
return editor.commit();
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
public boolean clear() {
|
|
95
|
-
return clear(null);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
public boolean clear(String prefix) {
|
|
99
|
-
if (prefix != null) {
|
|
100
|
-
// Clear only keys with the given prefix
|
|
101
|
-
Set<String> keysToRemove = new HashSet<>();
|
|
102
|
-
for (String key : encryptedPrefs.getAll().keySet()) {
|
|
103
|
-
if (key.startsWith(prefix) || key.contains(prefix)) {
|
|
104
|
-
keysToRemove.add(key);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
for (String key : keysToRemove) {
|
|
108
|
-
editor.remove(key);
|
|
109
|
-
}
|
|
110
|
-
} else {
|
|
111
|
-
// Clear all keys
|
|
112
|
-
editor.clear();
|
|
113
|
-
}
|
|
114
|
-
return editor.commit();
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
public List<String> keys() {
|
|
118
|
-
return keys(null);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
public List<String> keys(String pattern) {
|
|
122
|
-
Set<String> allKeys = encryptedPrefs.getAll().keySet();
|
|
123
|
-
|
|
124
|
-
if (pattern == null) {
|
|
125
|
-
return new ArrayList<>(allKeys);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Filter keys by pattern
|
|
129
|
-
List<String> filteredKeys = new ArrayList<>();
|
|
130
|
-
for (String key : allKeys) {
|
|
131
|
-
if (key.startsWith(pattern) || key.contains(pattern)) {
|
|
132
|
-
filteredKeys.add(key);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
return filteredKeys;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
public boolean has(String key) {
|
|
139
|
-
return encryptedPrefs.contains(key);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
public SizeInfo size() {
|
|
143
|
-
Map<String, ?> all = encryptedPrefs.getAll();
|
|
144
|
-
long totalSize = 0;
|
|
145
|
-
int count = all.size();
|
|
146
|
-
|
|
147
|
-
for (Map.Entry<String, ?> entry : all.entrySet()) {
|
|
148
|
-
String key = entry.getKey();
|
|
149
|
-
Object value = entry.getValue();
|
|
150
|
-
|
|
151
|
-
// Estimate size (key + value in bytes)
|
|
152
|
-
totalSize += key.getBytes().length;
|
|
153
|
-
if (value != null) {
|
|
154
|
-
totalSize += value.toString().getBytes().length;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return new SizeInfo(totalSize, count);
|
|
159
|
-
}
|
|
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
|
-
|
|
206
|
-
/**
|
|
207
|
-
* Size information class
|
|
208
|
-
*/
|
|
209
|
-
public static class SizeInfo {
|
|
210
|
-
public final long total;
|
|
211
|
-
public final int count;
|
|
212
|
-
|
|
213
|
-
public SizeInfo(long total, int count) {
|
|
214
|
-
this.total = total;
|
|
215
|
-
this.count = count;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|