import 'package:basic_utils/basic_utils.dart'; import 'package:dio/dio.dart'; import 'package:easy_localization/easy_localization.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/cloudflare.dart'; import 'package:selfprivacy/logic/api_maps/hetzner.dart'; import 'package:selfprivacy/logic/api_maps/server.dart'; import 'package:selfprivacy/logic/models/hive/backblaze_credential.dart'; import 'package:selfprivacy/logic/models/hive/server_domain.dart'; import 'package:selfprivacy/logic/models/message.dart'; import 'package:selfprivacy/logic/models/hive/server_details.dart'; import 'package:selfprivacy/logic/models/hive/user.dart'; import 'package:selfprivacy/ui/components/action_button/action_button.dart'; import 'package:selfprivacy/ui/components/brand_alert/brand_alert.dart'; import '../server_installation/server_installation_cubit.dart'; class ServerInstallationRepository { Box box = Hive.box(BNames.serverInstallation); Future load() async { final hetznerToken = getIt().hetznerKey; final cloudflareToken = getIt().cloudFlareKey; final serverDomain = getIt().serverDomain; final backblazeCredential = getIt().backblazeCredential; final serverDetails = getIt().serverDetails; if (box.get(BNames.hasFinalChecked, defaultValue: false)) { return ServerInstallationFinished( hetznerKey: hetznerToken!, cloudFlareKey: cloudflareToken!, 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 (getIt().serverDomain?.provider == DnsProvider.Unknown) { return ServerInstallationRecovery( hetznerKey: hetznerToken, cloudFlareKey: cloudflareToken, serverDomain: serverDomain, backblazeCredential: backblazeCredential, serverDetails: serverDetails, rootUser: box.get(BNames.rootUser), currentStep: _getCurrentRecoveryStep( hetznerToken, cloudflareToken, serverDomain!, serverDetails), ); } return ServerInstallationNotFinished( hetznerKey: hetznerToken, cloudFlareKey: cloudflareToken, 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), isLoading: box.get(BNames.isLoading, defaultValue: false), dnsMatches: null, ); } RecoveryStep _getCurrentRecoveryStep( String? hetznerToken, String? cloudflareToken, ServerDomain serverDomain, ServerHostingDetails? serverDetails, ) { if (serverDetails != null) { if (hetznerToken != null) { if (cloudflareToken != null) { return RecoveryStep.BackblazeToken; } return RecoveryStep.CloudflareToken; } return RecoveryStep.HetznerToken; } return RecoveryStep.Selecting; } void clearAppConfig() { box.clear(); } Future startServer( ServerHostingDetails hetznerServer, ) async { var hetznerApi = HetznerApi(); var serverDetails = await hetznerApi.powerOn(); return serverDetails; } Future> isDnsAddressesMatch(String? domainName, String? ip4, Map? skippedMatches) async { var addresses = [ '$domainName', 'api.$domainName', 'cloud.$domainName', 'meet.$domainName', 'password.$domainName' ]; var matches = {}; for (var address in addresses) { if (skippedMatches != null && skippedMatches[address] == true) { matches[address] = true; continue; } 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 == null ? 'empty' : (lookupRecordRes[0].data != ip4 ? 'wrong ip4' : 'right ip4')}', ), ); if (lookupRecordRes == null || lookupRecordRes.isEmpty || lookupRecordRes[0].data != ip4) { matches[address] = false; } else { matches[address] = true; } } return matches; } Future createServer( User rootUser, String domainName, String cloudFlareKey, BackblazeCredential backblazeCredential, { required void Function() onCancel, required Future Function(ServerHostingDetails serverDetails) onSuccess, }) async { var hetznerApi = HetznerApi(); late ServerVolume dataBase; try { dataBase = await hetznerApi.createVolume(); var serverDetails = await hetznerApi.createServer( cloudFlareKey: cloudFlareKey, rootUser: rootUser, domainName: domainName, dataBase: dataBase, ); saveServerDetails(serverDetails); onSuccess(serverDetails); } on DioError catch (e) { if (e.response!.data['error']['code'] == 'uniqueness_error') { var nav = getIt.get(); nav.showPopUpDialog( BrandAlert( title: 'modals.1'.tr(), contentText: 'modals.2'.tr(), actions: [ ActionButton( text: 'basis.delete'.tr(), isRed: true, onPressed: () async { await hetznerApi.deleteSelfprivacyServerAndAllVolumes( domainName: domainName); var serverDetails = await hetznerApi.createServer( cloudFlareKey: cloudFlareKey, rootUser: rootUser, domainName: domainName, dataBase: dataBase, ); await saveServerDetails(serverDetails); onSuccess(serverDetails); }, ), ActionButton( text: 'basis.cancel'.tr(), onPressed: () { onCancel(); }, ), ], ), ); } } } Future createDnsRecords( String ip4, ServerDomain cloudFlareDomain, { required void Function() onCancel, }) async { var cloudflareApi = CloudflareApi(); await cloudflareApi.removeSimilarRecords( ip4: ip4, cloudFlareDomain: cloudFlareDomain, ); try { await cloudflareApi.createMultipleDnsRecords( ip4: ip4, cloudFlareDomain: cloudFlareDomain, ); } on DioError catch (e) { var hetznerApi = HetznerApi(); var nav = getIt.get(); nav.showPopUpDialog( BrandAlert( title: e.response!.data["errors"][0]["code"] == 1038 ? 'modals.10'.tr() : 'providers.domain.states.error'.tr(), contentText: 'modals.6'.tr(), actions: [ ActionButton( text: 'basis.delete'.tr(), isRed: true, onPressed: () async { await hetznerApi.deleteSelfprivacyServerAndAllVolumes( domainName: cloudFlareDomain.domainName); onCancel(); }, ), ActionButton( text: 'basis.cancel'.tr(), onPressed: () { onCancel(); }, ), ], ), ); } await HetznerApi().createReverseDns( ip4: ip4, domainName: cloudFlareDomain.domainName, ); } Future createDkimRecord(ServerDomain cloudFlareDomain) async { var cloudflareApi = CloudflareApi(); var api = ServerApi(); var dkimRecordString = await api.getDkim(); await cloudflareApi.setDkim(dkimRecordString ?? "", cloudFlareDomain); } Future isHttpServerWorking() async { var api = ServerApi(); var isHttpServerWorking = await api.isHttpServerWorking(); try { await api.getDkim(); } catch (e) { return false; } return isHttpServerWorking; } Future restart() async { var hetznerApi = HetznerApi(); return await hetznerApi.reset(); } Future powerOn() async { var hetznerApi = HetznerApi(); return await hetznerApi.powerOn(); } Future saveServerDetails(ServerHostingDetails serverDetails) async { await getIt().storeServerDetails(serverDetails); } Future saveHetznerKey(String key) async { print('saved'); await getIt().storeHetznerKey(key); } Future saveBackblazeKey(BackblazeCredential backblazeCredential) async { await getIt().storeBackblazeCredential(backblazeCredential); } Future saveCloudFlareKey(String key) async { await getIt().storeCloudFlareKey(key); } Future saveDomain(ServerDomain serverDomain) async { await getIt().storeServerDomain(serverDomain); } Future saveIsServerStarted(bool value) async { await box.put(BNames.isServerStarted, value); } Future saveIsServerResetedFirstTime(bool value) async { await box.put(BNames.isServerResetedFirstTime, value); } Future saveIsServerResetedSecondTime(bool value) async { await box.put(BNames.isServerResetedSecondTime, value); } Future saveRootUser(User rootUser) async { await box.put(BNames.rootUser, rootUser); } Future saveHasFinalChecked(bool value) async { await box.put(BNames.hasFinalChecked, value); } Future deleteServer(ServerDomain serverDomain) async { var hetznerApi = HetznerApi(); var cloudFlare = CloudflareApi(); await hetznerApi.deleteSelfprivacyServerAndAllVolumes( domainName: serverDomain.domainName, ); 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); await cloudFlare.removeSimilarRecords(cloudFlareDomain: serverDomain); } Future deleteRecords() async { await box.deleteAll([ BNames.serverDetails, BNames.isServerStarted, BNames.isServerResetedFirstTime, BNames.isServerResetedSecondTime, BNames.hasFinalChecked, BNames.isLoading, ]); getIt().init(); } }