mirror of
https://github.com/Such-Software/wownerogue.git
synced 2026-10-23 17:18:32 +02:00
Feat: add IP-based rate limiting and house balance thresholds
This commit is contained in:
@@ -47,6 +47,19 @@ class PaymentHandlers {
|
||||
this.io.to(socket.id).emit('payment_error', { error: 'Payment system not available' });
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if house balance is critically low before proceeding with payment
|
||||
if (this.gameModeManager.alertService) {
|
||||
const balanceCheck = await this.gameModeManager.alertService.checkBalanceForGameStart();
|
||||
if (balanceCheck.halted) {
|
||||
this.io.to(socket.id).emit('balance_critical', {
|
||||
reason: 'low_balance',
|
||||
message: balanceCheck.reason || 'Sorry, the house balance is too low to initiate new games. Please try again later.'
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const { type, packageId } = data;
|
||||
const paymentType = type || data.gameMode || 'single_game';
|
||||
@@ -104,7 +117,19 @@ class PaymentHandlers {
|
||||
|
||||
async createAndShowPaymentRequest(socket, options = {}) {
|
||||
if (!this.gameModeManager) return;
|
||||
|
||||
|
||||
// Check if house balance is critically low before proceeding with payment
|
||||
if (this.gameModeManager.alertService) {
|
||||
const balanceCheck = await this.gameModeManager.alertService.checkBalanceForGameStart();
|
||||
if (balanceCheck.halted) {
|
||||
this.io.to(socket.id).emit('balance_critical', {
|
||||
reason: 'low_balance',
|
||||
message: balanceCheck.reason || 'Sorry, the house balance is too low to initiate new games. Please try again later.'
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If both direct and credits modes are enabled, let the user choose
|
||||
const bothModesEnabled = this.gameModeManager.directModeEnabled && this.gameModeManager.creditsModeEnabled;
|
||||
const forceShowOptions = options.showOptions === true;
|
||||
|
||||
@@ -43,13 +43,14 @@ class RateLimiter {
|
||||
|
||||
const now = Date.now();
|
||||
const key = `${userId}:${action}`;
|
||||
|
||||
|
||||
// Check user-based limits
|
||||
const userResult = this._checkSingleLimit(key, limit, now);
|
||||
|
||||
// Check IP-based limits if IP provided and it's a connection-type action
|
||||
|
||||
// Check IP-based limits if IP provided
|
||||
// Apply to: connection actions, payment actions, and game actions
|
||||
let ipResult = { allowed: true, remaining: Infinity, retryAfter: 0 };
|
||||
if (ip && action.startsWith('connection:')) {
|
||||
if (ip && this._shouldApplyIpLimit(action)) {
|
||||
const ipKey = `${ip}:${action}`;
|
||||
ipResult = this._checkSingleLimit(ipKey, limit, now, this.ipStorage);
|
||||
}
|
||||
@@ -68,6 +69,23 @@ class RateLimiter {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if an action should have IP-based rate limiting applied
|
||||
* @param {string} action - Action type
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_shouldApplyIpLimit(action) {
|
||||
// Actions that should be rate limited by IP (in addition to socket ID)
|
||||
// This prevents abuse when users reconnect to bypass socket-based limits
|
||||
const ipLimitedPrefixes = [
|
||||
'connection:', // Connection attempts
|
||||
'payment:', // Payment creation/operations
|
||||
'game:', // Game start/queue operations
|
||||
'address:' // Address changes
|
||||
];
|
||||
return ipLimitedPrefixes.some(prefix => action.startsWith(prefix));
|
||||
}
|
||||
|
||||
/**
|
||||
* Record an action attempt (increment counter)
|
||||
* @param {string} userId - User identifier
|
||||
@@ -77,12 +95,12 @@ class RateLimiter {
|
||||
async recordAttempt(userId, action, ip = null) {
|
||||
const now = Date.now();
|
||||
const key = `${userId}:${action}`;
|
||||
|
||||
|
||||
// Record user attempt
|
||||
this._recordSingleAttempt(key, now);
|
||||
|
||||
// Record IP attempt for connection actions
|
||||
if (ip && action.startsWith('connection:')) {
|
||||
|
||||
// Record IP attempt for actions that should have IP-based limiting
|
||||
if (ip && this._shouldApplyIpLimit(action)) {
|
||||
const ipKey = `${ip}:${action}`;
|
||||
this._recordSingleAttempt(ipKey, now, this.ipStorage);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user