"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 addressHighest IP addressHost`; 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:

`; for (const proxyIP of openProxies) { html += ``; } html += `
IPType
${proxyIP}Single IP open proxy
`; html += `

Proxy hosts:

`; for (const proxyHost of proxyHosts) { html += ``; } html += `
HostType
${proxyHost}Proxy host
`; 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:

`; for (const mobileHost of mobileHosts) { html += ``; } html += `
HostType
${mobileHost}Mobile host
`; html += `

Residential hosts:

`; for (const resHost of residentialHosts) { html += ``; } html += `
HostType
${resHost}Residential host
`; 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 += ``; } html += `
${ip}
`; } 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 += `
`; 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 += ``; } buf += `
IPReason
${ip}${reason}
`; } 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 += `
`; 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 += ``; } buf += `
IPLocation
${ip}${location}
`; } 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