diff --git a/src/faction/faction.dto.ts b/src/faction/faction.dto.ts index df69715283e4de46cdf7d09e4ac657fbb81a1d68..c905999bf4739f4d3360ef8e81efe4a7bcd08182 100644 --- a/src/faction/faction.dto.ts +++ b/src/faction/faction.dto.ts @@ -13,7 +13,6 @@ import { } from 'class-validator'; import { GameEntity } from '../game/game.entity'; -import { RoleValidation } from '../shared/custom-validation'; import { GameDTO } from '../game/game.dto'; import { FactionEntity, GameGroupEntity } from './faction.entity'; @@ -57,7 +56,7 @@ export class JoinFactionDTO { export class PromotePlayerDTO { @IsUUID('4') player: string; - @Validate(RoleValidation) + @IsIn(['admin', 'soldier', 'factionleader']) role: string; } diff --git a/src/game/tick.service.ts b/src/game/tick.service.ts index b6ba273588a4b706ebf3b5b929d8ff49946251c0..0bd2c413ff8cad00ee6d5d0e5fd97506e0c8e35e 100644 --- a/src/game/tick.service.ts +++ b/src/game/tick.service.ts @@ -5,8 +5,7 @@ import { GameService } from './game.service'; @Injectable() export class TickService { constructor( - private scoreService: ScoreService, - private gameService: GameService, + private scoreService: ScoreService, //private gameService: GameService, ) { // whenever Tickservice is called, it will start ticktimer /* @@ -25,14 +24,10 @@ export class TickService { async startTimer() { this.logger.log('Started timer'); setInterval(this.Tick, this.tickInterval); - - // get games with STARTED value - let games = await this.gameService.listGames('STARTED'); - - // add STARTED games to dictionary + /* // add STARTED games to dictionary games.map(game => { this.ongoingGames[game.id] = Date.now(); - }); + }); */ } // add the game to tick queue diff --git a/src/shared/auth.guard.ts b/src/shared/auth.guard.ts index ff2bdf406d5badffc467cdf22d0f61935aae0af8..acde301a9dca4202d4971a3b34e6d251dc07a7c1 100644 --- a/src/shared/auth.guard.ts +++ b/src/shared/auth.guard.ts @@ -7,6 +7,14 @@ import { } from '@nestjs/common'; import * as jwt from 'jsonwebtoken'; +///////////////////////////////////////////////////////// +/// https://docs.nestjs.com/guards /// +/// AuthGuard verifies the user's token /// +/// It adds user information to request.user /// +/// which can be used by UserDecorator in services /// +/// return 403 if token validation fails /// +///////////////////////////////////////////////////////// + @Injectable() export class AuthGuard implements CanActivate { // check for logged in user diff --git a/src/shared/custom-validation.ts b/src/shared/custom-validation.ts deleted file mode 100644 index 13b96372e0b76a2897364baa15562edf383a2d81..0000000000000000000000000000000000000000 --- a/src/shared/custom-validation.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { - ValidatorConstraint, - ValidatorConstraintInterface, - ValidationArguments, - Validator, -} from 'class-validator'; - -// check if input is null or valid uuid -@ValidatorConstraint({ name: 'uuid', async: true }) -export class Uuid implements ValidatorConstraintInterface { - validate(uuid: string, args: ValidationArguments) { - const validator = new Validator(); - return validator.isUUID(uuid, '4') || uuid == null; // for async validations you must return a Promise<boolean> here - } - - defaultMessage(args: ValidationArguments) { - return 'Not valid uuid'; - } -} - -// checks if role is valid -@ValidatorConstraint({ name: 'roleValidation', async: true }) -export class RoleValidation implements ValidatorConstraintInterface { - validate(role: string, args: ValidationArguments) { - const validRoles = ['admin', 'soldier', 'factionleader']; - return validRoles.includes(role); - } - - defaultMessage(args: ValidationArguments) { - return 'Not valid uuid'; - } -} - -// checks for valid JSON for center -@ValidatorConstraint({ name: 'centerJSON', async: true }) -export class CenterJSON implements ValidatorConstraintInterface { - validate(center: JSON, args: ValidationArguments) { - const validator = new Validator(); - return ( - validator.isNumber(center['lat']) && - validator.isNumber(center['lng']) && - validator.min(center['lat'], -90) && - validator.max(center['lat'], 90) && - validator.min(center['lng'], -180) && - validator.max(center['lng'], 180) - ); - } - - defaultMessage(args: ValidationArguments) { - return 'Error with center JSON'; - } -} diff --git a/src/shared/guard.decorator.ts b/src/shared/guard.decorator.ts index b299d6de913f54dd496c344f6dcdafd2942b2c9c..a313b3a6e52321b70b2f9768b5131252cb7816f7 100644 --- a/src/shared/guard.decorator.ts +++ b/src/shared/guard.decorator.ts @@ -1,5 +1,12 @@ import { SetMetadata } from '@nestjs/common'; +///////////////////////////////////////////////////////// +/// pass information from controllers to guards /// +/// for example @Roles("admin") passes it to /// +/// roles.guard, which compares user's role /// +/// to the values return by SetMetadata /// +///////////////////////////////////////////////////////// + export const Roles = (...roles: string[]) => SetMetadata('roles', roles); export const GameStates = (...states: string[]) => diff --git a/src/shared/http-error.filter.ts b/src/shared/http-error.filter.ts index 8a65068c4275c4a8d576da54b0340c17b6ac8cc4..bf7316fa20d8c5e3107a10b0972a1d1d9e18e940 100644 --- a/src/shared/http-error.filter.ts +++ b/src/shared/http-error.filter.ts @@ -7,6 +7,12 @@ import { HttpStatus, } from '@nestjs/common'; +///////////////////////////////////////////////////////// +/// Global tryCatch for catching errors in services /// +/// Returns error message for end-users /// +/// Also logs the error in console /// +///////////////////////////////////////////////////////// + @Catch() export class HttpErrorFilter implements ExceptionFilter { catch(exception: HttpException, host: ArgumentsHost) { diff --git a/src/shared/roles.controller.ts b/src/shared/roles.controller.ts deleted file mode 100644 index 0298723936651e1859e76273b14b9086e167f6c9..0000000000000000000000000000000000000000 --- a/src/shared/roles.controller.ts +++ /dev/null @@ -1,51 +0,0 @@ -const AccessControl = require('accesscontrol'); - -const grants = { - admin: { - mapmarker: { - 'create:any': [], - 'delete:any': [], - 'read:any': [], - 'update:any': [], - }, - powerup: { - 'create:any': [], - 'delete:any': [], - 'read:any': [], - 'update:any': [], - }, - faction: { - 'create:any': [], - 'delete:any': [], - 'read:any': [], - 'update:any': [], - }, - players: { - 'create:any': [], - 'delete:any': [], - 'read:any': [], - 'update:any': [], - }, - }, - faction_leader: { - mapmarker: { - 'create:own': [], - 'delete:own': [], - 'read:own': [], - }, - powerup: { - 'read:own': [], - }, - faction: { - 'read:own': [], - 'update:own': [], - }, - players: { - 'read:own': [], - 'update:own': [], - }, - }, - //player & spectator -}; - -const ac = new AccessControl(grants); \ No newline at end of file diff --git a/src/shared/roles.guard.ts b/src/shared/roles.guard.ts index 7ae58d2f0c2d9f1258e41ea1a8341e2e664df15d..5e97482e408df52075c4e97553707e32ca70a447 100644 --- a/src/shared/roles.guard.ts +++ b/src/shared/roles.guard.ts @@ -13,6 +13,15 @@ import { Validator } from 'class-validator'; import { Game_PersonEntity } from '../game/game.entity'; +///////////////////////////////////////////////////////// +/// https://docs.nestjs.com/guards /// +/// RolesGuard verifies the user's token and role /// +/// It adds user information to request.user /// +/// which can be used by GamePerson /// +/// decorator in services /// +/// return 403 if token/role validation fails /// +///////////////////////////////////////////////////////// + @Injectable() export class RolesGuard implements CanActivate { constructor( diff --git a/src/shared/states.guard.ts b/src/shared/states.guard.ts index 961b93619883e3c55be3ab5e54fdc92e65f27e74..544918d56e4653f6d52950a06ee8abd3e0eea4f1 100644 --- a/src/shared/states.guard.ts +++ b/src/shared/states.guard.ts @@ -12,6 +12,13 @@ import { Validator } from 'class-validator'; import { GameEntity } from '../game/game.entity'; +////////////////////////////////////////////////////////// +/// https://docs.nestjs.com/guards /// +/// StatesGuard verifies the game's state /// +/// Guard needs gameId as 'id' in request parameters /// +/// return 400 if state if state validation fails /// +////////////////////////////////////////////////////////// + @Injectable() export class StatesGuard implements CanActivate { constructor( diff --git a/src/shared/validation.pipe.ts b/src/shared/validation.pipe.ts index 423f23152e202e3c808d8c1e888f2a5fc00dac30..7e4bb8796f7b036c20238729b54f9c3d6093505c 100644 --- a/src/shared/validation.pipe.ts +++ b/src/shared/validation.pipe.ts @@ -8,6 +8,15 @@ import { import { validate } from 'class-validator'; import { plainToClass } from 'class-transformer'; +/////////////////////////////////////////////////////////// +/// https://docs.nestjs.com/techniques/validation /// +/// ValidationPipe for validating DTO's /// +/// DTO's use ClassValidator which are /// +/// validated by ValidationPipes /// +/// return 400 if pipe validation fails with /// +/// errorMessage stating reason for validation fail /// +/////////////////////////////////////////////////////////// + @Injectable() export class ValidationPipe implements PipeTransform<any> { async transform(value: any, metadata: ArgumentMetadata) { diff --git a/src/task/task.dto.ts b/src/task/task.dto.ts index a1576e7d12c9d9a6263b445fdba293fe94e8964a..02653c39d5762784215303956652aaec78c60f81 100644 --- a/src/task/task.dto.ts +++ b/src/task/task.dto.ts @@ -5,10 +5,10 @@ import { Validate, IsUUID, Equals, + IsOptional, } from 'class-validator'; import { FactionEntity } from '../faction/faction.entity'; import { GameEntity } from '../game/game.entity'; -import { Uuid } from '../shared/custom-validation'; export class CreateTaskDTO { @IsString() @@ -19,7 +19,8 @@ export class CreateTaskDTO { taskDescription: string; @IsBoolean() taskIsActive: boolean; - @Validate(Uuid) + @IsOptional() + @IsUUID('4') faction: FactionEntity; @Equals(null) taskWinner: FactionEntity;