- Refactor Hive boxes

- Delete SSH generation leftovers
- Migrate users box to an encrypted box
pull/90/head
Inex Code 2022-05-17 23:08:28 +03:00
parent 19bc780db1
commit bf79fb1adf
22 changed files with 134 additions and 156 deletions

View File

@ -27,7 +27,7 @@ class BlocAndProviderConfig extends StatelessWidget {
BlocProvider( BlocProvider(
create: (_) => AppSettingsCubit( create: (_) => AppSettingsCubit(
isDarkModeOn: isDark, isDarkModeOn: isDark,
isOnbordingShowing: true, isOnboardingShowing: true,
)..load(), )..load(),
), ),
BlocProvider(create: (_) => serverInstallationCubit, lazy: false), BlocProvider(create: (_) => serverInstallationCubit, lazy: false),

View File

@ -2,7 +2,6 @@ import 'package:get_it/get_it.dart';
import 'package:selfprivacy/logic/get_it/api_config.dart'; import 'package:selfprivacy/logic/get_it/api_config.dart';
import 'package:selfprivacy/logic/get_it/console.dart'; import 'package:selfprivacy/logic/get_it/console.dart';
import 'package:selfprivacy/logic/get_it/navigation.dart'; import 'package:selfprivacy/logic/get_it/navigation.dart';
import 'package:selfprivacy/logic/get_it/ssh.dart';
import 'package:selfprivacy/logic/get_it/timer.dart'; import 'package:selfprivacy/logic/get_it/timer.dart';
export 'package:selfprivacy/logic/get_it/api_config.dart'; export 'package:selfprivacy/logic/get_it/api_config.dart';
@ -17,7 +16,6 @@ Future<void> getItSetup() async {
getIt.registerSingleton<ConsoleModel>(ConsoleModel()); getIt.registerSingleton<ConsoleModel>(ConsoleModel());
getIt.registerSingleton<TimerModel>(TimerModel()); getIt.registerSingleton<TimerModel>(TimerModel());
getIt.registerSingleton<SSHModel>(SSHModel()..init());
getIt.registerSingleton<ApiConfigModel>(ApiConfigModel()..init()); getIt.registerSingleton<ApiConfigModel>(ApiConfigModel()..init());
await getIt.allReady(); await getIt.allReady();

View File

@ -19,15 +19,22 @@ class HiveConfig {
Hive.registerAdapter(BackblazeBucketAdapter()); Hive.registerAdapter(BackblazeBucketAdapter());
Hive.registerAdapter(ServerVolumeAdapter()); Hive.registerAdapter(ServerVolumeAdapter());
await Hive.openBox(BNames.appSettings); await Hive.openBox(BNames.appSettingsBox);
await Hive.openBox<User>(BNames.users);
await Hive.openBox(BNames.servicesState);
var cipher = HiveAesCipher(await getEncryptedKey(BNames.key)); var cipher = HiveAesCipher(
await Hive.openBox(BNames.appConfig, encryptionCipher: cipher); await getEncryptedKey(BNames.serverInstallationEncryptionKey));
var sshCipher = HiveAesCipher(await getEncryptedKey(BNames.sshEnckey)); await Hive.openBox<User>(BNames.usersDeprecated);
await Hive.openBox(BNames.sshConfig, encryptionCipher: sshCipher); await Hive.openBox<User>(BNames.users, encryptionCipher: cipher);
Box<User> deprecatedUsers = Hive.box<User>(BNames.usersDeprecated);
if (deprecatedUsers.isNotEmpty) {
Box<User> users = Hive.box<User>(BNames.users);
users.addAll(deprecatedUsers.values.toList());
deprecatedUsers.clear();
}
await Hive.openBox(BNames.serverInstallation, encryptionCipher: cipher);
} }
static Future<Uint8List> getEncryptedKey(String encKey) async { static Future<Uint8List> getEncryptedKey(String encKey) async {
@ -43,33 +50,65 @@ class HiveConfig {
} }
} }
/// Mappings for the different boxes and their keys
class BNames { class BNames {
static String appConfig = 'appConfig'; /// App settings box. Contains app settings like [isDarkModeOn], [isOnboardingShowing]
static String appSettingsBox = 'appSettings';
/// A boolean field of [appSettingsBox] box.
static String isDarkModeOn = 'isDarkModeOn'; static String isDarkModeOn = 'isDarkModeOn';
static String isOnbordingShowing = 'isOnbordingShowing';
static String users = 'users'; /// A boolean field of [appSettingsBox] box.
static String isOnboardingShowing = 'isOnboardingShowing';
/// Encryption key to decrypt [serverInstallation] and [users] box.
static String serverInstallationEncryptionKey = 'key';
/// Server installation box. Contains server details and provider tokens.
static String serverInstallation = 'appConfig';
/// A List<String> field of [serverInstallation] box.
static String rootKeys = 'rootKeys'; static String rootKeys = 'rootKeys';
static String appSettings = 'appSettings'; /// A boolean field of [serverInstallation] box.
static String servicesState = 'servicesState';
static String key = 'key';
static String sshEnckey = 'sshEngkey';
static String hasFinalChecked = 'hasFinalChecked'; static String hasFinalChecked = 'hasFinalChecked';
/// A boolean field of [serverInstallation] box.
static String isServerStarted = 'isServerStarted'; static String isServerStarted = 'isServerStarted';
/// A [ServerDomain] field of [serverInstallation] box.
static String serverDomain = 'cloudFlareDomain'; static String serverDomain = 'cloudFlareDomain';
/// A String field of [serverInstallation] box.
static String hetznerKey = 'hetznerKey'; static String hetznerKey = 'hetznerKey';
/// A String field of [serverInstallation] box.
static String cloudFlareKey = 'cloudFlareKey'; static String cloudFlareKey = 'cloudFlareKey';
/// A [User] field of [serverInstallation] box.
static String rootUser = 'rootUser'; static String rootUser = 'rootUser';
/// A [ServerHostingDetails] field of [serverInstallation] box.
static String serverDetails = 'hetznerServer'; static String serverDetails = 'hetznerServer';
static String backblazeKey = 'backblazeKey';
/// A [BackblazeCredential] field of [serverInstallation] box.
static String backblazeCredential = 'backblazeKey';
/// A [BackblazeBucket] field of [serverInstallation] box.
static String backblazeBucket = 'backblazeBucket'; static String backblazeBucket = 'backblazeBucket';
/// A boolean field of [serverInstallation] box.
static String isLoading = 'isLoading'; static String isLoading = 'isLoading';
/// A boolean field of [serverInstallation] box.
static String isServerResetedFirstTime = 'isServerResetedFirstTime'; static String isServerResetedFirstTime = 'isServerResetedFirstTime';
/// A boolean field of [serverInstallation] box.
static String isServerResetedSecondTime = 'isServerResetedSecondTime'; static String isServerResetedSecondTime = 'isServerResetedSecondTime';
static String sshConfig = 'sshConfig';
static String sshPrivateKey = "sshPrivateKey"; /// Deprecated users box as it is unencrypted
static String sshPublicKey = "sshPublicKey"; static String usersDeprecated = 'users';
/// Box with users
static String users = 'usersEncrypted';
} }

View File

@ -10,11 +10,12 @@ part 'authentication_dependend_state.dart';
abstract class ServerInstallationDependendCubit< abstract class ServerInstallationDependendCubit<
T extends ServerInstallationDependendState> extends Cubit<T> { T extends ServerInstallationDependendState> extends Cubit<T> {
ServerInstallationDependendCubit( ServerInstallationDependendCubit(
this.appConfigCubit, this.serverInstallationCubit,
T initState, T initState,
) : super(initState) { ) : super(initState) {
authCubitSubscription = appConfigCubit.stream.listen(checkAuthStatus); authCubitSubscription =
checkAuthStatus(appConfigCubit.state); serverInstallationCubit.stream.listen(checkAuthStatus);
checkAuthStatus(serverInstallationCubit.state);
} }
void checkAuthStatus(ServerInstallationState state) { void checkAuthStatus(ServerInstallationState state) {
@ -26,7 +27,7 @@ abstract class ServerInstallationDependendCubit<
} }
late StreamSubscription authCubitSubscription; late StreamSubscription authCubitSubscription;
final ServerInstallationCubit appConfigCubit; final ServerInstallationCubit serverInstallationCubit;
void load(); void load();
void clear(); void clear();

View File

@ -9,22 +9,22 @@ part 'app_settings_state.dart';
class AppSettingsCubit extends Cubit<AppSettingsState> { class AppSettingsCubit extends Cubit<AppSettingsState> {
AppSettingsCubit({ AppSettingsCubit({
required bool isDarkModeOn, required bool isDarkModeOn,
required bool isOnbordingShowing, required bool isOnboardingShowing,
}) : super( }) : super(
AppSettingsState( AppSettingsState(
isDarkModeOn: isDarkModeOn, isDarkModeOn: isDarkModeOn,
isOnbordingShowing: isOnbordingShowing, isOnboardingShowing: isOnboardingShowing,
), ),
); );
Box box = Hive.box(BNames.appSettings); Box box = Hive.box(BNames.appSettingsBox);
void load() { void load() {
bool? isDarkModeOn = box.get(BNames.isDarkModeOn); bool? isDarkModeOn = box.get(BNames.isDarkModeOn);
bool? isOnbordingShowing = box.get(BNames.isOnbordingShowing); bool? isOnboardingShowing = box.get(BNames.isOnboardingShowing);
emit(state.copyWith( emit(state.copyWith(
isDarkModeOn: isDarkModeOn, isDarkModeOn: isDarkModeOn,
isOnbordingShowing: isOnbordingShowing, isOnboardingShowing: isOnboardingShowing,
)); ));
} }
@ -34,8 +34,8 @@ class AppSettingsCubit extends Cubit<AppSettingsState> {
} }
void turnOffOnboarding() { void turnOffOnboarding() {
box.put(BNames.isOnbordingShowing, false); box.put(BNames.isOnboardingShowing, false);
emit(state.copyWith(isOnbordingShowing: false)); emit(state.copyWith(isOnboardingShowing: false));
} }
} }

View File

@ -3,18 +3,18 @@ part of 'app_settings_cubit.dart';
class AppSettingsState extends Equatable { class AppSettingsState extends Equatable {
const AppSettingsState({ const AppSettingsState({
required this.isDarkModeOn, required this.isDarkModeOn,
required this.isOnbordingShowing, required this.isOnboardingShowing,
}); });
final bool isDarkModeOn; final bool isDarkModeOn;
final bool isOnbordingShowing; final bool isOnboardingShowing;
AppSettingsState copyWith({isDarkModeOn, isOnbordingShowing}) => AppSettingsState copyWith({isDarkModeOn, isOnboardingShowing}) =>
AppSettingsState( AppSettingsState(
isDarkModeOn: isDarkModeOn ?? this.isDarkModeOn, isDarkModeOn: isDarkModeOn ?? this.isDarkModeOn,
isOnbordingShowing: isOnbordingShowing ?? this.isOnbordingShowing, isOnboardingShowing: isOnboardingShowing ?? this.isOnboardingShowing,
); );
@override @override
List<Object> get props => [isDarkModeOn, isOnbordingShowing]; List<Object> get props => [isDarkModeOn, isOnboardingShowing];
} }

View File

@ -11,14 +11,14 @@ import 'package:selfprivacy/logic/models/json/backup.dart';
part 'backups_state.dart'; part 'backups_state.dart';
class BackupsCubit extends ServerInstallationDependendCubit<BackupsState> { class BackupsCubit extends ServerInstallationDependendCubit<BackupsState> {
BackupsCubit(ServerInstallationCubit appConfigCubit) BackupsCubit(ServerInstallationCubit serverInstallationCubit)
: super(appConfigCubit, BackupsState(preventActions: true)); : super(serverInstallationCubit, BackupsState(preventActions: true));
final api = ServerApi(); final api = ServerApi();
final backblaze = BackblazeApi(); final backblaze = BackblazeApi();
Future<void> load() async { Future<void> load() async {
if (appConfigCubit.state is ServerInstallationFinished) { if (serverInstallationCubit.state is ServerInstallationFinished) {
final bucket = getIt<ApiConfigModel>().backblazeBucket; final bucket = getIt<ApiConfigModel>().backblazeBucket;
if (bucket == null) { if (bucket == null) {
emit(BackupsState( emit(BackupsState(
@ -85,9 +85,9 @@ class BackupsCubit extends ServerInstallationDependendCubit<BackupsState> {
Future<void> createBucket() async { Future<void> createBucket() async {
emit(state.copyWith(preventActions: true)); emit(state.copyWith(preventActions: true));
final domain = appConfigCubit.state.serverDomain!.domainName final domain = serverInstallationCubit.state.serverDomain!.domainName
.replaceAll(RegExp(r'[^a-zA-Z0-9]'), '-'); .replaceAll(RegExp(r'[^a-zA-Z0-9]'), '-');
final serverId = appConfigCubit.state.serverDetails!.id; final serverId = serverInstallationCubit.state.serverDetails!.id;
var bucketName = 'selfprivacy-$domain-$serverId'; var bucketName = 'selfprivacy-$domain-$serverId';
// If bucket name is too long, shorten it // If bucket name is too long, shorten it
if (bucketName.length > 49) { if (bucketName.length > 49) {

View File

@ -10,8 +10,8 @@ part 'dns_records_state.dart';
class DnsRecordsCubit class DnsRecordsCubit
extends ServerInstallationDependendCubit<DnsRecordsState> { extends ServerInstallationDependendCubit<DnsRecordsState> {
DnsRecordsCubit(ServerInstallationCubit appConfigCubit) DnsRecordsCubit(ServerInstallationCubit serverInstallationCubit)
: super(appConfigCubit, : super(serverInstallationCubit,
DnsRecordsState(dnsState: DnsRecordsStatus.refreshing)); DnsRecordsState(dnsState: DnsRecordsStatus.refreshing));
final api = ServerApi(); final api = ServerApi();
@ -21,11 +21,12 @@ class DnsRecordsCubit
emit(DnsRecordsState( emit(DnsRecordsState(
dnsState: DnsRecordsStatus.refreshing, dnsState: DnsRecordsStatus.refreshing,
dnsRecords: _getDesiredDnsRecords( dnsRecords: _getDesiredDnsRecords(
appConfigCubit.state.serverDomain?.domainName, "", ""))); serverInstallationCubit.state.serverDomain?.domainName, "", "")));
print('Loading DNS status'); print('Loading DNS status');
if (appConfigCubit.state is ServerInstallationFinished) { if (serverInstallationCubit.state is ServerInstallationFinished) {
final ServerDomain? domain = appConfigCubit.state.serverDomain; final ServerDomain? domain = serverInstallationCubit.state.serverDomain;
final String? ipAddress = appConfigCubit.state.serverDetails?.ip4; final String? ipAddress =
serverInstallationCubit.state.serverDetails?.ip4;
if (domain != null && ipAddress != null) { if (domain != null && ipAddress != null) {
final List<DnsRecord> records = final List<DnsRecord> records =
await cloudflare.getDnsRecords(cloudFlareDomain: domain); await cloudflare.getDnsRecords(cloudFlareDomain: domain);
@ -96,8 +97,8 @@ class DnsRecordsCubit
Future<void> fix() async { Future<void> fix() async {
emit(state.copyWith(dnsState: DnsRecordsStatus.refreshing)); emit(state.copyWith(dnsState: DnsRecordsStatus.refreshing));
final ServerDomain? domain = appConfigCubit.state.serverDomain; final ServerDomain? domain = serverInstallationCubit.state.serverDomain;
final String? ipAddress = appConfigCubit.state.serverDetails?.ip4; final String? ipAddress = serverInstallationCubit.state.serverDetails?.ip4;
final String? dkimPublicKey = await api.getDkim(); final String? dkimPublicKey = await api.getDkim();
await cloudflare.removeSimilarRecords(cloudFlareDomain: domain!); await cloudflare.removeSimilarRecords(cloudFlareDomain: domain!);
await cloudflare.createMultipleDnsRecords( await cloudflare.createMultipleDnsRecords(

View File

@ -2,8 +2,6 @@ import 'dart:async';
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/get_it/ssh.dart';
import 'package:selfprivacy/logic/models/hive/backblaze_credential.dart'; import 'package:selfprivacy/logic/models/hive/backblaze_credential.dart';
import 'package:selfprivacy/logic/models/hive/server_domain.dart'; import 'package:selfprivacy/logic/models/hive/server_domain.dart';
import 'package:selfprivacy/logic/models/hive/server_details.dart'; import 'package:selfprivacy/logic/models/hive/server_details.dart';
@ -18,7 +16,7 @@ part '../server_installation/server_installation_state.dart';
class ServerInstallationCubit extends Cubit<ServerInstallationState> { class ServerInstallationCubit extends Cubit<ServerInstallationState> {
ServerInstallationCubit() : super(ServerInstallationEmpty()); ServerInstallationCubit() : super(ServerInstallationEmpty());
final repository = AppConfigRepository(); final repository = ServerInstallationRepository();
Timer? timer; Timer? timer;
@ -266,7 +264,6 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
if (state.serverDetails != null) { if (state.serverDetails != null) {
await repository.deleteServer(state.serverDomain!); await repository.deleteServer(state.serverDomain!);
await getIt<SSHModel>().clear();
} }
await repository.deleteRecords(); await repository.deleteRecords();
emit(ServerInstallationNotFinished( emit(ServerInstallationNotFinished(

View File

@ -17,8 +17,8 @@ import 'package:selfprivacy/ui/components/brand_alert/brand_alert.dart';
import '../server_installation/server_installation_cubit.dart'; import '../server_installation/server_installation_cubit.dart';
class AppConfigRepository { class ServerInstallationRepository {
Box box = Hive.box(BNames.appConfig); Box box = Hive.box(BNames.serverInstallation);
Future<ServerInstallationState> load() async { Future<ServerInstallationState> load() async {
final hetznerToken = getIt<ApiConfigModel>().hetznerKey; final hetznerToken = getIt<ApiConfigModel>().hetznerKey;

View File

@ -1,5 +1,3 @@
import 'package:hive/hive.dart';
import 'package:selfprivacy/config/hive_config.dart';
import 'package:selfprivacy/logic/api_maps/server.dart'; import 'package:selfprivacy/logic/api_maps/server.dart';
import 'package:selfprivacy/logic/common_enum/common_enum.dart'; import 'package:selfprivacy/logic/common_enum/common_enum.dart';
import 'package:selfprivacy/logic/cubit/app_config_dependent/authentication_dependend_cubit.dart'; import 'package:selfprivacy/logic/cubit/app_config_dependent/authentication_dependend_cubit.dart';
@ -7,13 +5,11 @@ import 'package:selfprivacy/logic/cubit/app_config_dependent/authentication_depe
part 'services_state.dart'; part 'services_state.dart';
class ServicesCubit extends ServerInstallationDependendCubit<ServicesState> { class ServicesCubit extends ServerInstallationDependendCubit<ServicesState> {
ServicesCubit(ServerInstallationCubit appConfigCubit) ServicesCubit(ServerInstallationCubit serverInstallationCubit)
: super(appConfigCubit, ServicesState.allOff()); : super(serverInstallationCubit, ServicesState.allOff());
Box box = Hive.box(BNames.servicesState);
final api = ServerApi(); final api = ServerApi();
Future<void> load() async { Future<void> load() async {
if (appConfigCubit.state is ServerInstallationFinished) { if (serverInstallationCubit.state is ServerInstallationFinished) {
var statuses = await api.servicesPowerCheck(); var statuses = await api.servicesPowerCheck();
emit( emit(
ServicesState( ServicesState(
@ -29,7 +25,6 @@ class ServicesCubit extends ServerInstallationDependendCubit<ServicesState> {
@override @override
void clear() async { void clear() async {
box.clear();
emit(ServicesState.allOff()); emit(ServicesState.allOff());
} }
} }

View File

@ -1,4 +1,3 @@
import 'package:bloc/bloc.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:selfprivacy/config/hive_config.dart'; import 'package:selfprivacy/config/hive_config.dart';
import 'package:selfprivacy/logic/cubit/app_config_dependent/authentication_dependend_cubit.dart'; import 'package:selfprivacy/logic/cubit/app_config_dependent/authentication_dependend_cubit.dart';
@ -11,23 +10,23 @@ export 'package:provider/provider.dart';
part 'users_state.dart'; part 'users_state.dart';
class UsersCubit extends ServerInstallationDependendCubit<UsersState> { class UsersCubit extends ServerInstallationDependendCubit<UsersState> {
UsersCubit(ServerInstallationCubit appConfigCubit) UsersCubit(ServerInstallationCubit serverInstallationCubit)
: super( : super(
appConfigCubit, serverInstallationCubit,
UsersState( UsersState(
<User>[], User(login: 'root'), User(login: 'loading...'))); <User>[], User(login: 'root'), User(login: 'loading...')));
Box<User> box = Hive.box<User>(BNames.users); Box<User> box = Hive.box<User>(BNames.users);
Box configBox = Hive.box(BNames.appConfig); Box serverInstallationBox = Hive.box(BNames.serverInstallation);
final api = ServerApi(); final api = ServerApi();
Future<void> load() async { Future<void> load() async {
if (appConfigCubit.state is ServerInstallationFinished) { if (serverInstallationCubit.state is ServerInstallationFinished) {
var loadedUsers = box.values.toList(); var loadedUsers = box.values.toList();
final primaryUser = configBox.get(BNames.rootUser, final primaryUser = serverInstallationBox.get(BNames.rootUser,
defaultValue: User(login: 'loading...')); defaultValue: User(login: 'loading...'));
List<String> rootKeys = [ List<String> rootKeys = [
...configBox.get(BNames.rootKeys, defaultValue: []) ...serverInstallationBox.get(BNames.rootKeys, defaultValue: [])
]; ];
if (loadedUsers.isNotEmpty) { if (loadedUsers.isNotEmpty) {
emit(UsersState( emit(UsersState(
@ -48,10 +47,10 @@ class UsersCubit extends ServerInstallationDependendCubit<UsersState> {
box.addAll(usersWithSshKeys); box.addAll(usersWithSshKeys);
final rootUserWithSshKeys = (await loadSshKeys([state.rootUser])).first; final rootUserWithSshKeys = (await loadSshKeys([state.rootUser])).first;
configBox.put(BNames.rootKeys, rootUserWithSshKeys.sshKeys); serverInstallationBox.put(BNames.rootKeys, rootUserWithSshKeys.sshKeys);
final primaryUserWithSshKeys = final primaryUserWithSshKeys =
(await loadSshKeys([state.primaryUser])).first; (await loadSshKeys([state.primaryUser])).first;
configBox.put(BNames.rootUser, primaryUserWithSshKeys); serverInstallationBox.put(BNames.rootUser, primaryUserWithSshKeys);
emit(UsersState( emit(UsersState(
usersWithSshKeys, rootUserWithSshKeys, primaryUserWithSshKeys)); usersWithSshKeys, rootUserWithSshKeys, primaryUserWithSshKeys));
} }
@ -142,10 +141,10 @@ class UsersCubit extends ServerInstallationDependendCubit<UsersState> {
box.clear(); box.clear();
box.addAll(usersWithSshKeys); box.addAll(usersWithSshKeys);
final rootUserWithSshKeys = (await loadSshKeys([state.rootUser])).first; final rootUserWithSshKeys = (await loadSshKeys([state.rootUser])).first;
configBox.put(BNames.rootKeys, rootUserWithSshKeys.sshKeys); serverInstallationBox.put(BNames.rootKeys, rootUserWithSshKeys.sshKeys);
final primaryUserWithSshKeys = final primaryUserWithSshKeys =
(await loadSshKeys([state.primaryUser])).first; (await loadSshKeys([state.primaryUser])).first;
configBox.put(BNames.rootUser, primaryUserWithSshKeys); serverInstallationBox.put(BNames.rootUser, primaryUserWithSshKeys);
emit(UsersState( emit(UsersState(
usersWithSshKeys, rootUserWithSshKeys, primaryUserWithSshKeys)); usersWithSshKeys, rootUserWithSshKeys, primaryUserWithSshKeys));
return; return;
@ -195,10 +194,10 @@ class UsersCubit extends ServerInstallationDependendCubit<UsersState> {
final result = await api.addRootSshKey(publicKey); final result = await api.addRootSshKey(publicKey);
if (result.isSuccess) { if (result.isSuccess) {
// Add ssh key to the array of root keys // Add ssh key to the array of root keys
final rootKeys = final rootKeys = serverInstallationBox
configBox.get(BNames.rootKeys, defaultValue: []) as List<String>; .get(BNames.rootKeys, defaultValue: []) as List<String>;
rootKeys.add(publicKey); rootKeys.add(publicKey);
configBox.put(BNames.rootKeys, rootKeys); serverInstallationBox.put(BNames.rootKeys, rootKeys);
emit(state.copyWith( emit(state.copyWith(
rootUser: User( rootUser: User(
login: state.rootUser.login, login: state.rootUser.login,
@ -224,7 +223,7 @@ class UsersCubit extends ServerInstallationDependendCubit<UsersState> {
sshKeys: primaryUserKeys, sshKeys: primaryUserKeys,
note: state.primaryUser.note, note: state.primaryUser.note,
); );
configBox.put(BNames.rootUser, updatedUser); serverInstallationBox.put(BNames.rootUser, updatedUser);
emit(state.copyWith( emit(state.copyWith(
primaryUser: updatedUser, primaryUser: updatedUser,
)); ));
@ -258,10 +257,10 @@ class UsersCubit extends ServerInstallationDependendCubit<UsersState> {
// If it is not primary user, update user // If it is not primary user, update user
if (user.login == 'root') { if (user.login == 'root') {
final rootKeys = final rootKeys = serverInstallationBox
configBox.get(BNames.rootKeys, defaultValue: []) as List<String>; .get(BNames.rootKeys, defaultValue: []) as List<String>;
rootKeys.remove(publicKey); rootKeys.remove(publicKey);
configBox.put(BNames.rootKeys, rootKeys); serverInstallationBox.put(BNames.rootKeys, rootKeys);
emit(state.copyWith( emit(state.copyWith(
rootUser: User( rootUser: User(
login: state.rootUser.login, login: state.rootUser.login,
@ -284,7 +283,7 @@ class UsersCubit extends ServerInstallationDependendCubit<UsersState> {
sshKeys: primaryUserKeys, sshKeys: primaryUserKeys,
note: state.primaryUser.note, note: state.primaryUser.note,
); );
configBox.put(BNames.rootUser, updatedUser); serverInstallationBox.put(BNames.rootUser, updatedUser);
emit(state.copyWith( emit(state.copyWith(
primaryUser: updatedUser, primaryUser: updatedUser,
)); ));

View File

@ -6,7 +6,7 @@ import 'package:selfprivacy/logic/models/hive/server_domain.dart';
import 'package:selfprivacy/logic/models/hive/server_details.dart'; import 'package:selfprivacy/logic/models/hive/server_details.dart';
class ApiConfigModel { class ApiConfigModel {
Box _box = Hive.box(BNames.appConfig); Box _box = Hive.box(BNames.serverInstallation);
ServerHostingDetails? get serverDetails => _serverDetails; ServerHostingDetails? get serverDetails => _serverDetails;
String? get hetznerKey => _hetznerKey; String? get hetznerKey => _hetznerKey;
@ -33,7 +33,7 @@ class ApiConfigModel {
} }
Future<void> storeBackblazeCredential(BackblazeCredential value) async { Future<void> storeBackblazeCredential(BackblazeCredential value) async {
await _box.put(BNames.backblazeKey, value); await _box.put(BNames.backblazeCredential, value);
_backblazeCredential = value; _backblazeCredential = value;
} }
@ -66,7 +66,7 @@ class ApiConfigModel {
_hetznerKey = _box.get(BNames.hetznerKey); _hetznerKey = _box.get(BNames.hetznerKey);
_cloudFlareKey = _box.get(BNames.cloudFlareKey); _cloudFlareKey = _box.get(BNames.cloudFlareKey);
_backblazeCredential = _box.get(BNames.backblazeKey); _backblazeCredential = _box.get(BNames.backblazeCredential);
_serverDomain = _box.get(BNames.serverDomain); _serverDomain = _box.get(BNames.serverDomain);
_serverDetails = _box.get(BNames.serverDetails); _serverDetails = _box.get(BNames.serverDetails);
_backblazeBucket = _box.get(BNames.backblazeBucket); _backblazeBucket = _box.get(BNames.backblazeBucket);

View File

@ -1,39 +0,0 @@
import 'package:hive/hive.dart';
import 'package:pointycastle/pointycastle.dart';
import 'package:rsa_encrypt/rsa_encrypt.dart';
import 'package:selfprivacy/config/hive_config.dart';
import 'package:pointycastle/api.dart' as crypto;
import 'package:ssh_key/ssh_key.dart' as ssh_key;
class SSHModel {
Box _box = Hive.box(BNames.sshConfig);
String? savedPrivateKey;
String? savedPubKey;
Future<void> generateKeys() async {
var helper = RsaKeyHelper();
crypto.AsymmetricKeyPair pair =
await helper.computeRSAKeyPair(helper.getSecureRandom());
var privateKey = pair.privateKey as RSAPrivateKey;
var publicKey = pair.publicKey as RSAPublicKey;
savedPrivateKey = helper.encodePrivateKeyToPemPKCS1(privateKey);
savedPubKey = publicKey.encode(ssh_key.PubKeyEncoding.openSsh);
await _box.put(BNames.sshPrivateKey, savedPrivateKey);
await _box.put(BNames.sshPublicKey, savedPubKey);
}
void init() async {
savedPrivateKey = _box.get(BNames.sshPrivateKey);
savedPubKey = _box.get(BNames.sshPublicKey);
}
bool get isSSHKeyGenerated => savedPrivateKey != null && savedPubKey != null;
Future<void> clear() async {
savedPrivateKey = null;
savedPubKey = null;
await _box.clear();
}
}

View File

@ -1,4 +1,3 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
part 'api_token.g.dart'; part 'api_token.g.dart';

View File

@ -83,7 +83,7 @@ class MyApp extends StatelessWidget {
darkTheme: darkThemeData, darkTheme: darkThemeData,
themeMode: themeMode:
appSettings.isDarkModeOn ? ThemeMode.dark : ThemeMode.light, appSettings.isDarkModeOn ? ThemeMode.dark : ThemeMode.light,
home: appSettings.isOnbordingShowing home: appSettings.isOnboardingShowing
? OnboardingPage(nextPage: InitializingPage()) ? OnboardingPage(nextPage: InitializingPage())
: RootPage(), : RootPage(),
builder: (BuildContext context, Widget? widget) { builder: (BuildContext context, Widget? widget) {

View File

@ -4,7 +4,7 @@ import 'package:flutter/services.dart' show rootBundle;
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:selfprivacy/config/brand_colors.dart'; import 'package:selfprivacy/config/brand_colors.dart';
import 'package:selfprivacy/config/text_themes.dart'; import 'package:selfprivacy/config/text_themes.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher_string.dart';
class BrandMarkdown extends StatefulWidget { class BrandMarkdown extends StatefulWidget {
const BrandMarkdown({ const BrandMarkdown({
@ -60,9 +60,9 @@ class _BrandMarkdownState extends State<BrandMarkdown> {
styleSheet: markdown, styleSheet: markdown,
onTapLink: (String text, String? href, String title) { onTapLink: (String text, String? href, String title) {
if (href != null) { if (href != null) {
canLaunch(href).then((canLaunchURL) { canLaunchUrlString(href).then((canLaunchURL) {
if (canLaunchURL) { if (canLaunchURL) {
launch(href); launchUrlString(href);
} }
}); });
} }

View File

@ -26,8 +26,8 @@ class BrandSpanButton extends TextSpan {
); );
static _launchURL(String link) async { static _launchURL(String link) async {
if (await canLaunch(link)) { if (await canLaunchUrl(Uri.parse(link))) {
await launch(link); await launchUrl(Uri.parse(link));
} else { } else {
throw 'Could not launch $link'; throw 'Could not launch $link';
} }

View File

@ -19,7 +19,7 @@ import 'package:selfprivacy/ui/components/icon_status_mask/icon_status_mask.dart
import 'package:selfprivacy/ui/components/not_ready_card/not_ready_card.dart'; import 'package:selfprivacy/ui/components/not_ready_card/not_ready_card.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:selfprivacy/utils/ui_helpers.dart'; import 'package:selfprivacy/utils/ui_helpers.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher_string.dart';
import '../rootRoute.dart'; import '../rootRoute.dart';
@ -39,13 +39,12 @@ class ServicesPage extends StatefulWidget {
} }
void _launchURL(url) async { void _launchURL(url) async {
var _possible = await canLaunch(url); var _possible = await canLaunchUrlString(url);
if (_possible) { if (_possible) {
try { try {
await launch( await launchUrlString(
url, url,
enableJavaScript: true,
); );
} catch (e) { } catch (e) {
print(e); print(e);
@ -151,11 +150,9 @@ class _Card extends StatelessWidget {
builder: (context) { builder: (context) {
late bool isActive; late bool isActive;
if (hasSwitchJob) { if (hasSwitchJob) {
isActive = ((jobState as JobsStateWithJobs) isActive = ((jobState).jobList.firstWhere((el) =>
.jobList el is ServiceToggleJob &&
.firstWhere((el) => el.type == serviceType) as ServiceToggleJob)
el is ServiceToggleJob &&
el.type == serviceType) as ServiceToggleJob)
.needToTurnOn; .needToTurnOn;
} else { } else {
isActive = serviceState.isEnableByType(serviceType); isActive = serviceState.isEnableByType(serviceType);

View File

@ -10,11 +10,11 @@ import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.da
class RecoveryDomain extends StatelessWidget { class RecoveryDomain extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var appConfig = context.watch<ServerInstallationCubit>(); var serverInstallation = context.watch<ServerInstallationCubit>();
return BlocProvider( return BlocProvider(
create: (context) => create: (context) => RecoveryDomainFormCubit(
RecoveryDomainFormCubit(appConfig, FieldCubitFactory(context)), serverInstallation, FieldCubitFactory(context)),
child: Builder( child: Builder(
builder: (context) { builder: (context) {
var formCubitState = context.watch<RecoveryDomainFormCubit>().state; var formCubitState = context.watch<RecoveryDomainFormCubit>().state;

View File

@ -715,7 +715,7 @@ packages:
source: hosted source: hosted
version: "2.1.2" version: "2.1.2"
pointycastle: pointycastle:
dependency: "direct main" dependency: transitive
description: description:
name: pointycastle name: pointycastle
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
@ -770,13 +770,6 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "3.1.0" version: "3.1.0"
rsa_encrypt:
dependency: "direct main"
description:
name: rsa_encrypt
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
share_plus: share_plus:
dependency: "direct main" dependency: "direct main"
description: description:

View File

@ -34,10 +34,8 @@ dependencies:
modal_bottom_sheet: ^2.0.1 modal_bottom_sheet: ^2.0.1
nanoid: ^1.0.0 nanoid: ^1.0.0
package_info: ^2.0.2 package_info: ^2.0.2
pointycastle: ^3.5.1
pretty_dio_logger: ^1.2.0-beta-1 pretty_dio_logger: ^1.2.0-beta-1
provider: ^6.0.2 provider: ^6.0.2
rsa_encrypt: ^2.0.0
share_plus: ^4.0.4 share_plus: ^4.0.4
ssh_key: ^0.7.1 ssh_key: ^0.7.1
system_theme: ^2.0.0 system_theme: ^2.0.0