{ "version": 3, "sources": ["../../server/sockets.ts"], "sourcesContent": ["/**\n * Connections\n * Pokemon Showdown - http://pokemonshowdown.com/\n *\n * Abstraction layer for multi-process SockJS connections.\n *\n * This file handles all the communications between the users'\n * browsers, the networking processes, and users.ts in the\n * main process.\n *\n * @license MIT\n */\n\nimport * as fs from 'fs';\nimport * as http from 'http';\nimport * as https from 'https';\nimport * as path from 'path';\nimport { crashlogger, ProcessManager, Streams, Repl } from '../lib';\nimport { IPTools } from './ip-tools';\nimport { type ChannelID, extractChannelMessages } from '../sim/battle';\n\ntype StreamWorker = ProcessManager.StreamWorker;\n\nexport const Sockets = new class {\n\tasync onSpawn(worker: StreamWorker) {\n\t\tconst id = worker.workerid;\n\t\tfor await (const data of worker.stream) {\n\t\t\tswitch (data.charAt(0)) {\n\t\t\tcase '*': {\n\t\t\t\t// *socketid, ip, protocol\n\t\t\t\t// connect\n\t\t\t\tworker.load++;\n\t\t\t\tconst [socketid, ip, protocol] = data.substr(1).split('\\n');\n\t\t\t\tUsers.socketConnect(worker, id, socketid, ip, protocol);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase '!': {\n\t\t\t\t// !socketid\n\t\t\t\t// disconnect\n\t\t\t\tworker.load--;\n\t\t\t\tconst socketid = data.substr(1);\n\t\t\t\tUsers.socketDisconnect(worker, id, socketid);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase '<': {\n\t\t\t\t// void this.onSpawn(worker));\n\t\tPM.subscribeUnspawn(this.onUnspawn);\n\n\t\tPM.spawn(workerCount);\n\t}\n\n\tsocketSend(worker: StreamWorker, socketid: string, message: string) {\n\t\tvoid worker.stream.write(`>${socketid}\\n${message}`);\n\t}\n\n\tsocketDisconnect(worker: StreamWorker, socketid: string) {\n\t\tvoid worker.stream.write(`!${socketid}`);\n\t}\n\n\troomBroadcast(roomid: RoomID, message: string) {\n\t\tfor (const worker of PM.workers) {\n\t\t\tvoid worker.stream.write(`#${roomid}\\n${message}`);\n\t\t}\n\t}\n\n\troomAdd(worker: StreamWorker, roomid: RoomID, socketid: string) {\n\t\tvoid worker.stream.write(`+${roomid}\\n${socketid}`);\n\t}\n\n\troomRemove(worker: StreamWorker, roomid: RoomID, socketid: string) {\n\t\tvoid worker.stream.write(`-${roomid}\\n${socketid}`);\n\t}\n\n\tchannelBroadcast(roomid: RoomID, message: string) {\n\t\tfor (const worker of PM.workers) {\n\t\t\tvoid worker.stream.write(`:${roomid}\\n${message}`);\n\t\t}\n\t}\n\n\tchannelMove(worker: StreamWorker, roomid: RoomID, channelid: ChannelID, socketid: string) {\n\t\tvoid worker.stream.write(`.${roomid}\\n${channelid}\\n${socketid}`);\n\t}\n\n\teval(worker: StreamWorker, query: string) {\n\t\tvoid worker.stream.write(`$${query}`);\n\t}\n};\n\nexport class ServerStream extends Streams.ObjectReadWriteStream {\n\t/** socketid:Connection */\n\tsockets = new Map();\n\t/** roomid:socketid:Connection */\n\trooms = new Map>();\n\t/** roomid:socketid:channelid */\n\troomChannels = new Map>();\n\n\tserver: http.Server;\n\tserverSsl: https.Server | null;\n\tsocketCounter = 0;\n\n\tisTrustedProxyIp: (ip: string) => boolean;\n\n\treceivers: { [k: string]: (this: ServerStream, data: string) => void } = {\n\t\t'$'(data) {\n\t\t\t// $code\n\t\t\t// eslint-disable-next-line no-eval\n\t\t\teval(data.substr(1));\n\t\t},\n\t\t'!'(data) {\n\t\t\t// !socketid\n\t\t\t// destroy\n\t\t\tconst socketid = data.substr(1);\n\t\t\tconst socket = this.sockets.get(socketid);\n\t\t\tif (!socket) return;\n\t\t\tsocket.destroy();\n\t\t\tthis.sockets.delete(socketid);\n\t\t\tfor (const [curRoomid, curRoom] of this.rooms) {\n\t\t\t\tcurRoom.delete(socketid);\n\t\t\t\tconst roomChannel = this.roomChannels.get(curRoomid);\n\t\t\t\tif (roomChannel) roomChannel.delete(socketid);\n\t\t\t\tif (!curRoom.size) {\n\t\t\t\t\tthis.rooms.delete(curRoomid);\n\t\t\t\t\tif (roomChannel) this.roomChannels.delete(curRoomid);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t'>'(data) {\n\t\t\t// >socketid, message\n\t\t\t// message to single connection\n\t\t\tconst nlLoc = data.indexOf('\\n');\n\t\t\tconst socketid = data.substr(1, nlLoc - 1);\n\t\t\tconst socket = this.sockets.get(socketid);\n\t\t\tif (!socket) return;\n\t\t\tconst message = data.substr(nlLoc + 1);\n\t\t\tsocket.write(message);\n\t\t},\n\t\t'#'(data) {\n\t\t\t// #roomid, message\n\t\t\t// message to all connections in room\n\t\t\t// #, message\n\t\t\t// message to all connections\n\t\t\tconst nlLoc = data.indexOf('\\n');\n\t\t\tconst roomid = data.substr(1, nlLoc - 1) as RoomID;\n\t\t\tconst room = roomid ? this.rooms.get(roomid) : this.sockets;\n\t\t\tif (!room) return;\n\t\t\tconst message = data.substr(nlLoc + 1);\n\t\t\tfor (const curSocket of room.values()) curSocket.write(message);\n\t\t},\n\t\t'+'(data) {\n\t\t\t// +roomid, socketid\n\t\t\t// join room with connection\n\t\t\tconst nlLoc = data.indexOf('\\n');\n\t\t\tconst socketid = data.substr(nlLoc + 1);\n\t\t\tconst socket = this.sockets.get(socketid);\n\t\t\tif (!socket) return;\n\t\t\tconst roomid = data.substr(1, nlLoc - 1) as RoomID;\n\t\t\tlet room = this.rooms.get(roomid);\n\t\t\tif (!room) {\n\t\t\t\troom = new Map();\n\t\t\t\tthis.rooms.set(roomid, room);\n\t\t\t}\n\t\t\troom.set(socketid, socket);\n\t\t},\n\t\t'-'(data) {\n\t\t\t// -roomid, socketid\n\t\t\t// leave room with connection\n\t\t\tconst nlLoc = data.indexOf('\\n');\n\t\t\tconst roomid = data.slice(1, nlLoc) as RoomID;\n\t\t\tconst room = this.rooms.get(roomid);\n\t\t\tif (!room) return;\n\t\t\tconst socketid = data.slice(nlLoc + 1);\n\t\t\troom.delete(socketid);\n\t\t\tconst roomChannel = this.roomChannels.get(roomid);\n\t\t\tif (roomChannel) roomChannel.delete(socketid);\n\t\t\tif (!room.size) {\n\t\t\t\tthis.rooms.delete(roomid);\n\t\t\t\tif (roomChannel) this.roomChannels.delete(roomid);\n\t\t\t}\n\t\t},\n\t\t'.'(data) {\n\t\t\t// .roomid, channelid, socketid\n\t\t\t// move connection to different channel in room\n\t\t\tconst nlLoc = data.indexOf('\\n');\n\t\t\tconst roomid = data.slice(1, nlLoc) as RoomID;\n\t\t\tconst nlLoc2 = data.indexOf('\\n', nlLoc + 1);\n\t\t\tconst channelid = Number(data.slice(nlLoc + 1, nlLoc2)) as ChannelID;\n\t\t\tconst socketid = data.slice(nlLoc2 + 1);\n\n\t\t\tlet roomChannel = this.roomChannels.get(roomid);\n\t\t\tif (!roomChannel) {\n\t\t\t\troomChannel = new Map();\n\t\t\t\tthis.roomChannels.set(roomid, roomChannel);\n\t\t\t}\n\t\t\tif (channelid === 0) {\n\t\t\t\troomChannel.delete(socketid);\n\t\t\t} else {\n\t\t\t\troomChannel.set(socketid, channelid);\n\t\t\t}\n\t\t},\n\t\t':'(data) {\n\t\t\t// :roomid, message\n\t\t\t// message to a room, splitting `|split` by channel\n\t\t\tconst nlLoc = data.indexOf('\\n');\n\t\t\tconst roomid = data.slice(1, nlLoc) as RoomID;\n\t\t\tconst room = this.rooms.get(roomid);\n\t\t\tif (!room) return;\n\n\t\t\tconst messages: [string | null, string | null, string | null, string | null, string | null] = [\n\t\t\t\tnull, null, null, null, null,\n\t\t\t];\n\t\t\tconst message = data.substr(nlLoc + 1);\n\t\t\tconst channelMessages = extractChannelMessages(message, [0, 1, 2, 3, 4]);\n\t\t\tconst roomChannel = this.roomChannels.get(roomid);\n\t\t\tfor (const [curSocketid, curSocket] of room) {\n\t\t\t\tconst channelid = roomChannel?.get(curSocketid) || 0;\n\t\t\t\tif (!messages[channelid]) messages[channelid] = channelMessages[channelid].join('\\n');\n\t\t\t\tcurSocket.write(messages[channelid]);\n\t\t\t}\n\t\t},\n\t};\n\n\tconstructor(config: {\n\t\tport: number,\n\t\tbindaddress?: string,\n\t\tssl?: typeof Config.ssl,\n\t\twsdeflate?: typeof Config.wsdeflate,\n\t\tproxyip?: typeof Config.proxyip,\n\t\tcustomhttpresponse?: typeof Config.customhttpresponse,\n\t\tdisablenodestatic?: boolean,\n\t}) {\n\t\tsuper();\n\t\tif (!config.bindaddress) config.bindaddress = '0.0.0.0';\n\n\t\tthis.isTrustedProxyIp = config.proxyip ? IPTools.checker(config.proxyip) : () => false;\n\n\t\t// Static HTTP server\n\n\t\t// This handles the custom CSS and custom avatar features, and also\n\t\t// redirects yourserver:8001 to yourserver-8001.psim.us\n\n\t\t// It's optional if you don't need these features.\n\n\t\tthis.server = http.createServer();\n\t\tthis.serverSsl = null;\n\t\tif (config.ssl) {\n\t\t\tlet key;\n\t\t\ttry {\n\t\t\t\tkey = path.resolve(__dirname, config.ssl.options.key);\n\t\t\t\tif (!fs.statSync(key).isFile()) throw new Error();\n\t\t\t\ttry {\n\t\t\t\t\tkey = fs.readFileSync(key);\n\t\t\t\t} catch (e: any) {\n\t\t\t\t\tcrashlogger(\n\t\t\t\t\t\tnew Error(`Failed to read the configured SSL private key PEM file:\\n${e.stack}`),\n\t\t\t\t\t\t`Socket process ${process.pid}`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tconsole.warn('SSL private key config values will not support HTTPS server option values in the future. Please set it to use the absolute path of its PEM file.');\n\t\t\t\tkey = config.ssl.options.key;\n\t\t\t}\n\n\t\t\tlet cert;\n\t\t\ttry {\n\t\t\t\tcert = path.resolve(__dirname, config.ssl.options.cert);\n\t\t\t\tif (!fs.statSync(cert).isFile()) throw new Error();\n\t\t\t\ttry {\n\t\t\t\t\tcert = fs.readFileSync(cert);\n\t\t\t\t} catch (e: any) {\n\t\t\t\t\tcrashlogger(\n\t\t\t\t\t\tnew Error(`Failed to read the configured SSL certificate PEM file:\\n${e.stack}`),\n\t\t\t\t\t\t`Socket process ${process.pid}`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tconsole.warn('SSL certificate config values will not support HTTPS server option values in the future. Please set it to use the absolute path of its PEM file.');\n\t\t\t\tcert = config.ssl.options.cert;\n\t\t\t}\n\n\t\t\tif (key && cert) {\n\t\t\t\ttry {\n\t\t\t\t\t// In case there are additional SSL config settings besides the key and cert...\n\t\t\t\t\tthis.serverSsl = https.createServer({ ...config.ssl.options, key, cert });\n\t\t\t\t} catch (e: any) {\n\t\t\t\t\tcrashlogger(new Error(`The SSL settings are misconfigured:\\n${e.stack}`), `Socket process ${process.pid}`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Static server\n\t\ttry {\n\t\t\tif (config.disablenodestatic) throw new Error(\"disablenodestatic\");\n\t\t\tconst StaticServer: typeof import('node-static').Server = require('node-static').Server;\n\t\t\tconst roomidRegex = /^\\/(?:[A-Za-z0-9][A-Za-z0-9-]*)\\/?$/;\n\t\t\tconst cssServer = new StaticServer('./config');\n\t\t\tconst avatarServer = new StaticServer('./config/avatars');\n\t\t\tconst staticServer = new StaticServer('./server/static');\n\t\t\tconst staticRequestHandler = (req: http.IncomingMessage, res: http.ServerResponse) => {\n\t\t\t\t// console.log(`static rq: ${req.socket.remoteAddress}:${req.socket.remotePort} -> ${req.socket.localAddress}:${req.socket.localPort} - ${req.method} ${req.url} ${req.httpVersion} - ${req.rawHeaders.join('|')}`);\n\t\t\t\treq.resume();\n\t\t\t\treq.addListener('end', () => {\n\t\t\t\t\tif (config.customhttpresponse?.(req, res)) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet server = staticServer;\n\t\t\t\t\tif (req.url) {\n\t\t\t\t\t\tif (req.url === '/custom.css') {\n\t\t\t\t\t\t\tserver = cssServer;\n\t\t\t\t\t\t} else if (req.url.startsWith('/avatars/')) {\n\t\t\t\t\t\t\treq.url = req.url.substr(8);\n\t\t\t\t\t\t\tserver = avatarServer;\n\t\t\t\t\t\t} else if (roomidRegex.test(req.url)) {\n\t\t\t\t\t\t\treq.url = '/';\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tserver.serve(req, res, e => {\n\t\t\t\t\t\tif (e && (e as any).status === 404) {\n\t\t\t\t\t\t\tstaticServer.serveFile('404.html', 404, {}, req, res);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t};\n\n\t\t\tthis.server.on('request', staticRequestHandler);\n\t\t\tif (this.serverSsl) this.serverSsl.on('request', staticRequestHandler);\n\t\t} catch (e: any) {\n\t\t\tif (e.message === 'disablenodestatic') {\n\t\t\t\tconsole.log('node-static is disabled');\n\t\t\t} else {\n\t\t\t\tconsole.log('Could not start node-static - try `npm install` if you want to use it');\n\t\t\t}\n\t\t}\n\n\t\t// SockJS server\n\n\t\t// This is the main server that handles users connecting to our server\n\t\t// and doing things on our server.\n\n\t\tconst sockjs: typeof import('sockjs') = (require as any)('sockjs');\n\t\tconst options: import('sockjs').ServerOptions & { faye_server_options?: { [key: string]: any } } = {\n\t\t\tsockjs_url: `//play.pokemonshowdown.com/js/lib/sockjs-1.4.0-nwjsfix.min.js`,\n\t\t\tprefix: '/showdown',\n\t\t\tlog(severity: string, message: string) {\n\t\t\t\tif (severity === 'error') console.log(`ERROR: ${message}`);\n\t\t\t},\n\t\t};\n\n\t\tif (config.wsdeflate !== null) {\n\t\t\ttry {\n\t\t\t\tconst deflate = (require as any)('permessage-deflate').configure(config.wsdeflate);\n\t\t\t\toptions.faye_server_options = { extensions: [deflate] };\n\t\t\t} catch {\n\t\t\t\tcrashlogger(\n\t\t\t\t\tnew Error(\"Dependency permessage-deflate is not installed or is otherwise unaccessable. No message compression will take place until server restart.\"),\n\t\t\t\t\t\"Sockets\"\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tconst server = sockjs.createServer(options);\n\n\t\tprocess.once('disconnect', () => this.cleanup());\n\t\tprocess.once('exit', () => this.cleanup());\n\n\t\t// this is global so it can be hotpatched if necessary\n\t\tserver.on('connection', connection => this.onConnection(connection));\n\t\tserver.installHandlers(this.server, {});\n\t\tthis.server.listen(config.port, config.bindaddress);\n\t\tconsole.log(`Worker ${PM.workerid} now listening on ${config.bindaddress}:${config.port}`);\n\n\t\tif (this.serverSsl) {\n\t\t\tserver.installHandlers(this.serverSsl, {});\n\t\t\t// @ts-expect-error if appssl exists, then `config.ssl` must also exist\n\t\t\tthis.serverSsl.listen(config.ssl.port, config.bindaddress);\n\t\t\t// @ts-expect-error if appssl exists, then `config.ssl` must also exist\n\t\t\tconsole.log(`Worker ${PM.workerid} now listening for SSL on port ${config.ssl.port}`);\n\t\t}\n\n\t\tconsole.log(`Test your server at http://${config.bindaddress === '0.0.0.0' ? 'localhost' : config.bindaddress}:${config.port}`);\n\t}\n\n\t/**\n\t * Clean up any remaining connections on disconnect. If this isn't done,\n\t * the process will not exit until any remaining connections have been destroyed.\n\t * Afterwards, the worker process will die on its own\n\t */\n\tcleanup() {\n\t\tfor (const socket of this.sockets.values()) {\n\t\t\ttry {\n\t\t\t\tsocket.destroy();\n\t\t\t} catch {}\n\t\t}\n\t\tthis.sockets.clear();\n\t\tthis.rooms.clear();\n\t\tthis.roomChannels.clear();\n\n\t\tthis.server.close();\n\t\tif (this.serverSsl) this.serverSsl.close();\n\n\t\t// Let the server(s) finish closing.\n\t\tsetImmediate(() => process.exit(0));\n\t}\n\n\tonConnection(socket: import('sockjs').Connection) {\n\t\t// For reasons that are not entirely clear, SockJS sometimes triggers\n\t\t// this event with a null `socket` argument.\n\t\tif (!socket) return;\n\n\t\tif (!socket.remoteAddress) {\n\t\t\t// SockJS sometimes fails to be able to cache the IP, port, and\n\t\t\t// address from connection request headers.\n\t\t\ttry {\n\t\t\t\tsocket.destroy();\n\t\t\t} catch {}\n\t\t\treturn;\n\t\t}\n\n\t\tconst socketid = `${++this.socketCounter}`;\n\t\tthis.sockets.set(socketid, socket);\n\n\t\tlet socketip = socket.remoteAddress;\n\t\tif (this.isTrustedProxyIp(socketip)) {\n\t\t\tconst ips = (socket.headers['x-forwarded-for'] || '').split(',').reverse();\n\t\t\tfor (const ip of ips) {\n\t\t\t\tconst proxy = ip.trim();\n\t\t\t\tif (!this.isTrustedProxyIp(proxy)) {\n\t\t\t\t\tsocketip = proxy;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.push(`*${socketid}\\n${socketip}\\n${socket.protocol}`);\n\n\t\tsocket.on('data', message => {\n\t\t\t// drop empty messages (DDoS?)\n\t\t\tif (!message) return;\n\t\t\t// drop messages over 100KB\n\t\t\tif (message.length > (100 * 1024)) {\n\t\t\t\tsocket.write(`|popup|Your message must be below 100KB`);\n\t\t\t\tconsole.log(`Dropping client message ${message.length / 1024} KB...`);\n\t\t\t\tconsole.log(message.slice(0, 160));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// drop legacy JSON messages\n\t\t\tif (typeof message !== 'string' || message.startsWith('{')) return;\n\t\t\t// drop blank messages (DDoS?)\n\t\t\tconst pipeIndex = message.indexOf('|');\n\t\t\tif (pipeIndex < 0 || pipeIndex === message.length - 1) return;\n\n\t\t\tthis.push(`<${socketid}\\n${message}`);\n\t\t});\n\n\t\tsocket.once('close', () => {\n\t\t\tthis.push(`!${socketid}`);\n\t\t\tthis.sockets.delete(socketid);\n\t\t\tfor (const room of this.rooms.values()) room.delete(socketid);\n\t\t});\n\t}\n\n\t_write(data: string) {\n\t\t// console.log('worker received: ' + data);\n\n\t\tconst receiver = this.receivers[data.charAt(0)];\n\t\tif (receiver) receiver.call(this, data);\n\t}\n}\n\n/*********************************************************\n * Process manager\n *********************************************************/\n\nexport const PM = new ProcessManager.RawProcessManager({\n\tmodule,\n\tsetupChild: () => new ServerStream(Config),\n\tisCluster: true,\n});\n\nif (!PM.isParentProcess) {\n\t// This is a child process!\n\tglobal.Config = (require as any)('./config-loader').Config;\n\n\tif (Config.crashguard) {\n\t\t// graceful crash - allow current battles to finish before restarting\n\t\tprocess.on('uncaughtException', err => {\n\t\t\tcrashlogger(err, `Socket process ${PM.workerid} (${process.pid})`);\n\t\t});\n\t\tprocess.on('unhandledRejection', err => {\n\t\t\tcrashlogger(err as any || {}, `Socket process ${PM.workerid} (${process.pid}) Promise`);\n\t\t});\n\t}\n\n\tif (Config.sockets) {\n\t\ttry {\n\t\t\trequire.resolve('node-oom-heapdump');\n\t\t} catch (e: any) {\n\t\t\tif (e.code !== 'MODULE_NOT_FOUND') throw e; // should never happen\n\t\t\tthrow new Error(\n\t\t\t\t'node-oom-heapdump is not installed, but it is a required dependency if Config.ofesockets is set to true! ' +\n\t\t\t\t'Run npm install node-oom-heapdump and restart the server.'\n\t\t\t);\n\t\t}\n\n\t\t// Create a heapdump if the process runs out of memory.\n\t\t(global as any).nodeOomHeapdump = (require as any)('node-oom-heapdump')({\n\t\t\taddTimestamp: true,\n\t\t});\n\t}\n\n\t// setup worker\n\tif (process.env.PSPORT) Config.port = +process.env.PSPORT;\n\tif (process.env.PSBINDADDR) Config.bindaddress = process.env.PSBINDADDR;\n\tif (process.env.PSNOSSL && parseInt(process.env.PSNOSSL)) Config.ssl = null;\n\n\t// eslint-disable-next-line no-eval\n\tRepl.start(`sockets-${PM.workerid}-${process.pid}`, cmd => eval(cmd));\n}\n"], "mappings": "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", "names": ["data", "server"] }