fix(dave): hard RUN_MS time-box ceiling armed at startup, not on ready gate
The RUN_MS auto-leave was only armed inside announceReady(), which requires a fully successful join (DAVE/MLS op29/op30 -> mlsReady). When the E2EE handshake stalls after op26 key_package, announceReady never fires, so the "time-boxed" selfbot ran unbounded in a live channel. Arm RUN_MS at process startup instead, independent of handshake state, and make leaveAndExit idempotent so the ceiling, ready timer, and signal handlers can't double-fire. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -46,7 +46,10 @@ const ssrcToUser = new Map(); // audio ssrc -> user id
|
|||||||
const rtpCount = new Map(); // ssrc -> packet count
|
const rtpCount = new Map(); // ssrc -> packet count
|
||||||
const voiceState = { session_id: null, token: null, endpoint: null, ssrc: null, ip: null, port: null, mode: null };
|
const voiceState = { session_id: null, token: null, endpoint: null, ssrc: null, ip: null, port: null, mode: null };
|
||||||
|
|
||||||
|
let leaving = false;
|
||||||
function leaveAndExit(code = 0) {
|
function leaveAndExit(code = 0) {
|
||||||
|
if (leaving) return; // idempotent: hard ceiling + ready timer + signals must not double-fire
|
||||||
|
leaving = true;
|
||||||
try { mainWs?.send(JSON.stringify({ op: 4, d: { guild_id: GUILD_ID, channel_id: null, self_mute: true, self_deaf: true } })); } catch {}
|
try { mainWs?.send(JSON.stringify({ op: 4, d: { guild_id: GUILD_ID, channel_id: null, self_mute: true, self_deaf: true } })); } catch {}
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
try { voiceWs?.close(); } catch {}
|
try { voiceWs?.close(); } catch {}
|
||||||
@@ -59,6 +62,11 @@ function leaveAndExit(code = 0) {
|
|||||||
process.on('SIGINT', () => { log('SIGINT'); leaveAndExit(0); });
|
process.on('SIGINT', () => { log('SIGINT'); leaveAndExit(0); });
|
||||||
process.on('SIGTERM', () => { log('SIGTERM'); leaveAndExit(0); });
|
process.on('SIGTERM', () => { log('SIGTERM'); leaveAndExit(0); });
|
||||||
|
|
||||||
|
// Hard time-box ceiling, armed at startup regardless of handshake state. Without
|
||||||
|
// this, a partial join (e.g. DAVE/MLS never completes op29/op30 so announceReady
|
||||||
|
// never fires) would run the selfbot forever — a guardrail hole for a live test.
|
||||||
|
if (RUN_MS > 0) setTimeout(() => { log(`RUN_MS=${RUN_MS} hard ceiling elapsed — leaving`); leaveAndExit(0); }, RUN_MS);
|
||||||
|
|
||||||
// ---------- MAIN GATEWAY ----------
|
// ---------- MAIN GATEWAY ----------
|
||||||
mainWs = new WebSocket('wss://gateway.discord.gg/?v=10&encoding=json');
|
mainWs = new WebSocket('wss://gateway.discord.gg/?v=10&encoding=json');
|
||||||
let mainHb;
|
let mainHb;
|
||||||
@@ -190,7 +198,7 @@ function maybeConnectVoice() {
|
|||||||
announced = true;
|
announced = true;
|
||||||
log(`✅ JOINED & READY. channel=${CHANNEL_ID} dave=${voiceState.daveVer} mlsReady=${mlsReady} privacyCode=${daveSession?.voicePrivacyCode || 'n/a'}`);
|
log(`✅ JOINED & READY. channel=${CHANNEL_ID} dave=${voiceState.daveVer} mlsReady=${mlsReady} privacyCode=${daveSession?.voicePrivacyCode || 'n/a'}`);
|
||||||
log(' staying connected, listening for speakers…');
|
log(' staying connected, listening for speakers…');
|
||||||
if (RUN_MS > 0) setTimeout(() => { log(`RUN_MS=${RUN_MS} elapsed`); leaveAndExit(0); }, RUN_MS);
|
// time-box is owned by the startup hard-ceiling timer (armed regardless of ready state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user