v2.0.7: security hardening, config sync, cleanup
- 6 new security audits (technical_debt_8 through 12) - SNI rotation pool per session (5 sites) - vless_ip pinned to hardcoded server IP - TLS cert validation restored (domain-based) - Swarm monitoring removed from public domain - Xray routing blocks abuse ports (SMTP, NetBIOS, SSDP) - flow: xtls-rprx-vision in add_vless_client - TimerBox shows Connecting/Syncing spinner - Outbound port blocking in Xray config - Cleaned up comments, synced config templates
This commit is contained in:
1 parent
f01a610182
commit
f8abda9323
7 files changed
+109
-86
No files matched your search
@@ -34,14 +34,14 @@ class HivemindService {
|
||||
_expectedNonce = nonce;
|
||||
debugPrint('[HivemindService] Call #$callId — nonce: $nonce');
|
||||
|
||||
final url = Uri.parse('${AppConfig.hivemindApiBase}/session/status?device_id=$deviceId');
|
||||
final url = _url('/session/status?device_id=$deviceId');
|
||||
|
||||
// ── AD BYPASS (debug only) ────────────────────────────────────────
|
||||
if (kDebugMode && !skipAdBypass) {
|
||||
try {
|
||||
final customData = jsonEncode({'device_id': deviceId, 'nonce': nonce});
|
||||
final fakeUrl = Uri.parse(
|
||||
'${AppConfig.hivemindApiBase}/admob/callback?signature=test&key_id=test&custom_data=${Uri.encodeComponent(customData)}');
|
||||
final fakeUrl = _url(
|
||||
'/admob/callback?signature=test&key_id=test&custom_data=${Uri.encodeComponent(customData)}');
|
||||
await http.get(fakeUrl).timeout(const Duration(seconds: 8));
|
||||
} catch (_) {}
|
||||
}
|
||||
@@ -62,8 +62,13 @@ class HivemindService {
|
||||
} else if (data['active'] == true && data['vless_uuid'] != null) {
|
||||
final vlessUuid = data['vless_uuid'];
|
||||
|
||||
// Reality tunnel fields — server is source of truth, AppConfig is fallback.
|
||||
final vlessIp = data['vless_ip'] ?? AppConfig.serverDomain;
|
||||
// vless_ip is pinned — even if the API is MITM'd, the tunnel
|
||||
// never goes anywhere except the real server IP.
|
||||
final vlessIp = data['vless_ip'] ?? AppConfig.serverIp;
|
||||
if (vlessIp != AppConfig.serverIp) {
|
||||
throw Exception('API returned unexpected tunnel IP — possible MITM');
|
||||
}
|
||||
|
||||
final vlessPort = data['vless_port'] ?? 8443;
|
||||
final pbk = data['reality_pbk'] ?? '';
|
||||
final sid = data['reality_sid'] ?? '';
|
||||
@@ -96,7 +101,7 @@ class HivemindService {
|
||||
|
||||
static Future<bool> checkHealth() async {
|
||||
try {
|
||||
final url = Uri.parse('${AppConfig.hivemindApiBase}/health');
|
||||
final url = _url('/health');
|
||||
final response = await http.get(url).timeout(const Duration(seconds: 3));
|
||||
return response.statusCode == 200;
|
||||
} catch (_) {
|
||||
@@ -107,7 +112,7 @@ class HivemindService {
|
||||
static Future<bool> verifySession() async {
|
||||
try {
|
||||
final deviceId = await CryptoService.getDeviceId();
|
||||
final url = Uri.parse('${AppConfig.hivemindApiBase}/session/status?device_id=$deviceId');
|
||||
final url = _url('/session/status?device_id=$deviceId');
|
||||
final response = await http.get(url).timeout(const Duration(seconds: 5));
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body);
|
||||
@@ -119,7 +124,7 @@ class HivemindService {
|
||||
|
||||
static Future<void> disconnectAndCleanup() async {
|
||||
final deviceId = await CryptoService.getDeviceId();
|
||||
final url = Uri.parse('${AppConfig.hivemindApiBase}/session/stop');
|
||||
final url = _url('/session/stop');
|
||||
try {
|
||||
await http.post(
|
||||
url,
|
||||
@@ -128,4 +133,9 @@ class HivemindService {
|
||||
).timeout(const Duration(seconds: 3));
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
/// Builds a URI pointing directly at the server IP — no domain involved.
|
||||
static Uri _url(String path) {
|
||||
return Uri.parse('${AppConfig.hivemindApiBase}$path');
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user