many improvements and fixes
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
const net = require('net');
|
const net = require('net');
|
||||||
|
const dns = require('dns');
|
||||||
|
|
||||||
class WTVIRC {
|
class WTVIRC {
|
||||||
/*
|
/*
|
||||||
@@ -24,8 +25,10 @@ class WTVIRC {
|
|||||||
this.channelinvites = new Map(); // channel -> Set of invited users
|
this.channelinvites = new Map(); // channel -> Set of invited users
|
||||||
this.channelbans = new Map(); // channel -> Set of banned users
|
this.channelbans = new Map(); // channel -> Set of banned users
|
||||||
this.channelexemptions = new Map(); // channel -> Set of exempted users
|
this.channelexemptions = new Map(); // channel -> Set of exempted users
|
||||||
|
this.inviteexceptions = new Map(); // channel -> Set of users who can bypass invite only mode
|
||||||
this.channelmodes = new Map(); // channel -> Array of modes (e.g. ['m', 'i', 'l10', 'k secret'])
|
this.channelmodes = new Map(); // channel -> Array of modes (e.g. ['m', 'i', 'l10', 'k secret'])
|
||||||
this.usertimestamps = new Map(); // nickname -> timestamp since last message
|
this.usertimestamps = new Map(); // nickname -> timestamp since last message
|
||||||
|
this.usermodes = new Map(); // nickname -> Array of modes (e.g. ['w', 'i'])
|
||||||
this.usersignontimestamps = new Map(); // nickname -> timestamp since user signed on
|
this.usersignontimestamps = new Map(); // nickname -> timestamp since user signed on
|
||||||
this.nicknames = new Map(); // socket -> nickname
|
this.nicknames = new Map(); // socket -> nickname
|
||||||
this.awaymsgs = new Map(); // nickname -> away message
|
this.awaymsgs = new Map(); // nickname -> away message
|
||||||
@@ -40,8 +43,11 @@ class WTVIRC {
|
|||||||
this.kicklen = 390;
|
this.kicklen = 390;
|
||||||
this.awaylen = 200;
|
this.awaylen = 200;
|
||||||
this.channelprefixes = ['#','&'];
|
this.channelprefixes = ['#','&'];
|
||||||
|
this.default_channel_modes = ['t'];
|
||||||
this.servername = 'irc.local';
|
this.servername = 'irc.local';
|
||||||
this.server_start_time = Date.now();
|
this.server_start_time = Date.now();
|
||||||
|
this.oper_username = minisrv_config.config.irc_oper_username || 'minisrv';
|
||||||
|
this.oper_password = minisrv_config.config.irc_oper_password || 'changeme573';
|
||||||
this.caps = `AWAYLEN=${this.awaylen} CHANTYPES=${this.channelprefixes.join('')} PREFIX=(ov)@+ CHANMODES=beI,k,l,imnp SAFELIST MAXLIST=b:${this.maxbans},e:${this.maxexcept},i:${this.maxinvite},k:${this.maxkeylen},l:${this.maxlimit} CHANLIMIT=${this.channelprefixes.join('')}:${this.channellimit} NICKLEN=${this.nicklen} TOPICLEN=${this.topiclen} KICKLEN=${this.kicklen}`;
|
this.caps = `AWAYLEN=${this.awaylen} CHANTYPES=${this.channelprefixes.join('')} PREFIX=(ov)@+ CHANMODES=beI,k,l,imnp SAFELIST MAXLIST=b:${this.maxbans},e:${this.maxexcept},i:${this.maxinvite},k:${this.maxkeylen},l:${this.maxlimit} CHANLIMIT=${this.channelprefixes.join('')}:${this.channellimit} NICKLEN=${this.nicklen} TOPICLEN=${this.topiclen} KICKLEN=${this.kicklen}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +61,7 @@ class WTVIRC {
|
|||||||
let nickname = '';
|
let nickname = '';
|
||||||
let username = '';
|
let username = '';
|
||||||
let channel = '';
|
let channel = '';
|
||||||
let host = socket.remoteAddress || 'minisrv.local';
|
let host = this.getHostname(socket);
|
||||||
let timestamp = Date.now();
|
let timestamp = Date.now();
|
||||||
|
|
||||||
if (this.debug) {
|
if (this.debug) {
|
||||||
@@ -82,6 +88,32 @@ class WTVIRC {
|
|||||||
}
|
}
|
||||||
const [command, ...params] = line.trim().split(' ');
|
const [command, ...params] = line.trim().split(' ');
|
||||||
switch (command.toUpperCase()) {
|
switch (command.toUpperCase()) {
|
||||||
|
case 'OPER':
|
||||||
|
if (!registered) {
|
||||||
|
socket.write(`:${this.servername} 451 ${nickname} :You have not registered\r\n`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (params.length < 2) {
|
||||||
|
socket.write(`:${this.servername} 461 ${nickname} OPER :Not enough parameters\r\n`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const [operName, operPassword] = params;
|
||||||
|
if (operName !== this.oper_username) {
|
||||||
|
socket.write(`:${this.servername} 491 ${nickname} :No permission\r\n`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (operPassword !== this.oper_password) {
|
||||||
|
socket.write(`:${this.servername} 464 ${nickname} :Password incorrect\r\n`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
var usermodes = this.usermodes.get(nickname) || [];
|
||||||
|
if (usermodes === true) {
|
||||||
|
usermodes = [];
|
||||||
|
}
|
||||||
|
this.usermodes.set(nickname, [...usermodes, 'o']);
|
||||||
|
socket.write(`:${this.servername} 381 ${nickname} :You are now an IRC operator\r\n`);
|
||||||
|
socket.write(`:${nickname}!${username}@${host} MODE ${nickname} +o\r\n`);
|
||||||
|
break;
|
||||||
case 'UPTIME':
|
case 'UPTIME':
|
||||||
if (!registered) {
|
if (!registered) {
|
||||||
socket.write(`:${this.servername} 451 ${nickname} :You have not registered\r\n`);
|
socket.write(`:${this.servername} 451 ${nickname} :You have not registered\r\n`);
|
||||||
@@ -135,22 +167,21 @@ class WTVIRC {
|
|||||||
if (params.length < 1) {
|
if (params.length < 1) {
|
||||||
socket.write(`:${this.servername} 461 ${nickname} TOPIC :Not enough parameters\r\n`);
|
socket.write(`:${this.servername} 461 ${nickname} TOPIC :Not enough parameters\r\n`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
const chanmodes = this.channelmodes.get(channel) || [];
|
||||||
|
if (chanmodes.includes('t')) {
|
||||||
|
// Only allow channel operators to change the topic if +t is set
|
||||||
|
if (!this.channelops.has(channel) || !this.channelops.get(channel).has(nickname)) {
|
||||||
|
socket.write(`:${this.servername} 482 ${nickname} ${channel} :You're not channel operator\r\n`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
this.usertimestamps.set(nickname, Date.now());
|
this.usertimestamps.set(nickname, Date.now());
|
||||||
channel = params[0];
|
channel = params[0];
|
||||||
if (!this.channels.has(channel)) {
|
if (!this.channels.has(channel)) {
|
||||||
socket.write(`:${this.servername} 403 ${nickname} ${channel} :No such channel\r\n`);
|
socket.write(`:${this.servername} 403 ${nickname} ${channel} :No such channel\r\n`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!this.channelops.has(channel) || this.channelops.get(channel) === true) {
|
|
||||||
socket.write(`:${this.servername} 482 ${nickname} ${channel} :You're not channel operator\r\n`);
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
if (!this.channelops.get(channel).has(nickname)) {
|
|
||||||
socket.write(`:${this.servername} 482 ${nickname} ${channel} :You're not channel operator\r\n`);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (params.length > 1) {
|
if (params.length > 1) {
|
||||||
var topic = params.slice(1).join(' ');
|
var topic = params.slice(1).join(' ');
|
||||||
if (topic.startsWith(':')) {
|
if (topic.startsWith(':')) {
|
||||||
@@ -198,24 +229,79 @@ class WTVIRC {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
channel = params[0];
|
channel = params[0];
|
||||||
|
var isChannel = true;
|
||||||
if (!this.channels.has(channel)) {
|
if (!this.channels.has(channel)) {
|
||||||
socket.write(`:${this.servername} 403 ${nickname} ${channel} :No such channel\r\n`);
|
isChannel = false;
|
||||||
|
}
|
||||||
|
// Check if 'channel' is actually a user (nickname) instead of a channel name
|
||||||
|
let isUser = false;
|
||||||
|
for (const prefix of this.channelprefixes) {
|
||||||
|
if (channel.startsWith(prefix)) {
|
||||||
|
isUser = false;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
isUser = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isChannel && !isUser) {
|
||||||
|
socket.write(`:${this.servername} 403 ${nickname} ${channel} :No such channel or user\r\n`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const mode = params[1];
|
const mode = params[1];
|
||||||
|
if (isUser) {
|
||||||
|
if (!this.isIRCOp(nickname) && channel !== nickname) {
|
||||||
|
socket.write(`:${this.servername} 501 ${nickname} :Cannot set modes on other users\r\n`);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
var usermodes = this.usermodes.get(nickname) || [];
|
||||||
|
if (usermodes === true) {
|
||||||
|
usermodes = [];
|
||||||
|
}
|
||||||
|
if (!mode) {
|
||||||
|
// List user modes
|
||||||
|
if (usermodes.length === 0) {
|
||||||
|
socket.write(`:${this.servername} 324 ${nickname} ${channel} :No modes set\r\n`);
|
||||||
|
} else {
|
||||||
|
const modes = usermodes.map(m => (m.startsWith('+') ? m : '+' + m)).join(' ');
|
||||||
|
socket.write(`:${this.servername} 324 ${nickname} ${channel} :${modes}\r\n`);
|
||||||
|
}
|
||||||
|
} else if (mode.startsWith('+h')) {
|
||||||
|
this.usermodes.set(nickname, [...usermodes, 'h']);
|
||||||
|
host = this.getHostname(socket);
|
||||||
|
socket.write(`:${nickname}!${username}@${host} MODE ${nickname} +h\r\n`);
|
||||||
|
} else if (mode.startsWith('-h')) {
|
||||||
|
this.usermodes.set(nickname, (usermodes).filter(m => m !== 'h'));
|
||||||
|
host = this.getHostname(socket);
|
||||||
|
socket.write(`:${nickname}!${username}@${host} MODE ${nickname} -h\r\n`);
|
||||||
|
} else if (mode.startsWith('+w')) {
|
||||||
|
this.usermodes.set(nickname, [...usermodes, 'w']);
|
||||||
|
socket.write(`:${nickname}!${username}@${host} MODE ${nickname} +w\r\n`);
|
||||||
|
} else if (mode.startsWith('-w')) {
|
||||||
|
this.usermodes.set(nickname, (usermodes).filter(m => m !== 'w'));
|
||||||
|
socket.write(`:${nickname}!${username}@${host} MODE ${nickname} -w\r\n`);
|
||||||
|
} else if (mode.startsWith('+i')) {
|
||||||
|
this.usermodes.set(nickname, [...usermodes, 'i']);
|
||||||
|
socket.write(`:${nickname}!${username}@${host} MODE ${nickname} +i\r\n`);
|
||||||
|
} else if (mode.startsWith('-i')) {
|
||||||
|
this.usermodes.set(nickname, (usermodes).filter(m => m !== 'i'));
|
||||||
|
socket.write(`:${nickname}!${username}@${host} MODE ${nickname} -i\r\n`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (!mode) {
|
if (!mode) {
|
||||||
var chanmodes = this.channelmodes.get(channel);
|
var chan_modes = this.channelmodes.get(channel);
|
||||||
if (!chanmodes || chanmodes === true) {
|
if (!chan_modes || chan_modes === true) {
|
||||||
chanmodes = [];
|
chan_modes = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
chanmodes = chanmodes.map(mode => {
|
chan_modes = chan_modes.map(mode => {
|
||||||
if (typeof mode === 'string' && !mode.startsWith('+')) {
|
if (typeof mode === 'string' && !mode.startsWith('+')) {
|
||||||
return '+' + mode;
|
return '+' + mode;
|
||||||
}
|
}
|
||||||
return mode;
|
return mode;
|
||||||
});
|
});
|
||||||
chanmodes.forEach(m => {
|
chan_modes.forEach(m => {
|
||||||
socket.write(`:${this.servername} 324 ${nickname} ${channel} ${m}\r\n`);
|
socket.write(`:${this.servername} 324 ${nickname} ${channel} ${m}\r\n`);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
@@ -229,12 +315,12 @@ class WTVIRC {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var chanmodes = this.channelmodes.get(channel);
|
var chan_modes = this.channelmodes.get(channel);
|
||||||
if (!chanmodes || chanmodes === true) {
|
if (!chan_modes || chan_modes === true) {
|
||||||
chanmodes = [];
|
chan_modes = [];
|
||||||
}
|
}
|
||||||
if (!chanmodes.includes('m')) {
|
if (!chan_modes.includes('m')) {
|
||||||
this.channelmodes.set(channel, [...chanmodes, 'm']);
|
this.channelmodes.set(channel, [...chan_modes, 'm']);
|
||||||
}
|
}
|
||||||
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} +m\r\n`);
|
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} +m\r\n`);
|
||||||
break;
|
break;
|
||||||
@@ -248,13 +334,67 @@ class WTVIRC {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var chanmodes = this.channelmodes.get(channel);
|
var chan_modes = this.channelmodes.get(channel);
|
||||||
if (!chanmodes || chanmodes === true) {
|
if (!chan_modes || chan_modes === true) {
|
||||||
chanmodes = [];
|
chan_modes = [];
|
||||||
}
|
}
|
||||||
this.channelmodes.set(channel, (chanmodes).filter(m => m !== 'm'));
|
this.channelmodes.set(channel, (chanmodes).filter(m => m !== 'm'));
|
||||||
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} -m\r\n`);
|
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} -m\r\n`);
|
||||||
break;
|
break;
|
||||||
|
} else if (mode.startsWith("+I")) {
|
||||||
|
if (!this.channelops.has(channel) || this.channelops.get(channel) === true) {
|
||||||
|
socket.write(`:${this.servername} 482 ${nickname} ${channel} :You're not channel operator\r\n`);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (!this.channelops.get(channel).has(nickname)) {
|
||||||
|
socket.write(`:${this.servername} 482 ${nickname} ${channel} :You're not channel operator\r\n`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (params.length < 3) {
|
||||||
|
socket.write(`:${this.servername} 461 ${nickname} MODE :Not enough parameters\r\n`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const inviteMask = params[2];
|
||||||
|
if (!inviteMask) {
|
||||||
|
socket.write(`:${this.servername} 461 ${nickname} MODE :Not enough parameters\r\n`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!this.inviteexceptions.has(channel)) {
|
||||||
|
this.inviteexceptions.set(channel, new Set());
|
||||||
|
}
|
||||||
|
this.inviteexceptions.get(channel).add(inviteMask);
|
||||||
|
socket.write(`:${this.servername} 346 ${nickname} ${channel} ${inviteMask}\r\n`);
|
||||||
|
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} +I ${inviteMask}\r\n`, socket);
|
||||||
|
break;
|
||||||
|
} else if (mode.startsWith("-I")) {
|
||||||
|
if (!this.channelops.has(channel) || this.channelops.get(channel) === true) {
|
||||||
|
socket.write(`:${this.servername} 482 ${nickname} ${channel} :You're not channel operator\r\n`);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (!this.channelops.get(channel).has(nickname)) {
|
||||||
|
socket.write(`:${this.servername} 482 ${nickname} ${channel} :You're not channel operator\r\n`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (params.length < 3) {
|
||||||
|
socket.write(`:${this.servername} 461 ${nickname} MODE :Not enough parameters\r\n`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const inviteMask = params[2];
|
||||||
|
if (!inviteMask) {
|
||||||
|
socket.write(`:${this.servername} 461 ${nickname} MODE :Not enough parameters\r\n`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (this.inviteexceptions.has(channel)) {
|
||||||
|
this.inviteexceptions.get(channel).delete(inviteMask);
|
||||||
|
socket.write(`:${this.servername} 347 ${nickname} ${channel} ${inviteMask}\r\n`);
|
||||||
|
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} -I ${inviteMask}\r\n`, socket);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
socket.write(`:${this.servername} 403 ${nickname} ${channel} :No such channel\r\n`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else if (mode.startsWith('+l')) {
|
} else if (mode.startsWith('+l')) {
|
||||||
if (!this.channelops.has(channel) || this.channelops.get(channel) === true) {
|
if (!this.channelops.has(channel) || this.channelops.get(channel) === true) {
|
||||||
socket.write(`:${this.servername} 482 ${nickname} ${channel} :You're not channel operator\r\n`);
|
socket.write(`:${this.servername} 482 ${nickname} ${channel} :You're not channel operator\r\n`);
|
||||||
@@ -274,13 +414,13 @@ class WTVIRC {
|
|||||||
socket.write(`:${this.servername} 501 ${nickname} :Invalid channel limit\r\n`);
|
socket.write(`:${this.servername} 501 ${nickname} :Invalid channel limit\r\n`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
var chanmodes = this.channelmodes.get(channel);
|
var chan_modes = this.channelmodes.get(channel);
|
||||||
if (!chanmodes || chanmodes === true) {
|
if (!chan_modes || chan_modes === true) {
|
||||||
chanmodes = [];
|
chan_modes = [];
|
||||||
}
|
}
|
||||||
// replace limit mode if it exists
|
// replace limit mode if it exists
|
||||||
chanmodes = chanmodes.filter(m => !/^l\d+$/.test(m));
|
chan_modes = chan_modes.filter(m => !/^l\d+$/.test(m));
|
||||||
this.channelmodes.set(channel, [...chanmodes, `l${limit}`]);
|
this.channelmodes.set(channel, [...chan_modes, `l${limit}`]);
|
||||||
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} +l ${limit}\r\n`);
|
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} +l ${limit}\r\n`);
|
||||||
break;
|
break;
|
||||||
} else if (mode.startsWith('-l')) {
|
} else if (mode.startsWith('-l')) {
|
||||||
@@ -297,11 +437,11 @@ class WTVIRC {
|
|||||||
socket.write(`:${this.servername} 461 ${nickname} MODE :Not enough parameters\r\n`);
|
socket.write(`:${this.servername} 461 ${nickname} MODE :Not enough parameters\r\n`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
var chanmodes = this.channelmodes.get(channel);
|
var chan_modes = this.channelmodes.get(channel);
|
||||||
if (!chanmodes || chanmodes === true) {
|
if (!chan_modes || chan_modes === true) {
|
||||||
chanmodes = [];
|
chan_modes = [];
|
||||||
}
|
}
|
||||||
this.channelmodes.set(channel, (chanmodes).filter(m => !/^l\d+$/.test(m)));
|
this.channelmodes.set(channel, (chan_modes).filter(m => !/^l\d+$/.test(m)));
|
||||||
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} -l\r\n`);
|
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} -l\r\n`);
|
||||||
break;
|
break;
|
||||||
} else if (mode.startsWith('+k')) {
|
} else if (mode.startsWith('+k')) {
|
||||||
@@ -319,11 +459,11 @@ class WTVIRC {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const key = params[2];
|
const key = params[2];
|
||||||
var chanmodes = this.channelmodes.get(channel);
|
var chan_modes = this.channelmodes.get(channel);
|
||||||
if (!chanmodes || chanmodes === true) {
|
if (!chan_modes || chan_modes === true) {
|
||||||
chanmodes = [];
|
chan_modes = [];
|
||||||
}
|
}
|
||||||
this.channelmodes.set(channel, [...chanmodes, `k ${key}`]);
|
this.channelmodes.set(channel, [...chan_modes, `k ${key}`]);
|
||||||
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} +k ${key}\r\n`);
|
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} +k ${key}\r\n`);
|
||||||
break;
|
break;
|
||||||
} else if (mode.startsWith('-k')) {
|
} else if (mode.startsWith('-k')) {
|
||||||
@@ -340,11 +480,11 @@ class WTVIRC {
|
|||||||
socket.write(`:${this.servername} 461 ${nickname} MODE :Not enough parameters\r\n`);
|
socket.write(`:${this.servername} 461 ${nickname} MODE :Not enough parameters\r\n`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
var chanmodes = this.channelmodes.get(channel);
|
var chan_modes = this.channelmodes.get(channel);
|
||||||
if (!chanmodes || chanmodes === true) {
|
if (!chan_modes || chan_modes === true) {
|
||||||
chanmodes = [];
|
chan_modes = [];
|
||||||
}
|
}
|
||||||
this.channelmodes.set(channel, (chanmodes).filter(m => !/^k.*$/.test(m)));
|
this.channelmodes.set(channel, (chan_modes).filter(m => !/^k.*$/.test(m)));
|
||||||
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} -k\r\n`);
|
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} -k\r\n`);
|
||||||
break;
|
break;
|
||||||
} else if (mode.startsWith('+i')) {
|
} else if (mode.startsWith('+i')) {
|
||||||
@@ -357,11 +497,11 @@ class WTVIRC {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var chanmodes = this.channelmodes.get(channel);
|
var chan_modes = this.channelmodes.get(channel);
|
||||||
if (!chanmodes || chanmodes === true) {
|
if (!chan_modes || chan_modes === true) {
|
||||||
chanmodes = [];
|
chan_modes = [];
|
||||||
}
|
}
|
||||||
this.channelmodes.set(channel, [...chanmodes, 'i']);
|
this.channelmodes.set(channel, [...chan_modes, 'i']);
|
||||||
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} +i\r\n`);
|
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} +i\r\n`);
|
||||||
break;
|
break;
|
||||||
} else if (mode.startsWith('-i')) {
|
} else if (mode.startsWith('-i')) {
|
||||||
@@ -374,9 +514,9 @@ class WTVIRC {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var chanmodes = this.channelmodes.get(channel);
|
var chan_modes = this.channelmodes.get(channel);
|
||||||
if (!chanmodes || chanmodes === true) {
|
if (!chan_modes || chan_modes === true) {
|
||||||
chanmodes = [];
|
chan_modes = [];
|
||||||
}
|
}
|
||||||
this.channelmodes.set(channel, (chanmodes).filter(m => m !== 'i'));
|
this.channelmodes.set(channel, (chanmodes).filter(m => m !== 'i'));
|
||||||
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} -i\r\n`);
|
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} -i\r\n`);
|
||||||
@@ -555,11 +695,11 @@ class WTVIRC {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var chanmodes = this.channelmodes.get(channel);
|
var chan_modes = this.channelmodes.get(channel);
|
||||||
if (!chanmodes || chanmodes === true) {
|
if (!chan_modes || chan_modes === true) {
|
||||||
chanmodes = [];
|
chan_modes = [];
|
||||||
}
|
}
|
||||||
this.channelmodes.set(channel, [...chanmodes, 'p']);
|
this.channelmodes.set(channel, [...chan_modes, 'p']);
|
||||||
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} +p\r\n`);
|
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} +p\r\n`);
|
||||||
break;
|
break;
|
||||||
} else if (mode.startsWith('-p')) {
|
} else if (mode.startsWith('-p')) {
|
||||||
@@ -572,13 +712,47 @@ class WTVIRC {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var chanmodes = this.channelmodes.get(channel);
|
var chan_modes = this.channelmodes.get(channel);
|
||||||
if (!chanmodes || chanmodes === true) {
|
if (!chan_modes || chan_modes === true) {
|
||||||
chanmodes = [];
|
chan_modes = [];
|
||||||
}
|
}
|
||||||
this.channelmodes.set(channel, (chanmodes).filter(m => m !== 'p'));
|
this.channelmodes.set(channel, (chan_modes).filter(m => m !== 'p'));
|
||||||
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} -p\r\n`);
|
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} -p\r\n`);
|
||||||
break;
|
break;
|
||||||
|
} else if (mode.startsWith('+t')) {
|
||||||
|
if (!this.channelops.has(channel) || this.channelops.get(channel) === true) {
|
||||||
|
socket.write(`:${this.servername} 482 ${nickname} ${channel} :You're not channel operator\r\n`);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (!this.channelops.get(channel).has(nickname)) {
|
||||||
|
socket.write(`:${this.servername} 482 ${nickname} ${channel} :You're not channel operator\r\n`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var chan_modes = this.channelmodes.get(channel);
|
||||||
|
if (!chan_modes || chan_modes === true) {
|
||||||
|
chan_modes = [];
|
||||||
|
}
|
||||||
|
this.channelmodes.set(channel, [...chan_modes, 't']);
|
||||||
|
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} +t\r\n`);
|
||||||
|
break;
|
||||||
|
} else if (mode.startsWith('-t')) {
|
||||||
|
if (!this.channelops.has(channel) || this.channelops.get(channel) === true) {
|
||||||
|
socket.write(`:${this.servername} 482 ${nickname} ${channel} :You're not channel operator\r\n`);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (!this.channelops.get(channel).has(nickname)) {
|
||||||
|
socket.write(`:${this.servername} 482 ${nickname} ${channel} :You're not channel operator\r\n`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var chan_modes = this.channelmodes.get(channel);
|
||||||
|
if (!chan_modes || chan_modes === true) {
|
||||||
|
chan_modes = [];
|
||||||
|
}
|
||||||
|
this.channelmodes.set(channel, (chan_modes).filter(m => m !== 't'));
|
||||||
|
this.broadcastChannel(channel, `:${nickname}!${username}@${host} MODE ${channel} -t\r\n`);
|
||||||
|
break;
|
||||||
} else if (mode === 'b') {
|
} else if (mode === 'b') {
|
||||||
if (this.channelbans.has(channel)) {
|
if (this.channelbans.has(channel)) {
|
||||||
const bans = Array.from(this.channelbans.get(channel));
|
const bans = Array.from(this.channelbans.get(channel));
|
||||||
@@ -648,11 +822,7 @@ class WTVIRC {
|
|||||||
registered = true;
|
registered = true;
|
||||||
this.usertimestamps.set(nickname, Date.now());
|
this.usertimestamps.set(nickname, Date.now());
|
||||||
this.usersignontimestamps.set(new_nickname, timestamp);
|
this.usersignontimestamps.set(new_nickname, timestamp);
|
||||||
socket.write(`:${this.servername} 001 ${nickname} :Welcome to the IRC server, ${nickname}\r\n`);
|
this.doLogin(nickname, socket);
|
||||||
socket.write(`:${this.servername} 002 ${nickname} :Your host is ${this.servername}, running version minisrv ${this.minisrv_config.version}\r\n`);
|
|
||||||
socket.write(`:${this.servername} 003 ${nickname} :This server is ready to accept commands\r\n`);
|
|
||||||
socket.write(`:${this.servername} 004 ${nickname} ${this.servername} minisrv ${this.minisrv_config.version} :End of /MOTD command\r\n`);
|
|
||||||
socket.write(`:${this.servername} 005 ${this.caps}\r\n`);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'USER':
|
case 'USER':
|
||||||
@@ -662,11 +832,7 @@ class WTVIRC {
|
|||||||
this.usernames.set(nickname, username);
|
this.usernames.set(nickname, username);
|
||||||
this.usertimestamps.set(nickname, Date.now());
|
this.usertimestamps.set(nickname, Date.now());
|
||||||
this.usersignontimestamps.set(new_nickname, timestamp);
|
this.usersignontimestamps.set(new_nickname, timestamp);
|
||||||
socket.write(`:${this.servername} 001 ${nickname} :Welcome to the IRC server, ${nickname}\r\n`);
|
this.doLogin(nickname, socket);
|
||||||
socket.write(`:${this.servername} 002 ${nickname} :Your host is ${this.servername}, running version minisrv ${this.minisrv_config.version}\r\n`);
|
|
||||||
socket.write(`:${this.servername} 003 ${nickname} :This server is ready to accept commands\r\n`);
|
|
||||||
socket.write(`:${this.servername} 004 ${nickname} ${this.servername} minisrv ${this.minisrv_config.version} :End of /MOTD command\r\n`);
|
|
||||||
socket.write(`:${this.servername} 005 ${this.caps}\r\n`);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'JOIN':
|
case 'JOIN':
|
||||||
@@ -703,6 +869,9 @@ class WTVIRC {
|
|||||||
socket.write(`:${this.servername} 403 ${nickname} ${ch} :No such channel\r\n`);
|
socket.write(`:${this.servername} 403 ${nickname} ${ch} :No such channel\r\n`);
|
||||||
continue; // Skip this channel
|
continue; // Skip this channel
|
||||||
}
|
}
|
||||||
|
if (!this.channels.has(ch)) {
|
||||||
|
this.createChannel(ch, nickname);
|
||||||
|
}
|
||||||
if (this.channelbans.has(ch)) {
|
if (this.channelbans.has(ch)) {
|
||||||
if (this.isBanned(nickname, ch)) {
|
if (this.isBanned(nickname, ch)) {
|
||||||
socket.write(`:${this.servername} 474 ${nickname} ${ch} :Cannot join channel (+b)\r\n`);
|
socket.write(`:${this.servername} 474 ${nickname} ${ch} :Cannot join channel (+b)\r\n`);
|
||||||
@@ -732,11 +901,34 @@ class WTVIRC {
|
|||||||
// We'll use a Map: this.channelinvites = new Map(); // channel -> Set of invited nicks
|
// We'll use a Map: this.channelinvites = new Map(); // channel -> Set of invited nicks
|
||||||
if (!this.channelinvites) this.channelinvites = new Map();
|
if (!this.channelinvites) this.channelinvites = new Map();
|
||||||
const invited = this.channelinvites.get(ch) || new Set();
|
const invited = this.channelinvites.get(ch) || new Set();
|
||||||
if (!invited.has(nickname)) {
|
let isInvited = false;
|
||||||
|
for (const inviteMask of invited) {
|
||||||
|
// inviteMask can be nick!user@host or wildcards
|
||||||
|
const maskParts = inviteMask.split(/[!@]/);
|
||||||
|
const nickPart = maskParts[0] || '*';
|
||||||
|
const userPart = maskParts[1] || '*';
|
||||||
|
const hostPart = maskParts[2] || '*';
|
||||||
|
// Build user mask for this user
|
||||||
|
const userMask = `${nickname}!${username}@${host}`;
|
||||||
|
// Convert mask to regex
|
||||||
|
const maskRegex = new RegExp('^' +
|
||||||
|
inviteMask
|
||||||
|
.replace(/\./g, '\\.')
|
||||||
|
.replace(/\*/g, '.*')
|
||||||
|
.replace(/\?/g, '.') +
|
||||||
|
'$');
|
||||||
|
if (maskRegex.test(userMask)) {
|
||||||
|
isInvited = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!invited.has(nickname) && !isInvited) {
|
||||||
socket.write(`:${this.servername} 473 ${nickname} ${ch} :Cannot join channel (+i)\r\n`);
|
socket.write(`:${this.servername} 473 ${nickname} ${ch} :Cannot join channel (+i)\r\n`);
|
||||||
continue; // Skip joining this channel
|
continue; // Skip joining this channel
|
||||||
}
|
}
|
||||||
invited.delete(nickname);
|
if (!isInvited) {
|
||||||
|
invited.delete(nickname);
|
||||||
|
}
|
||||||
this.channelinvites.set(ch, invited);
|
this.channelinvites.set(ch, invited);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1025,7 +1217,7 @@ class WTVIRC {
|
|||||||
const whoisSocket = Array.from(this.nicknames.keys()).find(s => this.nicknames.get(s) === whoisNick);
|
const whoisSocket = Array.from(this.nicknames.keys()).find(s => this.nicknames.get(s) === whoisNick);
|
||||||
if (whoisSocket) {
|
if (whoisSocket) {
|
||||||
const whois_username = this.usernames.get(whoisNick);
|
const whois_username = this.usernames.get(whoisNick);
|
||||||
socket.write(`:${this.servername} 311 ${nickname} ${whoisNick} ${whois_username} ${whoisSocket.remoteAddress} * ${whoisNick}\r\n`);
|
socket.write(`:${this.servername} 311 ${nickname} ${whoisNick} ${whois_username} ${this.getHostname(whoisSocket)} * ${whoisNick}\r\n`);
|
||||||
if (this.awaymsgs.has(whoisNick)) {
|
if (this.awaymsgs.has(whoisNick)) {
|
||||||
socket.write(`:${this.servername} 301 ${nickname} ${whoisNick} :${this.awaymsgs.get(whoisNick)}\r\n`);
|
socket.write(`:${this.servername} 301 ${nickname} ${whoisNick} :${this.awaymsgs.get(whoisNick)}\r\n`);
|
||||||
}
|
}
|
||||||
@@ -1043,6 +1235,10 @@ class WTVIRC {
|
|||||||
userChannels.push(prefix + ch);
|
userChannels.push(prefix + ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
socket.write(`:${this.servername} 312 ${nickname} ${whoisNick} ${this.servername} :minisrv-${this.minisrv_config.version}\r\n`);
|
||||||
|
if (this.isIRCOp(whoisNick)) {
|
||||||
|
socket.write(`:${this.servername} 313 ${nickname} ${whoisNick} :is an IRC operator\r\n`);
|
||||||
|
}
|
||||||
var now = Date.now();
|
var now = Date.now();
|
||||||
var userTimestamp = this.usertimestamps.get(whoisNick) || now;
|
var userTimestamp = this.usertimestamps.get(whoisNick) || now;
|
||||||
var idleTime = Math.floor((now - userTimestamp) / 1000);
|
var idleTime = Math.floor((now - userTimestamp) / 1000);
|
||||||
@@ -1055,45 +1251,39 @@ class WTVIRC {
|
|||||||
socket.write(`:${this.servername} 401 ${nickname} ${whoisNick} :No such nick/channel\r\n`);
|
socket.write(`:${this.servername} 401 ${nickname} ${whoisNick} :No such nick/channel\r\n`);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'KILL':
|
||||||
|
if (!registered) {
|
||||||
|
socket.write(`:${this.servername} 451 ${nickname} :You have not registered\r\n`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!this.isIRCOp(nickname)) {
|
||||||
|
socket.write(`:${this.servername} 481 ${nickname} :Permission denied - you are not an IRC operator\r\n`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (params.length < 2) {
|
||||||
|
socket.write(`:${this.servername} 461 ${nickname} KILL :Not enough parameters\r\n`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const target_nick = params[0];
|
||||||
|
const killReason = params.slice(1).join(' ');
|
||||||
|
let cleanKillReason = killReason;
|
||||||
|
if (cleanKillReason.startsWith(':')) {
|
||||||
|
cleanKillReason = cleanKillReason.slice(1);
|
||||||
|
}
|
||||||
|
const targetSocket = Array.from(this.nicknames.keys()).find(s => this.nicknames.get(s) === target_nick);
|
||||||
|
if (!targetSocket) {
|
||||||
|
socket.write(`:${this.servername} 401 ${nickname} ${target_nick} :No such nick/channel\r\n`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Broadcast the KILL message to all users
|
||||||
|
this.broadcastUser(target_nick, `:${nickname}!${username}@${host} KILL ${target_nick} :${cleanKillReason}\r\n`);
|
||||||
|
this.terminateSession(targetSocket, target_nick);
|
||||||
|
break;
|
||||||
case 'QUIT':
|
case 'QUIT':
|
||||||
if (!registered) {
|
if (!registered) {
|
||||||
socket.write(`:${this.servername} 451 ${nickname} :You have not registered\r\n`);
|
socket.write(`:${this.servername} 451 ${nickname} :You have not registered\r\n`);
|
||||||
} else {
|
} else {
|
||||||
if (nickname) {
|
|
||||||
this.usertimestamps.delete(nickname);
|
|
||||||
this.usersignontimestamps.delete(nickname);
|
|
||||||
for (const [ch, ops] of this.channelops.entries()) {
|
|
||||||
if (ops && ops !== true && ops.has(nickname)) {
|
|
||||||
ops.delete(nickname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const [ch, voices] of this.channelvoices.entries()) {
|
|
||||||
if (voices && voices !== true && voices.has(nickname)) {
|
|
||||||
voices.delete(nickname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Remove user from any pending invites
|
|
||||||
for (const [ch, invites] of (this.channelinvites || new Map()).entries()) {
|
|
||||||
if (invites && invites.has(nickname)) {
|
|
||||||
invites.delete(nickname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.channels.forEach((users, ch) => {
|
|
||||||
if (users.has(nickname)) {
|
|
||||||
users.delete(nickname);
|
|
||||||
if (users.size === 0) {
|
|
||||||
this.channels.delete(ch);
|
|
||||||
this.channelops.delete(ch);
|
|
||||||
this.channelvoices.delete(ch);
|
|
||||||
this.channeltopics.delete(ch);
|
|
||||||
this.channelbans.delete(ch);
|
|
||||||
this.channelexemptions.delete(ch);
|
|
||||||
this.channelinvites.delete(ch);
|
|
||||||
this.channelmodes.delete(ch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (params.length > 0) {
|
if (params.length > 0) {
|
||||||
let reason = params.join(' ');
|
let reason = params.join(' ');
|
||||||
if (reason.startsWith(':')) {
|
if (reason.startsWith(':')) {
|
||||||
@@ -1106,7 +1296,7 @@ class WTVIRC {
|
|||||||
this.broadcastUser(nickname, `:${nickname}!${username}@${host} QUIT\r\n`, socket);
|
this.broadcastUser(nickname, `:${nickname}!${username}@${host} QUIT\r\n`, socket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
socket.end();
|
this.terminateSession(socket, nickname);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Ignore unknown commands
|
// Ignore unknown commands
|
||||||
@@ -1133,6 +1323,45 @@ class WTVIRC {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
terminateSession(socket, nickname) {
|
||||||
|
if (nickname) {
|
||||||
|
this.usertimestamps.delete(nickname);
|
||||||
|
this.usersignontimestamps.delete(nickname);
|
||||||
|
for (const [ch, ops] of this.channelops.entries()) {
|
||||||
|
if (ops && ops !== true && ops.has(nickname)) {
|
||||||
|
ops.delete(nickname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const [ch, voices] of this.channelvoices.entries()) {
|
||||||
|
if (voices && voices !== true && voices.has(nickname)) {
|
||||||
|
voices.delete(nickname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Remove user from any pending invites
|
||||||
|
for (const [ch, invites] of (this.channelinvites || new Map()).entries()) {
|
||||||
|
if (invites && invites.has(nickname)) {
|
||||||
|
invites.delete(nickname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.channels.forEach((users, ch) => {
|
||||||
|
if (users.has(nickname)) {
|
||||||
|
users.delete(nickname);
|
||||||
|
if (users.size === 0) {
|
||||||
|
this.channels.delete(ch);
|
||||||
|
this.channelops.delete(ch);
|
||||||
|
this.channelvoices.delete(ch);
|
||||||
|
this.channeltopics.delete(ch);
|
||||||
|
this.channelbans.delete(ch);
|
||||||
|
this.channelexemptions.delete(ch);
|
||||||
|
this.channelinvites.delete(ch);
|
||||||
|
this.channelmodes.delete(ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
socket.end();
|
||||||
|
}
|
||||||
|
|
||||||
isBanned(nickname, channel) {
|
isBanned(nickname, channel) {
|
||||||
if (this.channelbans.has(channel)) {
|
if (this.channelbans.has(channel)) {
|
||||||
const bans = this.channelbans.get(channel);
|
const bans = this.channelbans.get(channel);
|
||||||
@@ -1241,6 +1470,80 @@ class WTVIRC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isIRCOp(nickname) {
|
||||||
|
// Check if the user is an IRC operator
|
||||||
|
if (!this.usermodes.has(nickname)) return false;
|
||||||
|
const modes = this.usermodes.get(nickname);
|
||||||
|
if (Array.isArray(modes)) {
|
||||||
|
return modes.includes('o');
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
createChannel(channel, creator) {
|
||||||
|
if (!this.channels.has(channel)) {
|
||||||
|
this.channels.set(channel, new Set());
|
||||||
|
this.channelops.set(channel, new Set([creator]));
|
||||||
|
this.channelvoices.set(channel, new Set());
|
||||||
|
this.channeltopics.set(channel, 'No topic set');
|
||||||
|
this.channelbans.set(channel, new Set());
|
||||||
|
this.channelexemptions.set(channel, new Set());
|
||||||
|
this.channelinvites.set(channel, new Set());
|
||||||
|
this.channelmodes.set(channel, this.default_channel_modes.slice());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getHostname(socket) {
|
||||||
|
const username = this.nicknames.get(socket);
|
||||||
|
const modes = this.usermodes.get(username);
|
||||||
|
var hostname = '';
|
||||||
|
if (socket && socket.remoteAddress) {
|
||||||
|
try {
|
||||||
|
// Synchronously resolve the hostname (not recommended for production, but simple for this context)
|
||||||
|
// For async, you'd need to refactor the call site to handle promises/callbacks
|
||||||
|
let resolved = socket.remoteAddress;
|
||||||
|
dns.reverse(socket.remoteAddress, (err, hostnames) => {
|
||||||
|
if (!err && hostnames && hostnames.length > 0) {
|
||||||
|
resolved = hostnames[0];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
hostname = resolved;
|
||||||
|
} catch (e) {
|
||||||
|
hostname = socket.remoteAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(modes) && modes.includes('h')) {
|
||||||
|
// Masked hostname for +h users
|
||||||
|
if (typeof hostname === 'string') {
|
||||||
|
// Mask everything except the first and last octet for IPv4
|
||||||
|
const ipv4Match = hostname.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/);
|
||||||
|
if (ipv4Match) {
|
||||||
|
return `${ipv4Match[1]}.x.x.${ipv4Match[4]}`;
|
||||||
|
}
|
||||||
|
// For hostnames, mask all but the first and last label
|
||||||
|
const parts = hostname.split('.');
|
||||||
|
if (parts.length > 2) {
|
||||||
|
return `${parts[0]}.x.${parts[parts.length - 1]}`;
|
||||||
|
}
|
||||||
|
// Otherwise, just return 'hidden.host'
|
||||||
|
return 'hidden.host';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hostname) {
|
||||||
|
return hostname;
|
||||||
|
}
|
||||||
|
return 'unknown.host';
|
||||||
|
}
|
||||||
|
|
||||||
|
doLogin(nickname, socket) {
|
||||||
|
socket.write(`:${this.servername} 001 ${nickname} :Welcome to the IRC server, ${nickname}\r\n`);
|
||||||
|
socket.write(`:${this.servername} 002 ${nickname} :Your host is ${this.servername}, running version minisrv ${this.minisrv_config.version}\r\n`);
|
||||||
|
socket.write(`:${this.servername} 003 ${nickname} :This server is ready to accept commands\r\n`);
|
||||||
|
socket.write(`:${this.servername} 004 ${nickname} ${this.servername} minisrv ${this.minisrv_config.version} ohiws obtkmeIlvn beIklov\r\n`);
|
||||||
|
socket.write(`:${this.servername} 005 ${this.caps}\r\n`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = WTVIRC;
|
module.exports = WTVIRC;
|
||||||
Reference in New Issue
Block a user