From 72661ecf4ac6d60167f6883a87a3631b83a9e04f Mon Sep 17 00:00:00 2001 From: Mia <49593536+mia-pi-git@users.noreply.github.com> Date: Sun, 27 Oct 2024 16:04:42 -0500 Subject: [PATCH] Add an action to manually check if a user is verified for a suspect For fallbacks, mostly. Shouldn't truly be needed. --- src/actions.ts | 101 +++++++++++++++++++++------------- src/schemas/ntbb-suspects.sql | 2 +- src/tables.ts | 2 +- 3 files changed, 65 insertions(+), 40 deletions(-) diff --git a/src/actions.ts b/src/actions.ts index aa32390..ac240d7 100644 --- a/src/actions.ts +++ b/src/actions.ts @@ -9,7 +9,7 @@ import * as pathModule from 'path'; import * as crypto from 'crypto'; import * as url from 'url'; import {Config} from './config-loader'; -import {Ladder} from './ladder'; +import {Ladder, LadderEntry} from './ladder'; import {Replays} from './replays'; import {ActionError, QueryHandler, Server} from './server'; import {Session} from './user'; @@ -80,6 +80,51 @@ const smogonFetch = async (targetUrl: string, method: string, data: {[k: string] }); }; +function checkSuspectVerified( + rating: LadderEntry, + suspect: {formatid: string, start_date: number}, + reqs: Record +) { + let reqsMet = 0; + let reqCount = 0; + const userData: Partial<{elo: number, gxe: number, coil: number}> = {}; + for (const k in reqs) { + if (!reqs[k as 'elo' | 'coil' | 'gxe']) continue; + reqCount++; + switch (k) { + case 'coil': + const N = rating.w + rating.l + rating.t; + const coilNum = Math.round(40.0 * rating.gxe * Math.pow(2.0, -coil[suspect.formatid] / N)); + if (coilNum >= reqs.coil!) { + reqsMet++; + } + userData.coil = coilNum; + break; + case 'elo': case 'gxe': + if (reqs[k] && rating[k] >= reqs[k]!) { + reqsMet++; + } + userData[k] = rating[k]; + break; + } + } + if ( + // sanity check for reqs existing just to be totally safe + (reqsMet >= 1 && reqsMet === reqCount) && + // did not play games before the test began + (rating?.first_played && rating.first_played > suspect.start_date) + ) { + void smogonFetch("tools/api/suspect-verify", "POST", { + userid: rating.userid, + format: suspect.formatid, + reqs: {required: reqs, actual: userData}, + suspectStartDate: suspect.start_date, + }); + return true; + } + return false; +} + export const actions: {[k: string]: QueryHandler} = { async register(params) { this.verifyCrossDomainRequest(); @@ -372,43 +417,7 @@ export const actions: {[k: string]: QueryHandler} = { if (suspect) { const reqs = {elo: suspect.elo, gxe: suspect.gxe, coil: suspect.gxe}; for (const rating of [p1rating, p2rating]) { - let reqsMet = 0; - let reqCount = 0; - const userData: Partial<{elo: number, gxe: number, coil: number}> = {}; - for (const k in reqs) { - if (!reqs[k as 'elo' | 'coil' | 'gxe']) continue; - reqCount++; - switch (k) { - case 'coil': - const N = rating.w + rating.l + rating.t; - const coilNum = Math.round(40.0 * rating.gxe * Math.pow(2.0, -coil[formatid] / N)); - if (coilNum >= reqs.coil!) { - reqsMet++; - } - userData.coil = coilNum; - break; - case 'elo': case 'gxe': - if (reqs[k] && rating[k] >= reqs[k]!) { - reqsMet++; - } - userData[k] = rating[k]; - break; - } - } - const ratingData = await ladder.getRating(rating.userid); - if ( - // sanity check for reqs existing just to be totally safe - (reqsMet >= 1 && reqsMet === reqCount) && - // did not play games before the test began - (ratingData?.first_played && ratingData.first_played > suspect.start_date) - ) { - void smogonFetch("tools/api/suspect-verify", "POST", { - userid: rating.userid, - format: formatid, - reqs: {required: reqs, actual: userData}, - suspectStartDate: suspect.start_date, - }); - } + checkSuspectVerified(rating, suspect, reqs); } } out.actionsuccess = true; @@ -1076,6 +1085,22 @@ export const actions: {[k: string]: QueryHandler} = { await tables.suspects.delete(id); return {success: true}; }, + async 'suspects/verify'(params) { + if (this.getIp() !== Config.restartip) { + throw new ActionError("Access denied."); + } + const id = toID(params.format); + if (!id) throw new ActionError("No format ID specified."); + const suspect = await tables.suspects.get(id); + if (!suspect) throw new ActionError("There is no ongoing suspect for " + id); + const userid = toID(params.userid); + if (!userid || userid.length > 18) throw new ActionError("Invalid userid Pprovided."); + const rating = await tables.ladder.get(userid); + if (!rating) throw new ActionError("That user has no ratings in the given ladder."); + return { + result: checkSuspectVerified(rating, suspect, {elo: suspect.elo, coil: suspect.coil, gxe: suspect.gxe}), + }; + }, }; if (Config.actions) { diff --git a/src/schemas/ntbb-suspects.sql b/src/schemas/ntbb-suspects.sql index 44f0818..416377b 100644 --- a/src/schemas/ntbb-suspects.sql +++ b/src/schemas/ntbb-suspects.sql @@ -2,7 +2,7 @@ -- Unfortunately necessary to be a table in order to properly synchronize -- cross-processes -CREATE TABLE ntbb_suspects ( +CREATE TABLE `ntbb_suspects` ( formatid varchar(100) NOT NULL PRIMARY KEY, start_date bigint(20) NOT NULL, elo int, diff --git a/src/tables.ts b/src/tables.ts index 3bc893b..66ad679 100644 --- a/src/tables.ts +++ b/src/tables.ts @@ -149,4 +149,4 @@ export const suspects = psdb.getTable<{ coil: number | null; gxe: number | null; elo: number | null; -}>("ntbb_suspects", 'formatid'); +}>("suspects", 'formatid');