From 80213abf9bd691599d1b46f55217844c1b51de85 Mon Sep 17 00:00:00 2001 From: Kherel Date: Thu, 21 Jan 2021 22:01:42 +0100 Subject: [PATCH] update --- ios/Podfile.lock | 6 ++ lib/config/hive_config.dart | 6 +- lib/logic/api_maps/api_map.dart | 20 ++++- lib/logic/api_maps/cloudflare.dart | 25 +++--- lib/logic/api_maps/server.dart | 43 ++++++++++- .../cubit/app_config/app_config_cubit.dart | 76 +++++++++++++++---- .../app_config/app_config_repository.dart | 34 ++++++++- .../cubit/app_config/app_config_state.dart | 24 ++++-- .../initializing/cloudflare_form_cubit.dart | 2 +- lib/logic/models/server_details.dart | 6 +- lib/logic/models/server_details.g.dart | 2 +- lib/logic/models/server_status.dart | 55 ++++++++++++++ .../components/brand_timer/brand_timer.dart | 3 +- lib/ui/pages/initializing/initializing.dart | 17 +++-- 14 files changed, 262 insertions(+), 57 deletions(-) create mode 100644 lib/logic/models/server_status.dart diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 2b3e7348..43fe023c 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -10,6 +10,8 @@ PODS: - Flutter - url_launcher (0.0.1): - Flutter + - wakelock (0.0.1): + - Flutter DEPENDENCIES: - Flutter (from `Flutter`) @@ -18,6 +20,7 @@ DEPENDENCIES: - path_provider (from `.symlinks/plugins/path_provider/ios`) - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) - url_launcher (from `.symlinks/plugins/url_launcher/ios`) + - wakelock (from `.symlinks/plugins/wakelock/ios`) EXTERNAL SOURCES: Flutter: @@ -32,6 +35,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/shared_preferences/ios" url_launcher: :path: ".symlinks/plugins/url_launcher/ios" + wakelock: + :path: ".symlinks/plugins/wakelock/ios" SPEC CHECKSUMS: Flutter: 0e3d915762c693b495b44d77113d4970485de6ec @@ -40,6 +45,7 @@ SPEC CHECKSUMS: path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef + wakelock: bfc7955c418d0db797614075aabbc58a39ab5107 PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c diff --git a/lib/config/hive_config.dart b/lib/config/hive_config.dart index 6f02ffb1..1c852e23 100644 --- a/lib/config/hive_config.dart +++ b/lib/config/hive_config.dart @@ -47,7 +47,9 @@ class BNames { static String hetznerKey = 'hetznerKey'; static String cloudFlareKey = 'cloudFlareKey'; static String rootUser = 'rootUser'; - static String hetznerServer = 'server'; + static String hetznerServer = 'hetznerServer'; + static String isDkimSetted = 'isDkimSetted'; static String isDnsChecked = 'isDnsChecked'; - static String serverInitStart = 'serverInitStart'; + + static String isServerStarted = 'isServerStarted'; } diff --git a/lib/logic/api_maps/api_map.dart b/lib/logic/api_maps/api_map.dart index f67077d4..a7c8949f 100644 --- a/lib/logic/api_maps/api_map.dart +++ b/lib/logic/api_maps/api_map.dart @@ -1,14 +1,26 @@ +import 'dart:developer'; +import 'dart:io'; + +import 'package:dio/adapter.dart'; import 'package:dio/dio.dart'; import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/logic/get_it/console.dart'; import 'package:selfprivacy/logic/models/message.dart'; abstract class ApiMap { + ApiMap() { + var client = Dio()..interceptors.add(ConsoleInterceptor()); + (client.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = + (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) => true; + return client; + }; + loggedClient = client; + } String rootAddress; - // Dio client = Dio(); - - Dio loggedClient = Dio()..interceptors.add(ConsoleInterceptor()); + Dio loggedClient; void close() { loggedClient.close(); @@ -45,7 +57,7 @@ class ConsoleInterceptor extends InterceptorsWrapper { @override Future onError(DioError err) async { var response = err.response; - + log(err.toString()); addMessage( Message.warn( text: diff --git a/lib/logic/api_maps/cloudflare.dart b/lib/logic/api_maps/cloudflare.dart index 5ead436c..eea03a61 100644 --- a/lib/logic/api_maps/cloudflare.dart +++ b/lib/logic/api_maps/cloudflare.dart @@ -7,7 +7,8 @@ import 'package:selfprivacy/logic/models/dns_records.dart'; class CloudflareApi extends ApiMap { CloudflareApi([String token]) { if (token != null) { - loggedClient.options = BaseOptions(headers: {'Authorization': 'Bearer $token'}); + loggedClient.options = + BaseOptions(headers: {'Authorization': 'Bearer $token'}); } } @@ -116,12 +117,18 @@ class CloudflareApi extends ApiMap { await Future.wait(allFutures); } - // createSDKIM(String dkim) { - // var txt3 = DnsRecords( - // type: 'TXT', - // name: 'selector._domainkey', - // content: dkim, - // ttl: 18000, - // ); - // } + setDkim(String dkimRecordString, String domainZoneId) { + var txt3 = DnsRecords( + type: 'TXT', + name: 'selector._domainkey', + content: dkimRecordString, + ttl: 18000, + ); + + var url = '$rootAddress/zones/$domainZoneId/dns_records'; + loggedClient.post( + url, + data: txt3.toJson(), + ); + } } diff --git a/lib/logic/api_maps/server.dart b/lib/logic/api_maps/server.dart index 44204ca6..d13261e0 100644 --- a/lib/logic/api_maps/server.dart +++ b/lib/logic/api_maps/server.dart @@ -1,12 +1,47 @@ +import 'dart:convert'; +import 'dart:io'; + 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'}); + ServerApi(String domainName) { + loggedClient.options = BaseOptions( + baseUrl: 'https://api.$domainName', + ); + } + + Future isHttpServerWorking() async { + bool res; + + Response response; + try { + response = await loggedClient.get('/serviceStatus'); + res = response.statusCode == HttpStatus.ok; + } catch (e) { + res = false; } + + return res; + } + + Future getDkim(String domainName) async { + var response = await loggedClient.get( + '/getDKIM', + options: Options(responseType: ResponseType.plain), + ); + return _decodeAndCutData(response.data, domainName); } } + +String _decodeAndCutData(String text, String domainName) { + var decodedTextString = text.substring(1, text.length - 1); + var stringToBase64 = utf8.fuse(base64); + + return stringToBase64 + .decode(decodedTextString) + .replaceAll("selector._domainkey IN TXT ( ", "") + .replaceAll("\"\n \"", "") + .replaceAll(' ) ; ----- DKIM key selector for $domainName\n', ''); +} diff --git a/lib/logic/cubit/app_config/app_config_cubit.dart b/lib/logic/cubit/app_config/app_config_cubit.dart index abb31b5d..7d2ee9d3 100644 --- a/lib/logic/cubit/app_config/app_config_cubit.dart +++ b/lib/logic/cubit/app_config/app_config_cubit.dart @@ -1,5 +1,8 @@ +import 'dart:async'; + import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; +import 'package:flutter/foundation.dart'; import 'package:selfprivacy/logic/models/cloudflare_domain.dart'; import 'package:selfprivacy/logic/models/server_details.dart'; @@ -9,6 +12,18 @@ import 'app_config_repository.dart'; part 'app_config_state.dart'; +/// initializeing steps: |setHetznerKey +/// 1. Hetzner key |setCloudFlare +/// 2. Cloudflare key |setCloudflareKey +/// 3. Set Domain address |setDomain +/// 4. Set Root user name password |setRootUser +/// 5. Set Create server ans set DNS-Records |createServerAndSetDnsRecords +/// (without start) +/// 6. ChecksAndSets: +/// 6.1 checkDnsAndStartServer |checkDnsAndStartServer +/// 6.2 setDkim |setDkim +/// (checkServer + getDkim + Set DKIM) + class AppConfigCubit extends Cubit { AppConfigCubit() : super(InitialAppConfigState()); @@ -29,7 +44,7 @@ class AppConfigCubit extends Cubit { emit(state.copyWith(hetznerKey: hetznerKey)); } - void setCloudFlare(String cloudFlareKey) { + void setCloudflareKey(String cloudFlareKey) { repository.saveCloudFlare(cloudFlareKey); emit(state.copyWith(cloudFlareKey: cloudFlareKey)); } @@ -44,7 +59,30 @@ class AppConfigCubit extends Cubit { emit(state.copyWith(rootUser: rootUser)); } - Future checkDns() async { + void setDkim() async { + var callBack = () async { + var isServerWorking = await repository.isHttpServerWorking( + state.cloudFlareDomain.domainName, + ); + if (!isServerWorking) { + var last = DateTime.now(); + print(last); + emit(state.copyWith(lastServerStatusCheckTime: last)); + return; + } + + await repository.setDkim( + state.cloudFlareDomain.domainName, + state.cloudFlareKey, + state.cloudFlareDomain.zoneId, + ); + emit(state.copyWith(isDkimSetted: true)); + }; + + _tryOrAddError(state, callBack); + } + + void checkDnsAndStartServer() async { var ip4 = state.hetznerServer.ip4; var domainName = state.cloudFlareDomain.domainName; @@ -58,7 +96,8 @@ class AppConfigCubit extends Cubit { repository.saveServerDetails(server); emit( state.copyWith( - isDnsCheckedAndServerStarted: true, + isDnsChecked: true, + isServerStarted: true, isLoading: false, hetznerServer: server, ), @@ -68,30 +107,39 @@ class AppConfigCubit extends Cubit { } } - void createServer() async { - emit(state.copyWith(isLoading: true)); - - try { + void createServerAndSetDnsRecords() async { + var callback = () async { var serverDetails = await repository.createServer( state.hetznerKey, state.rootUser, state.cloudFlareDomain.domainName, ); - await repository.createDnsRecords( - state.cloudFlareKey, - serverDetails.ip4, - state.cloudFlareDomain, - ); + // await repository.createDnsRecords( + // state.cloudFlareKey, + // serverDetails.ip4, + // state.cloudFlareDomain, + // ); emit(state.copyWith( isLoading: false, hetznerServer: serverDetails, )); + }; + _tryOrAddError(state, callback); + } + + FutureOr _tryOrAddError( + AppConfigState state, + AsyncCallback callback, + ) async { + emit(state.copyWith(isLoading: true)); + + try { + await callback(); } catch (e) { addError(e); - - emit(state.copyWith(isLoading: false)); + emit(state); } } } diff --git a/lib/logic/cubit/app_config/app_config_repository.dart b/lib/logic/cubit/app_config/app_config_repository.dart index 8633be9e..0fa639b3 100644 --- a/lib/logic/cubit/app_config/app_config_repository.dart +++ b/lib/logic/cubit/app_config/app_config_repository.dart @@ -2,6 +2,7 @@ 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/api_maps/server.dart'; import 'package:selfprivacy/logic/models/cloudflare_domain.dart'; import 'package:selfprivacy/logic/models/server_details.dart'; import 'package:selfprivacy/logic/models/user.dart'; @@ -21,7 +22,9 @@ class AppConfigRepository { cloudFlareDomain: box.get(BNames.cloudFlareDomain), rootUser: box.get(BNames.rootUser), hetznerServer: box.get(BNames.hetznerServer), - isDnsCheckedAndServerStarted: box.get(BNames.isDnsChecked), + isServerStarted: box.get(BNames.isServerStarted, defaultValue: false), + isDnsChecked: box.get(BNames.isDnsChecked, defaultValue: false), + isDkimSetted: box.get(BNames.isDkimSetted, defaultValue: false), ); } @@ -52,6 +55,7 @@ class AppConfigRepository { var hetznerApi = HetznerApi(hetznerKey); var serverDetails = await hetznerApi.startServer(server: hetznerServer); hetznerApi.close(); + box.put(BNames.isServerStarted, true); return serverDetails; } @@ -92,6 +96,8 @@ class AppConfigRepository { } } + box.put(BNames.isDnsChecked, true); + return true; } @@ -117,14 +123,36 @@ class AppConfigRepository { String ip4, CloudFlareDomain cloudFlareDomain, ) async { - var cloudflareApi = CloudflareApi(cloudFlareKey); await cloudflareApi.createMultipleDnsRecords( ip4: ip4, cloudFlareDomain: cloudFlareDomain, ); - + + cloudflareApi.close(); + } + + Future isHttpServerWorking(String domainName) async { + var api = ServerApi(domainName); + var isHttpServerWorking = await api.isHttpServerWorking(); + print('isHttpServerWorking: $isHttpServerWorking'); + api.close(); + return isHttpServerWorking; + } + + Future setDkim( + String domainName, + String cloudFlareKey, + String zoneId, + ) async { + var api = ServerApi(domainName); + var dkimRecordString = await api.getDkim(domainName); + var cloudflareApi = CloudflareApi(cloudFlareKey); + + await cloudflareApi.setDkim(dkimRecordString, zoneId); + box.put(BNames.isDkimSetted, true); + 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 1acb6763..aa6ecb6b 100644 --- a/lib/logic/cubit/app_config/app_config_state.dart +++ b/lib/logic/cubit/app_config/app_config_state.dart @@ -7,10 +7,12 @@ class AppConfigState extends Equatable { this.cloudFlareDomain, this.rootUser, this.hetznerServer, - this.isDnsCheckedAndServerStarted = false, this.isLoading = false, this.error, this.lastDnsCheckTime, + this.lastServerStatusCheckTime, + this.isDnsChecked = false, + this.isServerStarted = false, this.isDkimSetted = false, }); @@ -25,6 +27,7 @@ class AppConfigState extends Equatable { isLoading, error, lastDnsCheckTime, + lastServerStatusCheckTime, isDkimSetted, ]; @@ -33,10 +36,11 @@ class AppConfigState extends Equatable { final CloudFlareDomain cloudFlareDomain; final User rootUser; final HetznerServerDetails hetznerServer; - final bool isDnsCheckedAndServerStarted; final bool isDkimSetted; + final bool isServerStarted; + final bool isDnsChecked; final DateTime lastDnsCheckTime; - + final DateTime lastServerStatusCheckTime; final bool isLoading; final Exception error; @@ -46,11 +50,13 @@ class AppConfigState extends Equatable { CloudFlareDomain cloudFlareDomain, User rootUser, HetznerServerDetails hetznerServer, - bool isDnsCheckedAndServerStarted, bool isLoading, Exception error, DateTime lastDnsCheckTime, + DateTime lastServerStatusCheckTime, bool isDkimSetted, + bool isServerStarted, + bool isDnsChecked, }) => AppConfigState( hetznerKey: hetznerKey ?? this.hetznerKey, @@ -58,12 +64,14 @@ class AppConfigState extends Equatable { cloudFlareDomain: cloudFlareDomain ?? this.cloudFlareDomain, rootUser: rootUser ?? this.rootUser, hetznerServer: hetznerServer ?? this.hetznerServer, - isDnsCheckedAndServerStarted: - isDnsCheckedAndServerStarted ?? this.isDnsCheckedAndServerStarted, + isServerStarted: isServerStarted ?? this.isServerStarted, + isDnsChecked: isDnsChecked ?? this.isDnsChecked, isLoading: isLoading ?? this.isLoading, error: error ?? this.error, lastDnsCheckTime: lastDnsCheckTime ?? this.lastDnsCheckTime, - isDkimSetted: isDkimSetted, + lastServerStatusCheckTime: + lastServerStatusCheckTime ?? this.lastServerStatusCheckTime, + isDkimSetted: isDkimSetted ?? this.isDkimSetted, ); bool get isHetznerFilled => hetznerKey != null; @@ -73,6 +81,8 @@ class AppConfigState extends Equatable { bool get isServerFilled => hetznerServer != null; bool get hasFinalChecked => isDnsCheckedAndServerStarted && isDkimSetted; + bool get isDnsCheckedAndServerStarted => isDnsChecked && isServerStarted; + bool get isFullyInitilized => _fulfilementList.every((el) => el); int get progress => _fulfilementList.where((el) => el).length; diff --git a/lib/logic/cubit/forms/initializing/cloudflare_form_cubit.dart b/lib/logic/cubit/forms/initializing/cloudflare_form_cubit.dart index dc0796cb..ff51401c 100644 --- a/lib/logic/cubit/forms/initializing/cloudflare_form_cubit.dart +++ b/lib/logic/cubit/forms/initializing/cloudflare_form_cubit.dart @@ -25,7 +25,7 @@ class CloudFlareFormCubit extends FormCubit { @override FutureOr onSubmit() async { - initializingCubit.setCloudFlare(apiKey.state.value); + initializingCubit.setCloudflareKey(apiKey.state.value); } final AppConfigCubit initializingCubit; diff --git a/lib/logic/models/server_details.dart b/lib/logic/models/server_details.dart index fd51d30f..ae0ff7e3 100644 --- a/lib/logic/models/server_details.dart +++ b/lib/logic/models/server_details.dart @@ -18,12 +18,12 @@ class HetznerServerDetails { @HiveField(1) final int id; - @HiveField(2) - final DateTime startTime; - @HiveField(3) final DateTime createTime; + @HiveField(2) + final DateTime startTime; + HetznerServerDetails copyWith({DateTime startTime}) { return HetznerServerDetails( startTime: startTime ?? this.startTime, diff --git a/lib/logic/models/server_details.g.dart b/lib/logic/models/server_details.g.dart index 8561c135..fe05f186 100644 --- a/lib/logic/models/server_details.g.dart +++ b/lib/logic/models/server_details.g.dart @@ -19,8 +19,8 @@ class HetznerServerDetailsAdapter extends TypeAdapter { return HetznerServerDetails( ip4: fields[0] as String, id: fields[1] as int, - createTime: fields[3] as DateTime, startTime: fields[2] as DateTime, + createTime: fields[3] as DateTime, ); } diff --git a/lib/logic/models/server_status.dart b/lib/logic/models/server_status.dart new file mode 100644 index 00000000..af1165c1 --- /dev/null +++ b/lib/logic/models/server_status.dart @@ -0,0 +1,55 @@ +import 'package:flutter/foundation.dart'; + +class ServerStatus { + final StatusTypes http; + final StatusTypes imap; + final StatusTypes smtp; + + ServerStatus({ + @required this.http, + this.imap = StatusTypes.nodata, + this.smtp = StatusTypes.nodata, + }); + + ServerStatus fromJson(Map json) { + return ServerStatus( + http: statusTypeFromNumber(json['http']), + imap: statusTypeFromNumber(json['imap']), + smtp: statusTypeFromNumber(json['smtp']), + ); + } +} + +StatusTypes statusTypeFromNumber(int number) { + if (number == 0) { + return StatusTypes.ok; + } else if (number == 1) { + return StatusTypes.error; + } else if (number == 2) { + return StatusTypes.wrongArgument; + } else if (number == 3) { + return StatusTypes.wrongFunction; + } else if (number == 4) { + return StatusTypes.noRights; + } else if (number == 5) { + return StatusTypes.notInstalled; + } else if (number == 6) { + return StatusTypes.notConfigured; + } else if (number == 7) { + return StatusTypes.off; + } else { + throw Exception('wrong status'); + } +} + +enum StatusTypes { + ok, + error, + wrongArgument, + wrongFunction, + noRights, + notInstalled, + notConfigured, + off, + nodata, +} diff --git a/lib/ui/components/brand_timer/brand_timer.dart b/lib/ui/components/brand_timer/brand_timer.dart index 2dd67cdc..a365c39b 100644 --- a/lib/ui/components/brand_timer/brand_timer.dart +++ b/lib/ui/components/brand_timer/brand_timer.dart @@ -73,7 +73,8 @@ class _BrandTimerState extends State { String _durationToString(Duration duration) { String twoDigits(int n) => n.toString().padLeft(2, "0"); - String twoDigitSeconds = twoDigits(60 - duration.inSeconds.remainder(60)); + String twoDigitSeconds = + twoDigits(widget.duration.inSeconds - duration.inSeconds.remainder(60)); return "$twoDigitSeconds cек"; } diff --git a/lib/ui/pages/initializing/initializing.dart b/lib/ui/pages/initializing/initializing.dart index 39512a91..cbad8b03 100644 --- a/lib/ui/pages/initializing/initializing.dart +++ b/lib/ui/pages/initializing/initializing.dart @@ -270,7 +270,8 @@ class InitializingPage extends StatelessWidget { BrandText.body2('Создать сервер'), Spacer(), BrandButton.rised( - onPressed: isLoading ? null : appConfigCubit.createServer, + onPressed: + isLoading ? null : appConfigCubit.createServerAndSetDnsRecords, title: isLoading ? 'loading' : 'Создать сервер', ), Spacer(flex: 2), @@ -285,7 +286,7 @@ class InitializingPage extends StatelessWidget { Widget _stepCheck(AppConfigCubit appConfigCubit) { var state = appConfigCubit.state; - var isDnsChecked = appConfigCubit.state.isDnsCheckedAndServerStarted; + var isDnsChecked = state.isDnsCheckedAndServerStarted; return Builder(builder: (context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -303,19 +304,19 @@ class InitializingPage extends StatelessWidget { BrandText.body2('До следующей проверки: '), isDnsChecked ? BrandTimer( - startDateTime: - state.lastDnsCheckTime ?? state.hetznerServer.createTime, + startDateTime: state.lastServerStatusCheckTime ?? + state.hetznerServer.startTime, duration: Duration(minutes: 1), callback: () { - appConfigCubit.checkDns(); + appConfigCubit.setDkim(); }, ) : BrandTimer( - startDateTime: - state.lastDnsCheckTime ?? state.hetznerServer.createTime, + startDateTime: state.lastDnsCheckTime ?? + state.hetznerServer.createTime, duration: Duration(minutes: 1), callback: () { - appConfigCubit.checkDns(); + appConfigCubit.checkDnsAndStartServer(); }, ) ],