fix(security): close critical findings #1-3 from issue #17

- TLS: validate cert chain by default; debug-menu toggle to disable
  - Logs: redact secrets in sender/dispatcher payloads
  - Identity: per-install mt_instanceid/deviceId, per-launch clientSessionId
This commit is contained in:
klockky
2026-05-16 23:36:28 +03:00
parent 191ff7133f
commit 4e500ef087
9 changed files with 208 additions and 15 deletions
+13 -5
View File
@@ -5,6 +5,7 @@ import 'dart:typed_data';
import '../config/proxy_config.dart';
import '../utils/logger.dart';
import 'proxy_connector.dart';
import 'tls_config.dart';
import 'vpn_bypass.dart';
enum SocketState { disconnected, connecting, connected }
@@ -106,11 +107,18 @@ class Connection {
? await RawSocket.connect(host, port)
: await RawSocket.connect(host, port, timeout: timeout);
}
return RawSecureSocket.secure(
rawSocket,
host: host,
onBadCertificate: (_) => true,
);
final allowInsecure = await TlsConfig.isInsecureAllowed();
if (allowInsecure) {
logger.w(
'TLS: проверка сертификата отключена (дебаг) — соединение уязвимо к MitM',
);
return RawSecureSocket.secure(
rawSocket,
host: host,
onBadCertificate: (_) => true,
);
}
return RawSecureSocket.secure(rawSocket, host: host);
}
void write(Uint8List data) {
+3 -6
View File
@@ -2,6 +2,7 @@ import 'dart:async';
import '../protocol/packet.dart';
import '../protocol/opcode_map.dart';
import '../utils/log_redact.dart';
import '../utils/logger.dart';
typedef PacketHandler = void Function(Packet packet);
@@ -53,12 +54,8 @@ class PacketDispatcher {
if (packet.cmd == CmdType.ok ||
packet.cmd == CmdType.error ||
packet.cmd == CmdType.notFound) {
final payloadStr = packet.payload.toString();
final displayPayload = packet.opcode == Opcode.login && payloadStr.length > 50
? '${payloadStr.substring(0, 50)}...'
: payloadStr;
logger.i(
'<= {ver: ${packet.api}, cmd: ${packet.cmd}, seq: ${packet.seq}, opcode: ${packet.opcode}, payload: $displayPayload}',
'<= {ver: ${packet.api}, cmd: ${packet.cmd}, seq: ${packet.seq}, opcode: ${packet.opcode}, payload: ${redactForLog(packet.payload)}}',
);
final completer = _pendingRequests.remove(packet.seq);
@@ -84,7 +81,7 @@ class PacketDispatcher {
}
} else if (packet.isPush) {
logger.i(
'<= push {ver: ${packet.api}, cmd: ${packet.cmd}, seq: ${packet.seq}, opcode: ${packet.opcode}, payload: ${packet.payload}}',
'<= push {ver: ${packet.api}, cmd: ${packet.cmd}, seq: ${packet.seq}, opcode: ${packet.opcode}, payload: ${redactForLog(packet.payload)}}',
);
_pushHandlers[packet.opcode]?.call(packet);
_pushController.add(packet);
+2 -1
View File
@@ -1,4 +1,5 @@
import '../protocol/packet.dart';
import '../utils/log_redact.dart';
import '../utils/logger.dart';
import 'connection.dart';
@@ -17,7 +18,7 @@ class PacketSender {
final data = packPacket(opcode, payload, seq: seq);
connection.write(data);
logger.i(
'=> {ver: 10, cmd: 0, seq: $seq, opcode: $opcode, payload: $payload}',
'=> {ver: 10, cmd: 0, seq: $seq, opcode: $opcode, payload: ${redactForLog(payload)}}',
);
return seq;
}
+15
View File
@@ -0,0 +1,15 @@
import 'package:shared_preferences/shared_preferences.dart';
abstract class TlsConfig {
static const String prefKey = 'dev_tls_insecure';
static Future<bool> isInsecureAllowed() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getBool(prefKey) ?? false;
}
static Future<void> setInsecureAllowed(bool value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool(prefKey, value);
}
}