stack_wallet/lib/utilities/flutter_secure_storage_interface.dart

327 lines
7.7 KiB
Dart
Raw Normal View History

2022-08-26 08:11:35 +00:00
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
2022-11-09 22:43:26 +00:00
import 'package:isar/isar.dart';
import 'package:stack_wallet_backup/secure_storage.dart';
import 'package:stackwallet/models/isar/models/encrypted_string_value.dart';
2022-11-12 22:04:16 +00:00
import 'package:stackwallet/utilities/stack_file_system.dart';
2022-08-26 08:11:35 +00:00
abstract class SecureStorageInterface {
dynamic get store;
2022-08-26 08:11:35 +00:00
Future<void> write({
required String key,
required String? value,
IOSOptions? iOptions,
AndroidOptions? aOptions,
LinuxOptions? lOptions,
WebOptions? webOptions,
MacOsOptions? mOptions,
WindowsOptions? wOptions,
});
Future<String?> read({
required String key,
IOSOptions? iOptions,
AndroidOptions? aOptions,
LinuxOptions? lOptions,
WebOptions? webOptions,
MacOsOptions? mOptions,
WindowsOptions? wOptions,
});
Future<void> delete({
required String key,
IOSOptions? iOptions,
AndroidOptions? aOptions,
LinuxOptions? lOptions,
WebOptions? webOptions,
MacOsOptions? mOptions,
WindowsOptions? wOptions,
});
Future<void> deleteAll({
IOSOptions? iOptions,
AndroidOptions? aOptions,
LinuxOptions? lOptions,
WebOptions? webOptions,
MacOsOptions? mOptions,
WindowsOptions? wOptions,
});
2023-01-28 00:18:58 +00:00
Future<List<String>> get keys;
2022-08-26 08:11:35 +00:00
}
class DesktopSecureStore {
2022-11-09 22:43:26 +00:00
final StorageCryptoHandler handler;
late final Isar isar;
DesktopSecureStore(this.handler);
2022-11-09 22:43:26 +00:00
Future<void> init() async {
isar = await Isar.open(
[EncryptedStringValueSchema],
2022-11-12 22:04:16 +00:00
directory: (await StackFileSystem.applicationIsarDirectory()).path,
inspector: false,
name: "desktopStore",
);
}
2022-11-09 22:43:26 +00:00
Future<void> close() async {
await isar.close();
}
2022-11-09 22:43:26 +00:00
Future<String?> read({
required String key,
}) async {
final value =
await isar.encryptedStringValues.filter().keyEqualTo(key).findFirst();
// value does not exist;
if (value == null) {
return null;
}
2022-11-09 22:43:26 +00:00
return await handler.decryptValue(key, value.value);
2022-11-09 22:43:26 +00:00
}
Future<void> write({
required String key,
required String? value,
}) async {
if (value == null) {
// here we assume that a value is to be deleted
await isar.writeTxn(() async {
await isar.encryptedStringValues.deleteByKey(key);
});
} else {
// otherwise created encrypted object value
final object = EncryptedStringValue();
object.key = key;
object.value = await handler.encryptValue(key, value);
// store object value
await isar.writeTxn(() async {
await isar.encryptedStringValues.put(object);
});
}
2022-11-09 22:43:26 +00:00
}
Future<void> delete({
required String key,
}) async {
await isar.writeTxn(() async {
await isar.encryptedStringValues.deleteByKey(key);
});
2022-11-09 22:43:26 +00:00
}
2023-01-28 00:18:58 +00:00
Future<List<String>> get keys async {
return await isar.encryptedStringValues.where().keyProperty().findAll();
}
2022-11-09 22:43:26 +00:00
}
/// all *Options params ignored on desktop
class SecureStorageWrapper implements SecureStorageInterface {
2022-11-09 22:43:26 +00:00
final dynamic _store;
final bool _isDesktop;
2022-08-26 08:11:35 +00:00
@override
dynamic get store => _store;
2022-11-09 22:43:26 +00:00
const SecureStorageWrapper({
required dynamic store,
required bool isDesktop,
}) : assert(isDesktop
? store is DesktopSecureStore
2022-11-09 22:43:26 +00:00
: store is FlutterSecureStorage),
_store = store,
_isDesktop = isDesktop;
2022-08-26 08:11:35 +00:00
@override
Future<String?> read({
required String key,
IOSOptions? iOptions,
AndroidOptions? aOptions,
LinuxOptions? lOptions,
WebOptions? webOptions,
MacOsOptions? mOptions,
WindowsOptions? wOptions,
2022-11-09 22:43:26 +00:00
}) async {
if (_isDesktop) {
return await (_store as DesktopSecureStore).read(key: key);
2022-11-09 22:43:26 +00:00
} else {
return await (_store as FlutterSecureStorage).read(
key: key,
iOptions: iOptions,
aOptions: aOptions,
lOptions: lOptions,
webOptions: webOptions,
mOptions: mOptions,
wOptions: wOptions,
);
}
2022-08-26 08:11:35 +00:00
}
@override
Future<void> write({
required String key,
required String? value,
IOSOptions? iOptions,
AndroidOptions? aOptions,
LinuxOptions? lOptions,
WebOptions? webOptions,
MacOsOptions? mOptions,
WindowsOptions? wOptions,
2022-11-09 22:43:26 +00:00
}) async {
if (_isDesktop) {
return await (_store as DesktopSecureStore).write(key: key, value: value);
2022-11-09 22:43:26 +00:00
} else {
return await (_store as FlutterSecureStorage).write(
key: key,
value: value,
iOptions: iOptions,
aOptions: aOptions,
lOptions: lOptions,
webOptions: webOptions,
mOptions: mOptions,
wOptions: wOptions,
);
}
2022-08-26 08:11:35 +00:00
}
@override
Future<void> delete({
required String key,
IOSOptions? iOptions,
AndroidOptions? aOptions,
LinuxOptions? lOptions,
WebOptions? webOptions,
MacOsOptions? mOptions,
WindowsOptions? wOptions,
}) async {
2022-11-09 22:43:26 +00:00
if (_isDesktop) {
return (_store as DesktopSecureStore).delete(key: key);
2022-11-09 22:43:26 +00:00
} else {
return await (_store as FlutterSecureStorage).delete(
key: key,
iOptions: iOptions,
aOptions: aOptions,
lOptions: lOptions,
webOptions: webOptions,
mOptions: mOptions,
wOptions: wOptions,
);
}
2022-08-26 08:11:35 +00:00
}
@override
Future<void> deleteAll({
IOSOptions? iOptions,
AndroidOptions? aOptions,
LinuxOptions? lOptions,
WebOptions? webOptions,
MacOsOptions? mOptions,
WindowsOptions? wOptions,
}) async {
if (_isDesktop) {
// return (_store as DesktopSecureStore).deleteAll();
throw UnimplementedError();
} else {
return await (_store as FlutterSecureStorage).deleteAll(
iOptions: iOptions,
aOptions: aOptions,
lOptions: lOptions,
webOptions: webOptions,
mOptions: mOptions,
wOptions: wOptions,
);
}
}
2023-01-28 00:18:58 +00:00
@override
Future<List<String>> get keys async {
if (_isDesktop) {
return (_store as DesktopSecureStore).keys;
} else {
return (await (_store as FlutterSecureStorage).readAll()).keys.toList();
}
}
2022-08-26 08:11:35 +00:00
}
// Mock class for testing purposes
class FakeSecureStorage implements SecureStorageInterface {
2022-08-26 08:11:35 +00:00
final Map<String, String?> _store = {};
int _interactions = 0;
int get interactions => _interactions;
int _writes = 0;
int get writes => _writes;
int _reads = 0;
int get reads => _reads;
int _deletes = 0;
int get deletes => _deletes;
@override
Future<String?> read({
required String key,
IOSOptions? iOptions,
AndroidOptions? aOptions,
LinuxOptions? lOptions,
WebOptions? webOptions,
MacOsOptions? mOptions,
WindowsOptions? wOptions,
}) async {
_interactions++;
_reads++;
return _store[key];
}
@override
Future<void> write({
required String key,
required String? value,
IOSOptions? iOptions,
AndroidOptions? aOptions,
LinuxOptions? lOptions,
WebOptions? webOptions,
MacOsOptions? mOptions,
WindowsOptions? wOptions,
}) async {
_interactions++;
_writes++;
_store[key] = value;
}
@override
Future<void> delete({
required String key,
IOSOptions? iOptions,
AndroidOptions? aOptions,
LinuxOptions? lOptions,
WebOptions? webOptions,
MacOsOptions? mOptions,
WindowsOptions? wOptions,
}) async {
_interactions++;
_deletes++;
_store.remove(key);
}
@override
Future<void> deleteAll({
IOSOptions? iOptions,
AndroidOptions? aOptions,
LinuxOptions? lOptions,
WebOptions? webOptions,
MacOsOptions? mOptions,
WindowsOptions? wOptions,
}) async {
_interactions++;
_deletes++;
_store.clear();
}
@override
dynamic get store => throw UnimplementedError();
2023-01-28 00:18:58 +00:00
@override
Future<List<String>> get keys => Future(() => _store.keys.toList());
2022-08-26 08:11:35 +00:00
}