Implement local vault service with encryption key management and integrate it into the app. Add settings screen for data management and enhance home screen with new features. Update database connection for encryption support and modify repository to use the new database structure. Improve UI elements across the application for better user experience.
This commit is contained in:
@@ -19,7 +19,7 @@ class Notes extends Table {
|
||||
|
||||
@DriftDatabase(tables: [Notes])
|
||||
class AppDatabase extends _$AppDatabase {
|
||||
AppDatabase() : super(_openConnection());
|
||||
AppDatabase({required String encryptionKey}) : super(_openConnection(encryptionKey));
|
||||
|
||||
@override
|
||||
int get schemaVersion => 1;
|
||||
@@ -94,11 +94,21 @@ class AppDatabase extends _$AppDatabase {
|
||||
}
|
||||
}
|
||||
|
||||
LazyDatabase _openConnection() {
|
||||
LazyDatabase _openConnection(String encryptionKey) {
|
||||
return LazyDatabase(() async {
|
||||
final Directory supportDir = await getApplicationSupportDirectory();
|
||||
final File file = File(p.join(supportDir.path, 'notes.sqlite'));
|
||||
|
||||
return NativeDatabase(file);
|
||||
return NativeDatabase(
|
||||
file,
|
||||
setup: (database) {
|
||||
final String escapedKey = encryptionKey.replaceAll("'", "''");
|
||||
|
||||
// sqlite3mc can emulate SQLCipher file format for compatibility.
|
||||
database.execute("PRAGMA cipher = 'sqlcipher'");
|
||||
database.execute('PRAGMA legacy = 4');
|
||||
database.execute("PRAGMA key = '$escapedKey'");
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
|
||||
class LocalVaultService {
|
||||
LocalVaultService._();
|
||||
|
||||
static final LocalVaultService instance = LocalVaultService._();
|
||||
|
||||
static const String _encryptionKeyStorageKey =
|
||||
'notes_local_encryption_key_v1';
|
||||
|
||||
final FlutterSecureStorage _secureStorage = FlutterSecureStorage();
|
||||
|
||||
String? _cachedEncryptionKey;
|
||||
|
||||
Future<String?> readEncryptionKey() async {
|
||||
final String? cachedKey = _cachedEncryptionKey;
|
||||
if (cachedKey != null) {
|
||||
return cachedKey;
|
||||
}
|
||||
|
||||
final String? storedKey = await _secureStorage.read(
|
||||
key: _encryptionKeyStorageKey,
|
||||
);
|
||||
|
||||
_cachedEncryptionKey = storedKey;
|
||||
return storedKey;
|
||||
}
|
||||
|
||||
Future<String> createEncryptionKey() async {
|
||||
final String encryptionKey = _generateEncryptionKey();
|
||||
|
||||
await _secureStorage.write(
|
||||
key: _encryptionKeyStorageKey,
|
||||
value: encryptionKey,
|
||||
);
|
||||
|
||||
_cachedEncryptionKey = encryptionKey;
|
||||
return encryptionKey;
|
||||
}
|
||||
|
||||
Future<void> clearEncryptionKey() async {
|
||||
await _secureStorage.delete(key: _encryptionKeyStorageKey);
|
||||
_cachedEncryptionKey = null;
|
||||
}
|
||||
|
||||
String _generateEncryptionKey() {
|
||||
final Random random = Random.secure();
|
||||
final List<int> bytes = List<int>.generate(32, (_) => random.nextInt(256));
|
||||
|
||||
return bytes
|
||||
.map((int byte) => byte.toRadixString(16).padLeft(2, '0'))
|
||||
.join();
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,7 @@ import 'package:notas/data/app_database.dart';
|
||||
import 'package:notas/models/note.dart';
|
||||
|
||||
class NoteRepository {
|
||||
NoteRepository({AppDatabase? database}) : _database = database ?? _sharedDatabase;
|
||||
|
||||
static final AppDatabase _sharedDatabase = AppDatabase();
|
||||
NoteRepository({required AppDatabase database}) : _database = database;
|
||||
|
||||
final AppDatabase _database;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user