mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-01-23 17:26:35 +00:00
feat: Add the updateDnsRecords
to DNS providers
This commit is contained in:
parent
95e51732fc
commit
eab2f892c9
|
@ -155,7 +155,7 @@ class DesecApi extends RestApiMap {
|
||||||
return GenericResult(success: true, data: null);
|
return GenericResult(success: true, data: null);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<GenericResult<void>> removeSimilarRecords({
|
Future<GenericResult<void>> putRecords({
|
||||||
required final String domainName,
|
required final String domainName,
|
||||||
required final List<DesecDnsRecord> records,
|
required final List<DesecDnsRecord> records,
|
||||||
}) async {
|
}) async {
|
||||||
|
|
|
@ -43,6 +43,7 @@ class CloudflareDnsRecord {
|
||||||
this.ttl = 3600,
|
this.ttl = 3600,
|
||||||
this.priority = 10,
|
this.priority = 10,
|
||||||
this.id,
|
this.id,
|
||||||
|
this.comment = 'Created by SelfPrivacy app',
|
||||||
});
|
});
|
||||||
|
|
||||||
factory CloudflareDnsRecord.fromDnsRecord(
|
factory CloudflareDnsRecord.fromDnsRecord(
|
||||||
|
@ -90,6 +91,9 @@ class CloudflareDnsRecord {
|
||||||
/// `>= 0 <= 65535`
|
/// `>= 0 <= 65535`
|
||||||
final int priority;
|
final int priority;
|
||||||
|
|
||||||
|
/// Comments or notes about the DNS record. This field has no effect on DNS responses.
|
||||||
|
final String comment;
|
||||||
|
|
||||||
static CloudflareDnsRecord fromJson(final Map<String, dynamic> json) =>
|
static CloudflareDnsRecord fromJson(final Map<String, dynamic> json) =>
|
||||||
_$CloudflareDnsRecordFromJson(json);
|
_$CloudflareDnsRecordFromJson(json);
|
||||||
Map<String, dynamic> toJson() => _$CloudflareDnsRecordToJson(this);
|
Map<String, dynamic> toJson() => _$CloudflareDnsRecordToJson(this);
|
||||||
|
|
|
@ -27,6 +27,7 @@ CloudflareDnsRecord _$CloudflareDnsRecordFromJson(Map<String, dynamic> json) =>
|
||||||
ttl: (json['ttl'] as num?)?.toInt() ?? 3600,
|
ttl: (json['ttl'] as num?)?.toInt() ?? 3600,
|
||||||
priority: (json['priority'] as num?)?.toInt() ?? 10,
|
priority: (json['priority'] as num?)?.toInt() ?? 10,
|
||||||
id: json['id'] as String?,
|
id: json['id'] as String?,
|
||||||
|
comment: json['comment'] as String? ?? 'Created by SelfPrivacy app',
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$CloudflareDnsRecordToJson(
|
Map<String, dynamic> _$CloudflareDnsRecordToJson(
|
||||||
|
@ -39,4 +40,5 @@ Map<String, dynamic> _$CloudflareDnsRecordToJson(
|
||||||
'zone_name': instance.zoneName,
|
'zone_name': instance.zoneName,
|
||||||
'ttl': instance.ttl,
|
'ttl': instance.ttl,
|
||||||
'priority': instance.priority,
|
'priority': instance.priority,
|
||||||
|
'comment': instance.comment,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/server_settings.graphql.dart';
|
import 'package:selfprivacy/logic/api_maps/graphql_maps/schema/server_settings.graphql.dart';
|
||||||
|
|
||||||
part 'dns_records.g.dart';
|
part 'dns_records.g.dart';
|
||||||
|
|
||||||
@JsonSerializable(createToJson: true, createFactory: false)
|
@JsonSerializable()
|
||||||
class DnsRecord {
|
class DnsRecord extends Equatable {
|
||||||
DnsRecord({
|
const DnsRecord({
|
||||||
required this.type,
|
required this.type,
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.content,
|
required this.content,
|
||||||
|
@ -35,4 +36,14 @@ class DnsRecord {
|
||||||
final bool proxied;
|
final bool proxied;
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => _$DnsRecordToJson(this);
|
Map<String, dynamic> toJson() => _$DnsRecordToJson(this);
|
||||||
|
|
||||||
|
@override
|
||||||
|
@JsonKey(includeToJson: false)
|
||||||
|
List<Object?> get props => [
|
||||||
|
type,
|
||||||
|
name,
|
||||||
|
content,
|
||||||
|
ttl,
|
||||||
|
priority,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,16 @@ part of 'dns_records.dart';
|
||||||
// JsonSerializableGenerator
|
// JsonSerializableGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
|
DnsRecord _$DnsRecordFromJson(Map<String, dynamic> json) => DnsRecord(
|
||||||
|
type: json['type'] as String,
|
||||||
|
name: json['name'] as String?,
|
||||||
|
content: json['content'] as String?,
|
||||||
|
displayName: json['displayName'] as String?,
|
||||||
|
ttl: (json['ttl'] as num?)?.toInt() ?? 3600,
|
||||||
|
priority: (json['priority'] as num?)?.toInt() ?? 10,
|
||||||
|
proxied: json['proxied'] as bool? ?? false,
|
||||||
|
);
|
||||||
|
|
||||||
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,
|
'displayName': instance.displayName,
|
||||||
|
|
|
@ -198,6 +198,94 @@ class CloudflareDnsProvider extends DnsProvider {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<GenericResult<void>> updateDnsRecords({
|
||||||
|
required final List<DnsRecord> newRecords,
|
||||||
|
required final ServerDomain domain,
|
||||||
|
final List<DnsRecord>? oldRecords,
|
||||||
|
}) async {
|
||||||
|
final syncZoneIdResult = await syncZoneId(domain.domainName);
|
||||||
|
if (!syncZoneIdResult.success) {
|
||||||
|
return syncZoneIdResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
final result = await _adapter.api().getDnsRecords(
|
||||||
|
zoneId: _adapter.cachedZoneId,
|
||||||
|
);
|
||||||
|
if (result.data.isEmpty || !result.success) {
|
||||||
|
return GenericResult(
|
||||||
|
success: false,
|
||||||
|
data: null,
|
||||||
|
code: result.code,
|
||||||
|
message: result.message,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<CloudflareDnsRecord> newSelfprivacyRecords = newRecords
|
||||||
|
.map(
|
||||||
|
(final record) => CloudflareDnsRecord.fromDnsRecord(
|
||||||
|
record,
|
||||||
|
domain.domainName,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
final List<CloudflareDnsRecord>? oldSelfprivacyRecords = oldRecords
|
||||||
|
?.map(
|
||||||
|
(final record) => CloudflareDnsRecord.fromDnsRecord(
|
||||||
|
record,
|
||||||
|
domain.domainName,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
final List<CloudflareDnsRecord> cloudflareRecords = result.data;
|
||||||
|
|
||||||
|
final List<CloudflareDnsRecord> recordsToDelete = newSelfprivacyRecords
|
||||||
|
.where(
|
||||||
|
(final newRecord) => cloudflareRecords.any(
|
||||||
|
(final oldRecord) =>
|
||||||
|
newRecord.type == oldRecord.type &&
|
||||||
|
newRecord.name == oldRecord.name,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
if (oldSelfprivacyRecords != null) {
|
||||||
|
recordsToDelete.addAll(
|
||||||
|
oldSelfprivacyRecords
|
||||||
|
.where(
|
||||||
|
(final oldRecord) => !newSelfprivacyRecords.any(
|
||||||
|
(final newRecord) =>
|
||||||
|
newRecord.type == oldRecord.type &&
|
||||||
|
newRecord.name == oldRecord.name,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recordsToDelete.isNotEmpty) {
|
||||||
|
await _adapter.api().removeSimilarRecords(
|
||||||
|
records: cloudflareRecords
|
||||||
|
.where(
|
||||||
|
(final record) => recordsToDelete.any(
|
||||||
|
(final recordToDelete) =>
|
||||||
|
recordToDelete.type == record.type &&
|
||||||
|
recordToDelete.name == record.name,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
zoneId: _adapter.cachedZoneId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _adapter.api().createMultipleDnsRecords(
|
||||||
|
zoneId: _adapter.cachedZoneId,
|
||||||
|
records: newSelfprivacyRecords,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
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(
|
||||||
|
|
|
@ -112,7 +112,28 @@ class DesecDnsProvider extends DnsProvider {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _adapter.api().removeSimilarRecords(
|
return _adapter.api().putRecords(
|
||||||
|
domainName: domain.domainName,
|
||||||
|
records: bulkRecords,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<GenericResult<void>> updateDnsRecords({
|
||||||
|
required final List<DnsRecord> newRecords,
|
||||||
|
required final ServerDomain domain,
|
||||||
|
final List<DnsRecord>? oldRecords,
|
||||||
|
}) async {
|
||||||
|
if (oldRecords != null) {
|
||||||
|
await removeDomainRecords(records: oldRecords, domain: domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<DesecDnsRecord> bulkRecords = [];
|
||||||
|
for (final DnsRecord record in newRecords) {
|
||||||
|
bulkRecords.add(DesecDnsRecord.fromDnsRecord(record, domain.domainName));
|
||||||
|
}
|
||||||
|
|
||||||
|
return _adapter.api().putRecords(
|
||||||
domainName: domain.domainName,
|
domainName: domain.domainName,
|
||||||
records: bulkRecords,
|
records: bulkRecords,
|
||||||
);
|
);
|
||||||
|
|
|
@ -128,6 +128,79 @@ class DigitalOceanDnsProvider extends DnsProvider {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<GenericResult<void>> updateDnsRecords({
|
||||||
|
required final List<DnsRecord> newRecords,
|
||||||
|
required final ServerDomain domain,
|
||||||
|
final List<DnsRecord>? oldRecords,
|
||||||
|
}) async {
|
||||||
|
final result = await _adapter.api().getDnsRecords(domain.domainName);
|
||||||
|
if (result.data.isEmpty || !result.success) {
|
||||||
|
return GenericResult(
|
||||||
|
success: result.success,
|
||||||
|
data: null,
|
||||||
|
code: result.code,
|
||||||
|
message: result.message,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<DigitalOceanDnsRecord> newSelfprivacyRecords = newRecords
|
||||||
|
.map(
|
||||||
|
(final record) => DigitalOceanDnsRecord.fromDnsRecord(
|
||||||
|
record,
|
||||||
|
domain.domainName,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
final List<DigitalOceanDnsRecord>? oldSelfprivacyRecords = oldRecords
|
||||||
|
?.map(
|
||||||
|
(final record) => DigitalOceanDnsRecord.fromDnsRecord(
|
||||||
|
record,
|
||||||
|
domain.domainName,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
final List<DigitalOceanDnsRecord> oceanRecords = result.data;
|
||||||
|
|
||||||
|
final List<DigitalOceanDnsRecord> recordsToDelete = newSelfprivacyRecords
|
||||||
|
.where(
|
||||||
|
(final newRecord) => oceanRecords.any(
|
||||||
|
(final oldRecord) =>
|
||||||
|
newRecord.type == oldRecord.type &&
|
||||||
|
newRecord.name == oldRecord.name,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
if (oldSelfprivacyRecords != null) {
|
||||||
|
recordsToDelete.addAll(
|
||||||
|
oldSelfprivacyRecords
|
||||||
|
.where(
|
||||||
|
(final oldRecord) => !newSelfprivacyRecords.any(
|
||||||
|
(final newRecord) =>
|
||||||
|
newRecord.type == oldRecord.type &&
|
||||||
|
newRecord.name == oldRecord.name,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recordsToDelete.isNotEmpty) {
|
||||||
|
return _adapter.api().removeSimilarRecords(
|
||||||
|
domainName: domain.domainName,
|
||||||
|
records: recordsToDelete,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _adapter.api().createMultipleDnsRecords(
|
||||||
|
domainName: domain.domainName,
|
||||||
|
records: newSelfprivacyRecords,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<GenericResult<List<DnsRecord>>> getDnsRecords({
|
Future<GenericResult<List<DnsRecord>>> getDnsRecords({
|
||||||
required final ServerDomain domain,
|
required final ServerDomain domain,
|
||||||
|
|
|
@ -54,4 +54,14 @@ abstract class DnsProvider {
|
||||||
final DnsRecord record,
|
final DnsRecord record,
|
||||||
final ServerDomain domain,
|
final ServerDomain domain,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Tries to update existing domain records
|
||||||
|
///
|
||||||
|
/// If [oldRecords] is provided, it will also remove the records that
|
||||||
|
/// are not in [newRecords
|
||||||
|
Future<GenericResult<void>> updateDnsRecords({
|
||||||
|
required final List<DnsRecord> newRecords,
|
||||||
|
required final ServerDomain domain,
|
||||||
|
final List<DnsRecord>? oldRecords,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ List<DnsRecord> getProjectDnsRecords(
|
||||||
final DnsRecord socialA = DnsRecord(type: 'A', name: 'social', content: ip4);
|
final DnsRecord socialA = DnsRecord(type: 'A', name: 'social', content: ip4);
|
||||||
final DnsRecord vpn = DnsRecord(type: 'A', name: 'vpn', content: ip4);
|
final DnsRecord vpn = DnsRecord(type: 'A', name: 'vpn', content: ip4);
|
||||||
|
|
||||||
final DnsRecord txt1 = DnsRecord(
|
const DnsRecord txt1 = DnsRecord(
|
||||||
type: 'TXT',
|
type: 'TXT',
|
||||||
name: '_dmarc',
|
name: '_dmarc',
|
||||||
content: 'v=DMARC1; p=none',
|
content: 'v=DMARC1; p=none',
|
||||||
|
@ -125,7 +125,7 @@ List<DnsRecord> getProjectDnsRecords(
|
||||||
/// We never create this record!
|
/// We never create this record!
|
||||||
/// This declaration is only for removal
|
/// This declaration is only for removal
|
||||||
/// as we need to compare by 'type' and 'name'
|
/// as we need to compare by 'type' and 'name'
|
||||||
final DnsRecord txt3 = DnsRecord(
|
const DnsRecord txt3 = DnsRecord(
|
||||||
type: 'TXT',
|
type: 'TXT',
|
||||||
name: 'selector._domainkey',
|
name: 'selector._domainkey',
|
||||||
content: 'v=DKIM1; k=rsa; p=none',
|
content: 'v=DKIM1; k=rsa; p=none',
|
||||||
|
|
Loading…
Reference in a new issue