rename SYMBOL_TachiAPIData to TachiAPIAuth

This commit is contained in:
zkldi
2021-06-16 20:11:17 +01:00
parent 4760df19d9
commit 0248e4e5de
19 changed files with 213 additions and 48 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
import { Session, SessionData } from "express-session";
import { SYMBOL_TachiAPIData, SYMBOL_TachiData } from "../../src/lib/constants/tachi";
import { SYMBOL_TachiAPIAuth, SYMBOL_TachiData } from "../../src/lib/constants/tachi";
import { TachiRequestData, TachiSessionData } from "../../src/utils/types";
import { APITokenDocument } from "tachi-common";
@@ -21,7 +21,7 @@ declare global {
[SYMBOL_TachiData]?: Partial<TachiRequestData>;
// even though this is technically *not* present on every request
// it's always assigned in the main router, so its functionally equivalent.
[SYMBOL_TachiAPIData]: APITokenDocument;
[SYMBOL_TachiAPIAuth]: APITokenDocument;
}
}
}
+1 -1
View File
@@ -1,2 +1,2 @@
export const SYMBOL_TachiData = Symbol("tachi-request-patch");
export const SYMBOL_TachiAPIData = Symbol("tachi-api-auth-info");
export const SYMBOL_TachiAPIAuth = Symbol("tachi-api-auth-info");
+4 -4
View File
@@ -2,7 +2,7 @@ import t from "tap";
import { SetRequestPermissions, AllPermissions, RequireNotGuest, RequirePermissions } from "./auth";
import expMiddlewareMock from "express-request-mock";
import db from "../../external/mongo/db";
import { SYMBOL_TachiAPIData } from "../../lib/constants/tachi";
import { SYMBOL_TachiAPIAuth } from "../../lib/constants/tachi";
import { CloseAllConnections } from "../../test-utils/close-connections";
t.test("#SetRequestPermissions", (t) => {
@@ -22,7 +22,7 @@ t.test("#SetRequestPermissions", (t) => {
},
});
t.strictSame(req[SYMBOL_TachiAPIData], {
t.strictSame(req[SYMBOL_TachiAPIAuth], {
userID: 1,
identifier: "Mock API Token",
permissions: {
@@ -37,7 +37,7 @@ t.test("#SetRequestPermissions", (t) => {
t.test("Should assign guest APIKey information if no auth present", async (t) => {
const { req } = await expMiddlewareMock(SetRequestPermissions);
t.strictSame(req[SYMBOL_TachiAPIData], {
t.strictSame(req[SYMBOL_TachiAPIAuth], {
userID: null,
identifier: "Guest Token",
permissions: {},
@@ -101,7 +101,7 @@ t.test("#SetRequestPermissions", (t) => {
},
});
t.strictSame(req[SYMBOL_TachiAPIData], {
t.strictSame(req[SYMBOL_TachiAPIAuth], {
userID: 1,
identifier: `Session-Key 1`,
token: null,
+9 -9
View File
@@ -1,6 +1,6 @@
import { RequestHandler } from "express";
import db from "../../external/mongo/db";
import { SYMBOL_TachiAPIData } from "../../lib/constants/tachi";
import { SYMBOL_TachiAPIAuth } from "../../lib/constants/tachi";
import { SplitAuthorizationHeader } from "../../utils/misc";
import { APITokenDocument, APIPermissions } from "tachi-common";
import CreateLogCtx from "../../lib/logger/logger";
@@ -36,7 +36,7 @@ export const AllPermissions: Record<APIPermissions, true> = {
*/
export const SetRequestPermissions: RequestHandler = async (req, res, next) => {
if (req.session?.tachi?.userID) {
req[SYMBOL_TachiAPIData] = {
req[SYMBOL_TachiAPIAuth] = {
userID: req.session.tachi.userID,
identifier: `Session-Key ${req.session.tachi.userID}`,
token: null,
@@ -49,7 +49,7 @@ export const SetRequestPermissions: RequestHandler = async (req, res, next) => {
// if no auth was attempted, default to the guest token.
if (!header) {
req[SYMBOL_TachiAPIData] = GuestToken;
req[SYMBOL_TachiAPIAuth] = GuestToken;
return next();
}
@@ -80,7 +80,7 @@ export const SetRequestPermissions: RequestHandler = async (req, res, next) => {
});
}
req[SYMBOL_TachiAPIData] = {
req[SYMBOL_TachiAPIAuth] = {
userID: apiTokenData.userID,
token,
permissions: apiTokenData.permissions,
@@ -98,7 +98,7 @@ export const SetRequestPermissions: RequestHandler = async (req, res, next) => {
export const RequirePermissions =
(...perms: APIPermissions[]): RequestHandler =>
(req, res, next) => {
if (!req[SYMBOL_TachiAPIData]) {
if (!req[SYMBOL_TachiAPIAuth]) {
logger.error(`RequirePermissions middleware was hit without any TachiAPIData?`);
return res.status(500).json({
@@ -109,7 +109,7 @@ export const RequirePermissions =
const missingPerms = [];
for (const perm of perms) {
if (!req[SYMBOL_TachiAPIData]!.permissions[perm]) {
if (!req[SYMBOL_TachiAPIAuth]!.permissions[perm]) {
missingPerms.push(perm);
}
}
@@ -117,7 +117,7 @@ export const RequirePermissions =
if (missingPerms.length > 0) {
logger.info(
`IP ${req.ip} - userID ${
req[SYMBOL_TachiAPIData].userID
req[SYMBOL_TachiAPIAuth].userID
} had insufficient permissions for request ${req.method} ${
req.url
}. ${missingPerms.join(", ")}`
@@ -134,7 +134,7 @@ export const RequirePermissions =
};
export const RequireNotGuest: RequestHandler = (req, res, next) => {
if (!req[SYMBOL_TachiAPIData]) {
if (!req[SYMBOL_TachiAPIAuth]) {
logger.error(`RequirePermissions middleware was hit without any TachiAPIData?`);
return res.status(500).json({
success: false,
@@ -142,7 +142,7 @@ export const RequireNotGuest: RequestHandler = (req, res, next) => {
});
}
if (!req[SYMBOL_TachiAPIData].userID) {
if (!req[SYMBOL_TachiAPIAuth].userID) {
logger.info(`Request to ${req.method} ${req.url} was attempted by guest.`);
return res.status(401).json({
success: false,
@@ -1,5 +1,5 @@
import { Router } from "express";
import { SYMBOL_TachiAPIData } from "../../../../../lib/constants/tachi";
import { SYMBOL_TachiAPIAuth } from "../../../../../lib/constants/tachi";
import { FormatVersion } from "../../../../../lib/constants/version";
const router: Router = Router({ mergeParams: true });
@@ -17,7 +17,7 @@ router.get("/", (req, res) => {
serverTime: Date.now(),
version: FormatVersion(),
// converts {foo: true, bar: false, baz: true} into [foo, baz]
permissions: Object.entries(req[SYMBOL_TachiAPIData].permissions)
permissions: Object.entries(req[SYMBOL_TachiAPIAuth].permissions)
.filter((e) => e[1])
.map((e) => e[0]),
echo,
@@ -38,7 +38,7 @@ router.post("/", (req, res) => {
serverTime: Date.now(),
version: FormatVersion(),
// converts {foo: true, bar: false, baz: true} into [foo, baz]
permissions: Object.entries(req[SYMBOL_TachiAPIData].permissions)
permissions: Object.entries(req[SYMBOL_TachiAPIAuth].permissions)
.filter((e) => e[1])
.map((e) => e[0]),
echo,
@@ -0,0 +1,40 @@
import { RequestHandler } from "express";
import db from "../../../../../../../../../external/mongo/db";
import { SYMBOL_TachiData } from "../../../../../../../../../lib/constants/tachi";
import { IsValidGame, IsValidPlaytype } from "../../../../../../../../../utils/misc";
import { AssignToReqTachiData } from "../../../../../../../../../utils/req-tachi-data";
export const CheckUserPlayedGamePlaytype: RequestHandler = async (req, res, next) => {
const user = req[SYMBOL_TachiData]!.requestedUser!;
if (!IsValidGame(req.params.game)) {
return res.status(400).json({
success: false,
description: `The game ${req.params.game} is not supported.`,
});
}
if (!IsValidPlaytype(req.params.game, req.params.playtype)) {
return res.status(400).json({
success: false,
description: `The game ${req.params.game} does not have a playtype called ${req.params.playtype}.`,
});
}
const stats = await db["game-stats"].findOne({
userID: user.id,
game: req.params.game,
playtype: req.params.playtype,
});
if (!stats) {
return res.status(404).json({
success: false,
description: `The user ${user.username} has not played ${req.params.game} (${req.params.playtype})`,
});
}
AssignToReqTachiData(req, { requestedUserGameStats: stats });
return next();
};
@@ -0,0 +1,24 @@
import { Router } from "express";
import { SYMBOL_TachiData } from "../../../../../../../../../lib/constants/tachi";
import { CheckUserPlayedGamePlaytype } from "./middleware";
const router: Router = Router({ mergeParams: true });
router.use(CheckUserPlayedGamePlaytype);
/**
* Returns information about a user for this game + playtype.
* @name GET /api/v1/users/:userID/games/:game/:playtype
*/
router.use("/", async (req, res) => {
const user = req[SYMBOL_TachiData]!.requestedUser!;
const stats = req[SYMBOL_TachiData]!.requestedUserGameStats!;
return res.status(200).json({
success: true,
description: `Retrieved user statistics for ${user.username} (${req.params.game} ${req.params.playtype})`,
body:
});
});
export default router;
@@ -0,0 +1,25 @@
import { RequestHandler } from "express";
import { AssignToReqTachiData } from "../../../../../../utils/req-tachi-data";
import { ResolveUser } from "../../../../../../utils/user";
export const GetUserFromParam: RequestHandler = async (req, res, next) => {
if (!req.params.userID) {
return res.status(400).json({
success: false,
description: "No userID given.",
});
}
const user = await ResolveUser(req.params.userID);
if (!user) {
return res.status(404).json({
success: false,
description: `The user ${req.params.userID} does not exist.`,
});
}
AssignToReqTachiData(req, { requestedUser: user });
return next();
};
@@ -0,0 +1,43 @@
import { Router } from "express";
import db from "../../../../../../external/mongo/db";
import { SYMBOL_TachiData } from "../../../../../../lib/constants/tachi";
import { GetUserFromParam } from "./middleware";
const router: Router = Router({ mergeParams: true });
router.use(GetUserFromParam);
/**
* Get the user at this ID or name.
* @name GET /api/v1/users/:userID
*/
router.get("/", (req, res) => {
const user = req[SYMBOL_TachiData]!.requestedUser!;
return res.status(200).json({
success: true,
description: `Found user ${user.username}.`,
body: user,
});
});
/**
* Returns all of the game-stats this user has.
* This endpoint doubles up as a way of checking what games a user has played.
*
* @name GET /api/v1/users/:userID/stats
*/
router.get("/stats", async (req, res) => {
const user = req[SYMBOL_TachiData]!.requestedUser!;
// a user has played a game if and only if they have stats for it.
const stats = await db["game-stats"].find({ userID: user.id });
return res.status(200).json({
success: true,
description: `Returned ${stats.length} stats objects.`,
body: stats,
});
});
export default router;
@@ -0,0 +1,19 @@
import { Router } from "express";
import db from "../../../../../external/mongo/db";
import userIDRouter from "./!userID/router";
const router: Router = Router({ mergeParams: true });
/**
* List Users.
* @param online - Only return online users.
* @param username - Return users similar to this username.
* @name GET /api/v1/users
*/
router.get("/", async (req, res) => {
// i dont know yet.
});
router.use("/:userID", userIDRouter);
export default router;
@@ -3,7 +3,7 @@ import { GetUserWithIDGuaranteed } from "../../../../utils/user";
import { ExpressWrappedScoreImportMain } from "../../../../lib/score-import/framework/express-wrapper";
import { ParseBarbatosSingle } from "../../../../lib/score-import/import-types/ir/barbatos/parser";
import { RequirePermissions } from "../../../middleware/auth";
import { SYMBOL_TachiAPIData } from "../../../../lib/constants/tachi";
import { SYMBOL_TachiAPIAuth } from "../../../../lib/constants/tachi";
const router: Router = Router({ mergeParams: true });
@@ -14,7 +14,7 @@ router.use(RequirePermissions("submit:score"));
* @name POST /ir/barbatos/score/submit
*/
router.post("/score/submit", async (req, res) => {
const userDoc = await GetUserWithIDGuaranteed(req[SYMBOL_TachiAPIData]!.userID!);
const userDoc = await GetUserWithIDGuaranteed(req[SYMBOL_TachiAPIAuth]!.userID!);
const responseData = await ExpressWrappedScoreImportMain(
userDoc,
@@ -1,7 +1,7 @@
import { ChartDocument, PBScoreDocument } from "tachi-common";
import { Router, RequestHandler } from "express";
import db from "../../../../../external/mongo/db";
import { SYMBOL_TachiAPIData, SYMBOL_TachiData } from "../../../../../lib/constants/tachi";
import { SYMBOL_TachiAPIAuth, SYMBOL_TachiData } from "../../../../../lib/constants/tachi";
import { TachiPBScoreToBeatorajaFormat } from "./convert-scores";
import { AssignToReqTachiData } from "../../../../../utils/req-tachi-data";
@@ -41,7 +41,7 @@ router.get("/scores", async (req, res) => {
// @optimisable - This should be solved with a couple queries and a hashmap.
const beatorajaScores = await Promise.all(
scores.map((e) =>
TachiPBScoreToBeatorajaFormat(e, chart, req[SYMBOL_TachiAPIData]!.userID!)
TachiPBScoreToBeatorajaFormat(e, chart, req[SYMBOL_TachiAPIAuth]!.userID!)
)
);
@@ -1,6 +1,6 @@
import { Router } from "express";
import db from "../../../../external/mongo/db";
import { SYMBOL_TachiAPIData } from "../../../../lib/constants/tachi";
import { SYMBOL_TachiAPIAuth } from "../../../../lib/constants/tachi";
import CreateLogCtx, { KtLogger } from "../../../../lib/logger/logger";
import { ExpressWrappedScoreImportMain } from "../../../../lib/score-import/framework/express-wrapper";
import { ParseBeatorajaSingle } from "../../../../lib/score-import/import-types/ir/beatoraja/parser";
@@ -21,7 +21,7 @@ router.use(ValidateIRClientVersion);
* @name POST /ir/beatoraja/submit-score
*/
router.post("/submit-score", async (req, res) => {
const userDoc = await GetUserWithIDGuaranteed(req[SYMBOL_TachiAPIData]!.userID!);
const userDoc = await GetUserWithIDGuaranteed(req[SYMBOL_TachiAPIAuth]!.userID!);
const ParserFunction = (logger: KtLogger) => ParseBeatorajaSingle(req.body, logger);
@@ -164,7 +164,7 @@ router.post("/submit-course", async (req, res) => {
});
}
const userID = req[SYMBOL_TachiAPIData]!.userID!;
const userID = req[SYMBOL_TachiAPIAuth]!.userID!;
const result = await UpdateClassIfGreater(
userID,
@@ -3,7 +3,7 @@ import { GetUserWithIDGuaranteed } from "../../../../utils/user";
import { ExpressWrappedScoreImportMain } from "../../../../lib/score-import/framework/express-wrapper";
import ParseDirectManual from "../../../../lib/score-import/import-types/ir/direct-manual/parser";
import { RequirePermissions } from "../../../middleware/auth";
import { SYMBOL_TachiAPIData } from "../../../../lib/constants/tachi";
import { SYMBOL_TachiAPIAuth } from "../../../../lib/constants/tachi";
const router: Router = Router({ mergeParams: true });
@@ -12,7 +12,7 @@ const router: Router = Router({ mergeParams: true });
* @name POST /ir/chunitachi/score/submit
*/
router.post("/import", RequirePermissions("submit:score"), async (req, res) => {
const userDoc = await GetUserWithIDGuaranteed(req[SYMBOL_TachiAPIData].userID!);
const userDoc = await GetUserWithIDGuaranteed(req[SYMBOL_TachiAPIAuth].userID!);
if (req.body?.head?.game !== "chunithm") {
return res.status(400).json({
@@ -3,7 +3,7 @@ import { GetUserWithIDGuaranteed } from "../../../../utils/user";
import { RequireLoggedInSession } from "../../../middleware/require-logged-in";
import { ExpressWrappedScoreImportMain } from "../../../../lib/score-import/framework/express-wrapper";
import ParseDirectManual from "../../../../lib/score-import/import-types/ir/direct-manual/parser";
import { SYMBOL_TachiAPIData } from "../../../../lib/constants/tachi";
import { SYMBOL_TachiAPIAuth } from "../../../../lib/constants/tachi";
import { RequirePermissions } from "../../../middleware/auth";
const router: Router = Router({ mergeParams: true });
@@ -17,7 +17,7 @@ router.post(
RequirePermissions("submit:score"),
RequireLoggedInSession,
async (req, res) => {
const userDoc = await GetUserWithIDGuaranteed(req[SYMBOL_TachiAPIData].userID!);
const userDoc = await GetUserWithIDGuaranteed(req[SYMBOL_TachiAPIAuth].userID!);
const intent = req.header("X-User-Intent");
+12 -12
View File
@@ -9,7 +9,7 @@ import { ParseFervidexStatic } from "../../../../lib/score-import/import-types/i
import { ParseFervidexSingle } from "../../../../lib/score-import/import-types/ir/fervidex/parser";
import { Playtypes, integer } from "tachi-common";
import CreateLogCtx from "../../../../lib/logger/logger";
import { SYMBOL_TachiAPIData } from "../../../../lib/constants/tachi";
import { SYMBOL_TachiAPIAuth } from "../../../../lib/constants/tachi";
import { RequirePermissions } from "../../../middleware/auth";
const logger = CreateLogCtx(__filename);
@@ -21,7 +21,7 @@ const ValidateFervidexHeader: RequestHandler = (req, res, next) => {
if (!agent) {
logger.debug(
`Rejected fervidex client with no agent from user ${req[SYMBOL_TachiAPIData].userID!}.`
`Rejected fervidex client with no agent from user ${req[SYMBOL_TachiAPIAuth].userID!}.`
);
return res.status(400).json({
success: false,
@@ -32,7 +32,7 @@ const ValidateFervidexHeader: RequestHandler = (req, res, next) => {
if (!agent.startsWith("fervidex/")) {
logger.info(
`Rejected fervidex client with invalid agent ${agent} from user ${req[
SYMBOL_TachiAPIData
SYMBOL_TachiAPIAuth
].userID!}.`
);
return res.status(400).json({
@@ -46,7 +46,7 @@ const ValidateFervidexHeader: RequestHandler = (req, res, next) => {
if (!versions.every((e) => !Number.isNaN(e))) {
logger.info(
`Rejected fervidex client with agent ${agent} for NaN-like versions from user ${req[
SYMBOL_TachiAPIData
SYMBOL_TachiAPIAuth
].userID!}.`
);
return res.status(400).json({
@@ -58,7 +58,7 @@ const ValidateFervidexHeader: RequestHandler = (req, res, next) => {
// version.minor
if (versions[1] < 3) {
logger.debug(
`Rejected outdated fervidex client from user ${req[SYMBOL_TachiAPIData].userID!}.`
`Rejected outdated fervidex client from user ${req[SYMBOL_TachiAPIAuth].userID!}.`
);
return res.status(400).json({
success: false,
@@ -74,7 +74,7 @@ const RequireInf2ModelHeader: RequestHandler = (req, res, next) => {
if (!swModel) {
logger.debug(
`Rejected empty X-Software-Model from user ${req[SYMBOL_TachiAPIData].userID!}.`
`Rejected empty X-Software-Model from user ${req[SYMBOL_TachiAPIAuth].userID!}.`
);
return res.status(400).json({
success: false,
@@ -86,7 +86,7 @@ const RequireInf2ModelHeader: RequestHandler = (req, res, next) => {
const softID = ParseEA3SoftID(swModel);
if (softID.model !== MODEL_INFINITAS_2) {
logger.debug(`Rejected non-inf2 model from user ${req[SYMBOL_TachiAPIData].userID!}.`);
logger.debug(`Rejected non-inf2 model from user ${req[SYMBOL_TachiAPIAuth].userID!}.`);
return res.status(400).send({
success: false,
description: "This endpoint is only available for INF2 clients.",
@@ -108,7 +108,7 @@ const ValidateModelHeader: RequestHandler = (req, res, next) => {
if (!swModel) {
logger.debug(
`Rejected empty X-Software Model from user ${req[SYMBOL_TachiAPIData].userID!}.`
`Rejected empty X-Software Model from user ${req[SYMBOL_TachiAPIAuth].userID!}.`
);
return res.status(400).json({
success: false,
@@ -132,7 +132,7 @@ const ValidateModelHeader: RequestHandler = (req, res, next) => {
if (softID.ext !== EXT_HEROIC_VERSE) {
logger.info(
`Rejected invalid Software Model ${softID.ext} from user ${req[SYMBOL_TachiAPIData]
`Rejected invalid Software Model ${softID.ext} from user ${req[SYMBOL_TachiAPIAuth]
.userID!}.`
);
return res.status(400).json({
@@ -162,7 +162,7 @@ router.use(RequirePermissions("submit:score"), ValidateFervidexHeader, ValidateM
* @name POST /ir/fervidex/profile/submit
*/
router.post("/profile/submit", RequireInf2ModelHeader, async (req, res) => {
const userDoc = await GetUserWithIDGuaranteed(req[SYMBOL_TachiAPIData].userID!);
const userDoc = await GetUserWithIDGuaranteed(req[SYMBOL_TachiAPIAuth].userID!);
const headers = {
// guaranteed to exist because of RequireInf2ModelHeader
@@ -187,7 +187,7 @@ router.post("/profile/submit", RequireInf2ModelHeader, async (req, res) => {
* @name POST /ir/fervidex/score/submit
*/
router.post("/score/submit", ValidateModelHeader, async (req, res) => {
const userDoc = await GetUserWithIDGuaranteed(req[SYMBOL_TachiAPIData].userID!);
const userDoc = await GetUserWithIDGuaranteed(req[SYMBOL_TachiAPIAuth].userID!);
const model = req.header("X-Software-Model");
@@ -250,7 +250,7 @@ router.post("/class/submit", ValidateModelHeader, async (req, res) => {
const playtype: Playtypes["iidx"] = req.body.play_style === 0 ? "SP" : "DP";
const r = await UpdateClassIfGreater(
req[SYMBOL_TachiAPIData].userID!,
req[SYMBOL_TachiAPIAuth].userID!,
"iidx",
playtype,
"dan",
+5 -5
View File
@@ -1,6 +1,6 @@
import { Router, RequestHandler } from "express";
import { FindChartOnSHA256 } from "../../../../utils/queries/charts";
import { SYMBOL_TachiAPIData, SYMBOL_TachiData } from "../../../../lib/constants/tachi";
import { SYMBOL_TachiAPIAuth, SYMBOL_TachiData } from "../../../../lib/constants/tachi";
import db from "../../../../external/mongo/db";
import {
ChartDocument,
@@ -65,7 +65,7 @@ const ValidateUSCRequest: RequestHandler = async (req, res, next) => {
});
}
req[SYMBOL_TachiAPIData] = uscAuthDoc;
req[SYMBOL_TachiAPIAuth] = uscAuthDoc;
return next();
};
@@ -261,10 +261,10 @@ router.post("/scores", RequirePermissions("submit:score"), async (req, res) => {
});
}
const userDoc = await GetUserWithID(req[SYMBOL_TachiAPIData]!.userID!);
const userDoc = await GetUserWithID(req[SYMBOL_TachiAPIAuth]!.userID!);
if (!userDoc) {
logger.severe(`User ${req[SYMBOL_TachiAPIData]!.userID!} as no parent userDoc?`);
logger.severe(`User ${req[SYMBOL_TachiAPIAuth]!.userID!} as no parent userDoc?`);
return res.status(200).json({
statusCode: STATUS_CODES.SERVER_ERROR,
description: "An internal server error has occured.",
@@ -334,7 +334,7 @@ router.post(
}
const correspondingScore = await db.scores.findOne({
userID: req[SYMBOL_TachiAPIData]!.userID!,
userID: req[SYMBOL_TachiAPIAuth]!.userID!,
game: "usc",
scoreID: req.body.identifier,
});
+11
View File
@@ -1,4 +1,7 @@
import crypto from "crypto";
import { CONF_INFO } from "../lib/setup/config";
import { Game, Playtypes } from "tachi-common";
import { validPlaytypes } from "tachi-common/js/config";
// https://github.com/sindresorhus/escape-string-regexp/blob/main/index.js
// the developer of this has migrated everything to Force ES6 style modules,
@@ -58,3 +61,11 @@ export function SplitAuthorizationHeader(authHeader: string) {
export function HasOwnProperty<T>(obj: T, key: string | number | symbol): key is keyof T {
return Object.prototype.hasOwnProperty.call(obj, key);
}
export function IsValidGame(str: string): str is Game {
return !!CONF_INFO.SUPPORTED_GAMES.includes(str as Game);
}
export function IsValidPlaytype(game: Game, str: string): str is Playtypes[Game] {
return validPlaytypes[game].includes(str as Playtypes[Game]);
}
+4 -1
View File
@@ -1,4 +1,4 @@
import { integer, ChartDocument } from "tachi-common";
import { integer, ChartDocument, PublicUserDocument, UserGameStats } from "tachi-common";
declare module "express-session" {
// Inject additional properties on express-session
@@ -36,4 +36,7 @@ export interface TachiRequestData {
uscChartDoc?: ChartDocument<"usc:Single">;
beatorajaChartDoc?: ChartDocument<"bms:7K" | "bms:14K">;
requestedUser?: PublicUserDocument;
requestedUserGameStats?: UserGameStats;
}