mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-01-25 18:26:36 +00:00
refactor: Move DNS records validation to cubit layer
This commit is contained in:
parent
ada5f1a66c
commit
1c07476764
|
@ -5529,11 +5529,10 @@ extension ClientExtension$Mutation$RemoveRepository on graphql.GraphQLClient {
|
||||||
mutate$RemoveRepository(
|
mutate$RemoveRepository(
|
||||||
[Options$Mutation$RemoveRepository? options]) async =>
|
[Options$Mutation$RemoveRepository? options]) async =>
|
||||||
await this.mutate(options ?? Options$Mutation$RemoveRepository());
|
await this.mutate(options ?? Options$Mutation$RemoveRepository());
|
||||||
graphql.ObservableQuery<Mutation$RemoveRepository>
|
graphql.ObservableQuery<
|
||||||
watchMutation$RemoveRepository(
|
Mutation$RemoveRepository> watchMutation$RemoveRepository(
|
||||||
[WatchOptions$Mutation$RemoveRepository? options]) =>
|
[WatchOptions$Mutation$RemoveRepository? options]) =>
|
||||||
this.watchMutation(
|
this.watchMutation(options ?? WatchOptions$Mutation$RemoveRepository());
|
||||||
options ?? WatchOptions$Mutation$RemoveRepository());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Mutation$RemoveRepository$backup {
|
class Mutation$RemoveRepository$backup {
|
||||||
|
|
|
@ -150,6 +150,7 @@ type DnsRecord {
|
||||||
recordType: String!
|
recordType: String!
|
||||||
name: String!
|
name: String!
|
||||||
content: String!
|
content: String!
|
||||||
|
displayName: String!
|
||||||
ttl: Int!
|
ttl: Int!
|
||||||
priority: Int
|
priority: Int
|
||||||
}
|
}
|
||||||
|
|
|
@ -4440,11 +4440,10 @@ extension ClientExtension$Mutation$RunSystemRebuild on graphql.GraphQLClient {
|
||||||
mutate$RunSystemRebuild(
|
mutate$RunSystemRebuild(
|
||||||
[Options$Mutation$RunSystemRebuild? options]) async =>
|
[Options$Mutation$RunSystemRebuild? options]) async =>
|
||||||
await this.mutate(options ?? Options$Mutation$RunSystemRebuild());
|
await this.mutate(options ?? Options$Mutation$RunSystemRebuild());
|
||||||
graphql.ObservableQuery<Mutation$RunSystemRebuild>
|
graphql.ObservableQuery<
|
||||||
watchMutation$RunSystemRebuild(
|
Mutation$RunSystemRebuild> watchMutation$RunSystemRebuild(
|
||||||
[WatchOptions$Mutation$RunSystemRebuild? options]) =>
|
[WatchOptions$Mutation$RunSystemRebuild? options]) =>
|
||||||
this.watchMutation(
|
this.watchMutation(options ?? WatchOptions$Mutation$RunSystemRebuild());
|
||||||
options ?? WatchOptions$Mutation$RunSystemRebuild());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Mutation$RunSystemRebuild$runSystemRebuild
|
class Mutation$RunSystemRebuild$runSystemRebuild
|
||||||
|
@ -4883,11 +4882,10 @@ extension ClientExtension$Mutation$RunSystemRollback on graphql.GraphQLClient {
|
||||||
mutate$RunSystemRollback(
|
mutate$RunSystemRollback(
|
||||||
[Options$Mutation$RunSystemRollback? options]) async =>
|
[Options$Mutation$RunSystemRollback? options]) async =>
|
||||||
await this.mutate(options ?? Options$Mutation$RunSystemRollback());
|
await this.mutate(options ?? Options$Mutation$RunSystemRollback());
|
||||||
graphql.ObservableQuery<Mutation$RunSystemRollback>
|
graphql.ObservableQuery<
|
||||||
watchMutation$RunSystemRollback(
|
Mutation$RunSystemRollback> watchMutation$RunSystemRollback(
|
||||||
[WatchOptions$Mutation$RunSystemRollback? options]) =>
|
[WatchOptions$Mutation$RunSystemRollback? options]) =>
|
||||||
this.watchMutation(
|
this.watchMutation(options ?? WatchOptions$Mutation$RunSystemRollback());
|
||||||
options ?? WatchOptions$Mutation$RunSystemRollback());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Mutation$RunSystemRollback$runSystemRollback
|
class Mutation$RunSystemRollback$runSystemRollback
|
||||||
|
@ -5324,11 +5322,10 @@ extension ClientExtension$Mutation$RunSystemUpgrade on graphql.GraphQLClient {
|
||||||
mutate$RunSystemUpgrade(
|
mutate$RunSystemUpgrade(
|
||||||
[Options$Mutation$RunSystemUpgrade? options]) async =>
|
[Options$Mutation$RunSystemUpgrade? options]) async =>
|
||||||
await this.mutate(options ?? Options$Mutation$RunSystemUpgrade());
|
await this.mutate(options ?? Options$Mutation$RunSystemUpgrade());
|
||||||
graphql.ObservableQuery<Mutation$RunSystemUpgrade>
|
graphql.ObservableQuery<
|
||||||
watchMutation$RunSystemUpgrade(
|
Mutation$RunSystemUpgrade> watchMutation$RunSystemUpgrade(
|
||||||
[WatchOptions$Mutation$RunSystemUpgrade? options]) =>
|
[WatchOptions$Mutation$RunSystemUpgrade? options]) =>
|
||||||
this.watchMutation(
|
this.watchMutation(options ?? WatchOptions$Mutation$RunSystemUpgrade());
|
||||||
options ?? WatchOptions$Mutation$RunSystemUpgrade());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Mutation$RunSystemUpgrade$runSystemUpgrade
|
class Mutation$RunSystemUpgrade$runSystemUpgrade
|
||||||
|
@ -11384,11 +11381,10 @@ extension ClientExtension$Mutation$GetNewDeviceApiKey on graphql.GraphQLClient {
|
||||||
mutate$GetNewDeviceApiKey(
|
mutate$GetNewDeviceApiKey(
|
||||||
[Options$Mutation$GetNewDeviceApiKey? options]) async =>
|
[Options$Mutation$GetNewDeviceApiKey? options]) async =>
|
||||||
await this.mutate(options ?? Options$Mutation$GetNewDeviceApiKey());
|
await this.mutate(options ?? Options$Mutation$GetNewDeviceApiKey());
|
||||||
graphql.ObservableQuery<Mutation$GetNewDeviceApiKey>
|
graphql.ObservableQuery<
|
||||||
watchMutation$GetNewDeviceApiKey(
|
Mutation$GetNewDeviceApiKey> watchMutation$GetNewDeviceApiKey(
|
||||||
[WatchOptions$Mutation$GetNewDeviceApiKey? options]) =>
|
[WatchOptions$Mutation$GetNewDeviceApiKey? options]) =>
|
||||||
this.watchMutation(
|
this.watchMutation(options ?? WatchOptions$Mutation$GetNewDeviceApiKey());
|
||||||
options ?? WatchOptions$Mutation$GetNewDeviceApiKey());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Mutation$GetNewDeviceApiKey$getNewDeviceApiKey
|
class Mutation$GetNewDeviceApiKey$getNewDeviceApiKey
|
||||||
|
|
|
@ -25,6 +25,7 @@ query SystemIsUsingBinds {
|
||||||
fragment fragmentDnsRecords on DnsRecord {
|
fragment fragmentDnsRecords on DnsRecord {
|
||||||
recordType
|
recordType
|
||||||
name
|
name
|
||||||
|
displayName
|
||||||
content
|
content
|
||||||
ttl
|
ttl
|
||||||
priority
|
priority
|
||||||
|
|
|
@ -8,6 +8,7 @@ class Fragment$fragmentDnsRecords {
|
||||||
Fragment$fragmentDnsRecords({
|
Fragment$fragmentDnsRecords({
|
||||||
required this.recordType,
|
required this.recordType,
|
||||||
required this.name,
|
required this.name,
|
||||||
|
required this.displayName,
|
||||||
required this.content,
|
required this.content,
|
||||||
required this.ttl,
|
required this.ttl,
|
||||||
this.priority,
|
this.priority,
|
||||||
|
@ -17,6 +18,7 @@ class Fragment$fragmentDnsRecords {
|
||||||
factory Fragment$fragmentDnsRecords.fromJson(Map<String, dynamic> json) {
|
factory Fragment$fragmentDnsRecords.fromJson(Map<String, dynamic> json) {
|
||||||
final l$recordType = json['recordType'];
|
final l$recordType = json['recordType'];
|
||||||
final l$name = json['name'];
|
final l$name = json['name'];
|
||||||
|
final l$displayName = json['displayName'];
|
||||||
final l$content = json['content'];
|
final l$content = json['content'];
|
||||||
final l$ttl = json['ttl'];
|
final l$ttl = json['ttl'];
|
||||||
final l$priority = json['priority'];
|
final l$priority = json['priority'];
|
||||||
|
@ -24,6 +26,7 @@ class Fragment$fragmentDnsRecords {
|
||||||
return Fragment$fragmentDnsRecords(
|
return Fragment$fragmentDnsRecords(
|
||||||
recordType: (l$recordType as String),
|
recordType: (l$recordType as String),
|
||||||
name: (l$name as String),
|
name: (l$name as String),
|
||||||
|
displayName: (l$displayName as String),
|
||||||
content: (l$content as String),
|
content: (l$content as String),
|
||||||
ttl: (l$ttl as int),
|
ttl: (l$ttl as int),
|
||||||
priority: (l$priority as int?),
|
priority: (l$priority as int?),
|
||||||
|
@ -35,6 +38,8 @@ class Fragment$fragmentDnsRecords {
|
||||||
|
|
||||||
final String name;
|
final String name;
|
||||||
|
|
||||||
|
final String displayName;
|
||||||
|
|
||||||
final String content;
|
final String content;
|
||||||
|
|
||||||
final int ttl;
|
final int ttl;
|
||||||
|
@ -49,6 +54,8 @@ class Fragment$fragmentDnsRecords {
|
||||||
_resultData['recordType'] = l$recordType;
|
_resultData['recordType'] = l$recordType;
|
||||||
final l$name = name;
|
final l$name = name;
|
||||||
_resultData['name'] = l$name;
|
_resultData['name'] = l$name;
|
||||||
|
final l$displayName = displayName;
|
||||||
|
_resultData['displayName'] = l$displayName;
|
||||||
final l$content = content;
|
final l$content = content;
|
||||||
_resultData['content'] = l$content;
|
_resultData['content'] = l$content;
|
||||||
final l$ttl = ttl;
|
final l$ttl = ttl;
|
||||||
|
@ -64,6 +71,7 @@ class Fragment$fragmentDnsRecords {
|
||||||
int get hashCode {
|
int get hashCode {
|
||||||
final l$recordType = recordType;
|
final l$recordType = recordType;
|
||||||
final l$name = name;
|
final l$name = name;
|
||||||
|
final l$displayName = displayName;
|
||||||
final l$content = content;
|
final l$content = content;
|
||||||
final l$ttl = ttl;
|
final l$ttl = ttl;
|
||||||
final l$priority = priority;
|
final l$priority = priority;
|
||||||
|
@ -71,6 +79,7 @@ class Fragment$fragmentDnsRecords {
|
||||||
return Object.hashAll([
|
return Object.hashAll([
|
||||||
l$recordType,
|
l$recordType,
|
||||||
l$name,
|
l$name,
|
||||||
|
l$displayName,
|
||||||
l$content,
|
l$content,
|
||||||
l$ttl,
|
l$ttl,
|
||||||
l$priority,
|
l$priority,
|
||||||
|
@ -97,6 +106,11 @@ class Fragment$fragmentDnsRecords {
|
||||||
if (l$name != lOther$name) {
|
if (l$name != lOther$name) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
final l$displayName = displayName;
|
||||||
|
final lOther$displayName = other.displayName;
|
||||||
|
if (l$displayName != lOther$displayName) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
final l$content = content;
|
final l$content = content;
|
||||||
final lOther$content = other.content;
|
final lOther$content = other.content;
|
||||||
if (l$content != lOther$content) {
|
if (l$content != lOther$content) {
|
||||||
|
@ -142,6 +156,7 @@ abstract class CopyWith$Fragment$fragmentDnsRecords<TRes> {
|
||||||
TRes call({
|
TRes call({
|
||||||
String? recordType,
|
String? recordType,
|
||||||
String? name,
|
String? name,
|
||||||
|
String? displayName,
|
||||||
String? content,
|
String? content,
|
||||||
int? ttl,
|
int? ttl,
|
||||||
int? priority,
|
int? priority,
|
||||||
|
@ -165,6 +180,7 @@ class _CopyWithImpl$Fragment$fragmentDnsRecords<TRes>
|
||||||
TRes call({
|
TRes call({
|
||||||
Object? recordType = _undefined,
|
Object? recordType = _undefined,
|
||||||
Object? name = _undefined,
|
Object? name = _undefined,
|
||||||
|
Object? displayName = _undefined,
|
||||||
Object? content = _undefined,
|
Object? content = _undefined,
|
||||||
Object? ttl = _undefined,
|
Object? ttl = _undefined,
|
||||||
Object? priority = _undefined,
|
Object? priority = _undefined,
|
||||||
|
@ -177,6 +193,9 @@ class _CopyWithImpl$Fragment$fragmentDnsRecords<TRes>
|
||||||
name: name == _undefined || name == null
|
name: name == _undefined || name == null
|
||||||
? _instance.name
|
? _instance.name
|
||||||
: (name as String),
|
: (name as String),
|
||||||
|
displayName: displayName == _undefined || displayName == null
|
||||||
|
? _instance.displayName
|
||||||
|
: (displayName as String),
|
||||||
content: content == _undefined || content == null
|
content: content == _undefined || content == null
|
||||||
? _instance.content
|
? _instance.content
|
||||||
: (content as String),
|
: (content as String),
|
||||||
|
@ -198,6 +217,7 @@ class _CopyWithStubImpl$Fragment$fragmentDnsRecords<TRes>
|
||||||
call({
|
call({
|
||||||
String? recordType,
|
String? recordType,
|
||||||
String? name,
|
String? name,
|
||||||
|
String? displayName,
|
||||||
String? content,
|
String? content,
|
||||||
int? ttl,
|
int? ttl,
|
||||||
int? priority,
|
int? priority,
|
||||||
|
@ -229,6 +249,13 @@ const fragmentDefinitionfragmentDnsRecords = FragmentDefinitionNode(
|
||||||
directives: [],
|
directives: [],
|
||||||
selectionSet: null,
|
selectionSet: null,
|
||||||
),
|
),
|
||||||
|
FieldNode(
|
||||||
|
name: NameNode(value: 'displayName'),
|
||||||
|
alias: null,
|
||||||
|
arguments: [],
|
||||||
|
directives: [],
|
||||||
|
selectionSet: null,
|
||||||
|
),
|
||||||
FieldNode(
|
FieldNode(
|
||||||
name: NameNode(value: 'content'),
|
name: NameNode(value: 'content'),
|
||||||
alias: null,
|
alias: null,
|
||||||
|
|
|
@ -33,16 +33,16 @@ class DnsRecordsCubit
|
||||||
final ServerDomain? domain = serverInstallationCubit.state.serverDomain;
|
final ServerDomain? domain = serverInstallationCubit.state.serverDomain;
|
||||||
final String? ipAddress =
|
final String? ipAddress =
|
||||||
serverInstallationCubit.state.serverDetails?.ip4;
|
serverInstallationCubit.state.serverDetails?.ip4;
|
||||||
if (domain == null && ipAddress == null) {
|
|
||||||
|
if (domain == null || ipAddress == null) {
|
||||||
emit(const DnsRecordsState());
|
emit(const DnsRecordsState());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<DnsRecord> allDnsRecords = await api.getDnsRecords();
|
final List<DnsRecord> allDnsRecords = await api.getDnsRecords();
|
||||||
allDnsRecords.removeWhere((final record) => record.type == 'AAAA');
|
allDnsRecords.removeWhere((final record) => record.type == 'AAAA');
|
||||||
final foundRecords =
|
final foundRecords = await validateDnsRecords(
|
||||||
await ProvidersController.currentDnsProvider!.validateDnsRecords(
|
domain,
|
||||||
domain!,
|
|
||||||
ipAddress!,
|
|
||||||
extractDkimRecord(allDnsRecords)?.content ?? '',
|
extractDkimRecord(allDnsRecords)?.content ?? '',
|
||||||
allDnsRecords,
|
allDnsRecords,
|
||||||
);
|
);
|
||||||
|
@ -63,6 +63,93 @@ class DnsRecordsCubit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tries to check whether all known DNS records on the domain by ip4
|
||||||
|
/// match expectations of SelfPrivacy in order to launch.
|
||||||
|
///
|
||||||
|
/// Will return list of [DesiredDnsRecord] objects, which represent
|
||||||
|
/// only those records which have successfully passed validation.
|
||||||
|
Future<GenericResult<List<DesiredDnsRecord>>> validateDnsRecords(
|
||||||
|
final ServerDomain domain,
|
||||||
|
final String dkimPublicKey,
|
||||||
|
final List<DnsRecord> pendingDnsRecords,
|
||||||
|
) async {
|
||||||
|
final result = await ProvidersController.currentDnsProvider!
|
||||||
|
.getDnsRecords(domain: domain);
|
||||||
|
if (result.data.isEmpty || !result.success) {
|
||||||
|
return GenericResult(
|
||||||
|
success: result.success,
|
||||||
|
data: [],
|
||||||
|
code: result.code,
|
||||||
|
message: result.message,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<DnsRecord> providerDnsRecords = result.data;
|
||||||
|
final List<DesiredDnsRecord> foundRecords = [];
|
||||||
|
try {
|
||||||
|
for (final DnsRecord pendingDnsRecord in pendingDnsRecords) {
|
||||||
|
if (pendingDnsRecord.name == 'selector._domainkey') {
|
||||||
|
final foundRecord = providerDnsRecords.firstWhere(
|
||||||
|
(final r) =>
|
||||||
|
(r.name == pendingDnsRecord.name) &&
|
||||||
|
r.type == pendingDnsRecord.type,
|
||||||
|
orElse: () => DnsRecord(
|
||||||
|
displayName: pendingDnsRecord.displayName,
|
||||||
|
name: pendingDnsRecord.name,
|
||||||
|
type: pendingDnsRecord.type,
|
||||||
|
content: pendingDnsRecord.content,
|
||||||
|
ttl: pendingDnsRecord.ttl,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
final String foundContent =
|
||||||
|
foundRecord.content!.replaceAll(RegExp(r'\s+'), '').trim();
|
||||||
|
final String desiredContent =
|
||||||
|
pendingDnsRecord.content!.replaceAll(RegExp(r'\s+'), '').trim();
|
||||||
|
final isSatisfied = (desiredContent == foundContent);
|
||||||
|
foundRecords.add(
|
||||||
|
DesiredDnsRecord(
|
||||||
|
name: pendingDnsRecord.name!,
|
||||||
|
displayName: pendingDnsRecord.displayName,
|
||||||
|
content: pendingDnsRecord.content!,
|
||||||
|
isSatisfied: isSatisfied,
|
||||||
|
type: pendingDnsRecord.type,
|
||||||
|
category: DnsRecordsCategory.email,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
final foundMatch = providerDnsRecords.any(
|
||||||
|
(final r) =>
|
||||||
|
r.name == pendingDnsRecord.name &&
|
||||||
|
r.type == pendingDnsRecord.type &&
|
||||||
|
r.content == pendingDnsRecord.content,
|
||||||
|
);
|
||||||
|
foundRecords.add(
|
||||||
|
DesiredDnsRecord(
|
||||||
|
name: pendingDnsRecord.name!,
|
||||||
|
displayName: pendingDnsRecord.displayName,
|
||||||
|
content: pendingDnsRecord.content!,
|
||||||
|
isSatisfied: foundMatch,
|
||||||
|
category: pendingDnsRecord.type == 'A'
|
||||||
|
? DnsRecordsCategory.services
|
||||||
|
: DnsRecordsCategory.email,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print(e);
|
||||||
|
return GenericResult(
|
||||||
|
data: [],
|
||||||
|
success: false,
|
||||||
|
message: e.toString(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return GenericResult(
|
||||||
|
data: foundRecords,
|
||||||
|
success: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onChange(final Change<DnsRecordsState> change) {
|
void onChange(final Change<DnsRecordsState> change) {
|
||||||
// print(change);
|
// print(change);
|
||||||
|
|
|
@ -34,13 +34,17 @@ DnsRecord _toDnsRecord(
|
||||||
String name = desecRecord.subname;
|
String name = desecRecord.subname;
|
||||||
int? priority;
|
int? priority;
|
||||||
if (type == 'MX') {
|
if (type == 'MX') {
|
||||||
name = name.isEmpty ? '@' : name;
|
name = name.isEmpty ? domainName : name;
|
||||||
final contentBulk = content.split(' ');
|
final contentBulk = content.split(' ');
|
||||||
content = contentBulk[1];
|
content = contentBulk[1];
|
||||||
|
if (content.contains(domainName)) {
|
||||||
|
content =
|
||||||
|
content.substring(0, content.length - 1); // cut away trailing dot
|
||||||
|
}
|
||||||
priority = int.parse(contentBulk[0]);
|
priority = int.parse(contentBulk[0]);
|
||||||
}
|
}
|
||||||
if (type == 'TXT' && content.isNotEmpty && content.startsWith('"')) {
|
if (type == 'TXT' && content.isNotEmpty && content.startsWith('"')) {
|
||||||
content = content.substring(1, content.length); // cut away quotes
|
content = content.substring(1, content.length - 1); // cut away quotes
|
||||||
}
|
}
|
||||||
if (name.isEmpty) {
|
if (name.isEmpty) {
|
||||||
name = domainName;
|
name = domainName;
|
||||||
|
|
|
@ -27,9 +27,7 @@ DnsRecord _toDnsRecord(
|
||||||
String convert(final String entry) => (entry == '@') ? rootDomain : entry;
|
String convert(final String entry) => (entry == '@') ? rootDomain : entry;
|
||||||
String name = digitalOceanRecord.name;
|
String name = digitalOceanRecord.name;
|
||||||
final String content = convert(digitalOceanRecord.data);
|
final String content = convert(digitalOceanRecord.data);
|
||||||
if (type != 'MX') {
|
name = (name == '@') ? rootDomain : name;
|
||||||
name = convert(name);
|
|
||||||
}
|
|
||||||
return DnsRecord(
|
return DnsRecord(
|
||||||
name: name,
|
name: name,
|
||||||
content: content,
|
content: content,
|
||||||
|
|
|
@ -9,6 +9,7 @@ class DnsRecord {
|
||||||
required this.type,
|
required this.type,
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.content,
|
required this.content,
|
||||||
|
this.displayName,
|
||||||
this.ttl = 3600,
|
this.ttl = 3600,
|
||||||
this.priority = 10,
|
this.priority = 10,
|
||||||
this.proxied = false,
|
this.proxied = false,
|
||||||
|
@ -19,12 +20,14 @@ class DnsRecord {
|
||||||
) : this(
|
) : this(
|
||||||
type: record.recordType,
|
type: record.recordType,
|
||||||
name: record.name,
|
name: record.name,
|
||||||
|
displayName: record.displayName,
|
||||||
content: record.content,
|
content: record.content,
|
||||||
ttl: record.ttl,
|
ttl: record.ttl,
|
||||||
priority: record.priority ?? 10,
|
priority: record.priority ?? 10,
|
||||||
);
|
);
|
||||||
|
|
||||||
final String type;
|
final String type;
|
||||||
|
final String? displayName;
|
||||||
final String? name;
|
final String? name;
|
||||||
final String? content;
|
final String? content;
|
||||||
final int ttl;
|
final int ttl;
|
||||||
|
|
|
@ -8,6 +8,7 @@ part of 'dns_records.dart';
|
||||||
|
|
||||||
Map<String, dynamic> _$DnsRecordToJson(DnsRecord instance) => <String, dynamic>{
|
Map<String, dynamic> _$DnsRecordToJson(DnsRecord instance) => <String, dynamic>{
|
||||||
'type': instance.type,
|
'type': instance.type,
|
||||||
|
'displayName': instance.displayName,
|
||||||
'name': instance.name,
|
'name': instance.name,
|
||||||
'content': instance.content,
|
'content': instance.content,
|
||||||
'ttl': instance.ttl,
|
'ttl': instance.ttl,
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/cloudflare/cloudflare_api.dart';
|
import 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/cloudflare/cloudflare_api.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/hive/server_domain.dart';
|
||||||
import 'package:selfprivacy/logic/models/json/dns_providers/cloudflare_dns_info.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/models/json/dns_records.dart';
|
||||||
|
@ -180,103 +179,6 @@ class CloudflareDnsProvider extends DnsProvider {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<GenericResult<List<DesiredDnsRecord>>> validateDnsRecords(
|
|
||||||
final ServerDomain domain,
|
|
||||||
final String ip4,
|
|
||||||
final String dkimPublicKey,
|
|
||||||
final List<DnsRecord> pendingDnsRecords,
|
|
||||||
) async {
|
|
||||||
final syncZoneIdResult = await syncZoneId(domain.domainName);
|
|
||||||
if (!syncZoneIdResult.success) {
|
|
||||||
return GenericResult(
|
|
||||||
success: syncZoneIdResult.success,
|
|
||||||
data: [],
|
|
||||||
code: syncZoneIdResult.code,
|
|
||||||
message: syncZoneIdResult.message,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
final result =
|
|
||||||
await _adapter.api().getDnsRecords(zoneId: _adapter.cachedZoneId);
|
|
||||||
if (result.data.isEmpty || !result.success) {
|
|
||||||
return GenericResult(
|
|
||||||
success: result.success,
|
|
||||||
data: [],
|
|
||||||
code: result.code,
|
|
||||||
message: result.message,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
final records = result.data;
|
|
||||||
final List<DesiredDnsRecord> foundRecords = [];
|
|
||||||
try {
|
|
||||||
for (final DnsRecord pendingDnsRecord in pendingDnsRecords) {
|
|
||||||
final record = CloudflareDnsRecord.fromDnsRecord(
|
|
||||||
pendingDnsRecord,
|
|
||||||
domain.domainName,
|
|
||||||
);
|
|
||||||
if (record.name == 'selector._domainkey') {
|
|
||||||
final CloudflareDnsRecord foundRecord = records.firstWhere(
|
|
||||||
(final r) => (r.name == record.name) && r.type == record.type,
|
|
||||||
orElse: () => CloudflareDnsRecord(
|
|
||||||
zoneName: domain.domainName,
|
|
||||||
name: record.name,
|
|
||||||
type: record.type,
|
|
||||||
content: '',
|
|
||||||
ttl: 800,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
// remove all spaces and tabulators from
|
|
||||||
// the foundRecord.content and the record.content
|
|
||||||
// to compare them
|
|
||||||
final String? foundContent =
|
|
||||||
foundRecord.content?.replaceAll(RegExp(r'\s+'), '');
|
|
||||||
final String content =
|
|
||||||
record.content?.replaceAll(RegExp(r'\s+'), '') ?? '';
|
|
||||||
foundRecords.add(
|
|
||||||
DesiredDnsRecord(
|
|
||||||
name: record.name ?? '',
|
|
||||||
description: record.name?.split('.')[0] ?? '',
|
|
||||||
content: record.content ?? '',
|
|
||||||
isSatisfied: foundContent == content,
|
|
||||||
type: record.type,
|
|
||||||
category: DnsRecordsCategory.email,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
final foundMatch = records.any(
|
|
||||||
(final r) =>
|
|
||||||
(r.name == record.name) &&
|
|
||||||
r.type == record.type &&
|
|
||||||
r.content == record.content,
|
|
||||||
);
|
|
||||||
foundRecords.add(
|
|
||||||
DesiredDnsRecord(
|
|
||||||
name: record.name ?? '',
|
|
||||||
description: record.name?.split('.')[0] ?? '',
|
|
||||||
content: record.content ?? '',
|
|
||||||
isSatisfied: foundMatch,
|
|
||||||
type: record.type,
|
|
||||||
category: record.type == 'A'
|
|
||||||
? DnsRecordsCategory.services
|
|
||||||
: DnsRecordsCategory.email,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
print(e);
|
|
||||||
return GenericResult(
|
|
||||||
data: [],
|
|
||||||
success: false,
|
|
||||||
message: e.toString(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return GenericResult(
|
|
||||||
data: foundRecords,
|
|
||||||
success: true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<GenericResult<void>> syncZoneId(final String domain) async {
|
Future<GenericResult<void>> syncZoneId(final String domain) async {
|
||||||
if (domain == _adapter.cachedDomain && _adapter.cachedZoneId.isNotEmpty) {
|
if (domain == _adapter.cachedDomain && _adapter.cachedZoneId.isNotEmpty) {
|
||||||
return GenericResult(
|
return GenericResult(
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/desec/desec_api.dart';
|
import 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/desec/desec_api.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/hive/server_domain.dart';
|
||||||
import 'package:selfprivacy/logic/models/json/dns_providers/desec_dns_info.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/models/json/dns_records.dart';
|
||||||
|
@ -181,91 +180,4 @@ class DesecDnsProvider extends DnsProvider {
|
||||||
data: null,
|
data: null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<GenericResult<List<DesiredDnsRecord>>> validateDnsRecords(
|
|
||||||
final ServerDomain domain,
|
|
||||||
final String ip4,
|
|
||||||
final String dkimPublicKey,
|
|
||||||
final List<DnsRecord> pendingDnsRecords,
|
|
||||||
) async {
|
|
||||||
final result = await _adapter.api().getDnsRecords(domain.domainName);
|
|
||||||
if (result.data.isEmpty || !result.success) {
|
|
||||||
return GenericResult(
|
|
||||||
success: result.success,
|
|
||||||
data: [],
|
|
||||||
code: result.code,
|
|
||||||
message: result.message,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final records = result.data;
|
|
||||||
final List<DesiredDnsRecord> foundRecords = [];
|
|
||||||
try {
|
|
||||||
for (final DnsRecord pendingDnsRecord in pendingDnsRecords) {
|
|
||||||
final record = DesecDnsRecord.fromDnsRecord(
|
|
||||||
pendingDnsRecord,
|
|
||||||
domain.domainName,
|
|
||||||
);
|
|
||||||
if (record.subname == 'selector._domainkey') {
|
|
||||||
final DesecDnsRecord foundRecord = records.firstWhere(
|
|
||||||
(final r) =>
|
|
||||||
('${r.subname}.${domain.domainName}' == record.subname) &&
|
|
||||||
r.type == record.type,
|
|
||||||
orElse: () => DesecDnsRecord(
|
|
||||||
subname: record.subname,
|
|
||||||
type: record.type,
|
|
||||||
records: [],
|
|
||||||
ttl: record.ttl,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
final desecRecords = foundRecord.records;
|
|
||||||
final content = desecRecords.isEmpty ? '' : desecRecords[0];
|
|
||||||
final String foundContent = content.replaceAll(RegExp(r'\s+'), '');
|
|
||||||
final String desiredContent =
|
|
||||||
record.records[0].replaceAll(RegExp(r'\s+'), '');
|
|
||||||
foundRecords.add(
|
|
||||||
DesiredDnsRecord(
|
|
||||||
name: '${record.subname}.${domain.domainName}',
|
|
||||||
description:
|
|
||||||
record.subname.isEmpty ? record.subname : domain.domainName,
|
|
||||||
content: record.records[0],
|
|
||||||
isSatisfied: foundContent == desiredContent,
|
|
||||||
type: record.type,
|
|
||||||
category: DnsRecordsCategory.email,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
final foundMatch = records.any(
|
|
||||||
(final r) =>
|
|
||||||
r.subname == record.subname &&
|
|
||||||
r.type == record.type &&
|
|
||||||
r.records[0] == record.records[0],
|
|
||||||
);
|
|
||||||
foundRecords.add(
|
|
||||||
DesiredDnsRecord(
|
|
||||||
name: '${record.subname}.${domain.domainName}',
|
|
||||||
description: record.subname,
|
|
||||||
content: record.records[0],
|
|
||||||
isSatisfied: foundMatch,
|
|
||||||
category: record.type == 'A'
|
|
||||||
? DnsRecordsCategory.services
|
|
||||||
: DnsRecordsCategory.email,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
print(e);
|
|
||||||
return GenericResult(
|
|
||||||
data: [],
|
|
||||||
success: false,
|
|
||||||
message: e.toString(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return GenericResult(
|
|
||||||
data: foundRecords,
|
|
||||||
success: true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/desired_dns_record.dart';
|
|
||||||
import 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/digital_ocean_dns/digital_ocean_dns_api.dart';
|
import 'package:selfprivacy/logic/api_maps/rest_maps/dns_providers/digital_ocean_dns/digital_ocean_dns_api.dart';
|
||||||
import 'package:selfprivacy/logic/models/hive/server_domain.dart';
|
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_providers/digital_ocean_dns_info.dart';
|
||||||
|
@ -157,90 +156,4 @@ class DigitalOceanDnsProvider extends DnsProvider {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
|
||||||
Future<GenericResult<List<DesiredDnsRecord>>> validateDnsRecords(
|
|
||||||
final ServerDomain domain,
|
|
||||||
final String ip4,
|
|
||||||
final String dkimPublicKey,
|
|
||||||
final List<DnsRecord> pendingDnsRecords,
|
|
||||||
) async {
|
|
||||||
final result = await _adapter.api().getDnsRecords(domain.domainName);
|
|
||||||
if (result.data.isEmpty || !result.success) {
|
|
||||||
return GenericResult(
|
|
||||||
success: result.success,
|
|
||||||
data: [],
|
|
||||||
code: result.code,
|
|
||||||
message: result.message,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
final records = result.data;
|
|
||||||
final List<DesiredDnsRecord> foundRecords = [];
|
|
||||||
try {
|
|
||||||
for (final DnsRecord pendingDnsRecord in pendingDnsRecords) {
|
|
||||||
final record = DigitalOceanDnsRecord.fromDnsRecord(
|
|
||||||
pendingDnsRecord,
|
|
||||||
domain.domainName,
|
|
||||||
);
|
|
||||||
if (record.name == 'selector._domainkey') {
|
|
||||||
final DigitalOceanDnsRecord foundRecord = records.firstWhere(
|
|
||||||
(final r) => (r.name == record.name) && r.type == record.type,
|
|
||||||
orElse: () => DigitalOceanDnsRecord(
|
|
||||||
id: null,
|
|
||||||
name: record.name,
|
|
||||||
type: record.type,
|
|
||||||
data: '',
|
|
||||||
ttl: 800,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
// remove all spaces and tabulators from
|
|
||||||
// the foundRecord.content and the record.content
|
|
||||||
// to compare them
|
|
||||||
final String foundContent =
|
|
||||||
foundRecord.data.replaceAll(RegExp(r'\s+'), '');
|
|
||||||
final String content = record.data.replaceAll(RegExp(r'\s+'), '');
|
|
||||||
foundRecords.add(
|
|
||||||
DesiredDnsRecord(
|
|
||||||
name: record.name,
|
|
||||||
description: record.name == '@' ? domain.domainName : record.name,
|
|
||||||
content: record.data,
|
|
||||||
isSatisfied: foundContent == content,
|
|
||||||
type: record.type,
|
|
||||||
category: DnsRecordsCategory.email,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
final foundMatch = records.any(
|
|
||||||
(final r) =>
|
|
||||||
r.name == record.name &&
|
|
||||||
r.type == record.type &&
|
|
||||||
r.data == record.data,
|
|
||||||
);
|
|
||||||
foundRecords.add(
|
|
||||||
DesiredDnsRecord(
|
|
||||||
name: record.name,
|
|
||||||
description: record.name == '@' ? domain.domainName : record.name,
|
|
||||||
content: record.data,
|
|
||||||
isSatisfied: foundMatch,
|
|
||||||
type: record.type,
|
|
||||||
category: record.type == 'A'
|
|
||||||
? DnsRecordsCategory.services
|
|
||||||
: DnsRecordsCategory.email,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
print(e);
|
|
||||||
return GenericResult(
|
|
||||||
data: [],
|
|
||||||
success: false,
|
|
||||||
message: e.toString(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return GenericResult(
|
|
||||||
data: foundRecords,
|
|
||||||
success: true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:selfprivacy/logic/api_maps/generic_result.dart';
|
import 'package:selfprivacy/logic/api_maps/generic_result.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/hive/server_domain.dart';
|
||||||
import 'package:selfprivacy/logic/models/json/dns_records.dart';
|
import 'package:selfprivacy/logic/models/json/dns_records.dart';
|
||||||
export 'package:selfprivacy/logic/api_maps/generic_result.dart';
|
export 'package:selfprivacy/logic/api_maps/generic_result.dart';
|
||||||
|
@ -57,17 +56,4 @@ abstract class DnsProvider {
|
||||||
final DnsRecord record,
|
final DnsRecord record,
|
||||||
final ServerDomain domain,
|
final ServerDomain domain,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Tries to check whether all known DNS records on the domain by ip4
|
|
||||||
/// match expectations of SelfPrivacy in order to launch.
|
|
||||||
///
|
|
||||||
/// Will return list of [DesiredDnsRecord] objects, which represent
|
|
||||||
/// only those records which have successfully passed validation.
|
|
||||||
/// TODO: Unify across DNS providers
|
|
||||||
Future<GenericResult<List<DesiredDnsRecord>>> validateDnsRecords(
|
|
||||||
final ServerDomain domain,
|
|
||||||
final String ip4,
|
|
||||||
final String dkimPublicKey,
|
|
||||||
final List<DnsRecord> pendingDnsRecords,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,10 +151,8 @@ class _DnsDetailsPageState extends State<DnsDetailsPage> {
|
||||||
? neutralColor
|
? neutralColor
|
||||||
: errorColor,
|
: errorColor,
|
||||||
),
|
),
|
||||||
title: Text(dnsRecord.description),
|
title: Text(dnsRecord.displayName ?? dnsRecord.name),
|
||||||
subtitle: Text(
|
subtitle: Text(dnsRecord.content),
|
||||||
dnsRecord.displayName ?? dnsRecord.name,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -193,9 +191,8 @@ class _DnsDetailsPageState extends State<DnsDetailsPage> {
|
||||||
? neutralColor
|
? neutralColor
|
||||||
: errorColor,
|
: errorColor,
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(dnsRecord.displayName ?? dnsRecord.name),
|
||||||
dnsRecord.description,
|
subtitle: Text(dnsRecord.name),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
Loading…
Reference in a new issue