Skip to content

Commit

Permalink
Validate timeout durations (#7556)
Browse files Browse the repository at this point in the history
  • Loading branch information
AnnikaCodes committed Oct 22, 2020
1 parent 61f072f commit 97713ba
Show file tree
Hide file tree
Showing 7 changed files with 34 additions and 13 deletions.
7 changes: 5 additions & 2 deletions server/chat-plugins/announcements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,17 @@ export const commands: ChatCommands = {
return this.add(this.tr("The announcement timer was turned off."));
}
const timeout = parseFloat(target);
if (isNaN(timeout) || timeout <= 0 || timeout > 0x7FFFFFFF) return this.errorReply(this.tr("Invalid time given."));
const timeoutMs = timeout * 60 * 1000;
if (isNaN(timeoutMs) || timeoutMs <= 0 || timeoutMs > Chat.MAX_TIMEOUT_DURATION) {
return this.errorReply(this.tr("Invalid time given."));
}
if (announcement.timeout) clearTimeout(announcement.timeout);
announcement.timeoutMins = timeout;
announcement.timeout = setTimeout(() => {
if (!room) return; // do nothing if the room doesn't exist anymore
if (announcement) announcement.end();
room.minorActivity = null;
}, (timeout * 60000));
}, timeoutMs);
room.add(`The announcement timer was turned on: the announcement will end in ${timeout} minute${Chat.plural(timeout)}.`);
this.modlog('ANNOUNCEMENT TIMER', null, `${timeout} minutes`);
return this.privateModAction(`The announcement timer was set to ${timeout} minute${Chat.plural(timeout)} by ${user.name}.`);
Expand Down
2 changes: 1 addition & 1 deletion server/chat-plugins/blackjack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ export const commands: ChatCommands = {
if (room.game) return this.errorReply("There is already a game running in this room.");
if (room.settings.blackjackDisabled) return this.errorReply("Blackjack is currently disabled in this room.");
const autostartMinutes = target ? parseFloat(target) : 0;
if (isNaN(autostartMinutes)) {
if (isNaN(autostartMinutes) || autostartMinutes <= 0 || (autostartMinutes * 60 * 1000) > Chat.MAX_TIMEOUT_DURATION) {
return this.errorReply("Usage: /blackjack create [autostart] - where autostart is an integer");
}

Expand Down
4 changes: 3 additions & 1 deletion server/chat-plugins/poll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,9 @@ export const commands: ChatCommands = {
return this.add(this.tr("The poll timer was turned off."));
}
const timeout = parseFloat(target);
if (isNaN(timeout) || timeout <= 0 || timeout > 0x7FFFFFFF) return this.errorReply(this.tr("Invalid time given."));
if (isNaN(timeout) || timeout <= 0 || timeout > Chat.MAX_TIMEOUT_DURATION) {
return this.errorReply(this.tr("Invalid time given."));
}
if (poll.timeout) clearTimeout(poll.timeout);
poll.timeoutMins = timeout;
poll.timeout = setTimeout(() => {
Expand Down
11 changes: 7 additions & 4 deletions server/chat-plugins/scavengers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -571,9 +571,7 @@ export class ScavengerHunt extends Rooms.RoomGame {
return true;
}

setTimer(minutes: string | number) {
minutes = Number(minutes);

setTimer(minutes: number) {
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
Expand Down Expand Up @@ -1483,7 +1481,12 @@ const ScavengerCommands: ChatCommands = {
const game = room.getGame(ScavengerHunt);
if (!game) return this.errorReply(`There is no scavenger hunt currently running.`);

const result = game.setTimer(target);
const minutes = parseInt(target);
if (isNaN(minutes) || minutes <= 0 || (minutes * 60 * 1000) > Chat.MAX_TIMEOUT_DURATION) {
throw new Chat.ErrorMessage(`You must specify a timer length that is a postive number.`);
}

const result = game.setTimer(minutes);
const message = `The scavenger timer has been ${(result === 'off' ? "turned off" : `set to ${result} minutes`)}`;

room.add(message + '.');
Expand Down
4 changes: 2 additions & 2 deletions server/chat-plugins/trivia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2363,7 +2363,7 @@ const mastermindCommands: ChatCommands = {
}
const categoryName = ALL_CATEGORIES[CATEGORY_ALIASES[category] || category];
const timeout = parseInt(timeoutString);
if (isNaN(timeout) || timeout < 1) {
if (isNaN(timeout) || timeout < 1 || (timeout * 1000) > Chat.MAX_TIMEOUT_DURATION) {
return this.errorReply(this.tr`You must specify a round length of at least 1 second.`);
}

Expand All @@ -2386,7 +2386,7 @@ const mastermindCommands: ChatCommands = {
if (!target) return this.parse(`/help mastermind finals`);

const timeout = parseInt(target);
if (isNaN(timeout) || timeout < 1) {
if (isNaN(timeout) || timeout < 1 || (timeout * 1000) > Chat.MAX_TIMEOUT_DURATION) {
return this.errorReply(this.tr`You must specify a length of at least 1 second.`);
}

Expand Down
7 changes: 7 additions & 0 deletions server/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1368,6 +1368,13 @@ export const Chat = new class {
});
}
translationsLoaded = false;
/**
* As per the node.js documentation at https://nodejs.org/api/timers.html#timers_settimeout_callback_delay_args,
* timers with durations that are too long for a 32-bit signed integer will be invoked after 1 millisecond,
* which tends to cause unexpected behavior.
*/
readonly MAX_TIMEOUT_DURATION = 2147483647;

readonly multiLinePattern = new PatternTester();

/*********************************************************
Expand Down
12 changes: 9 additions & 3 deletions server/tournaments/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1659,9 +1659,12 @@ const commands: ChatCommands = {
target = 'off';
tournament.autostartcap = false;
}
const timeout = target.toLowerCase() === 'off' ? Infinity : target;
if (tournament.setAutoStartTimeout(Number(timeout) * 60 * 1000, this)) {
this.privateModAction(`The tournament auto start timer was set to ${target} by ${user.name}`);
const timeout = target.toLowerCase() === 'off' ? Infinity : Number(target) * 60 * 1000;
if (timeout <= 0 || (timeout !== Infinity && timeout > Chat.MAX_TIMEOUT_DURATION)) {
return this.errorReply(`The automatic tournament start timer must be set to a positive number.`);
}
if (tournament.setAutoStartTimeout(timeout, this)) {
this.privateModAction(`The tournament auto start timer was set to ${target} by ${user.name}`);
this.modlog('TOUR AUTOSTART', null, timeout === Infinity ? 'off' : target);
}
}
Expand All @@ -1682,6 +1685,9 @@ const commands: ChatCommands = {
}
if (target.toLowerCase() === 'infinity' || target === '0') target = 'off';
const timeout = target.toLowerCase() === 'off' ? Infinity : Number(target) * 60 * 1000;
if (timeout <= 0 || (timeout !== Infinity && timeout > Chat.MAX_TIMEOUT_DURATION)) {
return this.errorReply(`The automatic disqualification timer must be set to a positive number.`);
}
if (timeout === tournament.autoDisqualifyTimeout) {
return this.errorReply(`The automatic tournament disqualify timer is already set to ${target} minute(s).`);
}
Expand Down

0 comments on commit 97713ba

Please sign in to comment.