From 81f4f93d7c26408df16773913d36fe6c1974038b Mon Sep 17 00:00:00 2001 From: Inex Code Date: Fri, 12 Apr 2024 15:13:30 +0300 Subject: [PATCH 01/11] refactor: Fix typos in variable names --- .../server_installation/server_installation_state.dart | 10 +++++----- lib/logic/models/price.dart | 2 +- lib/ui/pages/setup/initializing/initializing.dart | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/logic/cubit/server_installation/server_installation_state.dart b/lib/logic/cubit/server_installation/server_installation_state.dart index 3f3ea267..bf0981e2 100644 --- a/lib/logic/cubit/server_installation/server_installation_state.dart +++ b/lib/logic/cubit/server_installation/server_installation_state.dart @@ -49,11 +49,11 @@ abstract class ServerInstallationState extends Equatable { bool get isPrimaryUserFilled => rootUser != null; bool get isServerCreated => serverDetails != null; - bool get isFullyInitilized => _fulfilementList.every((final el) => el!); + bool get isFullyInitialized => _fulfillmentList.every((final el) => el!); ServerSetupProgress get progress => ServerSetupProgress - .values[_fulfilementList.where((final el) => el!).length]; + .values[_fulfillmentList.where((final el) => el!).length]; - int get porgressBar { + int get progressBar { if (progress.index < 6) { return progress.index; } else if (progress.index < 10) { @@ -63,7 +63,7 @@ abstract class ServerInstallationState extends Equatable { } } - List get _fulfilementList { + List get _fulfillmentList { final List res = [ isServerProviderApiKeyFilled, isServerTypeFilled, @@ -118,7 +118,7 @@ class TimerState extends ServerInstallationNotFinished { enum ServerSetupProgress { nothingYet, serverProviderFilled, - servertTypeFilled, + serverTypeFilled, dnsProviderFilled, backblazeFilled, domainFilled, diff --git a/lib/logic/models/price.dart b/lib/logic/models/price.dart index 494b1511..19b5d59a 100644 --- a/lib/logic/models/price.dart +++ b/lib/logic/models/price.dart @@ -11,7 +11,7 @@ class Price { enum CurrencyType { eur, usd, - unkown, + unknown, } class Currency { diff --git a/lib/ui/pages/setup/initializing/initializing.dart b/lib/ui/pages/setup/initializing/initializing.dart index 54b5cbe2..d102e8e6 100644 --- a/lib/ui/pages/setup/initializing/initializing.dart +++ b/lib/ui/pages/setup/initializing/initializing.dart @@ -112,7 +112,7 @@ class InitializingPage extends StatelessWidget { 'Server', 'Installation', ], - activeIndex: cubit.state.porgressBar, + activeIndex: cubit.state.progressBar, ), ), ), From 16d1c8a9186b372f7e34057f58f42538ff6c44e4 Mon Sep 17 00:00:00 2001 From: Inex Code Date: Fri, 12 Apr 2024 15:41:32 +0300 Subject: [PATCH 02/11] refactor: Remove unused Users Hive box --- lib/config/hive_config.dart | 18 +----------------- .../server_installation_repository.dart | 2 -- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/lib/config/hive_config.dart b/lib/config/hive_config.dart index 55b35e9e..dbd5a2a3 100644 --- a/lib/config/hive_config.dart +++ b/lib/config/hive_config.dart @@ -32,16 +32,6 @@ class HiveConfig { await getEncryptedKey(BNames.serverInstallationEncryptionKey), ); - await Hive.openBox(BNames.usersDeprecated); - await Hive.openBox(BNames.usersBox, encryptionCipher: cipher); - - final Box deprecatedUsers = Hive.box(BNames.usersDeprecated); - if (deprecatedUsers.isNotEmpty) { - final Box users = Hive.box(BNames.usersBox); - await users.addAll(deprecatedUsers.values.toList()); - await deprecatedUsers.clear(); - } - await Hive.openBox(BNames.serverInstallationBox, encryptionCipher: cipher); } @@ -72,7 +62,7 @@ class BNames { /// A boolean field of [appSettingsBox] box. static String isOnboardingShowing = 'isOnboardingShowing'; - /// Encryption key to decrypt [serverInstallationBox] and [usersBox] box. + /// Encryption key to decrypt [serverInstallationBox] box. static String serverInstallationEncryptionKey = 'key'; /// Server installation box. Contains server details and provider tokens. @@ -131,10 +121,4 @@ class BNames { /// A boolean field of [serverInstallationBox] box. static String isRecoveringServer = 'isRecoveringServer'; - - /// Deprecated users box as it is unencrypted - static String usersDeprecated = 'users'; - - /// Box with users - static String usersBox = 'usersEncrypted'; } diff --git a/lib/logic/cubit/server_installation/server_installation_repository.dart b/lib/logic/cubit/server_installation/server_installation_repository.dart index 90035fea..28f6bd2f 100644 --- a/lib/logic/cubit/server_installation/server_installation_repository.dart +++ b/lib/logic/cubit/server_installation/server_installation_repository.dart @@ -34,7 +34,6 @@ class ServerAuthorizationException implements Exception { class ServerInstallationRepository { Box box = Hive.box(BNames.serverInstallationBox); - Box usersBox = Hive.box(BNames.usersBox); Future load() async { final String? providerApiToken = getIt().serverProviderKey; @@ -177,7 +176,6 @@ class ServerInstallationRepository { void clearAppConfig() { box.clear(); - usersBox.clear(); } Future startServer( From 1e024a236b68e7e0fab504286b43649086df865c Mon Sep 17 00:00:00 2001 From: Inex Code Date: Wed, 15 May 2024 17:16:59 +0300 Subject: [PATCH 03/11] refactor: Move information about tokens to the Resources model, and introduce a WizardData model --- lib/config/get_it_config.dart | 3 + lib/config/hive_config.dart | 117 ++++++- .../graphql_maps/graphql_api_map.dart | 5 +- .../graphql_maps/server_api/server_api.dart | 3 +- lib/logic/api_maps/rest_maps/backblaze.dart | 11 +- .../cloudflare/cloudflare_api.dart | 3 +- .../dns_providers/desec/desec_api.dart | 3 +- .../digital_ocean_dns_api.dart | 3 +- .../digital_ocean/digital_ocean_api.dart | 3 +- .../server_providers/hetzner/hetzner_api.dart | 3 +- lib/logic/bloc/backups/backups_bloc.dart | 5 +- .../cubit/metrics/metrics_repository.dart | 3 +- .../server_detailed_info_cubit.dart | 5 +- .../server_installation_cubit.dart | 20 +- .../server_installation_repository.dart | 311 +++++++----------- .../server_installation_state.dart | 47 +-- lib/logic/get_it/api_config.dart | 90 ----- .../get_it/api_connection_repository.dart | 19 +- lib/logic/get_it/resources_model.dart | 309 +++++++++++++++++ lib/logic/models/hive/README.md | 12 +- lib/logic/models/hive/backups_credential.dart | 1 + .../models/hive/dns_provider_credential.dart | 27 ++ .../hive/dns_provider_credential.g.dart | 50 +++ lib/logic/models/hive/server.dart | 20 ++ lib/logic/models/hive/server.g.dart | 44 +++ lib/logic/models/hive/server_details.dart | 23 +- lib/logic/models/hive/server_details.g.dart | 14 +- .../hive/server_provider_credential.dart | 27 ++ .../hive/server_provider_credential.g.dart | 51 +++ .../server_installation_wizard_data.dart | 130 ++++++++ .../server_installation_wizard_data.g.dart | 87 +++++ lib/ui/pages/dns_details/dns_details.dart | 3 +- 32 files changed, 1107 insertions(+), 345 deletions(-) create mode 100644 lib/logic/get_it/resources_model.dart create mode 100644 lib/logic/models/hive/dns_provider_credential.dart create mode 100644 lib/logic/models/hive/dns_provider_credential.g.dart create mode 100644 lib/logic/models/hive/server.dart create mode 100644 lib/logic/models/hive/server.g.dart create mode 100644 lib/logic/models/hive/server_provider_credential.dart create mode 100644 lib/logic/models/hive/server_provider_credential.g.dart create mode 100644 lib/logic/models/hive/wizards_data/server_installation_wizard_data.dart create mode 100644 lib/logic/models/hive/wizards_data/server_installation_wizard_data.g.dart diff --git a/lib/config/get_it_config.dart b/lib/config/get_it_config.dart index 78e40261..8a3d9e26 100644 --- a/lib/config/get_it_config.dart +++ b/lib/config/get_it_config.dart @@ -3,6 +3,7 @@ import 'package:selfprivacy/logic/get_it/api_config.dart'; import 'package:selfprivacy/logic/get_it/api_connection_repository.dart'; import 'package:selfprivacy/logic/get_it/console.dart'; import 'package:selfprivacy/logic/get_it/navigation.dart'; +import 'package:selfprivacy/logic/get_it/resources_model.dart'; export 'package:selfprivacy/logic/get_it/api_config.dart'; export 'package:selfprivacy/logic/get_it/api_connection_repository.dart'; @@ -15,6 +16,8 @@ Future getItSetup() async { getIt.registerSingleton(NavigationService()); getIt.registerSingleton(ConsoleModel()); + getIt.registerSingleton(ResourcesModel()..init()); + getIt.registerSingleton(WizardDataModel()..init()); getIt.registerSingleton(ApiConfigModel()..init()); getIt.registerSingleton( diff --git a/lib/config/hive_config.dart b/lib/config/hive_config.dart index dbd5a2a3..2853b955 100644 --- a/lib/config/hive_config.dart +++ b/lib/config/hive_config.dart @@ -5,9 +5,13 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart'; import 'package:selfprivacy/logic/models/hive/backups_credential.dart'; +import 'package:selfprivacy/logic/models/hive/dns_provider_credential.dart'; +import 'package:selfprivacy/logic/models/hive/server.dart'; import 'package:selfprivacy/logic/models/hive/server_details.dart'; import 'package:selfprivacy/logic/models/hive/server_domain.dart'; +import 'package:selfprivacy/logic/models/hive/server_provider_credential.dart'; import 'package:selfprivacy/logic/models/hive/user.dart'; +import 'package:selfprivacy/logic/models/hive/wizards_data/server_installation_wizard_data.dart'; import 'package:selfprivacy/utils/platform_adapter.dart'; class HiveConfig { @@ -19,12 +23,16 @@ class HiveConfig { Hive.registerAdapter(ServerHostingDetailsAdapter()); Hive.registerAdapter(ServerDomainAdapter()); Hive.registerAdapter(BackupsCredentialAdapter()); - Hive.registerAdapter(BackblazeBucketAdapter()); Hive.registerAdapter(ServerProviderVolumeAdapter()); - Hive.registerAdapter(UserTypeAdapter()); + Hive.registerAdapter(BackblazeBucketAdapter()); + Hive.registerAdapter(ServerProviderCredentialAdapter()); + Hive.registerAdapter(DnsProviderCredentialAdapter()); + Hive.registerAdapter(ServerAdapter()); Hive.registerAdapter(DnsProviderTypeAdapter()); Hive.registerAdapter(ServerProviderTypeAdapter()); + Hive.registerAdapter(UserTypeAdapter()); Hive.registerAdapter(BackupsProviderTypeAdapter()); + Hive.registerAdapter(ServerInstallationWizardDataAdapter()); await Hive.openBox(BNames.appSettingsBox); @@ -33,6 +41,88 @@ class HiveConfig { ); await Hive.openBox(BNames.serverInstallationBox, encryptionCipher: cipher); + await Hive.openBox(BNames.resourcesBox, encryptionCipher: cipher); + await Hive.openBox(BNames.wizardDataBox, encryptionCipher: cipher); + + final Box resourcesBox = Hive.box(BNames.resourcesBox); + if (resourcesBox.isEmpty) { + final Box serverInstallationBox = Hive.box(BNames.serverInstallationBox); + + final String? serverProviderKey = + serverInstallationBox.get(BNames.hetznerKey); + final String? serverLocation = + serverInstallationBox.get(BNames.serverLocation); + final String? dnsProviderKey = + serverInstallationBox.get(BNames.cloudFlareKey); + final BackupsCredential? backblazeCredential = + serverInstallationBox.get(BNames.backblazeCredential); + final ServerDomain? serverDomain = + serverInstallationBox.get(BNames.serverDomain); + final ServerHostingDetails? serverDetails = + serverInstallationBox.get(BNames.serverDetails); + final BackblazeBucket? backblazeBucket = + serverInstallationBox.get(BNames.backblazeBucket); + final String? serverType = + serverInstallationBox.get(BNames.serverTypeIdentifier); + final ServerProviderType? serverProvider = + serverInstallationBox.get(BNames.serverProvider); + final DnsProviderType? dnsProvider = + serverInstallationBox.get(BNames.dnsProvider); + + if (serverProviderKey != null && + (serverProvider != null || + (serverDetails != null && + serverDetails.provider != ServerProviderType.unknown))) { + final ServerProviderCredential serverProviderCredential = + ServerProviderCredential( + tokenId: null, + token: serverProviderKey, + provider: serverProvider ?? serverDetails!.provider, + associatedServerIds: serverDetails != null ? [serverDetails.id] : [], + ); + + await resourcesBox + .put(BNames.serverProviderTokens, [serverProviderCredential]); + } + + if (dnsProviderKey != null && + (dnsProvider != null || + (serverDomain != null && + serverDomain.provider != DnsProviderType.unknown))) { + final DnsProviderCredential dnsProviderCredential = + DnsProviderCredential( + tokenId: null, + token: dnsProviderKey, + provider: dnsProvider ?? serverDomain!.provider, + associatedDomainNames: + serverDomain != null ? [serverDomain.domainName] : [], + ); + + await resourcesBox + .put(BNames.dnsProviderTokens, [dnsProviderCredential]); + } + + if (backblazeCredential != null) { + await resourcesBox + .put(BNames.backupsProviderTokens, [backblazeCredential]); + } + + if (backblazeBucket != null) { + await resourcesBox.put(BNames.backblazeBucket, backblazeBucket); + } + + if (serverDetails != null && serverDomain != null) { + await resourcesBox.put(BNames.servers, [ + Server( + domain: serverDomain, + hostingDetails: serverDetails.copyWith( + serverLocation: serverLocation, + serverType: serverType, + ), + ), + ]); + } + } } static Future getEncryptedKey(final String encKey) async { @@ -95,7 +185,7 @@ class BNames { /// A String field of [serverInstallationBox] box. static String cloudFlareKey = 'cloudFlareKey'; - /// A String field of [serverTypeIdentifier] box. + /// A String field of [serverInstallationBox] box. static String serverTypeIdentifier = 'serverTypeIdentifier'; /// A [User] field of [serverInstallationBox] box. @@ -121,4 +211,25 @@ class BNames { /// A boolean field of [serverInstallationBox] box. static String isRecoveringServer = 'isRecoveringServer'; + + /// Resources and provider tokens box, + static String resourcesBox = 'resourcesBox'; + + /// Server Provider Tokens of [resourcesBox] box. + static String serverProviderTokens = 'serverProviderTokens'; + + /// DNS Provider Tokens of [resourcesBox] box. + static String dnsProviderTokens = 'dnsProviderTokens'; + + /// Backups Provider Tokens of [resourcesBox] box. + static String backupsProviderTokens = 'backupsProviderTokens'; + + /// Servers of [resourcesBox] box. + static String servers = 'servers'; + + /// Wizard data box + static String wizardDataBox = 'wizardDataBox'; + + /// Server installation wizard data of [wizardDataBox] box. + static String serverInstallationWizardData = 'serverInstallationWizardData'; } diff --git a/lib/logic/api_maps/graphql_maps/graphql_api_map.dart b/lib/logic/api_maps/graphql_maps/graphql_api_map.dart index 6a00f5b6..bade5e91 100644 --- a/lib/logic/api_maps/graphql_maps/graphql_api_map.dart +++ b/lib/logic/api_maps/graphql_maps/graphql_api_map.dart @@ -4,6 +4,7 @@ import 'package:graphql_flutter/graphql_flutter.dart'; import 'package:http/io_client.dart'; import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/logic/api_maps/tls_options.dart'; +import 'package:selfprivacy/logic/get_it/resources_model.dart'; import 'package:selfprivacy/logic/models/message.dart'; void _logToAppConsole(final T objectToLog) { @@ -117,9 +118,9 @@ abstract class GraphQLApiMap { String get _token { String token = ''; - final serverDetails = getIt().serverDetails; + final serverDetails = getIt().serverDetails; if (serverDetails != null) { - token = getIt().serverDetails!.apiToken; + token = getIt().serverDetails!.apiToken; } return token; } diff --git a/lib/logic/api_maps/graphql_maps/server_api/server_api.dart b/lib/logic/api_maps/graphql_maps/server_api/server_api.dart index e2efb41b..ac384c01 100644 --- a/lib/logic/api_maps/graphql_maps/server_api/server_api.dart +++ b/lib/logic/api_maps/graphql_maps/server_api/server_api.dart @@ -9,6 +9,7 @@ import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/server_api.graphq import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/server_settings.graphql.dart'; import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/services.graphql.dart'; import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/users.graphql.dart'; +import 'package:selfprivacy/logic/get_it/resources_model.dart'; import 'package:selfprivacy/logic/models/auto_upgrade_settings.dart'; import 'package:selfprivacy/logic/models/backup.dart'; import 'package:selfprivacy/logic/models/hive/server_details.dart'; @@ -57,7 +58,7 @@ class ServerApi extends GraphQLApiMap String customToken; @override String? get rootAddress => - overrideDomain ?? getIt().serverDomain?.domainName; + overrideDomain ?? getIt().serverDomain?.domainName; String? overrideDomain; Future getApiVersion() async { diff --git a/lib/logic/api_maps/rest_maps/backblaze.dart b/lib/logic/api_maps/rest_maps/backblaze.dart index 65f17463..37d87dd8 100644 --- a/lib/logic/api_maps/rest_maps/backblaze.dart +++ b/lib/logic/api_maps/rest_maps/backblaze.dart @@ -4,6 +4,7 @@ import 'package:dio/dio.dart'; import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/logic/api_maps/generic_result.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/rest_api_map.dart'; +import 'package:selfprivacy/logic/get_it/resources_model.dart'; import 'package:selfprivacy/logic/models/backup.dart'; import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart'; import 'package:selfprivacy/logic/models/hive/backups_credential.dart'; @@ -39,7 +40,7 @@ class BackblazeApi extends RestApiMap { ); if (isWithToken) { final BackupsCredential? backblazeCredential = - getIt().backblazeCredential; + getIt().backblazeCredential; final String token = backblazeCredential!.applicationKey; options.headers = {'Authorization': 'Basic $token'}; } @@ -59,7 +60,7 @@ class BackblazeApi extends RestApiMap { Future getAuthorizationToken() async { final Dio client = await getClient(); final BackupsCredential? backblazeCredential = - getIt().backblazeCredential; + getIt().backblazeCredential; if (backblazeCredential == null) { throw Exception('Backblaze credential is null'); } @@ -124,7 +125,7 @@ class BackblazeApi extends RestApiMap { Future createBucket(final String bucketName) async { final BackblazeApiAuth auth = await getAuthorizationToken(); final BackupsCredential? backblazeCredential = - getIt().backblazeCredential; + getIt().backblazeCredential; final Dio client = await getClient(); client.options.baseUrl = auth.apiUrl; final Response response = await client.post( @@ -161,7 +162,7 @@ class BackblazeApi extends RestApiMap { final Response response = await client.post( '$apiPrefix/b2_create_key', data: { - 'accountId': getIt().backblazeCredential!.keyId, + 'accountId': getIt().backblazeCredential!.keyId, 'bucketId': bucketId, 'capabilities': ['listBuckets', 'listFiles', 'readFiles', 'writeFiles'], 'keyName': 'selfprivacy-restricted-server-key', @@ -192,7 +193,7 @@ class BackblazeApi extends RestApiMap { final Response response = await client.get( '$apiPrefix/b2_list_buckets', queryParameters: { - 'accountId': getIt().backblazeCredential!.keyId, + 'accountId': getIt().backblazeCredential!.keyId, }, options: Options( headers: {'Authorization': auth.authorizationToken}, diff --git a/lib/logic/api_maps/rest_maps/dns_providers/cloudflare/cloudflare_api.dart b/lib/logic/api_maps/rest_maps/dns_providers/cloudflare/cloudflare_api.dart index fa325ef5..aa5bf88e 100644 --- a/lib/logic/api_maps/rest_maps/dns_providers/cloudflare/cloudflare_api.dart +++ b/lib/logic/api_maps/rest_maps/dns_providers/cloudflare/cloudflare_api.dart @@ -4,6 +4,7 @@ import 'package:dio/dio.dart'; import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/logic/api_maps/generic_result.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/rest_api_map.dart'; +import 'package:selfprivacy/logic/get_it/resources_model.dart'; import 'package:selfprivacy/logic/models/json/dns_providers/cloudflare_dns_info.dart'; class CloudflareApi extends RestApiMap { @@ -27,7 +28,7 @@ class CloudflareApi extends RestApiMap { responseType: ResponseType.json, ); if (isWithToken) { - final String? token = getIt().dnsProviderKey; + final String? token = getIt().dnsProviderKey; assert(token != null); options.headers = {'Authorization': 'Bearer $token'}; } diff --git a/lib/logic/api_maps/rest_maps/dns_providers/desec/desec_api.dart b/lib/logic/api_maps/rest_maps/dns_providers/desec/desec_api.dart index 2bc15c22..1584e819 100644 --- a/lib/logic/api_maps/rest_maps/dns_providers/desec/desec_api.dart +++ b/lib/logic/api_maps/rest_maps/dns_providers/desec/desec_api.dart @@ -4,6 +4,7 @@ import 'package:dio/dio.dart'; import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/logic/api_maps/generic_result.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/rest_api_map.dart'; +import 'package:selfprivacy/logic/get_it/resources_model.dart'; import 'package:selfprivacy/logic/models/json/dns_providers/desec_dns_info.dart'; class DesecApi extends RestApiMap { @@ -27,7 +28,7 @@ class DesecApi extends RestApiMap { responseType: ResponseType.json, ); if (isWithToken) { - final String? token = getIt().dnsProviderKey; + final String? token = getIt().dnsProviderKey; assert(token != null); options.headers = {'Authorization': 'Token $token'}; } diff --git a/lib/logic/api_maps/rest_maps/dns_providers/digital_ocean_dns/digital_ocean_dns_api.dart b/lib/logic/api_maps/rest_maps/dns_providers/digital_ocean_dns/digital_ocean_dns_api.dart index 10da51e3..0a2cea53 100644 --- a/lib/logic/api_maps/rest_maps/dns_providers/digital_ocean_dns/digital_ocean_dns_api.dart +++ b/lib/logic/api_maps/rest_maps/dns_providers/digital_ocean_dns/digital_ocean_dns_api.dart @@ -4,6 +4,7 @@ import 'package:dio/dio.dart'; import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/logic/api_maps/generic_result.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/rest_api_map.dart'; +import 'package:selfprivacy/logic/get_it/resources_model.dart'; import 'package:selfprivacy/logic/models/json/dns_providers/digital_ocean_dns_info.dart'; class DigitalOceanDnsApi extends RestApiMap { @@ -27,7 +28,7 @@ class DigitalOceanDnsApi extends RestApiMap { responseType: ResponseType.json, ); if (isWithToken) { - final String? token = getIt().dnsProviderKey; + final String? token = getIt().dnsProviderKey; assert(token != null); options.headers = {'Authorization': 'Bearer $token'}; } diff --git a/lib/logic/api_maps/rest_maps/server_providers/digital_ocean/digital_ocean_api.dart b/lib/logic/api_maps/rest_maps/server_providers/digital_ocean/digital_ocean_api.dart index 26f1cc8b..d9ec1e5b 100644 --- a/lib/logic/api_maps/rest_maps/server_providers/digital_ocean/digital_ocean_api.dart +++ b/lib/logic/api_maps/rest_maps/server_providers/digital_ocean/digital_ocean_api.dart @@ -5,6 +5,7 @@ import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/logic/api_maps/generic_result.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/rest_api_map.dart'; import 'package:selfprivacy/logic/api_maps/tls_options.dart'; +import 'package:selfprivacy/logic/get_it/resources_model.dart'; import 'package:selfprivacy/logic/models/hive/user.dart'; import 'package:selfprivacy/logic/models/json/digital_ocean_server_info.dart'; import 'package:selfprivacy/utils/password_generator.dart'; @@ -30,7 +31,7 @@ class DigitalOceanApi extends RestApiMap { responseType: ResponseType.json, ); if (isWithToken) { - final String? token = getIt().serverProviderKey; + final String? token = getIt().serverProviderKey; assert(token != null); options.headers = {'Authorization': 'Bearer $token'}; } diff --git a/lib/logic/api_maps/rest_maps/server_providers/hetzner/hetzner_api.dart b/lib/logic/api_maps/rest_maps/server_providers/hetzner/hetzner_api.dart index 84e65cd7..ef731d80 100644 --- a/lib/logic/api_maps/rest_maps/server_providers/hetzner/hetzner_api.dart +++ b/lib/logic/api_maps/rest_maps/server_providers/hetzner/hetzner_api.dart @@ -5,6 +5,7 @@ import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/logic/api_maps/generic_result.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/rest_api_map.dart'; import 'package:selfprivacy/logic/api_maps/tls_options.dart'; +import 'package:selfprivacy/logic/get_it/resources_model.dart'; import 'package:selfprivacy/logic/models/disk_size.dart'; import 'package:selfprivacy/logic/models/hive/user.dart'; import 'package:selfprivacy/logic/models/json/hetzner_server_info.dart'; @@ -31,7 +32,7 @@ class HetznerApi extends RestApiMap { responseType: ResponseType.json, ); if (isWithToken) { - final String? token = getIt().serverProviderKey; + final String? token = getIt().serverProviderKey; assert(token != null); options.headers = {'Authorization': 'Bearer $token'}; } diff --git a/lib/logic/bloc/backups/backups_bloc.dart b/lib/logic/bloc/backups/backups_bloc.dart index 5c0e9e64..4e8930a6 100644 --- a/lib/logic/bloc/backups/backups_bloc.dart +++ b/lib/logic/bloc/backups/backups_bloc.dart @@ -6,6 +6,7 @@ import 'package:equatable/equatable.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/backblaze.dart'; +import 'package:selfprivacy/logic/get_it/resources_model.dart'; import 'package:selfprivacy/logic/models/backup.dart'; import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart'; import 'package:selfprivacy/logic/models/hive/backups_credential.dart'; @@ -108,7 +109,7 @@ class BackupsBloc extends Bloc { final BackupsServerLoaded event, final Emitter emit, ) async { - BackblazeBucket? bucket = getIt().backblazeBucket; + BackblazeBucket? bucket = getIt().backblazeBucket; final backups = getIt().apiData.backups; final backupConfig = getIt().apiData.backupConfig; if (backupConfig.data == null || backups.data == null) { @@ -227,7 +228,7 @@ class BackupsBloc extends Bloc { emit(BackupsUnititialized()); return; } - final BackblazeBucket? bucket = getIt().backblazeBucket; + final BackblazeBucket? bucket = getIt().backblazeBucket; emit( BackupsInitialized( backblazeBucket: bucket, diff --git a/lib/logic/cubit/metrics/metrics_repository.dart b/lib/logic/cubit/metrics/metrics_repository.dart index 0c6a82ef..561d75ef 100644 --- a/lib/logic/cubit/metrics/metrics_repository.dart +++ b/lib/logic/cubit/metrics/metrics_repository.dart @@ -2,6 +2,7 @@ import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/logic/common_enum/common_enum.dart'; import 'package:selfprivacy/logic/cubit/metrics/metrics_cubit.dart'; +import 'package:selfprivacy/logic/get_it/resources_model.dart'; import 'package:selfprivacy/logic/providers/providers_controller.dart'; class MetricsLoadException implements Exception { @@ -30,7 +31,7 @@ class MetricsRepository { break; } - final serverId = getIt().serverDetails!.id; + final serverId = getIt().serverDetails!.id; final result = await ProvidersController.currentServerProvider!.getMetrics( serverId, start, diff --git a/lib/logic/cubit/server_detailed_info/server_detailed_info_cubit.dart b/lib/logic/cubit/server_detailed_info/server_detailed_info_cubit.dart index d6e548f8..09b9e845 100644 --- a/lib/logic/cubit/server_detailed_info/server_detailed_info_cubit.dart +++ b/lib/logic/cubit/server_detailed_info/server_detailed_info_cubit.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/logic/cubit/server_connection_dependent/server_connection_dependent_cubit.dart'; +import 'package:selfprivacy/logic/get_it/resources_model.dart'; import 'package:selfprivacy/logic/models/auto_upgrade_settings.dart'; import 'package:selfprivacy/logic/models/server_metadata.dart'; import 'package:selfprivacy/logic/models/ssh_settings.dart'; @@ -43,7 +44,7 @@ class ServerDetailsCubit final serverProviderApi = ProvidersController.currentServerProvider; final dnsProviderApi = ProvidersController.currentDnsProvider; if (serverProviderApi != null && dnsProviderApi != null) { - final serverId = getIt().serverDetails?.id ?? 0; + final serverId = getIt().serverDetails?.id ?? 0; final metadataResult = await serverProviderApi.getMetadata(serverId); metadataResult.data.add( ServerMetadataEntity( @@ -60,7 +61,7 @@ class ServerDetailsCubit } void check() async { - final bool isReadyToCheck = getIt().serverDetails != null; + final bool isReadyToCheck = getIt().serverDetails != null; try { if (isReadyToCheck) { emit(const ServerDetailsLoading()); diff --git a/lib/logic/cubit/server_installation/server_installation_cubit.dart b/lib/logic/cubit/server_installation/server_installation_cubit.dart index 66e9e2f2..6b507e93 100644 --- a/lib/logic/cubit/server_installation/server_installation_cubit.dart +++ b/lib/logic/cubit/server_installation/server_installation_cubit.dart @@ -15,6 +15,7 @@ import 'package:selfprivacy/logic/models/hive/backups_credential.dart'; import 'package:selfprivacy/logic/models/hive/server_details.dart'; import 'package:selfprivacy/logic/models/hive/server_domain.dart'; import 'package:selfprivacy/logic/models/hive/user.dart'; +import 'package:selfprivacy/logic/models/hive/wizards_data/server_installation_wizard_data.dart'; import 'package:selfprivacy/logic/models/launch_installation_data.dart'; import 'package:selfprivacy/logic/models/price.dart'; import 'package:selfprivacy/logic/models/server_basic_info.dart'; @@ -222,12 +223,14 @@ class ServerInstallationCubit extends Cubit { provider: BackupsProviderType.backblaze, ); final BackblazeBucket? bucket; - await repository.saveBackblazeKey(backblazeCredential); + await repository.saveBackupsCredential(backblazeCredential); if (state is ServerInstallationRecovery) { final configuration = await ServerApi( customToken: (state as ServerInstallationRecovery).serverDetails!.apiToken, isWithToken: true, + overrideDomain: + (state as ServerInstallationRecovery).serverDomain!.domainName, ).getBackupsConfiguration(); if (configuration != null) { try { @@ -401,7 +404,7 @@ class ServerInstallationCubit extends Cubit { ); timer = Timer(pauseDuration, () async { final ServerHostingDetails serverDetails = await repository.restart(); - await repository.saveIsServerResetedFirstTime(true); + await repository.saveIsServerRebootedFirstTime(true); await repository.saveServerDetails(serverDetails); final ServerInstallationNotFinished newState = dataState.copyWith( @@ -442,7 +445,7 @@ class ServerInstallationCubit extends Cubit { ); timer = Timer(pauseDuration, () async { final ServerHostingDetails serverDetails = await repository.restart(); - await repository.saveIsServerResetedSecondTime(true); + await repository.saveIsServerRebootedSecondTime(true); await repository.saveServerDetails(serverDetails); final ServerInstallationNotFinished newState = dataState.copyWith( @@ -577,10 +580,12 @@ class ServerInstallationCubit extends Cubit { final ServerProviderType serverProvider = await ServerApi( customToken: serverDetails.apiToken, isWithToken: true, + overrideDomain: serverDomain.domainName, ).getServerProviderType(); final dnsProvider = await ServerApi( customToken: serverDetails.apiToken, isWithToken: true, + overrideDomain: serverDomain.domainName, ).getDnsProviderType(); if (serverProvider == ServerProviderType.unknown || dnsProvider == DnsProviderType.unknown) { @@ -762,6 +767,7 @@ class ServerInstallationCubit extends Cubit { final dnsProviderType = await ServerApi( customToken: dataState.serverDetails!.apiToken, isWithToken: true, + overrideDomain: serverDomain.domainName, ).getDnsProviderType(); await repository.saveDomain( ServerDomain( @@ -769,6 +775,7 @@ class ServerInstallationCubit extends Cubit { provider: dnsProviderType, ), ); + await repository.setDnsApiToken(token); emit( dataState.copyWith( serverDomain: ServerDomain( @@ -785,8 +792,8 @@ class ServerInstallationCubit extends Cubit { final BackupsCredential backblazeCredential, ) async { await repository.saveIsServerStarted(true); - await repository.saveIsServerResetedFirstTime(true); - await repository.saveIsServerResetedSecondTime(true); + await repository.saveIsServerRebootedFirstTime(true); + await repository.saveIsServerRebootedSecondTime(true); await repository.saveHasFinalChecked(true); await repository.saveIsRecoveringServer(false); final serverType = await ProvidersController.currentServerProvider! @@ -794,12 +801,9 @@ class ServerInstallationCubit extends Cubit { await repository.saveServerType(serverType.data!); await ProvidersController.currentServerProvider! .trySetServerLocation(serverType.data!.location.identifier); - final User mainUser = await repository.getMainUser(); - await repository.saveRootUser(mainUser); final ServerInstallationRecovery updatedState = (state as ServerInstallationRecovery).copyWith( backblazeCredential: backblazeCredential, - rootUser: mainUser, serverTypeIdentificator: serverType.data!.identifier, ); emit(updatedState.finish()); diff --git a/lib/logic/cubit/server_installation/server_installation_repository.dart b/lib/logic/cubit/server_installation/server_installation_repository.dart index 28f6bd2f..72ca5025 100644 --- a/lib/logic/cubit/server_installation/server_installation_repository.dart +++ b/lib/logic/cubit/server_installation/server_installation_repository.dart @@ -9,10 +9,15 @@ import 'package:selfprivacy/config/hive_config.dart'; import 'package:selfprivacy/logic/api_maps/graphql_maps/server_api/server_api.dart'; import 'package:selfprivacy/logic/api_maps/tls_options.dart'; import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart'; +import 'package:selfprivacy/logic/get_it/resources_model.dart'; import 'package:selfprivacy/logic/models/hive/backups_credential.dart'; +import 'package:selfprivacy/logic/models/hive/dns_provider_credential.dart'; +import 'package:selfprivacy/logic/models/hive/server.dart'; import 'package:selfprivacy/logic/models/hive/server_details.dart'; import 'package:selfprivacy/logic/models/hive/server_domain.dart'; +import 'package:selfprivacy/logic/models/hive/server_provider_credential.dart'; import 'package:selfprivacy/logic/models/hive/user.dart'; +import 'package:selfprivacy/logic/models/hive/wizards_data/server_installation_wizard_data.dart'; import 'package:selfprivacy/logic/models/json/device_token.dart'; import 'package:selfprivacy/logic/models/json/dns_records.dart'; import 'package:selfprivacy/logic/models/server_basic_info.dart'; @@ -36,19 +41,23 @@ class ServerInstallationRepository { Box box = Hive.box(BNames.serverInstallationBox); Future load() async { - final String? providerApiToken = getIt().serverProviderKey; - final String? location = getIt().serverLocation; - final String? dnsApiToken = getIt().dnsProviderKey; - final String? serverTypeIdentificator = getIt().serverType; - final ServerDomain? serverDomain = getIt().serverDomain; - final DnsProviderType? dnsProvider = getIt().dnsProvider; + final ServerInstallationWizardData? wizardData = + getIt().serverInstallation; + final List servers = getIt().servers; + final String? providerApiToken = getIt().serverProviderKey; + final String? location = getIt().serverLocation; + final String? dnsApiToken = getIt().dnsProviderKey; + final String? serverTypeIdentificator = getIt().serverType; + final ServerDomain? serverDomain = getIt().serverDomain; + final DnsProviderType? dnsProvider = getIt().dnsProvider; final ServerProviderType? serverProvider = - getIt().serverProvider; + getIt().serverProvider; final BackupsCredential? backblazeCredential = - getIt().backblazeCredential; + getIt().backblazeCredential; final ServerHostingDetails? serverDetails = - getIt().serverDetails; + getIt().serverDetails; + // TODO: Init server providers in another place if (serverProvider != null || (serverDetails != null && serverDetails.provider != ServerProviderType.unknown)) { @@ -72,85 +81,48 @@ class ServerInstallationRepository { ); } - if (box.get(BNames.hasFinalChecked, defaultValue: false)) { - TlsOptions.verifyCertificate = true; - if (serverTypeIdentificator == null && serverDetails != null) { - final finalServerType = await ProvidersController.currentServerProvider! - .getServerType(serverDetails.id); - await saveServerType(finalServerType.data!); - await ProvidersController.currentServerProvider! - .trySetServerLocation(finalServerType.data!.location.identifier); - return ServerInstallationFinished( - installationDialoguePopUp: null, - providerApiToken: providerApiToken!, - serverTypeIdentificator: finalServerType.data!.identifier, - dnsApiToken: dnsApiToken!, - serverDomain: serverDomain!, - backblazeCredential: backblazeCredential!, - serverDetails: serverDetails, - rootUser: box.get(BNames.rootUser), - isServerStarted: box.get(BNames.isServerStarted, defaultValue: false), - isServerResetedFirstTime: - box.get(BNames.isServerResetedFirstTime, defaultValue: false), - isServerResetedSecondTime: - box.get(BNames.isServerResetedSecondTime, defaultValue: false), + // If we don't have any wizard data, we either have a server set up, or we are starting from scratch + // This behaviour shall change when we introduce multitenancy + if (wizardData == null) { + if (servers.isEmpty) { + // We don't have anything set up, so we start from scratch + return ServerInstallationNotFinished.fromWizardData( + ServerInstallationWizardData.empty(), ); } else { + // We have a server set up, so we load it + TlsOptions.verifyCertificate = true; return ServerInstallationFinished( - installationDialoguePopUp: null, providerApiToken: providerApiToken!, serverTypeIdentificator: serverTypeIdentificator!, dnsApiToken: dnsApiToken!, serverDomain: serverDomain!, backblazeCredential: backblazeCredential!, serverDetails: serverDetails!, - rootUser: box.get(BNames.rootUser), - isServerStarted: box.get(BNames.isServerStarted, defaultValue: false), - isServerResetedFirstTime: - box.get(BNames.isServerResetedFirstTime, defaultValue: false), - isServerResetedSecondTime: - box.get(BNames.isServerResetedSecondTime, defaultValue: false), ); } } - if (box.get(BNames.isRecoveringServer, defaultValue: false) && - serverDomain != null) { + if (wizardData.isRecoveringServer && wizardData.serverDomain != null) { return ServerInstallationRecovery( - providerApiToken: providerApiToken, - dnsApiToken: dnsApiToken, - serverDomain: serverDomain, - serverTypeIdentificator: serverTypeIdentificator, - backblazeCredential: backblazeCredential, - serverDetails: serverDetails, - rootUser: box.get(BNames.rootUser), + providerApiToken: wizardData.serverProviderKey, + dnsApiToken: wizardData.dnsProviderKey, + serverDomain: wizardData.serverDomain, + serverTypeIdentificator: wizardData.serverTypeIdentifier, + backblazeCredential: wizardData.backupsCredential, + serverDetails: wizardData.serverDetails, currentStep: _getCurrentRecoveryStep( - providerApiToken, - dnsApiToken, - serverDomain, - serverDetails, + wizardData.serverProviderKey, + wizardData.dnsProviderKey, + wizardData.serverDomain!, + wizardData.serverDetails, ), - recoveryCapabilities: await getRecoveryCapabilities(serverDomain), + recoveryCapabilities: + await getRecoveryCapabilities(wizardData.serverDomain!), ); } - return ServerInstallationNotFinished( - providerApiToken: providerApiToken, - dnsApiToken: dnsApiToken, - serverDomain: serverDomain, - serverTypeIdentificator: serverTypeIdentificator, - backblazeCredential: backblazeCredential, - serverDetails: serverDetails, - rootUser: box.get(BNames.rootUser), - isServerStarted: box.get(BNames.isServerStarted, defaultValue: false), - isServerResetedFirstTime: - box.get(BNames.isServerResetedFirstTime, defaultValue: false), - isServerResetedSecondTime: - box.get(BNames.isServerResetedSecondTime, defaultValue: false), - isLoading: box.get(BNames.isLoading, defaultValue: false), - dnsMatches: null, - customSshKey: null, - ); + return ServerInstallationNotFinished.fromWizardData(wizardData); } RecoveryStep _getCurrentRecoveryStep( @@ -176,6 +148,9 @@ class ServerInstallationRepository { void clearAppConfig() { box.clear(); + getIt().clear(); + getIt().clear(); + getIt().clear(); } Future startServer( @@ -214,7 +189,12 @@ class ServerInstallationRepository { } Future createDkimRecord(final ServerDomain domain) async { - final ServerApi api = ServerApi(); + final ServerApi api = ServerApi( + overrideDomain: domain.domainName, + customToken: + getIt().serverInstallation!.serverDetails!.apiToken, + isWithToken: true, + ); late DnsRecord record; try { @@ -231,14 +211,26 @@ class ServerInstallationRepository { } Future isHttpServerWorking() async { - final ServerApi api = ServerApi(); + final ServerApi api = ServerApi( + overrideDomain: + getIt().serverInstallation!.serverDomain!.domainName, + customToken: + getIt().serverInstallation!.serverDetails!.apiToken, + isWithToken: true, + ); return api.isHttpServerWorking(); } Future restart() async { - final server = getIt().serverDetails!; + final server = getIt().serverDetails!; - final result = await ServerApi().reboot(); + final result = await ServerApi( + overrideDomain: + getIt().serverInstallation!.serverDomain!.domainName, + customToken: + getIt().serverInstallation!.serverDetails!.apiToken, + isWithToken: true, + ).reboot(); if (result.success && result.data != null) { server.copyWith(startTime: result.data); @@ -250,7 +242,7 @@ class ServerInstallationRepository { } Future powerOn() async { - final server = getIt().serverDetails!; + final server = getIt().serverDetails!; return startServer(server); } @@ -434,174 +426,117 @@ class ServerInstallationRepository { ); } - Future getMainUser() async { - final ServerApi serverApi = ServerApi(); - const User fallbackUser = User( - isFoundOnServer: false, - type: UserType.primary, - note: "Couldn't find main user on server, API is outdated", - login: 'UNKNOWN', - sshKeys: [], - ); - - final String? serverApiVersion = await serverApi.getApiVersion(); - final users = await serverApi.getAllUsers(); - if (serverApiVersion == null || users.isEmpty) { - return fallbackUser; - } - try { - final Version parsedVersion = Version.parse(serverApiVersion); - if (!VersionConstraint.parse('>=1.2.5').allows(parsedVersion)) { - return fallbackUser; - } - return users.firstWhere( - (final User user) => user.type == UserType.primary, - ); - } on FormatException { - return fallbackUser; - } - } - Future> getServersOnProviderAccount() async => (await ProvidersController.currentServerProvider!.getServers()).data; Future saveServerDetails( final ServerHostingDetails serverDetails, ) async { - await getIt().setServerDetails(serverDetails); + await getIt().setServerDetails(serverDetails); } Future deleteServerDetails() async { - await box.delete(BNames.serverDetails); - getIt().init(); + await getIt().deleteServerDetails(); } Future saveServerProviderType(final ServerProviderType type) async { - await getIt().storeServerProviderType(type); + await getIt().setServerProviderType(type); } Future saveDnsProviderType(final DnsProviderType type) async { - await getIt().setDnsProviderType(type); + await getIt().setDnsProviderType(type); } Future saveServerProviderKey(final String key) async { - await getIt().setServerProviderKey(key); + await getIt().setServerProviderKey(key); + await getIt().addServerProviderToken( + ServerProviderCredential( + tokenId: null, + token: key, + provider: + getIt().serverInstallation!.serverProviderType!, + associatedServerIds: [], + ), + ); } Future saveServerType(final ServerType serverType) async { - await getIt().setServerTypeIdentifier( + await getIt().setServerTypeIdentifier( serverType.identifier, ); - await getIt().setServerLocation( + await getIt().setServerLocation( serverType.location.identifier, ); } - Future deleteServerProviderKey() async { - await box.delete(BNames.hetznerKey); - getIt().init(); - } - - Future saveBackblazeKey( - final BackupsCredential backblazeCredential, + Future saveBackupsCredential( + final BackupsCredential backupsCredential, ) async { - await getIt().setBackblazeCredential(backblazeCredential); - } - - Future deleteBackblazeKey() async { - await box.delete(BNames.backblazeCredential); - getIt().init(); + await getIt().setBackupsCredential(backupsCredential); } Future setDnsApiToken(final String key) async { - await getIt().setDnsProviderKey(key); - } - - Future deleteDnsProviderKey() async { - await box.delete(BNames.cloudFlareKey); - getIt().init(); + await getIt().setDnsProviderKey(key); + await getIt().addDnsProviderToken( + DnsProviderCredential( + tokenId: null, + token: key, + provider: getIt().serverInstallation!.dnsProviderType!, + associatedDomainNames: [], + ), + ); } Future saveDomain(final ServerDomain serverDomain) async { - await getIt().setServerDomain(serverDomain); + await getIt().setServerDomain(serverDomain); } Future deleteDomain() async { - await box.delete(BNames.serverDomain); - getIt().init(); + await getIt().deleteServerDomain(); } Future saveIsServerStarted(final bool value) async { - await box.put(BNames.isServerStarted, value); + await getIt().setIsServerStarted(value); } - Future saveIsServerResetedFirstTime(final bool value) async { - await box.put(BNames.isServerResetedFirstTime, value); + Future saveIsServerRebootedFirstTime(final bool value) async { + await getIt().setIsServerRebootedFirstTime(value); } - Future saveIsServerResetedSecondTime(final bool value) async { - await box.put(BNames.isServerResetedSecondTime, value); + Future saveIsServerRebootedSecondTime(final bool value) async { + await getIt().setIsServerRebootedSecondTime(value); } Future saveRootUser(final User rootUser) async { - await box.put(BNames.rootUser, rootUser); + await getIt().setRootUser(rootUser); } Future saveIsRecoveringServer(final bool value) async { - await box.put(BNames.isRecoveringServer, value); + await getIt().setIsRecoveringServer(value); } Future saveHasFinalChecked(final bool value) async { - await box.put(BNames.hasFinalChecked, value); - } - - Future deleteServer(final ServerDomain serverDomain) async { - final ServerApi api = ServerApi(); - final dnsRecords = await api.getDnsRecords(); - final GenericResult removalResult = - await ProvidersController.currentDnsProvider!.removeDomainRecords( - domain: serverDomain, - records: dnsRecords, + // We are finished here. Time to save the state and finish the wizard + // TODO: A lot of null checks are skipped here. Implication that every value exists might become false in the future. + // TODO: We would actually want to handle token creation elsewhere. + final ServerInstallationWizardData wizardData = + getIt().serverInstallation!; + await getIt().addServer( + Server( + hostingDetails: wizardData.serverDetails!, + domain: wizardData.serverDomain!, + ), ); - - if (!removalResult.success) { - getIt().showSnackBar( - 'modals.dns_removal_error'.tr(), - ); - return false; - } - - final deletionResult = - await ProvidersController.currentServerProvider!.deleteServer( - serverDomain.domainName, + await getIt().associateServerWithToken( + wizardData.serverDetails!.id, + wizardData.serverProviderKey!, + ); + await getIt().associateDomainWithToken( + wizardData.serverDomain!.domainName, + wizardData.dnsProviderKey!, + ); + await getIt().addBackupsCredential( + wizardData.backupsCredential!, ); - - if (!deletionResult.success) { - getIt().showSnackBar( - 'modals.server_validators_error'.tr(), - ); - return false; - } - - await box.put(BNames.hasFinalChecked, false); - await box.put(BNames.isServerStarted, false); - await box.put(BNames.isServerResetedFirstTime, false); - await box.put(BNames.isServerResetedSecondTime, false); - await box.put(BNames.isLoading, false); - await box.put(BNames.serverDetails, null); - - return true; - } - - Future deleteServerRelatedRecords() async { - await box.deleteAll([ - BNames.serverDetails, - BNames.isServerStarted, - BNames.isServerResetedFirstTime, - BNames.isServerResetedSecondTime, - BNames.hasFinalChecked, - BNames.isLoading, - ]); - getIt().init(); } } diff --git a/lib/logic/cubit/server_installation/server_installation_state.dart b/lib/logic/cubit/server_installation/server_installation_state.dart index bf0981e2..5e15b9cb 100644 --- a/lib/logic/cubit/server_installation/server_installation_state.dart +++ b/lib/logic/cubit/server_installation/server_installation_state.dart @@ -146,6 +146,26 @@ class ServerInstallationNotFinished extends ServerInstallationState { super.serverDetails, super.installationDialoguePopUp, }); + + ServerInstallationNotFinished.fromWizardData( + final ServerInstallationWizardData data, + ) : this( + providerApiToken: data.serverProviderKey, + dnsApiToken: data.dnsProviderKey, + serverDomain: data.serverDomain, + serverTypeIdentificator: data.serverTypeIdentifier, + backblazeCredential: data.backupsCredential, + serverDetails: data.serverDetails, + rootUser: data.rootUser, + isServerStarted: data.isServerStarted, + isServerResetedFirstTime: data.isServerResetedFirstTime, + isServerResetedSecondTime: data.isServerResetedSecondTime, + isLoading: data.isLoading, + dnsMatches: null, + customSshKey: null, + installationDialoguePopUp: null, + ); + final bool isLoading; final Map? dnsMatches; final String? customSshKey; @@ -210,12 +230,7 @@ class ServerInstallationNotFinished extends ServerInstallationState { dnsApiToken: dnsApiToken!, backblazeCredential: backblazeCredential!, serverDomain: serverDomain!, - rootUser: rootUser!, serverDetails: serverDetails!, - isServerStarted: isServerStarted, - isServerResetedFirstTime: isServerResetedFirstTime, - isServerResetedSecondTime: isServerResetedSecondTime, - installationDialoguePopUp: installationDialoguePopUp, ); } @@ -246,13 +261,14 @@ class ServerInstallationFinished extends ServerInstallationState { required String super.dnsApiToken, required BackupsCredential super.backblazeCredential, required ServerDomain super.serverDomain, - required User super.rootUser, required ServerHostingDetails super.serverDetails, - required super.isServerStarted, - required super.isServerResetedFirstTime, - required super.isServerResetedSecondTime, - required super.installationDialoguePopUp, - }); + }) : super( + rootUser: null, + isServerStarted: true, + isServerResetedFirstTime: true, + isServerResetedSecondTime: true, + installationDialoguePopUp: null, + ); @override List get props => [ @@ -301,9 +317,9 @@ class ServerInstallationRecovery extends ServerInstallationState { super.dnsApiToken, super.backblazeCredential, super.serverDomain, - super.rootUser, super.serverDetails, }) : super( + rootUser: null, isServerStarted: true, isServerResetedFirstTime: true, isServerResetedSecondTime: true, @@ -333,7 +349,6 @@ class ServerInstallationRecovery extends ServerInstallationState { final String? dnsApiToken, final BackupsCredential? backblazeCredential, final ServerDomain? serverDomain, - final User? rootUser, final ServerHostingDetails? serverDetails, final RecoveryStep? currentStep, final ServerRecoveryCapabilities? recoveryCapabilities, @@ -345,7 +360,6 @@ class ServerInstallationRecovery extends ServerInstallationState { dnsApiToken: dnsApiToken ?? this.dnsApiToken, backblazeCredential: backblazeCredential ?? this.backblazeCredential, serverDomain: serverDomain ?? this.serverDomain, - rootUser: rootUser ?? this.rootUser, serverDetails: serverDetails ?? this.serverDetails, currentStep: currentStep ?? this.currentStep, recoveryCapabilities: recoveryCapabilities ?? this.recoveryCapabilities, @@ -357,11 +371,6 @@ class ServerInstallationRecovery extends ServerInstallationState { dnsApiToken: dnsApiToken!, backblazeCredential: backblazeCredential!, serverDomain: serverDomain!, - rootUser: rootUser!, serverDetails: serverDetails!, - isServerStarted: true, - isServerResetedFirstTime: true, - isServerResetedSecondTime: true, - installationDialoguePopUp: null, ); } diff --git a/lib/logic/get_it/api_config.dart b/lib/logic/get_it/api_config.dart index b32cd995..65310be9 100644 --- a/lib/logic/get_it/api_config.dart +++ b/lib/logic/get_it/api_config.dart @@ -1,117 +1,27 @@ import 'package:hive/hive.dart'; import 'package:selfprivacy/config/hive_config.dart'; import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart'; -import 'package:selfprivacy/logic/models/hive/backups_credential.dart'; -import 'package:selfprivacy/logic/models/hive/server_details.dart'; -import 'package:selfprivacy/logic/models/hive/server_domain.dart'; class ApiConfigModel { final Box _box = Hive.box(BNames.serverInstallationBox); - ServerHostingDetails? get serverDetails => _serverDetails; String? get localeCode => _localeCode; - String? get serverProviderKey => _serverProviderKey; - String? get serverLocation => _serverLocation; - String? get serverType => _serverType; - String? get dnsProviderKey => _dnsProviderKey; - ServerProviderType? get serverProvider => _serverProvider; - DnsProviderType? get dnsProvider => _dnsProvider; - - BackupsCredential? get backblazeCredential => _backblazeCredential; - ServerDomain? get serverDomain => _serverDomain; - BackblazeBucket? get backblazeBucket => _backblazeBucket; String? _localeCode; - String? _serverProviderKey; - String? _serverLocation; - String? _dnsProviderKey; - String? _serverType; - ServerProviderType? _serverProvider; - DnsProviderType? _dnsProvider; - ServerHostingDetails? _serverDetails; - BackupsCredential? _backblazeCredential; - ServerDomain? _serverDomain; - BackblazeBucket? _backblazeBucket; Future setLocaleCode(final String value) async { _localeCode = value; } - Future storeServerProviderType(final ServerProviderType value) async { - await _box.put(BNames.serverProvider, value); - _serverProvider = value; - } - - Future setDnsProviderType(final DnsProviderType value) async { - await _box.put(BNames.dnsProvider, value); - _dnsProvider = value; - } - - Future setServerProviderKey(final String value) async { - await _box.put(BNames.hetznerKey, value); - _serverProviderKey = value; - } - - Future setDnsProviderKey(final String value) async { - await _box.put(BNames.cloudFlareKey, value); - _dnsProviderKey = value; - } - - Future setServerTypeIdentifier(final String typeIdentifier) async { - await _box.put(BNames.serverTypeIdentifier, typeIdentifier); - _serverType = typeIdentifier; - } - - Future setServerLocation(final String serverLocation) async { - await _box.put(BNames.serverLocation, serverLocation); - _serverLocation = serverLocation; - } - - Future setBackblazeCredential(final BackupsCredential value) async { - await _box.put(BNames.backblazeCredential, value); - _backblazeCredential = value; - } - - Future setServerDomain(final ServerDomain value) async { - await _box.put(BNames.serverDomain, value); - _serverDomain = value; - } - - Future setServerDetails(final ServerHostingDetails value) async { - await _box.put(BNames.serverDetails, value); - _serverDetails = value; - } - Future setBackblazeBucket(final BackblazeBucket value) async { await _box.put(BNames.backblazeBucket, value); - _backblazeBucket = value; } void clear() { _localeCode = null; - _serverProviderKey = null; - _dnsProvider = null; - _serverLocation = null; - _dnsProviderKey = null; - _backblazeCredential = null; - _serverDomain = null; - _serverDetails = null; - _backblazeBucket = null; - _serverType = null; - _serverProvider = null; } void init() { _localeCode = 'en'; - _serverProviderKey = _box.get(BNames.hetznerKey); - _serverLocation = _box.get(BNames.serverLocation); - _dnsProviderKey = _box.get(BNames.cloudFlareKey); - _backblazeCredential = _box.get(BNames.backblazeCredential); - _serverDomain = _box.get(BNames.serverDomain); - _serverDetails = _box.get(BNames.serverDetails); - _backblazeBucket = _box.get(BNames.backblazeBucket); - _serverType = _box.get(BNames.serverTypeIdentifier); - _serverProvider = _box.get(BNames.serverProvider); - _dnsProvider = _box.get(BNames.dnsProvider); } } diff --git a/lib/logic/get_it/api_connection_repository.dart b/lib/logic/get_it/api_connection_repository.dart index b46c9e81..a849c8b9 100644 --- a/lib/logic/get_it/api_connection_repository.dart +++ b/lib/logic/get_it/api_connection_repository.dart @@ -6,6 +6,7 @@ import 'package:pub_semver/pub_semver.dart'; import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/config/hive_config.dart'; import 'package:selfprivacy/logic/api_maps/graphql_maps/server_api/server_api.dart'; +import 'package:selfprivacy/logic/get_it/resources_model.dart'; import 'package:selfprivacy/logic/models/auto_upgrade_settings.dart'; import 'package:selfprivacy/logic/models/backup.dart'; import 'package:selfprivacy/logic/models/hive/server_details.dart'; @@ -246,14 +247,12 @@ class ApiConnectionRepository { } ServerHostingDetails? get serverDetails => - getIt().serverDetails; - ServerDomain? get serverDomain => getIt().serverDomain; + getIt().serverDetails; + ServerDomain? get serverDomain => getIt().serverDomain; void init() async { - final serverDetails = getIt().serverDetails; - final hasFinalChecked = - box.get(BNames.hasFinalChecked, defaultValue: false); - if (serverDetails == null || !hasFinalChecked) { + final serverDetails = getIt().serverDetails; + if (serverDetails == null) { return; } connectionStatus = ConnectionStatus.reconnecting; @@ -281,6 +280,12 @@ class ApiConnectionRepository { ); } + void clear() async { + connectionStatus = ConnectionStatus.nonexistent; + _connectionStatusStream.add(connectionStatus); + _timer?.cancel(); + } + Future _refetchEverything(final Version version) async { await _apiData.serverJobs .refetchData(version, () => _dataStream.add(_apiData)); @@ -302,7 +307,7 @@ class ApiConnectionRepository { } Future reload(final Timer? timer) async { - final serverDetails = getIt().serverDetails; + final serverDetails = getIt().serverDetails; if (serverDetails == null) { return; } diff --git a/lib/logic/get_it/resources_model.dart b/lib/logic/get_it/resources_model.dart new file mode 100644 index 00000000..269f0fe8 --- /dev/null +++ b/lib/logic/get_it/resources_model.dart @@ -0,0 +1,309 @@ +import 'package:hive/hive.dart'; +import 'package:selfprivacy/config/hive_config.dart'; +import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart'; +import 'package:selfprivacy/logic/models/hive/backups_credential.dart'; +import 'package:selfprivacy/logic/models/hive/dns_provider_credential.dart'; +import 'package:selfprivacy/logic/models/hive/server.dart'; +import 'package:selfprivacy/logic/models/hive/server_details.dart'; +import 'package:selfprivacy/logic/models/hive/server_domain.dart'; +import 'package:selfprivacy/logic/models/hive/server_provider_credential.dart'; +import 'package:selfprivacy/logic/models/hive/user.dart'; +import 'package:selfprivacy/logic/models/hive/wizards_data/server_installation_wizard_data.dart'; + +class ResourcesModel { + final Box _box = Hive.box(BNames.resourcesBox); + + List get serverProviderCredentials => + _serverProviderTokens; + List get dnsProviderCredentials => _dnsProviderTokens; + List get backupsCredentials => _backupsCredentials; + List get servers => _servers; + BackblazeBucket? get backblazeBucket => _backblazeBucket; + + List _serverProviderTokens = []; + List _dnsProviderTokens = []; + List _backupsCredentials = []; + List _servers = []; + // TODO: As we will add support for other backup storages, we should + // refactor this. + BackblazeBucket? _backblazeBucket; + + @Deprecated('Compatibility getter') + ServerHostingDetails? get serverDetails => + _servers.firstOrNull?.hostingDetails; + @Deprecated('Compatibility getter') + String? get serverProviderKey => _serverProviderTokens.firstOrNull?.token; + @Deprecated('Compatibility getter') + String? get serverLocation => + _servers.firstOrNull?.hostingDetails.serverLocation; + @Deprecated('Compatibility getter') + String? get serverType => _servers.firstOrNull?.hostingDetails.serverType; + @Deprecated('Compatibility getter') + String? get dnsProviderKey => _dnsProviderTokens.firstOrNull?.token; + @Deprecated('Compatibility getter') + ServerProviderType? get serverProvider => + _serverProviderTokens.firstOrNull?.provider; + @Deprecated('Compatibility getter') + DnsProviderType? get dnsProvider => _dnsProviderTokens.firstOrNull?.provider; + @Deprecated('Compatibility getter') + BackupsCredential? get backblazeCredential => _backupsCredentials.firstOrNull; + @Deprecated('Compatibility getter') + ServerDomain? get serverDomain => _servers.firstOrNull?.domain; + + Future addServerProviderToken( + final ServerProviderCredential token, + ) async { + _serverProviderTokens.add(token); + await _box.put(BNames.serverProviderTokens, _serverProviderTokens); + } + + Future associateServerWithToken( + final int serverId, + final String token, + ) async { + _serverProviderTokens + .firstWhere( + (final credential) => credential.token == token, + ) + .associatedServerIds + .add(serverId); + await _box.put(BNames.serverProviderTokens, _serverProviderTokens); + } + + Future removeServerProviderToken( + final ServerProviderCredential token, + ) async { + _serverProviderTokens.remove(token); + await _box.put(BNames.serverProviderTokens, _serverProviderTokens); + } + + Future addDnsProviderToken(final DnsProviderCredential token) async { + _dnsProviderTokens.add(token); + await _box.put(BNames.dnsProviderTokens, _dnsProviderTokens); + } + + Future associateDomainWithToken( + final String domain, + final String token, + ) async { + _dnsProviderTokens + .firstWhere( + (final credential) => credential.token == token, + ) + .associatedDomainNames + .add(domain); + await _box.put(BNames.dnsProviderTokens, _dnsProviderTokens); + } + + Future removeDnsProviderToken(final DnsProviderCredential token) async { + _dnsProviderTokens.remove(token); + await _box.put(BNames.dnsProviderTokens, _dnsProviderTokens); + } + + Future addBackupsCredential(final BackupsCredential credential) async { + _backupsCredentials.add(credential); + await _box.put(BNames.backupsProviderTokens, _backupsCredentials); + } + + Future removeBackupsCredential( + final BackupsCredential credential, + ) async { + _backupsCredentials.remove(credential); + await _box.put(BNames.backupsProviderTokens, _backupsCredentials); + } + + Future addServer(final Server server) async { + _servers.add(server); + await _box.put(BNames.servers, _servers); + } + + Future removeServer(final Server server) async { + _servers.remove(server); + await _box.put(BNames.servers, _servers); + } + + Future setBackblazeBucket(final BackblazeBucket bucket) async { + _backblazeBucket = bucket; + await _box.put(BNames.backblazeBucket, _backblazeBucket); + } + + Future removeBackblazeBucket() async { + _backblazeBucket = null; + await _box.delete(BNames.backblazeBucket); + } + + void clear() { + _servers.clear(); + _serverProviderTokens.clear(); + _dnsProviderTokens.clear(); + _backupsCredentials.clear(); + _backblazeBucket = null; + + _box.clear(); + _box.compact(); + } + + void init() { + _serverProviderTokens = _box + .get( + BNames.serverProviderTokens, + defaultValue: [], + ) + .map( + (final e) => e as ServerProviderCredential, + ) + .toList(); + _dnsProviderTokens = _box + .get( + BNames.dnsProviderTokens, + defaultValue: [], + ) + .map((final e) => e as DnsProviderCredential) + .toList(); + _backupsCredentials = _box + .get( + BNames.backupsProviderTokens, + defaultValue: [], + ) + .map((final e) => e as BackupsCredential) + .toList(); + _servers = _box + .get( + BNames.servers, + defaultValue: [], + ) + .map((final e) => e as Server) + .toList(); + _backblazeBucket = _box.get(BNames.backblazeBucket); + } +} + +class WizardDataModel { + final Box _box = Hive.box(BNames.wizardDataBox); + + ServerInstallationWizardData? get serverInstallation => _serverInstallation; + + ServerInstallationWizardData? _serverInstallation; + + Future setServerProviderType(final ServerProviderType provider) async { + _serverInstallation = + (_serverInstallation ?? ServerInstallationWizardData.empty()) + .copyWith(serverProviderType: provider); + await _box.put(BNames.serverInstallationWizardData, _serverInstallation); + } + + Future setServerProviderKey(final String key) async { + _serverInstallation = + (_serverInstallation ?? ServerInstallationWizardData.empty()) + .copyWith(serverProviderKey: key); + await _box.put(BNames.serverInstallationWizardData, _serverInstallation); + } + + Future setDnsProviderType(final DnsProviderType provider) async { + _serverInstallation = + (_serverInstallation ?? ServerInstallationWizardData.empty()) + .copyWith(dnsProviderType: provider); + await _box.put(BNames.serverInstallationWizardData, _serverInstallation); + } + + Future setDnsProviderKey(final String key) async { + _serverInstallation = + (_serverInstallation ?? ServerInstallationWizardData.empty()) + .copyWith(dnsProviderKey: key); + await _box.put(BNames.serverInstallationWizardData, _serverInstallation); + } + + Future setServerTypeIdentifier(final String identifier) async { + _serverInstallation = + (_serverInstallation ?? ServerInstallationWizardData.empty()) + .copyWith(serverTypeIdentifier: identifier); + await _box.put(BNames.serverInstallationWizardData, _serverInstallation); + } + + Future setServerLocation(final String location) async { + _serverInstallation = + (_serverInstallation ?? ServerInstallationWizardData.empty()) + .copyWith(serverLocation: location); + await _box.put(BNames.serverInstallationWizardData, _serverInstallation); + } + + Future setServerDetails(final ServerHostingDetails details) async { + _serverInstallation = + (_serverInstallation ?? ServerInstallationWizardData.empty()) + .copyWith(serverDetails: () => details); + await _box.put(BNames.serverInstallationWizardData, _serverInstallation); + } + + Future deleteServerDetails() async { + _serverInstallation = + (_serverInstallation ?? ServerInstallationWizardData.empty()) + .copyWith(serverDetails: () => null); + await _box.put(BNames.serverInstallationWizardData, _serverInstallation); + } + + Future setBackupsCredential(final BackupsCredential credential) async { + _serverInstallation = + (_serverInstallation ?? ServerInstallationWizardData.empty()) + .copyWith(backupsCredential: credential); + await _box.put(BNames.serverInstallationWizardData, _serverInstallation); + } + + Future setServerDomain(final ServerDomain domain) async { + _serverInstallation = + (_serverInstallation ?? ServerInstallationWizardData.empty()) + .copyWith(serverDomain: () => domain); + await _box.put(BNames.serverInstallationWizardData, _serverInstallation); + } + + Future deleteServerDomain() async { + _serverInstallation = + (_serverInstallation ?? ServerInstallationWizardData.empty()) + .copyWith(serverDomain: () => null); + await _box.put(BNames.serverInstallationWizardData, _serverInstallation); + } + + Future setIsServerStarted(final bool isStarted) async { + _serverInstallation = + (_serverInstallation ?? ServerInstallationWizardData.empty()) + .copyWith(isServerStarted: isStarted); + await _box.put(BNames.serverInstallationWizardData, _serverInstallation); + } + + Future setIsServerRebootedFirstTime(final bool isRebooted) async { + _serverInstallation = + (_serverInstallation ?? ServerInstallationWizardData.empty()) + .copyWith(isServerResetedFirstTime: isRebooted); + await _box.put(BNames.serverInstallationWizardData, _serverInstallation); + } + + Future setIsServerRebootedSecondTime(final bool isRebooted) async { + _serverInstallation = + (_serverInstallation ?? ServerInstallationWizardData.empty()) + .copyWith(isServerResetedSecondTime: isRebooted); + await _box.put(BNames.serverInstallationWizardData, _serverInstallation); + } + + Future setRootUser(final User user) async { + _serverInstallation = + (_serverInstallation ?? ServerInstallationWizardData.empty()) + .copyWith(rootUser: user); + await _box.put(BNames.serverInstallationWizardData, _serverInstallation); + } + + Future setIsRecoveringServer(final bool isRecovering) async { + _serverInstallation = + (_serverInstallation ?? ServerInstallationWizardData.empty()) + .copyWith(isRecoveringServer: isRecovering); + await _box.put(BNames.serverInstallationWizardData, _serverInstallation); + } + + Future clear() async { + await _box.clear(); + await _box.compact(); + } + + void init() { + _serverInstallation = + _box.get(BNames.serverInstallationWizardData, defaultValue: null); + } +} diff --git a/lib/logic/models/hive/README.md b/lib/logic/models/hive/README.md index d50da34c..1183db87 100644 --- a/lib/logic/models/hive/README.md +++ b/lib/logic/models/hive/README.md @@ -3,13 +3,19 @@ 1. User 2. ServerHostingDetails 3. ServerDomain -4. BackblazeCredential -5. ServerVolume +4. BackupsCredential +5. ServerProviderVolume 6. BackblazeBucket +7. ServerProviderCredential +8. DnsProviderCredential +9. Server + +## Wizards store +60. ServerInstallationWizardData ## Enums 100. DnsProvider 101. ServerProvider 102. UserType -103. BackupsProvider +103. BackupsProviderType diff --git a/lib/logic/models/hive/backups_credential.dart b/lib/logic/models/hive/backups_credential.dart index 0c0cf48d..b091a1a1 100644 --- a/lib/logic/models/hive/backups_credential.dart +++ b/lib/logic/models/hive/backups_credential.dart @@ -5,6 +5,7 @@ import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/schema.graphql.da part 'backups_credential.g.dart'; +// TODO: Make a constant type. @HiveType(typeId: 4) class BackupsCredential { BackupsCredential({ diff --git a/lib/logic/models/hive/dns_provider_credential.dart b/lib/logic/models/hive/dns_provider_credential.dart new file mode 100644 index 00000000..709559aa --- /dev/null +++ b/lib/logic/models/hive/dns_provider_credential.dart @@ -0,0 +1,27 @@ +import 'package:hive/hive.dart'; +import 'package:selfprivacy/logic/models/hive/server_domain.dart'; + +part 'dns_provider_credential.g.dart'; + +// TODO: Make a constant type. +@HiveType(typeId: 8) +class DnsProviderCredential { + DnsProviderCredential({ + required this.tokenId, + required this.token, + required this.provider, + required this.associatedDomainNames, + }); + + @HiveField(0) + final String? tokenId; + + @HiveField(1) + final String token; + + @HiveField(2) + final DnsProviderType provider; + + @HiveField(3) + final List associatedDomainNames; +} diff --git a/lib/logic/models/hive/dns_provider_credential.g.dart b/lib/logic/models/hive/dns_provider_credential.g.dart new file mode 100644 index 00000000..e78d2237 --- /dev/null +++ b/lib/logic/models/hive/dns_provider_credential.g.dart @@ -0,0 +1,50 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'dns_provider_credential.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class DnsProviderCredentialAdapter extends TypeAdapter { + @override + final int typeId = 8; + + @override + DnsProviderCredential read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return DnsProviderCredential( + tokenId: fields[0] as String?, + token: fields[1] as String, + provider: fields[2] as DnsProviderType, + associatedDomainNames: (fields[3] as List).cast(), + ); + } + + @override + void write(BinaryWriter writer, DnsProviderCredential obj) { + writer + ..writeByte(4) + ..writeByte(0) + ..write(obj.tokenId) + ..writeByte(1) + ..write(obj.token) + ..writeByte(2) + ..write(obj.provider) + ..writeByte(3) + ..write(obj.associatedDomainNames); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is DnsProviderCredentialAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} diff --git a/lib/logic/models/hive/server.dart b/lib/logic/models/hive/server.dart new file mode 100644 index 00000000..90712aaf --- /dev/null +++ b/lib/logic/models/hive/server.dart @@ -0,0 +1,20 @@ +import 'package:hive/hive.dart'; +import 'package:selfprivacy/logic/models/hive/server_details.dart'; +import 'package:selfprivacy/logic/models/hive/server_domain.dart'; + +part 'server.g.dart'; + +// TODO: Make a constant type. +@HiveType(typeId: 9) +class Server { + Server({ + required this.hostingDetails, + required this.domain, + }); + + @HiveField(0) + final ServerHostingDetails hostingDetails; + + @HiveField(1) + final ServerDomain domain; +} diff --git a/lib/logic/models/hive/server.g.dart b/lib/logic/models/hive/server.g.dart new file mode 100644 index 00000000..ba83e895 --- /dev/null +++ b/lib/logic/models/hive/server.g.dart @@ -0,0 +1,44 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'server.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class ServerAdapter extends TypeAdapter { + @override + final int typeId = 9; + + @override + Server read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return Server( + hostingDetails: fields[0] as ServerHostingDetails, + domain: fields[1] as ServerDomain, + ); + } + + @override + void write(BinaryWriter writer, Server obj) { + writer + ..writeByte(2) + ..writeByte(0) + ..write(obj.hostingDetails) + ..writeByte(1) + ..write(obj.domain); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is ServerAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} diff --git a/lib/logic/models/hive/server_details.dart b/lib/logic/models/hive/server_details.dart index c19be012..6624a512 100644 --- a/lib/logic/models/hive/server_details.dart +++ b/lib/logic/models/hive/server_details.dart @@ -12,6 +12,8 @@ class ServerHostingDetails { required this.volume, required this.apiToken, required this.provider, + this.serverLocation, + this.serverType, this.startTime, }); @@ -21,12 +23,13 @@ class ServerHostingDetails { @HiveField(1) final int id; - @HiveField(3) - final DateTime? createTime; - + // TODO: Check if it is still needed @HiveField(2) final DateTime? startTime; + @HiveField(3) + final DateTime? createTime; + // TODO: Check if it is still needed @HiveField(4) final ServerProviderVolume volume; @@ -37,9 +40,21 @@ class ServerHostingDetails { @HiveField(6, defaultValue: ServerProviderType.hetzner) final ServerProviderType provider; - ServerHostingDetails copyWith({final DateTime? startTime}) => + @HiveField(7) + final String? serverLocation; + + @HiveField(8) + final String? serverType; + + ServerHostingDetails copyWith({ + final DateTime? startTime, + final String? serverLocation, + final String? serverType, + }) => ServerHostingDetails( startTime: startTime ?? this.startTime, + serverLocation: serverLocation ?? this.serverLocation, + serverType: serverType ?? this.serverType, createTime: createTime, id: id, ip4: ip4, diff --git a/lib/logic/models/hive/server_details.g.dart b/lib/logic/models/hive/server_details.g.dart index 491344b9..1ace42fc 100644 --- a/lib/logic/models/hive/server_details.g.dart +++ b/lib/logic/models/hive/server_details.g.dart @@ -25,6 +25,8 @@ class ServerHostingDetailsAdapter extends TypeAdapter { provider: fields[6] == null ? ServerProviderType.hetzner : fields[6] as ServerProviderType, + serverLocation: fields[7] as String?, + serverType: fields[8] as String?, startTime: fields[2] as DateTime?, ); } @@ -32,21 +34,25 @@ class ServerHostingDetailsAdapter extends TypeAdapter { @override void write(BinaryWriter writer, ServerHostingDetails obj) { writer - ..writeByte(7) + ..writeByte(9) ..writeByte(0) ..write(obj.ip4) ..writeByte(1) ..write(obj.id) - ..writeByte(3) - ..write(obj.createTime) ..writeByte(2) ..write(obj.startTime) + ..writeByte(3) + ..write(obj.createTime) ..writeByte(4) ..write(obj.volume) ..writeByte(5) ..write(obj.apiToken) ..writeByte(6) - ..write(obj.provider); + ..write(obj.provider) + ..writeByte(7) + ..write(obj.serverLocation) + ..writeByte(8) + ..write(obj.serverType); } @override diff --git a/lib/logic/models/hive/server_provider_credential.dart b/lib/logic/models/hive/server_provider_credential.dart new file mode 100644 index 00000000..995739e0 --- /dev/null +++ b/lib/logic/models/hive/server_provider_credential.dart @@ -0,0 +1,27 @@ +import 'package:hive/hive.dart'; +import 'package:selfprivacy/logic/models/hive/server_details.dart'; + +part 'server_provider_credential.g.dart'; + +// TODO: Make a constant type. +@HiveType(typeId: 7) +class ServerProviderCredential { + ServerProviderCredential({ + required this.tokenId, + required this.token, + required this.provider, + required this.associatedServerIds, + }); + + @HiveField(0) + final String? tokenId; + + @HiveField(1) + final String token; + + @HiveField(2) + final ServerProviderType provider; + + @HiveField(3) + final List associatedServerIds; +} diff --git a/lib/logic/models/hive/server_provider_credential.g.dart b/lib/logic/models/hive/server_provider_credential.g.dart new file mode 100644 index 00000000..00beb2ee --- /dev/null +++ b/lib/logic/models/hive/server_provider_credential.g.dart @@ -0,0 +1,51 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'server_provider_credential.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class ServerProviderCredentialAdapter + extends TypeAdapter { + @override + final int typeId = 7; + + @override + ServerProviderCredential read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return ServerProviderCredential( + tokenId: fields[0] as String?, + token: fields[1] as String, + provider: fields[2] as ServerProviderType, + associatedServerIds: (fields[3] as List).cast(), + ); + } + + @override + void write(BinaryWriter writer, ServerProviderCredential obj) { + writer + ..writeByte(4) + ..writeByte(0) + ..write(obj.tokenId) + ..writeByte(1) + ..write(obj.token) + ..writeByte(2) + ..write(obj.provider) + ..writeByte(3) + ..write(obj.associatedServerIds); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is ServerProviderCredentialAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} diff --git a/lib/logic/models/hive/wizards_data/server_installation_wizard_data.dart b/lib/logic/models/hive/wizards_data/server_installation_wizard_data.dart new file mode 100644 index 00000000..ccbae528 --- /dev/null +++ b/lib/logic/models/hive/wizards_data/server_installation_wizard_data.dart @@ -0,0 +1,130 @@ +import 'package:flutter/cupertino.dart'; +import 'package:hive/hive.dart'; +import 'package:selfprivacy/logic/models/hive/backups_credential.dart'; +import 'package:selfprivacy/logic/models/hive/server_details.dart'; +import 'package:selfprivacy/logic/models/hive/server_domain.dart'; +import 'package:selfprivacy/logic/models/hive/user.dart'; + +part 'server_installation_wizard_data.g.dart'; + +@HiveType(typeId: 60) +class ServerInstallationWizardData { + const ServerInstallationWizardData({ + required this.hasFinalChecked, + required this.isServerStarted, + required this.isServerResetedFirstTime, + required this.isServerResetedSecondTime, + required this.isLoading, + required this.isRecoveringServer, + required this.rootUser, + required this.serverProviderType, + required this.serverProviderKey, + required this.dnsProviderType, + required this.dnsProviderKey, + required this.backupsCredential, + required this.serverTypeIdentifier, + required this.serverLocation, + required this.serverDetails, + required this.serverDomain, + }); + + ServerInstallationWizardData.empty() + : this( + hasFinalChecked: false, + isServerStarted: false, + isServerResetedFirstTime: false, + isServerResetedSecondTime: false, + isLoading: false, + isRecoveringServer: false, + rootUser: null, + serverProviderType: null, + serverProviderKey: null, + dnsProviderType: null, + dnsProviderKey: null, + backupsCredential: null, + serverTypeIdentifier: null, + serverLocation: null, + serverDetails: null, + serverDomain: null, + ); + + // Bool flags used by installer + @HiveField(0) + final bool hasFinalChecked; + @HiveField(1) + final bool isServerStarted; + @HiveField(2) + final bool isServerResetedFirstTime; + @HiveField(3) + final bool isServerResetedSecondTime; + @HiveField(4) + final bool isLoading; + + @HiveField(5) + final bool isRecoveringServer; + + @HiveField(6) + final User? rootUser; + + @HiveField(7) + final ServerProviderType? serverProviderType; + @HiveField(8) + final String? serverProviderKey; + + @HiveField(9) + final DnsProviderType? dnsProviderType; + @HiveField(10) + final String? dnsProviderKey; + + @HiveField(11) + final BackupsCredential? backupsCredential; + + @HiveField(12) + final String? serverTypeIdentifier; + @HiveField(13) + final String? serverLocation; + @HiveField(14) + final ServerHostingDetails? serverDetails; + @HiveField(15) + final ServerDomain? serverDomain; + + ServerInstallationWizardData copyWith({ + final bool? hasFinalChecked, + final bool? isServerStarted, + final bool? isServerResetedFirstTime, + final bool? isServerResetedSecondTime, + final bool? isLoading, + final bool? isRecoveringServer, + final User? rootUser, + final ServerProviderType? serverProviderType, + final String? serverProviderKey, + final DnsProviderType? dnsProviderType, + final String? dnsProviderKey, + final BackupsCredential? backupsCredential, + final String? serverTypeIdentifier, + final String? serverLocation, + final ValueGetter? serverDetails, + final ValueGetter? serverDomain, + }) => + ServerInstallationWizardData( + hasFinalChecked: hasFinalChecked ?? this.hasFinalChecked, + isServerStarted: isServerStarted ?? this.isServerStarted, + isServerResetedFirstTime: + isServerResetedFirstTime ?? this.isServerResetedFirstTime, + isServerResetedSecondTime: + isServerResetedSecondTime ?? this.isServerResetedSecondTime, + isLoading: isLoading ?? this.isLoading, + isRecoveringServer: isRecoveringServer ?? this.isRecoveringServer, + rootUser: rootUser ?? this.rootUser, + serverProviderType: serverProviderType ?? this.serverProviderType, + serverProviderKey: serverProviderKey ?? this.serverProviderKey, + dnsProviderType: dnsProviderType ?? this.dnsProviderType, + dnsProviderKey: dnsProviderKey ?? this.dnsProviderKey, + backupsCredential: backupsCredential ?? this.backupsCredential, + serverTypeIdentifier: serverTypeIdentifier ?? this.serverTypeIdentifier, + serverLocation: serverLocation ?? this.serverLocation, + serverDetails: + serverDetails != null ? serverDetails() : this.serverDetails, + serverDomain: serverDomain != null ? serverDomain() : this.serverDomain, + ); +} diff --git a/lib/logic/models/hive/wizards_data/server_installation_wizard_data.g.dart b/lib/logic/models/hive/wizards_data/server_installation_wizard_data.g.dart new file mode 100644 index 00000000..cad2a199 --- /dev/null +++ b/lib/logic/models/hive/wizards_data/server_installation_wizard_data.g.dart @@ -0,0 +1,87 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'server_installation_wizard_data.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class ServerInstallationWizardDataAdapter + extends TypeAdapter { + @override + final int typeId = 60; + + @override + ServerInstallationWizardData read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return ServerInstallationWizardData( + hasFinalChecked: fields[0] as bool, + isServerStarted: fields[1] as bool, + isServerResetedFirstTime: fields[2] as bool, + isServerResetedSecondTime: fields[3] as bool, + isLoading: fields[4] as bool, + isRecoveringServer: fields[5] as bool, + rootUser: fields[6] as User?, + serverProviderType: fields[7] as ServerProviderType?, + serverProviderKey: fields[8] as String?, + dnsProviderType: fields[9] as DnsProviderType?, + dnsProviderKey: fields[10] as String?, + backupsCredential: fields[11] as BackupsCredential?, + serverTypeIdentifier: fields[12] as String?, + serverLocation: fields[13] as String?, + serverDetails: fields[14] as ServerHostingDetails?, + serverDomain: fields[15] as ServerDomain?, + ); + } + + @override + void write(BinaryWriter writer, ServerInstallationWizardData obj) { + writer + ..writeByte(16) + ..writeByte(0) + ..write(obj.hasFinalChecked) + ..writeByte(1) + ..write(obj.isServerStarted) + ..writeByte(2) + ..write(obj.isServerResetedFirstTime) + ..writeByte(3) + ..write(obj.isServerResetedSecondTime) + ..writeByte(4) + ..write(obj.isLoading) + ..writeByte(5) + ..write(obj.isRecoveringServer) + ..writeByte(6) + ..write(obj.rootUser) + ..writeByte(7) + ..write(obj.serverProviderType) + ..writeByte(8) + ..write(obj.serverProviderKey) + ..writeByte(9) + ..write(obj.dnsProviderType) + ..writeByte(10) + ..write(obj.dnsProviderKey) + ..writeByte(11) + ..write(obj.backupsCredential) + ..writeByte(12) + ..write(obj.serverTypeIdentifier) + ..writeByte(13) + ..write(obj.serverLocation) + ..writeByte(14) + ..write(obj.serverDetails) + ..writeByte(15) + ..write(obj.serverDomain); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is ServerInstallationWizardDataAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} diff --git a/lib/ui/pages/dns_details/dns_details.dart b/lib/ui/pages/dns_details/dns_details.dart index 02626f9c..04640732 100644 --- a/lib/ui/pages/dns_details/dns_details.dart +++ b/lib/ui/pages/dns_details/dns_details.dart @@ -5,6 +5,7 @@ import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/desired_dns_record.dart'; import 'package:selfprivacy/logic/cubit/dns_records/dns_records_cubit.dart'; import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart'; +import 'package:selfprivacy/logic/get_it/resources_model.dart'; import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart'; import 'package:selfprivacy/ui/components/cards/filled_card.dart'; import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart'; @@ -86,7 +87,7 @@ class _DnsDetailsPageState extends State { final bool isReady = context.watch().state is ServerInstallationFinished; final String domain = - getIt().serverDomain?.domainName ?? ''; + getIt().serverDomain?.domainName ?? ''; final DnsRecordsState dnsCubit = context.watch().state; print(dnsCubit.dnsState); From e9f13c547112eb763f01102d9220cbd3fd736731 Mon Sep 17 00:00:00 2001 From: Inex Code Date: Wed, 15 May 2024 17:58:24 +0300 Subject: [PATCH 04/11] fix: Server couldn't install due to a faulty null check --- .../server_installation/server_installation_repository.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/logic/cubit/server_installation/server_installation_repository.dart b/lib/logic/cubit/server_installation/server_installation_repository.dart index 72ca5025..d2a23426 100644 --- a/lib/logic/cubit/server_installation/server_installation_repository.dart +++ b/lib/logic/cubit/server_installation/server_installation_repository.dart @@ -222,7 +222,7 @@ class ServerInstallationRepository { } Future restart() async { - final server = getIt().serverDetails!; + final server = getIt().serverInstallation!.serverDetails!; final result = await ServerApi( overrideDomain: From 9e56afba50747693443d789a3f667583c1037d96 Mon Sep 17 00:00:00 2001 From: Inex Code Date: Wed, 15 May 2024 19:23:39 +0300 Subject: [PATCH 05/11] fix: Clear serverInstallationWizardData after the wizard is finished --- .../server_installation/server_installation_repository.dart | 1 + lib/logic/get_it/resources_model.dart | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/lib/logic/cubit/server_installation/server_installation_repository.dart b/lib/logic/cubit/server_installation/server_installation_repository.dart index d2a23426..57b47c81 100644 --- a/lib/logic/cubit/server_installation/server_installation_repository.dart +++ b/lib/logic/cubit/server_installation/server_installation_repository.dart @@ -538,5 +538,6 @@ class ServerInstallationRepository { await getIt().addBackupsCredential( wizardData.backupsCredential!, ); + await getIt().clearServerInstallation(); } } diff --git a/lib/logic/get_it/resources_model.dart b/lib/logic/get_it/resources_model.dart index 269f0fe8..ebde7870 100644 --- a/lib/logic/get_it/resources_model.dart +++ b/lib/logic/get_it/resources_model.dart @@ -297,6 +297,11 @@ class WizardDataModel { await _box.put(BNames.serverInstallationWizardData, _serverInstallation); } + Future clearServerInstallation() async { + _serverInstallation = null; + await _box.delete(BNames.serverInstallationWizardData); + } + Future clear() async { await _box.clear(); await _box.compact(); From 78b026ed42f37548eede3e19521a940eec0af0e1 Mon Sep 17 00:00:00 2001 From: Inex Code Date: Tue, 25 Jun 2024 18:06:50 +0300 Subject: [PATCH 06/11] chore: Post-merge cleanup --- lib/config/get_it_config.dart | 1 - lib/config/hive_config.dart | 36 ++++++++++--------- lib/logic/get_it/api_config.dart | 10 ------ .../flutter/generated_plugin_registrant.cc | 3 ++ windows/flutter/generated_plugins.cmake | 1 + 5 files changed, 23 insertions(+), 28 deletions(-) diff --git a/lib/config/get_it_config.dart b/lib/config/get_it_config.dart index 5732346d..d570e005 100644 --- a/lib/config/get_it_config.dart +++ b/lib/config/get_it_config.dart @@ -19,7 +19,6 @@ Future getItSetup() async { getIt.registerSingleton(WizardDataModel()..init()); final apiConfigModel = ApiConfigModel(); - await apiConfigModel.init(); getIt.registerSingleton(apiConfigModel); getIt.registerSingleton( diff --git a/lib/config/hive_config.dart b/lib/config/hive_config.dart index c6337ecb..261c6450 100644 --- a/lib/config/hive_config.dart +++ b/lib/config/hive_config.dart @@ -41,45 +41,48 @@ class HiveConfig { await getEncryptedKey(BNames.serverInstallationEncryptionKey), ); - await Hive.openBox(BNames.serverInstallationBox, encryptionCipher: cipher); + await Hive.openBox(BNames.serverInstallationBox, + encryptionCipher: cipher); await Hive.openBox(BNames.resourcesBox, encryptionCipher: cipher); await Hive.openBox(BNames.wizardDataBox, encryptionCipher: cipher); final Box resourcesBox = Hive.box(BNames.resourcesBox); if (resourcesBox.isEmpty) { - final Box serverInstallationBox = Hive.box(BNames.serverInstallationBox); + final Box serverInstallationBox = + Hive.box(BNames.serverInstallationBox); final String? serverProviderKey = - serverInstallationBox.get(BNames.hetznerKey); + serverInstallationBox.get(BNames.hetznerKey); final String? serverLocation = - serverInstallationBox.get(BNames.serverLocation); + serverInstallationBox.get(BNames.serverLocation); final String? dnsProviderKey = - serverInstallationBox.get(BNames.cloudFlareKey); + serverInstallationBox.get(BNames.cloudFlareKey); final BackupsCredential? backblazeCredential = - serverInstallationBox.get(BNames.backblazeCredential); + serverInstallationBox.get(BNames.backblazeCredential); final ServerDomain? serverDomain = - serverInstallationBox.get(BNames.serverDomain); + serverInstallationBox.get(BNames.serverDomain); final ServerHostingDetails? serverDetails = - serverInstallationBox.get(BNames.serverDetails); + serverInstallationBox.get(BNames.serverDetails); final BackblazeBucket? backblazeBucket = - serverInstallationBox.get(BNames.backblazeBucket); + serverInstallationBox.get(BNames.backblazeBucket); final String? serverType = - serverInstallationBox.get(BNames.serverTypeIdentifier); + serverInstallationBox.get(BNames.serverTypeIdentifier); final ServerProviderType? serverProvider = - serverInstallationBox.get(BNames.serverProvider); + serverInstallationBox.get(BNames.serverProvider); final DnsProviderType? dnsProvider = - serverInstallationBox.get(BNames.dnsProvider); + serverInstallationBox.get(BNames.dnsProvider); if (serverProviderKey != null && (serverProvider != null || (serverDetails != null && serverDetails.provider != ServerProviderType.unknown))) { final ServerProviderCredential serverProviderCredential = - ServerProviderCredential( + ServerProviderCredential( tokenId: null, token: serverProviderKey, provider: serverProvider ?? serverDetails!.provider, - associatedServerIds: serverDetails != null ? [serverDetails.id] : [], + associatedServerIds: + serverDetails != null ? [serverDetails.id] : [], ); await resourcesBox @@ -91,12 +94,12 @@ class HiveConfig { (serverDomain != null && serverDomain.provider != DnsProviderType.unknown))) { final DnsProviderCredential dnsProviderCredential = - DnsProviderCredential( + DnsProviderCredential( tokenId: null, token: dnsProviderKey, provider: dnsProvider ?? serverDomain!.provider, associatedDomainNames: - serverDomain != null ? [serverDomain.domainName] : [], + serverDomain != null ? [serverDomain.domainName] : [], ); await resourcesBox @@ -128,7 +131,6 @@ class HiveConfig { print('HiveConfig: Error while opening boxes: $e'); rethrow; } - } static Future getEncryptedKey(final String encKey) async { diff --git a/lib/logic/get_it/api_config.dart b/lib/logic/get_it/api_config.dart index 43271204..65c64a3e 100644 --- a/lib/logic/get_it/api_config.dart +++ b/lib/logic/get_it/api_config.dart @@ -5,8 +5,6 @@ import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart'; class ApiConfigModel { final Box _box = Hive.box(BNames.serverInstallationBox); - String? get localeCode => _localeCode; - static const localeCodeFallback = 'en'; String? _localeCode; @@ -17,12 +15,4 @@ class ApiConfigModel { Future setBackblazeBucket(final BackblazeBucket value) async { await _box.put(BNames.backblazeBucket, value); } - - // TODO: Remove it - void clear() { - } - - // TODO: Remove it - void init() { - } } diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index a01f420e..4ff4b899 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include void RegisterPlugins(flutter::PluginRegistry* registry) { @@ -18,6 +19,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("DynamicColorPluginCApi")); FlutterSecureStorageWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); + LocalAuthPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("LocalAuthPlugin")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 258f1683..ae5ef358 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST connectivity_plus dynamic_color flutter_secure_storage_windows + local_auth_windows url_launcher_windows ) From 85bc997776e46d59ed4500b2a7b882e884912642 Mon Sep 17 00:00:00 2001 From: Aliaksei Tratseuski Date: Wed, 26 Jun 2024 01:54:56 +0400 Subject: [PATCH 07/11] feat: db versioning and better logging --- .vscode/launch.json | 4 +- lib/config/config.dart | 18 + lib/config/hive_config.dart | 316 +++++++++++------- .../api_maps/rest_maps/rest_api_map.dart | 19 +- lib/utils/app_logger.dart | 26 ++ lib/utils/secure_storage.dart | 48 +++ 6 files changed, 293 insertions(+), 138 deletions(-) create mode 100644 lib/config/config.dart create mode 100644 lib/utils/app_logger.dart create mode 100644 lib/utils/secure_storage.dart diff --git a/.vscode/launch.json b/.vscode/launch.json index 2b83ac77..aea512cb 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -31,7 +31,7 @@ ] }, { - "name": "debug (production)", + "name": "debug (production flavor)", "request": "launch", "type": "dart", "args": [ @@ -41,7 +41,7 @@ }, { - "name": "debug (nightly)", + "name": "debug (nightly flavor)", "request": "launch", "type": "dart", "args": [ diff --git a/lib/config/config.dart b/lib/config/config.dart new file mode 100644 index 00000000..0b76d915 --- /dev/null +++ b/lib/config/config.dart @@ -0,0 +1,18 @@ +import 'package:flutter/foundation.dart'; + +/// internal app configuration +const config = InternalConfig( + shouldDebugPrint: kDebugMode, +); + +class InternalConfig { + const InternalConfig({ + required this.shouldDebugPrint, + }); + + final bool shouldDebugPrint; + + // example of other possible fields + // final String appVersion; + // +} diff --git a/lib/config/hive_config.dart b/lib/config/hive_config.dart index 261c6450..28b51de9 100644 --- a/lib/config/hive_config.dart +++ b/lib/config/hive_config.dart @@ -1,7 +1,3 @@ -import 'dart:convert'; - -import 'package:flutter/services.dart'; -import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart'; import 'package:selfprivacy/logic/models/hive/backups_credential.dart'; @@ -12,144 +8,210 @@ import 'package:selfprivacy/logic/models/hive/server_domain.dart'; import 'package:selfprivacy/logic/models/hive/server_provider_credential.dart'; import 'package:selfprivacy/logic/models/hive/user.dart'; import 'package:selfprivacy/logic/models/hive/wizards_data/server_installation_wizard_data.dart'; +import 'package:selfprivacy/utils/app_logger.dart'; import 'package:selfprivacy/utils/platform_adapter.dart'; +import 'package:selfprivacy/utils/secure_storage.dart'; class HiveConfig { + static final log = const AppLogger(name: 'hive_config').log; + + /// bump on schema changes + static const version = 2; + static Future init() async { final String? storagePath = PlatformAdapter.storagePath; - print('HiveConfig: Custom storage path: $storagePath'); + log('set custom storage path to: "$storagePath"'); + await Hive.initFlutter(storagePath); - Hive.registerAdapter(UserAdapter()); - Hive.registerAdapter(ServerHostingDetailsAdapter()); - Hive.registerAdapter(ServerDomainAdapter()); - Hive.registerAdapter(BackupsCredentialAdapter()); - Hive.registerAdapter(ServerProviderVolumeAdapter()); - Hive.registerAdapter(BackblazeBucketAdapter()); - Hive.registerAdapter(ServerProviderCredentialAdapter()); - Hive.registerAdapter(DnsProviderCredentialAdapter()); - Hive.registerAdapter(ServerAdapter()); - Hive.registerAdapter(DnsProviderTypeAdapter()); - Hive.registerAdapter(ServerProviderTypeAdapter()); - Hive.registerAdapter(UserTypeAdapter()); - Hive.registerAdapter(BackupsProviderTypeAdapter()); - Hive.registerAdapter(ServerInstallationWizardDataAdapter()); - await Hive.openBox(BNames.appSettingsBox); + registerAdapters(); + await decryptBoxes(); + await performMigrations(); + } + static void registerAdapters() { try { - final HiveAesCipher cipher = HiveAesCipher( - await getEncryptedKey(BNames.serverInstallationEncryptionKey), + Hive.registerAdapter(UserAdapter()); + Hive.registerAdapter(ServerHostingDetailsAdapter()); + Hive.registerAdapter(ServerDomainAdapter()); + Hive.registerAdapter(BackupsCredentialAdapter()); + Hive.registerAdapter(ServerProviderVolumeAdapter()); + Hive.registerAdapter(BackblazeBucketAdapter()); + Hive.registerAdapter(ServerProviderCredentialAdapter()); + Hive.registerAdapter(DnsProviderCredentialAdapter()); + Hive.registerAdapter(ServerAdapter()); + Hive.registerAdapter(DnsProviderTypeAdapter()); + Hive.registerAdapter(ServerProviderTypeAdapter()); + Hive.registerAdapter(UserTypeAdapter()); + Hive.registerAdapter(BackupsProviderTypeAdapter()); + Hive.registerAdapter(ServerInstallationWizardDataAdapter()); + log('successfully registered every adapter'); + } catch (error, stackTrace) { + log( + 'error registering adapters', + error: error, + stackTrace: stackTrace, ); - - await Hive.openBox(BNames.serverInstallationBox, - encryptionCipher: cipher); - await Hive.openBox(BNames.resourcesBox, encryptionCipher: cipher); - await Hive.openBox(BNames.wizardDataBox, encryptionCipher: cipher); - - final Box resourcesBox = Hive.box(BNames.resourcesBox); - if (resourcesBox.isEmpty) { - final Box serverInstallationBox = - Hive.box(BNames.serverInstallationBox); - - final String? serverProviderKey = - serverInstallationBox.get(BNames.hetznerKey); - final String? serverLocation = - serverInstallationBox.get(BNames.serverLocation); - final String? dnsProviderKey = - serverInstallationBox.get(BNames.cloudFlareKey); - final BackupsCredential? backblazeCredential = - serverInstallationBox.get(BNames.backblazeCredential); - final ServerDomain? serverDomain = - serverInstallationBox.get(BNames.serverDomain); - final ServerHostingDetails? serverDetails = - serverInstallationBox.get(BNames.serverDetails); - final BackblazeBucket? backblazeBucket = - serverInstallationBox.get(BNames.backblazeBucket); - final String? serverType = - serverInstallationBox.get(BNames.serverTypeIdentifier); - final ServerProviderType? serverProvider = - serverInstallationBox.get(BNames.serverProvider); - final DnsProviderType? dnsProvider = - serverInstallationBox.get(BNames.dnsProvider); - - if (serverProviderKey != null && - (serverProvider != null || - (serverDetails != null && - serverDetails.provider != ServerProviderType.unknown))) { - final ServerProviderCredential serverProviderCredential = - ServerProviderCredential( - tokenId: null, - token: serverProviderKey, - provider: serverProvider ?? serverDetails!.provider, - associatedServerIds: - serverDetails != null ? [serverDetails.id] : [], - ); - - await resourcesBox - .put(BNames.serverProviderTokens, [serverProviderCredential]); - } - - if (dnsProviderKey != null && - (dnsProvider != null || - (serverDomain != null && - serverDomain.provider != DnsProviderType.unknown))) { - final DnsProviderCredential dnsProviderCredential = - DnsProviderCredential( - tokenId: null, - token: dnsProviderKey, - provider: dnsProvider ?? serverDomain!.provider, - associatedDomainNames: - serverDomain != null ? [serverDomain.domainName] : [], - ); - - await resourcesBox - .put(BNames.dnsProviderTokens, [dnsProviderCredential]); - } - - if (backblazeCredential != null) { - await resourcesBox - .put(BNames.backupsProviderTokens, [backblazeCredential]); - } - - if (backblazeBucket != null) { - await resourcesBox.put(BNames.backblazeBucket, backblazeBucket); - } - - if (serverDetails != null && serverDomain != null) { - await resourcesBox.put(BNames.servers, [ - Server( - domain: serverDomain, - hostingDetails: serverDetails.copyWith( - serverLocation: serverLocation, - serverType: serverType, - ), - ), - ]); - } - } - } on PlatformException catch (e) { - print('HiveConfig: Error while opening boxes: $e'); rethrow; } } - static Future getEncryptedKey(final String encKey) async { - const FlutterSecureStorage secureStorage = FlutterSecureStorage(); - try { - final bool hasEncryptionKey = - await secureStorage.containsKey(key: encKey); - if (!hasEncryptionKey) { - final List key = Hive.generateSecureKey(); - await secureStorage.write(key: encKey, value: base64UrlEncode(key)); - } + static Future getCipher() async { + List? key = await SecureStorage.getKey(); + if (key == null) { + key = Hive.generateSecureKey(); + await SecureStorage.setKey(key); + } + return HiveAesCipher(key); + } - final String? string = await secureStorage.read(key: encKey); - return base64Url.decode(string!); - } on PlatformException catch (e) { - print('HiveConfig: Error while getting encryption key: $e'); + static Future decryptBoxes() async { + try { + // load encrypted boxes into memory + final HiveAesCipher cipher = await getCipher(); + + await Hive.openBox( + BNames.serverInstallationBox, + encryptionCipher: cipher, + ); + await Hive.openBox( + BNames.resourcesBox, + encryptionCipher: cipher, + ); + await Hive.openBox( + BNames.wizardDataBox, + encryptionCipher: cipher, + ); + log('successfully decrypted boxes'); + } catch (error, stackTrace) { + log( + 'error initializing encrypted boxes', + error: error, + stackTrace: stackTrace, + ); rethrow; } } + + // migrations + + static Future performMigrations() async { + try { + // perform migration check + final localSettingsBox = await Hive.openBox(BNames.appSettingsBox); + + // if it is an initial app launch, we do not need to perform any migrations + final savedVersion = localSettingsBox.isEmpty + ? version + // if box was initialized, but database version was not introduced in + // it yet, it means that we have initial value + : await localSettingsBox.get(BNames.databaseVersion, defaultValue: 1); + + /// launch migrations based on version + if (savedVersion < version) { + if (savedVersion < 2) { + await migrateFrom1To2(); + } + + /// add new migrations here, like: + /// if (version < 3) {...}, etc. + + /// update saved version after successfull migraions + await localSettingsBox.put(BNames.databaseVersion, version); + } + } catch (error, stackTrace) { + log( + 'error running db migrations', + error: error, + stackTrace: stackTrace, + ); + rethrow; + } + } + + /// introduce and populate resourcesBox + static Future migrateFrom1To2() async { + final Box resourcesBox = Hive.box(BNames.resourcesBox); + if (resourcesBox.isEmpty) { + final Box serverInstallationBox = Hive.box(BNames.serverInstallationBox); + + final String? serverProviderKey = + serverInstallationBox.get(BNames.hetznerKey); + final String? serverLocation = + serverInstallationBox.get(BNames.serverLocation); + final String? dnsProviderKey = + serverInstallationBox.get(BNames.cloudFlareKey); + final BackupsCredential? backblazeCredential = + serverInstallationBox.get(BNames.backblazeCredential); + final ServerDomain? serverDomain = + serverInstallationBox.get(BNames.serverDomain); + final ServerHostingDetails? serverDetails = + serverInstallationBox.get(BNames.serverDetails); + final BackblazeBucket? backblazeBucket = + serverInstallationBox.get(BNames.backblazeBucket); + final String? serverType = + serverInstallationBox.get(BNames.serverTypeIdentifier); + final ServerProviderType? serverProvider = + serverInstallationBox.get(BNames.serverProvider); + final DnsProviderType? dnsProvider = + serverInstallationBox.get(BNames.dnsProvider); + + if (serverProviderKey != null && + (serverProvider != null || + (serverDetails != null && + serverDetails.provider != ServerProviderType.unknown))) { + final ServerProviderCredential serverProviderCredential = + ServerProviderCredential( + tokenId: null, + token: serverProviderKey, + provider: serverProvider ?? serverDetails!.provider, + associatedServerIds: serverDetails != null ? [serverDetails.id] : [], + ); + + await resourcesBox + .put(BNames.serverProviderTokens, [serverProviderCredential]); + } + + if (dnsProviderKey != null && + (dnsProvider != null || + (serverDomain != null && + serverDomain.provider != DnsProviderType.unknown))) { + final DnsProviderCredential dnsProviderCredential = + DnsProviderCredential( + tokenId: null, + token: dnsProviderKey, + provider: dnsProvider ?? serverDomain!.provider, + associatedDomainNames: + serverDomain != null ? [serverDomain.domainName] : [], + ); + + await resourcesBox + .put(BNames.dnsProviderTokens, [dnsProviderCredential]); + } + + if (backblazeCredential != null) { + await resourcesBox + .put(BNames.backupsProviderTokens, [backblazeCredential]); + } + + if (backblazeBucket != null) { + await resourcesBox.put(BNames.backblazeBucket, backblazeBucket); + } + + if (serverDetails != null && serverDomain != null) { + await resourcesBox.put(BNames.servers, [ + Server( + domain: serverDomain, + hostingDetails: serverDetails.copyWith( + serverLocation: serverLocation, + serverType: serverType, + ), + ), + ]); + } + } + log('successfully migration of db from 1 to 2 version'); + } } /// Mappings for the different boxes and their keys @@ -157,6 +219,9 @@ class BNames { /// App settings box. Contains app settings like [darkThemeModeOn], [shouldShowOnboarding] static String appSettingsBox = 'appSettings'; + /// An integer with last saved version of the database + static String databaseVersion = 'databaseVersion'; + /// A boolean field of [appSettingsBox] box. static String darkThemeModeOn = 'isDarkModeOn'; @@ -169,9 +234,6 @@ class BNames { /// A string field static String appLocale = 'appLocale'; - /// Encryption key to decrypt [serverInstallationBox] box. - static String serverInstallationEncryptionKey = 'key'; - /// Server installation box. Contains server details and provider tokens. static String serverInstallationBox = 'appConfig'; diff --git a/lib/logic/api_maps/rest_maps/rest_api_map.dart b/lib/logic/api_maps/rest_maps/rest_api_map.dart index 5426248f..73c44c1e 100644 --- a/lib/logic/api_maps/rest_maps/rest_api_map.dart +++ b/lib/logic/api_maps/rest_maps/rest_api_map.dart @@ -1,19 +1,25 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:developer'; import 'dart:io'; import 'package:dio/dio.dart'; import 'package:dio/io.dart'; -import 'package:pretty_dio_logger/pretty_dio_logger.dart'; +// import 'package:pretty_dio_logger/pretty_dio_logger.dart'; import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/logic/models/console_log.dart'; +import 'package:selfprivacy/utils/app_logger.dart'; abstract class RestApiMap { + static final log = const AppLogger(name: 'rest_api_map').log; + Future getClient({final BaseOptions? customOptions}) async { final Dio dio = Dio(customOptions ?? (await options)); if (hasLogger) { - dio.interceptors.add(PrettyDioLogger()); + // dio.interceptors.add( + // PrettyDioLogger( + // logPrint: (final object) => log('$object'), + // ), + // ); } dio.interceptors.add(ConsoleInterceptor()); dio.httpClientAdapter = IOHttpClientAdapter( @@ -29,11 +35,7 @@ abstract class RestApiMap { dio.interceptors.add( InterceptorsWrapper( onError: (final DioException e, final ErrorInterceptorHandler handler) { - print(e.requestOptions.path); - print(e.requestOptions.data); - - print(e.message); - print(e.response); + log('got dio error', error: e); return handler.next(e); }, @@ -103,7 +105,6 @@ class ConsoleInterceptor extends InterceptorsWrapper { final ErrorInterceptorHandler handler, ) async { final Response? response = err.response; - log(err.toString()); addConsoleLog( ManualConsoleLog.warning( diff --git a/lib/utils/app_logger.dart b/lib/utils/app_logger.dart new file mode 100644 index 00000000..b03c01f7 --- /dev/null +++ b/lib/utils/app_logger.dart @@ -0,0 +1,26 @@ +import 'dart:developer' as developer; + +import 'package:selfprivacy/config/config.dart'; + +class AppLogger { + const AppLogger({required this.name}); + final String name; + + // TODO: research other possible options, which could support both + // throttling and output formatting + void log( + final String message, { + final Object? error, + final StackTrace? stackTrace, + }) { + if (config.shouldDebugPrint) { + developer.log( + message, + error: error, + stackTrace: stackTrace, + time: DateTime.now(), + name: name, + ); + } + } +} diff --git a/lib/utils/secure_storage.dart b/lib/utils/secure_storage.dart new file mode 100644 index 00000000..a51562c5 --- /dev/null +++ b/lib/utils/secure_storage.dart @@ -0,0 +1,48 @@ +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:selfprivacy/utils/app_logger.dart'; + +class SecureStorage { + static final log = const AppLogger(name: 'secure_storage').log; + + static const FlutterSecureStorage secureStorage = FlutterSecureStorage(); + static String keyName = 'key'; + + static Future getKey() async { + try { + final bool hasEncryptionKey = + await secureStorage.containsKey(key: keyName); + if (!hasEncryptionKey) { + return null; + } + final String? string = await secureStorage.read(key: keyName); + log('successfully got encryption key: $string'); + + return base64Url.decode(string!); + } catch (error, stackTrace) { + log( + 'error reading encryption key', + error: error, + stackTrace: stackTrace, + ); + rethrow; + } + } + + static Future setKey(final List key) async { + try { + final value = base64UrlEncode(key); + await secureStorage.write(key: keyName, value: value); + log('successfully saved encryption key: $value'); + } catch (error, stackTrace) { + log( + 'error saving new encryption key', + error: error, + stackTrace: stackTrace, + ); + rethrow; + } + } +} From f7f791cc0c8f2130c2d8ac02d64b8c741a9ce41d Mon Sep 17 00:00:00 2001 From: Aliaksei Tratseuski Date: Sun, 30 Jun 2024 18:47:26 +0400 Subject: [PATCH 08/11] feat: console_page - cleaned up dead code and unused l10n strings --- assets/translations/en.json | 2 - lib/ui/pages/more/console/console_page.dart | 91 ++++++--------------- 2 files changed, 27 insertions(+), 66 deletions(-) diff --git a/assets/translations/en.json b/assets/translations/en.json index 9f672acd..234e0702 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -46,12 +46,10 @@ }, "console_page": { "title": "Console", - "waiting": "Waiting for initialization…", "copy": "Copy", "copy_raw": "Raw response", "history_empty": "No data yet", "error": "Error", - "log": "Log", "rest_api_request": "Rest API Request", "rest_api_response": "Rest API Response", "graphql_request": "GraphQL Request", diff --git a/lib/ui/pages/more/console/console_page.dart b/lib/ui/pages/more/console/console_page.dart index e69eb2fe..6c549a70 100644 --- a/lib/ui/pages/more/console/console_page.dart +++ b/lib/ui/pages/more/console/console_page.dart @@ -1,7 +1,6 @@ import 'package:auto_route/auto_route.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import 'package:gap/gap.dart'; import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/logic/models/console_log.dart'; import 'package:selfprivacy/ui/pages/more/console/console_log_item_widget.dart'; @@ -18,21 +17,15 @@ class ConsolePage extends StatefulWidget { class _ConsolePageState extends State { ConsoleModel get console => getIt(); - /// should freeze logs state to properly read logs - late final Future future; - @override void initState() { super.initState(); - - future = getIt.allReady(); console.addListener(update); } @override void dispose() { console.removeListener(update); - super.dispose(); } @@ -48,66 +41,36 @@ class _ConsolePageState extends State { } @override - Widget build(final BuildContext context) => SafeArea( - child: Scaffold( - appBar: AppBar( - title: Text('console_page.title'.tr()), - leading: IconButton( - icon: const Icon(Icons.arrow_back), - onPressed: () => Navigator.of(context).maybePop(), - ), - actions: [ - IconButton( - icon: Icon( - console.paused - ? Icons.play_arrow_outlined - : Icons.pause_outlined, - ), - onPressed: console.paused ? console.play : console.pause, + Widget build(final BuildContext context) { + final List logs = console.logs; + + return SafeArea( + child: Scaffold( + appBar: AppBar( + title: Text('console_page.title'.tr()), + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () => Navigator.of(context).maybePop(), + ), + actions: [ + IconButton( + icon: Icon( + console.paused + ? Icons.play_arrow_outlined + : Icons.pause_outlined, ), - ], - ), - body: Scrollbar( - child: FutureBuilder( - future: future, - builder: ( - final BuildContext context, - final AsyncSnapshot snapshot, - ) { - if (snapshot.hasData) { - final List logs = console.logs; - - return logs.isEmpty - ? const _ConsoleViewEmpty() - : _ConsoleViewLoaded(logs: logs); - } - - return const _ConsoleViewLoading(); - }, + onPressed: console.paused ? console.play : console.pause, ), - ), + ], ), - ); -} - -class _ConsoleViewLoading extends StatelessWidget { - const _ConsoleViewLoading(); - - @override - Widget build(final BuildContext context) => Column( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Text('console_page.waiting'.tr()), - const Gap(16), - const Expanded( - child: Center( - child: CircularProgressIndicator.adaptive(), - ), - ), - ], - ); + body: Scrollbar( + child: logs.isEmpty + ? const _ConsoleViewEmpty() + : _ConsoleViewLoaded(logs: logs), + ), + ), + ); + } } class _ConsoleViewEmpty extends StatelessWidget { From 4bda23eaf9d9300b2b1b3908402ae9b82a78ce78 Mon Sep 17 00:00:00 2001 From: Aliaksei Tratseuski Date: Sun, 30 Jun 2024 18:49:07 +0400 Subject: [PATCH 09/11] fix: re-enabled dio logs (developer debug console) --- .../api_maps/rest_maps/rest_api_map.dart | 23 +++++++++++-------- lib/utils/app_logger.dart | 2 ++ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/lib/logic/api_maps/rest_maps/rest_api_map.dart b/lib/logic/api_maps/rest_maps/rest_api_map.dart index 73c44c1e..3e06a803 100644 --- a/lib/logic/api_maps/rest_maps/rest_api_map.dart +++ b/lib/logic/api_maps/rest_maps/rest_api_map.dart @@ -4,7 +4,9 @@ import 'dart:io'; import 'package:dio/dio.dart'; import 'package:dio/io.dart'; -// import 'package:pretty_dio_logger/pretty_dio_logger.dart'; +import 'package:flutter/foundation.dart'; +import 'package:pretty_dio_logger/pretty_dio_logger.dart'; +import 'package:selfprivacy/config/config.dart'; import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/logic/models/console_log.dart'; import 'package:selfprivacy/utils/app_logger.dart'; @@ -14,12 +16,10 @@ abstract class RestApiMap { Future getClient({final BaseOptions? customOptions}) async { final Dio dio = Dio(customOptions ?? (await options)); - if (hasLogger) { - // dio.interceptors.add( - // PrettyDioLogger( - // logPrint: (final object) => log('$object'), - // ), - // ); + if (hasLogger && config.shouldDebugPrint) { + dio.interceptors.add( + PrettyDioLogger(logPrint: (final object) => debugPrint('$object')), + ); } dio.interceptors.add(ConsoleInterceptor()); dio.httpClientAdapter = IOHttpClientAdapter( @@ -34,10 +34,13 @@ abstract class RestApiMap { dio.interceptors.add( InterceptorsWrapper( - onError: (final DioException e, final ErrorInterceptorHandler handler) { - log('got dio error', error: e); + onError: ( + final DioException exception, + final ErrorInterceptorHandler handler, + ) { + log('got dio exception:', error: exception); - return handler.next(e); + return handler.next(exception); }, ), ); diff --git a/lib/utils/app_logger.dart b/lib/utils/app_logger.dart index b03c01f7..863eba9e 100644 --- a/lib/utils/app_logger.dart +++ b/lib/utils/app_logger.dart @@ -4,6 +4,7 @@ import 'package:selfprivacy/config/config.dart'; class AppLogger { const AppLogger({required this.name}); + final String name; // TODO: research other possible options, which could support both @@ -14,6 +15,7 @@ class AppLogger { final StackTrace? stackTrace, }) { if (config.shouldDebugPrint) { + // TODO: could probably add UI logging for console_page developer.log( message, error: error, From 2fbcc3c232838d8ee243e8838c7e509c6d2c353c Mon Sep 17 00:00:00 2001 From: Aliaksei Tratseuski Date: Sun, 30 Jun 2024 18:50:21 +0400 Subject: [PATCH 10/11] feat: some more decomposition in hive_config --- lib/config/hive_config.dart | 104 ++++++++++++---------- lib/logic/models/hive/server_details.dart | 4 + lib/logic/models/hive/server_domain.dart | 4 + 3 files changed, 65 insertions(+), 47 deletions(-) diff --git a/lib/config/hive_config.dart b/lib/config/hive_config.dart index 28b51de9..e010cfed 100644 --- a/lib/config/hive_config.dart +++ b/lib/config/hive_config.dart @@ -116,7 +116,7 @@ class HiveConfig { /// add new migrations here, like: /// if (version < 3) {...}, etc. - /// update saved version after successfull migraions + /// update saved version after successfull migrations await localSettingsBox.put(BNames.databaseVersion, version); } } catch (error, stackTrace) { @@ -135,60 +135,82 @@ class HiveConfig { if (resourcesBox.isEmpty) { final Box serverInstallationBox = Hive.box(BNames.serverInstallationBox); - final String? serverProviderKey = - serverInstallationBox.get(BNames.hetznerKey); - final String? serverLocation = - serverInstallationBox.get(BNames.serverLocation); - final String? dnsProviderKey = - serverInstallationBox.get(BNames.cloudFlareKey); - final BackupsCredential? backblazeCredential = - serverInstallationBox.get(BNames.backblazeCredential); - final ServerDomain? serverDomain = - serverInstallationBox.get(BNames.serverDomain); final ServerHostingDetails? serverDetails = serverInstallationBox.get(BNames.serverDetails); - final BackblazeBucket? backblazeBucket = - serverInstallationBox.get(BNames.backblazeBucket); - final String? serverType = - serverInstallationBox.get(BNames.serverTypeIdentifier); - final ServerProviderType? serverProvider = - serverInstallationBox.get(BNames.serverProvider); - final DnsProviderType? dnsProvider = - serverInstallationBox.get(BNames.dnsProvider); - if (serverProviderKey != null && - (serverProvider != null || - (serverDetails != null && - serverDetails.provider != ServerProviderType.unknown))) { + // move server provider config + + final ServerProviderType? serverProvider = + serverInstallationBox.get(BNames.serverProvider) ?? + serverDetails?.provider; + final String? serverProviderKey = + serverInstallationBox.get(BNames.hetznerKey); + + if (serverProviderKey != null && serverProvider.isSpecified) { final ServerProviderCredential serverProviderCredential = ServerProviderCredential( tokenId: null, token: serverProviderKey, - provider: serverProvider ?? serverDetails!.provider, - associatedServerIds: serverDetails != null ? [serverDetails.id] : [], + provider: serverProvider!, + associatedServerIds: [if (serverDetails != null) serverDetails.id], ); - await resourcesBox - .put(BNames.serverProviderTokens, [serverProviderCredential]); + await resourcesBox.put( + BNames.serverProviderTokens, + [serverProviderCredential], + ); } - if (dnsProviderKey != null && - (dnsProvider != null || - (serverDomain != null && - serverDomain.provider != DnsProviderType.unknown))) { + final String? serverLocation = + serverInstallationBox.get(BNames.serverLocation); + final String? serverType = + serverInstallationBox.get(BNames.serverTypeIdentifier); + final ServerDomain? serverDomain = + serverInstallationBox.get(BNames.serverDomain); + + if (serverDetails != null && serverDomain != null) { + await resourcesBox.put( + BNames.servers, + [ + Server( + domain: serverDomain, + hostingDetails: serverDetails.copyWith( + serverLocation: serverLocation, + serverType: serverType, + ), + ), + ], + ); + } + + // move dns config + final String? dnsProviderKey = + serverInstallationBox.get(BNames.cloudFlareKey); + final DnsProviderType? dnsProvider = + serverInstallationBox.get(BNames.dnsProvider) ?? + serverDomain?.provider; + + if (dnsProviderKey != null && dnsProvider.isSpecified) { final DnsProviderCredential dnsProviderCredential = DnsProviderCredential( tokenId: null, token: dnsProviderKey, - provider: dnsProvider ?? serverDomain!.provider, - associatedDomainNames: - serverDomain != null ? [serverDomain.domainName] : [], + provider: dnsProvider!, + associatedDomainNames: [ + if (serverDomain != null) serverDomain.domainName, + ], ); await resourcesBox .put(BNames.dnsProviderTokens, [dnsProviderCredential]); } + // move backblaze (backups) config + final BackupsCredential? backblazeCredential = + serverInstallationBox.get(BNames.backblazeCredential); + final BackblazeBucket? backblazeBucket = + serverInstallationBox.get(BNames.backblazeBucket); + if (backblazeCredential != null) { await resourcesBox .put(BNames.backupsProviderTokens, [backblazeCredential]); @@ -197,20 +219,8 @@ class HiveConfig { if (backblazeBucket != null) { await resourcesBox.put(BNames.backblazeBucket, backblazeBucket); } - - if (serverDetails != null && serverDomain != null) { - await resourcesBox.put(BNames.servers, [ - Server( - domain: serverDomain, - hostingDetails: serverDetails.copyWith( - serverLocation: serverLocation, - serverType: serverType, - ), - ), - ]); - } } - log('successfully migration of db from 1 to 2 version'); + log('successfully migrated db from 1 to 2 version'); } } diff --git a/lib/logic/models/hive/server_details.dart b/lib/logic/models/hive/server_details.dart index 6624a512..9a11165c 100644 --- a/lib/logic/models/hive/server_details.dart +++ b/lib/logic/models/hive/server_details.dart @@ -118,3 +118,7 @@ enum ServerProviderType { unknown => 'Unknown', }; } + +extension ServerProviderTypeIsSpecified on ServerProviderType? { + bool get isSpecified => this != null && this != ServerProviderType.unknown; +} diff --git a/lib/logic/models/hive/server_domain.dart b/lib/logic/models/hive/server_domain.dart index f86e228f..63387145 100644 --- a/lib/logic/models/hive/server_domain.dart +++ b/lib/logic/models/hive/server_domain.dart @@ -57,3 +57,7 @@ enum DnsProviderType { unknown => 'Unknown', }; } + +extension DnsProviderTypeIsSpecified on DnsProviderType? { + bool get isSpecified => this != null && this != DnsProviderType.unknown; +} From 1ad8fccbb68b19155013c74ef8b7298fa192bd24 Mon Sep 17 00:00:00 2001 From: Inex Code Date: Thu, 4 Jul 2024 18:05:01 +0400 Subject: [PATCH 11/11] fix: App didn't save the server type and location correctly --- lib/config/hive_config.dart | 6 ++-- .../server_installation_cubit.dart | 2 +- .../server_installation_repository.dart | 4 +++ lib/logic/get_it/resources_model.dart | 30 ++++++++++++++++++- 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/lib/config/hive_config.dart b/lib/config/hive_config.dart index e010cfed..a5054674 100644 --- a/lib/config/hive_config.dart +++ b/lib/config/hive_config.dart @@ -115,10 +115,10 @@ class HiveConfig { /// add new migrations here, like: /// if (version < 3) {...}, etc. - - /// update saved version after successfull migrations - await localSettingsBox.put(BNames.databaseVersion, version); } + + /// update saved version after successfull migrations + await localSettingsBox.put(BNames.databaseVersion, version); } catch (error, stackTrace) { log( 'error running db migrations', diff --git a/lib/logic/cubit/server_installation/server_installation_cubit.dart b/lib/logic/cubit/server_installation/server_installation_cubit.dart index 6b507e93..4f1a52f3 100644 --- a/lib/logic/cubit/server_installation/server_installation_cubit.dart +++ b/lib/logic/cubit/server_installation/server_installation_cubit.dart @@ -794,13 +794,13 @@ class ServerInstallationCubit extends Cubit { await repository.saveIsServerStarted(true); await repository.saveIsServerRebootedFirstTime(true); await repository.saveIsServerRebootedSecondTime(true); - await repository.saveHasFinalChecked(true); await repository.saveIsRecoveringServer(false); final serverType = await ProvidersController.currentServerProvider! .getServerType(state.serverDetails!.id); await repository.saveServerType(serverType.data!); await ProvidersController.currentServerProvider! .trySetServerLocation(serverType.data!.location.identifier); + await repository.saveHasFinalChecked(true); final ServerInstallationRecovery updatedState = (state as ServerInstallationRecovery).copyWith( backblazeCredential: backblazeCredential, diff --git a/lib/logic/cubit/server_installation/server_installation_repository.dart b/lib/logic/cubit/server_installation/server_installation_repository.dart index 57b47c81..995e5922 100644 --- a/lib/logic/cubit/server_installation/server_installation_repository.dart +++ b/lib/logic/cubit/server_installation/server_installation_repository.dart @@ -182,6 +182,9 @@ class ServerInstallationRepository { if (!domainResult.success || domainResult.data.isEmpty) { return false; } + await getIt().removeDnsProviderToken( + getIt().dnsProviderCredentials.first, + ); return domainResult.data.any( (final serverDomain) => serverDomain.domainName == domain, @@ -519,6 +522,7 @@ class ServerInstallationRepository { // We are finished here. Time to save the state and finish the wizard // TODO: A lot of null checks are skipped here. Implication that every value exists might become false in the future. // TODO: We would actually want to handle token creation elsewhere. + await getIt().moveServerTypeToServerDetails(); final ServerInstallationWizardData wizardData = getIt().serverInstallation!; await getIt().addServer( diff --git a/lib/logic/get_it/resources_model.dart b/lib/logic/get_it/resources_model.dart index ebde7870..b2055381 100644 --- a/lib/logic/get_it/resources_model.dart +++ b/lib/logic/get_it/resources_model.dart @@ -78,6 +78,11 @@ class ResourcesModel { } Future addDnsProviderToken(final DnsProviderCredential token) async { + // Check if this token already exists + if (_dnsProviderTokens + .any((final credential) => credential.token == token.token)) { + throw Exception('Token already exists'); + } _dnsProviderTokens.add(token); await _box.put(BNames.dnsProviderTokens, _dnsProviderTokens); } @@ -227,10 +232,33 @@ class WizardDataModel { await _box.put(BNames.serverInstallationWizardData, _serverInstallation); } + Future moveServerTypeToServerDetails() async { + final details = _serverInstallation?.serverDetails; + if (details != null) { + if (_serverInstallation?.serverTypeIdentifier != null && + _serverInstallation?.serverLocation != null) { + _serverInstallation = _serverInstallation?.copyWith( + serverDetails: () => details.copyWith( + serverType: _serverInstallation?.serverTypeIdentifier, + serverLocation: _serverInstallation?.serverLocation, + ), + ); + await _box.put( + BNames.serverInstallationWizardData, + _serverInstallation, + ); + } + } + } + Future setServerDetails(final ServerHostingDetails details) async { + final detailsWithServerType = details.copyWith( + serverLocation: _serverInstallation?.serverLocation, + serverType: _serverInstallation?.serverTypeIdentifier, + ); _serverInstallation = (_serverInstallation ?? ServerInstallationWizardData.empty()) - .copyWith(serverDetails: () => details); + .copyWith(serverDetails: () => detailsWithServerType); await _box.put(BNames.serverInstallationWizardData, _serverInstallation); }