mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-01-22 08:46:18 +01:00
Add encrypted pref variant
This commit is contained in:
parent
88ee044e62
commit
fd8251b86c
13 changed files with 300 additions and 54 deletions
|
@ -21,6 +21,7 @@ import 'package:nc_photos/entity/local_file/data_source.dart';
|
|||
import 'package:nc_photos/entity/nc_album/data_source.dart';
|
||||
import 'package:nc_photos/entity/nc_album/repo.dart';
|
||||
import 'package:nc_photos/entity/pref.dart';
|
||||
import 'package:nc_photos/entity/pref/provider/secure_storage.dart';
|
||||
import 'package:nc_photos/entity/pref/provider/shared_preferences.dart';
|
||||
import 'package:nc_photos/entity/pref_util.dart' as pref_util;
|
||||
import 'package:nc_photos/entity/recognize_face/data_source.dart';
|
||||
|
@ -137,6 +138,7 @@ void _initSelfSignedCertManager() {
|
|||
Future<void> _initDiContainer(InitIsolateType isolateType) async {
|
||||
final c = DiContainer.late();
|
||||
c.pref = Pref();
|
||||
c.securePref = await _createSecurePref();
|
||||
c.npDb = await _createDb(isolateType);
|
||||
|
||||
c.albumRepo = AlbumRepo(AlbumCachedDataSource(c));
|
||||
|
@ -204,5 +206,11 @@ Future<NpDb> _createDb(InitIsolateType isolateType) async {
|
|||
return npDb;
|
||||
}
|
||||
|
||||
Future<Pref> _createSecurePref() async {
|
||||
final provider = PrefSecureStorageProvider();
|
||||
await provider.init();
|
||||
return Pref.scoped(provider);
|
||||
}
|
||||
|
||||
final _log = Logger("app_init");
|
||||
var _hasInitedInThisIsolate = false;
|
||||
|
|
|
@ -6,14 +6,16 @@ import 'package:nc_photos/di_container.dart';
|
|||
import 'package:nc_photos/entity/pref.dart';
|
||||
import 'package:nc_photos/language_util.dart';
|
||||
import 'package:nc_photos/object_extension.dart';
|
||||
import 'package:nc_photos/protected_page_handler.dart';
|
||||
import 'package:nc_photos/size.dart';
|
||||
import 'package:np_codegen/np_codegen.dart';
|
||||
import 'package:np_common/object_util.dart';
|
||||
import 'package:np_gps_map/np_gps_map.dart';
|
||||
import 'package:np_string/np_string.dart';
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
|
||||
part 'pref_controller.g.dart';
|
||||
|
||||
@npLog
|
||||
@npSubjectAccessor
|
||||
class PrefController {
|
||||
PrefController(this._c);
|
||||
|
@ -145,20 +147,13 @@ class PrefController {
|
|||
required BehaviorSubject<T> controller,
|
||||
required Future<bool> Function(Pref pref, T value) setter,
|
||||
required T value,
|
||||
}) async {
|
||||
final backup = controller.value;
|
||||
controller.add(value);
|
||||
try {
|
||||
if (!await setter(_c.pref, value)) {
|
||||
throw StateError("Unknown error");
|
||||
}
|
||||
} catch (e, stackTrace) {
|
||||
_log.severe("[_set] Failed setting preference", e, stackTrace);
|
||||
controller
|
||||
..addError(e, stackTrace)
|
||||
..add(backup);
|
||||
}
|
||||
}
|
||||
}) =>
|
||||
_doSet(
|
||||
pref: _c.pref,
|
||||
controller: controller,
|
||||
setter: setter,
|
||||
value: value,
|
||||
);
|
||||
|
||||
Future<void> _setOrRemove<T>({
|
||||
required BehaviorSubject<T?> controller,
|
||||
|
@ -166,26 +161,15 @@ class PrefController {
|
|||
required Future<bool> Function(Pref pref) remover,
|
||||
required T? value,
|
||||
T? defaultValue,
|
||||
}) async {
|
||||
final backup = controller.value;
|
||||
controller.add(value ?? defaultValue);
|
||||
try {
|
||||
if (value == null) {
|
||||
if (!await remover(_c.pref)) {
|
||||
throw StateError("Unknown error");
|
||||
}
|
||||
} else {
|
||||
if (!await setter(_c.pref, value)) {
|
||||
throw StateError("Unknown error");
|
||||
}
|
||||
}
|
||||
} catch (e, stackTrace) {
|
||||
_log.severe("[_set] Failed setting preference", e, stackTrace);
|
||||
controller
|
||||
..addError(e, stackTrace)
|
||||
..add(backup);
|
||||
}
|
||||
}
|
||||
}) =>
|
||||
_doSetOrRemove(
|
||||
pref: _c.pref,
|
||||
controller: controller,
|
||||
setter: setter,
|
||||
remover: remover,
|
||||
value: value,
|
||||
defaultValue: defaultValue,
|
||||
);
|
||||
|
||||
static AppLanguage _langIdToAppLanguage(int langId) {
|
||||
try {
|
||||
|
@ -254,3 +238,92 @@ class PrefController {
|
|||
late final _secondarySeedColorController = BehaviorSubject<Color?>.seeded(
|
||||
_c.pref.getSecondarySeedColor()?.run(Color.new));
|
||||
}
|
||||
|
||||
class SecurePrefController {
|
||||
SecurePrefController(this._c);
|
||||
|
||||
// ignore: unused_element
|
||||
Future<void> _set<T>({
|
||||
required BehaviorSubject<T> controller,
|
||||
required Future<bool> Function(Pref pref, T value) setter,
|
||||
required T value,
|
||||
}) =>
|
||||
_doSet(
|
||||
pref: _c.securePref,
|
||||
controller: controller,
|
||||
setter: setter,
|
||||
value: value,
|
||||
);
|
||||
|
||||
// ignore: unused_element
|
||||
Future<void> _setOrRemove<T>({
|
||||
required BehaviorSubject<T?> controller,
|
||||
required Future<bool> Function(Pref pref, T value) setter,
|
||||
required Future<bool> Function(Pref pref) remover,
|
||||
required T? value,
|
||||
T? defaultValue,
|
||||
}) =>
|
||||
_doSetOrRemove(
|
||||
pref: _c.securePref,
|
||||
controller: controller,
|
||||
setter: setter,
|
||||
remover: remover,
|
||||
value: value,
|
||||
defaultValue: defaultValue,
|
||||
);
|
||||
|
||||
final DiContainer _c;
|
||||
}
|
||||
|
||||
Future<void> _doSet<T>({
|
||||
required Pref pref,
|
||||
required BehaviorSubject<T> controller,
|
||||
required Future<bool> Function(Pref pref, T value) setter,
|
||||
required T value,
|
||||
}) async {
|
||||
final backup = controller.value;
|
||||
controller.add(value);
|
||||
try {
|
||||
if (!await setter(pref, value)) {
|
||||
throw StateError("Unknown error");
|
||||
}
|
||||
} catch (e, stackTrace) {
|
||||
_$__NpLog.log.severe("[_doSet] Failed setting preference", e, stackTrace);
|
||||
controller
|
||||
..addError(e, stackTrace)
|
||||
..add(backup);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _doSetOrRemove<T>({
|
||||
required Pref pref,
|
||||
required BehaviorSubject<T?> controller,
|
||||
required Future<bool> Function(Pref pref, T value) setter,
|
||||
required Future<bool> Function(Pref pref) remover,
|
||||
required T? value,
|
||||
T? defaultValue,
|
||||
}) async {
|
||||
final backup = controller.value;
|
||||
controller.add(value ?? defaultValue);
|
||||
try {
|
||||
if (value == null) {
|
||||
if (!await remover(pref)) {
|
||||
throw StateError("Unknown error");
|
||||
}
|
||||
} else {
|
||||
if (!await setter(pref, value)) {
|
||||
throw StateError("Unknown error");
|
||||
}
|
||||
}
|
||||
} catch (e, stackTrace) {
|
||||
_$__NpLog.log
|
||||
.severe("[_doSetOrRemove] Failed setting preference", e, stackTrace);
|
||||
controller
|
||||
..addError(e, stackTrace)
|
||||
..add(backup);
|
||||
}
|
||||
}
|
||||
|
||||
@npLog
|
||||
// ignore: camel_case_types
|
||||
class __ {}
|
||||
|
|
|
@ -6,11 +6,11 @@ part of 'pref_controller.dart';
|
|||
// NpLogGenerator
|
||||
// **************************************************************************
|
||||
|
||||
extension _$PrefControllerNpLog on PrefController {
|
||||
extension _$__NpLog on __ {
|
||||
// ignore: unused_element
|
||||
Logger get _log => log;
|
||||
|
||||
static final log = Logger("controller.pref_controller.PrefController");
|
||||
static final log = Logger("controller.pref_controller.__");
|
||||
}
|
||||
|
||||
// **************************************************************************
|
||||
|
|
|
@ -51,6 +51,7 @@ enum DiType {
|
|||
pref,
|
||||
touchManager,
|
||||
npDb,
|
||||
securePref,
|
||||
}
|
||||
|
||||
class DiContainer {
|
||||
|
@ -88,6 +89,7 @@ class DiContainer {
|
|||
Pref? pref,
|
||||
TouchManager? touchManager,
|
||||
NpDb? npDb,
|
||||
Pref? securePref,
|
||||
}) : _albumRepo = albumRepo,
|
||||
_albumRepoRemote = albumRepoRemote,
|
||||
_albumRepoLocal = albumRepoLocal,
|
||||
|
@ -120,7 +122,8 @@ class DiContainer {
|
|||
_recognizeFaceRepoLocal = recognizeFaceRepoLocal,
|
||||
_pref = pref,
|
||||
_touchManager = touchManager,
|
||||
_npDb = npDb;
|
||||
_npDb = npDb,
|
||||
_securePref = securePref;
|
||||
|
||||
DiContainer.late();
|
||||
|
||||
|
@ -192,6 +195,8 @@ class DiContainer {
|
|||
return contianer._touchManager != null;
|
||||
case DiType.npDb:
|
||||
return contianer._npDb != null;
|
||||
case DiType.securePref:
|
||||
return contianer._securePref != null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,6 +218,7 @@ class DiContainer {
|
|||
OrNull<Pref>? pref,
|
||||
OrNull<TouchManager>? touchManager,
|
||||
OrNull<NpDb>? npDb,
|
||||
OrNull<Pref>? securePref,
|
||||
}) {
|
||||
return DiContainer(
|
||||
albumRepo: albumRepo == null ? _albumRepo : albumRepo.obj,
|
||||
|
@ -237,6 +243,7 @@ class DiContainer {
|
|||
pref: pref == null ? _pref : pref.obj,
|
||||
touchManager: touchManager == null ? _touchManager : touchManager.obj,
|
||||
npDb: npDb == null ? _npDb : npDb.obj,
|
||||
securePref: securePref == null ? _securePref : securePref.obj,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -277,6 +284,7 @@ class DiContainer {
|
|||
Pref get pref => _pref!;
|
||||
TouchManager get touchManager => _touchManager!;
|
||||
NpDb get npDb => _npDb!;
|
||||
Pref get securePref => _securePref!;
|
||||
|
||||
set albumRepo(AlbumRepo v) {
|
||||
assert(_albumRepo == null);
|
||||
|
@ -443,6 +451,11 @@ class DiContainer {
|
|||
_npDb = v;
|
||||
}
|
||||
|
||||
set securePref(Pref v) {
|
||||
assert(_securePref == null);
|
||||
_securePref = v;
|
||||
}
|
||||
|
||||
AlbumRepo? _albumRepo;
|
||||
AlbumRepo? _albumRepoRemote;
|
||||
// Explicitly request a AlbumRepo backed by local source
|
||||
|
@ -480,6 +493,7 @@ class DiContainer {
|
|||
Pref? _pref;
|
||||
TouchManager? _touchManager;
|
||||
NpDb? _npDb;
|
||||
Pref? _securePref;
|
||||
}
|
||||
|
||||
extension DiContainerExtension on DiContainer {
|
||||
|
|
|
@ -6,7 +6,6 @@ import 'package:logging/logging.dart';
|
|||
import 'package:nc_photos/account.dart';
|
||||
import 'package:nc_photos/entity/pref/provider/memory.dart';
|
||||
import 'package:np_codegen/np_codegen.dart';
|
||||
import 'package:np_common/type.dart';
|
||||
|
||||
part 'pref.g.dart';
|
||||
part 'pref/extension.dart';
|
||||
|
@ -57,8 +56,6 @@ class AccountPref {
|
|||
}
|
||||
}
|
||||
|
||||
Future<JsonObj> toJson() => provider.toJson();
|
||||
|
||||
Future<bool> _set<T>(AccountPrefKey key, T value,
|
||||
Future<bool> Function(AccountPrefKey key, T value) setFn) =>
|
||||
setFn(key, value);
|
||||
|
@ -241,6 +238,4 @@ abstract class PrefProvider {
|
|||
|
||||
Future<bool> remove(PrefKeyInterface key);
|
||||
Future<bool> clear();
|
||||
|
||||
Future<JsonObj> toJson();
|
||||
}
|
||||
|
|
|
@ -42,8 +42,6 @@ class PrefMemoryProvider extends PrefProvider {
|
|||
_data.clear();
|
||||
return true;
|
||||
}
|
||||
@override
|
||||
Future<JsonObj> toJson() async => Map.of(_data);
|
||||
|
||||
T? _get<T>(PrefKeyInterface key) => _data[key.toStringKey()];
|
||||
|
||||
|
|
100
app/lib/entity/pref/provider/secure_storage.dart
Normal file
100
app/lib/entity/pref/provider/secure_storage.dart
Normal file
|
@ -0,0 +1,100 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:nc_photos/entity/pref.dart';
|
||||
import 'package:np_codegen/np_codegen.dart';
|
||||
import 'package:np_common/object_util.dart';
|
||||
|
||||
part 'secure_storage.g.dart';
|
||||
|
||||
@npLog
|
||||
class PrefSecureStorageProvider implements PrefProvider {
|
||||
Future<void> init() async {
|
||||
_storage = const FlutterSecureStorage(
|
||||
aOptions: AndroidOptions(
|
||||
encryptedSharedPreferences: true,
|
||||
preferencesKeyPrefix: "com.nkming.nc_photos",
|
||||
sharedPreferencesName: "secure_pref",
|
||||
),
|
||||
iOptions: IOSOptions(
|
||||
accountName: "com.nkming.nc_photos",
|
||||
),
|
||||
);
|
||||
_rawData = await _storage.readAll();
|
||||
}
|
||||
|
||||
@override
|
||||
bool? getBool(PrefKeyInterface key) {
|
||||
final value = _rawData[key.toStringKey()];
|
||||
return value?.let((e) => bool.tryParse(e, caseSensitive: false));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> setBool(PrefKeyInterface key, bool value) =>
|
||||
setString(key, value.toString());
|
||||
|
||||
@override
|
||||
int? getInt(PrefKeyInterface key) {
|
||||
final value = _rawData[key.toStringKey()];
|
||||
return value?.let(int.tryParse);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> setInt(PrefKeyInterface key, int value) =>
|
||||
setString(key, value.toString());
|
||||
|
||||
@override
|
||||
String? getString(PrefKeyInterface key) {
|
||||
return _rawData[key.toStringKey()];
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> setString(PrefKeyInterface key, String value) async {
|
||||
try {
|
||||
await _storage.write(key: key.toStringKey(), value: value);
|
||||
_rawData[key.toStringKey()] = value;
|
||||
return true;
|
||||
} catch (e, stackTrace) {
|
||||
_log.severe("[setString] Failed while write", e, stackTrace);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
List<String>? getStringList(PrefKeyInterface key) {
|
||||
final value = _rawData[key.toStringKey()];
|
||||
return (value?.let(jsonDecode) as List).cast<String>();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> setStringList(PrefKeyInterface key, List<String> value) =>
|
||||
setString(key, jsonEncode(value));
|
||||
|
||||
@override
|
||||
Future<bool> remove(PrefKeyInterface key) async {
|
||||
try {
|
||||
await _storage.delete(key: key.toStringKey());
|
||||
_rawData.remove(key.toStringKey());
|
||||
return true;
|
||||
} catch (e, stackTrace) {
|
||||
_log.severe("[remove] Failed while write", e, stackTrace);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> clear() async {
|
||||
try {
|
||||
await _storage.deleteAll();
|
||||
_rawData.clear();
|
||||
return true;
|
||||
} catch (e, stackTrace) {
|
||||
_log.severe("[clear] Failed while write", e, stackTrace);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
late FlutterSecureStorage _storage;
|
||||
late Map<String, String> _rawData;
|
||||
}
|
15
app/lib/entity/pref/provider/secure_storage.g.dart
Normal file
15
app/lib/entity/pref/provider/secure_storage.g.dart
Normal file
|
@ -0,0 +1,15 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'secure_storage.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// NpLogGenerator
|
||||
// **************************************************************************
|
||||
|
||||
extension _$PrefSecureStorageProviderNpLog on PrefSecureStorageProvider {
|
||||
// ignore: unused_element
|
||||
Logger get _log => log;
|
||||
|
||||
static final log =
|
||||
Logger("entity.pref.provider.secure_storage.PrefSecureStorageProvider");
|
||||
}
|
|
@ -1,9 +1,7 @@
|
|||
import 'package:nc_photos/entity/pref.dart';
|
||||
import 'package:nc_photos/use_case/compat/v34.dart';
|
||||
import 'package:np_common/type.dart';
|
||||
import 'package:np_universal_storage/np_universal_storage.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
|
||||
|
||||
/// [Pref] stored with [SharedPreferences] lib
|
||||
class PrefSharedPreferencesProvider extends PrefProvider {
|
||||
|
@ -55,8 +53,5 @@ class PrefSharedPreferencesProvider extends PrefProvider {
|
|||
@override
|
||||
Future<bool> clear() => _pref.clear();
|
||||
|
||||
@override
|
||||
Future<JsonObj> toJson() => SharedPreferencesStorePlatform.instance.getAll();
|
||||
|
||||
late SharedPreferences _pref;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:nc_photos/entity/pref.dart';
|
||||
import 'package:np_common/type.dart';
|
||||
import 'package:np_universal_storage/np_universal_storage.dart';
|
||||
|
||||
/// [Pref] backed by [UniversalStorage]
|
||||
|
@ -52,9 +51,6 @@ class PrefUniversalStorageProvider extends PrefProvider {
|
|||
return true;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<JsonObj> toJson() async => Map.of(_data);
|
||||
|
||||
T? _get<T>(PrefKeyInterface key) => _data[key.toStringKey()];
|
||||
|
||||
Future<bool> _set<T>(PrefKeyInterface key, T value) async {
|
||||
|
|
|
@ -72,6 +72,9 @@ class MyApp extends StatelessWidget {
|
|||
RepositoryProvider(
|
||||
create: (_) => PrefController(_c),
|
||||
),
|
||||
RepositoryProvider(
|
||||
create: (_) => SecurePrefController(_c),
|
||||
),
|
||||
RepositoryProvider(
|
||||
create: (context) => AccountController(
|
||||
prefController: context.read(),
|
||||
|
|
|
@ -553,6 +553,54 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.15"
|
||||
flutter_secure_storage:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_secure_storage
|
||||
sha256: "165164745e6afb5c0e3e3fcc72a012fb9e58496fb26ffb92cf22e16a821e85d0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.2.2"
|
||||
flutter_secure_storage_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_linux
|
||||
sha256: "4d91bfc23047422cbcd73ac684bc169859ee766482517c22172c86596bf1464b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
flutter_secure_storage_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_macos
|
||||
sha256: "1693ab11121a5f925bbea0be725abfcfbbcf36c1e29e571f84a0c0f436147a81"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
flutter_secure_storage_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_platform_interface
|
||||
sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
flutter_secure_storage_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_web
|
||||
sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
flutter_secure_storage_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_secure_storage_windows
|
||||
sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
flutter_staggered_grid_view:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
|
@ -69,6 +69,7 @@ dependencies:
|
|||
flutter_cache_manager: any
|
||||
flutter_colorpicker: ^1.0.3
|
||||
flutter_isolate: ^2.0.4
|
||||
flutter_secure_storage: ^9.2.2
|
||||
flutter_staggered_grid_view:
|
||||
git:
|
||||
url: https://gitlab.com/nc-photos/flutter_staggered_grid_view
|
||||
|
|
Loading…
Reference in a new issue