Use HWIDs for bans.

This commit is contained in:
Pieter-Jan Briers
2021-03-22 01:30:50 +01:00
parent 071362ed25
commit a321b4302e
19 changed files with 1589 additions and 181 deletions

View File

@@ -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);