|
1 | | -/// A secure storage backend for HyperStorage using platform-native encryption. |
2 | | -/// |
3 | | -/// This library provides a [SecureStorageBackend] implementation that leverages |
4 | | -/// platform-specific secure storage mechanisms to protect sensitive data through |
5 | | -/// hardware-backed encryption and operating system security features. |
6 | | -/// |
7 | | -/// ## Overview |
8 | | -/// |
9 | | -/// The hyper_secure_storage backend is designed for storing sensitive information |
10 | | -/// such as authentication tokens, API keys, user credentials, encryption keys, |
11 | | -/// and personally identifiable information (PII). It integrates with: |
12 | | -/// |
13 | | -/// - **Android**: Android Keystore system with AES256-encrypted SharedPreferences |
14 | | -/// - **iOS/macOS**: Keychain Services with configurable accessibility levels |
15 | | -/// - **Windows**: Windows Credential Store (Credential Manager) |
16 | | -/// - **Linux**: Secret Service API (libsecret) / GNOME Keyring |
17 | | -/// - **Web**: Web Cryptography API with IndexedDB storage |
18 | | -/// |
19 | | -/// ## Key Features |
20 | | -/// |
21 | | -/// ### Security |
22 | | -/// - **Hardware-Backed Encryption**: Uses device security hardware when available |
23 | | -/// - **OS-Managed Keys**: Cryptographic keys are managed by the operating system |
24 | | -/// - **Secure Enclave**: Utilizes iOS Secure Enclave and Android Keystore TEE |
25 | | -/// - **Data Protection**: Automatic encryption at rest for all stored values |
26 | | -/// - **Secure Deletion**: Platform-native secure wiping of deleted data |
27 | | -/// |
28 | | -/// ### Platform Integration |
29 | | -/// - **Biometric Protection**: Leverages device biometric authentication |
30 | | -/// - **Device Lock Integration**: Respects device lock screen security |
31 | | -/// - **App Sandboxing**: Data is isolated per application |
32 | | -/// - **System Backup**: Configurable inclusion/exclusion from system backups |
33 | | -/// |
34 | | -/// ### Developer Experience |
35 | | -/// - **Simple API**: Familiar key-value storage interface |
36 | | -/// - **Type Safety**: Strongly-typed getters and setters |
37 | | -/// - **Async Operations**: All operations are asynchronous and non-blocking |
38 | | -/// - **Error Handling**: Clear exceptions for error scenarios |
39 | | -/// |
40 | | -/// ## Installation |
41 | | -/// |
42 | | -/// Add the package to your `pubspec.yaml`: |
43 | | -/// |
44 | | -/// ```yaml |
45 | | -/// dependencies: |
46 | | -/// hyper_storage: ^latest_version |
47 | | -/// hyper_secure_storage: ^latest_version |
48 | | -/// flutter_secure_storage: ^latest_version |
49 | | -/// ``` |
50 | | -/// |
51 | | -/// ### Platform-Specific Setup |
52 | | -/// |
53 | | -/// #### Android |
54 | | -/// |
55 | | -/// Minimum SDK version 18 (Android 4.3) is required. For encrypted shared |
56 | | -/// preferences, API level 23 (Android 6.0) or higher is recommended. |
57 | | -/// |
58 | | -/// No additional configuration required for basic usage. |
59 | | -/// |
60 | | -/// #### iOS/macOS |
61 | | -/// |
62 | | -/// Enable Keychain Sharing in Xcode if you need to share data between apps: |
63 | | -/// |
64 | | -/// 1. Open your project in Xcode |
65 | | -/// 2. Select your target |
66 | | -/// 3. Go to "Signing & Capabilities" |
67 | | -/// 4. Add "Keychain Sharing" capability |
68 | | -/// 5. Add a keychain group identifier |
69 | | -/// |
70 | | -/// #### Linux |
71 | | -/// |
72 | | -/// Install libsecret: |
73 | | -/// |
74 | | -/// ```bash |
75 | | -/// sudo apt-get install libsecret-1-dev |
76 | | -/// ``` |
77 | | -/// |
78 | | -/// #### Web |
79 | | -/// |
80 | | -/// No additional setup required. Uses browser's built-in secure storage APIs. |
81 | | -/// |
82 | | -/// ## Usage |
83 | | -/// |
84 | | -/// ### Basic Usage |
85 | | -/// |
86 | | -/// ```dart |
87 | | -/// import 'package:hyper_storage/hyper_storage.dart'; |
88 | | -/// import 'package:hyper_secure_storage/hyper_secure_storage_backend.dart'; |
89 | | -/// |
90 | | -/// // Initialize the storage with secure backend |
91 | | -/// final storage = await HyperStorage.getInstance( |
92 | | -/// backend: SecureStorageBackend(), |
93 | | -/// ); |
94 | | -/// |
95 | | -/// // Store sensitive data |
96 | | -/// await storage.setString('auth_token', 'eyJhbGciOiJIUzI1NiIs...'); |
97 | | -/// await storage.setInt('user_id', 12345); |
98 | | -/// await storage.setBool('biometric_enabled', true); |
99 | | -/// |
100 | | -/// // Retrieve data |
101 | | -/// final token = await storage.getString('auth_token'); |
102 | | -/// final userId = await storage.getInt('user_id'); |
103 | | -/// final biometricEnabled = await storage.getBool('biometric_enabled'); |
104 | | -/// |
105 | | -/// // Remove data |
106 | | -/// await storage.remove('auth_token'); |
107 | | -/// |
108 | | -/// // Clear all data (e.g., on logout) |
109 | | -/// await storage.clear(); |
110 | | -/// ``` |
111 | | -/// |
112 | | -/// ### Custom Configuration |
113 | | -/// |
114 | | -/// ```dart |
115 | | -/// import 'package:flutter_secure_storage/flutter_secure_storage.dart'; |
116 | | -/// import 'package:hyper_secure_storage/hyper_secure_storage_backend.dart'; |
117 | | -/// |
118 | | -/// // High-security configuration for sensitive applications |
119 | | -/// final secureBackend = SecureStorageBackend( |
120 | | -/// storage: FlutterSecureStorage( |
121 | | -/// aOptions: AndroidOptions( |
122 | | -/// encryptedSharedPreferences: true, |
123 | | -/// keyCipherAlgorithm: KeyCipherAlgorithm.RSA_ECB_OAEPwithSHA_256andMGF1Padding, |
124 | | -/// storageCipherAlgorithm: StorageCipherAlgorithm.AES_GCM_NoPadding, |
125 | | -/// ), |
126 | | -/// iOptions: IOSOptions( |
127 | | -/// accessibility: KeychainAccessibility.first_unlock_this_device_only, |
128 | | -/// synchronizable: false, // Don't sync to iCloud |
129 | | -/// ), |
130 | | -/// ), |
131 | | -/// ); |
132 | | -/// |
133 | | -/// final storage = await HyperStorage.getInstance(backend: secureBackend); |
134 | | -/// ``` |
135 | | -/// |
136 | | -/// ### Common Use Cases |
137 | | -/// |
138 | | -/// #### Authentication Flow |
139 | | -/// |
140 | | -/// ```dart |
141 | | -/// // Store authentication data on login |
142 | | -/// Future<void> saveAuthData(String token, String refreshToken, int userId) async { |
143 | | -/// await storage.setString('auth_token', token); |
144 | | -/// await storage.setString('refresh_token', refreshToken); |
145 | | -/// await storage.setInt('user_id', userId); |
146 | | -/// await storage.setInt('login_timestamp', DateTime.now().millisecondsSinceEpoch); |
147 | | -/// } |
148 | | -/// |
149 | | -/// // Check if user is authenticated |
150 | | -/// Future<bool> isAuthenticated() async { |
151 | | -/// final token = await storage.getString('auth_token'); |
152 | | -/// return token != null && token.isNotEmpty; |
153 | | -/// } |
154 | | -/// |
155 | | -/// // Clear authentication data on logout |
156 | | -/// Future<void> logout() async { |
157 | | -/// await storage.removeAll(['auth_token', 'refresh_token', 'user_id', 'login_timestamp']); |
158 | | -/// } |
159 | | -/// ``` |
160 | | -/// |
161 | | -/// #### Secure Configuration Storage |
162 | | -/// |
163 | | -/// ```dart |
164 | | -/// // Store API configuration |
165 | | -/// Future<void> saveApiConfig(String apiKey, String endpoint) async { |
166 | | -/// await storage.setString('api_key', apiKey); |
167 | | -/// await storage.setString('api_endpoint', endpoint); |
168 | | -/// } |
169 | | -/// |
170 | | -/// // Retrieve API configuration |
171 | | -/// Future<Map<String, String>> getApiConfig() async { |
172 | | -/// final data = await storage.getAll(['api_key', 'api_endpoint']); |
173 | | -/// return { |
174 | | -/// 'api_key': data['api_key'] as String? ?? '', |
175 | | -/// 'api_endpoint': data['api_endpoint'] as String? ?? '', |
176 | | -/// }; |
177 | | -/// } |
178 | | -/// ``` |
179 | | -/// |
180 | | -/// #### Biometric Settings |
181 | | -/// |
182 | | -/// ```dart |
183 | | -/// // Store user's biometric preference |
184 | | -/// Future<void> setBiometricEnabled(bool enabled) async { |
185 | | -/// await storage.setBool('biometric_enabled', enabled); |
186 | | -/// if (!enabled) { |
187 | | -/// // Clear any biometric-protected data |
188 | | -/// await storage.remove('biometric_token'); |
189 | | -/// } |
190 | | -/// } |
191 | | -/// |
192 | | -/// // Check biometric setting |
193 | | -/// Future<bool> isBiometricEnabled() async { |
194 | | -/// return await storage.getBool('biometric_enabled') ?? false; |
195 | | -/// } |
196 | | -/// ``` |
197 | | -/// |
198 | | -/// ## Security Best Practices |
199 | | -/// |
200 | | -/// ### DO |
201 | | -/// |
202 | | -/// - Use secure storage for authentication tokens, API keys, and passwords |
203 | | -/// - Clear sensitive data from memory after use when possible |
204 | | -/// - Implement proper logout flows that clear all sensitive data |
205 | | -/// - Use appropriate keychain accessibility levels for your use case |
206 | | -/// - Test security configurations on physical devices |
207 | | -/// - Implement token refresh mechanisms for expired credentials |
208 | | -/// - Use biometric authentication for additional security layer |
209 | | -/// - Consider encrypting additional sensitive data before storage |
210 | | -/// |
211 | | -/// ### DON'T |
212 | | -/// |
213 | | -/// - Don't store large amounts of data (use regular storage for non-sensitive data) |
214 | | -/// - Don't store sensitive data in plain text elsewhere in your app |
215 | | -/// - Don't share secure storage keys across different security contexts |
216 | | -/// - Don't disable encryption features unless absolutely necessary |
217 | | -/// - Don't ignore platform-specific security requirements |
218 | | -/// - Don't assume stored data is accessible immediately after device boot |
219 | | -/// - Don't store secrets in source code or configuration files |
220 | | -/// |
221 | | -/// ## Platform-Specific Considerations |
222 | | -/// |
223 | | -/// ### Android |
224 | | -/// |
225 | | -/// - **API 23+**: Uses Android Keystore with hardware-backed encryption |
226 | | -/// - **API 18-22**: Uses software-based encryption fallback |
227 | | -/// - **Device Security**: Requires device lock screen for maximum security |
228 | | -/// - **App Uninstall**: Data is automatically cleared on app uninstall |
229 | | -/// - **Backup**: Encrypted SharedPreferences are excluded from backups |
230 | | -/// |
231 | | -/// ### iOS |
232 | | -/// |
233 | | -/// - **Accessibility Levels**: Choose based on when data should be accessible |
234 | | -/// - `unlocked`: Only when device is unlocked (recommended) |
235 | | -/// - `first_unlock`: After first unlock since boot |
236 | | -/// - `always`: Even when device is locked (less secure) |
237 | | -/// - **Keychain Groups**: Enable sharing between apps if needed |
238 | | -/// - **iCloud Sync**: Configure `synchronizable` flag appropriately |
239 | | -/// - **App Deletion**: Keychain items may persist after app deletion |
240 | | -/// |
241 | | -/// ### Web |
242 | | -/// |
243 | | -/// - **Browser Support**: Requires modern browsers with Web Crypto API |
244 | | -/// - **Storage Limits**: Subject to browser storage quotas |
245 | | -/// - **Incognito Mode**: Data may not persist in private browsing |
246 | | -/// - **Cross-Origin**: Data is isolated per origin |
247 | | -/// |
248 | | -/// ## Performance Characteristics |
249 | | -/// |
250 | | -/// - **Write Operations**: ~10-50ms depending on platform and data size |
251 | | -/// - **Read Operations**: ~5-20ms depending on platform and encryption |
252 | | -/// - **Batch Operations**: Use `setAll()` and `getAll()` for better performance |
253 | | -/// - **Memory Usage**: Minimal, data is encrypted on disk |
254 | | -/// - **Storage Limits**: Platform-dependent, typically several MB |
255 | | -/// |
256 | | -/// ## Error Handling |
257 | | -/// |
258 | | -/// ```dart |
259 | | -/// try { |
260 | | -/// await storage.setString('secure_key', 'sensitive_value'); |
261 | | -/// } on PlatformException catch (e) { |
262 | | -/// if (e.code == 'USER_CANCELED') { |
263 | | -/// // User canceled biometric authentication |
264 | | -/// } else if (e.code == 'NOT_AVAILABLE') { |
265 | | -/// // Secure storage not available on this device |
266 | | -/// } else { |
267 | | -/// // Handle other platform-specific errors |
268 | | -/// } |
269 | | -/// } catch (e) { |
270 | | -/// // Handle unexpected errors |
271 | | -/// } |
272 | | -/// ``` |
273 | | -/// |
274 | | -/// ## Testing |
275 | | -/// |
276 | | -/// For unit testing, use a mock backend: |
277 | | -/// |
278 | | -/// ```dart |
279 | | -/// import 'package:mockito/mockito.dart'; |
280 | | -/// import 'package:hyper_storage/hyper_storage.dart'; |
281 | | -/// |
282 | | -/// class MockSecureStorage extends Mock implements StorageBackend {} |
283 | | -/// |
284 | | -/// void main() { |
285 | | -/// test('authentication flow', () async { |
286 | | -/// final mockBackend = MockSecureStorage(); |
287 | | -/// when(mockBackend.getString('auth_token')) |
288 | | -/// .thenAnswer((_) async => 'mock_token'); |
289 | | -/// |
290 | | -/// final storage = await HyperStorage.getInstance(backend: mockBackend); |
291 | | -/// // Test your authentication logic... |
292 | | -/// }); |
293 | | -/// } |
294 | | -/// ``` |
295 | | -/// |
296 | | -/// ## Migration from Other Storage Solutions |
297 | | -/// |
298 | | -/// ### From SharedPreferences |
299 | | -/// |
300 | | -/// ```dart |
301 | | -/// // Read from old storage |
302 | | -/// final prefs = await SharedPreferences.getInstance(); |
303 | | -/// final token = prefs.getString('auth_token'); |
304 | | -/// |
305 | | -/// // Migrate to secure storage |
306 | | -/// if (token != null) { |
307 | | -/// await storage.setString('auth_token', token); |
308 | | -/// await prefs.remove('auth_token'); // Clean up old storage |
309 | | -/// } |
310 | | -/// ``` |
311 | | -/// |
312 | | -/// ### From Hive |
313 | | -/// |
314 | | -/// ```dart |
315 | | -/// final box = await Hive.openBox('secure'); |
316 | | -/// final token = box.get('auth_token'); |
317 | | -/// |
318 | | -/// if (token != null) { |
319 | | -/// await storage.setString('auth_token', token); |
320 | | -/// await box.delete('auth_token'); |
321 | | -/// } |
322 | | -/// ``` |
323 | | -/// |
324 | | -/// ## Troubleshooting |
325 | | -/// |
326 | | -/// ### Issue: Data not persisting |
327 | | -/// - Check device lock screen is configured (Android) |
328 | | -/// - Verify app has proper permissions |
329 | | -/// - Check platform-specific setup requirements |
330 | | -/// |
331 | | -/// ### Issue: Data inaccessible after device restart |
332 | | -/// - Review iOS accessibility settings |
333 | | -/// - Consider using `first_unlock` instead of `unlocked` |
334 | | -/// |
335 | | -/// ### Issue: Performance problems |
336 | | -/// - Reduce storage size (avoid large values) |
337 | | -/// - Use batch operations where possible |
338 | | -/// - Consider caching frequently accessed values |
339 | | -/// |
340 | | -/// ## Related Packages |
341 | | -/// |
342 | | -/// - [hyper_storage](https://pub.dev/packages/hyper_storage) - Core storage framework |
343 | | -/// - [hyper_storage_hive](https://pub.dev/packages/hyper_storage_hive) - High-performance local storage |
344 | | -/// - [hyper_storage_shared_preferences](https://pub.dev/packages/hyper_storage_shared_preferences) - SharedPreferences backend |
345 | | -/// - [flutter_secure_storage](https://pub.dev/packages/flutter_secure_storage) - Underlying secure storage library |
346 | | -/// |
347 | | -/// ## API Reference |
348 | | -/// |
349 | | -/// See [SecureStorageBackend] for the main class documentation. |
350 | | -/// |
351 | | -/// ## Support |
352 | | -/// |
353 | | -/// For issues, feature requests, and contributions, visit: |
354 | | -/// https://github.com/birjuvachhani/hyper_storage |
| 1 | +// Copyright © 2025 Hyperdesigned. All rights reserved. |
| 2 | +// Use of this source code is governed by a BSD license that can be |
| 3 | +// found in the LICENSE file. |
355 | 4 | library; |
356 | 5 |
|
357 | 6 | export 'src/backend.dart'; |
0 commit comments