893 lines
39 KiB
JavaScript
893 lines
39 KiB
JavaScript
"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 chat_monitor_exports = {};
|
|
__export(chat_monitor_exports, {
|
|
Filters: () => Filters,
|
|
chatfilter: () => chatfilter,
|
|
commands: () => commands,
|
|
loginfilter: () => loginfilter,
|
|
namefilter: () => namefilter,
|
|
nicknamefilter: () => nicknamefilter,
|
|
pages: () => pages,
|
|
statusfilter: () => statusfilter
|
|
});
|
|
module.exports = __toCommonJS(chat_monitor_exports);
|
|
var import_lib = require("../../lib");
|
|
const LEGACY_MONITOR_FILE = "config/chat-plugins/chat-monitor.tsv";
|
|
const MONITOR_FILE = "config/chat-plugins/chat-filter.json";
|
|
const WRITE_THROTTLE_TIME = 5 * 60 * 1e3;
|
|
const EVASION_DETECTION_SUBSTITUTIONS = {
|
|
a: ["a", "4", "@", "\xE1", "\xE2", "\xE3", "\xE0", "\u15E9", "A", "\u24D0", "\u24B6", "\u03B1", "\u034F", "\u20B3", "\xE4", "\xC4", "\u13D7", "\u03BB", "\u0394", "\u1E00", "\u13AA", "\u01DF", "\u033E", "\uFF41", "\uFF21", "\u1D00", "\u0250", "\u{1F150}", "\u{1D41A}", "\u{1D400}", "\u{1D622}", "\u{1D608}", "\u{1D656}", "\u{1D63C}", "\u{1D4B6}", "\u{1D4EA}", "\u{1D4D0}", "\u{1D552}", "\u{1D538}", "\u{1D51E}", "\u{1D504}", "\u{1D586}", "\u{1D56C}", "\u{1F130}", "\u{1F170}", "\u{1D49C}", "\u{1D68A}", "\u{1D670}", "\uA34F", "\u0430", "\u{1D4EA}"],
|
|
b: ["b", "8", "\u15F7", "B", "\u24D1", "\u24B7", "\u0432", "\u0E3F", "\u1E05", "\u1E04", "\u13F0", "\u03D0", "\u0181", "\u1E03", "\u1E02", "\u026E", "\uFF42", "\uFF22", "\u0299", "\u{1F151}", "\u{1D41B}", "\u{1D401}", "\u{1D623}", "\u{1D609}", "\u{1D657}", "\u{1D63D}", "\u{1D4B7}", "\u{1D4EB}", "\u{1D4D1}", "\u{1D553}", "\u{1D539}", "\u{1D51F}", "\u{1D505}", "\u{1D587}", "\u{1D56D}", "\u{1F131}", "\u{1F171}", "\u{1D435}", "\u10A6", "\u{1D68B}", "\u{1D671}", "\u266D", "b"],
|
|
c: ["c", "\xE7", "\u1455", "C", "\u24D2", "\u24B8", "\xA2", "\u034F", "\u20B5", "\u010B", "\u010A", "\u1348", "\u03C2", "\u1E09", "\u1E08", "\u13DF", "\u0188", "\u033E", "\uFF43", "\uFF23", "\u1D04", "\u0254", "\u{1F152}", "\u{1D41C}", "\u{1D402}", "\u{1D624}", "\u{1D60A}", "\u{1D658}", "\u{1D63E}", "\u{1D4B8}", "\u{1D4EC}", "\u{1D4D2}", "\u{1D554}", "\u2102", "\u{1D520}", "\u212D", "\u{1D588}", "\u{1D56E}", "\u{1F132}", "\u{1F172}", "\u{1D49E}", "\u{1D68C}", "\u{1D672}", "\u263E", "\u0441"],
|
|
d: ["d", "\u15EA", "D", "\u24D3", "\u24B9", "\u2202", "\u0110", "\u010F", "\u010E", "\u13B4", "\u1E0A", "\u13A0", "\u0256", "\uFF44", "\uFF24", "\u1D05", "\u{1F153}", "\u{1D41D}", "\u{1D403}", "\u{1D625}", "\u{1D60B}", "\u{1D659}", "\u{1D63F}", "\u{1D4B9}", "\u{1D4ED}", "\u{1D4D3}", "\u{1D555}", "\u200B", "\u{1D521}", "\u{1D589}", "\u{1D56F}", "\u{1F133}", "\u{1F173}", "\u{1D49F}", "\u0503", "\u{1D68D}", "\u{1D673}", "\u25D7", "\u217E"],
|
|
e: ["e", "3", "\xE9", "\xEA", "E", "\u24D4", "\u24BA", "\u0454", "\u034F", "\u0246", "\u1EC7", "\u1EC6", "\u13CB", "\u03B5", "\u03A3", "\u1E15", "\u1E14", "\u13AC", "\u025B", "\u033E", "\uFF45", "\uFF25", "\u1D07", "\u01DD", "\u{1F154}", "\u{1D41E}", "\u{1D404}", "\u{1D626}", "\u{1D60C}", "\u{1D65A}", "\u{1D640}", "\u212F", "\u{1D4EE}", "\u{1D4D4}", "\u{1D556}", "\u{1D53B}", "\u{1D522}", "\u{1D507}", "\u{1D58A}", "\u{1D570}", "\u{1F134}", "\u{1F174}", "\u{1D452}", "\u{1D438}", "\u04BD", "\u{1D68E}", "\u{1D674}", "\u20AC", "\u0435", "\u0451", "\u{1D4EE}"],
|
|
f: ["f", "\u15B4", "F", "\u24D5", "\u24BB", "\u20A3", "\u1E1F", "\u1E1E", "\u13A6", "\u0493", "\u0284", "\uFF46", "\uFF26", "\u025F", "\u{1F155}", "\u{1D41F}", "\u{1D405}", "\u{1D627}", "\u{1D60D}", "\u{1D65B}", "\u{1D641}", "\u{1D4BB}", "\u{1D4EF}", "\u{1D4D5}", "\u{1D557}", "\u{1D53C}", "\u{1D523}", "\u{1D508}", "\u{1D58B}", "\u{1D571}", "\u{1F135}", "\u{1F175}", "\u{1D439}", "\u03DD", "\u{1D68F}", "\u{1D675}", "\u03DC", "f"],
|
|
g: ["g", "q", "6", "9", "G", "\u24D6", "\u24BC", "\u034F", "\u20B2", "\u0121", "\u0120", "\u13B6", "\u03D1", "\u1E20", "\u0262", "\u033E", "\uFF47", "\uFF27", "\u0183", "\u{1F156}", "\u{1D420}", "\u{1D406}", "\u{1D628}", "\u{1D60E}", "\u{1D65C}", "\u{1D642}", "\u210A", "\u{1D4F0}", "\u{1D4D6}", "\u{1D558}", "\u{1D53D}", "\u{1D524}", "\u{1D509}", "\u{1D58C}", "\u{1D572}", "\u{1F136}", "\u{1F176}", "\u{1D454}", "\u{1D4A2}", "\u0260", "\u{1D690}", "\u{1D676}", "\u2761", "\u0581", "\u{1D676}", "\u{1D4F0}"],
|
|
h: [
|
|
"h",
|
|
"\u157C",
|
|
"H",
|
|
"\u24D7",
|
|
"\u24BD",
|
|
"\u043D",
|
|
"\u2C67",
|
|
"\u1E27",
|
|
"\u1E26",
|
|
"\u13C2",
|
|
"\u0266",
|
|
"\uFF48",
|
|
"\uFF28",
|
|
"\u029C",
|
|
"\u0265",
|
|
"\u{1F157}",
|
|
"\u{1D421}",
|
|
"\u{1D407}",
|
|
"\u{1D629}",
|
|
"\u{1D60F}",
|
|
"\u{1D65D}",
|
|
"\u{1D643}",
|
|
"\u{1D4BD}",
|
|
"\u{1D4F1}",
|
|
"\u{1D4D7}",
|
|
"\u{1D559}",
|
|
"\u{1D53E}",
|
|
"\u{1D525}",
|
|
"\u{1D50A}",
|
|
"\u{1D58D}",
|
|
"\u{1D573}",
|
|
"\u{1F137}",
|
|
"\u{1F177}",
|
|
"\u{1D43B}",
|
|
"\u050B",
|
|
"\u{1D691}",
|
|
"\u{1D677}",
|
|
"\u2644",
|
|
"h"
|
|
],
|
|
i: ["i", "!", "l", "1", "\xED", "I", "\u24D8", "\u24BE", "\u03B9", "\u034F", "\u0142", "\xEF", "\xCF", "\u13A5", "\u1E2D", "\u1E2C", "\u0268", "\u033E", "\uFF49", "\uFF29", "\u026A", "\u0131", "\u{1F158}", "\u{1D422}", "\u{1D408}", "\u{1D62A}", "\u{1D610}", "\u{1D65E}", "\u{1D644}", "\u{1D4BE}", "\u{1D4F2}", "\u{1D4D8}", "\u{1D55A}", "\u210D", "\u{1D526}", "\u210C", "\u{1D58E}", "\u{1D574}", "\u{1F138}", "\u{1F178}", "\u{1D43C}", "\u{1D692}", "\u{1D678}", "\u2657", "\u0456", "\xA1", "|", "\u{1D4F2}"],
|
|
j: ["j", "\u148D", "J", "\u24D9", "\u24BF", "\u05E0", "\u13E0", "\u03F3", "\u029D", "\uFF4A", "\uFF2A", "\u1D0A", "\u027E", "\u{1F159}", "\u{1D423}", "\u{1D409}", "\u{1D62B}", "\u{1D611}", "\u{1D65F}", "\u{1D645}", "\u{1D4BF}", "\u{1D4F3}", "\u{1D4D9}", "\u{1D55B}", "\u200B", "\u{1D527}", "\u{1D58F}", "\u{1D575}", "\u{1F139}", "\u{1F179}", "\u{1D4A5}", "\u{1D693}", "\u{1D679}", "\u266A", "\u0458"],
|
|
k: ["k", "K", "\u24DA", "\u24C0", "\u043A", "\u034F", "\u20AD", "\u1E33", "\u1E32", "\u13E6", "\u03BA", "\u0198", "\u04C4", "\u033E", "\uFF4B", "\uFF2B", "\u1D0B", "\u029E", "\u{1F15A}", "\u{1D424}", "\u{1D40A}", "\u{1D62C}", "\u{1D612}", "\u{1D660}", "\u{1D646}", "\u{1D4C0}", "\u{1D4F4}", "\u{1D4DA}", "\u{1D55C}", "\u{1D540}", "\u{1D528}", "\u2111", "\u{1D590}", "\u{1D576}", "\u{1F13A}", "\u{1F17A}", "\u{1D4A6}", "\u0199", "\u{1D694}", "\u{1D67A}", "\u03F0", "k", "\u{1D4F4}"],
|
|
l: ["l", "i", "1", "/", "|", "\u14AA", "L", "\u24DB", "\u24C1", "\u2113", "\u2C60", "\u0140", "\u013F", "\u13DD", "\u1E36", "\u13DE", "\u029F", "\uFF4C", "\uFF2C", "\u{1F15B}", "\u{1D425}", "\u{1D40B}", "\u{1D62D}", "\u{1D613}", "\u{1D661}", "\u{1D647}", "\u{1D4C1}", "\u{1D4F5}", "\u{1D4DB}", "\u{1D55D}", "\u{1D541}", "\u{1D529}", "\u200B", "\u{1D591}", "\u{1D577}", "\u{1F13B}", "\u{1F17B}", "\u{1D43F}", "\u0285", "\u{1D695}", "\u{1D67B}", "\u21B3", "\u217C"],
|
|
m: [
|
|
"m",
|
|
"\u15F0",
|
|
"M",
|
|
"\u24DC",
|
|
"\u24C2",
|
|
"\u043C",
|
|
"\u034F",
|
|
"\u20A5",
|
|
"\u1E43",
|
|
"\u1E42",
|
|
"\u13B7",
|
|
"\u03FB",
|
|
"\u039C",
|
|
"\u1E41",
|
|
"\u1E40",
|
|
"\u028D",
|
|
"\u033E",
|
|
"\uFF4D",
|
|
"\uFF2D",
|
|
"\u1D0D",
|
|
"\u026F",
|
|
"\u{1F15C}",
|
|
"\u{1D426}",
|
|
"\u{1D40C}",
|
|
"\u{1D62E}",
|
|
"\u{1D614}",
|
|
"\u{1D662}",
|
|
"\u{1D648}",
|
|
"\u{1D4C2}",
|
|
"\u{1D4F6}",
|
|
"\u{1D4DC}",
|
|
"\u{1D55E}",
|
|
"\u{1D542}",
|
|
"\u{1D52A}",
|
|
"\u{1D50D}",
|
|
"\u{1D592}",
|
|
"\u{1D578}",
|
|
"\u{1F13C}",
|
|
"\u{1F17C}",
|
|
"\u{1D440}",
|
|
"\u0271",
|
|
"\u{1D696}",
|
|
"\u{1D67C}",
|
|
"\u2654",
|
|
"\u217F"
|
|
],
|
|
n: ["n", "\xF1", "\u144E", "N", "\u24DD", "\u24C3", "\u0438", "\u20A6", "\u0144", "\u0143", "\u13C1", "\u03C0", "\u220F", "\u1E46", "\u057C", "\uFF4E", "\uFF2E", "\u0274", "\u{1F15D}", "\u{1D427}", "\u{1D40D}", "\u{1D62F}", "\u{1D615}", "\u{1D663}", "\u{1D649}", "\u{1D4C3}", "\u{1D4F7}", "\u{1D4DD}", "\u{1D55F}", "\u{1D543}", "\u{1D52B}", "\u{1D50E}", "\u{1D593}", "\u{1D579}", "\u{1F13D}", "\u{1F17D}", "\u{1D4A9}", "\u0273", "\u{1D697}", "\u{1D67D}", "\u266B", "\u0578", "\u03B7", "\u{1D67D}", "\u019E", "\u{1D4F7}"],
|
|
o: ["o", "0", "\xF3", "\xF4", "\xF5", "\xFA", "O", "\u24DE", "\u24C4", "\u03C3", "\u034F", "\xD8", "\xF6", "\xD6", "\u13A7", "\u0398", "\u1E4F", "\u1E4E", "\u13BE", "\u0585", "\u033E", "\uFF4F", "\uFF2F", "\u1D0F", "\u{1F15E}", "\u{1D428}", "\u{1D40E}", "\u{1D630}", "\u{1D616}", "\u{1D664}", "\u{1D64A}", "\u2134", "\u{1D4F8}", "\u{1D4DE}", "\u{1D560}", "\u{1D544}", "\u{1D52C}", "\u{1D50F}", "\u{1D594}", "\u{1D57A}", "\u{1F13E}", "\u{1F17E}", "\u{1D45C}", "\u{1D4AA}", "\u{1D698}", "\u{1D67E}", "\u2299", "\u03BF"],
|
|
p: ["p", "\u146D", "P", "\u24DF", "\u24C5", "\u03C1", "\u20B1", "\u1E57", "\u1E56", "\u13AE", "\u01A4", "\u13E2", "\u0584", "\uFF50", "\uFF30", "\u1D18", "\u{1F15F}", "\u{1D429}", "\u{1D40F}", "\u{1D631}", "\u{1D617}", "\u{1D665}", "\u{1D64B}", "\u{1D4C5}", "\u{1D4F9}", "\u{1D4DF}", "\u{1D561}", "\u2115", "\u{1D52D}", "\u{1D510}", "\u{1D595}", "\u{1D57B}", "\u{1F13F}", "\u{1F17F}", "\u{1D4AB}", "\u{1D699}", "\u{1D67F}", "\u0440"],
|
|
q: [
|
|
"q",
|
|
"\u146B",
|
|
"Q",
|
|
"\u24E0",
|
|
"\u24C6",
|
|
"\u034F",
|
|
"\u13A4",
|
|
"\u03C6",
|
|
"\u10B3",
|
|
"\u0566",
|
|
"\u033E",
|
|
"\uFF51",
|
|
"\uFF31",
|
|
"\u03D9",
|
|
"\u01EB",
|
|
"\u{1F160}",
|
|
"\u{1D42A}",
|
|
"\u{1D410}",
|
|
"\u{1D632}",
|
|
"\u{1D618}",
|
|
"\u{1D666}",
|
|
"\u{1D64C}",
|
|
"\u{1D4C6}",
|
|
"\u{1D4FA}",
|
|
"\u{1D4E0}",
|
|
"\u{1D562}",
|
|
"\u200B",
|
|
"\u{1D52E}",
|
|
"\u{1D511}",
|
|
"\u{1D596}",
|
|
"\u{1D57C}",
|
|
"\u{1F140}",
|
|
"\u{1F180}",
|
|
"\u{1D4AC}",
|
|
"\u{1D69A}",
|
|
"\u{1D680}",
|
|
"\u262D",
|
|
"\u051B"
|
|
],
|
|
r: ["r", "\u1587", "R", "\u24E1", "\u24C7", "\u044F", "\u2C64", "\u0155", "\u0154", "\u13D2", "\u0433", "\u0393", "\u1E59", "\u1E58", "\u0280", "\uFF52", "\uFF32", "\u0279", "\u{1F161}", "\u{1D42B}", "\u{1D411}", "\u{1D633}", "\u{1D619}", "\u{1D667}", "\u{1D64D}", "\u{1D4C7}", "\u{1D4FB}", "\u{1D4E1}", "\u{1D563}", "\u{1D546}", "\u{1D52F}", "\u{1D512}", "\u{1D597}", "\u{1D57D}", "\u{1F141}", "\u{1F181}", "\u{1D445}", "\u027E", "\u{1D69B}", "\u{1D681}", "\u2608", "r", "\u{1D681}", "\u{1D4FB}"],
|
|
s: ["s", "5", "\u1515", "S", "\u24E2", "\u24C8", "\u0455", "\u034F", "\u20B4", "\u1E69", "\u1E68", "\u13D5", "\u0405", "\u1E60", "\u0586", "\u033E", "\uFF53", "\uFF33", "\uA731", "\u{1F162}", "\u{1D42C}", "\u{1D412}", "\u{1D634}", "\u{1D61A}", "\u{1D668}", "\u{1D64E}", "\u{1D4C8}", "\u{1D4FC}", "\u{1D4E2}", "\u{1D564}", "\u2119", "\u{1D530}", "\u{1D513}", "\u{1D598}", "\u{1D57E}", "\u{1F142}", "\u{1F182}", "\u{1D4AE}", "\u0282", "\u{1D69C}", "\u{1D682}", "\u0455", "\u{1D4FC}"],
|
|
t: ["t", "+", "T", "\u24E3", "\u24C9", "\u0442", "\u20AE", "\u1E97", "\u1E6E", "\u13D6", "\u03C4", "\u01AC", "\u13C6", "\u0236", "\uFF54", "\uFF34", "\u1D1B", "\u0287", "\u{1F163}", "\u{1D42D}", "\u{1D413}", "\u{1D635}", "\u{1D61B}", "\u{1D669}", "\u{1D64F}", "\u{1D4C9}", "\u{1D4FD}", "\u{1D4E3}", "\u{1D565}", "\u200B", "\u{1D531}", "\u{1D514}", "\u{1D599}", "\u{1D57F}", "\u{1F143}", "\u{1F183}", "\u{1D4AF}", "\u019A", "\u{1D69D}", "\u{1D683}", "\u2602", "t", "\u{1D4FD}"],
|
|
u: ["u", "\xFA", "\xFC", "\u144C", "U", "\u24E4", "\u24CA", "\u03C5", "\u034F", "\u0244", "\xDC", "\u13EC", "\u01B1", "\u1E73", "\u1E72", "\u028A", "\u033E", "\uFF55", "\uFF35", "\u1D1C", "\u{1F164}", "\u{1D42E}", "\u{1D414}", "\u{1D636}", "\u{1D61C}", "\u{1D66A}", "\u{1D650}", "\u{1D4CA}", "\u{1D4FE}", "\u{1D4E4}", "\u{1D566}", "\u211A", "\u{1D532}", "\u211C", "\u{1D59A}", "\u{1D580}", "\u{1F144}", "\u{1F184}", "\u{1D4B0}", "\u{1D69E}", "\u{1D684}", "\u260B", "\u057D"],
|
|
v: ["v", "\u142F", "V", "\u24E5", "\u24CB", "\u03BD", "\u1E7F", "\u1E7E", "\u13C9", "\u01B2", "\u1E7C", "\u028B", "\uFF56", "\uFF36", "\u1D20", "\u028C", "\u{1F165}", "\u{1D42F}", "\u{1D415}", "\u{1D637}", "\u{1D61D}", "\u{1D66B}", "\u{1D651}", "\u{1D4CB}", "\u{1D4FF}", "\u{1D4E5}", "\u{1D567}", "\u200B", "\u{1D533}", "\u{1D59B}", "\u{1D581}", "\u{1F145}", "\u{1F185}", "\u{1D4B1}", "\u{1D69F}", "\u{1D685}", "\u2713", "\u2174"],
|
|
w: ["w", "\u15EF", "W", "\u24E6", "\u24CC", "\u03C9", "\u034F", "\u20A9", "\u1E85", "\u1E84", "\u13C7", "\u0448", "\u0428", "\u1E87", "\u1E86", "\u13B3", "\u0561", "\u033E", "\uFF57", "\uFF37", "\u1D21", "\u028D", "\u{1F166}", "\u{1D430}", "\u{1D416}", "\u{1D638}", "\u{1D61E}", "\u{1D66C}", "\u{1D652}", "\u{1D4CC}", "\u{1D500}", "\u{1D4E6}", "\u{1D568}", "\u211D", "\u{1D534}", "\u{1D516}", "\u{1D59C}", "\u{1D582}", "\u{1F146}", "\u{1F186}", "\u{1D4B2}", "\u026F", "\u{1D6A0}", "\u{1D686}", "\u051D"],
|
|
x: ["x", "\u166D", "X", "\u24E7", "\u24CD", "\u03C7", "\u04FE", "\u1E8D", "\u1E8C", "\u1300", "\u03F0", "\u0416", "\u0445", "\u04FC", "\uFF58", "\uFF38", "\u{1F167}", "\u{1D431}", "\u{1D417}", "\u{1D639}", "\u{1D61F}", "\u{1D66D}", "\u{1D653}", "\u{1D4CD}", "\u{1D501}", "\u{1D4E7}", "\u{1D569}", "\u200B", "\u{1D535}", "\u{1D517}", "\u{1D59D}", "\u{1D583}", "\u{1F147}", "\u{1F187}", "\u{1D4B3}", "\u{1D6A1}", "\u{1D687}", "\u2318", "\u0445"],
|
|
y: [
|
|
"y",
|
|
"Y",
|
|
"\u24E8",
|
|
"\u24CE",
|
|
"\u0443",
|
|
"\u034F",
|
|
"\u024E",
|
|
"\xFF",
|
|
"\u0178",
|
|
"\u13A9",
|
|
"\u03C8",
|
|
"\u03A8",
|
|
"\u1E8F",
|
|
"\u1E8E",
|
|
"\u13BD",
|
|
"\u0447",
|
|
"\u028F",
|
|
"\u033E",
|
|
"\uFF59",
|
|
"\uFF39",
|
|
"\u028E",
|
|
"\u{1F168}",
|
|
"\u{1D432}",
|
|
"\u{1D418}",
|
|
"\u{1D63A}",
|
|
"\u{1D620}",
|
|
"\u{1D66E}",
|
|
"\u{1D654}",
|
|
"\u{1D4CE}",
|
|
"\u{1D502}",
|
|
"\u{1D4E8}",
|
|
"\u{1D56A}",
|
|
"\u{1D54A}",
|
|
"\u{1D536}",
|
|
"\u{1D518}",
|
|
"\u{1D59E}",
|
|
"\u{1D584}",
|
|
"\u{1F148}",
|
|
"\u{1F188}",
|
|
"\u{1D4B4}",
|
|
"\u10E7",
|
|
"\u{1D6A2}",
|
|
"\u{1D688}",
|
|
"\u263F",
|
|
"\u0443"
|
|
],
|
|
z: ["z", "\u1614", "Z", "\u24E9", "\u24CF", "\u2C6B", "\u1E93", "\u1E92", "\u135A", "\u13C3", "\u0290", "\uFF5A", "\uFF3A", "\u1D22", "\u{1F169}", "\u{1D433}", "\u{1D419}", "\u{1D63B}", "\u{1D621}", "\u{1D66F}", "\u{1D655}", "\u{1D4CF}", "\u{1D503}", "\u{1D4E9}", "\u{1D56B}", "\u{1D54B}", "\u{1D537}", "\u{1D519}", "\u{1D59F}", "\u{1D585}", "\u{1F149}", "\u{1F189}", "\u{1D4B5}", "\u0225", "\u{1D6A3}", "\u{1D689}", "\u2621", "z", "\u{1D503}"]
|
|
};
|
|
const filterWords = Chat.filterWords;
|
|
const Filters = new class {
|
|
constructor() {
|
|
this.EVASION_DETECTION_SUB_STRINGS = {};
|
|
for (const letter in EVASION_DETECTION_SUBSTITUTIONS) {
|
|
this.EVASION_DETECTION_SUB_STRINGS[letter] = `[${EVASION_DETECTION_SUBSTITUTIONS[letter].join("")}]`;
|
|
}
|
|
this.load();
|
|
}
|
|
constructEvasionRegex(str) {
|
|
const buf = "\\b" + [...str].map((letter) => (this.EVASION_DETECTION_SUB_STRINGS[letter] || letter) + "+").join("\\.?") + "\\b";
|
|
return new RegExp(buf, "iu");
|
|
}
|
|
generateRegex(word, isEvasion = false, isShortener = false, isReplacement = false) {
|
|
try {
|
|
if (isEvasion) {
|
|
return this.constructEvasionRegex(word);
|
|
} else {
|
|
return new RegExp(isShortener ? `\\b${word}` : word, isReplacement ? "igu" : "iu");
|
|
}
|
|
} catch (e) {
|
|
throw new Chat.ErrorMessage(
|
|
e.message.startsWith("Invalid regular expression: ") ? e.message : `Invalid regular expression: /${word}/: ${e.message}`
|
|
);
|
|
}
|
|
}
|
|
stripWordBoundaries(regex) {
|
|
return new RegExp(regex.toString().replace("/\\b", "").replace("\\b/iu", ""), "iu");
|
|
}
|
|
save(force = false) {
|
|
(0, import_lib.FS)(MONITOR_FILE).writeUpdate(() => {
|
|
const buf = {};
|
|
for (const key in Chat.monitors) {
|
|
buf[key] = [];
|
|
for (const filterWord of filterWords[key]) {
|
|
const word = { ...filterWord };
|
|
delete word.regex;
|
|
buf[key].push(word);
|
|
}
|
|
}
|
|
return JSON.stringify(buf);
|
|
}, { throttle: force ? 0 : WRITE_THROTTLE_TIME });
|
|
}
|
|
add(filterWord) {
|
|
if (!filterWord.hits)
|
|
filterWord.hits = 0;
|
|
const punishment = Chat.monitors[filterWord.list].punishment;
|
|
if (!filterWord.regex) {
|
|
filterWord.regex = this.generateRegex(
|
|
filterWord.word,
|
|
punishment === "EVASION",
|
|
punishment === "SHORTENER",
|
|
!!filterWord.replacement
|
|
);
|
|
}
|
|
if (filterWords[filterWord.list].some((val) => String(val.regex) === String(filterWord.regex))) {
|
|
throw new Chat.ErrorMessage(`${filterWord.word} is already added to the ${filterWord.list} list.`);
|
|
}
|
|
filterWords[filterWord.list].push(filterWord);
|
|
this.save(true);
|
|
}
|
|
load() {
|
|
const legacy = (0, import_lib.FS)(LEGACY_MONITOR_FILE);
|
|
if (legacy.existsSync()) {
|
|
return process.nextTick(() => {
|
|
this.loadLegacy();
|
|
legacy.renameSync(LEGACY_MONITOR_FILE + ".backup");
|
|
Monitor.notice(`Legacy chatfilter data loaded and renamed to a .backup file.`);
|
|
});
|
|
}
|
|
const data = JSON.parse((0, import_lib.FS)(MONITOR_FILE).readIfExistsSync() || "{}");
|
|
for (const k in data) {
|
|
filterWords[k] = [];
|
|
for (const entry of data[k]) {
|
|
if (k === "evasion") {
|
|
entry.regex = this.constructEvasionRegex(entry.word);
|
|
} else {
|
|
entry.regex = new RegExp(
|
|
k === "shorteners" ? `\\b${entry.word}` : entry.word,
|
|
entry.replacement ? "igu" : "iu"
|
|
);
|
|
}
|
|
filterWords[k].push(entry);
|
|
}
|
|
}
|
|
}
|
|
loadLegacy() {
|
|
let data;
|
|
try {
|
|
data = (0, import_lib.FS)(LEGACY_MONITOR_FILE).readSync();
|
|
} catch (e) {
|
|
if (e.code !== "ENOENT")
|
|
throw e;
|
|
}
|
|
if (!data)
|
|
return;
|
|
const lines = data.split("\n");
|
|
loop:
|
|
for (const line of lines) {
|
|
if (!line || line === "\r")
|
|
continue;
|
|
const [location, word, punishment, reason, times, ...rest] = line.split(" ").map((param) => param.trim());
|
|
if (location === "Location")
|
|
continue;
|
|
if (!(location && word && punishment))
|
|
continue;
|
|
for (const key in Chat.monitors) {
|
|
if (Chat.monitors[key].location === location && Chat.monitors[key].punishment === punishment) {
|
|
const replacement = rest[0];
|
|
const publicReason = rest[1];
|
|
let regex;
|
|
if (punishment === "EVASION") {
|
|
regex = Filters.constructEvasionRegex(word);
|
|
} else {
|
|
regex = new RegExp(punishment === "SHORTENER" ? `\\b${word}` : word, replacement ? "igu" : "iu");
|
|
}
|
|
const filterWord = { regex, word, hits: parseInt(times) || 0 };
|
|
if (reason && reason !== "undefined")
|
|
filterWord.reason = reason;
|
|
if (publicReason)
|
|
filterWord.publicReason = publicReason;
|
|
if (replacement)
|
|
filterWord.replacement = replacement;
|
|
filterWords[key].push(filterWord);
|
|
continue loop;
|
|
}
|
|
}
|
|
Monitor.crashlog(new Error("Couldn't find [location, punishment] pair for a filter word"), "The main process", {
|
|
location,
|
|
word,
|
|
punishment,
|
|
reason,
|
|
times,
|
|
rest
|
|
});
|
|
}
|
|
}
|
|
}();
|
|
Chat.registerMonitor("autolock", {
|
|
location: "EVERYWHERE",
|
|
punishment: "AUTOLOCK",
|
|
label: "Autolock",
|
|
monitor(line, room, user, message, lcMessage, isStaff) {
|
|
const { regex, word, reason, publicReason } = line;
|
|
const match = regex.exec(lcMessage);
|
|
if (match) {
|
|
if (isStaff)
|
|
return `${message} __[would be locked: ${word}${reason ? ` (${reason})` : ""}]__`;
|
|
message = message.replace(/(https?):\/\//g, "$1__:__//");
|
|
message = message.replace(/\./g, "__.__");
|
|
if (room) {
|
|
void Punishments.autolock(
|
|
user,
|
|
room,
|
|
"ChatMonitor",
|
|
`Filtered phrase: ${word}`,
|
|
`<<${room.roomid}>> ${user.name}: ||\`\`${message}\`\`${reason ? ` __(${reason})__` : ""}||`,
|
|
true
|
|
);
|
|
} else {
|
|
this.errorReply(`Please do not say '${match[0]}'${publicReason ? ` ${publicReason}` : ``}.`);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
});
|
|
Chat.registerMonitor("publicwarn", {
|
|
location: "PUBLIC",
|
|
punishment: "WARN",
|
|
label: "Filtered in public",
|
|
monitor(line, room, user, message, lcMessage, isStaff) {
|
|
const { regex, word, reason, publicReason } = line;
|
|
const match = regex.exec(lcMessage);
|
|
if (match) {
|
|
if (isStaff)
|
|
return `${message} __[would be filtered in public: ${word}${reason ? ` (${reason})` : ""}]__`;
|
|
this.errorReply(`Please do not say '${match[0]}'${publicReason ? ` ${publicReason}` : ``}.`);
|
|
return false;
|
|
}
|
|
}
|
|
});
|
|
Chat.registerMonitor("warn", {
|
|
location: "EVERYWHERE",
|
|
punishment: "WARN",
|
|
label: "Filtered",
|
|
monitor(line, room, user, message, lcMessage, isStaff) {
|
|
const { regex, word, reason, publicReason } = line;
|
|
const match = regex.exec(lcMessage);
|
|
if (match) {
|
|
if (isStaff)
|
|
return `${message} __[would be filtered: ${word}${reason ? ` (${reason})` : ""}]__`;
|
|
this.errorReply(`Please do not say '${match[0]}'${publicReason ? ` ${publicReason}` : ``}.`);
|
|
return false;
|
|
}
|
|
}
|
|
});
|
|
Chat.registerMonitor("evasion", {
|
|
location: "EVERYWHERE",
|
|
punishment: "EVASION",
|
|
label: "Filter Evasion Detection",
|
|
monitor(line, room, user, message, lcMessage, isStaff) {
|
|
const { regex, word, reason, publicReason } = line;
|
|
let normalizedMessage = lcMessage.normalize("NFKC");
|
|
normalizedMessage = normalizedMessage.replace(/[\s-_,.]+/g, ".");
|
|
const match = regex.exec(normalizedMessage);
|
|
if (match) {
|
|
if (match[0] === word && regex.test(message)) {
|
|
if (isStaff)
|
|
return `${message} __[would be filtered: ${word}${reason ? ` (${reason})` : ""}]__`;
|
|
this.errorReply(`Do not say '${word}'.`);
|
|
return false;
|
|
}
|
|
if (isStaff)
|
|
return `${message} __[would be locked for filter evading: ${match[0]} (${word})]__`;
|
|
message = message.replace(/(https?):\/\//g, "$1__:__//");
|
|
if (room) {
|
|
void Punishments.autolock(
|
|
user,
|
|
room,
|
|
"FilterEvasionMonitor",
|
|
`Evading filter: ${message} (${match[0]} => ${word})`,
|
|
`<<${room.roomid}>> ${user.name}: ||\`\`${message}\`\` __(${match[0]} => ${word})__||`,
|
|
true
|
|
);
|
|
} else {
|
|
this.errorReply(`Please do not say '${word}'${publicReason ? ` ${publicReason}` : ``}.`);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
});
|
|
Chat.registerMonitor("wordfilter", {
|
|
location: "EVERYWHERE",
|
|
punishment: "FILTERTO",
|
|
label: "Filtered to a different phrase",
|
|
condition: "notStaff",
|
|
monitor(line, room, user, message, lcMessage, isStaff) {
|
|
const { regex, replacement } = line;
|
|
let match = regex.exec(message);
|
|
while (match) {
|
|
let filtered = replacement || "";
|
|
if (match[0] === match[0].toUpperCase())
|
|
filtered = filtered.toUpperCase();
|
|
if (match[0].startsWith(match[0].charAt(0).toUpperCase())) {
|
|
filtered = `${filtered ? filtered.charAt(0).toUpperCase() : ""}${filtered.slice(1)}`;
|
|
}
|
|
message = message.replace(match[0], filtered);
|
|
match = regex.exec(message);
|
|
}
|
|
return message;
|
|
}
|
|
});
|
|
Chat.registerMonitor("namefilter", {
|
|
location: "NAMES",
|
|
punishment: "WARN",
|
|
label: "Filtered in names"
|
|
});
|
|
Chat.registerMonitor("battlefilter", {
|
|
location: "BATTLES",
|
|
punishment: "MUTE",
|
|
label: "Filtered in battles",
|
|
monitor(line, room, user, message, lcMessage, isStaff) {
|
|
const { regex, word, reason, publicReason } = line;
|
|
const match = regex.exec(lcMessage);
|
|
if (match) {
|
|
if (isStaff)
|
|
return `${message} __[would be filtered: ${word}${reason ? ` (${reason})` : ""}]__`;
|
|
message = message.replace(/(https?):\/\//g, "$1__:__//");
|
|
message = message.replace(/\./g, "__.__");
|
|
if (room) {
|
|
room.mute(user);
|
|
this.errorReply(
|
|
`You have been muted for using a banned phrase. Please do not say '${match[0]}'${publicReason ? ` ${publicReason}` : ``}.`
|
|
);
|
|
const text = `[BattleMonitor] <<${room.roomid}>> MUTED: ${user.name}: ${message}${reason ? ` __(${reason})__` : ""}`;
|
|
const adminlog = Rooms.get("adminlog");
|
|
if (adminlog) {
|
|
adminlog.add(`|c|~|${text}`).update();
|
|
} else {
|
|
Monitor.log(text);
|
|
}
|
|
void room.uploadReplay(user, this.connection, "forpunishment");
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
});
|
|
Chat.registerMonitor("shorteners", {
|
|
location: "EVERYWHERE",
|
|
punishment: "SHORTENER",
|
|
label: "URL Shorteners",
|
|
condition: "notTrusted",
|
|
monitor(line, room, user, message, lcMessage, isStaff) {
|
|
const { regex, word, publicReason } = line;
|
|
if (regex.test(lcMessage)) {
|
|
if (isStaff)
|
|
return `${message} __[shortener: ${word}]__`;
|
|
this.errorReply(`Please do not use URL shorteners such as '${word}'${publicReason ? ` ${publicReason}` : ``}.`);
|
|
return false;
|
|
}
|
|
}
|
|
});
|
|
const chatfilter = function(message, user, room) {
|
|
let lcMessage = message.replace(/\u039d/g, "N").toLowerCase().replace(/[\u200b\u007F\u00AD\uDB40\uDC00\uDC21]/g, "").replace(/\u03bf/g, "o").replace(/\u043e/g, "o").replace(/\u0430/g, "a").replace(/\u0435/g, "e").replace(/\u039d/g, "e");
|
|
lcMessage = lcMessage.replace(/__|\*\*|``|\[\[|\]\]/g, "");
|
|
const isStaffRoom = room && (room.persist && room.roomid.endsWith("staff") || room.roomid.startsWith("help-"));
|
|
const isStaff = isStaffRoom || user.isStaff || !!(this.pmTarget && this.pmTarget.isStaff);
|
|
for (const list in Chat.monitors) {
|
|
const { location, condition, monitor } = Chat.monitors[list];
|
|
if (!monitor)
|
|
continue;
|
|
if (location === "BATTLES" && !(room && room.battle && room.battle.challengeType !== "challenge"))
|
|
continue;
|
|
if (location === "PUBLIC" && room && room.settings.isPrivate === true)
|
|
continue;
|
|
switch (condition) {
|
|
case "notTrusted":
|
|
if (user.trusted && !isStaffRoom)
|
|
continue;
|
|
break;
|
|
case "notStaff":
|
|
if (isStaffRoom)
|
|
continue;
|
|
break;
|
|
}
|
|
for (const line of Chat.filterWords[list]) {
|
|
const ret = monitor.call(this, line, room, user, message, lcMessage, isStaff);
|
|
if (ret !== void 0 && ret !== message) {
|
|
line.hits++;
|
|
Filters.save();
|
|
}
|
|
if (typeof ret === "string") {
|
|
message = ret;
|
|
} else if (ret === false) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return message;
|
|
};
|
|
const namefilter = (name, user) => {
|
|
const id = toID(name);
|
|
if (Punishments.namefilterwhitelist.has(id))
|
|
return name;
|
|
if (Monitor.forceRenames.has(id)) {
|
|
if (typeof Monitor.forceRenames.get(id) === "number") {
|
|
Monitor.forceRenames.set(id, false);
|
|
}
|
|
if (!Monitor.forceRenames.get(id)) {
|
|
user.trackRename = id;
|
|
Monitor.forceRenames.set(id, true);
|
|
}
|
|
return "";
|
|
}
|
|
if (id === toID(user.trackRename))
|
|
return "";
|
|
let lcName = name.replace(/\u039d/g, "N").toLowerCase().replace(/[\u200b\u007F\u00AD]/g, "").replace(/\u03bf/g, "o").replace(/\u043e/g, "o").replace(/\u0430/g, "a").replace(/\u0435/g, "e").replace(/\u039d/g, "e");
|
|
lcName = lcName.replace("herapist", "").replace("grape", "").replace("scrape", "");
|
|
for (const list in filterWords) {
|
|
if (!Chat.monitors[list] || Chat.monitors[list].location === "BATTLES")
|
|
continue;
|
|
const punishment = Chat.monitors[list].punishment;
|
|
for (const line of filterWords[list]) {
|
|
const regex = punishment === "EVASION" ? Filters.stripWordBoundaries(line.regex) : line.regex;
|
|
if (regex.test(lcName)) {
|
|
if (Chat.monitors[list].punishment === "AUTOLOCK") {
|
|
void Punishments.autolock(
|
|
user,
|
|
"staff",
|
|
`NameMonitor`,
|
|
`inappropriate name: ${name}`,
|
|
`using an inappropriate name: ||${name} (from ${user.name})||`,
|
|
false,
|
|
name
|
|
);
|
|
}
|
|
line.hits++;
|
|
Filters.save();
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
return name;
|
|
};
|
|
const loginfilter = (user) => {
|
|
if (user.namelocked)
|
|
return;
|
|
if (user.trackRename) {
|
|
const manualForceRename = Monitor.forceRenames.has(toID(user.trackRename));
|
|
Rooms.global.notifyRooms(
|
|
["staff"],
|
|
import_lib.Utils.html`|html|[NameMonitor] Username used: <span class="username">${user.name}</span> ${user.getAccountStatusString()} (${!manualForceRename ? "automatically " : ""}forcerenamed from <span class="username">${user.trackRename}</span>)`
|
|
);
|
|
user.trackRename = "";
|
|
}
|
|
const offlineWarn = Punishments.offlineWarns.get(user.id);
|
|
if (typeof offlineWarn !== "undefined") {
|
|
user.send(`|c|~|/warn You were warned while offline${offlineWarn.length ? `: ${offlineWarn}` : "."}`);
|
|
Punishments.offlineWarns.delete(user.id);
|
|
}
|
|
};
|
|
const nicknamefilter = (name, user) => {
|
|
let lcName = name.replace(/\u039d/g, "N").toLowerCase().replace(/[\u200b\u007F\u00AD]/g, "").replace(/\u03bf/g, "o").replace(/\u043e/g, "o").replace(/\u0430/g, "a").replace(/\u0435/g, "e").replace(/\u039d/g, "e");
|
|
lcName = lcName.replace("herapist", "").replace("grape", "").replace("scrape", "");
|
|
for (const list in filterWords) {
|
|
if (!Chat.monitors[list])
|
|
continue;
|
|
if (Chat.monitors[list].location === "BATTLES")
|
|
continue;
|
|
for (const line of filterWords[list]) {
|
|
let { regex, word } = line;
|
|
if (Chat.monitors[list].punishment === "EVASION") {
|
|
regex = Filters.stripWordBoundaries(regex);
|
|
}
|
|
const match = regex.exec(lcName);
|
|
if (match) {
|
|
if (Chat.monitors[list].punishment === "AUTOLOCK") {
|
|
void Punishments.autolock(
|
|
user,
|
|
"staff",
|
|
`NameMonitor`,
|
|
`inappropriate Pok\xE9mon nickname: ${name}`,
|
|
`${user.name} - using an inappropriate Pok\xE9mon nickname: ||${name}||`,
|
|
true
|
|
);
|
|
} else if (Chat.monitors[list].punishment === "EVASION" && match[0] !== lcName) {
|
|
void Punishments.autolock(
|
|
user,
|
|
"staff",
|
|
"FilterEvasionMonitor",
|
|
`Evading filter in Pok\xE9mon nickname (${name} => ${word})`,
|
|
`${user.name}: Pok\xE9mon nicknamed ||\`\`${name} => ${word}\`\`||`,
|
|
true
|
|
);
|
|
}
|
|
line.hits++;
|
|
Filters.save();
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
return name;
|
|
};
|
|
const statusfilter = (status, user) => {
|
|
let lcStatus = status.replace(/\u039d/g, "N").toLowerCase().replace(/[\u200b\u007F\u00AD]/g, "").replace(/\u03bf/g, "o").replace(/\u043e/g, "o").replace(/\u0430/g, "a").replace(/\u0435/g, "e").replace(/\u039d/g, "e");
|
|
lcStatus = lcStatus.replace("herapist", "").replace("grape", "").replace("scrape", "");
|
|
const impersonationRegex = /\b(?:global|room|upper|senior)?\s*(?:staff|admin|administrator|leader|owner|founder|mod|moderator|driver|voice|operator|sysop|creator)\b/gi;
|
|
if (!user.can("lock") && impersonationRegex.test(lcStatus))
|
|
return "";
|
|
for (const list in filterWords) {
|
|
if (!Chat.monitors[list])
|
|
continue;
|
|
const punishment = Chat.monitors[list].punishment;
|
|
for (const line of filterWords[list]) {
|
|
const regex = punishment === "EVASION" ? Filters.stripWordBoundaries(line.regex) : line.regex;
|
|
if (regex.test(lcStatus)) {
|
|
if (punishment === "AUTOLOCK") {
|
|
void Punishments.autolock(
|
|
user,
|
|
"staff",
|
|
`NameMonitor`,
|
|
`inappropriate status message: ${status}`,
|
|
`${user.name} - using an inappropriate status: ||${status}||`,
|
|
true
|
|
);
|
|
}
|
|
line.hits++;
|
|
Filters.save();
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
return status;
|
|
};
|
|
const pages = {
|
|
filters(query, user, connection) {
|
|
if (!user.named)
|
|
return Rooms.RETRY_AFTER_LOGIN;
|
|
this.title = "Filters";
|
|
let buf = `<div class="pad ladder"><h2>Filters</h2>`;
|
|
if (!user.can("addhtml"))
|
|
this.checkCan("lock");
|
|
let content = ``;
|
|
for (const key in Chat.monitors) {
|
|
content += `<tr><th colspan="2"><h3>${Chat.monitors[key].label} <span style="font-size:8pt;">[${key}]</span></h3></tr></th>`;
|
|
if (filterWords[key].length) {
|
|
content += filterWords[key].map(({ regex, word, reason, publicReason, replacement, hits }) => {
|
|
let entry = import_lib.Utils.html`<abbr title="${reason}"><code>${word}</code></abbr>`;
|
|
if (publicReason)
|
|
entry += import_lib.Utils.html` <small>(public reason: ${publicReason})</small>`;
|
|
if (replacement)
|
|
entry += import_lib.Utils.html` ⇒ ${replacement}`;
|
|
return `<tr><td>${entry}</td><td>${hits}</td></tr>`;
|
|
}).join("");
|
|
}
|
|
}
|
|
if (Punishments.namefilterwhitelist.size) {
|
|
content += `<tr><th colspan="2"><h3>Whitelisted names</h3></tr></th>`;
|
|
for (const [val] of Punishments.namefilterwhitelist) {
|
|
content += `<tr><td>${val}</td></tr>`;
|
|
}
|
|
}
|
|
if (!content) {
|
|
buf += `<p>There are no filtered words.</p>`;
|
|
} else {
|
|
buf += `<table>${content}</table>`;
|
|
}
|
|
buf += `</div>`;
|
|
return buf;
|
|
}
|
|
};
|
|
const commands = {
|
|
filters: "filter",
|
|
filter: {
|
|
add(target, room, user) {
|
|
this.checkCan("rangeban");
|
|
let separator = ",";
|
|
if (target.includes("\n")) {
|
|
separator = "\n";
|
|
} else if (target.includes("/")) {
|
|
separator = "/";
|
|
}
|
|
let [list, ...rest] = target.split(separator);
|
|
list = toID(list);
|
|
if (!list || !rest.length) {
|
|
return this.errorReply(`Syntax: /filter add list ${separator} word ${separator} reason [${separator} optional public reason]`);
|
|
}
|
|
if (!(list in filterWords)) {
|
|
return this.errorReply(`Invalid list: ${list}. Possible options: ${Object.keys(filterWords).join(", ")}`);
|
|
}
|
|
const filterWord = { list, word: "" };
|
|
rest = rest.map((part) => part.trim());
|
|
if (Chat.monitors[list].punishment === "FILTERTO") {
|
|
[filterWord.word, filterWord.replacement, filterWord.reason, filterWord.publicReason] = rest;
|
|
if (!filterWord.replacement) {
|
|
return this.errorReply(
|
|
`Syntax for word filters: /filter add ${list} ${separator} regex ${separator} reason [${separator} optional public reason]`
|
|
);
|
|
}
|
|
} else {
|
|
[filterWord.word, filterWord.reason, filterWord.publicReason] = rest;
|
|
}
|
|
filterWord.word = filterWord.word.trim();
|
|
if (!filterWord.word) {
|
|
return this.errorReply(`Invalid word: '${filterWord.word}'.`);
|
|
}
|
|
Filters.add(filterWord);
|
|
const reason = filterWord.reason ? ` (${filterWord.reason})` : "";
|
|
if (Chat.monitors[list].punishment === "FILTERTO") {
|
|
this.globalModlog(`ADDFILTER`, null, `'${String(filterWord.regex)} => ${filterWord.replacement}' to ${list} list${reason}`);
|
|
} else {
|
|
this.globalModlog(`ADDFILTER`, null, `'${filterWord.word}' to ${list} list${reason}`);
|
|
}
|
|
const output = `'${filterWord.word}' was added to the ${list} list.`;
|
|
Rooms.get("upperstaff")?.add(output).update();
|
|
if (room?.roomid !== "upperstaff")
|
|
this.sendReply(output);
|
|
},
|
|
remove(target, room, user) {
|
|
this.checkCan("rangeban");
|
|
let [list, ...words] = target.split(target.includes("\n") ? "\n" : ",").map((param) => param.trim());
|
|
list = toID(list);
|
|
if (!list || !words.length)
|
|
return this.errorReply("Syntax: /filter remove list, words");
|
|
if (!(list in filterWords)) {
|
|
return this.errorReply(`Invalid list: ${list}. Possible options: ${Object.keys(filterWords).join(", ")}`);
|
|
}
|
|
const notFound = words.filter((val) => !filterWords[list].filter((entry) => entry.word === val).length);
|
|
if (notFound.length) {
|
|
return this.errorReply(`${notFound.join(", ")} ${Chat.plural(notFound, "are", "is")} not on the ${list} list.`);
|
|
}
|
|
filterWords[list] = filterWords[list].filter((entry) => !words.includes(entry.word));
|
|
this.globalModlog(`REMOVEFILTER`, null, `'${words.join(", ")}' from ${list} list`);
|
|
Filters.save(true);
|
|
const output = `'${words.join(", ")}' ${Chat.plural(words, "were", "was")} removed from the ${list} list.`;
|
|
Rooms.get("upperstaff")?.add(output).update();
|
|
if (room?.roomid !== "upperstaff")
|
|
this.sendReply(output);
|
|
},
|
|
"": "view",
|
|
list: "view",
|
|
view(target, room, user) {
|
|
this.parse(`/join view-filters`);
|
|
},
|
|
help(target, room, user) {
|
|
this.parse(`/help filter`);
|
|
},
|
|
test(target, room, user) {
|
|
this.checkCan("lock");
|
|
if (room && ["staff", "upperstaff"].includes(room.roomid)) {
|
|
this.runBroadcast(true, `!filter test ${target}`);
|
|
}
|
|
const lcMessage = Chat.stripFormatting(target.replace(/\u039d/g, "N").toLowerCase().replace(/[\u200b\u007F\u00AD\uDB40\uDC00\uDC21]/g, "").replace(/\u03bf/g, "o").replace(/\u043e/g, "o").replace(/\u0430/g, "a").replace(/\u0435/g, "e").replace(/\u039d/g, "e"));
|
|
const buf = [];
|
|
for (const monitorName in Chat.monitors) {
|
|
const monitor = Chat.monitors[monitorName];
|
|
if (!monitor.monitor)
|
|
continue;
|
|
for (const line of Chat.filterWords[monitorName]) {
|
|
const ret = monitor.monitor.call(this, line, room, user, target, lcMessage, true);
|
|
if (typeof ret === "string") {
|
|
buf.push(`${monitorName}: ${ret}`);
|
|
break;
|
|
} else if (ret === false) {
|
|
buf.push(`${monitorName}: "${target}" would be blocked from being sent.`);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (buf.length) {
|
|
return this.sendReplyBox(Chat.formatText(buf.join("\n"), false, true));
|
|
} else {
|
|
throw new Chat.ErrorMessage(
|
|
`"${target}" doesn't trigger any filters. Check spelling?`
|
|
);
|
|
}
|
|
},
|
|
testhelp(target, room, user) {
|
|
this.checkCan("lock");
|
|
if (room && ["staff", "upperstaff"].includes(room.roomid))
|
|
this.runBroadcast(true);
|
|
const monitorNames = [...Object.keys(Chat.monitors).filter((x) => Chat.monitors[x].monitor)];
|
|
monitorNames.push(
|
|
...Object.keys(Chat.monitors).filter((x) => Chat.monitors[x].monitor && x.includes("filter")).map((x) => x.replace("filter", ""))
|
|
);
|
|
this.sendReplyBox(
|
|
`<code>/filter test [monitor name] [test string]</code>:<br />Tests whether or not the provided test string would trigger the respective monitor.<br />All usable commands: <code>${monitorNames.sort().map((x) => `/filter test ${x}`).join("</code>, <code>")}</code><br />Can only be broadcast in Staff and Upper Staff. Requires: % @ &`
|
|
);
|
|
}
|
|
},
|
|
filterhelp: [
|
|
`/filter add list, word, reason[, optional public reason] - Adds a word to the given filter list. Requires: &`,
|
|
`/filter remove list, words - Removes words from the given filter list. Requires: &`,
|
|
`/filter view - Opens the list of filtered words. Requires: % @ &`,
|
|
`/filter test - Do "/help filter test" for more information. Requires: % @ &`,
|
|
`You may use / instead of , in /filter add if you want to specify a reason that includes commas.`
|
|
],
|
|
allowname(target, room, user) {
|
|
this.checkCan("forcerename");
|
|
target = toID(target);
|
|
if (!target)
|
|
return this.errorReply(`Syntax: /allowname username`);
|
|
if (Punishments.namefilterwhitelist.has(target)) {
|
|
return this.errorReply(`${target} is already allowed as a username.`);
|
|
}
|
|
const msg = `${target} was allowed as a username by ${user.name}.`;
|
|
const toNotify = ["staff", "upperstaff"];
|
|
Rooms.global.notifyRooms(toNotify, `|c|${user.getIdentity()}|/log ${msg}`);
|
|
if (!room || !toNotify.includes(room.roomid)) {
|
|
this.sendReply(msg);
|
|
}
|
|
this.globalModlog(`ALLOWNAME`, target);
|
|
Monitor.forceRenames.delete(target);
|
|
}
|
|
};
|
|
process.nextTick(() => {
|
|
Chat.multiLinePattern.register("/filter (add|remove) ");
|
|
});
|
|
//# sourceMappingURL=chat-monitor.js.map
|