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);
|
2022-08-30 15:21:00 +00:00
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|