Skip to content

Commit

Permalink
Integrate Modern HWID into content
Browse files Browse the repository at this point in the history
This should be the primary changes for the future-proof "Modern HWID" system implemented into Robust and the auth server.

HWIDs in the database have been given an additional column representing their version, legacy or modern. This is implemented via an EF Core owned entity. By manually setting the column name of the main value column, we can keep DB compatibility and the migration is just adding some type columns.

This new HWID type has to be plumbed through everywhere, resulting in some breaking changes for the DB layer and such.

New bans and player records are placed with the new modern HWID. Old bans are still checked against legacy HWIDs.

Modern HWIDs are presented with a "V2-" prefix to admins, to allow distinguishing them. This is also integrated into the parsing logic for placing new bans.

There's also some code cleanup to reduce copy pasting around the place from my changes.

Requires latest engine to support ImmutableArray<byte> in NetSerializer.
  • Loading branch information
PJB3005 authored and sleepyyapril committed Nov 24, 2024
1 parent ca44453 commit 9ae7874
Show file tree
Hide file tree
Showing 34 changed files with 9,139 additions and 216 deletions.
11 changes: 5 additions & 6 deletions Content.Client/Administration/UI/BanPanel/BanPanel.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ namespace Content.Client.Administration.UI.BanPanel;
[GenerateTypedNameReferences]
public sealed partial class BanPanel : DefaultWindow
{
public event Action<string?, (IPAddress, int)?, bool, byte[]?, bool, uint, string, NoteSeverity, string[]?, bool>? BanSubmitted;
public event Action<string?, (IPAddress, int)?, bool, ImmutableTypedHwid?, bool, uint, string, NoteSeverity, string[]?, bool>? BanSubmitted;
public event Action<string>? PlayerChanged;
private string? PlayerUsername { get; set; }
private (IPAddress, int)? IpAddress { get; set; }
private byte[]? Hwid { get; set; }
private ImmutableTypedHwid? Hwid { get; set; }
private double TimeEntered { get; set; }
private uint Multiplier { get; set; }
private bool HasBanFlag { get; set; }
Expand Down Expand Up @@ -371,9 +371,8 @@ private void OnIpChanged()
private void OnHwidChanged()
{
var hwidString = HwidLine.Text;
var length = 3 * (hwidString.Length / 4) - hwidString.TakeLast(2).Count(c => c == '=');
Hwid = new byte[length];
if (HwidCheckbox.Pressed && !(string.IsNullOrEmpty(hwidString) && LastConnCheckbox.Pressed) && !Convert.TryFromBase64String(hwidString, Hwid, out _))
ImmutableTypedHwid? hwid = null;
if (HwidCheckbox.Pressed && !(string.IsNullOrEmpty(hwidString) && LastConnCheckbox.Pressed) && !ImmutableTypedHwid.TryParse(hwidString, out hwid))
{
ErrorLevel |= ErrorLevelEnum.Hwid;
HwidLine.ModulateSelfOverride = Color.Red;
Expand All @@ -390,7 +389,7 @@ private void OnHwidChanged()
Hwid = null;
return;
}
Hwid = Convert.FromHexString(hwidString);
Hwid = hwid;
}

private void OnTypeChanged()
Expand Down
24 changes: 12 additions & 12 deletions Content.IntegrationTests/Tests/Commands/PardonCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ public async Task PardonTest()
// No bans on record
Assert.Multiple(async () =>
{
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null), Is.Null);
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null, null), Is.Null);
Assert.That(await sDatabase.GetServerBanAsync(1), Is.Null);
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null), Is.Empty);
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null, null), Is.Empty);
});

// Try to pardon a ban that does not exist
Expand All @@ -43,9 +43,9 @@ public async Task PardonTest()
// Still no bans on record
Assert.Multiple(async () =>
{
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null), Is.Null);
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null, null), Is.Null);
Assert.That(await sDatabase.GetServerBanAsync(1), Is.Null);
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null), Is.Empty);
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null, null), Is.Empty);
});

var banReason = "test";
Expand All @@ -57,9 +57,9 @@ public async Task PardonTest()
// Should have one ban on record now
Assert.Multiple(async () =>
{
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null), Is.Not.Null);
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null, null), Is.Not.Null);
Assert.That(await sDatabase.GetServerBanAsync(1), Is.Not.Null);
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null), Has.Count.EqualTo(1));
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null, null), Has.Count.EqualTo(1));
});

await pair.RunTicksSync(5);
Expand All @@ -70,13 +70,13 @@ public async Task PardonTest()
await server.WaitPost(() => sConsole.ExecuteCommand("pardon 2"));

// The existing ban is unaffected
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null), Is.Not.Null);
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null, null), Is.Not.Null);

var ban = await sDatabase.GetServerBanAsync(1);
Assert.Multiple(async () =>
{
Assert.That(ban, Is.Not.Null);
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null), Has.Count.EqualTo(1));
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null, null), Has.Count.EqualTo(1));

// Check that it matches
Assert.That(ban.Id, Is.EqualTo(1));
Expand All @@ -95,7 +95,7 @@ public async Task PardonTest()
await server.WaitPost(() => sConsole.ExecuteCommand("pardon 1"));

// No bans should be returned
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null), Is.Null);
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null, null), Is.Null);

// Direct id lookup returns a pardoned ban
var pardonedBan = await sDatabase.GetServerBanAsync(1);
Expand All @@ -105,7 +105,7 @@ public async Task PardonTest()
Assert.That(pardonedBan, Is.Not.Null);

// The list is still returned since that ignores pardons
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null), Has.Count.EqualTo(1));
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null, null), Has.Count.EqualTo(1));

Assert.That(pardonedBan.Id, Is.EqualTo(1));
Assert.That(pardonedBan.UserId, Is.EqualTo(clientId));
Expand Down Expand Up @@ -133,13 +133,13 @@ public async Task PardonTest()
Assert.Multiple(async () =>
{
// No bans should be returned
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null), Is.Null);
Assert.That(await sDatabase.GetServerBanAsync(null, clientId, null, null), Is.Null);

// Direct id lookup returns a pardoned ban
Assert.That(await sDatabase.GetServerBanAsync(1), Is.Not.Null);

// The list is still returned since that ignores pardons
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null), Has.Count.EqualTo(1));
Assert.That(await sDatabase.GetServerBansAsync(null, clientId, null, null), Has.Count.EqualTo(1));
});

// Reconnect client. Slightly faster than dirtying the pair.
Expand Down
Loading

0 comments on commit 9ae7874

Please sign in to comment.