Add an action to manually check if a user is verified for a suspect

For fallbacks, mostly. Shouldn't truly be needed.
This commit is contained in:
Mia 2024-10-27 16:04:42 -05:00
parent 735b408ed0
commit 72661ecf4a
3 changed files with 65 additions and 40 deletions

View File

@ -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<string, number | null>
) {
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) {

View File

@ -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,

View File

@ -149,4 +149,4 @@ export const suspects = psdb.getTable<{
coil: number | null;
gxe: number | null;
elo: number | null;
}>("ntbb_suspects", 'formatid');
}>("suspects", 'formatid');