Slight restructure, updated auth, implement player and game endpoints

This commit is contained in:
jd
2026-02-18 21:32:28 +00:00
parent 99c7bdc0fd
commit 2996a2eb95
32 changed files with 2093 additions and 266 deletions

View File

@@ -1,31 +1,103 @@
import {orm} from "../orm/orm";
import jwt from "jsonwebtoken";
import {UnwrappedRequest} from "../utilities/guard";
import {ErrorResponse} from "../utilities/responseHelper";
import {Claims} from "../orm/claims";
import {UnauthorizedError} from "../utilities/errors";
import { orm } from '../orm/orm';
import jwt from 'jsonwebtoken';
import { UnwrappedRequest } from '../utilities/guard';
import { ErrorResponse, OkResponse, UnauthorizedResponse } from '../utilities/responseHelper';
import { Claims } from '../orm/claims';
import { UnauthorizedError } from '../utilities/errors';
import { ChangePasswordRequest, LoginRequest, SecureId } from '../utilities/requestModels';
async function login(request: UnwrappedRequest): Promise<Response> {
try {
const requestBody = request.json;
console.log(`/api/auth/login: username=${requestBody.username}`);
const claims: Claims | null = await orm.users.verify(requestBody.username, requestBody.password);
console.log(claims);
if (claims) {
const token = jwt.sign({...claims}, process.env.JWT_SECRET_KEY as string, {expiresIn: "24h"});
return Response.json({token: token, claims: claims}, {status: 200});
const requestBody = request.body as LoginRequest;
const verify: {
userId: SecureId;
refreshCount: string;
} | null = await orm.users.verifyCredentials(requestBody.username, requestBody.password);
if (!verify) {
throw new UnauthorizedError('Invalid credentials');
}
throw new UnauthorizedError('Invalid credentials');
// Build refresh token that expires in 30 days, return as secure HTTP only cookie.
const tokenLifeSpanInDays = 30;
const token = jwt.sign(
{
u: verify.userId.raw,
r: verify.refreshCount,
},
process.env.JWT_SECRET_KEY as string,
{ expiresIn: `${tokenLifeSpanInDays * 24}h` },
);
const cookies = request?.request?.cookies;
cookies?.set({
name: 'refresh',
value: token,
httpOnly: true,
secure: true,
maxAge: tokenLifeSpanInDays * 24 * 60 * 60,
});
return new OkResponse();
} catch (error: any) {
return new ErrorResponse(error as Error);
}
}
async function test(request: UnwrappedRequest) {
return Response.json(request.claims, {status: 200});
async function token(request: UnwrappedRequest): Promise<Response> {
try {
const cookies = request.request.cookies;
const refreshCookie = cookies.get('refresh');
if (!refreshCookie) {
throw new UnauthorizedError('No refresh token found');
}
const refreshToken: {
u: string;
r: string;
} = jwt.verify(refreshCookie, process.env.JWT_SECRET_KEY as string) as { u: string; r: string };
if (!(await orm.users.verifyRefreshCount(SecureId.fromID(refreshToken.u), refreshToken.r))) {
const response = new UnauthorizedResponse('Invalid refresh token');
response.headers.set('Clear-Site-Data', '"cookies","cache","storage","executionContexts"');
return response;
}
const claims: Claims | null = await orm.claims.getByUserId(refreshToken.u);
const token = jwt.sign({ ...claims }, process.env.JWT_SECRET_KEY as string, { expiresIn: '1h' });
return new OkResponse({ token });
} catch (error: any) {
return new ErrorResponse(error as Error);
}
}
async function logout(request: UnwrappedRequest): Promise<Response> {
try {
const response = new OkResponse();
response.headers.set('Clear-Site-Data', '"cookies","cache","storage","executionContexts"');
return response;
} catch (error: any) {
return new ErrorResponse(error as Error);
}
}
async function changePassword(request: UnwrappedRequest): Promise<Response> {
try {
const requestBody = request.body as ChangePasswordRequest;
return new OkResponse(
await orm.users.changePassword(
SecureId.fromHash(request.params.id),
requestBody.oldPassword,
requestBody.newPassword,
request.claims,
),
);
} catch (error: any) {
return new ErrorResponse(error as Error);
}
}
export default {
login,
test
};
token,
logout,
changePassword,
};