Use HWIDs for bans.
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using Content.Server.Database;
|
||||
using Content.Shared.Administration;
|
||||
@@ -51,14 +53,16 @@ namespace Content.Server.Administration.Commands
|
||||
return;
|
||||
}
|
||||
|
||||
var resolvedUid = await locator.LookupIdByNameOrIdAsync(target);
|
||||
if (resolvedUid == null)
|
||||
var located = await locator.LookupIdByNameOrIdAsync(target);
|
||||
if (located == null)
|
||||
{
|
||||
shell.WriteError("Unable to find a player with that name.");
|
||||
return;
|
||||
}
|
||||
|
||||
var targetUid = resolvedUid.Value;
|
||||
var targetUid = located.UserId;
|
||||
var targetHWid = located.LastHWId;
|
||||
var targetAddr = located.LastAddress;
|
||||
|
||||
if (player != null && player.UserId == targetUid)
|
||||
{
|
||||
@@ -72,7 +76,29 @@ namespace Content.Server.Administration.Commands
|
||||
expires = DateTimeOffset.Now + TimeSpan.FromMinutes(minutes);
|
||||
}
|
||||
|
||||
await dbMan.AddServerBanAsync(new ServerBanDef(null, targetUid, null, DateTimeOffset.Now, expires, reason, player?.UserId, null));
|
||||
(IPAddress, int)? addrRange = null;
|
||||
if (targetAddr != null)
|
||||
{
|
||||
if (targetAddr.IsIPv4MappedToIPv6)
|
||||
targetAddr = targetAddr.MapToIPv4();
|
||||
|
||||
// Ban /64 for IPv4, /32 for IPv4.
|
||||
var cidr = targetAddr.AddressFamily == AddressFamily.InterNetworkV6 ? 64 : 32;
|
||||
addrRange = (targetAddr, cidr);
|
||||
}
|
||||
|
||||
var banDef = new ServerBanDef(
|
||||
null,
|
||||
targetUid,
|
||||
addrRange,
|
||||
targetHWid,
|
||||
DateTimeOffset.Now,
|
||||
expires,
|
||||
reason,
|
||||
player?.UserId,
|
||||
null);
|
||||
|
||||
await dbMan.AddServerBanAsync(banDef);
|
||||
|
||||
var response = new StringBuilder($"Banned {target} with reason \"{reason}\"");
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace Content.Server.Administration.Commands
|
||||
return;
|
||||
}
|
||||
|
||||
var bans = await dbMan.GetServerBansAsync(null, targetUid);
|
||||
var bans = await dbMan.GetServerBansAsync(null, targetUid, null);
|
||||
|
||||
if (bans.Count == 0)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
@@ -15,6 +16,8 @@ using Robust.Shared.Network;
|
||||
|
||||
namespace Content.Server.Administration
|
||||
{
|
||||
public sealed record LocatedPlayerData(NetUserId UserId, IPAddress? LastAddress, ImmutableArray<byte>? LastHWId);
|
||||
|
||||
/// <summary>
|
||||
/// Utilities for finding user IDs that extend to more than the server database.
|
||||
/// </summary>
|
||||
@@ -28,19 +31,13 @@ namespace Content.Server.Administration
|
||||
/// Look up a user ID by name globally.
|
||||
/// </summary>
|
||||
/// <returns>Null if the player does not exist.</returns>
|
||||
Task<NetUserId?> LookupIdByNameAsync(string playerName, CancellationToken cancel = default);
|
||||
Task<LocatedPlayerData?> LookupIdByNameAsync(string playerName, CancellationToken cancel = default);
|
||||
|
||||
/// <summary>
|
||||
/// If passed a GUID, runs <see cref="DoesPlayerExistAsync"/> and only returns it if the account exists.
|
||||
/// If passed a GUID, looks up the ID and tries to find HWId for it.
|
||||
/// If passed a player name, returns <see cref="LookupIdByNameAsync"/>.
|
||||
/// </summary>
|
||||
Task<NetUserId?> LookupIdByNameOrIdAsync(string playerName, CancellationToken cancel = default);
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the specified user ID is an existing account, globally.
|
||||
/// </summary>
|
||||
/// <returns>True if the player account exists, false otherwise</returns>
|
||||
Task<bool> DoesPlayerExistAsync(NetUserId userId, CancellationToken cancel = default);
|
||||
Task<LocatedPlayerData?> LookupIdByNameOrIdAsync(string playerName, CancellationToken cancel = default);
|
||||
}
|
||||
|
||||
internal sealed class PlayerLocator : IPlayerLocator
|
||||
@@ -49,22 +46,27 @@ namespace Content.Server.Administration
|
||||
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
||||
[Dependency] private readonly IServerDbManager _db = default!;
|
||||
|
||||
public async Task<NetUserId?> LookupIdByNameAsync(string playerName, CancellationToken cancel = default)
|
||||
public async Task<LocatedPlayerData?> LookupIdByNameAsync(string playerName, CancellationToken cancel = default)
|
||||
{
|
||||
// Check people currently on the server, the easiest case.
|
||||
if (_playerManager.TryGetSessionByUsername(playerName, out var session))
|
||||
return session.UserId;
|
||||
{
|
||||
var userId = session.UserId;
|
||||
var address = session.ConnectedClient.RemoteEndPoint.Address;
|
||||
var hwId = session.ConnectedClient.UserData.HWId;
|
||||
return new LocatedPlayerData(userId, address, hwId);
|
||||
}
|
||||
|
||||
// Check database for past players.
|
||||
var record = await _db.GetPlayerRecordByUserName(playerName, cancel);
|
||||
if (record != null)
|
||||
return record.UserId;
|
||||
return new LocatedPlayerData(record.UserId, record.LastSeenAddress, record.HWId);
|
||||
|
||||
// If all else fails, ask the auth server.
|
||||
var client = new HttpClient();
|
||||
var authServer = _configurationManager.GetCVar(CVars.AuthServer);
|
||||
var resp = await client.GetAsync($"{authServer}api/query/name?name={WebUtility.UrlEncode(playerName)}",
|
||||
cancel);
|
||||
var requestUri = $"{authServer}api/query/name?name={WebUtility.UrlEncode(playerName)}";
|
||||
using var resp = await client.GetAsync(requestUri, cancel);
|
||||
|
||||
if (resp.StatusCode == HttpStatusCode.NotFound)
|
||||
return null;
|
||||
@@ -83,45 +85,49 @@ namespace Content.Server.Administration
|
||||
return null;
|
||||
}
|
||||
|
||||
return new NetUserId(responseData.UserId);
|
||||
return new LocatedPlayerData(new NetUserId(responseData.UserId), null, null);
|
||||
}
|
||||
|
||||
public async Task<bool> DoesPlayerExistAsync(NetUserId userId, CancellationToken cancel = default)
|
||||
public async Task<LocatedPlayerData?> LookupIdAsync(NetUserId userId, CancellationToken cancel = default)
|
||||
{
|
||||
// Check people currently on the server, the easiest case.
|
||||
if (_playerManager.ValidSessionId(userId))
|
||||
return true;
|
||||
if (_playerManager.TryGetSessionById(userId, out var session))
|
||||
{
|
||||
var address = session.ConnectedClient.RemoteEndPoint.Address;
|
||||
var hwId = session.ConnectedClient.UserData.HWId;
|
||||
return new LocatedPlayerData(userId, address, hwId);
|
||||
}
|
||||
|
||||
// Check database for past players.
|
||||
var record = await _db.GetPlayerRecordByUserId(userId, cancel);
|
||||
if (record != null)
|
||||
return true;
|
||||
return new LocatedPlayerData(record.UserId, record.LastSeenAddress, record.HWId);
|
||||
|
||||
// If all else fails, ask the auth server.
|
||||
var client = new HttpClient();
|
||||
var authServer = _configurationManager.GetCVar(CVars.AuthServer);
|
||||
var requestUri = $"{authServer}api/query/userid?userid={WebUtility.UrlEncode(userId.UserId.ToString())}";
|
||||
var resp = await client.SendAsync(new HttpRequestMessage(HttpMethod.Head, requestUri), cancel);
|
||||
using var resp = await client.SendAsync(new HttpRequestMessage(HttpMethod.Head, requestUri), cancel);
|
||||
|
||||
if (resp.StatusCode == HttpStatusCode.NotFound)
|
||||
return false;
|
||||
return null;
|
||||
|
||||
if (!resp.IsSuccessStatusCode)
|
||||
{
|
||||
Logger.ErrorS("PlayerLocate", "Auth server returned bad response {StatusCode}!", resp.StatusCode);
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
return true;
|
||||
return new LocatedPlayerData(userId, null, null);
|
||||
}
|
||||
|
||||
public async Task<NetUserId?> LookupIdByNameOrIdAsync(string playerName, CancellationToken cancel = default)
|
||||
public async Task<LocatedPlayerData?> LookupIdByNameOrIdAsync(string playerName, CancellationToken cancel = default)
|
||||
{
|
||||
if (Guid.TryParse(playerName, out var guid))
|
||||
{
|
||||
var userId = new NetUserId(guid);
|
||||
|
||||
return await DoesPlayerExistAsync(userId, cancel) ? userId : null;
|
||||
return await LookupIdAsync(userId, cancel);
|
||||
}
|
||||
|
||||
return await LookupIdByNameAsync(playerName, cancel);
|
||||
|
||||
Reference in New Issue
Block a user