diff --git a/lib/server.dart b/lib/server.dart index ee0db44..6457b21 100644 --- a/lib/server.dart +++ b/lib/server.dart @@ -4,7 +4,8 @@ enum ServerStatus { notOk, timeout, dnsError, - clientConnectivityIssues + clientConnectivityIssues, + certificateError } class Server { diff --git a/lib/serverlist.dart b/lib/serverlist.dart index 7f8bf70..7760fdf 100644 --- a/lib/serverlist.dart +++ b/lib/serverlist.dart @@ -262,6 +262,26 @@ class _ServerListState extends State { ), ), ), + IconButton( + alignment: Alignment.center, + icon: Icon( + Icons.keyboard_arrow_up, + color: Colors.blueGrey, + ), + onPressed: () { + _moveServerUp(index); + }, + ), + IconButton( + alignment: Alignment.center, + icon: Icon( + Icons.keyboard_arrow_down, + color: Colors.blueGrey, + ), + onPressed: () { + _moveServerDown(index); + }, + ), IconButton( alignment: Alignment.center, icon: Icon( @@ -375,38 +395,59 @@ class _ServerListState extends State { } static Future _checkStatus(String uri) async { - Uri parsedUri; - try { - parsedUri = Uri.parse(uri); - } catch (FormatException) { - return ServerStatus.dnsError; - } + Uri parsedUri; - try { - await HttpUtils.getForFullResponse('https://dns.google.com'); - } catch (SocketException) { - return ServerStatus.clientConnectivityIssues; - } - - try { - // Check if host is IP address - InternetAddress(parsedUri.host); - } catch (ArgumentError) /* Host is a DNS name */ { - var v4recs, v6recs; try { - v4recs = await DnsUtils.lookupRecord(parsedUri.host, RRecordType.A); - v6recs = await DnsUtils.lookupRecord(parsedUri.host, RRecordType.AAAA); - } catch (SocketException) { - return ServerStatus.clientConnectivityIssues; - } - var v4 = await _resolveHostname(v4recs, RRecordType.A); - var v6 = await _resolveHostname(v6recs, RRecordType.AAAA); - if (v4 == null && v6 == null) { + parsedUri = Uri.parse(uri); + } on FormatException { return ServerStatus.dnsError; } + + try { + // Check if host is IP address + var ip = InternetAddress(parsedUri.host); + InternetAddress reversedIp = await ip.reverse(); + if (ip.host != reversedIp.host) { + parsedUri = parsedUri.replace(host: reversedIp.host); + throw ArgumentError("Valid IP, but trying with reverse hostname..."); + } + if (parsedUri.scheme == "https") return ServerStatus.certificateError; + } on ArgumentError /* Host is a DNS name */ { + List v4recs, v6recs; + try { + try { + v4recs = await DnsUtils.lookupRecord(parsedUri.host, RRecordType.A); + } on HttpResponseException { + v4recs = []; + } + try { + v6recs = + await DnsUtils.lookupRecord(parsedUri.host, RRecordType.AAAA); + } on HttpResponseException { + v6recs = []; + } + } on SocketException catch (e) { + return ServerStatus.clientConnectivityIssues; + } + var v4 = await _resolveHostname(v4recs, RRecordType.A); + var v6 = await _resolveHostname(v6recs, RRecordType.AAAA); + if (v4 == null && v6 == null) { + return ServerStatus.dnsError; + } + } + try { + return await _checkResponse(parsedUri); + } on TlsException { + return ServerStatus.certificateError; + } + } on SocketException catch (e) { + // Network unreachable + if (e.osError.errorCode == 101) + return ServerStatus.clientConnectivityIssues; + + throw e; } - return await _checkResponse(parsedUri); } Icon _generateIcon(Server server) { @@ -436,6 +477,10 @@ class _ServerListState extends State { icon = Icons.signal_wifi_off; color = Colors.red.shade400; break; + case ServerStatus.certificateError: + icon = Icons.security; + color = Colors.yellow.shade400; + break; default: icon = Icons.device_unknown; color = Colors.blueGrey.shade400; @@ -465,7 +510,7 @@ class _ServerListState extends State { try { response = await HttpUtils.getForFullResponse(uri.toString()) .timeout(new Duration(seconds: 3)); - } catch (TimeoutException) { + } on TimeoutException { return ServerStatus.timeout; } @@ -526,17 +571,48 @@ class _ServerListState extends State { case ServerStatus.unknown: return 'Loading...'; case ServerStatus.ok: - return 'Reachable'; + return 'Reachable.'; case ServerStatus.notOk: - return 'Unexpected response'; + return 'Unexpected response received.'; case ServerStatus.timeout: - return 'Timeout'; + return 'Server took more than 3 seconds to respond.'; case ServerStatus.dnsError: - return 'DNS issues'; + return 'DNS issues.'; case ServerStatus.clientConnectivityIssues: - return 'Connectivity issues on your device'; + return 'Connectivity issues on your device.'; + case ServerStatus.certificateError: + return 'A secure connection could not be established.'; default: return ''; } } + + void _moveServer(int index, AxisDirection direction) { + int newIndex; + switch (direction) { + case AxisDirection.up: + if (index == 0) return; + newIndex = index - 1; + break; + case AxisDirection.down: + if (index == servers.length - 1) return; + newIndex = index + 1; + break; + default: + return; + break; + } + + Server server = servers[index]; + servers.removeAt(index); + setState(() { + servers.insert(newIndex, server); + selectedServer = newIndex; + }); + _saveServersToPreferences(); + } + + void _moveServerUp(int index) => _moveServer(index, AxisDirection.up); + + void _moveServerDown(int index) => _moveServer(index, AxisDirection.down); }