pokemon-showdown/users.js
Bill Meltsner 64d210940a Add support for lists of words to be banned from being used in usernames (NOT chat).
& and higher can change the list with /banword and /unbanword (or /bw and /ubw respectively). The words/phrases are turned into IDs (only lowercase alphanumeric characters allowed) and checked against the ID form of a given username.

Keep in mind the list has no sense of context, and so overzealous banning, particularly of short or otherwise common words, should be avoided. Or else user "Cofagrigus" will want to have a word with you.
2012-07-01 21:46:55 -05:00

938 lines
26 KiB
JavaScript

var THROTTLE_DELAY = 400;
var users = {};
var prevUsers = {};
var numUsers = 0;
var people = {};
var numPeople = 0;
function sanitizeName(name) {
name = name.trim();
if (name.length > 18) name = name.substr(0,18);
while (config.groups[name.substr(0,1)]) {
name = name.substr(1);
}
name = name.replace(/[\|\[\]\,]/g, '');
return name;
}
function getUser(name) {
if (!name || name === '!') return null;
if (name && name.userid) return name;
var userid = toUserid(name);
var i = 0;
while (userid && !users[userid] && i < 1000) {
userid = prevUsers[userid];
i++;
}
return users[userid];
}
function searchUser(name) {
var userid = toUserid(name);
while (userid && !users[userid]) {
userid = prevUsers[userid];
}
return users[userid];
}
function nameLock(user,name,ip) {
ip = ip||user.ip;
var userid = toUserid(name);
if(nameLockedIps[ip]) {
return user.nameLock(nameLockedIps[ip]);
} for(var i in nameLockedIps) {
if((userid && toUserid(nameLockedIps[i])==userid)||user.userid==toUserid(nameLockedIps[i])) {
nameLockedIps[ip] = nameLockedIps[i];
return user.nameLock(nameLockedIps[ip]);
}
}
return name||user.name;
}
function connectUser(name, socket, token, room) {
var userid = toUserid(name);
var user;
console.log("NEW PERSON: "+socket.id);
var person = new Person(name, socket, true);
if (person.banned) return person;
if (users[userid]) {
user = users[userid];
if (!user.add(name, person, token)) {
console.log("NEW USER: [guest] (userid: "+userid+" taken) "+name);
user = new User('', person, token);
user.rename(name, token);
}
} else {
console.log("NEW USER: [guest] "+name);
user = new User(name, person, token);
var nameSuggestion = nameLock(user);
if (nameSuggestion !== user.name) {
user.rename(nameSuggestion);
}
}
if (room) {
user.joinRoom(room, person);
}
return person;
}
var usergroups = {};
function importUsergroups() {
fs.readFile('config/usergroups.csv', function(err, data) {
if (err) return;
data = (''+data).split("\n");
usergroups = {};
for (var i = 0; i < data.length; i++) {
if (!data[i]) continue;
var row = data[i].split(",");
usergroups[toUserid(row[0])] = (row[1]||config.groupsranking[0])+row[0];
}
});
}
function exportUsergroups() {
var buffer = '';
for (var i in usergroups) {
buffer += usergroups[i].substr(1).replace(/,/g,'') + ',' + usergroups[i].substr(0,1) + "\n";
}
fs.writeFile('config/usergroups.csv', buffer);
}
importUsergroups();
var bannedWords = {};
function importBannedWords() {
fs.readFile('config/bannedwords.txt', function(err, data) {
if (err) return;
data = (''+data).split("\n");
bannedWords = {};
for (var i = 0; i < data.length; i++) {
if (!data[i]) continue;
bannedWords[data[i]] = true;
}
});
}
function exportBannedWords() {
fs.writeFile('config/bannedwords.txt', Object.keys(bannedWords).join('\n'));
}
function addBannedWord(word) {
bannedWords[word] = true;
exportBannedWords();
}
function removeBannedWord(word) {
delete bannedWords[word];
exportBannedWords();
}
importBannedWords();
// User
var User = (function () {
function User(name, person, token) {
numUsers++;
if (!token) {
//token = ''+Math.floor(Math.random()*10000);
token = ''+person.socket.id;
}
this.token = token;
this.guestNum = numUsers;
this.name = 'Guest '+numUsers;
this.named = false;
this.renamePending = false;
this.authenticated = false;
this.userid = toUserid(this.name);
this.group = config.groupsranking[0];
var trainersprites = [1, 2, 101, 102, 169, 170];
this.avatar = trainersprites[parseInt(Math.random()*trainersprites.length)];
this.connected = true;
if (person.user) person.user = this;
this.people = [person];
this.ip = person.ip;
this.muted = !!ipSearch(this.ip,mutedIps);
this.prevNames = {};
this.sides = {};
this.roomCount = {};
// challenges
this.challengesFrom = {};
this.challengeTo = null;
this.lastChallenge = 0;
// initialize
users[this.userid] = this;
if (person.banned) {
this.destroy();
} else if (name) {
this.rename(name,token);
}
}
User.prototype.emit = function(message, data) {
var roomid = false;
if (data && data.room) {
roomid = data.room;
}
for (var i=0; i<this.people.length; i++) {
if (roomid && !this.people[i].rooms[roomid]) continue;
this.people[i].socket.emit(message, data);
}
};
User.prototype.getIdentity = function() {
if (this.muted) {
return '!'+this.name;
} if(this.nameLocked()) {
return '#'+this.name;
}
return this.group+this.name;
};
User.prototype.can = function(permission, target) {
var group = this.group;
var groupData = config.groups[group];
var checkedGroups = {};
while (groupData) {
// Cycle checker
if (checkedGroups[group]) return false;
checkedGroups[group] = true;
if (groupData['root']) {
return true;
}
if (groupData[permission]) {
var jurisdiction = groupData[permission];
if (!target) {
return !!jurisdiction;
}
if (jurisdiction === true && permission !== 'jurisdiction') {
return this.can('jurisdiction', target);
}
if (typeof jurisdiction !== 'string') {
return !!jurisdiction;
}
if (jurisdiction.indexOf(target.group) >= 0) {
return true;
}
if (jurisdiction.indexOf('s') >= 0 && target === this) {
return true;
}
if (jurisdiction.indexOf('u') >= 0 && config.groupsranking.indexOf(this.group) > config.groupsranking.indexOf(target.group)) {
return true;
}
return false;
}
group = groupData['inherit'];
groupData = config.groups[group];
}
return false;
};
// Special permission check is needed for promoting and demoting
User.prototype.checkPromotePermission = function(targetUser, targetGroupSymbol) {
if (!this.can('promote', targetUser)) return false;
var fakeUser = {group:targetGroupSymbol};
if (!this.can('promote', fakeUser)) return false;
return true;
};
User.prototype.getNextGroupSymbol = function(isDown) {
var nextGroupRank = config.groupsranking[config.groupsranking.indexOf(this.group) + (isDown ? -1 : 1)];
if (!nextGroupRank) {
if (isDown) {
return config.groupsranking[0];
} else {
return config.groupsranking[config.groupsranking.length - 1];
}
}
return nextGroupRank;
};
User.prototype.forceRename = function(name, authenticated) {
// skip the login server
var userid = toUserid(name);
if (users[userid] && users[userid] !== this) {
return false;
}
if (this.named) this.prevNames[this.userid] = this.name;
if (typeof authenticated === 'undefined' && userid === this.userid) {
authenticated = this.authenticated;
}
if (userid !== this.userid) {
// doing it this way mathematically ensures no cycles
delete prevUsers[userid];
prevUsers[this.userid] = userid;
}
this.name = name;
var oldid = this.userid;
delete users[oldid];
this.userid = userid;
users[this.userid] = this;
this.authenticated = !!authenticated;
if (config.localsysop && this.ip === '127.0.0.1') {
this.group = config.groupsranking[config.groupsranking.length - 1];
}
for (var i=0; i<this.people.length; i++) {
this.people[i].rename(name, oldid);
console.log(''+name+' renaming: socket '+i+' of '+this.people.length);
this.people[i].socket.emit('update', {
name: name,
userid: this.userid,
named: true,
token: this.token
});
}
var joining = !this.named;
this.named = true;
for (var i in this.roomCount) {
Rooms.get(i).rename(this, oldid, joining);
}
rooms.lobby.usersChanged = true;
return true;
};
User.prototype.resetName = function() {
var name = 'Guest '+this.guestNum;
var userid = toUserid(name);
if (this.userid === userid) return;
var i = 0;
while (users[userid] && users[userid] !== this) {
this.guestNum++;
name = 'Guest '+this.guestNum;
userid = toUserid(name);
if (i > 1000) return false;
}
if (this.named) this.prevNames[this.userid] = this.name;
delete prevUsers[userid];
prevUsers[this.userid] = userid;
this.name = name;
var oldid = this.userid;
delete users[oldid];
this.userid = userid;
users[this.userid] = this;
this.authenticated = false;
for (var i=0; i<this.people.length; i++) {
this.people[i].rename(name, oldid);
console.log(''+name+' renaming: socket '+i+' of '+this.people.length);
this.people[i].socket.emit('update', {
name: name,
userid: this.userid,
named: false,
token: this.token
});
}
this.named = false;
for (var i in this.roomCount) {
Rooms.get(i).rename(this, oldid, false);
}
return true;
};
/**
*
* @param name The name you want
* @param token Login token
* @param auth Make sure this account will identify as registered
*/
User.prototype.rename = function(name, token, auth) {
for (var i in this.roomCount) {
var room = Rooms.get(i);
if (room.rated && (this.userid === room.rated.p1 || this.userid === room.rated.p2)) {
this.emit('message', "You can't change your name right now because you're in the middle of a rated battle.");
return false;
}
}
if (!name) name = '';
name = sanitizeName(name);
console.log("checking name lock for: "+this.name+" renaming to "+name);
name = nameLock(this,name);
console.log("returned "+name);
var userid = toUserid(name);
if (this.authenticated) auth = false;
if (!userid) {
// technically it's not "taken", but if your client doesn't warn you
// before it gets to this stage it's your own fault
this.emit('nameTaken', {userid: '', reason: "You did not specify a name."});
return false;
} else {
for (var w in bannedWords) {
if (userid.indexOf(w) >= 0) {
this.emit('nameTaken', {userid: '', reason: "That name contains a banned word or phrase."});
return false;
}
}
if (userid === this.userid && !auth) {
return this.forceRename(name, this.authenticated);
}
}
if (users[userid] && !users[userid].authenticated && users[userid].connected && !auth) {
this.emit('nameTaken', {userid:this.userid, token:token, reason: "Someone is already using the name \""+users[userid].name+"\"."});
return false;
}
this.renamePending = true;
// todo: sanitize
// This is ridiculous spaghetti code because I made a mistake in the authentication protocol earlier
// this should hopefully fix it while remaining backwards-compatible
var loginservertoken = 'novawave.ca';
var tokens = [''];
if (token) tokens = token.split('::');
if (tokens[1]) loginservertoken = tokens[1];
token = tokens[0];
var selfP = this;
console.log('POSTING TO SERVER: loginserver/action.php?act=verifysessiontoken&servertoken='+loginservertoken+'&userid='+userid+'&token='+token);
request({
uri: config.loginserver+'action.php?act=verifysessiontoken&servertoken='+loginservertoken+'&userid='+userid+'&token='+token
}, function(error, response, body) {
selfP.renamePending = false;
if (body) {
console.log('BODY: "'+body+'"');
if (users[userid] && !users[userid].authenticated && users[userid].connected) {
if (auth) {
if (users[userid] !== selfP) users[userid].resetName();
} else {
selfP.emit('nameTaken', {userid:selfP.userid, token:token, reason: "Someone is already using the name \""+users[userid].name+"\"."});
return false;
}
}
var group = config.groupsranking[0];
var avatar = 0;
var authenticated = false;
if (body !== '1') {
authenticated = true;
if (userid === "serei") avatar = 172;
else if (userid === "hobsgoblin") avatar = 52;
else if (userid === "ataraxia") avatar = 1002;
else if (userid === "verbatim") avatar = 1003;
else if (userid === "mortygymleader") avatar = 144;
else if (userid === "leadermorty") avatar = 144;
else if (userid === "leaderjasmine") avatar = 146;
else if (userid === "championcynthia") avatar = 260;
else if (userid === "aeo" || userid === "zarel") avatar = 167;
else if (userid === "aeo1") avatar = 167;
else if (userid === "aeo2") avatar = 166;
else if (userid === "sharktamer") avatar = 7;
else if (userid === "bmelts") avatar = 1004;
else if (userid === "n") avatar = 209;
else if (userid === "desolate") avatar = 152;
else if (userid === "steamroll") avatar = 126;
try {
var data = JSON.parse(body);
switch (data.group) {
case '2':
group = '~';
break;
case '3':
group = '+';
break;
case '4':
group = '%';
break;
case '5':
group = '@';
break;
case '6':
group = '&';
break;
}
/* var userdata = JSON.parse(body.userdata);
avatar = parseInt(userdata.trainersprite);
if (!avatar || avatar > 263 || avatar < 1) {
avatar = 0;
} */
} catch(e) {
}
if (usergroups[userid]) {
group = usergroups[userid].substr(0,1);
}
}
if (users[userid] && users[userid] !== selfP) {
// This user already exists; let's merge
var user = users[userid];
if (selfP === user) {
// !!!
return true;
}
for (var i in selfP.roomCount) {
Rooms.get(i).leave(selfP);
}
for (var i=0; i<selfP.people.length; i++) {
console.log(''+selfP.name+' preparing to merge: socket '+i+' of '+selfP.people.length);
user.merge(selfP.people[i]);
}
selfP.roomCount = {};
selfP.people = [];
selfP.connected = false;
if (!selfP.authenticated) {
selfP.group = config.groupsranking[0];
}
user.group = group;
if (avatar) user.avatar = avatar;
user.authenticated = authenticated;
user.ip = selfP.ip;
if (userid !== selfP.userid) {
// doing it this way mathematically ensures no cycles
delete prevUsers[userid];
prevUsers[selfP.userid] = userid;
}
for (var i in selfP.prevNames) {
if (!user.prevNames[i]) {
user.prevNames[i] = selfP.prevNames[i];
}
}
if (selfP.named) user.prevNames[selfP.userid] = selfP.name;
return true;
}
// rename success
selfP.token = token;
selfP.group = group;
if (avatar) selfP.avatar = avatar;
return selfP.forceRename(name, authenticated);
} else if (tokens[1]) {
console.log('BODY: ""');
// rename failed, but shouldn't
selfP.emit('nameTaken', {userid:userid, name:name, token:token, reason: "Your authentication token was invalid."});
} else {
console.log('BODY: ""');
// rename failed
selfP.emit('nameTaken', {userid:userid, name:name, token:token, reason: "The name you chose is registered"});
}
return false;
});
};
User.prototype.add = function(name, person, token) {
// name is ignored - this is intentional
if (person.banned || this.token !== token) {
return false;
}
this.connected = true;
person.user = this;
this.people.push(person);
this.ip = person.ip;
return person;
};
User.prototype.merge = function(person) {
this.connected = true;
var oldid = person.userid;
this.people.push(person);
person.rename(this.name, oldid);
console.log(''+this.name+' merging: socket '+person.socket.id+' of ');
person.socket.emit('update', {
name: this.name,
userid: this.userid,
named: true,
token: this.token
});
person.user = this;
for (var i in person.rooms) {
if (!this.roomCount[i]) {
person.rooms[i].join(this);
this.roomCount[i] = 0;
}
this.roomCount[i]++;
}
};
User.prototype.debugData = function() {
var str = ''+this.group+this.name+' ('+this.userid+')';
for (var i=0; i<this.people.length; i++) {
var person = this.people[i];
str += ' socket'+i+'[';
var first = true;
for (var j in person.rooms) {
if (first) first=false;
else str+=',';
str += j;
}
str += ']';
}
if (!this.connected) str += ' (DISCONNECTED)';
return str;
};
User.prototype.setGroup = function(group) {
this.group = group.substr(0,1);
if (!this.group || this.group === config.groupsranking[0]) {
delete usergroups[this.userid];
} else {
usergroups[this.userid] = this.group+this.name;
}
exportUsergroups();
};
User.prototype.disconnect = function(socket) {
var person = null;
for (var i=0; i<this.people.length; i++) {
if (this.people[i].socket === socket) {
console.log('DISCONNECT: '+this.userid);
if (this.people.length <= 1) {
this.connected = false;
if (!this.authenticated) {
this.group = config.groupsranking[0];
}
}
person = this.people[i];
for (var j in person.rooms) {
this.leaveRoom(person.rooms[j], socket);
}
person.user = null;
this.people.splice(i,1);
break;
}
}
if (!this.people.length) {
// cleanup
for (var i in this.roomCount) {
if (this.roomCount[i] > 0) {
// should never happen.
console.log('!! room miscount: '+i+' not left');
Rooms.get(i).leave(this);
}
}
this.roomCount = {};
}
};
User.prototype.getAlts = function() {
var alts = [];
for (var i in users) {
if (users[i].ip === this.ip && users[i] !== this) {
if (!users[i].named && !users[i].connected) {
continue;
}
alts.push(users[i].name);
}
}
return alts;
};
User.prototype.getHighestRankedAlt = function() {
var result = this;
var groupRank = config.groupsranking.indexOf(this.group);
for (var i in users) {
if (users[i].ip === this.ip && users[i] !== this) {
if (config.groupsranking.indexOf(users[i].group) > groupRank) {
result = users[i];
groupRank = config.groupsranking.indexOf(users[i].group);
}
}
}
return result;
};
User.prototype.nameLock = function(targetName, recurse) {
var targetUser = getUser(targetName);
if (!targetUser) return targetName;
if (nameLockedIps[this.ip] === targetName || !targetUser.ip || targetUser.ip === this.ip) {
nameLockedIps[this.ip] = targetName;
if (recurse) {
for (var i in users) {
if (users[i].ip === this.ip && users[i] !== this) {
users[i].destroy();
}
}
this.forceRename(targetName, this.authenticated);
}
}
return targetName;
};
User.prototype.nameLocked = function() {
if (nameLockedIps[this.ip]) {
this.nameLock(nameLockedIps[this.ip]);
return true;
}
for (var i in nameLockedIps) {
if (nameLockedIps[i] === this.name) {
nameLockedIps[this.ip] = nameLockedIps[i];
this.nameLock(nameLockedIps[this.ip]);
return true;
}
}
return false;
};
User.prototype.ban = function(noRecurse) {
// no need to recurse, since the root for-loop already bans everything with your IP
if (!noRecurse) for (var i in users) {
if (users[i].ip === this.ip && users[i] !== this) {
users[i].ban(true);
}
}
bannedIps[this.ip] = this.userid;
this.destroy();
};
User.prototype.destroy = function() {
// Disconnects a user from the server
this.destroyChatQueue();
var person = null;
this.connected = false;
for (var i=0; i<this.people.length; i++) {
console.log('DESTROY: '+this.userid);
person = this.people[i];
person.user = null;
for (var j in person.rooms) {
this.leaveRoom(person.rooms[j], person);
}
}
this.people = [];
};
User.prototype.joinRoom = function(room, socket) {
roomid = room?(room.id||room):'';
room = Rooms.get(room);
var person = null;
//console.log('JOIN ROOM: '+this.userid+' '+room.id);
if (!socket) {
for (var i=0; i<this.people.length;i++) {
// only join full clients, not pop-out single-room
// clients
if (this.people[i].rooms['lobby']) {
this.joinRoom(room, this.people[i]);
}
}
return;
} else if (socket.socket) {
person = socket;
socket = person.socket;
}
if (!socket) return;
else {
var i=0;
while (this.people[i].socket !== socket) i++;
if (this.people[i].socket === socket) {
person = this.people[i];
}
}
if (person && !person.rooms[room.id]) {
person.rooms[room.id] = room;
if (!this.roomCount[room.id]) {
this.roomCount[room.id]=1;
room.join(this);
} else {
this.roomCount[room.id]++;
room.initSocket(this, socket);
}
} else if (person && room.id === 'lobby') {
person.socket.emit('init', {room: roomid, notFound: true});
}
};
User.prototype.leaveRoom = function(room, socket) {
room = Rooms.get(room);
for (var i=0; i<this.people.length; i++) {
if (this.people[i] === socket || this.people[i].socket === socket || !socket) {
if (this.people[i].rooms[room.id]) {
if (this.roomCount[room.id]) {
this.roomCount[room.id]--;
if (!this.roomCount[room.id]) {
room.leave(this);
delete this.roomCount[room.id];
}
}
if (!this.people[i]) {
// race condition? This should never happen, but it does.
fs.createWriteStream('logs/errors.txt', {'flags': 'a'}).on("open", function(fd) {
this.write("\npeople="+JSON.stringify(this.people)+"\ni="+i+"\n\n");
this.end();
});
} else {
delete this.people[i].rooms[room.id];
}
}
if (socket) {
break;
}
}
}
if (!socket && this.roomCount[room.id]) {
room.leave(this);
delete this.roomCount[room.id];
}
};
User.prototype.updateChallenges = function() {
this.emit('update', {
challengesFrom: this.challengesFrom,
challengeTo: this.challengeTo
});
};
User.prototype.makeChallenge = function(user, format, isPrivate) {
user = getUser(user);
if (!user || this.challengeTo) {
return false;
}
if (new Date().getTime() < this.lastChallenge + 10000) {
// 10 seconds ago
return false;
}
var time = new Date().getTime();
var challenge = {
time: time,
from: this.userid,
to: user.userid,
format: ''+(format||''),
isPrivate: !!isPrivate
};
this.lastChallenge = time;
this.challengeTo = challenge;
user.challengesFrom[this.userid] = challenge;
this.updateChallenges();
user.updateChallenges();
};
User.prototype.cancelChallengeTo = function() {
if (!this.challengeTo) return true;
var user = getUser(this.challengeTo.to);
if (user) delete user.challengesFrom[this.userid];
this.challengeTo = null;
this.updateChallenges();
if (user) user.updateChallenges();
};
User.prototype.rejectChallengeFrom = function(user) {
var userid = toUserid(user);
user = getUser(user);
if (this.challengesFrom[userid]) {
delete this.challengesFrom[userid];
}
if (user) {
delete this.challengesFrom[user.userid];
if (user.challengeTo && user.challengeTo.to === this.userid) {
user.challengeTo = null;
user.updateChallenges();
}
}
this.updateChallenges();
};
User.prototype.acceptChallengeFrom = function(user) {
var userid = toUserid(user);
user = getUser(user);
if (!user || !user.challengeTo || user.challengeTo.to !== this.userid) {
if (this.challengesFrom[userid]) {
delete this.challengesFrom[userid];
this.updateChallenges();
}
return false;
}
Rooms.get('lobby').startBattle(this, user, user.challengeTo.format);
delete this.challengesFrom[user.userid];
user.challengeTo = null;
this.updateChallenges();
user.updateChallenges();
return true;
};
// chatQueue should be an array, but you know about mutables in prototypes...
// P.S. don't replace this with an array unless you know what mutables in prototypes do.
User.prototype.chatQueue = null;
User.prototype.chatQueueTimeout = null;
User.prototype.lastChatMessage = 0;
User.prototype.chat = function(message, room, socket) {
var now = new Date().getTime();
if (this.chatQueueTimeout) {
if (!this.chatQueue) this.chatQueue = []; // this should never happen
if (this.chatQueue.length > 6) {
socket.emit('console', {
room: room.id,
rawMessage: "<strong style=\"color:red\">Your message was not sent because you've been typing too quickly.</strong>"
});
} else {
this.chatQueue.push([message, room, socket]);
}
} else if (now < this.lastChatMessage + THROTTLE_DELAY) {
this.chatQueue = [[message, room, socket]];
// Needs to be a closure so the "this" variable stays correct. I think.
var self = this;
this.chatQueueTimeout = setTimeout(function() {
self.processChatQueue();
}, THROTTLE_DELAY);
} else {
this.lastChatMessage = now;
room.chat(this, message, socket);
}
};
User.prototype.destroyChatQueue = function() {
// don't call this function unless the user's getting deallocated
this.chatQueue = null;
if (this.chatQueueTimeout) {
clearTimeout(this.chatQueueTimeout);
this.chatQueueTimeout = null;
}
};
User.prototype.processChatQueue = function() {
if (!this.chatQueue) return; // this should never happen
var toChat = this.chatQueue.shift();
toChat[1].chat(this, toChat[0], toChat[2]);
if (this.chatQueue.length) {
// Needs to be a closure so the "this" variable stays correct. I think.
var self = this;
this.chatQueueTimeout = setTimeout(function() {
self.processChatQueue();
}, THROTTLE_DELAY);
} else {
this.chatQueue = null;
this.chatQueueTimeout = null;
}
};
return User;
})();
var Person = (function () {
function Person(name, socket, user) {
this.named = true;
this.name = name;
this.userid = toUserid(name);
this.socket = socket;
this.rooms = {};
this.user = user;
numPeople++;
while (people['p'+numPeople]) {
// should never happen
numPeople++;
}
this.id = 'p'+numPeople;
people[this.id] = this;
this.ip = '';
if (socket.handshake && socket.handshake.address && socket.handshake.address.address) {
this.ip = socket.handshake.address.address;
}
if (ipSearch(this.ip,bannedIps)) {
// gonna kill this
this.banned = true;
this.user = null;
}
}
Person.prototype.rename = function(name) {
this.name = name;
this.userid = toUserid(name);
};
return Person;
})();
function ipSearch(ip, table) {
if (table[ip]) return true;
var dotIndex = ip.lastIndexOf('.');
for (var i=0; i<4 && dotIndex > 0; i++) {
ip = ip.substr(0, dotIndex);
if (table[ip+'.*']) return true;
dotIndex = ip.lastIndexOf('.');
}
return false;
}
exports.get = getUser;
exports.searchUser = searchUser;
exports.connectUser = connectUser;
exports.users = users;
exports.prevUsers = prevUsers;
exports.importUsergroups = importUsergroups;
exports.addBannedWord = addBannedWord;
exports.removeBannedWord = removeBannedWord;