mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-02-04 07:20:39 +00:00
feat: Adapt Desired DNS Records checking for Digital Ocean
This commit is contained in:
parent
120a8fc644
commit
3b962c5f5a
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue