{ "version": 3, "sources": ["../../../../server/chat-plugins/modlog-viewer.ts"], "sourcesContent": ["/**\r\n * Modlog viewer\r\n * Pokemon Showdown - http://pokemonshowdown.com/\r\n *\r\n * Actually reading, writing, and searching modlog is handled in server/modlog/.\r\n *\r\n * @license MIT\r\n */\r\n\r\nimport {Dashycode, Utils} from '../../lib';\r\nimport {ModlogID, ModlogSearch, ModlogEntry} from '../modlog';\r\n\r\nconst MAX_QUERY_LENGTH = 2500;\r\nconst DEFAULT_RESULTS_LENGTH = 100;\r\nconst MORE_BUTTON_INCREMENTS = [200, 400, 800, 1600, 3200];\r\nconst LINES_SEPARATOR = 'lines=';\r\nconst MAX_RESULTS_LENGTH = MORE_BUTTON_INCREMENTS[MORE_BUTTON_INCREMENTS.length - 1];\r\nconst IPS_REGEX = /[([]?([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})[)\\]]?/g;\r\n\r\nconst ALIASES: {[k: string]: string} = {\r\n\t'helpticket': 'help-rooms',\r\n\t'groupchat': 'groupchat-rooms',\r\n\t'battle': 'battle-rooms',\r\n};\r\n\r\n/*********************************************************\r\n * Modlog Functions\r\n *********************************************************/\r\n\r\nfunction getMoreButton(\r\n\troomid: ModlogID, searchCmd: string,\r\n\tlines: number, maxLines: number, onlyPunishments: boolean, onlyNotes: boolean,\r\n) {\r\n\tlet newLines = 0;\r\n\tfor (const increase of MORE_BUTTON_INCREMENTS) {\r\n\t\tif (increase > lines) {\r\n\t\t\tnewLines = increase;\r\n\t\t\tbreak;\r\n\t\t}\r\n\t}\r\n\tif (!newLines || lines < maxLines) {\r\n\t\treturn ''; // don't show a button if no more pre-set increments are valid or if the amount of results is already below the max\r\n\t} else {\r\n\t\tlet cmd = `/modlog`;\r\n\t\tif (onlyNotes) cmd = `/modnotes`;\r\n\t\tif (onlyPunishments) cmd = `/punishlog`;\r\n\r\n\t\treturn Utils.html`
`;\r\n\t}\r\n}\r\n\r\nfunction getRoomID(id: string) {\r\n\tif (id in ALIASES) return ALIASES[id] as ModlogID;\r\n\treturn id as ModlogID;\r\n}\r\n\r\nfunction prettifyResults(\r\n\tresultArray: ModlogEntry[], roomid: ModlogID, search: ModlogSearch, searchCmd: string,\r\n\taddModlogLinks: boolean, hideIps: boolean, maxLines: number, onlyPunishments: boolean, onlyNotes: boolean\r\n) {\r\n\tif (resultArray === null) {\r\n\t\treturn \"|popup|The modlog query crashed.\";\r\n\t}\r\n\tlet roomName;\r\n\tswitch (roomid) {\r\n\tcase 'all':\r\n\t\troomName = \"all rooms\";\r\n\t\tbreak;\r\n\tcase 'public':\r\n\t\troomName = \"all public rooms\";\r\n\t\tbreak;\r\n\tdefault:\r\n\t\troomName = `room ${roomid}`;\r\n\t}\r\n\tconst scope = onlyPunishments ? 'punishment-related ' : '';\r\n\tlet searchString = ``;\r\n\tconst excludes = search.note.filter(s => s.isExclusion).map(s => s.search) || [];\r\n\tconst includes = search.note.filter(s => !s.isExclusion).map(s => s.search) || [];\r\n\tif (includes.length) searchString += `with a note including any of: ${includes.join(', ')} `;\r\n\tif (excludes.length) searchString += `with a note that does not include any of: ${excludes.join(', ')} `;\r\n\tfor (const u of search.user) searchString += `${u.isExclusion ? 'not ' : ''}taken against ${u.search} `;\r\n\tfor (const ip of search.ip) {\r\n\t\tsearchString += `${ip.isExclusion ? 'not ' : ''}taken against a user on the IP ${ip.search} `;\r\n\t}\r\n\tfor (const action of search.action) searchString += `${action.isExclusion ? 'not ' : ''}of the type ${action.search} `;\r\n\tfor (const actionTaker of search.actionTaker) {\r\n\t\tsearchString += `${actionTaker.isExclusion ? 'not ' : ''}taken by ${actionTaker.search} `;\r\n\t}\r\n\tif (!resultArray.length) {\r\n\t\treturn `|popup|No ${scope}moderator actions ${searchString}found on ${roomName}.`;\r\n\t}\r\n\tconst title = `[${roomid}] ${searchCmd}`;\r\n\tconst lines = resultArray.length;\r\n\tlet curDate = '';\r\n\tconst resultString = resultArray.map(result => {\r\n\t\tconst date = new Date(result.time || Date.now());\r\n\t\tconst entryRoom = result.visualRoomID || result.roomID || 'global';\r\n\t\tlet [dateString, timestamp] = Chat.toTimestamp(date, {human: true}).split(' ');\r\n\t\tlet line = `[${timestamp}] (${entryRoom}) ${result.action}`;\r\n\t\tif (result.userid) {\r\n\t\t\tline += `: [${result.userid}]`;\r\n\t\t\tif (result.autoconfirmedID) line += ` ac: [${result.autoconfirmedID}]`;\r\n\t\t\tif (result.alts.length) line += ` alts: [${result.alts.join('], [')}]`;\r\n\t\t\tif (!hideIps && result.ip) line += ` [${result.ip}]`;\r\n\t\t}\r\n\r\n\t\tif (result.loggedBy) line += `: by ${result.loggedBy}`;\r\n\t\tif (result.note) line += `: ${result.note}`;\r\n\r\n\t\tif (dateString !== curDate) {\r\n\t\t\tcurDate = dateString;\r\n\t\t\tdateString = `

[${dateString}]
`;\r\n\t\t} else {\r\n\t\t\tdateString = ``;\r\n\t\t}\r\n\t\tconst thisRoomID = entryRoom?.split(' ')[0];\r\n\t\tif (addModlogLinks) {\r\n\t\t\tif (thisRoomID.startsWith('battle-')) {\r\n\t\t\t\ttimestamp = `${timestamp}`;\r\n\t\t\t} else {\r\n\t\t\t\tconst [day, time] = Chat.toTimestamp(date).split(' ');\r\n\t\t\t\ttimestamp = `${timestamp}`;\r\n\t\t\t}\r\n\t\t}\r\n\t\tline = Utils.escapeHTML(line.slice(line.indexOf(')') + ` `.length));\r\n\t\tline = line.replace(\r\n\t\t\tIPS_REGEX,\r\n\t\t\thideIps ? '' : `[$1]`\r\n\t\t);\r\n\t\treturn `${dateString}[${timestamp}] (${thisRoomID})${line}`;\r\n\t}).join(`
`);\r\n\tconst [dateString, timestamp] = Chat.toTimestamp(new Date(), {human: true}).split(' ');\r\n\tlet preamble;\r\n\tconst modlogid = roomid + (searchString ? '-' + Dashycode.encode(searchString) : '');\r\n\tif (searchString) {\r\n\t\tpreamble = `>view-modlog-${modlogid}\\n|init|html\\n|title|[Modlog]${title}\\n` +\r\n\t\t\t`|pagehtml|

The last ${scope}${Chat.count(lines, \"logged actions\")} ${Utils.escapeHTML(searchString)} on ${roomName}.`;\r\n\t} else {\r\n\t\tpreamble = `>view-modlog-${modlogid}\\n|init|html\\n|title|[Modlog]${title}\\n` +\r\n\t\t\t`|pagehtml|

The last ${Chat.count(lines, `${scope}lines`)} of the Moderator Log of ${roomName}.`;\r\n\t}\r\n\tpreamble += `

[${dateString}]
[${timestamp}] \\u2190 current server time`;\r\n\tconst moreButton = getMoreButton(roomid, searchCmd, lines, maxLines, onlyPunishments, onlyNotes);\r\n\treturn `${preamble}${resultString}${moreButton}

`;\r\n}\r\n\r\nasync function getModlog(\r\n\tconnection: Connection, roomid: ModlogID = 'global', search: ModlogSearch,\r\n\tsearchCmd: string, maxLines = 20, onlyPunishments = false, timed = false, onlyNotes = false,\r\n) {\r\n\tconst targetRoom = Rooms.search(roomid);\r\n\tconst user = connection.user;\r\n\troomid = getRoomID(roomid);\r\n\r\n\t// permission checking\r\n\tif (roomid === 'all' || roomid === 'public') {\r\n\t\tif (!user.can('modlog')) {\r\n\t\t\treturn connection.popup(\"Access denied\");\r\n\t\t}\r\n\t} else {\r\n\t\tif (!user.can('modlog', null, targetRoom) && !user.can('modlog')) {\r\n\t\t\treturn connection.popup(\"Access denied\");\r\n\t\t}\r\n\t}\r\n\r\n\tconst hideIps = !user.can('lock');\r\n\tconst addModlogLinks = !!(\r\n\t\t(user.tempGroup !== ' ' || (targetRoom && targetRoom.settings.isPrivate !== true))\r\n\t);\r\n\tif (hideIps && search.ip.length) {\r\n\t\tconnection.popup(`You cannot search for IPs.`);\r\n\t\treturn;\r\n\t}\r\n\tif (Object.values(search).join('').length > MAX_QUERY_LENGTH) {\r\n\t\tconnection.popup(`Your search query is too long.`);\r\n\t\treturn;\r\n\t}\r\n\r\n\tif (search.note?.length) {\r\n\t\tfor (const [i, noteSearch] of search.note.entries()) {\r\n\t\t\tif (/^[\"'].+[\"']$/.test(noteSearch.search)) {\r\n\t\t\t\tsearch.note[i] = {...noteSearch, search: noteSearch.search.substring(1, noteSearch.search.length - 1)};\r\n\t\t\t\tsearch.note[i].isExact = true;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tfor (const [i, userSearch] of search.user.entries()) {\r\n\t\tif (/^[\"'].+[\"']$/.test(userSearch.search)) {\r\n\t\t\tuserSearch.search = userSearch.search.substring(1, userSearch.search.length - 1);\r\n\t\t\tuserSearch.isExact = true;\r\n\t\t}\r\n\t\tuserSearch.search = toID(userSearch.search);\r\n\r\n\t\tsearch.user[i] = userSearch;\r\n\t}\r\n\tif (onlyNotes) search.action.push({search: 'NOTE'});\r\n\r\n\tconst response = await Rooms.Modlog.search(roomid, search, maxLines, onlyPunishments);\r\n\tif (!response) return connection.popup(`The moderator log is currently disabled.`);\r\n\r\n\tconnection.send(\r\n\t\tprettifyResults(\r\n\t\t\tresponse.results,\r\n\t\t\troomid,\r\n\t\t\tsearch,\r\n\t\t\tsearchCmd,\r\n\t\t\taddModlogLinks,\r\n\t\t\thideIps,\r\n\t\t\tmaxLines,\r\n\t\t\tonlyPunishments,\r\n\t\t\tonlyNotes,\r\n\t\t)\r\n\t);\r\n\tif (timed) connection.popup(`The modlog query took ${response.duration} ms to complete.`);\r\n}\r\n\r\nconst shouldSearchGlobal = ['staff', 'adminlog'];\r\n\r\nexport const commands: Chat.ChatCommands = {\r\n\tml: 'modlog',\r\n\tpunishlog: 'modlog',\r\n\tpl: 'modlog',\r\n\ttimedmodlog: 'modlog',\r\n\tmlid: 'modlog',\r\n\tmlip: 'modlog',\r\n\tplid: 'modlog',\r\n\tplip: 'modlog',\r\n\tmodnotes: 'modlog',\r\n\tmodlog(target, room, user, connection, cmd) {\r\n\t\tlet roomid: ModlogID = (!room || shouldSearchGlobal.includes(room.roomid) ? 'global' : room.roomid);\r\n\t\tconst onlyPunishments = cmd.startsWith('pl') || cmd.startsWith('punishlog');\r\n\t\tlet lines;\r\n\t\tconst possibleParam = cmd.slice(2);\r\n\t\tconst targets = target.split(',').map(f => f.trim()).filter(Boolean);\r\n\t\tconst search: ModlogSearch = {note: [], user: [], ip: [], action: [], actionTaker: []};\r\n\r\n\t\tswitch (possibleParam) {\r\n\t\tcase 'id':\r\n\t\t\ttargets.unshift(`user='${targets.shift()}'`);\r\n\t\t\tbreak;\r\n\t\tcase 'ip':\r\n\t\t\ttargets.unshift(`ip=${targets.shift()}`);\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\tfor (const [i, option] of targets.entries()) {\r\n\t\t\tlet [param, value] = option.split('=').map(part => part.trim());\r\n\t\t\tif (!value) {\r\n\t\t\t\t// If no specific parameter is specified, we should search all fields\r\n\t\t\t\tvalue = param.trim();\r\n\t\t\t\tif (i === 0 && value) {\r\n\t\t\t\t\t// they might mean a roomid, as per the old format of /modlog\r\n\t\t\t\t\tparam = 'room';\r\n\t\t\t\t\t// if the room exists, they probably mean a roomid. otherwise, assume they're misusing it.\r\n\t\t\t\t\t// we except gdrivers+ from this because drivers can access deleted room modlogs\r\n\t\t\t\t\tif (!Rooms.search(toID(value)) && !user.can('lock')) {\r\n\t\t\t\t\t\treturn this.parse(`/help modlog`);\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthis.errorReply(`You must specify a search type and search value.`);\r\n\t\t\t\t\treturn this.parse(`/help modlog`);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tconst isExclusion = param.endsWith('!');\r\n\t\t\tparam = toID(param);\r\n\t\t\tswitch (param) {\r\n\t\t\tcase 'note': case 'text':\r\n\t\t\t\tif (!search.note) search.note = [];\r\n\t\t\t\tsearch.note.push({search: value, isExclusion});\r\n\t\t\t\tbreak;\r\n\t\t\tcase 'user': case 'name': case 'username': case 'userid':\r\n\t\t\t\tsearch.user.push({search: value});\r\n\t\t\t\tbreak;\r\n\t\t\tcase 'ip': case 'ipaddress': case 'ipaddr':\r\n\t\t\t\tsearch.ip.push({search: value, isExclusion});\r\n\t\t\t\tbreak;\r\n\t\t\tcase 'action': case 'punishment':\r\n\t\t\t\tsearch.action.push({search: value.toUpperCase(), isExclusion});\r\n\t\t\t\tbreak;\r\n\t\t\tcase 'actiontaker': case 'moderator': case 'staff': case 'mod':\r\n\t\t\t\tsearch.actionTaker.push({search: toID(value), isExclusion});\r\n\t\t\t\tbreak;\r\n\t\t\tcase 'room': case 'roomid':\r\n\t\t\t\troomid = value.toLowerCase().replace(/[^a-z0-9-]+/g, '') as ModlogID;\r\n\t\t\t\tbreak;\r\n\t\t\tcase 'lines': case 'maxlines':\r\n\t\t\t\tlines = parseInt(value);\r\n\t\t\t\tif (isNaN(lines) || lines < 1) return this.errorReply(`Invalid linecount: '${value}'.`);\r\n\t\t\t\tbreak;\r\n\t\t\tdefault:\r\n\t\t\t\tthis.errorReply(`Invalid modlog parameter: '${param}'.`);\r\n\t\t\t\treturn this.errorReply(`Please specify 'room', 'note', 'user', 'ip', 'action', 'staff', or 'lines'.`);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst targetRoom = Rooms.search(roomid);\r\n\t\t// if a room alias was used, replace alias with actual id\r\n\t\tif (targetRoom) roomid = targetRoom.roomid;\r\n\r\n\t\tif (roomid.includes('-')) {\r\n\t\t\tif (user.can('modlog')) {\r\n\t\t\t\t// default to global modlog for staff convenience\r\n\t\t\t\troomid = 'global';\r\n\t\t\t} else {\r\n\t\t\t\treturn this.errorReply(`Only global staff may view battle and groupchat modlogs.`);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!target && !lines) {\r\n\t\t\tlines = 20;\r\n\t\t}\r\n\t\tif (!lines) lines = DEFAULT_RESULTS_LENGTH;\r\n\t\tif (lines > MAX_RESULTS_LENGTH) lines = MAX_RESULTS_LENGTH;\r\n\r\n\t\tvoid getModlog(\r\n\t\t\tconnection,\r\n\t\t\troomid,\r\n\t\t\tsearch,\r\n\t\t\ttarget.replace(/^\\s?([^,=]*),\\s?/, '').replace(/,?\\s*(room|lines)\\s*=[^,]*,?/g, ''),\r\n\t\t\tlines,\r\n\t\t\tonlyPunishments,\r\n\t\t\tcmd === 'timedmodlog',\r\n\t\t\tcmd === 'modnotes',\r\n\t\t);\r\n\t},\r\n\tmodloghelp() {\r\n\t\tthis.sendReplyBox(\r\n\t\t\t`/modlog [comma-separated list of parameters]: searches the moderator log, defaulting to the current room unless specified otherwise.
` +\r\n\t\t\t`You can replace the = in a parameter with a != to exclude entries that match that parameter.
` +\r\n\t\t\t`
Parameters` +\r\n\t\t\t`` +\r\n\t\t\t`
` +\r\n\t\t\t`
Additional commands` +\r\n\t\t\t`` +\r\n\t\t\t`
`\r\n\t\t);\r\n\t},\r\n\tmls: 'modlogstats',\r\n\tmodlogstats(target, room, user) {\r\n\t\tthis.checkCan('lock');\r\n\t\ttarget = toID(target);\r\n\t\tif (!target) return this.parse(`/help modlogstats`);\r\n\t\treturn this.parse(`/join view-modlogstats-${target}`);\r\n\t},\r\n\tmodlogstatshelp: [`/modlogstats [userid] - Fetch all information on that [userid] from the modlog (IPs, alts, etc). Requires: @ &`],\r\n};\r\n\r\nexport const pages: Chat.PageTable = {\r\n\tasync modlogstats(query, user) {\r\n\t\tthis.checkCan('lock');\r\n\t\tconst target = toID(query.shift());\r\n\t\tif (!target || target.length > 18) {\r\n\t\t\treturn this.errorReply(`Invalid userid - must be between 1 and 18 characters long.`);\r\n\t\t}\r\n\t\tthis.title = `[Modlog Stats] ${target}`;\r\n\t\tthis.setHTML(`
Running modlog search...
`);\r\n\t\tconst entries = await Rooms.Modlog.search('global', {\r\n\t\t\tuser: [{\r\n\t\t\t\tsearch: target,\r\n\t\t\t\tisExact: true,\r\n\t\t\t}], note: [], ip: [], action: [], actionTaker: [],\r\n\t\t}, 1000);\r\n\t\tif (!entries?.results.length) {\r\n\t\t\treturn this.errorReply(`No data found.`);\r\n\t\t}\r\n\t\tconst punishmentTable = new Utils.Multiset();\r\n\t\tconst punishmentsByIp = new Map>();\r\n\t\tconst actionsWithIp = new Set();\r\n\t\tconst alts = new Set();\r\n\t\tconst autoconfirmed = new Set();\r\n\t\tconst ips = new Set();\r\n\t\tfor (const entry of entries.results) {\r\n\t\t\tif (entry.action !== 'NOTE') {\r\n\t\t\t\tpunishmentTable.add(entry.action);\r\n\t\t\t\tif (entry.ip) {\r\n\t\t\t\t\tlet ipTable = punishmentsByIp.get(entry.ip);\r\n\t\t\t\t\tif (!ipTable) {\r\n\t\t\t\t\t\tipTable = new Utils.Multiset();\r\n\t\t\t\t\t\tpunishmentsByIp.set(entry.ip, ipTable);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tipTable.add(entry.action);\r\n\t\t\t\t\tactionsWithIp.add(entry.action);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (entry.alts) {\r\n\t\t\t\tfor (const alt of entry.alts) alts.add(alt);\r\n\t\t\t}\r\n\t\t\tif (entry.autoconfirmedID) autoconfirmed.add(entry.autoconfirmedID);\r\n\t\t\tif (entry.ip) ips.add(entry.ip);\r\n\t\t}\r\n\t\tlet buf = `

Modlog information for ${target}


`;\r\n\t\tif (alts.size) {\r\n\t\t\tbuf += `Listed alts: `;\r\n\t\t\tbuf += `(These are userids sharing the same IP at the time of the punishment, they may not be direct alts)
`;\r\n\t\t\tbuf += [...alts]\r\n\t\t\t\t.map(id => `${toID(id)}`)\r\n\t\t\t\t.join(', ');\r\n\t\t\tbuf += `

`;\r\n\t\t}\r\n\r\n\t\tif (autoconfirmed.size) {\r\n\t\t\tbuf += `Autoconfirmed alts:`;\r\n\t\t\tbuf += ` (these are autoconfirmed accounts linked to their name, and are very likely them)
`;\r\n\t\t\tbuf += [...autoconfirmed]\r\n\t\t\t\t.map(id => `${toID(id)}`)\r\n\t\t\t\t.join(', ');\r\n\t\t\tbuf += `

`;\r\n\t\t}\r\n\r\n\t\tif (ips.size) {\r\n\t\t\tbuf += `Known IPs:
`;\r\n\t\t\tconst mapped = await Promise.all([...ips].map(async ip => {\r\n\t\t\t\tconst info = await IPTools.lookup(ip);\r\n\t\t\t\treturn `${ip} [${info.hostType}]`;\r\n\t\t\t}));\r\n\t\t\tbuf += mapped.join(', ');\r\n\t\t\tbuf += `

`;\r\n\t\t}\r\n\r\n\t\tif (punishmentTable.size) {\r\n\t\t\tbuf += `Punishments:
`;\r\n\t\t\tbuf += `
`;\r\n\t\t\tbuf += ``;\r\n\t\t\tfor (const [punishment, number] of punishmentTable) {\r\n\t\t\t\tbuf += ``;\r\n\t\t\t}\r\n\t\t\tbuf += `
Punishment typeCount
${punishment}${number}

`;\r\n\t\t}\r\n\t\tif (punishmentsByIp.size) {\r\n\t\t\tbuf += `Punishments by IP:
`;\r\n\t\t\tconst keys = [...actionsWithIp];\r\n\t\t\tbuf += `
`;\r\n\t\t\tbuf += `${keys.map(k => ``).join(\"\")}`;\r\n\t\t\tfor (const [ip, table] of punishmentsByIp) {\r\n\t\t\t\tbuf += ``;\r\n\t\t\t\tfor (const key of keys) {\r\n\t\t\t\t\tbuf += ``;\r\n\t\t\t\t}\r\n\t\t\t\tbuf += ``;\r\n\t\t\t}\r\n\t\t\tbuf += `
${k}
${ip}${table.get(key) || 0}
`;\r\n\t\t}\r\n\r\n\t\tbuf += `

`;\r\n\t\treturn buf;\r\n\t},\r\n};\r\n"], "mappings": "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", "names": ["dateString", "timestamp"] }