NBloodServerSupervisor/WebInterface/Services/RateLimiterService.cs
CommonLoon102 3af4c9dfc7
add option to play custom maps on private servers (#9)
* add option to play custom maps on private servers

* don't show every exception to the end-user

* hash the IPs

* add description about the purpose of the public custom map list

* add punctuation to error messages
2020-01-29 15:32:23 +00:00

63 lines
1.9 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace WebInterface.Services
{
public class RateLimiterService : IRateLimiterService
{
private static readonly ConcurrentDictionary<string, List<DateTime>> requestHistory = new ConcurrentDictionary<string, List<DateTime>>();
public bool IsRequestAllowed(IPAddress remoteIpAddress)
{
string hash = GetHash(remoteIpAddress);
if (requestHistory.TryGetValue(hash, out var list))
{
bool isLimited = list.Count(e => DateTime.UtcNow - e < TimeSpan.FromHours(1)) >= 5;
if (isLimited)
return false;
}
requestHistory.AddOrUpdate(hash,
(ip) =>
{
var list = new List<DateTime>();
list.Add(DateTime.UtcNow);
return list;
},
(ip, list) =>
{
list.Add(DateTime.UtcNow);
return list;
});
return true;
}
private string GetHash(IPAddress remoteIpAddress)
{
const string pepper = "Somewhere, over the rainbow, way up this pepper.";
var data = Encoding.ASCII.GetBytes(remoteIpAddress.ToString() + pepper);
string hash;
using (SHA512 shaM = new SHA512Managed())
{
byte[] bytes = shaM.ComputeHash(data);
for (int i = 0; i < 1000; i++)
{
bytes = shaM.ComputeHash(bytes);
}
bytes = bytes.Take(bytes.Length / 4).ToArray();
hash = Encoding.ASCII.GetString(bytes);
}
return hash;
}
}
}