From 7b2540640fd9ab133e4eac7dde06de472514651a Mon Sep 17 00:00:00 2001 From: NaiJi Date: Wed, 22 Mar 2023 21:28:16 -0300 Subject: [PATCH] chore: Rewrite server installation function on api level for Digital Ocean --- .../digital_ocean/digital_ocean_api.dart | 56 ++++++++++++++++- lib/logic/providers/server_provider.dart | 1 + .../server_providers/digital_ocean.dart | 60 +++++++++++++++++++ 3 files changed, 116 insertions(+), 1 deletion(-) 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 0d25dc2b..264f227d 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 @@ -306,7 +306,61 @@ class DigitalOceanApi extends ServerProviderApi with VolumeProviderApi { ); } - Future> createServer({ + Future createServer({ + required final String dnsApiToken, + required final String dnsProviderType, + required final String serverApiToken, + required final User rootUser, + required final String base64Password, + required final String databasePassword, + required final String domainName, + required final String hostName, + required final int volumeId, + required final String serverType, + }) async { + final String stagingAcme = StagingOptions.stagingAcme ? 'true' : 'false'; + + Response? serverCreateResponse; + final Dio client = await getClient(); + try { + final Map data = { + 'name': hostName, + 'size': serverType, + 'image': 'ubuntu-20-04-x64', + 'user_data': '#cloud-config\n' + 'runcmd:\n' + '- curl https://git.selfprivacy.org/SelfPrivacy/selfprivacy-nixos-infect/raw/branch/providers/digital-ocean/nixos-infect | ' + "PROVIDER=$infectProviderName DNS_PROVIDER_TYPE=$dnsProviderType STAGING_ACME='$stagingAcme' DOMAIN='$domainName' " + "LUSER='${rootUser.login}' ENCODED_PASSWORD='$base64Password' CF_TOKEN=$dnsApiToken DB_PASSWORD=$databasePassword " + 'API_TOKEN=$serverApiToken HOSTNAME=$hostName bash 2>&1 | tee /tmp/infect.log', + 'region': region!, + }; + print('Decoded data: $data'); + + serverCreateResponse = await client.post( + '/droplets', + data: data, + ); + } catch (e) { + print(e); + return GenericResult( + success: false, + data: null, + message: e.toString(), + ); + } finally { + close(client); + } + + return GenericResult( + data: serverCreateResponse, + success: true, + code: serverCreateResponse.statusCode, + message: serverCreateResponse.statusMessage, + ); + } + + Future> creatfgdfeServer({ required final String dnsApiToken, required final User rootUser, required final String domainName, diff --git a/lib/logic/providers/server_provider.dart b/lib/logic/providers/server_provider.dart index 519307e8..7a2f4a02 100644 --- a/lib/logic/providers/server_provider.dart +++ b/lib/logic/providers/server_provider.dart @@ -6,6 +6,7 @@ import 'package:selfprivacy/logic/models/server_provider_location.dart'; import 'package:selfprivacy/logic/models/server_type.dart'; export 'package:selfprivacy/logic/api_maps/generic_result.dart'; +export 'package:selfprivacy/logic/models/launch_installation_data.dart'; abstract class ServerProvider { Future> trySetServerLocation(final String location); diff --git a/lib/logic/providers/server_providers/digital_ocean.dart b/lib/logic/providers/server_providers/digital_ocean.dart index df7af648..4393f80e 100644 --- a/lib/logic/providers/server_providers/digital_ocean.dart +++ b/lib/logic/providers/server_providers/digital_ocean.dart @@ -1,8 +1,11 @@ +import 'dart:convert'; + import 'package:easy_localization/easy_localization.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/server_providers/digital_ocean/digital_ocean_api.dart'; import 'package:selfprivacy/logic/models/callback_dialogue_branching.dart'; import 'package:selfprivacy/logic/models/disk_size.dart'; import 'package:selfprivacy/logic/models/hive/server_details.dart'; +import 'package:selfprivacy/logic/models/hive/server_domain.dart'; import 'package:selfprivacy/logic/models/metrics.dart'; import 'package:selfprivacy/logic/models/price.dart'; import 'package:selfprivacy/logic/models/server_basic_info.dart'; @@ -12,6 +15,7 @@ import 'package:selfprivacy/logic/models/server_type.dart'; import 'package:selfprivacy/logic/providers/server_provider.dart'; import 'package:selfprivacy/utils/extensions/string_extensions.dart'; import 'package:selfprivacy/utils/network_utils.dart'; +import 'package:selfprivacy/utils/password_generator.dart'; class ApiAdapter { ApiAdapter({final String? region, final bool isWithToken = true}) @@ -111,6 +115,62 @@ class DigitalOceanServerProvider extends ServerProvider { return emoji; } + String dnsProviderToInfectName(final DnsProviderType dnsProvider) { + String dnsProviderType; + switch (dnsProvider) { + case DnsProviderType.digitalOcean: + dnsProviderType = 'DIGITALOCEAN'; + break; + case DnsProviderType.cloudflare: + default: + dnsProviderType = 'CLOUDFLARE'; + break; + } + return dnsProviderType; + } + + @override + Future> launchInstallation( + final LaunchInstallationData installationData, + ) async { + final serverResult = await _adapter.api().createServer( + dnsApiToken: installationData.dnsApiToken, + rootUser: installationData.rootUser, + domainName: installationData.domainName, + serverType: installationData.serverTypeId, + dnsProviderType: + dnsProviderToInfectName(installationData.dnsProviderType), + hostName: getHostnameFromDomain(installationData.domainName), + base64Password: base64.encode( + utf8.encode(installationData.rootUser.password ?? 'PASS'), + ), + databasePassword: StringGenerators.dbPassword(), + serverApiToken: StringGenerators.apiToken(), + ); + + if (!serverResult.success || serverResult.data == null) { + GenericResult( + data: CallbackDialogueBranching( + choices: [ + CallbackDialogueChoice( + title: 'basis.cancel'.tr(), + callback: await installationData.errorCallback(), + ), + CallbackDialogueChoice( + title: 'basis.try_again'.tr(), + callback: () async => launchInstallation(installationData), + ), + ], + description: serverResult.message ?? 'recovering.generic_error'.tr(), + title: 'modals.unexpected_error'.tr(), + ), + success: false, + message: serverResult.message, + code: serverResult.code, + ); + } + } + @override Future>> getAvailableLocations() async {