improve ban handling edge cases
This commit is contained in:
parent
f90cdbef16
commit
557cc1614f
@ -11,6 +11,7 @@ using SharedLibraryCore.Dtos.Meta.Responses;
|
|||||||
using SharedLibraryCore.Helpers;
|
using SharedLibraryCore.Helpers;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using SharedLibraryCore.QueryHelper;
|
using SharedLibraryCore.QueryHelper;
|
||||||
|
using SharedLibraryCore.Services;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.Meta
|
namespace IW4MAdmin.Application.Meta
|
||||||
@ -19,7 +20,8 @@ namespace IW4MAdmin.Application.Meta
|
|||||||
/// implementation of IResourceQueryHelper
|
/// implementation of IResourceQueryHelper
|
||||||
/// used to pull in penalties applied to a given client id
|
/// used to pull in penalties applied to a given client id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ReceivedPenaltyResourceQueryHelper : IResourceQueryHelper<ClientPaginationRequest, ReceivedPenaltyResponse>
|
public class
|
||||||
|
ReceivedPenaltyResourceQueryHelper : IResourceQueryHelper<ClientPaginationRequest, ReceivedPenaltyResponse>
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IDatabaseContextFactory _contextFactory;
|
private readonly IDatabaseContextFactory _contextFactory;
|
||||||
@ -33,7 +35,8 @@ namespace IW4MAdmin.Application.Meta
|
|||||||
_appConfig = appConfig;
|
_appConfig = appConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ResourceQueryHelperResult<ReceivedPenaltyResponse>> QueryResource(ClientPaginationRequest query)
|
public async Task<ResourceQueryHelperResult<ReceivedPenaltyResponse>> QueryResource(
|
||||||
|
ClientPaginationRequest query)
|
||||||
{
|
{
|
||||||
var linkedPenaltyType = Utilities.LinkedPenaltyTypes();
|
var linkedPenaltyType = Utilities.LinkedPenaltyTypes();
|
||||||
await using var ctx = _contextFactory.CreateContext(enableTracking: false);
|
await using var ctx = _contextFactory.CreateContext(enableTracking: false);
|
||||||
@ -48,13 +51,20 @@ namespace IW4MAdmin.Application.Meta
|
|||||||
linkedPenaltyType.Contains(_penalty.Type) && _penalty.LinkId == linkId.AliasLinkId);
|
linkedPenaltyType.Contains(_penalty.Type) && _penalty.LinkId == linkId.AliasLinkId);
|
||||||
|
|
||||||
IQueryable<EFPenalty> iqIpLinkedPenalties = null;
|
IQueryable<EFPenalty> iqIpLinkedPenalties = null;
|
||||||
|
IQueryable<EFPenalty> identifierPenalties = null;
|
||||||
|
|
||||||
if (!_appConfig.EnableImplicitAccountLinking)
|
if (!_appConfig.EnableImplicitAccountLinking)
|
||||||
{
|
{
|
||||||
var usedIps = await ctx.Aliases.AsNoTracking()
|
var usedIps = await ctx.Aliases.AsNoTracking()
|
||||||
.Where(alias => (alias.LinkId == linkId.AliasLinkId || alias.AliasId == linkId.CurrentAliasId) && alias.IPAddress != null)
|
.Where(alias =>
|
||||||
|
(alias.LinkId == linkId.AliasLinkId || alias.AliasId == linkId.CurrentAliasId) &&
|
||||||
|
alias.IPAddress != null)
|
||||||
.Select(alias => alias.IPAddress).ToListAsync();
|
.Select(alias => alias.IPAddress).ToListAsync();
|
||||||
|
|
||||||
|
identifierPenalties = ctx.PenaltyIdentifiers.AsNoTracking().Where(identifier =>
|
||||||
|
identifier.IPv4Address != null && usedIps.Contains(identifier.IPv4Address))
|
||||||
|
.Select(id => id.Penalty);
|
||||||
|
|
||||||
var aliasedIds = await ctx.Aliases.AsNoTracking().Where(alias => usedIps.Contains(alias.IPAddress))
|
var aliasedIds = await ctx.Aliases.AsNoTracking().Where(alias => usedIps.Contains(alias.IPAddress))
|
||||||
.Select(alias => alias.LinkId)
|
.Select(alias => alias.LinkId)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
@ -71,6 +81,11 @@ namespace IW4MAdmin.Application.Meta
|
|||||||
iqAllPenalties = iqPenalties.Union(iqIpLinkedPenalties);
|
iqAllPenalties = iqPenalties.Union(iqIpLinkedPenalties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (identifierPenalties != null)
|
||||||
|
{
|
||||||
|
iqAllPenalties = iqPenalties.Union(identifierPenalties);
|
||||||
|
}
|
||||||
|
|
||||||
var penalties = await iqAllPenalties
|
var penalties = await iqAllPenalties
|
||||||
.Where(_penalty => _penalty.When < query.Before)
|
.Where(_penalty => _penalty.When < query.Before)
|
||||||
.OrderByDescending(_penalty => _penalty.When)
|
.OrderByDescending(_penalty => _penalty.When)
|
||||||
@ -97,7 +112,7 @@ namespace IW4MAdmin.Application.Meta
|
|||||||
{
|
{
|
||||||
// todo: maybe actually count
|
// todo: maybe actually count
|
||||||
RetrievedResultCount = penalties.Count,
|
RetrievedResultCount = penalties.Count,
|
||||||
Results = penalties
|
Results = penalties.Distinct()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,6 +153,7 @@ namespace SharedLibraryCore.Configuration
|
|||||||
public bool EnablePrivilegedUserPrivacy { get; set; }
|
public bool EnablePrivilegedUserPrivacy { get; set; }
|
||||||
|
|
||||||
[ConfigurationIgnore] public bool EnableImplicitAccountLinking { get; set; } = false;
|
[ConfigurationIgnore] public bool EnableImplicitAccountLinking { get; set; } = false;
|
||||||
|
[ConfigurationIgnore] public TimeSpan RecentAliasIpLinkTimeLimit { get; set; } = TimeSpan.FromDays(7);
|
||||||
|
|
||||||
[ConfigurationIgnore] public TimeSpan MaxClientHistoryTime { get; set; } = TimeSpan.FromHours(12);
|
[ConfigurationIgnore] public TimeSpan MaxClientHistoryTime { get; set; } = TimeSpan.FromHours(12);
|
||||||
|
|
||||||
|
@ -693,13 +693,14 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
if (Level != Permission.Banned)
|
if (Level != Permission.Banned)
|
||||||
{
|
{
|
||||||
Utilities.DefaultLogger.LogInformation(
|
Utilities.DefaultLogger.LogInformation(
|
||||||
"Client {client} has a ban penalty, but they're using a new GUID, we we're updating their level and kicking them",
|
"Client {Client} has a ban penalty, but they're using a new GUID, we we're updating their level and kicking them",
|
||||||
ToString());
|
ToString());
|
||||||
|
|
||||||
await SetLevel(Permission.Banned, autoKickClient).WaitAsync(Utilities.DefaultCommandTimeout,
|
await SetLevel(Permission.Banned, autoKickClient).WaitAsync(Utilities.DefaultCommandTimeout,
|
||||||
CurrentServer.Manager.CancellationToken);
|
CurrentServer.Manager.CancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
Utilities.DefaultLogger.LogInformation("Kicking {client} because they are banned", ToString());
|
Utilities.DefaultLogger.LogInformation("Kicking {Client} because they are banned", ToString());
|
||||||
Kick(loc["WEBFRONT_PENALTY_LIST_BANNED_REASON"], autoKickClient, banPenalty);
|
Kick(loc["WEBFRONT_PENALTY_LIST_BANNED_REASON"], autoKickClient, banPenalty);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -732,6 +733,34 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
ToString());
|
ToString());
|
||||||
Unflag(Utilities.CurrentLocalization.LocalizationIndex["SERVER_AUTOFLAG_UNFLAG"], autoKickClient);
|
Unflag(Utilities.CurrentLocalization.LocalizationIndex["SERVER_AUTOFLAG_UNFLAG"], autoKickClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Level != Permission.Banned)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we want to see if they've recently used a banned IP
|
||||||
|
var recentIPPenalties= await CurrentServer.Manager.GetPenaltyService().ActivePenaltiesByRecentIdentifiers(AliasLinkId);
|
||||||
|
|
||||||
|
var recentBanPenalty =
|
||||||
|
recentIPPenalties.FirstOrDefault(penalty => penalty.Type == EFPenalty.PenaltyType.Ban);
|
||||||
|
|
||||||
|
if (recentBanPenalty is null || !IPAddress.HasValue)
|
||||||
|
{
|
||||||
|
Utilities.DefaultLogger.LogInformation(
|
||||||
|
"Setting {Client} level to user because they are banned but no direct penalties or recent penalty identifiers exist for them",
|
||||||
|
ToString());
|
||||||
|
await SetLevel(Permission.User, autoKickClient).WaitAsync(Utilities.DefaultCommandTimeout,
|
||||||
|
CurrentServer.Manager.CancellationToken);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Utilities.DefaultLogger.LogInformation("Updating penalty for {Client} because they recently used a banned IP", this);
|
||||||
|
await CurrentServer.Manager.GetPenaltyService()
|
||||||
|
.CreatePenaltyIdentifier(recentBanPenalty.PenaltyId, NetworkId, IPAddress.Value);
|
||||||
|
|
||||||
|
Utilities.DefaultLogger.LogInformation("Kicking {Client} because they are banned", ToString());
|
||||||
|
Kick(loc["WEBFRONT_PENALTY_LIST_BANNED_REASON"], autoKickClient, recentBanPenalty);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -59,6 +59,20 @@ namespace SharedLibraryCore.Services
|
|||||||
return newEntity;
|
return newEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task CreatePenaltyIdentifier(int penaltyId, long networkId, int ipv4Address)
|
||||||
|
{
|
||||||
|
await using var context = _contextFactory.CreateContext();
|
||||||
|
var penaltyIdentifiers = new EFPenaltyIdentifier
|
||||||
|
{
|
||||||
|
PenaltyId = penaltyId,
|
||||||
|
NetworkId = networkId,
|
||||||
|
IPv4Address = ipv4Address
|
||||||
|
};
|
||||||
|
|
||||||
|
context.PenaltyIdentifiers.Add(penaltyIdentifiers);
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
public Task<EFPenalty> Delete(EFPenalty entity)
|
public Task<EFPenalty> Delete(EFPenalty entity)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
@ -172,12 +186,34 @@ namespace SharedLibraryCore.Services
|
|||||||
public async Task<List<EFPenalty>> GetActivePenaltiesByIdentifier(int? ip, long networkId)
|
public async Task<List<EFPenalty>> GetActivePenaltiesByIdentifier(int? ip, long networkId)
|
||||||
{
|
{
|
||||||
await using var context = _contextFactory.CreateContext(false);
|
await using var context = _contextFactory.CreateContext(false);
|
||||||
|
|
||||||
var activePenaltiesIds = context.PenaltyIdentifiers.Where(identifier =>
|
var activePenaltiesIds = context.PenaltyIdentifiers.Where(identifier =>
|
||||||
identifier.IPv4Address != null && identifier.IPv4Address == ip || identifier.NetworkId == networkId)
|
identifier.IPv4Address != null && identifier.IPv4Address == ip || identifier.NetworkId == networkId)
|
||||||
.Where(FilterById);
|
.Where(FilterById);
|
||||||
return await activePenaltiesIds.Select(ids => ids.Penalty).ToListAsync();
|
return await activePenaltiesIds.Select(ids => ids.Penalty).ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<List<EFPenalty>> ActivePenaltiesByRecentIdentifiers(int linkId)
|
||||||
|
{
|
||||||
|
await using var context = _contextFactory.CreateContext(false);
|
||||||
|
|
||||||
|
var recentlyUsedIps = await context.Aliases.Where(alias => alias.LinkId == linkId)
|
||||||
|
.Where(alias => alias.IPAddress != null)
|
||||||
|
.Where(alias => alias.DateAdded >= DateTime.UtcNow - _appConfig.RecentAliasIpLinkTimeLimit)
|
||||||
|
.Select(alias => alias.IPAddress).ToListAsync();
|
||||||
|
|
||||||
|
if (!recentlyUsedIps.Any())
|
||||||
|
{
|
||||||
|
return new List<EFPenalty>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var activePenaltiesIds = context.PenaltyIdentifiers
|
||||||
|
.Where(identifier => recentlyUsedIps.Contains(identifier.IPv4Address))
|
||||||
|
.Where(FilterById);
|
||||||
|
|
||||||
|
return await activePenaltiesIds.Select(ids => ids.Penalty).ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
public virtual async Task RemoveActivePenalties(int aliasLinkId, long networkId, int? ipAddress = null)
|
public virtual async Task RemoveActivePenalties(int aliasLinkId, long networkId, int? ipAddress = null)
|
||||||
{
|
{
|
||||||
await using var context = _contextFactory.CreateContext();
|
await using var context = _contextFactory.CreateContext();
|
||||||
|
Loading…
Reference in New Issue
Block a user