diff --git a/lib/features/login/data/network/dns_service.dart b/lib/features/login/data/network/dns_service.dart new file mode 100644 index 000000000..7b33ebbd5 --- /dev/null +++ b/lib/features/login/data/network/dns_service.dart @@ -0,0 +1,65 @@ + +import 'package:core/utils/app_logger.dart'; +import 'package:dns_client/dns_client.dart'; +import 'package:tmail_ui_user/features/login/domain/exceptions/login_exception.dart'; + +class DNSService { + static const String _jmapServiceName = '_jmap._tcp'; + + Future _dnsLookupToUrlFromSRVType({required String hostName}) async { + try { + final url = await _dnsLookupToUrlByGoogle(hostName: hostName); + if (url.isEmpty) { + return await _dnsLookupToUrlByCloudflare(hostName: hostName); + } + return url; + } catch (e) { + return await _dnsLookupToUrlByCloudflare(hostName: hostName); + } + } + + Future _dnsLookupToUrlByGoogle({required String hostName}) async { + final dns = DnsOverHttps.google(); + final listData = await dns.lookupDataByRRType(hostName, RRType.SRVType); + if (listData.isEmpty) { + throw NotFoundDataResourceRecordException(); + } + return _parsingUrlFromDataResourceRecord(listData.first); + } + + Future _dnsLookupToUrlByCloudflare({required String hostName}) async { + final dns = DnsOverHttps.cloudflare(); + final listData = await dns.lookupDataByRRType(hostName, RRType.SRVType); + if (listData.isEmpty) { + throw NotFoundDataResourceRecordException(); + } + return _parsingUrlFromDataResourceRecord(listData.first); + } + + String _parsingUrlFromDataResourceRecord(String data) { + if (data.isEmpty) { + throw NotFoundDataResourceRecordException(); + } + final listFieldData = data.split(' '); + if (listFieldData.isEmpty) { + throw NotFoundUrlException(); + } + final url = _removeDotAtEndOfString(listFieldData.last); + log('DNSService::_parsingUrlFromDataResourceRecord:url: $url'); + return url; + } + + Future getJmapUrl(String emailAddress) async { + final domainName = emailAddress.split('@')[1]; + final jmapHostName = '$_jmapServiceName.$domainName'; + log('DNSHandler::getJmapUrl:jmapHostName: $jmapHostName'); + return await _dnsLookupToUrlFromSRVType(hostName: jmapHostName); + } + + String _removeDotAtEndOfString(String value) { + if (value.lastIndexOf('.') == value.length - 1) { + return value.substring(0, value.length - 1); + } + return value; + } +} diff --git a/lib/features/login/domain/exceptions/login_exception.dart b/lib/features/login/domain/exceptions/login_exception.dart new file mode 100644 index 000000000..665f20c1a --- /dev/null +++ b/lib/features/login/domain/exceptions/login_exception.dart @@ -0,0 +1,4 @@ + +class NotFoundDataResourceRecordException implements Exception {} + +class NotFoundUrlException implements Exception {} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 2f6325165..75979938b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -360,6 +360,15 @@ packages: url: "https://pub.dev" source: hosted version: "5.0.0" + dns_client: + dependency: "direct main" + description: + path: "." + ref: twake-supported + resolved-ref: "0ba4d48f287d408c70612dfc8bacc5ba11cd421b" + url: "https://github.com/dab246/dns_client.git" + source: git + version: "0.2.1" dotted_border: dependency: "direct main" description: @@ -861,6 +870,14 @@ packages: relative: true source: path version: "1.0.0+1" + freezed_annotation: + dependency: transitive + description: + name: freezed_annotation + sha256: "1be037f901137bf2b9a0c309e9bf2694d6ec77687645211218191ade4f41a4b8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" frontend_server_client: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 346277816..49be1beb6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -86,6 +86,11 @@ dependencies: url: https://github.com/dab246/super_tag_editor.git ref: master + dns_client: + git: + url: https://github.com/dab246/dns_client.git + ref: twake-supported + ### Dependencies from pub.dev ### cupertino_icons: 1.0.5