vault_storage 0.0.2
vault_storage: ^0.0.2 copied to clipboard
A package for secure key-value and file storage using Hive and flutter_secure_storage.
Vault Storage #
A secure and performant local storage solution for Flutter applications, built with Hive, Flutter Secure Storage, and Riverpod. It provides both key-value storage and encrypted file storage, with intensive cryptographic operations offloaded to background isolates to ensure a smooth UI.
Note: This package depends on Riverpod v3 (
riverpod: ^3.0.0-dev), which is currently in pre-release. Be mindful of potential API changes in future Riverpod updates.
Features #
- Dual Storage Model: Simple key-value storage via Hive and secure file storage for larger data blobs (e.g., images, documents).
- Robust Security: Utilizes
flutter_secure_storageto protect the master encryption key, an encrypted Hive box for sensitive key-value pairs, and per-file encryption for file storage. - High Performance: Cryptographic operations (AES-GCM) are executed in background isolates using
computeto prevent UI jank. - Type-Safe Error Handling: Leverages
fpdart'sEitherandTaskEitherfor explicit, functional-style error management. - Ready for Dependency Injection: Comes with a pre-configured Riverpod provider for easy integration and lifecycle management.
Getting Started #
Add vault_storage to your pubspec.yaml file. You can get the latest version from pub.flutter-io.cn.
dependencies:
# ... other dependencies
vault_storage: ^0.0.1 # Replace with the latest version
Then, run flutter pub get in your terminal.
Before running your app, you must initialize the service. This is typically done in your main.dart or an initialization module.
// In your main function or an initialization class
import 'package:vault_storage/vault_storage.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// Create a ProviderContainer to access the provider.
final container = ProviderContainer();
// Initialize the vault storage.
await container.read(storageServiceProvider.future);
runApp(
UncontrolledProviderScope(
container: container,
child: const MyApp(),
),
);
}
Usage #
Key-Value Storage #
You can store and retrieve simple key-value pairs using the set and get methods. The BoxType enum determines whether the data is stored in the encrypted secure box or the unencrypted normal box.
final storageService = await container.read(storageServiceProvider.future);
// Store a secure value
await storageService.set(BoxType.secure, 'api_key', 'my_secret_key');
// Retrieve a secure value
final apiKey = await storageService.get<String>(BoxType.secure, 'api_key');
apiKey.fold(
(error) => print('Error retrieving key: ${error.message}'),
(key) => print('Retrieved API key: $key'),
);
Secure File Storage #
For larger data like images or documents, you can use the secure file storage methods.
import 'dart:typed_data';
// Assume 'imageData' is a Uint8List
final storageService = await container.read(storageServiceProvider.future);
// Save a file
final saveResult = await storageService.saveSecureFile(
fileBytes: imageData,
fileExtension: 'png',
);
saveResult.fold(
(error) => print('Error saving file: ${error.message}'),
(metadata) async {
print('File saved successfully. Metadata: $metadata');
// Retrieve the file
final getResult = await storageService.getSecureFile(fileMetadata: metadata);
getResult.fold(
(error) => print('Error retrieving file: ${error.message}'),
(fileBytes) => print('Retrieved file with ${fileBytes.length} bytes.'),
);
},
);
Usage without Riverpod #
If you are not using Riverpod, you can instantiate and manage the StorageService directly.
1. Initialization #
You'll need to create an instance of StorageService and initialize it when your application starts. You can store the instance in a global variable or use a service locator pattern (like get_it).
// In your main.dart or an initialization file
import 'package:vault_storage/vault_storage.dart';
// Using a global variable for simplicity.
late final StorageService storageService;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// Instantiate and initialize the service.
storageService = StorageService();
await storageService.init(); // You must call init() before using the service.
runApp(const MyApp());
}
2. Accessing the Service #
Once initialized, you can use your storageService instance anywhere in your app to call its methods. The API is identical to the one used with Riverpod.
// Example of using the manually created instance:
// Store a secure value
await storageService.set(BoxType.secure, 'api_key', 'my_secret_key');
// Retrieve a secure value
final apiKey = await storageService.get<String>(BoxType.secure, 'api_key');
apiKey.fold(
(error) => print('Error retrieving key: ${error.message}'),
(key) => print('Retrieved API key: $key'),
);
Error Handling #
The service uses fpdart's Either for error handling. All methods return an Either<StorageError, T>, where T is the success type. This forces you to handle potential failures explicitly.
Testing #
This package includes a comprehensive test suite. To run the tests, use the following command:
flutter test
License #
This project is licensed under the MIT License.