feat(web): implement progressive IP lockout duration scaling based on block counts
Validators (Pushes and Pull Requests) / validate-ui-and-storage (push) Successful in 22s
Prepare Release / Build & Create Release (push) Successful in 59s
Prepare Release / Release Notification (push) Successful in 1s
Validators (Pushes and Pull Requests) / validate-core (push) Successful in 2m1s
Validators (Pushes and Pull Requests) / validate-ui-and-storage (push) Successful in 22s
Prepare Release / Build & Create Release (push) Successful in 59s
Prepare Release / Release Notification (push) Successful in 1s
Validators (Pushes and Pull Requests) / validate-core (push) Successful in 2m1s
This commit is contained in:
@@ -9,9 +9,10 @@ public interface IIpLockoutService
|
||||
|
||||
public class IpLockoutService : IIpLockoutService
|
||||
{
|
||||
private readonly Dictionary<string, (int Attempts, DateTime LockedUntil)> _attemptLog = [];
|
||||
private readonly Dictionary<string, (int Attempts, int LockoutCount, DateTime LockedUntil)> _attemptLog = [];
|
||||
private const int MaxFailedAttempts = 3;
|
||||
private const int LockoutDurationMinutes = 15;
|
||||
private const int MaxLockoutDurationMinutes = 1440; // 24 hours cap
|
||||
private readonly object _lock = new();
|
||||
|
||||
public bool IsLockedOut(string ipAddress)
|
||||
@@ -23,7 +24,11 @@ public class IpLockoutService : IIpLockoutService
|
||||
if (DateTime.UtcNow < record.LockedUntil)
|
||||
return true;
|
||||
|
||||
_attemptLog.Remove(ipAddress);
|
||||
// Reset failed attempts but keep the LockoutCount to calculate progressive delay on next failure
|
||||
if (record.Attempts >= MaxFailedAttempts)
|
||||
{
|
||||
_attemptLog[ipAddress] = (0, record.LockoutCount, DateTime.MinValue);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -39,14 +44,19 @@ public class IpLockoutService : IIpLockoutService
|
||||
record.Attempts++;
|
||||
if (record.Attempts >= MaxFailedAttempts)
|
||||
{
|
||||
record.LockedUntil = DateTime.UtcNow.AddMinutes(LockoutDurationMinutes);
|
||||
// Calculate exponential progressive lockout duration: 15 * 2^LockoutCount
|
||||
var durationMinutes = LockoutDurationMinutes * Math.Pow(2, record.LockoutCount);
|
||||
durationMinutes = Math.Min(durationMinutes, MaxLockoutDurationMinutes);
|
||||
|
||||
record.LockedUntil = DateTime.UtcNow.AddMinutes(durationMinutes);
|
||||
record.LockoutCount++;
|
||||
}
|
||||
|
||||
_attemptLog[ipAddress] = record;
|
||||
}
|
||||
else
|
||||
{
|
||||
_attemptLog[ipAddress] = (1, DateTime.UtcNow);
|
||||
_attemptLog[ipAddress] = (1, 0, DateTime.MinValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user