Add encrypted UDP voice (OCB2-AES128) with TCP fallback

- Port of Mumble's CryptStateOCB2 (XEX* counter-measures, late/lost/replay
  handling, nonce resync), verified against Mumble's OCB2 test vectors
- UDP channel per connection in the main process, to the address the TLS
  connection reached; used only while the server answers UDP pings, falls back
  to the TCP tunnel automatically; "voice over TCP only" setting
- Voice statistics show the live transport
- Information dialog no longer infers the transport from ping counters
- Message box: no padding, input fills the bar; Edit HTML only in descriptions

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 01:14:36 +02:00
co-authored by Claude Opus 5.5
parent 9a3aeb29ad
commit b44b8230d4
19 changed files with 616 additions and 48 deletions
+4 -1
View File
@@ -2,7 +2,7 @@ import tls from 'node:tls';
import { describeCert, type CertDetails } from './certs.ts';
export interface TlsHandlers {
onSecure(info: { fingerprint: string; authorized: boolean; authError: string | null; chain: CertDetails[] }): void;
onSecure(info: { fingerprint: string; authorized: boolean; authError: string | null; chain: CertDetails[]; address: string; port: number }): void;
onData(chunk: Uint8Array): void;
onClose(reason: string): void;
}
@@ -35,6 +35,9 @@ export function openTls(host: string, port: number, cert: string, key: string, h
}
h.onSecure({
chain,
// The server's actual IP, so UDP voice goes to the same machine as the TCP connection
address: socket.remoteAddress ?? host,
port: socket.remotePort ?? port,
fingerprint: chain[0]?.fingerprint256 ?? '',
authorized: socket.authorized,
authError: socket.authorizationError ? String(socket.authorizationError) : null