using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using Content.Shared.Database;
using Content.Shared.Roles;
using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
namespace Content.Server.Administration.Managers;
public interface IBanManager
{
public void Initialize();
public void Restart();
///
/// Create a server ban in the database, blocking connection for matching players.
///
void CreateServerBan(CreateServerBanInfo banInfo);
///
/// Bans the specified target, address range and / or HWID. One of them must be non-null
///
/// Target user, username or GUID, null for none
/// The person who banned our target
/// Address range, null for none
/// H
/// Number of minutes to ban for. 0 and null mean permanent
/// Severity of the resulting ban note
/// Reason for the ban
[Obsolete("Use CreateServerBan(CreateBanInfo) instead")]
public void CreateServerBan(NetUserId? target,
string? targetUsername,
NetUserId? banningAdmin,
(IPAddress, int)? addressRange,
ImmutableTypedHwid? hwid,
uint? minutes,
NoteSeverity severity,
string reason)
{
var info = new CreateServerBanInfo(reason);
if (target != null)
{
ArgumentNullException.ThrowIfNull(targetUsername);
info.AddUser(target.Value, targetUsername);
}
if (addressRange != null)
info.AddAddressRange(addressRange.Value);
if (hwid != null)
info.AddHWId(hwid);
if (minutes > 0)
info.WithMinutes(minutes.Value);
if (banningAdmin != null)
info.WithBanningAdmin(banningAdmin.Value);
info.WithSeverity(severity);
CreateServerBan(info);
}
///
/// Gets a list of prefixed prototype IDs with the player's role bans.
///
public HashSet? GetRoleBans(NetUserId playerUserId);
///
/// Checks if the player is currently banned from any of the listed roles.
///
/// The player.
/// A list of valid antag prototype IDs.
/// Returns True if an active role ban is found for this player for any of the listed roles.
public bool IsRoleBanned(ICommonSession player, List> antags);
///
/// Checks if the player is currently banned from any of the listed roles.
///
/// The player.
/// A list of valid job prototype IDs.
/// Returns True if an active role ban is found for this player for any of the listed roles.
public bool IsRoleBanned(ICommonSession player, List> jobs);
///
/// Gets a list of prototype IDs with the player's job bans.
///
public HashSet>? GetJobBans(NetUserId playerUserId);
///
/// Gets a list of prototype IDs with the player's antag bans.
///
public HashSet>? GetAntagBans(NetUserId playerUserId);
///
/// Creates a role ban, preventing matching players from playing said roles.
///
public void CreateRoleBan(CreateRoleBanInfo banInfo);
///
/// Pardons a role ban by its ID.
///
/// The id of the role ban to pardon.
/// The admin, if any, that pardoned the role ban.
/// The time at which this role ban was pardoned.
public Task PardonRoleBan(int banId, NetUserId? unbanningAdmin, DateTimeOffset unbanTime);
///
/// Sends role bans to the target
///
/// Player's session
public void SendRoleBans(ICommonSession pSession);
}
///
/// Base info to fill out in created ban records.
///
///
///
[Access(typeof(BanManager), Other = AccessPermissions.Execute)]
public abstract class CreateBanInfo
{
[Access(Other = AccessPermissions.Read)]
public const int DefaultMaskIpv4 = 32;
[Access(Other = AccessPermissions.Read)]
public const int DefaultMaskIpv6 = 64;
internal readonly HashSet<(NetUserId UserId, string UserName)> Users = [];
internal readonly HashSet<(IPAddress Address, int Mask)> AddressRanges = [];
internal readonly HashSet HWIds = [];
internal readonly HashSet RoundIds = [];
internal TimeSpan? Duration;
internal NoteSeverity? Severity;
internal string Reason;
internal NetUserId? BanningAdmin;
protected CreateBanInfo(string reason)
{
Reason = reason;
}
///
/// Add a user to be matched by the ban.
///
///
/// Bans can target multiple users at once.
///
/// The ID of the user.
/// The name of the user (used for logging purposes).
/// The current object, for easy chaining.
public CreateBanInfo AddUser(NetUserId userId, string username)
{
Users.Add((userId, username));
return this;
}
///
/// Add an IP address to be matched by the ban.
///
///
/// Bans can target multiple addresses at once.
///
///
/// The IP address to add. If null, nothing is done.
///
/// The current object, for easy chaining.
public CreateBanInfo AddAddress(IPAddress? address)
{
if (address == null)
return this;
return AddAddressRange(
address,
address.AddressFamily == AddressFamily.InterNetwork ? DefaultMaskIpv4 : DefaultMaskIpv6);
}
///
/// Add an IP address range to be matched by the ban.
///
///
/// Bans can target multiple address ranges at once.
///
/// The current object, for easy chaining.
public CreateBanInfo AddAddressRange((IPAddress Address, int Mask) addressRange)
{
return AddAddressRange(addressRange.Address, addressRange.Mask);
}
///
/// Add an IP address range to be matched by the ban.
///
///
/// Bans can target multiple address ranges at once.
///
/// The current object, for easy chaining.
public CreateBanInfo AddAddressRange(IPAddress address, int mask)
{
AddressRanges.Add((address, mask));
return this;
}
///
/// Add a hardware IP (HWID) to be matched by the ban.
///
///
/// Bans can target multiple HWIDs at once.
///
///
/// The HWID to add. If null, nothing is done.
///
/// The current object, for easy chaining.
public CreateBanInfo AddHWId(ImmutableTypedHwid? hwId)
{
if (hwId != null)
HWIds.Add(hwId);
return this;
}
///
/// Add a relevant round ID to this ban.
///
///
///
/// If not specified, the current round ID is used for the ban.
/// Therefore, the first call to this function will replace the round ID,
/// and further calls will add additional round IDs.
///
///
/// Bans can target multiple round IDs at once.
///
///
/// The current object, for easy chaining.
public CreateBanInfo AddRoundId(int roundId)
{
RoundIds.Add(roundId);
return this;
}
///
/// Set how long the ban will last, in minutes.
///
///
/// If no duration is specified, the ban is permanent.
///
/// The duration of the ban, in minutes.
/// The current object, for easy chaining.
///
/// Thrown if is not a positive number.
///
public CreateBanInfo WithMinutes(int minutes)
{
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(minutes);
return WithMinutes((uint)minutes);
}
///
/// Set how long the ban will last, in minutes.
///
///
/// If no duration is specified, the ban is permanent.
///
/// The duration of the ban, in minutes.
/// The current object, for easy chaining.
///
/// Thrown if is not a positive number.
///
public CreateBanInfo WithMinutes(uint minutes)
{
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(minutes);
return WithDuration(TimeSpan.FromMinutes(minutes));
}
///
/// Set how long the ban will last.
///
///
/// If no duration is specified, the ban is permanent.
///
/// The duration of the ban.
/// The current object, for easy chaining.
///
/// Thrown if is not a positive amount of time.
///
public CreateBanInfo WithDuration(TimeSpan duration)
{
if (duration <= TimeSpan.Zero)
throw new ArgumentOutOfRangeException(nameof(duration), "Duration must be greater than zero.");
Duration = duration;
return this;
}
///
/// Set the severity of the ban.
///
///
/// If no severity is specified, the default is specified through server configuration.
///
///
/// The current object, for easy chaining.
public CreateBanInfo WithSeverity(NoteSeverity severity)
{
Severity = severity;
return this;
}
///
/// Set the reason for the ban.
///
///
/// This replaces the value given via the object constructor.
///
/// The current object, for easy chaining.
public CreateBanInfo WithReason(string reason)
{
Reason = reason;
return this;
}
///
/// Specify the admin responsible for placing the ban.
///
/// The current object, for easy chaining.
public CreateBanInfo WithBanningAdmin(NetUserId? banningAdmin)
{
BanningAdmin = banningAdmin;
return this;
}
}
///
/// Stores info to create server ban records.
///
///
[Access(typeof(BanManager), Other = AccessPermissions.Execute)]
public sealed class CreateServerBanInfo : CreateBanInfo
{
/// The reason for the server ban.
public CreateServerBanInfo(string reason) : base(reason)
{
}
}
///
/// Stores info to create role ban records.
///
///
[Access(typeof(BanManager), Other = AccessPermissions.Execute)]
public sealed class CreateRoleBanInfo : CreateBanInfo
{
internal readonly HashSet> AntagPrototypes = [];
internal readonly HashSet> JobPrototypes = [];
/// The reason for the role ban.
public CreateRoleBanInfo(string reason) : base(reason)
{
}
///
/// Add an antag role that will be unavailable for banned players.
///
///
///
/// Bans can have multiple roles at once.
///
///
/// While not checked in this function, adding a ban with invalid role IDs will cause a
/// when actually creating the ban.
///
///
/// The current object, for easy chaining.
public CreateRoleBanInfo AddAntag(ProtoId protoId)
{
AntagPrototypes.Add(protoId);
return this;
}
///
/// Add a job role that will be unavailable for banned players.
///
///
///
/// Bans can have multiple roles at once.
///
///
/// While not checked in this function, adding a ban with invalid role IDs will cause a
/// when actually creating the ban.
///
///
/// The current object, for easy chaining.
public CreateRoleBanInfo AddJob(ProtoId protoId)
{
JobPrototypes.Add(protoId);
return this;
}
}