mirror of
https://github.com/space-wizards/space-station-14.git
synced 2026-02-14 19:29:53 +01:00
Ban database refactor (#42495) * Ban DB refactor seems to work at a basic level for PostgreSQL * New ban creation API Supports all the new functionality (multiple players/addresses/hwids/roles/rounds per ban). * Make the migration irreversible * Re-implement ban notifications The server ID check is no longer done as admins may want to place bans spanning multiple rounds irrelevant of the source server. * Fix some split query warnings * Implement migration on SQLite * More comments * Remove required from ban reason SS14.Admin changes would like this * More missing AsSplitQuery() calls * Fix missing ban type filter * Fix old CreateServerBan API with permanent time * Fix department and role ban commands with permanent time * Re-add banhits navigation property Dropped this on accident, SS14.Admin needs it. * More ban API fixes. * Don't fetch ban exemption info for role bans Not relevant, reduces query performance * Regenerate migrations * Fix adminnotes command for players that never connected Would blow up handling null player records. Not a new bug introduced by the refactor, but I ran into it. * Great shame... I accidentally committed submodule update... * Update GDPR scripts * Fix sandbox violation * Fix bans with duplicate info causing DB exceptions Most notably happened with role bans, as multiple departments may include the same role.
122 lines
3.9 KiB
C#
122 lines
3.9 KiB
C#
using System.Collections.Immutable;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using Content.Server.IP;
|
|
using Content.Shared.Database;
|
|
using Robust.Shared.Network;
|
|
|
|
namespace Content.Server.Database;
|
|
|
|
/// <summary>
|
|
/// Implements logic to match a <see cref="BanDef"/> against a player query.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// This implementation is used by in-game ban matching code, and partially by the SQLite database layer.
|
|
/// Some logic is duplicated into both the SQLite and PostgreSQL database layers to provide more optimal SQL queries.
|
|
/// Both should be kept in sync, please!
|
|
/// </para>
|
|
/// </remarks>
|
|
public static class BanMatcher
|
|
{
|
|
/// <summary>
|
|
/// Check whether a ban matches the specified player info.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// This function does not check whether the ban itself is expired or manually unbanned.
|
|
/// </para>
|
|
/// </remarks>
|
|
/// <param name="ban">The ban information.</param>
|
|
/// <param name="player">Information about the player to match against.</param>
|
|
/// <returns>True if the ban matches the provided player info.</returns>
|
|
public static bool BanMatches(BanDef ban, in PlayerInfo player)
|
|
{
|
|
var exemptFlags = player.ExemptFlags;
|
|
// Any flag to bypass BlacklistedRange bans.
|
|
if (exemptFlags != ServerBanExemptFlags.None)
|
|
exemptFlags |= ServerBanExemptFlags.BlacklistedRange;
|
|
|
|
if ((ban.ExemptFlags & exemptFlags) != 0)
|
|
return false;
|
|
|
|
var playerAddr = player.Address;
|
|
if (!player.ExemptFlags.HasFlag(ServerBanExemptFlags.IP)
|
|
&& playerAddr != null
|
|
&& ban.Addresses.Any(addr => playerAddr.IsInSubnet(addr))
|
|
&& (!ban.ExemptFlags.HasFlag(ServerBanExemptFlags.BlacklistedRange) || player.IsNewPlayer))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (player.UserId is { } id && ban.UserIds.Contains(id))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
foreach (var banHwid in ban.HWIds)
|
|
{
|
|
switch (banHwid.Type)
|
|
{
|
|
case HwidType.Legacy:
|
|
if (player.HWId is { Length: > 0 } hwIdVar
|
|
&& hwIdVar.AsSpan().SequenceEqual(banHwid.Hwid.AsSpan()))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
break;
|
|
case HwidType.Modern:
|
|
if (player.ModernHWIds is { Length: > 0 } modernHwIdVar)
|
|
{
|
|
foreach (var hwid in modernHwIdVar)
|
|
{
|
|
if (hwid.AsSpan().SequenceEqual(banHwid.Hwid.AsSpan()))
|
|
return true;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// A simple struct containing player info used to match bans against.
|
|
/// </summary>
|
|
public struct PlayerInfo
|
|
{
|
|
/// <summary>
|
|
/// The user ID of the player.
|
|
/// </summary>
|
|
public NetUserId? UserId;
|
|
|
|
/// <summary>
|
|
/// The IP address of the player.
|
|
/// </summary>
|
|
public IPAddress? Address;
|
|
|
|
/// <summary>
|
|
/// The LEGACY hardware ID of the player. Corresponds with <see cref="NetUserData.HWId"/>.
|
|
/// </summary>
|
|
public ImmutableArray<byte>? HWId;
|
|
|
|
/// <summary>
|
|
/// The modern hardware IDs of the player. Corresponds with <see cref="NetUserData.ModernHWIds"/>.
|
|
/// </summary>
|
|
public ImmutableArray<ImmutableArray<byte>>? ModernHWIds;
|
|
|
|
/// <summary>
|
|
/// Exemption flags the player has been granted.
|
|
/// </summary>
|
|
public ServerBanExemptFlags ExemptFlags;
|
|
|
|
/// <summary>
|
|
/// True if this player is new and is thus eligible for more bans.
|
|
/// </summary>
|
|
public bool IsNewPlayer;
|
|
}
|
|
}
|