'use strict'; const assert = require('node:assert/strict'); const fs = require('node:fs'); const path = require('node:path'); const test = require('node:test'); const Database = require('better-sqlite3'); const { disconnectDuplicateBotSockets, getAccessibleVoiceChannels, getBotVoiceAccessFailure, isolateBotVoiceSocket, reconcileBotVoiceAccess, registerBotVoiceSocket } = require('../src/botVoice'); const registerAdmin = require('../src/socketHandlers/admin'); const registerVoice = require('../src/socketHandlers/voice'); const BOT_TOKEN = 'a'.repeat(64); function createDb() { const db = new Database(':memory:'); db.exec(` CREATE TABLE users (id INTEGER PRIMARY KEY, is_admin INTEGER DEFAULT 0); CREATE TABLE channels ( id INTEGER PRIMARY KEY, code TEXT, name TEXT, is_dm INTEGER DEFAULT 0, position INTEGER DEFAULT 0, voice_enabled INTEGER DEFAULT 1, voice_user_limit INTEGER DEFAULT 0, voice_bitrate INTEGER DEFAULT 0, role_gate TEXT DEFAULT NULL ); CREATE TABLE channel_members (channel_id INTEGER, user_id INTEGER); CREATE TABLE webhooks ( id INTEGER PRIMARY KEY, name TEXT, token TEXT, channel_id INTEGER, created_by INTEGER, avatar_url TEXT, is_active INTEGER DEFAULT 1, created_at TEXT DEFAULT CURRENT_TIMESTAMP, callback_url TEXT, callback_secret TEXT, subscribed_events TEXT DEFAULT '*', last_delivery_status INTEGER, last_delivery_at TEXT, last_delivery_error TEXT, failure_count INTEGER DEFAULT 0, can_moderate INTEGER DEFAULT 0, can_use_voice INTEGER DEFAULT 0 ); CREATE TABLE server_settings (key TEXT PRIMARY KEY, value TEXT); CREATE TABLE bans (user_id INTEGER PRIMARY KEY, banned_by INTEGER, reason TEXT); CREATE TABLE user_roles (user_id INTEGER, role_id INTEGER, channel_id INTEGER); `); db.prepare('INSERT INTO users (id, is_admin) VALUES (?, ?)').run(10, 0); db.prepare('INSERT INTO users (id, is_admin) VALUES (?, ?)').run(11, 1); const insertChannel = db.prepare(` INSERT INTO channels (id, code, name, is_dm, position, voice_enabled, voice_user_limit, voice_bitrate) VALUES (?, ?, ?, ?, ?, ?, ?, ?) `); insertChannel.run(1, '11111111', 'Assigned', 0, 1, 1, 0, 64); insertChannel.run(2, '22222222', 'Member', 0, 2, 1, 0, 64); insertChannel.run(3, '33333333', 'Private DM', 1, 3, 1, 0, 64); insertChannel.run(4, '44444444', 'Restricted', 0, 4, 1, 0, 64); db.prepare('INSERT INTO channel_members (channel_id, user_id) VALUES (?, ?)').run(2, 10); return db; } function insertBot(db, overrides = {}) { const bot = { id: 7, name: 'Listener', token: BOT_TOKEN, channel_id: 1, created_by: 10, is_active: 1, can_use_voice: 1, ...overrides }; db.prepare(` INSERT INTO webhooks (id, name, token, channel_id, created_by, is_active, can_use_voice) VALUES (@id, @name, @token, @channel_id, @created_by, @is_active, @can_use_voice) `).run(bot); return bot; } function createSocket(id = 'bot-socket') { const outgoing = []; const handlers = new Map(); const rooms = new Set([id]); let packetMiddleware = null; const socket = { id, connected: true, outgoing, handlers, rooms, user: { id: -7, webhookId: 7, botToken: BOT_TOKEN, username: 'bot-7', displayName: 'Listener', channelCode: '11111111', isBot: true }, on(event, handler) { handlers.set(event, handler); }, emit(event, payload) { outgoing.push({ target: id, event, payload }); }, use(handler) { packetMiddleware = handler; }, disconnect() { this.connected = false; }, join(room) { const joined = Array.isArray(room) ? room : [room]; for (const item of joined) rooms.add(item); outgoing.push({ target: 'join', event: room }); return Promise.resolve(); }, leave(room) { rooms.delete(room); outgoing.push({ target: 'leave', event: room }); return Promise.resolve(); }, get packetMiddleware() { return packetMiddleware; } }; return socket; } function createGatewayHarness(db, initialVoiceUsers = null) { const outgoing = []; const sockets = new Map(); const io = { sockets: { sockets }, to(target) { return { emit(event, payload) { outgoing.push({ target, event, payload }); } }; } }; const state = { voiceUsers: initialVoiceUsers || new Map(), voiceLastActivity: new Map() }; let broadcasts = 0; function handleVoiceLeave(socket, code) { const room = state.voiceUsers.get(code); if (room?.get(socket.user.id)?.socketId !== socket.id) return; room.delete(socket.user.id); socket.leave(`voice:${code}`); if (room.size === 0) state.voiceUsers.delete(code); state.voiceLastActivity.delete(socket.user.id); } function register(socket) { sockets.set(socket.id, socket); registerBotVoiceSocket(socket, { io, db, state, broadcastVoiceUsers() { broadcasts++; }, handleVoiceLeave }); return socket; } return { io, state, outgoing, register, handleVoiceLeave, get broadcasts() { return broadcasts; } }; } function createAdminHarness(db, user, io = null) { const handlers = new Map(); const outgoing = []; const socket = { user, on(event, handler) { handlers.set(event, handler); }, emit(event, payload) { outgoing.push({ event, payload }); } }; const actualIo = io || { sockets: { sockets: new Map() }, of() { return { sockets: new Map() }; }, except() { return { emit() {} }; } }; const revoked = []; registerAdmin(socket, { io: actualIo, db, state: { channelUsers: new Map() }, userHasPermission: () => true, getUserEffectiveLevel: () => 0, getUserPermissions: () => [], getUserRoles: () => [], getUserHighestRole: () => null, emitOnlineUsers() {}, broadcastChannelLists() {}, generateUniqueSharedCode: () => '99999999', logAudit() {}, fireWebhookEvent() {}, onReferrerPolicyChange() {}, automod: { invalidate() {}, settings: () => ({}) }, getIdleOnlineUsers: () => [], getUploadUsage: () => ({ byUser: new Map() }), roleGateAllows: () => true, revokeBotVoiceAccess(webhookId, reason) { revoked.push({ webhookId, reason }); } }); return { handlers, outgoing, revoked }; } test('voice channel access is scoped to assignment, membership, or admin ownership', t => { const db = createDb(); t.after(() => db.close()); const memberChannels = getAccessibleVoiceChannels(db, { channel_id: 1, created_by: 10 }); assert.deepEqual(memberChannels.map(channel => channel.code), ['11111111', '22222222']); const adminChannels = getAccessibleVoiceChannels(db, { channel_id: 1, created_by: 11 }); assert.deepEqual(adminChannels.map(channel => channel.code), ['11111111', '22222222', '44444444']); }); test('voice channel access follows the creator role gate and ban', t => { const db = createDb(); t.after(() => db.close()); db.prepare('UPDATE channels SET role_gate = ? WHERE id = 2').run(JSON.stringify({ mode: 'any', roles: [5] })); const codes = () => getAccessibleVoiceChannels(db, { channel_id: 1, created_by: 10 }).map(channel => channel.code); assert.deepEqual(codes(), ['11111111']); db.prepare('INSERT INTO user_roles (user_id, role_id, channel_id) VALUES (10, 5, NULL)').run(); assert.deepEqual(codes(), ['11111111', '22222222']); db.prepare('INSERT INTO bans (user_id, banned_by) VALUES (10, 11)').run(); assert.deepEqual(codes(), []); }); test('active bot access detects token, membership, channel, and permission revocation', t => { const db = createDb(); t.after(() => db.close()); insertBot(db); assert.equal(getBotVoiceAccessFailure(db, 7, ['11111111', '22222222'], BOT_TOKEN), null); db.prepare('DELETE FROM channel_members WHERE channel_id = 2 AND user_id = 10').run(); assert.match(getBotVoiceAccessFailure(db, 7, ['22222222'], BOT_TOKEN), /no longer has access/); db.prepare('UPDATE channels SET voice_enabled = 0 WHERE id = 1').run(); assert.match(getBotVoiceAccessFailure(db, 7, ['11111111'], BOT_TOKEN), /Voice was disabled/); assert.equal(getBotVoiceAccessFailure(db, 7, [], BOT_TOKEN), null); db.prepare("UPDATE webhooks SET token = ? WHERE id = 7").run('b'.repeat(64)); assert.match(getBotVoiceAccessFailure(db, 7, [], BOT_TOKEN), /token was rotated/); db.prepare('UPDATE webhooks SET token = ?, can_use_voice = 0 WHERE id = 7').run(BOT_TOKEN); assert.match(getBotVoiceAccessFailure(db, 7, [], BOT_TOKEN), /permission was revoked/); }); test('a bot whose creator is banned loses its token and its voice session', t => { const db = createDb(); t.after(() => db.close()); insertBot(db); const { getBotVoiceWebhookByToken } = require('../src/botVoice'); assert.ok(getBotVoiceWebhookByToken(db, BOT_TOKEN)); db.prepare('INSERT INTO bans (user_id, banned_by) VALUES (10, 11)').run(); assert.equal(getBotVoiceWebhookByToken(db, BOT_TOKEN), null); assert.match(getBotVoiceAccessFailure(db, 7, [], BOT_TOKEN), /is banned/); }); test('a bot reaches a channel only while its creator could read it', t => { const db = createDb(); t.after(() => db.close()); const { creatorCanReachChannel } = require('../src/botAccess'); const member = { id: 2, is_dm: 0, role_gate: null }; assert.equal(creatorCanReachChannel(db, 10, member), true); assert.equal(creatorCanReachChannel(db, 10, { id: 1, is_dm: 0, role_gate: null }), false); assert.equal(creatorCanReachChannel(db, 11, { id: 4, is_dm: 0, role_gate: null }), true); assert.equal(creatorCanReachChannel(db, null, member), false); assert.equal(creatorCanReachChannel(db, 999, member), false); const gated = { ...member, role_gate: JSON.stringify({ mode: 'any', roles: [5] }) }; assert.equal(creatorCanReachChannel(db, 10, gated), false); db.prepare('INSERT INTO user_roles (user_id, role_id, channel_id) VALUES (10, 5, NULL)').run(); assert.equal(creatorCanReachChannel(db, 10, gated), true); db.prepare('INSERT INTO bans (user_id, banned_by) VALUES (10, 11)').run(); assert.equal(creatorCanReachChannel(db, 10, gated), false); }); test('bot voice gateway joins visibly, relays authorized signaling, and refreshes AFK activity', t => { const db = createDb(); t.after(() => db.close()); insertBot(db); const room = new Map([[ 42, { id: 42, username: 'Human', socketId: 'human-socket', isMuted: false, isDeafened: false } ]]); const harness = createGatewayHarness(db, new Map([['11111111', room]])); const socket = harness.register(createSocket()); let acknowledgement; socket.handlers.get('voice-join')({ code: '11111111' }, result => { acknowledgement = result; }); assert.equal(acknowledgement.success, true); assert.equal(harness.state.voiceUsers.get('11111111').get(-7).isListening, true); assert.equal(harness.broadcasts, 1); assert.ok(harness.outgoing.some(item => item.target === 'human-socket' && item.event === 'voice-user-joined' && item.payload.user.isBot )); socket.handlers.get('voice-offer')({ code: '11111111', targetUserId: 42, offer: { type: 'offer', sdp: 'test' } }); assert.ok(harness.outgoing.some(item => item.target === 'human-socket' && item.event === 'voice-offer' && item.payload.from.isBot )); harness.state.voiceLastActivity.set(-7, 1); socket.handlers.get('voice-speaking')({ speaking: true }); assert.ok(harness.state.voiceLastActivity.get(-7) > 1); harness.state.voiceLastActivity.set(-7, 1); socket.handlers.get('voice-activity')(); assert.ok(harness.state.voiceLastActivity.get(-7) > 1); db.prepare('UPDATE webhooks SET can_use_voice = 0 WHERE id = 7').run(); let middlewareError; socket.packetMiddleware(['voice-speaking', { speaking: true }], error => { middlewareError = error; }); assert.match(middlewareError.message, /permission was revoked/); assert.equal(socket.connected, false); assert.equal(harness.state.voiceUsers.get('11111111').has(-7), false); }); test('a replaced bot socket is disconnected and cannot signal as its replacement', t => { const db = createDb(); t.after(() => db.close()); insertBot(db); const room = new Map([[ 42, { id: 42, username: 'Human', socketId: 'human-socket', isMuted: false, isDeafened: false } ]]); const harness = createGatewayHarness(db, new Map([['11111111', room]])); const first = harness.register(createSocket('bot-old')); first.handlers.get('voice-join')({ code: '11111111' }, () => {}); const second = harness.register(createSocket('bot-new')); second.handlers.get('voice-join')({ code: '11111111' }, () => {}); assert.equal(first.connected, false); assert.equal(harness.state.voiceUsers.get('11111111').get(-7).socketId, 'bot-new'); const before = harness.outgoing.length; first.handlers.get('voice-offer')({ code: '11111111', targetUserId: 42, offer: { type: 'offer', sdp: 'stale' } }); assert.equal(harness.outgoing.length, before); }); test('a failed join to a full channel keeps the bot in its current channel', t => { const db = createDb(); t.after(() => db.close()); insertBot(db); db.prepare('UPDATE channels SET voice_user_limit = 1 WHERE id = 2').run(); const harness = createGatewayHarness(db, new Map([ ['11111111', new Map()], ['22222222', new Map([[42, { id: 42, username: 'Human', socketId: 'human-socket' }]])] ])); const socket = harness.register(createSocket()); socket.handlers.get('voice-join')({ code: '11111111' }, () => {}); let result; socket.handlers.get('voice-join')({ code: '22222222' }, response => { result = response; }); assert.match(result.error, /Voice is full/); assert.equal(harness.state.voiceUsers.get('11111111').get(-7).socketId, socket.id); }); test('a voice-disabled channel rejects join without leaving the current channel', t => { const db = createDb(); t.after(() => db.close()); insertBot(db); db.prepare('UPDATE channels SET voice_enabled = 0 WHERE id = 2').run(); const harness = createGatewayHarness(db); const socket = harness.register(createSocket()); socket.handlers.get('voice-join')({ code: '11111111' }, () => {}); let result; socket.handlers.get('voice-join')({ code: '22222222' }, response => { result = response; }); assert.match(result.error, /Voice is disabled/); assert.equal(harness.state.voiceUsers.get('11111111').get(-7).socketId, socket.id); }); test('periodic reconciliation revokes an idle bot without waiting for another packet', t => { const db = createDb(); t.after(() => db.close()); insertBot(db); const socket = createSocket(); socket.rooms.add('voice:11111111'); const io = { sockets: { sockets: new Map([[socket.id, socket]]) } }; const state = { voiceUsers: new Map() }; db.prepare('UPDATE webhooks SET can_use_voice = 0 WHERE id = 7').run(); const revoked = []; const count = reconcileBotVoiceAccess(io, db, state, (webhookId, reason) => { revoked.push({ webhookId, reason }); }); assert.equal(count, 1); assert.deepEqual(revoked, [{ webhookId: 7, reason: 'Bot voice permission was revoked' }]); }); test('duplicate process protection disconnects the previous bot before it can keep voice ownership', t => { const db = createDb(); t.after(() => db.close()); insertBot(db); const oldSocket = createSocket('bot-old'); const newSocket = createSocket('bot-new'); const state = { voiceUsers: new Map([['11111111', new Map([[-7, { id: -7, username: 'Listener', socketId: oldSocket.id, isBot: true }]])]]), voiceLastActivity: new Map([[-7, Date.now()]]) }; const io = { sockets: { sockets: new Map([[oldSocket.id, oldSocket], [newSocket.id, newSocket]]) } }; function handleVoiceLeave(socket, code) { const room = state.voiceUsers.get(code); if (room?.get(socket.user.id)?.socketId === socket.id) room.delete(socket.user.id); } assert.equal(disconnectDuplicateBotSockets(newSocket, { io, state, handleVoiceLeave }), 1); assert.equal(oldSocket.connected, false); assert.equal(state.voiceUsers.get('11111111').has(-7), false); }); test('bot sockets can join voice rooms but cannot join or receive textual/global rooms', () => { const socket = createSocket(); isolateBotVoiceSocket(socket); socket.join('channel:11111111'); socket.join(['voice:11111111', 'admins', 'channel:22222222']); assert.equal(socket.rooms.has('bot-sockets'), true); assert.equal(socket.rooms.has('voice:11111111'), true); assert.equal(socket.rooms.has('channel:11111111'), false); assert.equal(socket.rooms.has('channel:22222222'), false); assert.equal(socket.rooms.has('admins'), false); }); test('only admins can change voice permission and revocation is immediate', t => { const db = createDb(); t.after(() => db.close()); insertBot(db, { can_use_voice: 0 }); // A moderator outside the bot's channel cannot touch it at all. const outsider = createAdminHarness(db, { id: 20, isAdmin: false }); outsider.handlers.get('update-webhook')({ id: 7, can_use_voice: 1 }); assert.equal(db.prepare('SELECT can_use_voice FROM webhooks WHERE id = 7').get().can_use_voice, 0); assert.match(outsider.outgoing.at(-1).payload, /Webhook not found/); // One in the channel still cannot change its voice permission. db.prepare('INSERT INTO channel_members (channel_id, user_id) VALUES (?, ?)').run(1, 20); const moderator = createAdminHarness(db, { id: 20, isAdmin: false }); moderator.handlers.get('update-webhook')({ id: 7, can_use_voice: 1 }); assert.equal(db.prepare('SELECT can_use_voice FROM webhooks WHERE id = 7').get().can_use_voice, 0); assert.match(moderator.outgoing.at(-1).payload, /Only admins/); const admin = createAdminHarness(db, { id: 11, isAdmin: true }); admin.handlers.get('update-webhook')({ id: 7, can_use_voice: 1 }); assert.equal(db.prepare('SELECT can_use_voice FROM webhooks WHERE id = 7').get().can_use_voice, 1); admin.handlers.get('update-webhook')({ id: 7, can_use_voice: 0 }); assert.equal(db.prepare('SELECT can_use_voice FROM webhooks WHERE id = 7').get().can_use_voice, 0); assert.match(admin.revoked.at(-1).reason, /permission was revoked/); }); test('non-admin integration managers cannot obtain privileged bot tokens owned by someone else', t => { const db = createDb(); t.after(() => db.close()); insertBot(db); insertBot(db, { id: 8, name: 'Admin Listener', token: 'd'.repeat(64), created_by: 11, can_use_voice: 0 }); insertBot(db, { id: 9, name: 'Elsewhere', token: 'e'.repeat(64), channel_id: 4, created_by: 11, can_use_voice: 0 }); db.prepare('INSERT INTO channel_members (channel_id, user_id) VALUES (?, ?)').run(1, 10); const moderator = createAdminHarness(db, { id: 10, isAdmin: false }); moderator.handlers.get('get-webhooks')(); let list = moderator.outgoing.filter(item => item.event === 'webhooks-list').at(-1).payload.webhooks; // Bots in channels the moderator is not in are not listed at all. assert.equal(list.some(webhook => webhook.id === 9), false); assert.equal(list.find(webhook => webhook.id === 7).token, BOT_TOKEN); assert.equal(list.find(webhook => webhook.id === 8).token, null); db.prepare('UPDATE webhooks SET can_use_voice = 1 WHERE id = 8').run(); moderator.handlers.get('get-webhooks')(); list = moderator.outgoing.filter(item => item.event === 'webhooks-list').at(-1).payload.webhooks; assert.equal(list.find(webhook => webhook.id === 8).token, null); }); test('human voice snapshots preserve bot identity and listening state', t => { const db = createDb(); t.after(() => db.close()); const handlers = new Map(); const outgoing = []; const socket = { id: 'human-socket', user: { id: 10, username: 'human', displayName: 'Human', isAdmin: false }, on(event, handler) { handlers.set(event, handler); }, emit(event, payload) { outgoing.push({ event, payload }); } }; const state = { channelUsers: new Map(), voiceUsers: new Map([['11111111', new Map([[-7, { id: -7, username: 'Listener', socketId: 'bot-socket', isMuted: false, isDeafened: false, isBot: true, isListening: true }]])]]), voiceLastActivity: new Map(), activeMusic: new Map(), activeScreenSharers: new Map(), activeWebcamUsers: new Map(), streamViewers: new Map(), pendingTempDelete: new Map(), pendingVoiceLeave: new Map() }; registerVoice(socket, { io: { to() { return { emit() {}, to() { return { emit() {} }; } }; } }, db, state, userHasPermission: () => true, getUserEffectiveLevel: () => 0, getUserHighestRole: () => null, broadcastVoiceUsers() {}, emitOnlineUsers() {}, handleVoiceLeave() {}, touchVoiceActivity() {}, pruneStaleVoiceUsers: () => [], voiceCodesVisibleTo: (userId) => new Set(db.prepare('SELECT c.code FROM channels c JOIN channel_members cm ON cm.channel_id = c.id WHERE cm.user_id = ?').all(userId).map(r => r.code)), getMentionableChannelMembers: () => [], getActiveMusicSyncState: () => null, getMusicQueuePayload: () => ({}) }); // Not a member of the voice room's channel: nothing comes back. handlers.get('request-voice-users')({ code: '11111111' }); handlers.get('get-voice-counts')(); assert.equal(outgoing.some(item => item.event === 'voice-users-update' || item.event === 'voice-count-update'), false); db.prepare('INSERT INTO channel_members (channel_id, user_id) VALUES (?, ?)').run(1, 10); handlers.get('request-voice-users')({ code: '11111111' }); handlers.get('get-voice-counts')(); const roster = outgoing.find(item => item.event === 'voice-users-update').payload.users[0]; const count = outgoing.find(item => item.event === 'voice-count-update').payload.users[0]; assert.equal(roster.isBot, true); assert.equal(roster.isListening, true); assert.equal(count.isBot, true); assert.equal(count.isListening, true); }); test('kicking a bot from voice clears its dynamic audio queue', t => { const db = createDb(); t.after(() => db.close()); const handlers = new Map(); const moderator = { id: 'human-socket', user: { id: 10, username: 'human', displayName: 'Human', isAdmin: true }, on(event, handler) { handlers.set(event, handler); }, emit() {} }; const botSocket = { leave() {} }; const state = { channelUsers: new Map(), voiceUsers: new Map([['11111111', new Map([ [10, { id: 10, username: 'Human', socketId: 'human-socket' }], [-7, { id: -7, username: 'Listener', socketId: 'bot-socket', isBot: true }] ])]]), voiceLastActivity: new Map(), activeMusic: new Map(), activeScreenSharers: new Map(), activeWebcamUsers: new Map(), streamViewers: new Map(), pendingTempDelete: new Map(), pendingVoiceLeave: new Map() }; const stopped = []; registerVoice(moderator, { io: { sockets: { sockets: new Map([['bot-socket', botSocket]]) }, to() { return { emit() {}, to() { return { emit() {} }; } }; } }, db, state, userHasPermission: () => true, getUserEffectiveLevel: userId => userId === 10 ? 10 : 0, getUserHighestRole: () => null, broadcastVoiceUsers() {}, emitOnlineUsers() {}, handleVoiceLeave() {}, touchVoiceActivity() {}, pruneStaleVoiceUsers: () => [], getMentionableChannelMembers: () => [], getActiveMusicSyncState: () => null, getMusicQueuePayload: () => ({}), botAudioManager: { stopWebhook(webhookId) { stopped.push(webhookId); } } }); handlers.get('voice-kick')({ code: '11111111', userId: -7 }); assert.deepEqual(stopped, [7]); assert.equal(state.voiceUsers.get('11111111').has(-7), false); }); test('administrative global broadcasts explicitly exclude bot sockets', t => { const db = createDb(); t.after(() => db.close()); const broadcasts = []; const io = { sockets: { sockets: new Map() }, of() { return { sockets: new Map() }; }, emit(event) { broadcasts.push({ room: null, event }); }, except(room) { return { emit(event, payload) { broadcasts.push({ room, event, payload }); } }; } }; const admin = createAdminHarness(db, { id: 11, isAdmin: true }, io); admin.handlers.get('update-server-setting')({ key: 'server_name', value: 'Gateway Test' }); assert.equal(broadcasts.some(item => item.room === null), false); assert.ok(broadcasts.some(item => item.room === 'bot-sockets' && item.event === 'server-setting-changed')); }); test('server namespace broadcasts always declare the bot exclusion room', () => { const root = path.resolve(__dirname, '..'); const files = [ path.join(root, 'src/channelRotation.js'), ...fs.readdirSync(path.join(root, 'src/socketHandlers')) .filter(file => file.endsWith('.js')) .map(file => path.join(root, 'src/socketHandlers', file)) ]; for (const file of files) { const source = fs.readFileSync(file, 'utf8'); assert.doesNotMatch(source, /\bio\.emit\(/, `${path.basename(file)} has an unrestricted io.emit`); assert.doesNotMatch(source, /\bsocket\.broadcast\.emit\(/, `${path.basename(file)} has an unrestricted broadcast.emit`); } });