From 40db8dee96b2734b1583b82617189d4263c8fd72 Mon Sep 17 00:00:00 2001 From: zefie Date: Fri, 20 Jun 2025 05:08:07 -0400 Subject: [PATCH] numerous fixes due to tests --- zefie_wtvp_minisrv/includes/classes/WTVIRC.js | 291 +++++++++--------- .../{testirc.js => testirc_run.js} | 0 zefie_wtvp_minisrv/testirc_tests.js | 101 ++++++ 3 files changed, 255 insertions(+), 137 deletions(-) rename zefie_wtvp_minisrv/{testirc.js => testirc_run.js} (100%) create mode 100644 zefie_wtvp_minisrv/testirc_tests.js diff --git a/zefie_wtvp_minisrv/includes/classes/WTVIRC.js b/zefie_wtvp_minisrv/includes/classes/WTVIRC.js index 3f814f79..1f349b92 100644 --- a/zefie_wtvp_minisrv/includes/classes/WTVIRC.js +++ b/zefie_wtvp_minisrv/includes/classes/WTVIRC.js @@ -240,12 +240,10 @@ class WTVIRC { socket.signedoff = oldSocket.signedoff; socket.hostname_resolved = oldSocket.hostname_resolved; socket.realhost = oldSocket.realhost; - socket.upgrading_to_tls = false; socket.client_version = oldSocket.client_version; socket.client_caps = oldSocket.client_caps || []; socket.host = oldSocket.host; socket.timestamp = oldSocket.timestamp; - socket.secure = secure; socket.uniqueId = oldSocket.uniqueId; } else { socket.registered = false; @@ -256,14 +254,15 @@ class WTVIRC { socket.signedoff = false; socket.hostname_resolved = false; socket.realhost = socket.remoteAddress; - socket.upgrading_to_tls = false; socket.client_version = ''; socket.client_caps = []; socket.host = this.filterHostname(socket, socket.remoteAddress); - socket.timestamp = this.getDate(); - socket.secure = secure; + socket.timestamp = this.getDate(); socket.uniqueId = `${this.serverId}${this.generateUniqueId(socket)}`; } + socket.secure = secure; + socket.upgrading_to_tls = false; + socket.error_count = 0; await this.doInitialHandshake(socket); socket.on('data', async data => { @@ -320,14 +319,23 @@ class WTVIRC { }); if (!matchedServer) { socket.write(`:${this.servername} :ERROR :Invalid server password\r\n`); - this.terminateSession(socket); - } + socket.error_count++; + setTimeout((socket) => { + if (socket) { + socket.error_count--; + } + }, 60000); + if (socket.error_count >= 5) { + socket.write(`:${this.servername} :ERROR :Too many errors, disconnecting\r\n`); + this.terminateSession(socket, true); + } + return; + } socket.serverinfo = matchedServer return; case 'CAPAB': - if (!socket.is_srv_authorized) { - socket.write(`:${this.servername} :ERROR :Permission denied\r\n`); - return; + if (!this.checkRegistered(socket, true)) { + break; } // Handle CAPAB command from server if (parts.length < 2) { @@ -354,9 +362,8 @@ class WTVIRC { socket.write(`CAPAB :${output_reply.join(' ')}\r\n`); break; case 'SERVER': - if (!socket.is_srv_authorized) { - socket.write(`:${this.servername} :ERROR :Permission denied\r\n`); - return; + if (!this.checkRegistered(socket, true)) { + break; } // Handle SERVER command from server if (parts.length < 6) { @@ -373,6 +380,7 @@ class WTVIRC { socket.isserver = true; this.clients = this.clients.filter(c => c !== socket); this.clientpeak = this.clientpeak - 1; + socket.registered = true; socket.servername = serverName; socket.uniqueId = serverId; socket.serverIdent = line; @@ -409,6 +417,9 @@ class WTVIRC { socket.write(`:${this.serverId} EOB \r\n`); break; case 'SVINFO': + if (!this.checkRegistered(socket, true)) { + break; + } // Handle SVINFO command from server if (parts.length < 4) { if (this.debug) { @@ -431,9 +442,8 @@ class WTVIRC { // Ignore PONG from server break; case 'RESV': - if (!socket.is_srv_authorized) { - socket.write(`:${this.servername} :ERROR :Permission denied\r\n`); - return; + if (!this.checkRegistered(socket)) { + break; } // Handle RESV command from server if (parts.length < 2) { @@ -461,9 +471,8 @@ class WTVIRC { this.broadcastToAllServers(`:${socket.servername} RESV ${targetMask} ${expiry} ${reservedNick} :${reason}\r\n`, socket); break; case 'UID': - if (!socket.is_srv_authorized) { - socket.write(`:${this.servername} :ERROR :Permission denied\r\n`); - return; + if (!this.checkRegistered(socket)) { + break; } // Handle UID command from server if (parts.length < 10) { @@ -496,9 +505,8 @@ class WTVIRC { this.broadcastToAllServers(`:${socket.servername} UID ${nickname} ${server_Id} ${timestamp} +${userModes.join('')} ${username} ${hostname} ${ipaddress} ${ipaddress2} ${userUniqueId} * :${userinfo}\r\n`, socket); break; case 'SVSHOST': - if (!socket.is_srv_authorized) { - socket.write(`:${this.servername} :ERROR :Permission denied\r\n`); - return; + if (!this.checkRegistered(socket)) { + break; } // Handle SVSHOST command from server if (parts.length < 4) { @@ -525,10 +533,8 @@ class WTVIRC { this.broadcastToAllServers(`:${socket.servername} SVSHOST ${uniqueId} ${hostname}\r\n`, socket); break; case 'SVSACCOUNT': - //:00B SVSACCOUNT 00A4KP23X 1750191263 zefie - if (!socket.is_srv_authorized) { - socket.write(`:${this.servername} :ERROR :Permission denied\r\n`); - return; + if (!this.checkRegistered(socket)) { + break; } if (parts.length < 4) { if (this.debug) { @@ -563,9 +569,8 @@ class WTVIRC { } break; case 'SVSNICK': - if (!socket.is_srv_authorized) { - socket.write(`:${this.servername} :ERROR :Permission denied\r\n`); - return; + if (!this.checkRegistered(socket)) { + break; } // Handle SVSNICK command from server if (parts.length < 5) { @@ -582,9 +587,8 @@ class WTVIRC { this.broadcastToAllServers(line, socket); break; case 'SJOIN': - if (!socket.is_srv_authorized) { - socket.write(`:${this.servername} :ERROR :Permission denied\r\n`); - return; + if (!this.checkRegistered(socket)) { + break; } var channel = parts[2]; var modes = parts[3]; @@ -619,9 +623,8 @@ class WTVIRC { this.servers.delete(socket); break; case (command.match(/^\d{3}$/) || {}).input: - if (!socket.is_srv_authorized) { - socket.write(`:${this.servername} :ERROR :Permission denied\r\n`); - return; + if (!this.checkRegistered(socket)) { + break; } // Numeric reply from server // Numeric replies are usually in the format: : @@ -744,9 +747,8 @@ class WTVIRC { targetSocket.write(`:${socket.serverinfo.name} ${numericCode} ${targetID} :${numericMessage}\r\n`); break; default: - if (!socket.is_srv_authorized) { - socket.write(`:${this.servername} :ERROR :Permission denied\r\n`); - return; + if (!this.checkRegistered(socket)) { + break; } if (command.startsWith(':')) { // part out the line to "sourceUniqueId command targetUniqueId :message" @@ -1122,8 +1124,8 @@ class WTVIRC { this.broadcastToAllServers(`:${sourceUniqueId} SVSMODE ${targetUniqueId} ${modes.join('')}\r\n`, socket); break; default: - if (!socket.is_srv_authorized) { - socket.write(`:${this.servername} :ERROR :Permission denied\r\n`); + if (!this.checkRegistered(socket)) { + break; } if (this.debug) { console.warn(`Unhandled server command from ${sourceUniqueId} to ${targetUniqueId}: ${srvCommand} ${message}`); @@ -1255,8 +1257,7 @@ class WTVIRC { const [command, ...params] = line.trim().split(' '); switch (command.toUpperCase()) { case 'OPER': - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } if (!this.oper_enabled) { @@ -1282,8 +1283,7 @@ class WTVIRC { this.broadcastToAllServers(`:${socket.uniqueId} MODE ${socket.uniqueId} +o\r\n`); break; case 'UPTIME': - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } const uptime = this.getDate() - this.server_start_time; @@ -1294,8 +1294,7 @@ class WTVIRC { socket.write(`:${this.servername} 242 ${socket.nickname} :Server uptime is ${days} days, ${hours} hours, ${minutes} minutes, ${seconds} seconds\r\n`); break; case 'KICK': - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } var channel = this.findChannel(params[0]); @@ -1357,8 +1356,7 @@ class WTVIRC { } break; case 'TOPIC': - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } if (params.length < 1) { @@ -1399,8 +1397,7 @@ class WTVIRC { } break; case 'AWAY': - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } this.usertimestamps.set(socket.nickname, this.getDate()); @@ -1452,8 +1449,7 @@ class WTVIRC { } break; case 'MODE': - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } if (params.length < 1) { @@ -1653,8 +1649,7 @@ class WTVIRC { } if (!mode) { // List channel modes - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } let validPrefix = this.channelprefixes.some(prefix => channel.startsWith(prefix)); @@ -1764,14 +1759,15 @@ class WTVIRC { socket.nickname = new_nickname; } this.nicknames.set(socket, socket.nickname); - if (socket.nickname && socket.nickname !== new_nickname) { - socket.write(`:${socket.nickname}!${socket.username}@${socket.host} NICK :${new_nickname}\r\n`); - this.broadcastUser(socket.nickname, `:${socket.nickname}!${socket.username}@${socket.host} NICK :${new_nickname}\r\n`, socket); + if (socket.nickname && socket.newickname != new_nickname) { this.processNickChange(socket, new_nickname); - this.broadcastToAllServers(`:${socket.uniqueId} NICK ${new_nickname} :${this.getDate()}\r\n`); + if (socket.registered) { + socket.write(`:${socket.nickname}!${socket.username}@${socket.host} NICK :${new_nickname}\r\n`); + this.broadcastUser(socket.nickname, `:${socket.nickname}!${socket.username}@${socket.host} NICK :${new_nickname}\r\n`, socket); + this.broadcastToAllServers(`:${socket.uniqueId} NICK ${new_nickname} :${this.getDate()}\r\n`); + } } if (!socket.registered && socket.nickname && socket.username) { - socket.registered = true; var totalSockets = this.clients.length + this.servers.size; var totalSockets = this.clients.length + this.servers.size; this.socketpeak = Math.max(this.socketpeak, totalSockets); @@ -1782,14 +1778,14 @@ class WTVIRC { } break; case 'USER': - socket.username = params[0]; if (params.length < 4) { socket.write(`:${this.servername} 461 ${socket.nickname} USER :Not enough parameters\r\n`); + this.addSocketError(socket); break; } + socket.username = params[0]; socket.userinfo = params.slice(3).join(' ').replace(/^:/, ''); if (!socket.registered && socket.nickname && socket.username) { - socket.registered = true; var totalSockets = this.clients.length + this.servers.size; this.socketpeak = Math.max(this.socketpeak, totalSockets); this.usernames.set(socket.nickname, socket.username); @@ -1800,8 +1796,7 @@ class WTVIRC { break; case 'JOIN': var key = null; - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } channel = params[0]; @@ -2059,8 +2054,7 @@ class WTVIRC { } break; case 'NAMES': - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } if (params.length < 1) { @@ -2092,8 +2086,7 @@ class WTVIRC { this.sendThrottled(socket, output_lines); break; case 'PART': - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } channel = this.findChannel(params[0]); @@ -2131,8 +2124,7 @@ class WTVIRC { this.broadcastToAllServers(`:${socket.uniqueId} PART ${channel}\r\n`); break; case 'INVITE': - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } if (params.length < 2) { @@ -2184,11 +2176,9 @@ class WTVIRC { break; } case 'LIST': - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; - } - let channelsToList; + } let channelsToList; if (params.length > 0 && params[0]) { channelsToList = params[0].split(',').filter(ch => ch.length > 0); } else { @@ -2219,8 +2209,7 @@ class WTVIRC { socket.write(`:${this.servername} 323 ${socket.nickname} :End of /LIST\r\n`); break; case 'WHO': - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.nickname} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } if (!params[0]) { @@ -2342,8 +2331,7 @@ class WTVIRC { } break; case 'PRIVMSG': - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } this.usertimestamps.set(socket.nickname, this.getDate()); @@ -2467,8 +2455,7 @@ class WTVIRC { } break; case 'NOTICE': - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } this.usertimestamps.set(socket.nickname, this.getDate()); @@ -2603,15 +2590,13 @@ class WTVIRC { } break; case 'PING': - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } socket.write(`PONG ${params.join(' ')}\r\n`); break; case 'KLINE': - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } if (!this.isIRCOp(socket.nickname)) { @@ -2650,8 +2635,7 @@ class WTVIRC { await this.scanUsersForKLines(); break; case 'UNKLINE': - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } if (!this.isIRCOp(socket.nickname)) { @@ -2674,8 +2658,7 @@ class WTVIRC { socket.write(`:${this.servername} 381 ${socket.nickname} :KLINE removed for ${targetMask}\r\n`); break; case 'WHOIS': - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } if (params.length < 1) { @@ -2778,8 +2761,7 @@ class WTVIRC { break; case 'EVAL': // VERY DANGEROUS - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } if (!this.isIRCOp(socket.nickname)) { @@ -2798,8 +2780,7 @@ class WTVIRC { } break; case 'KILL': - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } if (!this.isIRCOp(socket.nickname)) { @@ -2832,59 +2813,55 @@ class WTVIRC { this.terminateSession(targetSocket, true); break; case 'QUIT': - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { + break; + } + for (const [ch, users] of this.channels.entries()) { + if (users.has(socket.nickname)) { + if (this.channelops.has(ch) && this.channelops.get(ch) instanceof Set) { + this.channelops.get(ch).delete(socket.nickname); + } + if (this.channelhalfops.has(ch) && this.channelhalfops.get(ch) instanceof Set) { + this.channelhalfops.get(ch).delete(socket.nickname); + } + if (this.channelvoices.has(ch) && this.channelvoices.get(ch) instanceof Set) { + this.channelvoices.get(ch).delete(socket.nickname); + } + } + } + if (params.length > 0) { + let reason = params.join(' '); + if (reason.startsWith(':')) { + reason = reason.slice(1); + } + socket.write(`:${socket.nickname}!${socket.username}@${socket.host} QUIT :${reason}\r\n`); + this.broadcastUser(socket.nickname, `:${socket.nickname}!${socket.username}@${socket.host} QUIT :${reason}\r\n`, socket); + this.broadcastToAllServers(`:${socket.uniqueId} QUIT :${reason}\r\n`); + this.broadcastConnection(socket, `Quit: ${reason}`); + socket.signedoff = true; } else { - for (const [ch, users] of this.channels.entries()) { - if (users.has(socket.nickname)) { - if (this.channelops.has(ch) && this.channelops.get(ch) instanceof Set) { - this.channelops.get(ch).delete(socket.nickname); - } - if (this.channelhalfops.has(ch) && this.channelhalfops.get(ch) instanceof Set) { - this.channelhalfops.get(ch).delete(socket.nickname); - } - if (this.channelvoices.has(ch) && this.channelvoices.get(ch) instanceof Set) { - this.channelvoices.get(ch).delete(socket.nickname); - } - } - } - if (params.length > 0) { - let reason = params.join(' '); - if (reason.startsWith(':')) { - reason = reason.slice(1); - } - socket.write(`:${socket.nickname}!${socket.username}@${socket.host} QUIT :${reason}\r\n`); - this.broadcastUser(socket.nickname, `:${socket.nickname}!${socket.username}@${socket.host} QUIT :${reason}\r\n`, socket); - this.broadcastToAllServers(`:${socket.uniqueId} QUIT :${reason}\r\n`); - this.broadcastConnection(socket, `Quit: ${reason}`); - socket.signedoff = true; - } else { - socket.write(`:${socket.nickname}!${socket.username}@${socket.host} QUIT\r\n`); - this.broadcastUser(socket.nickname, `:${socket.nickname}!${socket.username}@${socket.host} QUIT\r\n`, socket); - this.broadcastToAllServers(`:${socket.uniqueId} QUIT :Client disconnected\r\n`); - this.broadcastConnection(socket, 'Quit: Client disconnected'); - socket.signedoff = true; - } + socket.write(`:${socket.nickname}!${socket.username}@${socket.host} QUIT\r\n`); + this.broadcastUser(socket.nickname, `:${socket.nickname}!${socket.username}@${socket.host} QUIT\r\n`, socket); + this.broadcastToAllServers(`:${socket.uniqueId} QUIT :Client disconnected\r\n`); + this.broadcastConnection(socket, 'Quit: Client disconnected'); + socket.signedoff = true; } this.terminateSession(socket, true); break; case 'MOTD': - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } await this.doMOTD(socket.nickname, socket); break; case 'VERSION': - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } socket.write(`:${this.servername} 351 ${socket.nickname} ${this.servername} zefIRCd ${this.version} :zefIRCd IRC server\r\n`); break; case 'WALLOPS': - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } if (!this.isIRCOp(socket.nickname)) { @@ -2901,8 +2878,7 @@ class WTVIRC { } this.broadcastWallops(`:${socket.nickname}!${socket.username}@${socket.host} WALLOPS :${wallopsMessage}\r\n`); case 'VHOST': - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { break; } if (!this.isIRCOp(socket.nickname) && !this.allow_public_vhosts) { @@ -3560,7 +3536,9 @@ class WTVIRC { async sendThrottled(socket, lines, delayMs = 1) { for (const line of lines) { await new Promise(res => setTimeout(res, delayMs)); - socket.write(line); + if (socket.writable) { + socket.write(line); + } } } @@ -4037,10 +4015,9 @@ class WTVIRC { let sourceUniqueId = this.uniqueids.get(nickname); serverModeMsg = `:${sourceUniqueId} MODE ${channel} `; } else { - if (!socket.registered) { - socket.write(`:${this.servername} 451 ${socket.uniqueId} ${command} :You have not registered\r\n`); + if (!this.checkRegistered(socket)) { return; - } + } serverModeMsg = `:${socket.uniqueId} MODE ${channel} `; } var username = this.usernames.get(nickname); @@ -4192,7 +4169,46 @@ class WTVIRC { this.broadcastChannel(channel, modeMsg); this.broadcastToAllServers(serverModeMsg, socket); } - } + } + + addSocketError(socket) { + socket.error_count++; + if (socket.error_count >= 5) { + if (socket.writable) { + socket.write(`:${this.servername} :ERROR :Too many errors, disconnecting\r\n`); + } + this.terminateSession(socket, true); + return; + } + setTimeout((socket) => { + if (socket) { + socket.error_count--; + } + }, 60000); + } + + checkRegistered(socket, allowUnregistered = false) { + var retval = false + if (socket.isserver) { + if (!socket.is_srv_authorized && (!socket.registered && !allowUnregistered)) { + if (socket.writable) { + socket.write(`:${this.servername} ERROR :Unauthorized\r\n`); + } + this.addSocketError(socket); + } else { + retval = true; // Server is authorized + } + } + if (!socket.registered && (!socket.registered && !allowUnregistered)) { + if (socket.writable) { + socket.write(`:${this.servername} 451 ${socket.uniqueId} :You have not registered\r\n`); + } + this.addSocketError(socket); + } else { + retval = true; // User is registered + } + return retval; + } async doLogin(nickname, socket) { if (await this.scanSocketForKLine(socket)) { @@ -4265,6 +4281,7 @@ class WTVIRC { for (const caps of this.caps) { output_lines.push(`:${this.servername} 005 ${caps}\r\n`); } + socket.registered = true; output_lines.push(`:${this.servername} 042 ${nickname} ${socket.uniqueId} :your unique ID\r\n`); output_lines.push(...(await this.doMOTD(nickname))); @@ -4320,7 +4337,7 @@ class WTVIRC { } output_lines.push(`:${this.servername} 221 ${nickname} :+${this.usermodes.get(nickname).join('')}\r\n`); await this.sendThrottled(socket, output_lines); - this.broadcastConnection(socket); + this.broadcastConnection(socket); } } diff --git a/zefie_wtvp_minisrv/testirc.js b/zefie_wtvp_minisrv/testirc_run.js similarity index 100% rename from zefie_wtvp_minisrv/testirc.js rename to zefie_wtvp_minisrv/testirc_run.js diff --git a/zefie_wtvp_minisrv/testirc_tests.js b/zefie_wtvp_minisrv/testirc_tests.js new file mode 100644 index 00000000..3d53a8f6 --- /dev/null +++ b/zefie_wtvp_minisrv/testirc_tests.js @@ -0,0 +1,101 @@ +'use strict'; +const path = require('path'); +var classPath = path.resolve(__dirname + path.sep + "includes" + path.sep + "classes" + path.sep) + path.sep; +require(classPath + "Prototypes.js"); +const WTVIRC = require(classPath + "WTVIRC.js"); +const { WTVShared, clientShowAlert } = require(classPath + "WTVShared.js"); +const wtvshared = new WTVShared(); // creates minisrv_config +const net = require('net'); + +var minisrv_config = wtvshared.readMiniSrvConfig(true, false, true); + +if (!minisrv_config.config.irc || !minisrv_config.config.irc.enabled) { + console.error('IRC is not enabled in the configuration.'); + process.exit(1); +} + +const HOST = 'localhost'; +const PORT = minisrv_config.config.irc.port; // Example IRC port + +const client = new net.Socket(); + +var lastLine = ''; + +client.connect(PORT, HOST, () => { + console.log(`Connected to ${HOST}:${PORT}`); + // You can send data here, e.g.: + // client.write('NICK testuser\r\n'); + // client.write('USER testuser 0 * :Test User\r\n'); +}); + +client.on('data', (data) => { + console.log('Received:', data.toString()); + lastLine = data.toString(); +}); + +client.on('close', () => { + console.log('Connection closed'); +}); + +client.on('error', (err) => { + console.error('Connection error:', err); +}); + + +testCase4(); + +function testCase1() { + // Try to auth as a server when we are not allowed to + client.write('SERVER testserver 0 * :Test Server\r\n'); + client.write('PASS \b\b\b\b\b\b\b\b\b\b\r\n'); + client.write('SERVER testserver 0 * :Test Server\r\n'); + client.write(`SVINFO 6 6 0 :-1\r\n`); + client.write('PASS \b\b\b\b\b\b\b\b\b\b\r\n'); + // we should be disconnected here +} + +function testCase2() { + // Malformed user authentication + client.write('NICK invaliduser\r\n'); + client.write('USER invaliduser\r\n'); + client.write('NICK invaliduser2\r\n'); + client.write('NICK invaliduser\r\n'); + client.write('USER invaliduser\r\n'); + client.write('USER invaliduser\r\n'); + client.write('USER invaliduser\r\n'); + client.write('USER invaliduser\r\n'); + // we should be disconnected here +} + +async function waitFor(expectedResponse) { + while (!lastLine.includes(expectedResponse)) { + await new Promise(resolve => setTimeout(resolve, 10)); // wait for 10ms + } +} + +async function testCase3() { + // join, msg, quit + client.write('NICK testuser\r\n'); + client.write('USER testuser 0 * :Test User\r\n'); + await waitFor("005"); + client.write('JOIN #testchannel\r\n'); + await new Promise(resolve => setTimeout(resolve, 10)); // wait for 10ms + client.write('PRIVMSG #testchannel :Hello, world!\r\n'); + await new Promise(resolve => setTimeout(resolve, 10)); // wait for 10ms + client.write('PART #testchannel\r\n'); + await new Promise(resolve => setTimeout(resolve, 10)); // wait for 10ms + client.write('QUIT :Goodbye\r\n'); + // we should be disconnected here +} + +function testCase4() { + // Arbitrary commands + client.write('NICK testuser\r\n'); + client.write('MODE testuser +i\r\n'); + client.write('TOPIC #testchannel :New topic\r\n'); + client.write('KICK #testchannel testuser :You have been kicked\r\n'); + client.write('NOTICE testuser :This is a notice\r\n'); + client.write('INVITE testuser #testchannel\r\n'); + client.write('WHO #testchannel\r\n'); + client.write('LIST\r\n'); +} \ No newline at end of file