From 7de50dd237bb706dfbe5fff8498e602dec9d66c8 Mon Sep 17 00:00:00 2001 From: Kherel Date: Thu, 21 Jan 2021 08:35:38 +0100 Subject: [PATCH] update --- lib/config/hive_config.dart | 4 +- .../{cloud_flare.dart => cloudflare.dart} | 4 +- lib/logic/api_maps/server.dart | 12 ++ .../cubit/app_config/app_config_cubit.dart | 148 ++++++------------ .../app_config/app_config_repository.dart | 130 +++++++++++++++ .../cubit/app_config/app_config_state.dart | 35 +++-- .../initializing/cloudflare_form_cubit.dart | 2 +- .../forms/initializing/domain_form_cubit.dart | 8 +- lib/logic/models/cloudflare_domain.dart | 6 +- lib/logic/models/cloudflare_domain.g.dart | 4 +- lib/ui/pages/initializing/initializing.dart | 31 ++-- 11 files changed, 245 insertions(+), 139 deletions(-) rename lib/logic/api_maps/{cloud_flare.dart => cloudflare.dart} (97%) create mode 100644 lib/logic/api_maps/server.dart create mode 100644 lib/logic/cubit/app_config/app_config_repository.dart diff --git a/lib/config/hive_config.dart b/lib/config/hive_config.dart index ab0b5368..6f02ffb1 100644 --- a/lib/config/hive_config.dart +++ b/lib/config/hive_config.dart @@ -43,11 +43,11 @@ class BNames { static String key = 'key'; - static String domain = 'domain'; + static String cloudFlareDomain = 'cloudFlareDomain'; static String hetznerKey = 'hetznerKey'; static String cloudFlareKey = 'cloudFlareKey'; static String rootUser = 'rootUser'; static String hetznerServer = 'server'; - static String isDnsCheckedAndDkimSet = 'isDnsCheckedAndDkimSet'; + static String isDnsChecked = 'isDnsChecked'; static String serverInitStart = 'serverInitStart'; } diff --git a/lib/logic/api_maps/cloud_flare.dart b/lib/logic/api_maps/cloudflare.dart similarity index 97% rename from lib/logic/api_maps/cloud_flare.dart rename to lib/logic/api_maps/cloudflare.dart index 2dfb36d3..5ead436c 100644 --- a/lib/logic/api_maps/cloud_flare.dart +++ b/lib/logic/api_maps/cloudflare.dart @@ -61,7 +61,7 @@ class CloudflareApi extends ApiMap { String ip4, CloudFlareDomain cloudFlareDomain, }) async { - var domainName = cloudFlareDomain.name; + var domainName = cloudFlareDomain.domainName; var domainZoneId = cloudFlareDomain.zoneId; var domainA = DnsRecords(type: 'A', name: domainName, content: ip4); @@ -82,7 +82,7 @@ class CloudflareApi extends ApiMap { var txt2 = DnsRecords( type: 'TXT', - name: cloudFlareDomain.name, + name: cloudFlareDomain.domainName, content: 'v=spf1 a mx ip4:$ip4 -all', ttl: 18000, ); diff --git a/lib/logic/api_maps/server.dart b/lib/logic/api_maps/server.dart new file mode 100644 index 00000000..44204ca6 --- /dev/null +++ b/lib/logic/api_maps/server.dart @@ -0,0 +1,12 @@ +import 'package:dio/dio.dart'; + +import 'api_map.dart'; + +class ServerApi extends ApiMap { + ServerApi([String token]) { + if (token != null) { + loggedClient.options = + BaseOptions(headers: {'Authorization': 'Bearer $token'}); + } + } +} diff --git a/lib/logic/cubit/app_config/app_config_cubit.dart b/lib/logic/cubit/app_config/app_config_cubit.dart index 28d0f32d..abb31b5d 100644 --- a/lib/logic/cubit/app_config/app_config_cubit.dart +++ b/lib/logic/cubit/app_config/app_config_cubit.dart @@ -1,153 +1,97 @@ import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; -import 'package:hive/hive.dart'; -import 'package:selfprivacy/config/get_it_config.dart'; -import 'package:selfprivacy/config/hive_config.dart'; -import 'package:selfprivacy/logic/api_maps/cloud_flare.dart'; -import 'package:selfprivacy/logic/api_maps/hetzner.dart'; -import 'package:selfprivacy/logic/get_it/console.dart'; import 'package:selfprivacy/logic/models/cloudflare_domain.dart'; -import 'package:selfprivacy/logic/models/message.dart'; + import 'package:selfprivacy/logic/models/server_details.dart'; import 'package:selfprivacy/logic/models/user.dart'; -import 'package:basic_utils/basic_utils.dart'; + +import 'app_config_repository.dart'; part 'app_config_state.dart'; class AppConfigCubit extends Cubit { AppConfigCubit() : super(InitialAppConfigState()); - Box box = Hive.box(BNames.appConfig); + final repository = AppConfigRepository(); void load() { - emit( - state.copyWith( - hetznerKey: box.get(BNames.hetznerKey), - cloudFlareKey: box.get(BNames.cloudFlareKey), - domain: box.get(BNames.domain), - rootUser: box.get(BNames.rootUser), - hetznerServer: box.get(BNames.hetznerServer), - serverStarted: box.get(BNames.isDnsCheckedAndDkimSet), - ), - ); + var state = repository.load(); + emit(state); } void reset() { - box.clear(); + repository.reset(); emit(InitialAppConfigState()); } - void setHetznerKey(String key) { - box.put(BNames.hetznerKey, key); - emit(state.copyWith(hetznerKey: key)); + void setHetznerKey(String hetznerKey) { + repository.saveHetznerKey(hetznerKey); + emit(state.copyWith(hetznerKey: hetznerKey)); } void setCloudFlare(String cloudFlareKey) { - box.put(BNames.cloudFlareKey, cloudFlareKey); + repository.saveCloudFlare(cloudFlareKey); emit(state.copyWith(cloudFlareKey: cloudFlareKey)); } - void setDomain(CloudFlareDomain domain) { - box.put(BNames.domain, domain); - emit(state.copyWith(domain: domain)); + void setDomain(CloudFlareDomain cloudFlareDomain) { + repository.saveDomain(cloudFlareDomain); + emit(state.copyWith(cloudFlareDomain: cloudFlareDomain)); } void setRootUser(User rootUser) { - box.put(BNames.rootUser, rootUser); + repository.saveRootUser(rootUser); emit(state.copyWith(rootUser: rootUser)); } Future checkDns() async { - var ip4 = state.server.ip4; - var domainName = state.cloudFlareDomain.name; - var addresses = [ - '$domainName', - 'api.$domainName', - 'cloud.$domainName', - 'meet.$domainName', - 'password.$domainName' - ]; - var hasError = false; - for (var address in addresses) { - var res = await DnsUtils.lookupRecord( - address, - RRecordType.A, - provider: DnsApiProvider.CLOUDFLARE, + var ip4 = state.hetznerServer.ip4; + var domainName = state.cloudFlareDomain.domainName; + + var isMatch = await repository.isDnsAddressesMatch(domainName, ip4); + + if (isMatch) { + var server = await repository.startServer( + state.hetznerKey, + state.hetznerServer, ); - getIt.get().addMessage( - Message( - text: - 'DnsLookup: address: $address, $RRecordType, provider: CLOUDFLARE, ip4: $ip4', - ), - ); - getIt.get().addMessage( - Message( - text: - 'DnsLookup: ${res.isEmpty ? (res[0].data != ip4 ? 'wrong ip4' : 'right ip4') : 'empty'}', - ), - ); - if (res.isEmpty || res[0].data != ip4) { - hasError = true; - break; - } - } - if (hasError) { - emit(state.copyWith(lastDnsCheckTime: DateTime.now())); - } else { - var hetznerApi = HetznerApi(state.hetznerKey); - - var serverDetails = await hetznerApi.startServer(server: state.server); - - await box.put(BNames.hetznerServer, serverDetails); - - hetznerApi.close(); - + repository.saveServerDetails(server); emit( state.copyWith( - serverStarted: true, + isDnsCheckedAndServerStarted: true, isLoading: false, - hetznerServer: serverDetails, + hetznerServer: server, ), ); + } else { + emit(state.copyWith(lastDnsCheckTime: DateTime.now())); } - - print('check complete: $hasError, time:' + DateTime.now().toString()); } void createServer() async { emit(state.copyWith(isLoading: true)); - var hetznerApi = HetznerApi(state.hetznerKey); - var cloudflareApi = CloudflareApi(state.cloudFlareKey); - - HetznerServerDetails serverDetails; try { - serverDetails = await hetznerApi.createServer( - rootUser: state.rootUser, - domainName: state.cloudFlareDomain.name, + var serverDetails = await repository.createServer( + state.hetznerKey, + state.rootUser, + state.cloudFlareDomain.domainName, ); + + await repository.createDnsRecords( + state.cloudFlareKey, + serverDetails.ip4, + state.cloudFlareDomain, + ); + + emit(state.copyWith( + isLoading: false, + hetznerServer: serverDetails, + )); } catch (e) { addError(e); + + emit(state.copyWith(isLoading: false)); } - - try { - cloudflareApi - .createMultipleDnsRecords( - ip4: serverDetails.ip4, - cloudFlareDomain: state.cloudFlareDomain, - ) - .then((_) => cloudflareApi.close()); - } catch (e) { - addError(e); - } - - await box.put(BNames.hetznerServer, serverDetails); - - hetznerApi.close(); - - emit(state.copyWith( - isLoading: false, - hetznerServer: serverDetails, - )); } } diff --git a/lib/logic/cubit/app_config/app_config_repository.dart b/lib/logic/cubit/app_config/app_config_repository.dart new file mode 100644 index 00000000..8633be9e --- /dev/null +++ b/lib/logic/cubit/app_config/app_config_repository.dart @@ -0,0 +1,130 @@ +import 'package:hive/hive.dart'; +import 'package:selfprivacy/config/hive_config.dart'; +import 'package:selfprivacy/logic/api_maps/cloudflare.dart'; +import 'package:selfprivacy/logic/api_maps/hetzner.dart'; +import 'package:selfprivacy/logic/models/cloudflare_domain.dart'; +import 'package:selfprivacy/logic/models/server_details.dart'; +import 'package:selfprivacy/logic/models/user.dart'; +import 'package:selfprivacy/config/get_it_config.dart'; +import 'package:selfprivacy/logic/get_it/console.dart'; +import 'package:selfprivacy/logic/models/message.dart'; +import 'package:basic_utils/basic_utils.dart'; +import 'app_config_cubit.dart'; + +class AppConfigRepository { + Box box = Hive.box(BNames.appConfig); + + AppConfigState load() { + return AppConfigState( + hetznerKey: box.get(BNames.hetznerKey), + cloudFlareKey: box.get(BNames.cloudFlareKey), + cloudFlareDomain: box.get(BNames.cloudFlareDomain), + rootUser: box.get(BNames.rootUser), + hetznerServer: box.get(BNames.hetznerServer), + isDnsCheckedAndServerStarted: box.get(BNames.isDnsChecked), + ); + } + + void reset() { + box.clear(); + } + + void saveHetznerKey(String key) { + box.put(BNames.hetznerKey, key); + } + + void saveCloudFlare(String key) { + box.put(BNames.cloudFlareKey, key); + } + + void saveDomain(CloudFlareDomain cloudFlareDomain) { + box.put(BNames.cloudFlareDomain, cloudFlareDomain); + } + + void saveRootUser(User rootUser) { + box.put(BNames.rootUser, rootUser); + } + + Future startServer( + String hetznerKey, + HetznerServerDetails hetznerServer, + ) async { + var hetznerApi = HetznerApi(hetznerKey); + var serverDetails = await hetznerApi.startServer(server: hetznerServer); + hetznerApi.close(); + + return serverDetails; + } + + Future saveServerDetails(HetznerServerDetails serverDetails) async { + await box.put(BNames.hetznerServer, serverDetails); + } + + Future isDnsAddressesMatch(String domainName, String ip4) async { + var addresses = [ + '$domainName', + 'api.$domainName', + 'cloud.$domainName', + 'meet.$domainName', + 'password.$domainName' + ]; + + for (var address in addresses) { + var lookupRecordRes = await DnsUtils.lookupRecord( + address, + RRecordType.A, + provider: DnsApiProvider.CLOUDFLARE, + ); + getIt.get().addMessage( + Message( + text: + 'DnsLookup: address: $address, $RRecordType, provider: CLOUDFLARE, ip4: $ip4', + ), + ); + getIt.get().addMessage( + Message( + text: + 'DnsLookup: ${lookupRecordRes.isEmpty ? (lookupRecordRes[0].data != ip4 ? 'wrong ip4' : 'right ip4') : 'empty'}', + ), + ); + if (lookupRecordRes.isEmpty || lookupRecordRes[0].data != ip4) { + return false; + } + } + + return true; + } + + Future createServer( + String hetznerKey, + User rootUser, + String domainName, + ) async { + var hetznerApi = HetznerApi(hetznerKey); + var serverDetails = await hetznerApi.createServer( + rootUser: rootUser, + domainName: domainName, + ); + await box.put(BNames.hetznerServer, serverDetails); + + hetznerApi.close(); + + return serverDetails; + } + + Future createDnsRecords( + String cloudFlareKey, + String ip4, + CloudFlareDomain cloudFlareDomain, + ) async { + + var cloudflareApi = CloudflareApi(cloudFlareKey); + + await cloudflareApi.createMultipleDnsRecords( + ip4: ip4, + cloudFlareDomain: cloudFlareDomain, + ); + + cloudflareApi.close(); + } +} diff --git a/lib/logic/cubit/app_config/app_config_state.dart b/lib/logic/cubit/app_config/app_config_state.dart index 80d7e256..1acb6763 100644 --- a/lib/logic/cubit/app_config/app_config_state.dart +++ b/lib/logic/cubit/app_config/app_config_state.dart @@ -6,11 +6,12 @@ class AppConfigState extends Equatable { this.cloudFlareKey, this.cloudFlareDomain, this.rootUser, - this.server, - this.isDnsChecked = false, + this.hetznerServer, + this.isDnsCheckedAndServerStarted = false, this.isLoading = false, this.error, this.lastDnsCheckTime, + this.isDkimSetted = false, }); @override @@ -19,19 +20,21 @@ class AppConfigState extends Equatable { cloudFlareKey, cloudFlareDomain, rootUser, - server, - isDnsChecked, + hetznerServer, + isDnsCheckedAndServerStarted, isLoading, error, - lastDnsCheckTime + lastDnsCheckTime, + isDkimSetted, ]; final String hetznerKey; final String cloudFlareKey; final CloudFlareDomain cloudFlareDomain; final User rootUser; - final HetznerServerDetails server; - final bool isDnsChecked; + final HetznerServerDetails hetznerServer; + final bool isDnsCheckedAndServerStarted; + final bool isDkimSetted; final DateTime lastDnsCheckTime; final bool isLoading; @@ -40,31 +43,35 @@ class AppConfigState extends Equatable { AppConfigState copyWith({ String hetznerKey, String cloudFlareKey, - CloudFlareDomain domain, + CloudFlareDomain cloudFlareDomain, User rootUser, HetznerServerDetails hetznerServer, - bool serverStarted, + bool isDnsCheckedAndServerStarted, bool isLoading, Exception error, DateTime lastDnsCheckTime, + bool isDkimSetted, }) => AppConfigState( hetznerKey: hetznerKey ?? this.hetznerKey, cloudFlareKey: cloudFlareKey ?? this.cloudFlareKey, - cloudFlareDomain: domain ?? this.cloudFlareDomain, + cloudFlareDomain: cloudFlareDomain ?? this.cloudFlareDomain, rootUser: rootUser ?? this.rootUser, - server: hetznerServer ?? this.server, - isDnsChecked: serverStarted ?? this.isDnsChecked, + hetznerServer: hetznerServer ?? this.hetznerServer, + isDnsCheckedAndServerStarted: + isDnsCheckedAndServerStarted ?? this.isDnsCheckedAndServerStarted, isLoading: isLoading ?? this.isLoading, error: error ?? this.error, lastDnsCheckTime: lastDnsCheckTime ?? this.lastDnsCheckTime, + isDkimSetted: isDkimSetted, ); bool get isHetznerFilled => hetznerKey != null; bool get isCloudFlareFilled => cloudFlareKey != null; bool get isDomainFilled => cloudFlareDomain != null; bool get isUserFilled => rootUser != null; - bool get isServerFilled => server != null; + bool get isServerFilled => hetznerServer != null; + bool get hasFinalChecked => isDnsCheckedAndServerStarted && isDkimSetted; bool get isFullyInitilized => _fulfilementList.every((el) => el); @@ -76,7 +83,7 @@ class AppConfigState extends Equatable { isDomainFilled, isUserFilled, isServerFilled, - isDnsChecked, + hasFinalChecked, ]; } diff --git a/lib/logic/cubit/forms/initializing/cloudflare_form_cubit.dart b/lib/logic/cubit/forms/initializing/cloudflare_form_cubit.dart index 2541ca2c..dc0796cb 100644 --- a/lib/logic/cubit/forms/initializing/cloudflare_form_cubit.dart +++ b/lib/logic/cubit/forms/initializing/cloudflare_form_cubit.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'package:cubit_form/cubit_form.dart'; -import 'package:selfprivacy/logic/api_maps/cloud_flare.dart'; +import 'package:selfprivacy/logic/api_maps/cloudflare.dart'; import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart'; import 'package:selfprivacy/logic/cubit/forms/validations/validations.dart'; diff --git a/lib/logic/cubit/forms/initializing/domain_form_cubit.dart b/lib/logic/cubit/forms/initializing/domain_form_cubit.dart index 8c1f69cf..6d77bf62 100644 --- a/lib/logic/cubit/forms/initializing/domain_form_cubit.dart +++ b/lib/logic/cubit/forms/initializing/domain_form_cubit.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'package:cubit_form/cubit_form.dart'; -import 'package:selfprivacy/logic/api_maps/cloud_flare.dart'; +import 'package:selfprivacy/logic/api_maps/cloudflare.dart'; import 'package:selfprivacy/logic/cubit/app_config/app_config_cubit.dart'; import 'package:selfprivacy/logic/models/cloudflare_domain.dart'; @@ -16,7 +16,9 @@ class DomainFormCubit extends FormCubit { validations: [ RequiredStringValidation('required'), ValidationModel( - (s) => !regExp.hasMatch(s), 'invalid domain format'), + (s) => !regExp.hasMatch(s), + 'invalid domain format', + ), ], ); @@ -26,7 +28,7 @@ class DomainFormCubit extends FormCubit { @override FutureOr onSubmit() async { var domain = CloudFlareDomain( - name: domainName.state.value, + domainName: domainName.state.value, zoneId: zoneId, ); initializingCubit.setDomain(domain); diff --git a/lib/logic/models/cloudflare_domain.dart b/lib/logic/models/cloudflare_domain.dart index 0cc24781..b050a92c 100644 --- a/lib/logic/models/cloudflare_domain.dart +++ b/lib/logic/models/cloudflare_domain.dart @@ -4,16 +4,16 @@ part 'cloudflare_domain.g.dart'; @HiveType(typeId: 3) class CloudFlareDomain { - CloudFlareDomain({this.name, this.zoneId}); + CloudFlareDomain({this.domainName, this.zoneId}); @HiveField(0) - final String name; + final String domainName; @HiveField(1) final String zoneId; @override String toString() { - return '$name: $zoneId'; + return '$domainName: $zoneId'; } } diff --git a/lib/logic/models/cloudflare_domain.g.dart b/lib/logic/models/cloudflare_domain.g.dart index c1dee8bd..dcd95317 100644 --- a/lib/logic/models/cloudflare_domain.g.dart +++ b/lib/logic/models/cloudflare_domain.g.dart @@ -17,7 +17,7 @@ class CloudFlareDomainAdapter extends TypeAdapter { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return CloudFlareDomain( - name: fields[0] as String, + domainName: fields[0] as String, zoneId: fields[1] as String, ); } @@ -27,7 +27,7 @@ class CloudFlareDomainAdapter extends TypeAdapter { writer ..writeByte(2) ..writeByte(0) - ..write(obj.name) + ..write(obj.domainName) ..writeByte(1) ..write(obj.zoneId); } diff --git a/lib/ui/pages/initializing/initializing.dart b/lib/ui/pages/initializing/initializing.dart index 106d565a..39512a91 100644 --- a/lib/ui/pages/initializing/initializing.dart +++ b/lib/ui/pages/initializing/initializing.dart @@ -181,7 +181,6 @@ class InitializingPage extends StatelessWidget { create: (context) => DomainFormCubit(initializingCubit), child: Builder(builder: (context) { var formCubit = context.watch(); - return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -286,6 +285,7 @@ class InitializingPage extends StatelessWidget { Widget _stepCheck(AppConfigCubit appConfigCubit) { var state = appConfigCubit.state; + var isDnsChecked = appConfigCubit.state.isDnsCheckedAndServerStarted; return Builder(builder: (context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -293,20 +293,31 @@ class InitializingPage extends StatelessWidget { Spacer(flex: 2), SizedBox(height: 10), BrandText.body2( - 'Мы начали процесс инциализации сервера, раз в минуты мы будем проверять наличие DNS записей, как только они вступят в силу мы закончим инциализацию', + isDnsChecked + ? 'Dns сервера вступили в силу, мы стартанули сервер, как только он поднимиться, мы закончим инициализацию.' + : 'Мы начали процесс инциализации сервера, раз в минуты мы будем проверять наличие DNS записей, как только они вступят в силу мы продолжим инциализацию', ), SizedBox(height: 10), Row( children: [ BrandText.body2('До следующей проверки: '), - BrandTimer( - startDateTime: - state.lastDnsCheckTime ?? state.server.createTime, - duration: Duration(minutes: 1), - callback: () { - appConfigCubit.checkDns(); - }, - ) + isDnsChecked + ? BrandTimer( + startDateTime: + state.lastDnsCheckTime ?? state.hetznerServer.createTime, + duration: Duration(minutes: 1), + callback: () { + appConfigCubit.checkDns(); + }, + ) + : BrandTimer( + startDateTime: + state.lastDnsCheckTime ?? state.hetznerServer.createTime, + duration: Duration(minutes: 1), + callback: () { + appConfigCubit.checkDns(); + }, + ) ], ), Spacer(