"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var hosts_exports = {};
__export(hosts_exports, {
commands: () => commands,
pages: () => pages,
visualizeRangeList: () => visualizeRangeList
});
module.exports = __toCommonJS(hosts_exports);
var import_lib = require("../../lib");
const HOST_SUFFIXES = ["res", "proxy", "mobile"];
const SUFFIX_ALIASES = {
residential: "res"
};
const WHITELISTED_USERIDS = [];
function checkCanPerform(context, user, permission = "lockdown") {
if (!WHITELISTED_USERIDS.includes(user.id))
context.checkCan(permission);
}
function getHostType(type) {
type = toID(type);
if (HOST_SUFFIXES.includes(type))
return type;
if (SUFFIX_ALIASES[type])
return SUFFIX_ALIASES[type];
throw new Chat.ErrorMessage(`'${type}' is not a valid host type. Please specify one of ${HOST_SUFFIXES.join(", ")}.`);
}
function visualizeRangeList(ranges) {
let html = `
Lowest IP address | Highest IP address | Host |
`;
for (const range of ranges) {
html += ``;
html += `${IPTools.numberToIP(range.minIP)} | `;
html += `${IPTools.numberToIP(range.maxIP)} | `;
html += import_lib.Utils.html`${range.host} | `;
html += `
`;
}
return html;
}
function formatRange(range, includeModlogBrackets) {
const startBracket = includeModlogBrackets ? "[" : "";
const endBracket = includeModlogBrackets ? "]" : "";
let result = `${startBracket}${IPTools.numberToIP(range.minIP)}${endBracket}`;
result += `-${startBracket}${IPTools.numberToIP(range.maxIP)}${endBracket}`;
if (range.host)
result += ` (${range.host})`;
return result;
}
const pages = {
proxies(query, user) {
this.title = "[Proxies]";
checkCanPerform(this, user, "globalban");
const openProxies = [...IPTools.singleIPOpenProxies];
const proxyHosts = [...IPTools.proxyHosts];
import_lib.Utils.sortBy(openProxies, (ip) => {
const number = IPTools.ipToNumber(ip);
if (number === null) {
Rooms.get("upperstaff")?.add(`|error|Invalid IP address in IPTools.singleIPOpenProxies: '${ip}'`);
return -1;
}
return number;
});
proxyHosts.sort();
IPTools.sortRanges();
let html = `Single IP proxies:
IP | Type |
`;
for (const proxyIP of openProxies) {
html += `${proxyIP} | Single IP open proxy |
`;
}
html += `
`;
html += `Proxy hosts:
Host | Type |
`;
for (const proxyHost of proxyHosts) {
html += `${proxyHost} | Proxy host |
`;
}
html += `
`;
html += `Proxy IP Ranges:
`;
html += visualizeRangeList(IPTools.ranges.filter((r) => r.host?.endsWith("/proxy")));
html += `
`;
return html;
},
hosts(query, user) {
this.title = "[Hosts]";
checkCanPerform(this, user, "globalban");
const type = toID(query[0]) || "all";
IPTools.sortRanges();
const mobileHosts = ["all", "mobile"].includes(type) ? [...IPTools.mobileHosts] : [];
const residentialHosts = ["all", "residential", "res"].includes(type) ? [...IPTools.residentialHosts] : [];
const hostRanges = ["all", "ranges", "isps"].includes(type) ? IPTools.ranges.filter((r) => r.host && !r.host.endsWith("/proxy")) : [];
mobileHosts.sort();
residentialHosts.sort();
let html = `Mobile hosts:
Host | Type |
`;
for (const mobileHost of mobileHosts) {
html += `${mobileHost} | Mobile host |
`;
}
html += `
`;
html += `Residential hosts:
Host | Type |
`;
for (const resHost of residentialHosts) {
html += `${resHost} | Residential host |
`;
}
html += `
`;
html += `ISP IP Ranges:
`;
html += visualizeRangeList(hostRanges);
html += `
`;
return html;
},
ranges(query, user) {
this.title = "[IP Ranges]";
checkCanPerform(this, user, "globalban");
const type = toID(query[0]) || "all";
IPTools.sortRanges();
let html = ``;
if (["all", "mobile"].includes(type)) {
html += `Mobile IP Ranges:
`;
html += visualizeRangeList(IPTools.ranges.filter((range) => range.host?.endsWith("/mobile")));
html += `
`;
}
if (["all", "res", "residential"].includes(type)) {
html += `Residential IP Ranges:
`;
html += visualizeRangeList(IPTools.ranges.filter((range) => range.host?.endsWith("/res")));
html += `
`;
}
if (["all", "proxy", "proxies"].includes(type)) {
html += `Proxy IP Ranges:
`;
html += visualizeRangeList(IPTools.ranges.filter((range) => range.host?.endsWith("/proxy")));
html += `
`;
}
if (["all", "openproxy"].includes(type)) {
html += `Single-IP Open Proxies:
`;
for (const ip of IPTools.singleIPOpenProxies) {
html += `${ip} |
`;
}
html += `
`;
}
return html;
},
sharedipblacklist(args, user, connection) {
this.title = `[Shared IP Blacklist]`;
checkCanPerform(this, user, "lock");
let buf = `IPs blocked from being marked as shared
`;
if (!Punishments.sharedIpBlacklist.size) {
buf += `
None currently.
`;
} else {
buf += `
IP | Reason |
`;
const sortedSharedIPBlacklist = [...Punishments.sharedIpBlacklist];
import_lib.Utils.sortBy(sortedSharedIPBlacklist, ([ipOrRange]) => {
if (IPTools.ipRegex.test(ipOrRange)) {
const number = IPTools.ipToNumber(ipOrRange);
if (number === null) {
Monitor.error(`Invalid blacklisted-from-markshared IP: '${ipOrRange}`);
return -1;
}
return number;
}
return IPTools.stringToRange(ipOrRange).minIP;
});
for (const [ip, reason] of sortedSharedIPBlacklist) {
buf += `${ip} | ${reason} |
`;
}
buf += `
`;
}
buf += `
`;
return buf;
},
sharedips(args, user, connection) {
this.title = `[Shared IPs]`;
checkCanPerform(this, user, "globalban");
let buf = `IPs marked as shared
`;
if (!Punishments.sharedIps.size) {
buf += `
None currently.
`;
} else {
buf += `
IP | Location |
`;
const sortedSharedIPs = [...Punishments.sharedIps];
import_lib.Utils.sortBy(sortedSharedIPs, ([ip]) => {
const number = IPTools.ipToNumber(ip);
if (number === null) {
Monitor.error(`Invalid shared IP address: '${ip}'`);
return -1;
}
return number;
});
for (const [ip, location] of sortedSharedIPs) {
buf += `${ip} | ${location} |
`;
}
buf += `
`;
}
buf += `
`;
return buf;
}
};
const commands = {
dc: "ipranges",
datacenter: "ipranges",
datacenters: "ipranges",
iprange: "ipranges",
ipranges: {
"": "help",
help() {
return this.parse("/help ipranges");
},
show: "view",
view(target, room, user) {
checkCanPerform(this, user, "globalban");
const types = ["all", "residential", "res", "mobile", "proxy", "openproxy"];
const type = target ? toID(target) : "all";
if (!types.includes(type)) {
return this.errorReply(`'${type}' isn't a valid host type. Specify one of ${types.join(", ")}.`);
}
return this.parse(`/join view-ranges-${type}`);
},
viewhelp: [
`/ipranges view - View the list of all IP ranges. Requires: hosts manager @ ~`,
`/ipranges view [type] - View the list of a particular type of IP range ('residential', 'mobile', or 'proxy'). Requires: hosts manager @ ~`
],
// Originally by Zarel
widen: "add",
add(target, room, user, connection, cmd) {
checkCanPerform(this, user, "globalban");
if (!target)
return this.parse("/help ipranges add");
const widen = cmd.includes("widen");
const [typeString, stringRange, host] = target.split(",").map((part) => part.trim());
if (!host || !IPTools.hostRegex.test(host)) {
return this.errorReply(`Invalid data: ${target}`);
}
const type = getHostType(typeString);
const range = IPTools.stringToRange(stringRange);
if (!range)
return this.errorReply(`Couldn't parse IP range '${stringRange}'.`);
range.host = `${IPTools.urlToHost(host)}?/${type}`;
IPTools.sortRanges();
let result;
try {
result = IPTools.checkRangeConflicts(range, IPTools.ranges, widen);
} catch (e) {
return this.errorReply(e.message);
}
if (typeof result === "number") {
IPTools.removeRange(IPTools.ranges[result].minIP, IPTools.ranges[result].maxIP);
}
IPTools.addRange(range);
this.privateGlobalModAction(`${user.name} added the IP range ${formatRange(range)} to the list of ${type} ranges.`);
this.globalModlog("IPRANGE ADD", null, formatRange(range, true));
},
addhelp: [
`/ipranges add [type], [low]-[high], [host] - Adds an IP range. Requires: hosts manager ~`,
`/ipranges widen [type], [low]-[high], [host] - Adds an IP range, allowing a new range to completely cover an old range. Requires: hosts manager ~`,
`For example: /ipranges add proxy, 5.152.192.0 - 5.152.223.255, redstation.com`,
`Get datacenter info from whois; [low], [high] are the range in the last inetnum; [type] is one of res, proxy, or mobile.`
],
remove(target, room, user) {
checkCanPerform(this, user);
if (!target)
return this.parse("/help ipranges remove");
const range = IPTools.stringToRange(target);
if (!range)
return this.errorReply(`Couldn't parse the IP range '${target}'.`);
if (!IPTools.getRange(range.minIP, range.maxIP))
return this.errorReply(`No IP range found at '${target}'.`);
void IPTools.removeRange(range.minIP, range.maxIP);
this.privateGlobalModAction(`${user.name} removed the IP range ${formatRange(range)}.`);
this.globalModlog("IPRANGE REMOVE", null, formatRange(range, true));
},
removehelp: [
`/ipranges remove [low IP]-[high IP] - Removes an IP range. Requires: hosts manager ~`,
`Example: /ipranges remove 5.152.192.0-5.152.223.255`
],
rename(target, room, user) {
checkCanPerform(this, user);
if (!target)
return this.parse("/help ipranges rename");
const [type, rangeString, url] = target.split(",").map((part) => part.trim());
if (!url) {
return this.parse("/help ipranges rename");
}
const toRename = IPTools.stringToRange(rangeString);
if (!toRename)
return this.errorReply(`Couldn't parse IP range '${rangeString}'.`);
const exists = IPTools.getRange(toRename.minIP, toRename.maxIP);
if (!exists)
return this.errorReply(`No IP range found at '${rangeString}'.`);
const range = {
minIP: toRename.minIP,
maxIP: toRename.maxIP,
host: `${IPTools.urlToHost(url)}?/${type}`
};
void IPTools.addRange(range);
this.privateGlobalModAction(`${user.name} renamed the IP range ${formatRange(toRename)} to ${range.host}.`);
this.globalModlog("IPRANGE RENAME", null, `IP range ${formatRange(toRename, true)} to ${range.host}`);
},
renamehelp: [
`/ipranges rename [type], [low IP]-[high IP], [host] - Changes the host an IP range resolves to. Requires: hosts manager ~`
]
},
iprangeshelp() {
const help = [
`/ipranges view [type]
: view the list of a particular type of IP range (residential
, mobile
, or proxy
). Requires: hosts manager @ ~`,
`/ipranges add [type], [low IP]-[high IP], [host]
: add IP ranges (can be multiline). Requires: hosts manager ~/ipranges view
: view the list of all IP ranges. Requires: hosts manager @ ~`,
`/ipranges widen [type], [low IP]-[high IP], [host]
: add IP ranges, allowing a new range to completely cover an old range. Requires: hosts manager ~`,
`For example: /ipranges add proxy, 5.152.192.0-5.152.223.255, redstation.com
.`,
`Get datacenter info from /whois
; [low IP]
, [high IP]
are the range in the last inetnum.`,
`/ipranges remove [low IP]-[high IP]
: remove IP range(s). Can be multiline. Requires: hosts manager ~`,
`For example: /ipranges remove 5.152.192.0, 5.152.223.255
.`,
`/ipranges rename [type], [low IP]-[high IP], [host]
: changes the host an IP range resolves to. Requires: hosts manager ~`
];
return this.sendReply(`|html|${help.join("
")}`);
},
viewhosts(target, room, user) {
checkCanPerform(this, user, "globalban");
const types = ["all", "residential", "mobile", "ranges"];
const type = target ? toID(target) : "all";
if (!types.includes(type)) {
return this.errorReply(`'${type}' isn't a valid host type. Specify one of ${types.join(", ")}.`);
}
return this.parse(`/join view-hosts-${type}`);
},
viewhostshelp: [
`/viewhosts - View the list of hosts. Requires: hosts manager @ ~`,
`/viewhosts [type] - View the list of a particular type of host. Requires: hosts manager @ ~`,
`Host types are: 'all', 'residential', 'mobile', and 'ranges'.`
],
removehost: "addhosts",
removehosts: "addhosts",
addhost: "addhosts",
addhosts(target, room, user, connection, cmd) {
checkCanPerform(this, user);
const removing = cmd.includes("remove");
let [type, ...hosts] = target.split(",");
type = toID(type);
hosts = hosts.map((host) => host.trim());
if (!hosts.length)
return this.parse("/help addhosts");
switch (type) {
case "openproxy":
for (const host of hosts) {
if (!IPTools.ipRegex.test(host))
return this.errorReply(`'${host}' is not a valid IP address.`);
if (removing !== IPTools.singleIPOpenProxies.has(host)) {
return this.errorReply(`'${host}' is ${removing ? "not" : "already"} in the list of proxy IPs.`);
}
}
if (removing) {
void IPTools.removeOpenProxies(hosts);
} else {
void IPTools.addOpenProxies(hosts);
}
break;
case "proxy":
for (const host of hosts) {
if (!IPTools.hostRegex.test(host))
return this.errorReply(`'${host}' is not a valid host.`);
if (removing !== IPTools.proxyHosts.has(host)) {
return this.errorReply(`'${host}' is ${removing ? "not" : "already"} in the list of proxy hosts.`);
}
}
if (removing) {
void IPTools.removeProxyHosts(hosts);
} else {
void IPTools.addProxyHosts(hosts);
}
break;
case "residential":
for (const host of hosts) {
if (!IPTools.hostRegex.test(host))
return this.errorReply(`'${host}' is not a valid host.`);
if (removing !== IPTools.residentialHosts.has(host)) {
return this.errorReply(`'${host}' is ${removing ? "not" : "already"} in the list of residential hosts.`);
}
}
if (removing) {
void IPTools.removeResidentialHosts(hosts);
} else {
void IPTools.addResidentialHosts(hosts);
}
break;
case "mobile":
for (const host of hosts) {
if (!IPTools.hostRegex.test(host))
return this.errorReply(`'${host}' is not a valid host.`);
if (removing !== IPTools.mobileHosts.has(host)) {
return this.errorReply(`'${host}' is ${removing ? "not" : "already"} in the list of mobile hosts.`);
}
}
if (removing) {
void IPTools.removeMobileHosts(hosts);
} else {
void IPTools.addMobileHosts(hosts);
}
break;
default:
return this.errorReply(`'${type}' isn't one of 'openproxy', 'proxy', 'residential', or 'mobile'.`);
}
this.privateGlobalModAction(
`${user.name} ${removing ? "removed" : "added"} ${hosts.length} hosts (${hosts.join(", ")}) ${removing ? "from" : "to"} the ${type} category`
);
this.globalModlog(removing ? "REMOVEHOSTS" : "ADDHOSTS", null, `${type}: ${hosts.join(", ")}`);
},
addhostshelp: [
`/addhosts [category], host1, host2, ... - Adds hosts to the given category. Requires: hosts manager ~`,
`/removehosts [category], host1, host2, ... - Removes hosts from the given category. Requires: hosts manager ~`,
`Categories are: 'openproxy' (which takes IP addresses, not hosts), 'proxy', 'residential', and 'mobile'.`
],
viewproxies(target, room, user) {
checkCanPerform(this, user, "globalban");
return this.parse("/join view-proxies");
},
viewproxieshelp: [
`/viewproxies - View the list of proxies. Requires: hosts manager @ ~`
],
markshared(target, room, user) {
if (!target)
return this.parse("/help markshared");
checkCanPerform(this, user, "globalban");
const [ip, note] = this.splitOne(target);
if (!IPTools.ipRegex.test(ip)) {
const pattern = IPTools.stringToRange(ip);
if (!pattern) {
return this.errorReply("Please enter a valid IP address.");
}
if (!user.can("rangeban")) {
return this.errorReply("Only upper staff can markshare ranges.");
}
for (const range of Punishments.sharedRanges.keys()) {
if (IPTools.rangeIntersects(range, pattern)) {
return this.errorReply(
`Range ${IPTools.rangeToString(pattern)} intersects with shared range ${IPTools.rangeToString(range)}`
);
}
}
}
if (Punishments.isSharedIp(ip))
return this.errorReply("This IP is already marked as shared.");
if (Punishments.isBlacklistedSharedIp(ip)) {
return this.errorReply(`This IP is blacklisted from being marked as shared.`);
}
if (!note) {
this.errorReply(`You must specify who owns this shared IP.`);
this.parse(`/help markshared`);
return;
}
Punishments.addSharedIp(ip, note);
this.privateGlobalModAction(`The IP '${ip}' was marked as shared by ${user.name}. (${note})`);
this.globalModlog("SHAREDIP", null, note, ip);
},
marksharedhelp: [
`/markshared [IP], [owner/organization of IP] - Marks an IP address as shared.`,
`Note: the owner/organization (i.e., University of Minnesota) of the shared IP is required. Requires @ ~`
],
unmarkshared(target, room, user) {
if (!target)
return this.parse("/help unmarkshared");
checkCanPerform(this, user, "globalban");
target = target.trim();
const pattern = IPTools.stringToRange(target);
if (!pattern)
return this.errorReply("Please enter a valid IP address.");
if (pattern.minIP !== pattern.maxIP && !user.can("rangeban")) {
return this.errorReply(`Only administrators can unmarkshare ranges.`);
}
let shared = false;
if (pattern.minIP !== pattern.maxIP) {
for (const range of Punishments.sharedRanges.keys()) {
shared = range.minIP === pattern.minIP && range.maxIP === pattern.maxIP;
if (shared)
break;
}
} else {
shared = Punishments.sharedIps.has(target);
}
if (!shared)
return this.errorReply(`That IP/range isn't marked as shared.`);
Punishments.removeSharedIp(target);
this.privateGlobalModAction(`The IP '${target}' was unmarked as shared by ${user.name}.`);
this.globalModlog("UNSHAREDIP", null, null, target);
},
unmarksharedhelp: [`/unmarkshared [IP] - Unmarks a shared IP address. Requires @ ~`],
marksharedblacklist: "nomarkshared",
marksharedbl: "nomarkshared",
nomarkshared: {
add(target, room, user) {
if (!target)
return this.parse(`/help nomarkshared`);
checkCanPerform(this, user, "globalban");
const [ip, ...reasonArr] = target.split(",");
if (!IPTools.ipRangeRegex.test(ip))
return this.errorReply(`Please enter a valid IP address or range.`);
if (!reasonArr?.length) {
this.errorReply(`A reason is required.`);
this.parse(`/help nomarkshared`);
return;
}
if (Punishments.isBlacklistedSharedIp(ip)) {
return this.errorReply(`This IP is already blacklisted from being marked as shared.`);
}
if (!IPTools.ipRegex.test(ip)) {
if (!ip.endsWith("*")) {
this.errorReply(`That looks like a range, but it is invalid.`);
this.errorReply(`Append * to the end of the range and try again.`);
return;
}
if (!user.can("bypassall")) {
return this.errorReply(`Only Administrators can add ranges.`);
}
const range = IPTools.stringToRange(ip);
if (!range)
return this.errorReply(`Invalid IP range.`);
for (const sharedIp of Punishments.sharedIps.keys()) {
const ipNum = IPTools.ipToNumber(sharedIp);
if (IPTools.checkPattern([range], ipNum)) {
this.parse(`/unmarkshared ${sharedIp}`);
}
}
} else {
if (Punishments.isSharedIp(ip))
this.parse(`/unmarkshared ${ip}`);
}
const reason = reasonArr.join(",");
Punishments.addBlacklistedSharedIp(ip, reason);
this.privateGlobalModAction(`The IP '${ip}' was blacklisted from being marked as shared by ${user.name}.`);
this.globalModlog("SHAREDIP BLACKLIST", null, reason.trim(), ip);
},
remove(target, room, user) {
if (!target)
return this.parse(`/help nomarkshared`);
checkCanPerform(this, user);
if (!IPTools.ipRangeRegex.test(target))
return this.errorReply(`Please enter a valid IP address or range.`);
if (!Punishments.sharedIpBlacklist.has(target)) {
return this.errorReply(`This IP is not blacklisted from being marked as shared.`);
}
Punishments.removeBlacklistedSharedIp(target);
this.privateGlobalModAction(`The IP '${target}' was unblacklisted from being marked as shared by ${user.name}.`);
this.globalModlog("SHAREDIP UNBLACKLIST", null, null, target);
},
view() {
return this.parse(`/join view-sharedipblacklist`);
},
help: "",
""() {
return this.parse(`/help nomarkshared`);
}
},
nomarksharedhelp: [
`/nomarkshared add [IP], [reason] - Prevents an IP from being marked as shared until it's removed from this list. Requires ~`,
`Note: Reasons are required.`,
`/nomarkshared remove [IP] - Removes an IP from the nomarkshared list. Requires ~`,
`/nomarkshared view - Lists all IPs prevented from being marked as shared. Requires @ ~`
],
sharedips: "viewsharedips",
viewsharedips() {
return this.parse("/join view-sharedips");
},
viewsharedipshelp: [
`/viewsharedips \u2014 Lists IP addresses marked as shared. Requires: hosts manager @ ~`
]
};
//# sourceMappingURL=hosts.js.map