diff --git a/package-lock.json b/package-lock.json index 06b2322df18d649071679ea42f4ecf6cf300e415..fe60e359660e52589b864d983fab69f17b4e7076 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2819,11 +2819,6 @@ } } }, - "express-rate-limit": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-4.0.4.tgz", - "integrity": "sha512-DLRj2vMO7Xgai8qWKU9O6ZztF2bdDmfFNFi9k3G9BPzJ+7MG7eWaaBikbe0eBpNGSxU8JziwW0PQKG78aNWa6g==" - }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", diff --git a/package.json b/package.json index 794db7d353397154ef795d59135b5771df8300ff..7f9b55f7927a8d9c62a905c3334d0d8025fb688a 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "bcryptjs": "^2.4.3", "class-transformer": "^0.2.3", "class-validator": "^0.9.1", - "express-rate-limit": "^4.0.4", "jsonwebtoken": "^8.5.1", "passport-jwt": "^4.0.0", "pg": "^7.11.0", diff --git a/src/faction/faction.controller.ts b/src/faction/faction.controller.ts index 2940b036852718e3af74947e120a513e138f74c9..c22ef1fab0c3ccddcddad9440a1803b2c93204d3 100644 --- a/src/faction/faction.controller.ts +++ b/src/faction/faction.controller.ts @@ -9,6 +9,7 @@ import { Put, UseInterceptors, ClassSerializerInterceptor, + Delete, } from '@nestjs/common'; import { AuthGuard } from '../shared/auth.guard'; @@ -90,6 +91,15 @@ export class FactionController { return this.factionservice.joinFaction(person, data); } + // used to leave a faction + // :id is the if of the game + @Delete('leave/:id') + @Roles('soldier') + @GameStates('CREATED') + leaveFaction(@GamePerson('gamepersonId') gamepersonId) { + return this.factionservice.leaveFaction(gamepersonId); + } + // check if person belongs to a faction in a game @Get('check-faction/:id') @UseGuards(new AuthGuard()) diff --git a/src/faction/faction.service.ts b/src/faction/faction.service.ts index ab1dd014165b8c8c37b812b70757f3792fa59711..016c405749dcbed0300db801a660499c8095159e 100644 --- a/src/faction/faction.service.ts +++ b/src/faction/faction.service.ts @@ -53,6 +53,14 @@ export class FactionService { } } + // removes entry from gameperson + async leaveFaction(gamepersonId) { + await this.game_PersonRepository.delete({ gamepersonId }); + return { + message: 'leaved faction', + }; + } + async promotePlayer(body) { const gamepersonId = body.player; // get playerdata diff --git a/src/main.ts b/src/main.ts index 68871be82d89a37a410b93b252fb6f1e712ad143..ebd53e5906d44738a4775716b7165108fae426ca 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,4 @@ import { NestFactory } from '@nestjs/core'; -import * as rateLimit from 'express-rate-limit'; import { AppModule } from './app.module'; @@ -7,20 +6,10 @@ import { AppModule } from './app.module'; Main.ts starts the server. */ -// due to a bug with newest release of express-rate-limit, call for rateLimit is broken -// (rateLimit as any) works as a workaround for now -// see https://github.com/nfriedly/express-rate-limit/issues/138 -const limiter = (rateLimit as any)({ - windowMs: 60 * 1000, // one minute - max: 100, // limit each IP to 100 requests per windowMs -}); - async function bootstrap() { const app = await NestFactory.create(AppModule); // Cors is needed for application/json POST app.enableCors(); - // apply limiter to all routes - app.use(limiter); await app.listen(5000); } bootstrap(); diff --git a/src/score/score.controller.ts b/src/score/score.controller.ts index 2fdebd9cbc1103961fcf99dad448aa5c838f144d..dd26dd24daaec51422557339c8d1a5939ca58ffc 100644 --- a/src/score/score.controller.ts +++ b/src/score/score.controller.ts @@ -1,4 +1,13 @@ -import { Controller, Post, UsePipes, Body, Param, Get } from '@nestjs/common'; +import { + Controller, + Post, + UsePipes, + Body, + Param, + Get, + UseInterceptors, + ClassSerializerInterceptor, +} from '@nestjs/common'; import { ValidationPipe } from '../shared/validation.pipe'; import { ScoreService } from './score.service'; @@ -29,6 +38,7 @@ export class ScoreController { // shows scores, :id is gameId @Get('get-score/:id') + @UseInterceptors(ClassSerializerInterceptor) @GameStates('STARTED') async getScores(@Param('id') gameId: GameEntity) { return this.scoreService.getScores(gameId); diff --git a/src/shared/roles.guard.ts b/src/shared/roles.guard.ts index ae5c05fcfdb1d1a812d079de7e43cdb3c237b59a..359a42d8165ee7d579078c300eded626b760df8b 100644 --- a/src/shared/roles.guard.ts +++ b/src/shared/roles.guard.ts @@ -9,6 +9,7 @@ import { Reflector } from '@nestjs/core'; import * as jwt from 'jsonwebtoken'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; +import { Validator } from 'class-validator'; import { Game_PersonEntity } from '../game/game.entity'; @@ -32,6 +33,12 @@ export class RolesGuard implements CanActivate { return false; } const gameId = request.params.id; + // create a valifator + const validator = new Validator(); + // verify UUID + if (!validator.isUUID(gameId)) { + throw new HttpException('Game not found', HttpStatus.BAD_REQUEST); + } request.user = await this.getUserObject(request.headers.authorization); const role = await this.game_PersonRepository.findOne({ where: { person: request.user['id'], game: gameId }, diff --git a/src/shared/states.guard.ts b/src/shared/states.guard.ts index 9e85e94e40f92ed6b016e451c592a3025a684cad..961b93619883e3c55be3ab5e54fdc92e65f27e74 100644 --- a/src/shared/states.guard.ts +++ b/src/shared/states.guard.ts @@ -8,6 +8,7 @@ import { import { Reflector } from '@nestjs/core'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; +import { Validator } from 'class-validator'; import { GameEntity } from '../game/game.entity'; @@ -29,6 +30,12 @@ export class StatesGuard implements CanActivate { } const request = context.switchToHttp().getRequest(); const gameId = request.params.id; + // create a valifator + const validator = new Validator(); + // verify UUID + if (!validator.isUUID(gameId)) { + throw new HttpException('Game not found', HttpStatus.BAD_REQUEST); + } const gameRef = await this.gameRepository.findOne({ id: gameId, }); diff --git a/src/tracking/tracking.entity.ts b/src/tracking/tracking.entity.ts index c2699a09388ce8ad47c7119b46f4614fa52b34ec..8c5b9ab59c8e4250aa313e6eda540f1847d41f78 100644 --- a/src/tracking/tracking.entity.ts +++ b/src/tracking/tracking.entity.ts @@ -7,6 +7,7 @@ import { GeoDTO } from './geo.dto'; export class TrackingEntity { @PrimaryGeneratedColumn('uuid') id: string; @Column({ type: 'json', nullable: true }) data: GeoDTO[]; + @Column('text') icon: string; @ManyToOne(type => Game_PersonEntity, person => person.gamepersonId, { onDelete: 'CASCADE', diff --git a/src/tracking/tracking.service.ts b/src/tracking/tracking.service.ts index 23944563b4f58e9f1bd54f2428a1bf7dbec3e67b..ff97aae3993f62c9dbb342ca9ff5744001d32366 100644 --- a/src/tracking/tracking.service.ts +++ b/src/tracking/tracking.service.ts @@ -24,7 +24,7 @@ export class TrackingService { let trackedperson = await this.trackingrepository.findOne({ gamepersonId: gameperson, }); - // if player has pushed tracking data, update entry + if (trackedperson) { trackdata['time'] = Date.now(); //add coordinates @@ -37,6 +37,7 @@ export class TrackingService { trackdata['time'] = Date.now(); // initialize data trackedperson = await this.trackingrepository.create(trackedperson); + trackedperson.icon = 'infantry.svg'; trackedperson.data = [trackdata]; trackedperson.faction = gameperson.faction; trackedperson.game = gameId; @@ -70,6 +71,8 @@ export class TrackingService { gamepersonId: player['gamepersonId']['gamepersonId'], gamepersonRole: player['gamepersonId']['role'], factionId: player['faction']['factionId'], + factionColour: player['faction']['colour'], + icon: player['icon'], coordinates: player['data'].pop(), }; }),