sharp-chat/SharpChat/BanManager.cs

193 lines
5.6 KiB
C#
Raw Normal View History

2022-08-30 15:00:58 +00:00
using SharpChat.Flashii;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
2023-02-06 20:14:50 +00:00
using System.Net.Http;
using System.Threading.Tasks;
2022-08-30 15:00:58 +00:00
namespace SharpChat {
public interface IBan {
DateTimeOffset Expires { get; }
string ToString();
}
public class BannedUser : IBan {
public long UserId { get; set; }
public DateTimeOffset Expires { get; set; }
public string Username { get; set; }
public BannedUser() {
}
public BannedUser(FlashiiBan fb) {
UserId = fb.UserId;
Expires = fb.Expires;
Username = fb.Username;
}
2023-02-07 15:01:56 +00:00
public override string ToString() {
return Username;
}
2022-08-30 15:00:58 +00:00
}
public class BannedIPAddress : IBan {
public IPAddress Address { get; set; }
public DateTimeOffset Expires { get; set; }
public BannedIPAddress() {
}
public BannedIPAddress(FlashiiBan fb) {
Address = IPAddress.Parse(fb.UserIP);
Expires = fb.Expires;
}
2023-02-07 15:01:56 +00:00
public override string ToString() {
return Address.ToString();
}
2022-08-30 15:00:58 +00:00
}
public class BanManager : IDisposable {
2023-02-06 20:14:50 +00:00
private readonly List<IBan> BanList = new();
2022-08-30 15:00:58 +00:00
2023-02-06 20:14:50 +00:00
private readonly HttpClient HttpClient;
2022-08-30 15:00:58 +00:00
public readonly ChatContext Context;
2023-02-06 20:14:50 +00:00
2022-08-30 15:00:58 +00:00
public bool IsDisposed { get; private set; }
2023-02-06 20:14:50 +00:00
public BanManager(HttpClient httpClient, ChatContext context) {
HttpClient = httpClient;
2022-08-30 15:00:58 +00:00
Context = context;
2023-02-06 20:14:50 +00:00
RefreshFlashiiBans().Wait();
2022-08-30 15:00:58 +00:00
}
public void Add(ChatUser user, DateTimeOffset expires) {
2023-02-06 20:14:50 +00:00
if(expires <= DateTimeOffset.Now)
2022-08-30 15:00:58 +00:00
return;
2023-02-06 20:14:50 +00:00
lock(BanList) {
2022-08-30 15:00:58 +00:00
BannedUser ban = BanList.OfType<BannedUser>().FirstOrDefault(x => x.UserId == user.UserId);
2023-02-06 20:14:50 +00:00
if(ban == null)
2022-08-30 15:00:58 +00:00
Add(new BannedUser { UserId = user.UserId, Expires = expires, Username = user.Username });
else
ban.Expires = expires;
}
}
public void Add(IPAddress addr, DateTimeOffset expires) {
2023-02-06 20:14:50 +00:00
if(expires <= DateTimeOffset.Now)
2022-08-30 15:00:58 +00:00
return;
2023-02-06 20:14:50 +00:00
lock(BanList) {
2022-08-30 15:00:58 +00:00
BannedIPAddress ban = BanList.OfType<BannedIPAddress>().FirstOrDefault(x => x.Address.Equals(addr));
2023-02-06 20:14:50 +00:00
if(ban == null)
2022-08-30 15:00:58 +00:00
Add(new BannedIPAddress { Address = addr, Expires = expires });
else
ban.Expires = expires;
}
}
private void Add(IBan ban) {
2023-02-06 20:14:50 +00:00
if(ban == null)
2022-08-30 15:00:58 +00:00
return;
2023-02-06 20:14:50 +00:00
lock(BanList)
if(!BanList.Contains(ban))
2022-08-30 15:00:58 +00:00
BanList.Add(ban);
}
public void Remove(ChatUser user) {
lock(BanList)
BanList.RemoveAll(x => x is BannedUser ub && ub.UserId == user.UserId);
}
public void Remove(IPAddress addr) {
lock(BanList)
BanList.RemoveAll(x => x is BannedIPAddress ib && ib.Address.Equals(addr));
}
public void Remove(IBan ban) {
2023-02-06 20:14:50 +00:00
lock(BanList)
2022-08-30 15:00:58 +00:00
BanList.Remove(ban);
}
public DateTimeOffset Check(ChatUser user) {
2023-02-06 20:14:50 +00:00
if(user == null)
2022-08-30 15:00:58 +00:00
return DateTimeOffset.MinValue;
lock(BanList)
return BanList.OfType<BannedUser>().Where(x => x.UserId == user.UserId).FirstOrDefault()?.Expires ?? DateTimeOffset.MinValue;
}
public DateTimeOffset Check(IPAddress addr) {
2023-02-06 20:14:50 +00:00
if(addr == null)
2022-08-30 15:00:58 +00:00
return DateTimeOffset.MinValue;
2023-02-06 20:14:50 +00:00
lock(BanList)
2022-08-30 15:00:58 +00:00
return BanList.OfType<BannedIPAddress>().Where(x => x.Address.Equals(addr)).FirstOrDefault()?.Expires ?? DateTimeOffset.MinValue;
}
public BannedUser GetUser(string username) {
2023-02-06 20:14:50 +00:00
if(username == null)
2022-08-30 15:00:58 +00:00
return null;
2023-02-06 20:14:50 +00:00
if(!long.TryParse(username, out long userId))
2022-08-30 15:00:58 +00:00
userId = 0;
2023-02-06 20:14:50 +00:00
lock(BanList)
2022-08-30 15:00:58 +00:00
return BanList.OfType<BannedUser>().FirstOrDefault(x => x.Username.ToLowerInvariant() == username.ToLowerInvariant() || (userId > 0 && x.UserId == userId));
}
public BannedIPAddress GetIPAddress(IPAddress addr) {
2023-02-06 20:14:50 +00:00
lock(BanList)
2022-08-30 15:00:58 +00:00
return BanList.OfType<BannedIPAddress>().FirstOrDefault(x => x.Address.Equals(addr));
}
public void RemoveExpired() {
lock(BanList)
BanList.RemoveAll(x => x.Expires <= DateTimeOffset.Now);
}
2023-02-06 20:14:50 +00:00
public async Task RefreshFlashiiBans() {
IEnumerable<FlashiiBan> bans = await FlashiiBan.GetListAsync(HttpClient);
2023-02-06 20:14:50 +00:00
if(!bans.Any())
return;
2022-08-30 15:00:58 +00:00
2023-02-06 20:14:50 +00:00
lock(BanList)
foreach(FlashiiBan fb in bans) {
if(!BanList.OfType<BannedUser>().Any(x => x.UserId == fb.UserId))
Add(new BannedUser(fb));
if(!BanList.OfType<BannedIPAddress>().Any(x => x.Address.ToString() == fb.UserIP))
Add(new BannedIPAddress(fb));
2022-08-30 15:00:58 +00:00
}
}
public IEnumerable<IBan> All() {
2023-02-06 20:14:50 +00:00
lock(BanList)
2022-08-30 15:00:58 +00:00
return BanList.ToList();
}
2023-02-07 15:01:56 +00:00
~BanManager() {
DoDispose();
}
2022-08-30 15:00:58 +00:00
2023-02-06 20:14:50 +00:00
public void Dispose() {
DoDispose();
GC.SuppressFinalize(this);
}
2022-08-30 15:00:58 +00:00
2023-02-06 20:14:50 +00:00
private void DoDispose() {
if(IsDisposed)
2022-08-30 15:00:58 +00:00
return;
IsDisposed = true;
BanList.Clear();
}
}
}