mirror of
https://github.com/AlecM33/Werewolf.git
synced 2025-12-26 15:57:50 +01:00
fully validate game creation parameters sent through the API
This commit is contained in:
@@ -2,7 +2,7 @@ export const globals = {
|
||||
CHAR_POOL: 'abcdefghijklmnopqrstuvwxyz0123456789',
|
||||
USER_SIGNATURE_LENGTH: 25,
|
||||
CLOCK_TICK_INTERVAL_MILLIS: 100,
|
||||
MAX_CUSTOM_ROLE_NAME_LENGTH: 30,
|
||||
MAX_CUSTOM_ROLE_NAME_LENGTH: 50,
|
||||
MAX_CUSTOM_ROLE_DESCRIPTION_LENGTH: 500,
|
||||
TOAST_DURATION_DEFAULT: 6,
|
||||
ACCESS_CODE_LENGTH: 4,
|
||||
|
||||
@@ -5,6 +5,5 @@ export class Game {
|
||||
this.timerParams = timerParams;
|
||||
this.hasDedicatedModerator = hasDedicatedModerator;
|
||||
this.moderatorName = moderatorName;
|
||||
this.accessCode = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,11 +54,13 @@ export class GameCreationStepManager {
|
||||
title: 'Set an optional timer:',
|
||||
forwardHandler: (e) => {
|
||||
if (e.type === 'click' || e.code === 'Enter') {
|
||||
const hours = parseInt(document.getElementById('game-hours').value);
|
||||
const minutes = parseInt(document.getElementById('game-minutes').value);
|
||||
if ((isNaN(hours) && isNaN(minutes))
|
||||
|| (isNaN(hours) && minutes > 0 && minutes < 60)
|
||||
|| (isNaN(minutes) && hours > 0 && hours < 6)
|
||||
let hours = parseInt(document.getElementById('game-hours').value);
|
||||
let minutes = parseInt(document.getElementById('game-minutes').value);
|
||||
hours = isNaN(hours) ? null : hours;
|
||||
minutes = isNaN(minutes) ? null : minutes;
|
||||
if ((hours === null && minutes === null)
|
||||
|| (hours === null && minutes > 0 && minutes < 60)
|
||||
|| (minutes === null && hours > 0 && hours < 6)
|
||||
|| (hours === 0 && minutes > 0 && minutes < 60)
|
||||
|| (minutes === 0 && hours > 0 && hours < 6)
|
||||
|| (hours > 0 && hours < 6 && minutes >= 0 && minutes < 60)
|
||||
@@ -571,7 +573,7 @@ function processNewCustomRoleSubmission (name, description, team, deckManager, i
|
||||
}
|
||||
|
||||
function hasTimer (hours, minutes) {
|
||||
return (!isNaN(hours) || !isNaN(minutes));
|
||||
return hours !== null || minutes !== null;
|
||||
}
|
||||
|
||||
function validateName (name) {
|
||||
|
||||
@@ -333,7 +333,7 @@ function validateCustomRoleCookie (cookie) {
|
||||
const cookieJSON = JSON.parse(cookie);
|
||||
if (Array.isArray(cookieJSON)) {
|
||||
for (const entry of cookieJSON) {
|
||||
if (typeof entry === 'object') {
|
||||
if (entry !== null && typeof entry === 'object') {
|
||||
if (typeof entry.role !== 'string' || entry.role.length > globals.MAX_CUSTOM_ROLE_NAME_LENGTH
|
||||
|| typeof entry.team !== 'string' || (entry.team !== globals.ALIGNMENT.GOOD && entry.team !== globals.ALIGNMENT.EVIL)
|
||||
|| typeof entry.description !== 'string' || entry.description.length > globals.MAX_CUSTOM_ROLE_DESCRIPTION_LENGTH
|
||||
|
||||
@@ -36,7 +36,6 @@ router.patch('/restart', (req, res, next) => {
|
||||
});
|
||||
|
||||
router.post('/create', gameEndpointLimiter, function (req, res) {
|
||||
logger.debug('Received request to create new game: ' + JSON.stringify(req.body, null, 4));
|
||||
const gameCreationPromise = gameManager.createGame(req.body, false);
|
||||
gameCreationPromise.then((result) => {
|
||||
if (result instanceof Error) {
|
||||
|
||||
@@ -3,6 +3,12 @@ const globals = {
|
||||
ACCESS_CODE_LENGTH: 4,
|
||||
ACCESS_CODE_GENERATION_ATTEMPTS: 50,
|
||||
CLOCK_TICK_INTERVAL_MILLIS: 100,
|
||||
MAX_CUSTOM_ROLE_NAME_LENGTH: 50,
|
||||
MAX_CUSTOM_ROLE_DESCRIPTION_LENGTH: 500,
|
||||
ALIGNMENT: {
|
||||
GOOD: 'good',
|
||||
EVIL: 'evil'
|
||||
},
|
||||
CORS: process.env.NODE_ENV?.trim() === 'development'
|
||||
? {
|
||||
origin: '*',
|
||||
|
||||
@@ -22,11 +22,12 @@ class GameManager {
|
||||
};
|
||||
|
||||
createGame = (gameParams) => {
|
||||
const expectedKeys = ['deck', 'hasTimer', 'timerParams', 'moderatorName'];
|
||||
const expectedKeys = ['deck', 'hasTimer', 'timerParams', 'moderatorName', 'hasDedicatedModerator'];
|
||||
if (typeof gameParams !== 'object'
|
||||
|| expectedKeys.some((key) => !Object.keys(gameParams).includes(key))
|
||||
|| !valid(gameParams)
|
||||
) {
|
||||
this.logger.error('Tried to create game with invalid options: ' + JSON.stringify(gameParams));
|
||||
this.logger.error('Tried to create game with invalid options.');
|
||||
return Promise.reject(globals.ERROR_MESSAGE.BAD_CREATE_REQUEST);
|
||||
} else {
|
||||
this.pruneStaleGames();
|
||||
@@ -493,6 +494,54 @@ function getGameSize (cards) {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
function valid(gameParams) {
|
||||
return typeof gameParams.hasTimer === "boolean"
|
||||
&& typeof gameParams.hasDedicatedModerator === "boolean"
|
||||
&& typeof gameParams.moderatorName === "string"
|
||||
&& gameParams.moderatorName.length > 0
|
||||
&& gameParams.moderatorName.length <= 30
|
||||
&& timerParamsAreValid(gameParams.hasTimer, gameParams.timerParams)
|
||||
&& deckIsValid(gameParams.deck);
|
||||
}
|
||||
|
||||
function timerParamsAreValid(hasTimer, timerParams) {
|
||||
if (hasTimer === false) {
|
||||
return timerParams === null
|
||||
} else {
|
||||
if (timerParams === null || typeof timerParams !== 'object') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (timerParams.hours === null && timerParams.minutes > 0 && timerParams.minutes < 60)
|
||||
|| (timerParams.minutes === null && timerParams.hours > 0 && timerParams.hours < 6)
|
||||
|| (timerParams.hours === 0 && timerParams.minutes > 0 && timerParams.minutes < 60)
|
||||
|| (timerParams.minutes === 0 && timerParams.hours > 0 && timerParams.hours < 6)
|
||||
|| (timerParams.hours > 0 && timerParams.hours < 6 && timerParams.minutes >= 0 && timerParams.minutes < 60)
|
||||
}
|
||||
}
|
||||
|
||||
function deckIsValid(deck) {
|
||||
if (Array.isArray(deck) && deck.length > 0) {
|
||||
for (const entry of deck) {
|
||||
if (entry !== null && typeof entry === 'object') {
|
||||
if (typeof entry.role !== 'string' || entry.role.length > globals.MAX_CUSTOM_ROLE_NAME_LENGTH
|
||||
|| typeof entry.team !== 'string' || (entry.team !== globals.ALIGNMENT.GOOD && entry.team !== globals.ALIGNMENT.EVIL)
|
||||
|| typeof entry.description !== 'string' || entry.description.length > globals.MAX_CUSTOM_ROLE_DESCRIPTION_LENGTH
|
||||
|| (entry.custom && typeof entry.custom !== 'boolean')
|
||||
|| typeof entry.quantity !== 'number' || entry.quantity < 1 || entry.quantity > 50
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function addSpectator (game, name, logger, namespace) {
|
||||
const spectator = new Person(
|
||||
createRandomId(),
|
||||
|
||||
Reference in New Issue
Block a user