From d820e11cc3b87c45a6bafad91714db44b9107279 Mon Sep 17 00:00:00 2001 From: xangelo Date: Tue, 5 Sep 2023 11:39:00 -0400 Subject: [PATCH] feat: migrate to augmenting express.Request interface We were originally extending the express.Request interface inline in `src/server/auth.ts`, We are now just augmenting the actual express.Request interface via typescript definition. --- src/server/api.ts | 52 +++++++++++++++---------------- src/server/auth.ts | 6 +--- src/server/fight.ts | 5 ++- src/server/locations/healer.ts | 8 ++--- src/server/locations/recruiter.ts | 8 ++--- src/server/locations/repair.ts | 8 ++--- src/types/express/index.d.ts | 7 +++++ tsconfig.json | 31 +++++++++--------- 8 files changed, 64 insertions(+), 61 deletions(-) create mode 100644 src/types/express/index.d.ts diff --git a/src/server/api.ts b/src/server/api.ts index f167ff6..355bd04 100644 --- a/src/server/api.ts +++ b/src/server/api.ts @@ -22,7 +22,7 @@ import {FightTrigger, Monster, MonsterForFight} from '../shared/monsters'; import {getShopEquipment, listShopItems } from './shopEquipment'; import {EquipmentSlot} from '../shared/inventory'; import { clearTravelPlan, completeTravel, getAllPaths, getAllServices, getCityDetails, getService, getTravelPlan, stepForward, travel } from './map'; -import { signup, login, authEndpoint, AuthRequest } from './auth'; +import { signup, login, authEndpoint } from './auth'; import {db} from './lib/db'; import { getPlayerSkills} from './skills'; @@ -150,13 +150,13 @@ app.use(professionRouter); app.use(repairRouter); -app.get('/chat/history', authEndpoint, async (req: AuthRequest, res: Response) => { +app.get('/chat/history', authEndpoint, async (req: Request, res: Response) => { let html = chatHistory.map(renderChatMessage); res.send(html.join("\n")); }); -app.post('/chat', authEndpoint, async (req: AuthRequest, res: Response) => { +app.post('/chat', authEndpoint, async (req: Request, res: Response) => { const msg = req.body.message.trim(); if(!msg || !msg.length) { @@ -207,12 +207,12 @@ app.post('/chat', authEndpoint, async (req: AuthRequest, res: Response) => { } }); -app.get('/player', authEndpoint, async (req: AuthRequest, res: Response) => { +app.get('/player', authEndpoint, async (req: Request, res: Response) => { const equipment = await getEquippedItems(req.player.id); res.send(renderPlayerBar(req.player) + renderProfilePage(req.player, equipment)); }); -app.post('/player/stat/:stat', authEndpoint, async (req: AuthRequest, res: Response) => { +app.post('/player/stat/:stat', authEndpoint, async (req: Request, res: Response) => { const equipment = await getEquippedItems(req.player.id); const stat = req.params.stat; if(!['strength', 'constitution', 'dexterity', 'intelligence'].includes(stat)) { @@ -235,13 +235,13 @@ app.post('/player/stat/:stat', authEndpoint, async (req: AuthRequest, res: Respo res.send(renderPlayerBar(req.player) + renderProfilePage(req.player, equipment)); }); -app.get('/player/skills', authEndpoint, async (req: AuthRequest, res: Response) => { +app.get('/player/skills', authEndpoint, async (req: Request, res: Response) => { const skills = await getPlayerSkills(req.player.id); res.send(renderSkills(skills)); }); -app.get('/player/inventory', authEndpoint, async (req: AuthRequest, res: Response) => { +app.get('/player/inventory', authEndpoint, async (req: Request, res: Response) => { const [inventory, items] = await Promise.all([ getInventory(req.player.id), getPlayersItems(req.player.id) @@ -250,7 +250,7 @@ app.get('/player/inventory', authEndpoint, async (req: AuthRequest, res: Respons res.send(renderInventoryPage(inventory, items)); }); -app.post('/player/equip/:item_id/:slot', authEndpoint, blockPlayerInFight, async (req: AuthRequest, res: Response) => { +app.post('/player/equip/:item_id/:slot', authEndpoint, blockPlayerInFight, async (req: Request, res: Response) => { const inventoryItem = await getInventoryItem(req.player.id, req.params.item_id); const equippedItems = await getEquippedItems(req.player.id); const requestedSlot = req.params.slot; @@ -302,7 +302,7 @@ app.post('/player/equip/:item_id/:slot', authEndpoint, blockPlayerInFight, async res.send(renderInventoryPage(inventory, items, inventoryItem.type) + renderPlayerBar(req.player)); }); -app.post('/player/unequip/:item_id', authEndpoint, blockPlayerInFight, async (req: AuthRequest, res: Response) => { +app.post('/player/unequip/:item_id', authEndpoint, blockPlayerInFight, async (req: Request, res: Response) => { const [item, ] = await Promise.all([ getInventoryItem(req.player.id, req.params.item_id), unequip(req.player.id, req.params.item_id) @@ -316,7 +316,7 @@ app.post('/player/unequip/:item_id', authEndpoint, blockPlayerInFight, async (re res.send(renderInventoryPage(inventory, items, item.type) + renderPlayerBar(req.player)); }); -app.get('/player/explore', authEndpoint, async (req: AuthRequest, res: Response) => { +app.get('/player/explore', authEndpoint, async (req: Request, res: Response) => { const fight = await loadMonsterFromFight(req.player.id); const travelPlan = await getTravelPlan(req.player.id); let closestTown = req.player.city_id; @@ -375,7 +375,7 @@ app.get('/player/explore', authEndpoint, async (req: AuthRequest, res: Response) }); // used to purchase equipment from a particular shop -app.put('/location/:location_id/equipment/:item_id', authEndpoint, async (req: AuthRequest, res: Response) => { +app.put('/location/:location_id/equipment/:item_id', authEndpoint, async (req: Request, res: Response) => { const item = await getShopEquipment(parseInt(req.params.item_id), parseInt(req.params.location_id)); if(!item) { @@ -397,7 +397,7 @@ app.put('/location/:location_id/equipment/:item_id', authEndpoint, async (req: A }); // used to purchase items from a particular shop -app.put('/location/:location_id/items/:item_id', authEndpoint, async (req: AuthRequest, res: Response) => { +app.put('/location/:location_id/items/:item_id', authEndpoint, async (req: Request, res: Response) => { const item: (ShopItem & Item) = await getItemFromShop(parseInt(req.params.item_id), parseInt(req.params.location_id)); if(!item) { @@ -421,7 +421,7 @@ app.put('/location/:location_id/items/:item_id', authEndpoint, async (req: AuthR // used to display equipment modals in a store, validates that // the equipment is actually in this store before displaying // the modal -app.get('/location/:location_id/equipment/:item_id/overview', authEndpoint, async (req: AuthRequest, res: Response) => { +app.get('/location/:location_id/equipment/:item_id/overview', authEndpoint, async (req: Request, res: Response) => { const equipment = await getShopEquipment(parseInt(req.params.item_id), parseInt(req.params.location_id)); if(!equipment) { @@ -452,7 +452,7 @@ app.get('/location/:location_id/equipment/:item_id/overview', authEndpoint, asyn // used to display item modals in a store, validates that // the item is actually in this store before displaying // the modal -app.get('/location/:location_id/items/:item_id/overview', authEndpoint, async (req: AuthRequest, res: Response) => { +app.get('/location/:location_id/items/:item_id/overview', authEndpoint, async (req: Request, res: Response) => { const item: (ShopItem & Item) = await getItemFromShop(parseInt(req.params.item_id), parseInt(req.params.location_id)); if(!item) { @@ -481,7 +481,7 @@ app.get('/location/:location_id/items/:item_id/overview', authEndpoint, async (r res.send(html); }); -app.put('/item/:item_id', authEndpoint, async (req: AuthRequest, res: Response) => { +app.put('/item/:item_id', authEndpoint, async (req: Request, res: Response) => { const item: PlayerItem = await getItemFromPlayer(req.player.id, parseInt(req.params.item_id)); if(!item) { @@ -524,7 +524,7 @@ app.put('/item/:item_id', authEndpoint, async (req: AuthRequest, res: Response) }); -app.get('/modal/items/:item_id', authEndpoint, async (req: AuthRequest, res: Response) => { +app.get('/modal/items/:item_id', authEndpoint, async (req: Request, res: Response) => { const item: PlayerItem = await getItemFromPlayer(req.player.id, parseInt(req.params.item_id)); if(!item) { @@ -553,7 +553,7 @@ app.get('/modal/items/:item_id', authEndpoint, async (req: AuthRequest, res: Res res.send(html); }); -app.get('/city/stores/city:stores/:location_id', authEndpoint, async (req: AuthRequest, res: Response) => { +app.get('/city/stores/city:stores/:location_id', authEndpoint, async (req: Request, res: Response) => { const location = await getService(parseInt(req.params.location_id)); if(!location || location.city_id !== req.player.city_id) { @@ -570,7 +570,7 @@ app.get('/city/stores/city:stores/:location_id', authEndpoint, async (req: AuthR res.send(html); }); -app.get('/city/explore/city:explore/:location_id', authEndpoint, async (req: AuthRequest, res: Response) => { +app.get('/city/explore/city:explore/:location_id', authEndpoint, async (req: Request, res: Response) => { const location = await getService(parseInt(req.params.location_id)); if(!location || location.city_id !== req.player.city_id) { @@ -582,7 +582,7 @@ app.get('/city/explore/city:explore/:location_id', authEndpoint, async (req: Aut res.send(renderOnlyMonsterSelector(monsters, 0, location)); }); -app.post('/travel', authEndpoint, async (req: AuthRequest, res: Response) => { +app.post('/travel', authEndpoint, async (req: Request, res: Response) => { const destination_id = parseInt(req.body.destination_id); if(!destination_id || isNaN(destination_id)) { @@ -595,7 +595,7 @@ app.post('/travel', authEndpoint, async (req: AuthRequest, res: Response) => { res.json(travelPlan); }); -app.post('/fight/turn', authEndpoint, async (req: AuthRequest, res: Response) => { +app.post('/fight/turn', authEndpoint, async (req: Request, res: Response) => { const fightBlockKey = `fightturn:${req.player.id}`; if(cache[fightBlockKey] && cache[fightBlockKey] > Date.now()) { @@ -646,7 +646,7 @@ app.post('/fight/turn', authEndpoint, async (req: AuthRequest, res: Response) => res.send(html + travelSection + playerBar); }); -app.post('/fight', fightRateLimiter, authEndpoint, async (req: AuthRequest, res: Response) => { +app.post('/fight', fightRateLimiter, authEndpoint, async (req: Request, res: Response) => { if(req.player.hp <= 0) { logger.log(`Player didn\'t have enough hp`); return res.sendStatus(400); @@ -688,7 +688,7 @@ app.post('/fight', fightRateLimiter, authEndpoint, async (req: AuthRequest, res: res.send(renderFightPreRound(data, true, location, location.city_id)); }); -app.post('/travel/step', authEndpoint, async (req: AuthRequest, res: Response) => { +app.post('/travel/step', authEndpoint, async (req: Request, res: Response) => { const stepTimerKey = `step:${req.player.id}`; const travelPlan = await getTravelPlan(req.player.id); @@ -755,7 +755,7 @@ app.post('/travel/step', authEndpoint, async (req: AuthRequest, res: Response) = } }); -app.post('/travel/return-to-source', authEndpoint, async (req: AuthRequest, res: Response) => { +app.post('/travel/return-to-source', authEndpoint, async (req: Request, res: Response) => { // puts the player back in their starting town // doesn't matter if they don't have one // redirect them! @@ -789,7 +789,7 @@ app.post('/travel/return-to-source', authEndpoint, async (req: AuthRequest, res: }); -app.post('/travel/:destination_id', authEndpoint, async (req: AuthRequest, res: Response) => { +app.post('/travel/:destination_id', authEndpoint, async (req: Request, res: Response) => { if(req.player.hp <= 0) { logger.log(`Player didn\'t have enough hp`); res.send(Alert.ErrorAlert('Sorry, you need some HP to start travelling.')); @@ -814,7 +814,7 @@ if(req.player.hp <= 0) { })); }); -app.get('/settings', authEndpoint, async (req: AuthRequest, res: Response) => { +app.get('/settings', authEndpoint, async (req: Request, res: Response) => { let warning = ''; let html = ''; if(req.player.account_type === 'session') { @@ -825,7 +825,7 @@ app.get('/settings', authEndpoint, async (req: AuthRequest, res: Response) => { res.send(warning + html); }); -app.post('/logout', authEndpoint, async (req: AuthRequest, res: Response) => { +app.post('/logout', authEndpoint, async (req: Request, res: Response) => { // ref to get the socket id for a particular player cache.delete(`socket:${req.player.id}`); // ref to get the player object diff --git a/src/server/auth.ts b/src/server/auth.ts index 456d293..9b4a3a4 100644 --- a/src/server/auth.ts +++ b/src/server/auth.ts @@ -6,10 +6,6 @@ import { Auth } from '../shared/auth'; import { db } from './lib/db'; import { Request, Response } from 'express'; -export interface AuthRequest extends Request { - player: Player -} - export async function signup(playerId: string, username: string, password: string): Promise { const salt = await bcrypt.genSalt(10); const hash = await bcrypt.hash(password, salt); @@ -63,7 +59,7 @@ export async function login(username: string, password: string): Promise } -export async function authEndpoint(req: AuthRequest, res: Response, next: any) { +export async function authEndpoint(req: Request, res: Response, next: any) { const authToken = req.headers['x-authtoken']; if(!authToken) { console.log(`Invalid auth token ${authToken}`); diff --git a/src/server/fight.ts b/src/server/fight.ts index 6e262df..c1bdc45 100644 --- a/src/server/fight.ts +++ b/src/server/fight.ts @@ -9,11 +9,10 @@ import { EquipmentSlot } from '../shared/inventory'; import { MonsterWithFaction, MonsterForFight } from '../shared/monsters'; import { getPlayerSkillsAsObject, updatePlayerSkills } from './skills'; import { SkillID, Skills } from '../shared/skills'; -import { AuthRequest } from './auth'; -import { Response } from 'express'; +import { Request, Response } from 'express'; import * as Alert from './views/alert'; -export async function blockPlayerInFight(req: AuthRequest, res: Response, next: any) { +export async function blockPlayerInFight(req: Request, res: Response, next: any) { const fight = await loadMonsterFromFight(req.player.id); if(!fight) { next(); diff --git a/src/server/locations/healer.ts b/src/server/locations/healer.ts index 2d12db0..3d7374b 100644 --- a/src/server/locations/healer.ts +++ b/src/server/locations/healer.ts @@ -1,6 +1,6 @@ -import { Response, Router } from "express"; +import { Request, Response, Router } from "express"; import { maxHp, maxVigor } from "../../shared/player"; -import { authEndpoint, AuthRequest } from '../auth'; +import { authEndpoint } from '../auth'; import { logger } from "../lib/logger"; import { updatePlayer } from "../player"; import { getCityDetails, getService } from '../map'; @@ -91,7 +91,7 @@ function getText(type: TextSegment, location: Location, city: City): string { } -router.get('/city/services/healer/:location_id', authEndpoint, async (req: AuthRequest, res: Response) => { +router.get('/city/services/healer/:location_id', authEndpoint, async (req: Request, res: Response) => { const service = await getService(parseInt(req.params.location_id)); const city = await getCityDetails(service.city_id); @@ -134,7 +134,7 @@ ${BackToTown()} -router.post('/city/services/healer/heal/:location_id', authEndpoint, async (req: AuthRequest, res: Response) => { +router.post('/city/services/healer/heal/:location_id', authEndpoint, async (req: Request, res: Response) => { const service = await getService(parseInt(req.params.location_id)); const city = await getCityDetails(service.city_id); diff --git a/src/server/locations/recruiter.ts b/src/server/locations/recruiter.ts index 96f720d..fa46860 100644 --- a/src/server/locations/recruiter.ts +++ b/src/server/locations/recruiter.ts @@ -1,6 +1,6 @@ -import { Response, Router } from "express"; +import { Request, Response, Router } from "express"; import { getService } from "../map"; -import { authEndpoint, AuthRequest } from '../auth'; +import { authEndpoint } from '../auth'; import { logger } from "../lib/logger"; import * as Alert from "../views/alert"; import { changeProfession } from "../player"; @@ -15,7 +15,7 @@ export const router = Router(); const MIN_LEVEL = 25; -router.get('/city/services/profession_recruitor/:location_id', authEndpoint, async(req: AuthRequest, res: Response) => { +router.get('/city/services/profession_recruitor/:location_id', authEndpoint, async(req: Request, res: Response) => { const service = await getService(parseInt(req.params.location_id)); if(!service || service.city_id !== req.player.city_id) { @@ -80,7 +80,7 @@ router.get('/city/services/profession_recruitor/:location_id', authEndpoint, asy `); }); -router.post('/city/services/profession_change/:location_id', authEndpoint, async(req: AuthRequest, res: Response) => { +router.post('/city/services/profession_change/:location_id', authEndpoint, async(req: Request, res: Response) => { const service = await getService(parseInt(req.params.location_id)); if(!service || service.city_id !== req.player.city_id) { diff --git a/src/server/locations/repair.ts b/src/server/locations/repair.ts index 6bb7423..19d382c 100644 --- a/src/server/locations/repair.ts +++ b/src/server/locations/repair.ts @@ -1,5 +1,5 @@ -import { Response, Router } from "express"; -import { authEndpoint, AuthRequest } from '../auth'; +import { Request, Response, Router } from "express"; +import { authEndpoint } from '../auth'; import { logger } from "../lib/logger"; import { getService } from "../map"; import { getInventory, getInventoryItem, repair } from '../inventory'; @@ -11,7 +11,7 @@ import { renderPlayerBar } from "../views/player-bar"; export const router = Router(); -router.get('/city/services/repair/:location_id', authEndpoint, async(req: AuthRequest, res: Response) => { +router.get('/city/services/repair/:location_id', authEndpoint, async(req: Request, res: Response) => { const service = await getService(parseInt(req.params.location_id)); if(!service || service.city_id !== req.player.city_id) { @@ -28,7 +28,7 @@ router.get('/city/services/repair/:location_id', authEndpoint, async(req: AuthRe res.send(renderRepairService(damaged, req.player, service)); }); -router.post('/city/services/:location_id/repair/:item_id', authEndpoint, async (req: AuthRequest, res: Response) => { +router.post('/city/services/:location_id/repair/:item_id', authEndpoint, async (req: Request, res: Response) => { const service = await getService(parseInt(req.params.location_id)); if(!service || service.city_id !== req.player.city_id) { diff --git a/src/types/express/index.d.ts b/src/types/express/index.d.ts new file mode 100644 index 0000000..9f12cde --- /dev/null +++ b/src/types/express/index.d.ts @@ -0,0 +1,7 @@ +import { Player } from '../../shared/player'; + +declare module 'express-serve-static-core' { + interface Request { + player: Player + } +} diff --git a/tsconfig.json b/tsconfig.json index 47b69bd..fa4cf87 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,17 +1,18 @@ { - "compilerOptions": { - "module": "commonjs", - "esModuleInterop": true, - "target": "es6", - "moduleResolution": "node", - "removeComments": true, - "preserveConstEnums": true, - "sourceMap": true, - "baseUrl": "src", - "outDir": "dist", - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "resolveJsonModule": true - }, - "include": ["src/server/api.ts"] + "compilerOptions": { + "module": "commonjs", + "esModuleInterop": true, + "target": "es6", + "moduleResolution": "node", + "removeComments": true, + "preserveConstEnums": true, + "sourceMap": true, + "baseUrl": "src", + "outDir": "dist", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "resolveJsonModule": true, + "typeRoots": ["./src/types"], + }, + "include": ["src/server/api.ts"] } -- 2.25.1