Files
Qlyra/lib/core/utils/ip_lookup_service.dart
sevenhill 50816588e4
Build Android (FCM) / build-android-fcm (push) Canceled after 0s
Build Android / build-android (push) Canceled after 0s
Build iOS / build-ios (push) Canceled after 0s
Build Linux / build-linux (push) Canceled after 0s
Build macOS / build-macos (push) Canceled after 0s
Build Windows / build-windows (push) Canceled after 0s
Release (main) / android (oneme) (push) Canceled after 0s
Release (main) / android (qlyra) (push) Canceled after 0s
Release (main) / windows (push) Canceled after 0s
Release (main) / linux (push) Canceled after 0s
Release (main) / macos (push) Canceled after 0s
Release (main) / ios (push) Canceled after 0s
Release (main) / release (push) Canceled after 0s
Update Qlyra application
2026-08-30 22:53:15 +03:00

83 lines
2.6 KiB
Dart

import 'dart:convert';
import 'dart:io';
class IpLookupDetails {
final String city;
final String country;
final String isp;
final String network;
final bool mobile;
final bool proxy;
final String timezone;
const IpLookupDetails({
required this.city,
required this.country,
required this.isp,
required this.network,
required this.mobile,
required this.proxy,
required this.timezone,
});
factory IpLookupDetails.fromIpWhoIs(Map<String, dynamic> data) {
if (data['success'] != true) {
throw FormatException(data['message']?.toString() ?? 'IP lookup failed');
}
final connection = data['connection'] is Map
? (data['connection'] as Map).cast<String, dynamic>()
: const <String, dynamic>{};
final security = data['security'] is Map
? (data['security'] as Map).cast<String, dynamic>()
: const <String, dynamic>{};
final timezoneData = data['timezone'] is Map
? (data['timezone'] as Map).cast<String, dynamic>()
: const <String, dynamic>{};
final asn = connection['asn'];
final organization = connection['org']?.toString() ?? '';
final network = [
if (asn != null) 'AS$asn',
if (organization.isNotEmpty) organization,
].join(' ');
return IpLookupDetails(
city: data['city']?.toString() ?? '',
country: data['country']?.toString() ?? '',
isp: connection['isp']?.toString() ?? organization,
network: network,
mobile: security['mobile'] == true,
proxy: security['proxy'] == true,
timezone: timezoneData['id']?.toString() ?? '',
);
}
}
abstract class IpLookupService {
static const String providerName = 'ipwho.is';
static const Duration _timeout = Duration(seconds: 8);
static Future<IpLookupDetails> lookup(String ip) async {
final uri = Uri.https(providerName, '/$ip');
final client = HttpClient()..connectionTimeout = _timeout;
try {
final request = await client.getUrl(uri);
request.headers.set(HttpHeaders.userAgentHeader, 'QlyraIpLookup');
final response = await request.close().timeout(_timeout);
if (response.statusCode != HttpStatus.ok) {
await response.drain<void>();
throw HttpException('HTTP ${response.statusCode}', uri: uri);
}
final body = await response
.transform(const Utf8Decoder())
.join()
.timeout(_timeout);
final decoded = jsonDecode(body);
if (decoded is! Map) {
throw const FormatException('Invalid IP lookup response');
}
return IpLookupDetails.fromIpWhoIs(decoded.cast<String, dynamic>());
} finally {
client.close(force: true);
}
}
}