Replace legacy checkBodyType with Zod
Start matchmaking integration Start rooms API Move existing room scene locations to roomtypes file Auth checkExpired util for client refreshing
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { APIUtils } from "../../apiutils.ts";
|
||||
import express from "express";
|
||||
import Profile from "../../data/profiles.ts";
|
||||
import { z } from "zod";
|
||||
|
||||
export const route = APIUtils.createRouter("/account");
|
||||
|
||||
@@ -10,6 +11,12 @@ interface CreateAccountRequestBody {
|
||||
deviceId: string;
|
||||
}
|
||||
|
||||
const CreateAccountRequestBodySchema = z.object({
|
||||
platform: z.string(),
|
||||
platformId: z.string(),
|
||||
deviceId: z.string()
|
||||
});
|
||||
|
||||
const rateLimit = new APIUtils.RateLimiter(25, 5);
|
||||
|
||||
route.router.post("/create",
|
||||
@@ -17,11 +24,7 @@ route.router.post("/create",
|
||||
rateLimit.middle(),
|
||||
APIUtils.Authentication,
|
||||
express.urlencoded({ extended: true }),
|
||||
APIUtils.checkBodyTypes<CreateAccountRequestBody>({
|
||||
platform: "",
|
||||
platformId: "",
|
||||
deviceId: "",
|
||||
}),
|
||||
APIUtils.validateRequestBody(CreateAccountRequestBodySchema),
|
||||
|
||||
async (_rq, rs) => {
|
||||
const newAcc = await Profile.init();
|
||||
@@ -33,6 +36,7 @@ route.router.post("/create",
|
||||
value: await newAcc.export(),
|
||||
});
|
||||
},
|
||||
|
||||
);
|
||||
|
||||
route.router.get("/bulk",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { APIUtils, NoBody } from "../../apiutils.ts";
|
||||
import express from "express";
|
||||
import Logging from "@proxnet/undead-logging";
|
||||
import { z } from "zod";
|
||||
|
||||
const log = new Logging("PlayerReportingRoute");
|
||||
|
||||
@@ -10,11 +11,15 @@ interface HileMessage {
|
||||
Message: string;
|
||||
}
|
||||
|
||||
const HileMessageSchema = z.object({
|
||||
Message: z.string()
|
||||
});
|
||||
|
||||
route.router.post('/v1/hile',
|
||||
|
||||
APIUtils.Authentication,
|
||||
express.json(),
|
||||
APIUtils.checkBodyTypes<HileMessage>({Message: ""}),
|
||||
APIUtils.validateRequestBody(HileMessageSchema),
|
||||
|
||||
(rq: express.Request<NoBody, NoBody, HileMessage>, rs) => {
|
||||
rs.sendStatus(204);
|
||||
|
||||
@@ -4,6 +4,7 @@ import Profile from "../../data/profiles.ts";
|
||||
import { decode } from "@gz/jwt";
|
||||
import { Config } from "../../config.ts";
|
||||
import Logging from "@proxnet/undead-logging";
|
||||
import { z } from "zod";
|
||||
|
||||
const config = Config.getConfig();
|
||||
|
||||
@@ -35,6 +36,35 @@ interface RefreshRequest extends AuthBodyBase {
|
||||
|
||||
type TokenRequestBody = TokenRequest | RefreshRequest;
|
||||
|
||||
const AuthBodyBaseSchema = z.object({
|
||||
grant_type: z.string(),
|
||||
client_id: z.string(),
|
||||
client_secret: z.string(),
|
||||
platform: z.string(),
|
||||
platform_id: z.string(),
|
||||
device_id: z.string(),
|
||||
device_class: z.string(),
|
||||
time: z.string(),
|
||||
ver: z.string(),
|
||||
asid: z.string(),
|
||||
platform_auth: z.string(),
|
||||
});
|
||||
|
||||
const TokenRequestSchema = AuthBodyBaseSchema.extend({
|
||||
grant_type: z.literal('cached_login'),
|
||||
account_id: z.string(),
|
||||
});
|
||||
|
||||
const RefreshRequestSchema = AuthBodyBaseSchema.extend({
|
||||
grant_type: z.literal('refresh_token'),
|
||||
refresh_token: z.string(),
|
||||
});
|
||||
|
||||
const TokenRequestBodySchema = z.discriminatedUnion('grant_type', [
|
||||
TokenRequestSchema,
|
||||
RefreshRequestSchema,
|
||||
]);
|
||||
|
||||
interface TokenResponseBody {
|
||||
error?: string;
|
||||
error_description?: string;
|
||||
@@ -47,19 +77,7 @@ route.router.post("/token",
|
||||
APIUtils.Authentication,
|
||||
express.urlencoded({ extended: true }),
|
||||
APIUtils.logBody,
|
||||
APIUtils.checkBodyTypes<AuthBodyBase>({
|
||||
grant_type: "",
|
||||
client_id: "",
|
||||
client_secret: "",
|
||||
platform: "",
|
||||
platform_id: "",
|
||||
device_id: "",
|
||||
device_class: "",
|
||||
time: "",
|
||||
ver: "",
|
||||
asid: "",
|
||||
platform_auth: ""
|
||||
}),
|
||||
APIUtils.validateRequestBody<AuthBodyBase>(TokenRequestBodySchema),
|
||||
|
||||
async (
|
||||
rq: express.Request<NoBody, NoBody, TokenRequestBody>,
|
||||
|
||||
6
src/routes/match.ts
Normal file
6
src/routes/match.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { APIUtils } from "../apiutils.ts";
|
||||
import { route as PlayerRoute } from "./match/player.ts";
|
||||
|
||||
export const route = APIUtils.createRouter('/match');
|
||||
|
||||
route.router.use(PlayerRoute.path, PlayerRoute.router);
|
||||
26
src/routes/match/player.ts
Normal file
26
src/routes/match/player.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { z } from "zod";
|
||||
import { APIUtils } from "../../apiutils.ts";
|
||||
import express from "express";
|
||||
|
||||
export const route = APIUtils.createRouter('/player');
|
||||
|
||||
interface BaseLoginLock {
|
||||
LoginLock: string
|
||||
}
|
||||
|
||||
const LoginSchema = z.object({
|
||||
LoginLock: z.string().uuid("LoginLock must be a UUIDv4")
|
||||
});
|
||||
|
||||
route.router.post('/login',
|
||||
|
||||
APIUtils.Authentication,
|
||||
express.urlencoded({extended: true}),
|
||||
APIUtils.validateRequestBody(LoginSchema),
|
||||
|
||||
(rq, rs) => {
|
||||
// temporary
|
||||
rs.sendStatus(200);
|
||||
},
|
||||
|
||||
)
|
||||
@@ -1,10 +1,12 @@
|
||||
import { APIUtils, getSrcIpDefault, NoBody } from "../apiutils.ts";
|
||||
// @ts-types = "npm:@types/express"
|
||||
import express from "express";
|
||||
import { User } from "../data/users.ts";
|
||||
import { User, UserTokenFormat } from "../data/users.ts";
|
||||
import { Config } from "../config.ts";
|
||||
import crypto from "node:crypto";
|
||||
import Logging from "@proxnet/undead-logging";
|
||||
import { decode } from "@gz/jwt";
|
||||
import z from "zod";
|
||||
|
||||
const log = new Logging("UserRoute");
|
||||
|
||||
@@ -25,22 +27,27 @@ interface AuthRequestRoot {
|
||||
pubkey: string;
|
||||
}
|
||||
|
||||
const AuthRequestSecSchema = z.object({
|
||||
timestamp: z.number(),
|
||||
nonce: z.string(),
|
||||
server_id: z.string(),
|
||||
});
|
||||
|
||||
const AuthRequestRootSchema = z.object({
|
||||
client_id: z.string(),
|
||||
message: AuthRequestSecSchema,
|
||||
signature: z.string(),
|
||||
pubkey: z.string(),
|
||||
});
|
||||
|
||||
const rateLimit = new APIUtils.RateLimiter(60, 1);
|
||||
|
||||
route.router.post(
|
||||
"/auth",
|
||||
route.router.post("/auth",
|
||||
|
||||
rateLimit.middle(),
|
||||
express.json(),
|
||||
APIUtils.checkBodyTypes<AuthRequestRoot>({
|
||||
client_id: "asdf",
|
||||
message: {
|
||||
timestamp: 0,
|
||||
nonce: "asdf",
|
||||
server_id: "asdf",
|
||||
},
|
||||
signature: "asdf",
|
||||
pubkey: "asdf",
|
||||
}),
|
||||
APIUtils.validateRequestBody(AuthRequestRootSchema),
|
||||
|
||||
async (
|
||||
rq: express.Request<NoBody, NoBody, AuthRequestRoot>,
|
||||
rs: express.Response,
|
||||
@@ -101,6 +108,7 @@ route.router.post(
|
||||
pubkey: rq.body.pubkey,
|
||||
});
|
||||
if (obj == null) {
|
||||
log.w(`Obj null`);
|
||||
rs.sendStatus(500);
|
||||
return;
|
||||
} else user = obj;
|
||||
@@ -118,3 +126,22 @@ route.router.post(
|
||||
rs.json({ token: token });
|
||||
},
|
||||
);
|
||||
|
||||
const checkRateLimit = new APIUtils.RateLimiter(10, 3);
|
||||
|
||||
route.router.get('/checkExpired', checkRateLimit.middle(), async (rq, rs) => {
|
||||
|
||||
const token = rq.header('GalvanicAuth');
|
||||
if (!token) {
|
||||
rs.json(true);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const decodedToken = await decode<UserTokenFormat>(token, config.auth.secret, { algorithm: "HS512", leeway: 31536000 }); // 1 year leeway
|
||||
rs.json(decodedToken.exp < Math.round(Date.now() / 1000));
|
||||
} catch {
|
||||
rs.json(true);
|
||||
}
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user