Files
ReVoltVPN/lib/logic/secure_socks_session.dart
Naveax d2283c07cc fix(app): enforce authenticated ephemeral local SOCKS5 (#9)
Require the active per-session loopback SOCKS credentials and remove unauthenticated fallback behavior from the client diagnostic path.
2026-09-06 11:18:35 +03:00

79 lines
2.2 KiB
Dart

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);
// ReVolt owns local ingress. Never accept listeners supplied by a remote
// or imported Xray config; the client exposes exactly one authenticated
// loopback SOCKS5 listener for the current ephemeral session.
decoded['inbounds'] = <Map<String, dynamic>>[
<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'],
},
},
];
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();
}
}