Pokemon_server / dist /server /friends.js.map
Jofthomas's picture
Jofthomas HF staff
Upload 4781 files
5c2ed06 verified
{
"version": 3,
"sources": ["../../server/friends.ts"],
"sourcesContent": ["/**\n * Friends chat-plugin database handler.\n * @author mia-pi-git\n */\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore in case it isn't installed\nimport type * as Database from 'better-sqlite3';\nimport { Utils, FS, ProcessManager, Repl } from '../lib';\nimport { Config } from './config-loader';\nimport * as path from 'path';\n\n/** Max friends per user */\nexport const MAX_FRIENDS = 100;\n/** Max friend requests. */\nexport const MAX_REQUESTS = 6;\nexport const DEFAULT_FILE = FS('databases/friends.db').path;\nconst REQUEST_EXPIRY_TIME = 30 * 24 * 60 * 60 * 1000;\nconst PM_TIMEOUT = 30 * 60 * 1000;\n\nexport interface DatabaseRequest {\n\tstatement: string;\n\ttype: 'all' | 'get' | 'run' | 'transaction';\n\tdata: AnyObject | any[];\n}\n\nexport interface DatabaseResult {\n\t/** Specify this to return an error message to the user */\n\terror?: string;\n\tresult?: any;\n}\n\nexport interface Friend {\n\t/** Always the same as Friend#friend. Use whichever you want. */\n\tuserid: ID;\n\t/** Always the same as Friend#userid. Use whichever you want. */\n\tfriend: ID;\n\tsend_login_data: number;\n\tlast_login: number;\n\tpublic_list: number;\n\tallowing_login: number;\n}\n\n/** Like Chat.ErrorMessage, but made for the subprocess so we can throw errors to the user not using errorMessage\n * because errorMessage crashes when imported (plus we have to spawn dex, etc, all unnecessary - this is easier)\n */\nexport class FailureMessage extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = 'FailureMessage';\n\t\tError.captureStackTrace(this, FailureMessage);\n\t}\n}\n\nexport function sendPM(message: string, to: string, from = '~') {\n\tconst senderID = toID(from);\n\tconst receiverID = toID(to);\n\tconst sendingUser = Users.get(senderID);\n\tconst receivingUser = Users.get(receiverID);\n\tconst fromIdentity = sendingUser ? sendingUser.getIdentity() : ` ${senderID}`;\n\tconst toIdentity = receivingUser ? receivingUser.getIdentity() : ` ${receiverID}`;\n\n\tif (from === '~') {\n\t\treturn receivingUser?.send(`|pm|~|${toIdentity}|${message}`);\n\t}\n\treceivingUser?.send(`|pm|${fromIdentity}|${toIdentity}|${message}`);\n}\n\nfunction canPM(sender: User, receiver: User | null) {\n\tif (!receiver?.settings.blockPMs) return true;\n\tif (receiver.settings.blockPMs === true) return sender.can('lock');\n\tif (receiver.settings.blockPMs === 'friends') return false;\n\treturn Users.globalAuth.atLeast(sender, receiver.settings.blockPMs);\n}\n\nexport class FriendsDatabase {\n\tfile: string;\n\tconstructor(file: string = DEFAULT_FILE) {\n\t\tthis.file = file === ':memory:' ? file : path.resolve(file);\n\t}\n\tasync updateUserCache(user: User) {\n\t\tuser.friends = new Set(); // we clear to account for users who may have been deleted\n\t\tconst friends = await this.getFriends(user.id);\n\t\tfor (const friend of friends) {\n\t\t\tuser.friends.add(friend.userid);\n\t\t}\n\t\treturn user.friends;\n\t}\n\tstatic setupDatabase(fileName?: string) {\n\t\tconst file = fileName || process.env.filename || DEFAULT_FILE;\n\t\tconst exists = FS(file).existsSync() || file === ':memory:';\n\t\tconst database: Database.Database = new (require('better-sqlite3'))(file);\n\t\tif (!exists) {\n\t\t\tdatabase.exec(FS('databases/schemas/friends.sql').readSync());\n\t\t} else {\n\t\t\tlet val;\n\t\t\ttry {\n\t\t\t\tval = (database\n\t\t\t\t\t.prepare(`SELECT val FROM database_settings WHERE name = 'version'`)\n\t\t\t\t\t.get() as AnyObject).val;\n\t\t\t} catch {}\n\t\t\tconst actualVersion = FS(`databases/migrations/friends`).readdirIfExistsSync().length;\n\t\t\tif (val === undefined) {\n\t\t\t\t// hasn't been set up before, write new version.\n\t\t\t\tdatabase.exec(FS('databases/schemas/friends.sql').readSync());\n\t\t\t}\n\t\t\tif (typeof val === 'number' && val !== actualVersion) {\n\t\t\t\tthrow new Error(`Friends DB is out of date, please migrate to latest version.`);\n\t\t\t}\n\t\t}\n\t\tdatabase.exec(FS(`databases/schemas/friends-startup.sql`).readSync());\n\n\t\tfor (const k in FUNCTIONS) {\n\t\t\tdatabase.function(k, FUNCTIONS[k]);\n\t\t}\n\n\t\tfor (const k in ACTIONS) {\n\t\t\ttry {\n\t\t\t\tstatements[k] = database.prepare(ACTIONS[k as keyof typeof ACTIONS]);\n\t\t\t} catch (e: any) {\n\t\t\t\tthrow new Error(`Friends DB statement crashed: ${ACTIONS[k as keyof typeof ACTIONS]} (${e.message})`);\n\t\t\t}\n\t\t}\n\n\t\tfor (const k in TRANSACTIONS) {\n\t\t\ttransactions[k] = database.transaction(TRANSACTIONS[k]);\n\t\t}\n\n\t\tstatements.expire.run();\n\t\treturn { database, statements };\n\t}\n\tasync getFriends(userid: ID): Promise<Friend[]> {\n\t\treturn (await this.all('get', [userid, MAX_FRIENDS])) || [];\n\t}\n\tasync getRequests(user: User) {\n\t\tconst sent = new Set<string>();\n\t\tconst received = new Set<string>();\n\t\tif (user.settings.blockFriendRequests) {\n\t\t\t// delete any pending requests that may have been sent to them while offline\n\t\t\t// we used to return but we will not since you can send requests while blocking\n\t\t\tawait this.run('deleteReceivedRequests', [user.id]);\n\t\t}\n\t\tconst sentResults = await this.all('getSent', [user.id]);\n\t\tif (sentResults === null) return { sent, received };\n\t\tfor (const request of sentResults) {\n\t\t\tsent.add(request.receiver);\n\t\t}\n\t\tconst receivedResults = await this.all('getReceived', [user.id]) || [];\n\t\tif (!receivedResults) {\n\t\t\treturn { received, sent };\n\t\t}\n\t\tfor (const request of receivedResults) {\n\t\t\treceived.add(request.sender);\n\t\t}\n\t\treturn { sent, received };\n\t}\n\tall(statement: string, data: any[] | AnyObject): Promise<any[] | null> {\n\t\treturn this.query({ type: 'all', data, statement });\n\t}\n\ttransaction(statement: string, data: any[] | AnyObject): Promise<{ result: any } | null> {\n\t\treturn this.query({ data, statement, type: 'transaction' });\n\t}\n\trun(statement: string, data: any[] | AnyObject): Promise<{ changes: number, lastInsertRowid: number }> {\n\t\treturn this.query({ statement, data, type: 'run' });\n\t}\n\tget(statement: string, data: any[] | AnyObject): Promise<AnyObject | null> {\n\t\treturn this.query({ statement, data, type: 'get' });\n\t}\n\tprivate async query(input: DatabaseRequest) {\n\t\tconst process = PM.acquire();\n\t\tif (!process || !Config.usesqlite) {\n\t\t\treturn null;\n\t\t}\n\t\tconst result = await process.query(input);\n\t\tif (result.error) {\n\t\t\tthrow new Chat.ErrorMessage(result.error);\n\t\t}\n\t\treturn result.result;\n\t}\n\tasync request(user: User, receiverID: ID) {\n\t\tconst receiver = Users.getExact(receiverID);\n\t\tif (receiverID === user.id || receiver?.previousIDs.includes(user.id)) {\n\t\t\tthrow new Chat.ErrorMessage(`You can't friend yourself.`);\n\t\t}\n\t\tif (receiver?.settings.blockFriendRequests) {\n\t\t\tthrow new Chat.ErrorMessage(`${receiver.name} is blocking friend requests.`);\n\t\t}\n\t\tlet buf = Utils.html`/uhtml sent-${user.id},<button class=\"button\" name=\"send\" value=\"/friends accept ${user.id}\">Accept</button> | `;\n\t\tbuf += Utils.html`<button class=\"button\" name=\"send\" value=\"/friends reject ${user.id}\">Deny</button><br /> `;\n\t\tbuf += `<small>(You can also stop this user from sending you friend requests with <code>/ignore</code>)</small>`;\n\t\tconst disclaimer = (\n\t\t\t`/raw <small>Note: If this request is accepted, your friend will be notified when you come online, ` +\n\t\t\t`and you will be notified when they do, unless you opt out of receiving them.</small>`\n\t\t);\n\t\tif (receiver?.settings.blockFriendRequests) {\n\t\t\tthrow new Chat.ErrorMessage(`This user is blocking friend requests.`);\n\t\t}\n\t\tif (!canPM(user, receiver)) {\n\t\t\tthrow new Chat.ErrorMessage(`This user is blocking PMs, and cannot be friended right now.`);\n\t\t}\n\n\t\tconst result = await this.transaction('send', [user.id, receiverID]);\n\t\tif (receiver) {\n\t\t\tsendPM(`/raw <span class=\"username\">${user.name}</span> sent you a friend request!`, receiver.id, user.id);\n\t\t\tsendPM(buf, receiver.id, user.id);\n\t\t\tsendPM(disclaimer, receiver.id, user.id);\n\t\t}\n\t\tsendPM(\n\t\t\t`/nonotify You sent a friend request to ${receiver?.connected ? receiver.name : receiverID}!`,\n\t\t\tuser.name\n\t\t);\n\t\tsendPM(\n\t\t\t`/uhtml undo-${receiverID},<button class=\"button\" name=\"send\" value=\"/friends undorequest ${Utils.escapeHTML(receiverID)}\">` +\n\t\t\t`<i class=\"fa fa-undo\"></i> Undo</button>`, user.name\n\t\t);\n\t\tsendPM(disclaimer, user.id);\n\t\treturn result;\n\t}\n\tasync removeRequest(receiverID: ID, senderID: ID) {\n\t\tif (!senderID) throw new Chat.ErrorMessage(`Invalid sender username.`);\n\t\tif (!receiverID) throw new Chat.ErrorMessage(`Invalid receiver username.`);\n\n\t\treturn this.run('deleteRequest', [senderID, receiverID]);\n\t}\n\tasync approveRequest(receiverID: ID, senderID: ID) {\n\t\treturn this.transaction('accept', [senderID, receiverID]);\n\t}\n\tasync removeFriend(userid: ID, friendID: ID) {\n\t\tif (!friendID || !userid) throw new Chat.ErrorMessage(`Invalid usernames supplied.`);\n\n\t\tconst result = await this.run('delete', { user1: userid, user2: friendID });\n\t\tif (result.changes < 1) {\n\t\t\tthrow new Chat.ErrorMessage(`You do not have ${friendID} friended.`);\n\t\t}\n\t}\n\twriteLogin(user: ID) {\n\t\treturn this.run('login', [user, Date.now(), Date.now()]);\n\t}\n\thideLoginData(id: ID) {\n\t\treturn this.run('hideLogin', [id, Date.now()]);\n\t}\n\tallowLoginData(id: ID) {\n\t\treturn this.run('showLogin', [id]);\n\t}\n\tasync getLastLogin(userid: ID) {\n\t\tconst result = await this.get('checkLastLogin', [userid]);\n\t\treturn parseInt(result?.['last_login']) || null;\n\t}\n\tasync getSettings(userid: ID) {\n\t\treturn (await this.get('getSettings', [userid])) || {};\n\t}\n\tsetHideList(userid: ID, setting: boolean) {\n\t\tconst num = setting ? 1 : 0;\n\t\t// name, send_login_data, last_login, public_list\n\t\treturn this.run('toggleList', [userid, num, num]);\n\t}\n\tasync findFriendship(user1: string, user2: string): Promise<boolean> {\n\t\tuser1 = toID(user1);\n\t\tuser2 = toID(user2);\n\t\treturn !!(await this.get('findFriendship', { user1, user2 }))?.length;\n\t}\n}\n\nconst statements: { [k: string]: Database.Statement } = {};\nconst transactions: { [k: string]: Database.Transaction } = {};\n\nconst ACTIONS = {\n\tadd: (\n\t\t`REPLACE INTO friends (user1, user2) VALUES ($user1, $user2) ON CONFLICT (user1, user2) ` +\n\t\t`DO UPDATE SET user1 = $user1, user2 = $user2`\n\t),\n\tget: (\n\t\t`SELECT * FROM friends_simplified f LEFT JOIN friend_settings fs ON f.friend = fs.userid WHERE f.userid = ? LIMIT ?`\n\t),\n\tdelete: `DELETE FROM friends WHERE (user1 = $user1 AND user2 = $user2) OR (user1 = $user2 AND user2 = $user1)`,\n\tgetSent: `SELECT receiver, sender FROM friend_requests WHERE sender = ?`,\n\tgetReceived: `SELECT receiver, sender FROM friend_requests WHERE receiver = ?`,\n\tinsertRequest: `INSERT INTO friend_requests(sender, receiver, sent_at) VALUES (?, ?, ?)`,\n\tdeleteRequest: `DELETE FROM friend_requests WHERE sender = ? AND receiver = ?`,\n\tdeleteReceivedRequests: `DELETE FROM friend_requests WHERE receiver = ?`,\n\tfindFriendship: `SELECT * FROM friends WHERE (user1 = $user1 AND user2 = $user2) OR (user2 = $user1 AND user1 = $user2)`,\n\tfindRequest: (\n\t\t`SELECT count(*) as num FROM friend_requests WHERE ` +\n\t\t`(sender = $user1 AND receiver = $user2) OR (sender = $user2 AND receiver = $user1)`\n\t),\n\tcountRequests: `SELECT count(*) as num FROM friend_requests WHERE (sender = ? OR receiver = ?)`,\n\tlogin: (\n\t\t`INSERT INTO friend_settings (userid, send_login_data, last_login, public_list) VALUES (?, 0, ?, 0) ` +\n\t\t`ON CONFLICT (userid) DO UPDATE SET last_login = ?`\n\t),\n\tcheckLastLogin: `SELECT last_login FROM friend_settings WHERE userid = ?`,\n\tdeleteLogin: `UPDATE friend_settings SET last_login = 0 WHERE userid = ?`,\n\texpire: (\n\t\t`DELETE FROM friend_requests WHERE EXISTS` +\n\t\t`(SELECT sent_at FROM friend_requests WHERE should_expire(sent_at) = 1)`\n\t),\n\thideLogin: ( // this works since if the insert works, they have no data, which means no public_list\n\t\t`INSERT INTO friend_settings (userid, send_login_data, last_login, public_list) VALUES (?, 1, ?, 0) ` +\n\t\t`ON CONFLICT (userid) DO UPDATE SET send_login_data = 1`\n\t),\n\tshowLogin: `DELETE FROM friend_settings WHERE userid = ? AND send_login_data = 1`,\n\tcountFriends: `SELECT count(*) as num FROM friends WHERE (user1 = ? OR user2 = ?)`,\n\tgetSettings: `SELECT * FROM friend_settings WHERE userid = ?`,\n\ttoggleList: (\n\t\t`INSERT INTO friend_settings (userid, send_login_data, last_login, public_list) VALUES (?, 0, 0, ?) ` +\n\t\t`ON CONFLICT (userid) DO UPDATE SET public_list = ?`\n\t),\n};\n\nconst FUNCTIONS: { [k: string]: (...input: any[]) => any } = {\n\t'should_expire': (sentTime: number) => {\n\t\tif (Date.now() - sentTime > REQUEST_EXPIRY_TIME) return 1;\n\t\treturn 0;\n\t},\n};\n\nconst TRANSACTIONS: { [k: string]: (input: any[]) => DatabaseResult } = {\n\tsend: requests => {\n\t\tfor (const request of requests) {\n\t\t\tconst [senderID, receiverID] = request;\n\t\t\tconst hasSentRequest = (\n\t\t\t\tstatements.findRequest.get({ user1: senderID, user2: receiverID }) as AnyObject\n\t\t\t)['num'];\n\t\t\tconst friends = (statements.countFriends.get(senderID, senderID) as AnyObject)['num'];\n\t\t\tconst totalRequests = (statements.countRequests.get(senderID, senderID) as AnyObject)['num'];\n\t\t\tif (friends >= MAX_FRIENDS) {\n\t\t\t\tthrow new FailureMessage(`You are at the maximum number of friends.`);\n\t\t\t}\n\t\t\tconst existingFriendship = statements.findFriendship.all({ user1: senderID, user2: receiverID });\n\t\t\tif (existingFriendship.length) {\n\t\t\t\tthrow new FailureMessage(`You are already friends with '${receiverID}'.`);\n\t\t\t}\n\t\t\tif (hasSentRequest) {\n\t\t\t\tthrow new FailureMessage(`You have already sent a friend request to '${receiverID}'.`);\n\t\t\t}\n\t\t\tif (totalRequests >= MAX_REQUESTS) {\n\t\t\t\tthrow new FailureMessage(\n\t\t\t\t\t`You already have ${MAX_REQUESTS} pending friend requests. Use \"/friends view sent\" to see your outgoing requests and \"/friends view receive\" to see your incoming requests.`\n\t\t\t\t);\n\t\t\t}\n\t\t\tstatements.insertRequest.run(senderID, receiverID, Date.now());\n\t\t}\n\t\treturn { result: [] };\n\t},\n\tadd: requests => {\n\t\tfor (const request of requests) {\n\t\t\tconst [senderID, receiverID] = request;\n\t\t\tstatements.add.run({ user1: senderID, user2: receiverID });\n\t\t}\n\t\treturn { result: [] };\n\t},\n\taccept: requests => {\n\t\tfor (const request of requests) {\n\t\t\tconst [senderID, receiverID] = request;\n\t\t\tconst friends = statements.get.all(receiverID, 101);\n\t\t\tif (friends?.length >= MAX_FRIENDS) {\n\t\t\t\tthrow new FailureMessage(`You are at the maximum number of friends.`);\n\t\t\t}\n\t\t\tconst { result } = TRANSACTIONS.removeRequest([request]);\n\t\t\tif (!result.length) throw new FailureMessage(`You have no request pending from ${senderID}.`);\n\t\t\tTRANSACTIONS.add([request]);\n\t\t}\n\t\treturn { result: [] };\n\t},\n\tremoveRequest: requests => {\n\t\tconst result = [];\n\t\tfor (const request of requests) {\n\t\t\tconst [to, from] = request;\n\t\t\tconst { changes } = statements.deleteRequest.run(to, from);\n\t\t\tif (changes) result.push(changes);\n\t\t}\n\t\treturn { result };\n\t},\n};\n\n/**\n * API STUFF - For use in other database child processes that may want to interface with the friends list.\n * todo: should these be under a namespace?\n */\n\n/** Find if a friendship exists between two users. */\nexport function findFriendship(users: [string, string]) {\n\tsetup();\n\treturn !!statements.findFriendship.get({ user1: users[0], user2: users[1] });\n}\n\n// internal for child process api - ensures statements are only set up\nconst setup = () => {\n\tif (!process.send) throw new Error(\"You should not be using this function in the main process\");\n\tif (!Object.keys(statements).length) FriendsDatabase.setupDatabase();\n};\n\n/** Process manager for main process use. */\nexport const PM = new ProcessManager.QueryProcessManager<DatabaseRequest, DatabaseResult>(module, query => {\n\tconst { type, statement, data } = query;\n\tconst start = Date.now();\n\tconst result: DatabaseResult = {};\n\ttry {\n\t\tswitch (type) {\n\t\tcase 'run':\n\t\t\tresult.result = statements[statement].run(data);\n\t\t\tbreak;\n\t\tcase 'get':\n\t\t\tresult.result = statements[statement].get(data);\n\t\t\tbreak;\n\t\tcase 'transaction':\n\t\t\tresult.result = transactions[statement]([data]);\n\t\t\tbreak;\n\t\tcase 'all':\n\t\t\tresult.result = statements[statement].all(data);\n\t\t\tbreak;\n\t\t}\n\t} catch (e: any) {\n\t\tif (!e.name.endsWith('FailureMessage')) {\n\t\t\tresult.error = \"Sorry! The database process crashed. We've been notified and will fix this.\";\n\t\t\tMonitor.crashlog(e, \"A friends database process\", query);\n\t\t} else {\n\t\t\tresult.error = e.message;\n\t\t}\n\t\treturn result;\n\t}\n\tconst delta = Date.now() - start;\n\tif (delta > 1000) {\n\t\tMonitor.slow(`[Slow friends list query] ${JSON.stringify(query)}`);\n\t}\n\treturn result;\n}, PM_TIMEOUT, message => {\n\tif (message.startsWith('SLOW\\n')) {\n\t\tMonitor.slow(message.slice(5));\n\t}\n});\n\nif (require.main === module) {\n\tglobal.Config = (require as any)('./config-loader').Config;\n\tif (Config.usesqlite) {\n\t\tFriendsDatabase.setupDatabase();\n\t}\n\t// since we require this in child processes\n\tif (process.mainModule === module) {\n\t\tglobal.Monitor = {\n\t\t\tcrashlog(error: Error, source = 'A friends database process', details: AnyObject | null = null) {\n\t\t\t\tconst repr = JSON.stringify([error.name, error.message, source, details]);\n\t\t\t\tprocess.send!(`THROW\\n@!!@${repr}\\n${error.stack}`);\n\t\t\t},\n\t\t\tslow(message: string) {\n\t\t\t\tprocess.send!(`CALLBACK\\nSLOW\\n${message}`);\n\t\t\t},\n\t\t} as any;\n\t\tprocess.on('uncaughtException', err => {\n\t\t\tif (Config.crashguard) {\n\t\t\t\tMonitor.crashlog(err, 'A friends child process');\n\t\t\t}\n\t\t});\n\t\t// eslint-disable-next-line no-eval\n\t\tRepl.start(`friends-${process.pid}`, cmd => eval(cmd));\n\t}\n} else if (!process.send) {\n\tPM.spawn(Config.friendsprocesses || 1);\n}\n"],
"mappings": "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",
"names": ["process"]
}