mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2024-10-03 08:42:54 +00:00
feat: Make DNS deletion and creation dynamic
- https://git.selfprivacy.org/SelfPrivacy/selfprivacy.org.app/issues/265
This commit is contained in:
parent
9e095a6808
commit
d841f9db44
1
devtools_options.yaml
Normal file
1
devtools_options.yaml
Normal file
|
@ -0,0 +1 @@
|
|||
extensions:
|
|
@ -168,25 +168,19 @@ class DnsRecordsCubit
|
|||
|
||||
Future<void> fix() async {
|
||||
emit(state.copyWith(dnsState: DnsRecordsStatus.refreshing));
|
||||
final List<DnsRecord> records = await api.getDnsRecords();
|
||||
|
||||
/// TODO: Error handling?
|
||||
final ServerDomain? domain = serverInstallationCubit.state.serverDomain;
|
||||
final String? ipAddress = serverInstallationCubit.state.serverDetails?.ip4;
|
||||
await ProvidersController.currentDnsProvider!.removeDomainRecords(
|
||||
records: records,
|
||||
domain: domain!,
|
||||
);
|
||||
await ProvidersController.currentDnsProvider!.createDomainRecords(
|
||||
records: records,
|
||||
domain: domain,
|
||||
ip4: ipAddress,
|
||||
);
|
||||
|
||||
final List<DnsRecord> records = await api.getDnsRecords();
|
||||
final DnsRecord? dkimRecord = extractDkimRecord(records);
|
||||
if (dkimRecord != null) {
|
||||
await ProvidersController.currentDnsProvider!.setDnsRecord(
|
||||
dkimRecord,
|
||||
domain,
|
||||
);
|
||||
}
|
||||
|
||||
await load();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -264,12 +264,20 @@ class ServerInstallationCubit extends Cubit<ServerInstallationState> {
|
|||
final ServerHostingDetails serverDetails,
|
||||
) async {
|
||||
await repository.saveServerDetails(serverDetails);
|
||||
|
||||
/// TODO: Error handling?
|
||||
await ProvidersController.currentDnsProvider!.removeDomainRecords(
|
||||
ip4: serverDetails.ip4,
|
||||
records: getProjectDnsRecords(
|
||||
state.serverDomain!.domainName,
|
||||
serverDetails.ip4,
|
||||
),
|
||||
domain: state.serverDomain!,
|
||||
);
|
||||
await ProvidersController.currentDnsProvider!.createDomainRecords(
|
||||
ip4: serverDetails.ip4,
|
||||
records: getProjectDnsRecords(
|
||||
state.serverDomain!.domainName,
|
||||
serverDetails.ip4,
|
||||
),
|
||||
domain: state.serverDomain!,
|
||||
);
|
||||
|
||||
|
|
|
@ -558,14 +558,30 @@ class ServerInstallationRepository {
|
|||
}
|
||||
|
||||
Future<bool> deleteServer(final ServerDomain serverDomain) async {
|
||||
final ServerApi api = ServerApi();
|
||||
final dnsRecords = await api.getDnsRecords();
|
||||
final GenericResult<void> removalResult =
|
||||
await ProvidersController.currentDnsProvider!.removeDomainRecords(
|
||||
domain: serverDomain,
|
||||
records: dnsRecords,
|
||||
);
|
||||
|
||||
if (!removalResult.success) {
|
||||
getIt<NavigationService>().showSnackBar(
|
||||
'modals.dns_removal_error'.tr(),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
final deletionResult =
|
||||
await ProvidersController.currentServerProvider!.deleteServer(
|
||||
serverDomain.domainName,
|
||||
);
|
||||
|
||||
if (!deletionResult.success) {
|
||||
getIt<NavigationService>()
|
||||
.showSnackBar('modals.server_validators_error'.tr());
|
||||
getIt<NavigationService>().showSnackBar(
|
||||
'modals.server_validators_error'.tr(),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -576,13 +592,6 @@ class ServerInstallationRepository {
|
|||
await box.put(BNames.isLoading, false);
|
||||
await box.put(BNames.serverDetails, null);
|
||||
|
||||
final GenericResult<void> removalResult = await ProvidersController
|
||||
.currentDnsProvider!
|
||||
.removeDomainRecords(domain: serverDomain);
|
||||
|
||||
if (!removalResult.success) {
|
||||
getIt<NavigationService>().showSnackBar('modals.dns_removal_error'.tr());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
|||
import 'package:selfprivacy/logic/models/json/dns_providers/cloudflare_dns_info.dart';
|
||||
import 'package:selfprivacy/logic/models/json/dns_records.dart';
|
||||
import 'package:selfprivacy/logic/providers/dns_providers/dns_provider.dart';
|
||||
import 'package:selfprivacy/utils/network_utils.dart';
|
||||
|
||||
class ApiAdapter {
|
||||
ApiAdapter({
|
||||
|
@ -80,15 +79,14 @@ class CloudflareDnsProvider extends DnsProvider {
|
|||
|
||||
@override
|
||||
Future<GenericResult<void>> createDomainRecords({
|
||||
required final List<DnsRecord> records,
|
||||
required final ServerDomain domain,
|
||||
final String? ip4,
|
||||
}) async {
|
||||
final syncZoneIdResult = await syncZoneId(domain.domainName);
|
||||
if (!syncZoneIdResult.success) {
|
||||
return syncZoneIdResult;
|
||||
}
|
||||
|
||||
final records = getProjectDnsRecords(domain.domainName, ip4);
|
||||
return _adapter.api().createMultipleDnsRecords(
|
||||
zoneId: _adapter.cachedZoneId,
|
||||
records: records
|
||||
|
@ -102,16 +100,17 @@ class CloudflareDnsProvider extends DnsProvider {
|
|||
|
||||
@override
|
||||
Future<GenericResult<void>> removeDomainRecords({
|
||||
required final List<DnsRecord> records,
|
||||
required final ServerDomain domain,
|
||||
final String? ip4,
|
||||
}) async {
|
||||
final syncZoneIdResult = await syncZoneId(domain.domainName);
|
||||
if (!syncZoneIdResult.success) {
|
||||
return syncZoneIdResult;
|
||||
}
|
||||
|
||||
final result =
|
||||
await _adapter.api().getDnsRecords(zoneId: _adapter.cachedZoneId);
|
||||
final result = await _adapter.api().getDnsRecords(
|
||||
zoneId: _adapter.cachedZoneId,
|
||||
);
|
||||
if (result.data.isEmpty || !result.success) {
|
||||
return GenericResult(
|
||||
success: result.success,
|
||||
|
@ -121,9 +120,29 @@ class CloudflareDnsProvider extends DnsProvider {
|
|||
);
|
||||
}
|
||||
|
||||
final List<CloudflareDnsRecord> selfprivacyRecords = records
|
||||
.map(
|
||||
(final record) => CloudflareDnsRecord.fromDnsRecord(
|
||||
record,
|
||||
domain.domainName,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
final List<CloudflareDnsRecord> cloudflareRecords = result.data;
|
||||
|
||||
/// Remove all records that do not match with SelfPrivacy
|
||||
cloudflareRecords.removeWhere(
|
||||
(final oceanRecord) => !selfprivacyRecords.any(
|
||||
(final selfprivacyRecord) =>
|
||||
selfprivacyRecord.type == oceanRecord.type &&
|
||||
selfprivacyRecord.name == oceanRecord.name,
|
||||
),
|
||||
);
|
||||
|
||||
return _adapter.api().removeSimilarRecords(
|
||||
zoneId: _adapter.cachedZoneId,
|
||||
records: result.data,
|
||||
records: cloudflareRecords,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
|||
import 'package:selfprivacy/logic/models/json/dns_providers/desec_dns_info.dart';
|
||||
import 'package:selfprivacy/logic/models/json/dns_records.dart';
|
||||
import 'package:selfprivacy/logic/providers/dns_providers/dns_provider.dart';
|
||||
import 'package:selfprivacy/utils/network_utils.dart';
|
||||
|
||||
class ApiAdapter {
|
||||
ApiAdapter({final bool isWithToken = true})
|
||||
|
@ -75,16 +74,11 @@ class DesecDnsProvider extends DnsProvider {
|
|||
|
||||
@override
|
||||
Future<GenericResult<void>> createDomainRecords({
|
||||
required final List<DnsRecord> records,
|
||||
required final ServerDomain domain,
|
||||
final String? ip4,
|
||||
}) async {
|
||||
final List<DnsRecord> listDnsRecords = getProjectDnsRecords(
|
||||
domain.domainName,
|
||||
ip4,
|
||||
);
|
||||
|
||||
final List<DesecDnsRecord> bulkRecords = [];
|
||||
for (final DnsRecord record in listDnsRecords) {
|
||||
for (final DnsRecord record in records) {
|
||||
bulkRecords.add(DesecDnsRecord.fromDnsRecord(record, domain.domainName));
|
||||
}
|
||||
|
||||
|
@ -96,21 +90,19 @@ class DesecDnsProvider extends DnsProvider {
|
|||
|
||||
@override
|
||||
Future<GenericResult<void>> removeDomainRecords({
|
||||
required final List<DnsRecord> records,
|
||||
required final ServerDomain domain,
|
||||
final String? ip4,
|
||||
}) async {
|
||||
final List<DnsRecord> listDnsRecords = getProjectDnsRecords(
|
||||
domain.domainName,
|
||||
ip4,
|
||||
);
|
||||
|
||||
final List<DesecDnsRecord> bulkRecords = [];
|
||||
for (final DnsRecord record in listDnsRecords) {
|
||||
for (final DnsRecord record in records) {
|
||||
final desecRecord = DesecDnsRecord.fromDnsRecord(
|
||||
record,
|
||||
domain.domainName,
|
||||
);
|
||||
bulkRecords.add(
|
||||
/// Yes, it looks weird, but exactly forcing 'records' field
|
||||
/// to empty array signals deSEC to remove the DNS record completely
|
||||
/// https://desec.readthedocs.io/en/latest/dns/rrsets.html#deleting-an-rrset
|
||||
DesecDnsRecord(
|
||||
subname: desecRecord.subname,
|
||||
type: desecRecord.type,
|
||||
|
@ -119,14 +111,6 @@ class DesecDnsProvider extends DnsProvider {
|
|||
),
|
||||
);
|
||||
}
|
||||
bulkRecords.add(
|
||||
DesecDnsRecord(
|
||||
subname: 'selector._domainkey',
|
||||
type: 'TXT',
|
||||
ttl: 18000,
|
||||
records: [],
|
||||
),
|
||||
);
|
||||
|
||||
return _adapter.api().removeSimilarRecords(
|
||||
domainName: domain.domainName,
|
||||
|
|
|
@ -3,7 +3,6 @@ import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
|||
import 'package:selfprivacy/logic/models/json/dns_providers/digital_ocean_dns_info.dart';
|
||||
import 'package:selfprivacy/logic/models/json/dns_records.dart';
|
||||
import 'package:selfprivacy/logic/providers/dns_providers/dns_provider.dart';
|
||||
import 'package:selfprivacy/utils/network_utils.dart';
|
||||
|
||||
class ApiAdapter {
|
||||
ApiAdapter({final bool isWithToken = true})
|
||||
|
@ -75,15 +74,12 @@ class DigitalOceanDnsProvider extends DnsProvider {
|
|||
|
||||
@override
|
||||
Future<GenericResult<void>> createDomainRecords({
|
||||
required final List<DnsRecord> records,
|
||||
required final ServerDomain domain,
|
||||
final String? ip4,
|
||||
}) async =>
|
||||
_adapter.api().createMultipleDnsRecords(
|
||||
domainName: domain.domainName,
|
||||
records: getProjectDnsRecords(
|
||||
domain.domainName,
|
||||
ip4,
|
||||
)
|
||||
records: records
|
||||
.map<DigitalOceanDnsRecord>(
|
||||
(final e) =>
|
||||
DigitalOceanDnsRecord.fromDnsRecord(e, domain.domainName),
|
||||
|
@ -93,8 +89,8 @@ class DigitalOceanDnsProvider extends DnsProvider {
|
|||
|
||||
@override
|
||||
Future<GenericResult<void>> removeDomainRecords({
|
||||
required final List<DnsRecord> records,
|
||||
required final ServerDomain domain,
|
||||
final String? ip4,
|
||||
}) async {
|
||||
final result = await _adapter.api().getDnsRecords(domain.domainName);
|
||||
if (result.data.isEmpty || !result.success) {
|
||||
|
@ -106,17 +102,29 @@ class DigitalOceanDnsProvider extends DnsProvider {
|
|||
);
|
||||
}
|
||||
|
||||
const ignoreType = 'SOA';
|
||||
final List<DigitalOceanDnsRecord> filteredRecords = [];
|
||||
for (final record in result.data) {
|
||||
if (record.type != ignoreType) {
|
||||
filteredRecords.add(record);
|
||||
}
|
||||
}
|
||||
final List<DigitalOceanDnsRecord> selfprivacyRecords = records
|
||||
.map(
|
||||
(final record) => DigitalOceanDnsRecord.fromDnsRecord(
|
||||
record,
|
||||
domain.domainName,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
|
||||
final List<DigitalOceanDnsRecord> oceanRecords = result.data;
|
||||
|
||||
/// Remove all records that do not match with SelfPrivacy
|
||||
oceanRecords.removeWhere(
|
||||
(final oceanRecord) => !selfprivacyRecords.any(
|
||||
(final selfprivacyRecord) =>
|
||||
selfprivacyRecord.type == oceanRecord.type &&
|
||||
selfprivacyRecord.name == oceanRecord.name,
|
||||
),
|
||||
);
|
||||
|
||||
return _adapter.api().removeSimilarRecords(
|
||||
domainName: domain.domainName,
|
||||
records: filteredRecords,
|
||||
records: oceanRecords,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,23 +23,21 @@ abstract class DnsProvider {
|
|||
/// Returns list of all available domain entries assigned to the account.
|
||||
Future<GenericResult<List<ServerDomain>>> domainList();
|
||||
|
||||
/// Tries to create all main domain records needed
|
||||
/// for SelfPrivacy to launch on requested domain by ip4.
|
||||
/// Tries to create domain records
|
||||
/// by our records list.
|
||||
///
|
||||
/// Doesn't check for duplication, cleaning has
|
||||
/// to be done beforehand by [removeDomainRecords]
|
||||
Future<GenericResult<void>> createDomainRecords({
|
||||
required final List<DnsRecord> records,
|
||||
required final ServerDomain domain,
|
||||
final String? ip4,
|
||||
});
|
||||
|
||||
/// Tries to remove all domain records of requested domain by ip4.
|
||||
///
|
||||
/// Will remove all entries, including the ones
|
||||
/// that weren't created by SelfPrivacy.
|
||||
/// Tries to remove all records of requested
|
||||
/// domain that match our records list.
|
||||
Future<GenericResult<void>> removeDomainRecords({
|
||||
required final List<DnsRecord> records,
|
||||
required final ServerDomain domain,
|
||||
final String? ip4,
|
||||
});
|
||||
|
||||
/// Returns list of all [DnsRecord] entries assigned to requested domain.
|
||||
|
|
Loading…
Reference in a new issue