feat(app): add secure routing and runtime resilience
Add explicit TUN and SOCKS5 connection modes, app routing controls, authenticated per-session local SOCKS5, Android network monitoring, persistent haptics, resilient session recovery, notification hardening and client-side Hivemind cleanup. Keep the hosted flutter_vless_android 1.1.5 runtime as the base and apply the Android compatibility/security patches at build time instead of restoring the unstable vendored runtime.
This commit is contained in:
1 parent
371db8da9f
commit
8ead3ff249
30 files changed
+3959
-484
No files matched your search
@@ -0,0 +1,89 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
||||
class SecureSocksSession {
|
||||
static const String inboundTag = 'revolt-secure-socks';
|
||||
static final Random _random = Random.secure();
|
||||
|
||||
final int port;
|
||||
final String username;
|
||||
final String password;
|
||||
final String configJson;
|
||||
|
||||
const SecureSocksSession._({
|
||||
required this.port,
|
||||
required this.username,
|
||||
required this.password,
|
||||
required this.configJson,
|
||||
});
|
||||
|
||||
static Future<SecureSocksSession> create(String baseConfig) async {
|
||||
final decoded = jsonDecode(baseConfig);
|
||||
if (decoded is! Map<String, dynamic>) {
|
||||
throw const FormatException('VLESS configuration must be a JSON object.');
|
||||
}
|
||||
|
||||
final reservation = await ServerSocket.bind(
|
||||
InternetAddress.loopbackIPv4,
|
||||
0,
|
||||
shared: false,
|
||||
);
|
||||
final port = reservation.port;
|
||||
await reservation.close();
|
||||
|
||||
if (port <= 1024 || port > 65535) {
|
||||
throw StateError('Could not allocate a safe local SOCKS5 port.');
|
||||
}
|
||||
|
||||
final username = _token(16);
|
||||
final password = _token(32);
|
||||
|
||||
final sourceInbounds = decoded['inbounds'];
|
||||
final inbounds = <dynamic>[];
|
||||
if (sourceInbounds is List) {
|
||||
for (final value in sourceInbounds) {
|
||||
if (value is Map) {
|
||||
final protocol = value['protocol']?.toString().toLowerCase();
|
||||
// ReVolt owns local proxy ingress on Android. Drop imported SOCKS/HTTP
|
||||
// listeners so a stale no-auth proxy cannot remain reachable beside
|
||||
// the authenticated session listener.
|
||||
if (protocol == 'socks' || protocol == 'http') continue;
|
||||
}
|
||||
inbounds.add(value);
|
||||
}
|
||||
}
|
||||
|
||||
inbounds.add(<String, dynamic>{
|
||||
'tag': inboundTag,
|
||||
'port': port,
|
||||
'listen': '127.0.0.1',
|
||||
'protocol': 'socks',
|
||||
'settings': <String, dynamic>{
|
||||
'auth': 'password',
|
||||
'udp': true,
|
||||
'ip': '127.0.0.1',
|
||||
'users': <Map<String, String>>[
|
||||
<String, String>{'user': username, 'pass': password},
|
||||
],
|
||||
},
|
||||
'sniffing': <String, dynamic>{
|
||||
'enabled': true,
|
||||
'destOverride': <String>['http', 'tls'],
|
||||
},
|
||||
});
|
||||
decoded['inbounds'] = inbounds;
|
||||
|
||||
return SecureSocksSession._(
|
||||
port: port,
|
||||
username: username,
|
||||
password: password,
|
||||
configJson: jsonEncode(decoded),
|
||||
);
|
||||
}
|
||||
|
||||
static String _token(int byteCount) {
|
||||
final bytes = List<int>.generate(byteCount, (_) => _random.nextInt(256));
|
||||
return bytes.map((value) => value.toRadixString(16).padLeft(2, '0')).join();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user