Merge pull request 'refactor(desec): Implement basic DTO for DESEC to avoid dynamic objects' (#246) from dto into master
continuous-integration/drone/push Build is passing Details

Reviewed-on: #246
Reviewed-by: Inex Code <inex.code@selfprivacy.org>
pull/247/head^2
NaiJi ✨ 2023-07-28 00:32:25 +03:00
commit fd1be6358c
7 changed files with 164 additions and 61 deletions

View File

@ -4,7 +4,7 @@ import 'package:dio/dio.dart';
import 'package:selfprivacy/config/get_it_config.dart'; import 'package:selfprivacy/config/get_it_config.dart';
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/rest_api_map.dart'; import 'package:selfprivacy/logic/api_maps/rest_maps/rest_api_map.dart';
import 'package:selfprivacy/logic/models/hive/server_domain.dart'; import 'package:selfprivacy/logic/models/json/desec_dns_info.dart';
class DesecApi extends RestApiMap { class DesecApi extends RestApiMap {
DesecApi({ DesecApi({
@ -92,8 +92,8 @@ class DesecApi extends RestApiMap {
); );
} }
Future<GenericResult<List>> getDomains() async { Future<GenericResult<List<DesecDomain>>> getDomains() async {
List domains = []; List<DesecDomain> domains = [];
late final Response? response; late final Response? response;
final Dio client = await getClient(); final Dio client = await getClient();
@ -102,7 +102,11 @@ class DesecApi extends RestApiMap {
'', '',
); );
await Future.delayed(const Duration(seconds: 1)); await Future.delayed(const Duration(seconds: 1));
domains = response.data; domains = response.data!
.map<DesecDomain>(
(final e) => DesecDomain.fromJson(e),
)
.toList();
} catch (e) { } catch (e) {
print(e); print(e);
return GenericResult( return GenericResult(
@ -124,15 +128,17 @@ class DesecApi extends RestApiMap {
} }
Future<GenericResult<void>> createMultipleDnsRecords({ Future<GenericResult<void>> createMultipleDnsRecords({
required final ServerDomain domain, required final String domainName,
required final List<dynamic> records, required final List<DesecDnsRecord> records,
}) async { }) async {
final String domainName = domain.domainName;
final String url = '/$domainName/rrsets/'; final String url = '/$domainName/rrsets/';
final Dio client = await getClient(); final Dio client = await getClient();
try { try {
await client.post(url, data: records); await client.post(
url,
data: records.map((final rec) => rec.toJson()).toList(),
);
await Future.delayed(const Duration(seconds: 1)); await Future.delayed(const Duration(seconds: 1));
} catch (e) { } catch (e) {
print(e); print(e);
@ -149,15 +155,17 @@ class DesecApi extends RestApiMap {
} }
Future<GenericResult<void>> removeSimilarRecords({ Future<GenericResult<void>> removeSimilarRecords({
required final ServerDomain domain, required final String domainName,
required final List<dynamic> records, required final List<DesecDnsRecord> records,
}) async { }) async {
final String domainName = domain.domainName;
final String url = '/$domainName/rrsets/'; final String url = '/$domainName/rrsets/';
final Dio client = await getClient(); final Dio client = await getClient();
try { try {
await client.put(url, data: records); await client.put(
url,
data: records.map((final rec) => rec.toJson()).toList(),
);
await Future.delayed(const Duration(seconds: 1)); await Future.delayed(const Duration(seconds: 1));
} catch (e) { } catch (e) {
print(e); print(e);
@ -173,12 +181,11 @@ class DesecApi extends RestApiMap {
return GenericResult(success: true, data: null); return GenericResult(success: true, data: null);
} }
Future<GenericResult<List<dynamic>>> getDnsRecords({ Future<GenericResult<List<DesecDnsRecord>>> getDnsRecords(
required final ServerDomain domain, final String domainName,
}) async { ) async {
Response? response; Response? response;
final String domainName = domain.domainName; List<DesecDnsRecord> allRecords = [];
List allRecords = [];
final String url = '/$domainName/rrsets/'; final String url = '/$domainName/rrsets/';
@ -186,7 +193,11 @@ class DesecApi extends RestApiMap {
try { try {
response = await client.get(url); response = await client.get(url);
await Future.delayed(const Duration(seconds: 1)); await Future.delayed(const Duration(seconds: 1));
allRecords = response.data; allRecords = response.data!
.map<DesecDnsRecord>(
(final e) => DesecDnsRecord.fromJson(e),
)
.toList();
} catch (e) { } catch (e) {
print(e); print(e);
return GenericResult( return GenericResult(

View File

@ -0,0 +1,63 @@
import 'package:json_annotation/json_annotation.dart';
part 'desec_dns_info.g.dart';
/// https://desec.readthedocs.io/en/latest/dns/domains.html#domain-management
@JsonSerializable()
class DesecDomain {
DesecDomain(
this.name,
this.minimumTtl,
);
/// Restrictions on what is a valid domain name apply on
/// a per-user basis.
///
/// The maximum length is 191.
final String name;
/// Smallest TTL that can be used in an RRset.
/// The value is set automatically by DESEC
@JsonKey(name: 'minimum_ttl')
final int minimumTtl;
static DesecDomain fromJson(final Map<String, dynamic> json) =>
_$DesecDomainFromJson(json);
}
/// https://desec.readthedocs.io/en/latest/dns/rrsets.html#retrieving-and-creating-dns-records
@JsonSerializable()
class DesecDnsRecord {
DesecDnsRecord({
required this.subname,
required this.type,
required this.ttl,
required this.records,
});
/// Subdomain string which, together with domain, defines the RRset name.
/// Typical examples are www or _443._tcp.
final String subname;
/// RRset type (uppercase). A broad range of record types is supported,
/// with most DNSSEC-related types (and the SOA type) managed automagically
/// by the backend.
final String type;
/// Time-to-live value, which dictates for how long resolvers may
/// cache this RRset, measured in seconds.
///
/// The smallest acceptable value is given by the domains minimum TTL setting.
/// The maximum value is 86400 (one day).
final int ttl;
/// Array of record content strings.
///
/// The maximum number of array elements is 4091,
/// and the maximum length of the array is 64,000 (after JSON encoding).
final List<String> records;
static DesecDnsRecord fromJson(final Map<String, dynamic> json) =>
_$DesecDnsRecordFromJson(json);
Map<String, dynamic> toJson() => _$DesecDnsRecordToJson(this);
}

View File

@ -0,0 +1,35 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'desec_dns_info.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
DesecDomain _$DesecDomainFromJson(Map<String, dynamic> json) => DesecDomain(
json['name'] as String,
json['minimum_ttl'] as int,
);
Map<String, dynamic> _$DesecDomainToJson(DesecDomain instance) =>
<String, dynamic>{
'name': instance.name,
'minimum_ttl': instance.minimumTtl,
};
DesecDnsRecord _$DesecDnsRecordFromJson(Map<String, dynamic> json) =>
DesecDnsRecord(
subname: json['subname'] as String,
type: json['type'] as String,
ttl: json['ttl'] as int,
records:
(json['records'] as List<dynamic>).map((e) => e as String).toList(),
);
Map<String, dynamic> _$DesecDnsRecordToJson(DesecDnsRecord instance) =>
<String, dynamic>{
'subname': instance.subname,
'type': instance.type,
'ttl': instance.ttl,
'records': instance.records,
};

View File

@ -9,7 +9,6 @@ class DnsRecord {
required this.type, required this.type,
required this.name, required this.name,
required this.content, required this.content,
this.id,
this.ttl = 3600, this.ttl = 3600,
this.priority = 10, this.priority = 10,
this.proxied = false, this.proxied = false,
@ -32,8 +31,5 @@ class DnsRecord {
final int priority; final int priority;
final bool proxied; final bool proxied;
/// TODO: Refactoring refactoring refactoring refactoring >:c
final int? id;
Map<String, dynamic> toJson() => _$DnsRecordToJson(this); Map<String, dynamic> toJson() => _$DnsRecordToJson(this);
} }

View File

@ -13,5 +13,4 @@ Map<String, dynamic> _$DnsRecordToJson(DnsRecord instance) => <String, dynamic>{
'ttl': instance.ttl, 'ttl': instance.ttl,
'priority': instance.priority, 'priority': instance.priority,
'proxied': instance.proxied, 'proxied': instance.proxied,
'id': instance.id,
}; };

View File

@ -1,6 +1,7 @@
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/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/desec_dns_info.dart';
import 'package:selfprivacy/logic/models/json/dns_records.dart'; import 'package:selfprivacy/logic/models/json/dns_records.dart';
import 'package:selfprivacy/logic/providers/dns_providers/dns_provider.dart'; import 'package:selfprivacy/logic/providers/dns_providers/dns_provider.dart';
@ -59,7 +60,7 @@ class DesecDnsProvider extends DnsProvider {
domains = result.data domains = result.data
.map<String>( .map<String>(
(final el) => el['name'] as String, (final el) => el.name,
) )
.toList(); .toList();
@ -79,20 +80,20 @@ class DesecDnsProvider extends DnsProvider {
ip4, ip4,
); );
final List<dynamic> bulkRecords = []; final List<DesecDnsRecord> bulkRecords = [];
for (final DnsRecord record in listDnsRecords) { for (final DnsRecord record in listDnsRecords) {
bulkRecords.add( bulkRecords.add(
{ DesecDnsRecord(
'subname': record.name, subname: record.name ?? '',
'type': record.type, type: record.type,
'ttl': record.ttl, ttl: record.ttl,
'records': [extractContent(record)], records: [extractContent(record) ?? ''],
}, ),
); );
} }
return _adapter.api().createMultipleDnsRecords( return _adapter.api().createMultipleDnsRecords(
domain: domain, domainName: domain.domainName,
records: bulkRecords, records: bulkRecords,
); );
} }
@ -107,28 +108,28 @@ class DesecDnsProvider extends DnsProvider {
ip4, ip4,
); );
final List<dynamic> bulkRecords = []; final List<DesecDnsRecord> bulkRecords = [];
for (final DnsRecord record in listDnsRecords) { for (final DnsRecord record in listDnsRecords) {
bulkRecords.add( bulkRecords.add(
{ DesecDnsRecord(
'subname': record.name, subname: record.name ?? '',
'type': record.type, type: record.type,
'ttl': record.ttl, ttl: record.ttl,
'records': [], records: [],
}, ),
); );
} }
bulkRecords.add( bulkRecords.add(
{ DesecDnsRecord(
'subname': 'selector._domainkey', subname: 'selector._domainkey',
'type': 'TXT', type: 'TXT',
'ttl': 18000, ttl: 18000,
'records': [], records: [],
}, ),
); );
return _adapter.api().removeSimilarRecords( return _adapter.api().removeSimilarRecords(
domain: domain, domainName: domain.domainName,
records: bulkRecords, records: bulkRecords,
); );
} }
@ -138,7 +139,7 @@ class DesecDnsProvider extends DnsProvider {
required final ServerDomain domain, required final ServerDomain domain,
}) async { }) async {
final List<DnsRecord> records = []; final List<DnsRecord> records = [];
final result = await _adapter.api().getDnsRecords(domain: domain); final result = await _adapter.api().getDnsRecords(domain.domainName);
if (result.data.isEmpty || !result.success) { if (result.data.isEmpty || !result.success) {
return GenericResult( return GenericResult(
success: result.success, success: result.success,
@ -150,15 +151,14 @@ class DesecDnsProvider extends DnsProvider {
try { try {
for (final record in result.data) { for (final record in result.data) {
final String? content = (record['records'] is List<dynamic>) final String? content =
? record['records'][0] record.records.isEmpty ? null : record.records[0];
: record['records'];
records.add( records.add(
DnsRecord( DnsRecord(
name: record['subname'], name: record.subname,
type: record['type'], type: record.type,
content: content, content: content,
ttl: record['ttl'], ttl: record.ttl,
), ),
); );
} }
@ -180,14 +180,14 @@ class DesecDnsProvider extends DnsProvider {
final ServerDomain domain, final ServerDomain domain,
) async { ) async {
final result = await _adapter.api().createMultipleDnsRecords( final result = await _adapter.api().createMultipleDnsRecords(
domain: domain, domainName: domain.domainName,
records: [ records: [
{ DesecDnsRecord(
'subname': record.name, subname: record.name ?? '',
'type': record.type, type: record.type,
'ttl': record.ttl, ttl: record.ttl,
'records': [extractContent(record)], records: [extractContent(record) ?? ''],
}, ),
], ],
); );

View File

@ -129,7 +129,6 @@ class DigitalOceanDnsProvider extends DnsProvider {
for (final rawRecord in result.data) { for (final rawRecord in result.data) {
records.add( records.add(
DnsRecord( DnsRecord(
id: rawRecord['id'],
name: rawRecord['name'], name: rawRecord['name'],
type: rawRecord['type'], type: rawRecord['type'],
content: rawRecord['data'], content: rawRecord['data'],