Skip to content

Commit

Permalink
Implement /sharedip (#2870)
Browse files Browse the repository at this point in the history
* Implement /markshared

* Refactor /whois ips to two lines

* Refactor splitTarget
  • Loading branch information
Asheviere authored and Zarel committed Dec 25, 2016
1 parent 9d4afca commit 37205d9
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 28 deletions.
26 changes: 26 additions & 0 deletions chat-commands.js
Expand Up @@ -2318,6 +2318,32 @@ exports.commands = {
},
showblacklishelp: ["/showblacklist OR /showbl - show a list of blacklisted users in the room"],

markshared: function (target, room, user) {
if (!this.can('ban')) return false;
if (!target) return this.errorReply("No IP entered.");
let [ip, note] = this.splitOne(target);
if (!/^[0-9.*]+$/.test(ip)) return this.errorReply("Please enter a valid IP address.");

if (Punishments.sharedIps.get(ip)) return this.errorReply("This IP is already marked as shared.");

Punishments.addSharedIp(ip, note);
if (note) note = ` (${note})`;
return this.addModCommand(`The IP '${ip}' was marked as shared by ${user.name}.${note}`);
},
marksharedhelp: ["/markshared [ip] - Marks an IP address as shared. Requires @, &, ~"],

unmarkshared: function (target, room, user) {
if (!this.can('ban')) return false;
if (!target) return this.errorReply("No IP entered.");
if (!/^[0-9.*]+$/.test(target)) return this.errorReply("Please enter a valid IP address.");

if (!Punishments.sharedIps.get(target)) return this.errorReply("This IP isn't marked as shared.");

Punishments.removeSharedIp(target);
return this.addModCommand(`The IP '${target}' was unmarked as shared by ${user.name}.`);
},
unmarksharedhelp: ["/unmarkshared [ip] - Unmarks a shared IP address. Requires @, &, ~"],

modlog: function (target, room, user, connection) {
let lines = 0;
// Specific case for modlog command. Room can be indicated with a comma, lines go after the comma.
Expand Down
1 change: 1 addition & 0 deletions chat-plugins/info.js
Expand Up @@ -128,6 +128,7 @@ exports.commands = {
}
if ((user.can('ip', targetUser) || user === targetUser)) {
let ips = Object.keys(targetUser.ips);
ips = ips.map(ip => ip + (Punishments.sharedIps.has(ip) ? ' (shared)' : ''));
buf += `<br /> IP${Chat.plural(ips)}: ${ips.join(", ")}`;
if (user.group !== ' ' && targetUser.latestHost) {
buf += Chat.html`<br />Host: ${targetUser.latestHost}`;
Expand Down
38 changes: 15 additions & 23 deletions chat.js
Expand Up @@ -745,34 +745,26 @@ class CommandContext {
this.splitTarget(target, exactName);
return this.targetUser;
}
splitTarget(target, exactName) {
splitOne(target) {
let commaIndex = target.indexOf(',');
if (commaIndex < 0) {
let targetUser = Users.get(target, exactName);
this.targetUser = targetUser;
this.inputUsername = target.trim();
this.targetUsername = targetUser ? targetUser.name : target;
return '';
}
this.inputUsername = target.substr(0, commaIndex);
let targetUser = Users.get(this.inputUsername, exactName);
if (targetUser) {
this.targetUser = targetUser;
this.targetUsername = targetUser.name;
} else {
this.targetUser = null;
this.targetUsername = this.inputUsername;
return [target, ''];
}
return target.substr(commaIndex + 1).trim();
return [target.substr(0, commaIndex), target.substr(commaIndex + 1).trim()];
}
splitTarget(target, exactName) {
let [name, rest] = this.splitOne(target);

this.targetUser = Users.get(name, exactName);
this.inputUsername = name.trim();
this.targetUsername = this.targetUser ? this.targetUser.name : this.inputUsername;
return rest;
}
splitTargetText(target) {
let commaIndex = target.indexOf(',');
if (commaIndex < 0) {
this.targetUsername = target;
return '';
}
this.targetUsername = target.substr(0, commaIndex);
return target.substr(commaIndex + 1).trim();
let [first, rest] = this.splitOne(target);

this.targetUsername = first.trim();
return rest.trim();
}
}
Chat.CommandContext = CommandContext;
Expand Down
95 changes: 91 additions & 4 deletions punishments.js
Expand Up @@ -20,6 +20,7 @@ const path = require('path');

const PUNISHMENT_FILE = path.resolve(__dirname, 'config/punishments.tsv');
const ROOM_PUNISHMENT_FILE = path.resolve(__dirname, 'config/room-punishments.tsv');
const SHAREDIPS_FILE = path.resolve(__dirname, 'config/sharedips.tsv');

const RANGELOCK_DURATION = 60 * 60 * 1000; // 1 hour
const LOCK_DURATION = 48 * 60 * 60 * 1000; // 48 hours
Expand Down Expand Up @@ -112,6 +113,11 @@ Punishments.roomUserids = new NestedPunishmentMap();
*/
Punishments.roomIps = new NestedPunishmentMap();

/**
* sharedIps is an ip:note Map
*/
Punishments.sharedIps = new Map();


/*********************************************************
* Persistence
Expand Down Expand Up @@ -332,10 +338,47 @@ Punishments.loadBanlist = function () {
});
};

// sharedips.tsv is in the format:
// IP, type (in this case always SHARED), note

Punishments.loadSharedIps = function () {
fs.readFile(SHAREDIPS_FILE, (err, data) => {
if (err) return;
data = String(data).split("\n");
for (let i = 0; i < data.length; i++) {
if (!data[i] || data[i] === '\r') continue;
const [ip, type, note] = data[i].trim().split("\t");
if (!ip.includes('.')) continue;
if (type !== 'SHARED') continue;

Punishments.sharedIps.set(ip, note);
}
});
};

/**
* @param {string} ip
* @param {string} note
*/
Punishments.appendSharedIp = function (ip, note) {
let buf = `${ip}\tSHARED\t${note}\r\n`;
fs.appendFile(SHAREDIPS_FILE, buf, () => {});
};

Punishments.saveSharedIps = function () {
let buf = 'IP\tType\tNote\r\n';
Punishments.sharedIps.forEach((note, ip) => {
buf += `${ip}\tSHARED\t${note}\r\n`;
});

fs.writeFile(SHAREDIPS_FILE, buf, () => {});
};

setImmediate(() => {
Punishments.loadPunishments();
Punishments.loadRoomPunishments();
Punishments.loadBanlist();
Punishments.loadSharedIps();
});

/*********************************************************
Expand Down Expand Up @@ -783,6 +826,34 @@ Punishments.roomUnblacklistAll = function (room) {
return unblacklisted;
};

/**
* @param {string} ip
* @param {string} note
*/
Punishments.addSharedIp = function (ip, note) {
Punishments.sharedIps.set(ip, note);
Punishments.appendSharedIp(ip, note);

Users.users.forEach(user => {
if (user.locked && user.locked !== user.userid && ip in user.ips) {
if (!user.autoconfirmed) {
user.semilocked = `#sharedip ${user.locked}`;
}
user.locked = false;

user.updateIdentity();
}
});
};

/**
* @param {string} ip
*/
Punishments.removeSharedIp = function (ip) {
Punishments.sharedIps.delete(ip);
Punishments.saveSharedIps();
};

/*********************************************************
* Checking
*********************************************************/
Expand Down Expand Up @@ -912,9 +983,15 @@ Punishments.checkIp = function (user, connection) {
let punishment = Punishments.ipSearch(ip);

if (punishment) {
user.locked = punishment[1];
if (punishment[0] === 'NAMELOCK') {
user.namelocked = punishment[1];
if (Punishments.sharedIps.has(user.latestIp)) {
if (connection.user && !connection.user.locked && !connection.user.autoconfirmed) {
connection.user.semilocked = `#sharedip ${punishment[1]}`;
}
} else {
user.locked = punishment[1];
if (punishment[0] === 'NAMELOCK') {
user.namelocked = punishment[1];
}
}
}

Expand Down Expand Up @@ -954,6 +1031,8 @@ Punishments.checkIpBanned = function (connection) {
return '#cflood';
}

if (Punishments.sharedIps.has(ip)) return false;

let banned = false;
let punishment = Punishments.ipSearch(ip);
if (punishment && punishment[0] === 'BAN') {
Expand Down Expand Up @@ -1041,7 +1120,15 @@ Punishments.isRoomBanned = function (user, roomid) {

for (let ip in user.ips) {
punishment = Punishments.roomIps.nestedGet(roomid, ip);
if (punishment && (punishment[0] === 'ROOMBAN' || punishment[0] === 'BLACKLIST')) return punishment;
if (punishment) {
if (punishment[0] === 'ROOMBAN') {
return punishment;
} else if (punishment[0] === 'BLACKLIST') {
if (Punishments.sharedIps.has(ip) && user.autoconfirmed) return;

return punishment;
}
}
}
};

Expand Down
4 changes: 3 additions & 1 deletion users.js
Expand Up @@ -937,7 +937,9 @@ class User {
this.namelocked = false;
}
if (this.autoconfirmed && this.semilocked) {
if (this.semilocked === '#dnsbl') {
if (this.semilocked.startsWith('#sharedip')) {
this.semilocked = false;
} else if (this.semilocked === '#dnsbl') {
this.popup(`You are locked because someone using your IP has spammed/hacked other websites. This usually means you're using a proxy, in a country where other people commonly hack, or have a virus on your computer that's spamming websites.`);
this.semilocked = '#dnsbl.';
}
Expand Down

0 comments on commit 37205d9

Please sign in to comment.