feat: Adapt Desired DNS Records checking for Digital Ocean

This commit is contained in:
NaiJi 2023-01-11 22:01:46 +04:00
parent 120a8fc644
commit 3b962c5f5a
7 changed files with 261 additions and 147 deletions

View File

@ -189,6 +189,88 @@ class CloudflareApi extends DnsProviderApi {
return allRecords;
}
@override
List<DesiredDnsRecord> getDesiredDnsRecords({
final String? domainName,
final String? ipAddress,
final String? dkimPublicKey,
}) {
if (domainName == null || ipAddress == null) {
return [];
}
return [
DesiredDnsRecord(
name: domainName,
content: ipAddress,
description: 'record.root',
),
DesiredDnsRecord(
name: 'api.$domainName',
content: ipAddress,
description: 'record.api',
),
DesiredDnsRecord(
name: 'cloud.$domainName',
content: ipAddress,
description: 'record.cloud',
),
DesiredDnsRecord(
name: 'git.$domainName',
content: ipAddress,
description: 'record.git',
),
DesiredDnsRecord(
name: 'meet.$domainName',
content: ipAddress,
description: 'record.meet',
),
DesiredDnsRecord(
name: 'social.$domainName',
content: ipAddress,
description: 'record.social',
),
DesiredDnsRecord(
name: 'password.$domainName',
content: ipAddress,
description: 'record.password',
),
DesiredDnsRecord(
name: 'vpn.$domainName',
content: ipAddress,
description: 'record.vpn',
),
DesiredDnsRecord(
name: domainName,
content: domainName,
description: 'record.mx',
type: 'MX',
category: DnsRecordsCategory.email,
),
DesiredDnsRecord(
name: '_dmarc.$domainName',
content: 'v=DMARC1; p=none',
description: 'record.dmarc',
type: 'TXT',
category: DnsRecordsCategory.email,
),
DesiredDnsRecord(
name: domainName,
content: 'v=spf1 a mx ip4:$ipAddress -all',
description: 'record.spf',
type: 'TXT',
category: DnsRecordsCategory.email,
),
if (dkimPublicKey != null)
DesiredDnsRecord(
name: 'selector._domainkey.$domainName',
content: dkimPublicKey,
description: 'record.dkim',
type: 'TXT',
category: DnsRecordsCategory.email,
),
];
}
@override
Future<APIGenericResult<void>> createMultipleDnsRecords({
required final ServerDomain domain,

View File

@ -0,0 +1,44 @@
enum DnsRecordsCategory {
services,
email,
other,
}
class DesiredDnsRecord {
const DesiredDnsRecord({
required this.name,
required this.content,
this.type = 'A',
this.description = '',
this.category = DnsRecordsCategory.services,
this.isSatisfied = false,
this.displayName,
});
final String name;
final String type;
final String content;
final String description;
final String? displayName;
final DnsRecordsCategory category;
final bool isSatisfied;
DesiredDnsRecord copyWith({
final String? name,
final String? type,
final String? content,
final String? description,
final String? displayName,
final DnsRecordsCategory? category,
final bool? isSatisfied,
}) =>
DesiredDnsRecord(
name: name ?? this.name,
type: type ?? this.type,
content: content ?? this.content,
description: description ?? this.description,
category: category ?? this.category,
isSatisfied: isSatisfied ?? this.isSatisfied,
displayName: displayName ?? this.displayName,
);
}

View File

@ -171,6 +171,96 @@ class DigitalOceanDnsApi extends DnsProviderApi {
return allRecords;
}
@override
List<DesiredDnsRecord> getDesiredDnsRecords({
final String? domainName,
final String? ipAddress,
final String? dkimPublicKey,
}) {
if (domainName == null || ipAddress == null) {
return [];
}
return [
DesiredDnsRecord(
name: '@',
content: ipAddress,
description: 'record.root',
displayName: domainName,
),
DesiredDnsRecord(
name: 'api',
content: ipAddress,
description: 'record.api',
displayName: 'api.$domainName',
),
DesiredDnsRecord(
name: 'cloud',
content: ipAddress,
description: 'record.cloud',
displayName: 'cloud.$domainName',
),
DesiredDnsRecord(
name: 'git',
content: ipAddress,
description: 'record.git',
displayName: 'git.$domainName',
),
DesiredDnsRecord(
name: 'meet',
content: ipAddress,
description: 'record.meet',
displayName: 'meet.$domainName',
),
DesiredDnsRecord(
name: 'social',
content: ipAddress,
description: 'record.social',
displayName: 'social.$domainName',
),
DesiredDnsRecord(
name: 'password',
content: ipAddress,
description: 'record.password',
displayName: 'password.$domainName',
),
DesiredDnsRecord(
name: 'vpn',
content: ipAddress,
description: 'record.vpn',
displayName: 'vpn.$domainName',
),
DesiredDnsRecord(
name: domainName,
content: domainName,
description: 'record.mx',
type: 'MX',
category: DnsRecordsCategory.email,
),
DesiredDnsRecord(
name: '_dmarc.$domainName',
content: 'v=DMARC1; p=none',
description: 'record.dmarc',
type: 'TXT',
category: DnsRecordsCategory.email,
),
DesiredDnsRecord(
name: domainName,
content: 'v=spf1 a mx ip4:$ipAddress -all',
description: 'record.spf',
type: 'TXT',
category: DnsRecordsCategory.email,
),
if (dkimPublicKey != null)
DesiredDnsRecord(
name: 'selector._domainkey.$domainName',
content: dkimPublicKey,
description: 'record.dkim',
type: 'TXT',
category: DnsRecordsCategory.email,
),
];
}
@override
Future<APIGenericResult<void>> createMultipleDnsRecords({
required final ServerDomain domain,

View File

@ -1,9 +1,11 @@
import 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
import 'package:selfprivacy/logic/api_maps/rest_maps/api_map.dart';
import 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/desired_dns_record.dart';
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
import 'package:selfprivacy/logic/models/json/dns_records.dart';
export 'package:selfprivacy/logic/api_maps/api_generic_result.dart';
export 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/desired_dns_record.dart';
class DomainNotFoundException implements Exception {
DomainNotFoundException(this.message);
@ -14,6 +16,11 @@ abstract class DnsProviderApi extends ApiMap {
Future<List<DnsRecord>> getDnsRecords({
required final ServerDomain domain,
});
List<DesiredDnsRecord> getDesiredDnsRecords({
final String? domainName,
final String? ipAddress,
final String? dkimPublicKey,
});
Future<APIGenericResult<void>> removeSimilarRecords({
required final ServerDomain domain,
final String? ip4,

View File

@ -25,11 +25,14 @@ class DnsRecordsCubit
emit(
DnsRecordsState(
dnsState: DnsRecordsStatus.refreshing,
dnsRecords: getDesiredDnsRecords(
serverInstallationCubit.state.serverDomain?.domainName,
'',
'',
),
dnsRecords: ApiController.currentDnsProviderApiFactory!
.getDnsProvider()
.getDesiredDnsRecords(
domainName:
serverInstallationCubit.state.serverDomain?.domainName,
dkimPublicKey: '',
ipAddress: '',
),
),
);
@ -44,16 +47,23 @@ class DnsRecordsCubit
.getDnsRecords(domain: domain);
final String? dkimPublicKey =
extractDkimRecord(await api.getDnsRecords())?.content;
final List<DesiredDnsRecord> desiredRecords =
getDesiredDnsRecords(domain.domainName, ipAddress, dkimPublicKey);
final List<DesiredDnsRecord> desiredRecords = ApiController
.currentDnsProviderApiFactory!
.getDnsProvider()
.getDesiredDnsRecords(
domainName: domain.domainName,
ipAddress: ipAddress,
dkimPublicKey: dkimPublicKey,
);
final List<DesiredDnsRecord> foundRecords = [];
for (final DesiredDnsRecord record in desiredRecords) {
if (record.description == 'record.dkim') {
for (final DesiredDnsRecord desiredRecord in desiredRecords) {
if (desiredRecord.description == 'record.dkim') {
final DnsRecord foundRecord = records.firstWhere(
(final r) => r.name == record.name && r.type == record.type,
(final r) =>
r.name == desiredRecord.name && r.type == desiredRecord.type,
orElse: () => DnsRecord(
name: record.name,
type: record.type,
name: desiredRecord.name,
type: desiredRecord.type,
content: '',
ttl: 800,
proxied: false,
@ -65,22 +75,22 @@ class DnsRecordsCubit
final String? foundContent =
foundRecord.content?.replaceAll(RegExp(r'\s+'), '');
final String content =
record.content.replaceAll(RegExp(r'\s+'), '');
desiredRecord.content.replaceAll(RegExp(r'\s+'), '');
if (foundContent == content) {
foundRecords.add(record.copyWith(isSatisfied: true));
foundRecords.add(desiredRecord.copyWith(isSatisfied: true));
} else {
foundRecords.add(record.copyWith(isSatisfied: false));
foundRecords.add(desiredRecord.copyWith(isSatisfied: false));
}
} else {
if (records.any(
(final r) =>
r.name == record.name &&
r.type == record.type &&
r.content == record.content,
r.name == desiredRecord.name &&
r.type == desiredRecord.type &&
r.content == desiredRecord.content,
)) {
foundRecords.add(record.copyWith(isSatisfied: true));
foundRecords.add(desiredRecord.copyWith(isSatisfied: true));
} else {
foundRecords.add(record.copyWith(isSatisfied: false));
foundRecords.add(desiredRecord.copyWith(isSatisfied: false));
}
}
}

View File

@ -1,12 +1,12 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:selfprivacy/config/get_it_config.dart';
import 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/desired_dns_record.dart';
import 'package:selfprivacy/logic/cubit/server_installation/server_installation_cubit.dart';
import 'package:selfprivacy/logic/cubit/dns_records/dns_records_cubit.dart';
import 'package:selfprivacy/ui/components/brand_cards/filled_card.dart';
import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.dart';
import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart';
import 'package:selfprivacy/utils/network_utils.dart';
class DnsDetailsPage extends StatefulWidget {
const DnsDetailsPage({super.key});
@ -109,9 +109,12 @@ class _DnsDetailsPageState extends State<DnsDetailsPage> {
heroIcon: BrandIcons.globe,
heroTitle: 'domain.screen_title'.tr(),
children: <Widget>[
_getStateCard(dnsCubit.dnsState, () {
context.read<DnsRecordsCubit>().fix();
}),
_getStateCard(
dnsCubit.dnsState,
() {
context.read<DnsRecordsCubit>().fix();
},
),
const SizedBox(height: 16.0),
ListTile(
title: Text(
@ -150,7 +153,7 @@ class _DnsDetailsPageState extends State<DnsDetailsPage> {
dnsRecord.description.tr(),
),
subtitle: Text(
dnsRecord.name,
dnsRecord.displayName ?? dnsRecord.name,
),
),
],

View File

@ -1,128 +1,6 @@
import 'package:selfprivacy/logic/models/json/dns_records.dart';
import 'package:url_launcher/url_launcher.dart';
enum DnsRecordsCategory {
services,
email,
other,
}
class DesiredDnsRecord {
const DesiredDnsRecord({
required this.name,
required this.content,
this.type = 'A',
this.description = '',
this.category = DnsRecordsCategory.services,
this.isSatisfied = false,
});
final String name;
final String type;
final String content;
final String description;
final DnsRecordsCategory category;
final bool isSatisfied;
DesiredDnsRecord copyWith({
final String? name,
final String? type,
final String? content,
final String? description,
final DnsRecordsCategory? category,
final bool? isSatisfied,
}) =>
DesiredDnsRecord(
name: name ?? this.name,
type: type ?? this.type,
content: content ?? this.content,
description: description ?? this.description,
category: category ?? this.category,
isSatisfied: isSatisfied ?? this.isSatisfied,
);
}
List<DesiredDnsRecord> getDesiredDnsRecords(
final String? domainName,
final String? ipAddress,
final String? dkimPublicKey,
) {
if (domainName == null || ipAddress == null) {
return [];
}
return [
DesiredDnsRecord(
name: domainName,
content: ipAddress,
description: 'record.root',
),
DesiredDnsRecord(
name: 'api.$domainName',
content: ipAddress,
description: 'record.api',
),
DesiredDnsRecord(
name: 'cloud.$domainName',
content: ipAddress,
description: 'record.cloud',
),
DesiredDnsRecord(
name: 'git.$domainName',
content: ipAddress,
description: 'record.git',
),
DesiredDnsRecord(
name: 'meet.$domainName',
content: ipAddress,
description: 'record.meet',
),
DesiredDnsRecord(
name: 'social.$domainName',
content: ipAddress,
description: 'record.social',
),
DesiredDnsRecord(
name: 'password.$domainName',
content: ipAddress,
description: 'record.password',
),
DesiredDnsRecord(
name: 'vpn.$domainName',
content: ipAddress,
description: 'record.vpn',
),
DesiredDnsRecord(
name: domainName,
content: domainName,
description: 'record.mx',
type: 'MX',
category: DnsRecordsCategory.email,
),
DesiredDnsRecord(
name: '_dmarc.$domainName',
content: 'v=DMARC1; p=none',
description: 'record.dmarc',
type: 'TXT',
category: DnsRecordsCategory.email,
),
DesiredDnsRecord(
name: domainName,
content: 'v=spf1 a mx ip4:$ipAddress -all',
description: 'record.spf',
type: 'TXT',
category: DnsRecordsCategory.email,
),
if (dkimPublicKey != null)
DesiredDnsRecord(
name: 'selector._domainkey.$domainName',
content: dkimPublicKey,
description: 'record.dkim',
type: 'TXT',
category: DnsRecordsCategory.email,
),
];
}
DnsRecord? extractDkimRecord(final List<DnsRecord> records) {
DnsRecord? dkimRecord;