Automated whitelists (#23985)

* Beginnings of making the breadmemes jobs easier

* stuff

* stuff pt. 2

* Stuff pt.3

* Stuff I forgot last time

* Basic whitelist

Only people that are added to the whitelist with the addwhitelist command will be able to join. I call this the "legacy" whitelist

* Remove always deny condition in favor of just breaking if playtime check fails

* Change default whitelist

Default whitelist is now the "legacy" whitelist.

* localization

* Admin check

* minor spelling change

* Fix build

* Whitelist message

* Fix vars not being datafield and spelling mistakes

* Minor spelling mistake

* Change config for salamander

* Reviews and stuff

* Add summaries

* Fix whitelists

* Forgot to add a datafield

* Fixing stuff I guess

* Reuse admin remarks to reduce load when connecting.

* Update log messages to be verbose instead of debug

* Reviews

* whoops

* Explain a bit more how whitelist checking works

* Apply CE's review

* Append Membership to Blacklist and Whitelist conditions

* Fix review comments

* Uncapitalize playerConnectionWhitelist, add to ignored client prototypes

* Make note count field work

* Fix cvar for thingy

---------

Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
This commit is contained in:
Simon
2024-08-27 18:01:17 +02:00
committed by GitHub
parent e59b9c5714
commit f92ef41538
28 changed files with 4289 additions and 47 deletions

View File

@@ -1,5 +1,9 @@
using System.Collections.Immutable;
using System.Linq;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using Content.Server.Connection.Whitelist;
using Content.Server.Connection.Whitelist.Conditions;
using System.Runtime.InteropServices;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
@@ -14,6 +18,7 @@ using Robust.Server.Player;
using Robust.Shared.Configuration;
using Robust.Shared.Enums;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
using Robust.Shared.Player;
using Robust.Shared.Timing;
@@ -26,6 +31,7 @@ namespace Content.Server.Connection
public interface IConnectionManager
{
void Initialize();
void PostInit();
/// <summary>
/// Temporarily allow a user to bypass regular connection requirements.
@@ -43,7 +49,7 @@ namespace Content.Server.Connection
/// <summary>
/// Handles various duties like guest username assignment, bans, connection logs, etc...
/// </summary>
public sealed class ConnectionManager : IConnectionManager
public sealed partial class ConnectionManager : IConnectionManager
{
[Dependency] private readonly IServerDbManager _dbManager = default!;
[Dependency] private readonly IPlayerManager _plyMgr = default!;
@@ -52,12 +58,14 @@ namespace Content.Server.Connection
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly ILocalizationManager _loc = default!;
[Dependency] private readonly ServerDbEntryManager _serverDbEntry = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly ILogManager _logManager = default!;
[Dependency] private readonly IChatManager _chatManager = default!;
private readonly Dictionary<NetUserId, TimeSpan> _temporaryBypasses = [];
private ISawmill _sawmill = default!;
private readonly Dictionary<NetUserId, TimeSpan> _temporaryBypasses = [];
public void Initialize()
{
@@ -268,20 +276,33 @@ namespace Content.Server.Connection
return (ConnectionDenyReason.Full, Loc.GetString("soft-player-cap-full"), null);
}
if (_cfg.GetCVar(CCVars.WhitelistEnabled))
// Checks for whitelist IF it's enabled AND the user isn't an admin. Admins are always allowed.
if (_cfg.GetCVar(CCVars.WhitelistEnabled) && adminData is null)
{
var min = _cfg.GetCVar(CCVars.WhitelistMinPlayers);
var max = _cfg.GetCVar(CCVars.WhitelistMaxPlayers);
var playerCountValid = _plyMgr.PlayerCount >= min && _plyMgr.PlayerCount < max;
if (playerCountValid && await _db.GetWhitelistStatusAsync(userId) == false
&& adminData is null)
if (_whitelists is null)
{
var msg = Loc.GetString(_cfg.GetCVar(CCVars.WhitelistReason));
// was the whitelist playercount changed?
if (min > 0 || max < int.MaxValue)
msg += "\n" + Loc.GetString("whitelist-playercount-invalid", ("min", min), ("max", max));
return (ConnectionDenyReason.Whitelist, msg, null);
_sawmill.Error("Whitelist enabled but no whitelists loaded.");
// Misconfigured, deny everyone.
return (ConnectionDenyReason.Whitelist, Loc.GetString("whitelist-misconfigured"), null);
}
foreach (var whitelist in _whitelists)
{
if (!IsValid(whitelist, _plyMgr.PlayerCount))
{
// Not valid for current player count.
continue;
}
var whitelistStatus = await IsWhitelisted(whitelist, e.UserData, _sawmill);
if (!whitelistStatus.isWhitelisted)
{
// Not whitelisted.
return (ConnectionDenyReason.Whitelist, Loc.GetString("whitelist-fail-prefix", ("msg", whitelistStatus.denyMessage!)), null);
}
// Whitelisted, don't check any more.
break;
}
}