Add friendcode && puid api (#743)

* Add friendcode && puid api

* Add Message 01/07 for client

* add anticheat
This commit is contained in:
Delusional Syndrome authored and GitHub committed 2026-10-05 21:00:43 +02:00
1 parent e97c28574b
commit bf52365a1a
13 files changed
+84 -18

No files matched your search

+1
View File
@@ -40,6 +40,7 @@ Impostor has an Anticheat that makes it possible to kick cheaters from games aut
| **EnableOwnershipChecks** | `true` | Enables checks that check if players are allowed to perform a certain action on themself or another player. |
| **EnableRoleChecks** | `true` | Enables checks that check if players have the correct role when performing certain role abilities like venting or murdering. |
| **EnableTargetChecks** | `true` | Enables checks that check if certain packets to everyone that should only have been sent to certain players or vice versa. This includes sending votes or network objects. |
| **EnableIdentifierChecks** | `true` | Enables checks that verify if the friendcode and puid a host claims for a player in their PlayerInfo match the ones known for that player. |
| **ForbidProtocolExtensions** | `true` | If disabled allows players to send network packets that go beyond the network packets sent by the vanilla game. This is necessary for most mods that need all players to install it. |
| **EnablePacketSizeChecks** | `true` | Enables checks that verify if network messages exceed the maximum allowed size. |
| **PacketSizeLimit** | `1203` | The maximum allowed size (in bytes) for a network message. The official servers of Among Us requires that a Hazel packet is < 1204 bytes, excluding headers. |
+5 -2
View File
@@ -35,9 +35,12 @@ public enum CheatCategory
/// <summary>A packet was sent that exceeded the maximum allowed RPC size.</summary>
PacketSize,
/// <summary>Legacy category for unsorted anticheat checks.</summary>
Other,
/// <summary>A packet was sent with more items than possible in the game.</summary>
ItemLimits,
/// <summary>Legacy category for unsorted anticheat checks.</summary>
Other,
/// <summary>A packet contained an identifier (friendcode or puid) that does not match the one known for that player.</summary>
Identifiers,
}
@@ -30,6 +30,8 @@ namespace Impostor.Api.Config
public bool EnableTargetChecks { get; set; } = true;
public bool EnableIdentifierChecks { get; set; } = true;
public bool ForbidProtocolExtensions { get; set; } = true;
public bool EnablePacketSizeChecks { get; set; } = true;
+16
View File
@@ -60,6 +60,22 @@ namespace Impostor.Api.Net
/// </remarks>
IDictionary<object, object> Items { get; }
/// <summary>
/// Gets or sets the friendcode of the player.
/// </summary>
/// <remarks>
/// Impostor's HTTP server does not resolve friendcodes, so this value will remain null unless a plugin has written a value in this field.
/// </remarks>
string? FriendCode { get; set; }
/// <summary>
/// Gets or sets the puid of the player.
/// </summary>
/// <remarks>
/// Impostor's HTTP server does not resolve puids, so this value will remain null unless a plugin has written a value in this field.
/// </remarks>
string? Puid { get; set; }
/// <summary>
/// Gets the current game data of the <see cref="IClient" />.
/// </summary>
+1 -1
View File
@@ -1,4 +1,4 @@
using System.Threading.Tasks;
using System.Threading.Tasks;
using Impostor.Api.Games;
using Impostor.Api.Net.Inner;
using Impostor.Api.Net.Inner.Objects;
@@ -43,5 +43,21 @@ namespace Impostor.Api.Net.Inner.Objects
DateTimeOffset LastMurder { get; }
uint PlayerLevel { get; }
/// <summary>
/// Gets the friendcode of the player.
/// </summary>
/// <remarks>
/// Impostor's HTTP server does not resolve friendcodes, so this value will remain null unless a plugin has written a value on the player's client.
/// </remarks>
string? FriendCode { get; }
/// <summary>
/// Gets the puid of the player.
/// </summary>
/// <remarks>
/// Impostor's HTTP server does not resolve puids, so this value will remain null unless a plugin has written a value on the player's client.
/// </remarks>
string? Puid { get; }
}
}
@@ -19,10 +19,8 @@ namespace Impostor.Api.Net.Messages.S2C
writer.Write(player.Client.Name);
player.Client.PlatformSpecificData.Serialize(writer);
writer.WritePacked(player.Character?.PlayerInfo?.PlayerLevel ?? 1);
// ProductUserId and FriendCode are not yet known, so set them to an empty string
writer.Write(string.Empty);
writer.Write(string.Empty);
writer.Write(player.Client.FriendCode ?? string.Empty);
writer.Write(player.Client.Puid ?? string.Empty);
writer.EndMessage();
}
@@ -23,10 +23,8 @@ namespace Impostor.Api.Net.Messages.S2C
writer.Write(ply.Client.Name);
ply.Client.PlatformSpecificData.Serialize(writer);
writer.WritePacked(ply.Character?.PlayerInfo?.PlayerLevel ?? 1);
// ProductUserId and FriendCode are not yet known, so set them to an empty string
writer.Write(string.Empty);
writer.Write(string.Empty);
writer.Write(ply.Client.FriendCode ?? string.Empty);
writer.Write(ply.Client.Puid ?? string.Empty);
}
writer.EndMessage();
+1
View File
@@ -80,6 +80,7 @@ namespace Impostor.Server.Net
CheatCategory.Ownership => _antiCheatConfig.EnableOwnershipChecks,
CheatCategory.Role => _antiCheatConfig.EnableRoleChecks,
CheatCategory.Target => _antiCheatConfig.EnableTargetChecks,
CheatCategory.Identifiers => _antiCheatConfig.EnableIdentifierChecks,
CheatCategory.HostOnlyExtension => _antiCheatConfig.AllowHostOnlyExtensions switch {
CheatingHostMode.Always => false,
CheatingHostMode.IfRequested => !GameVersion.HasDisableServerAuthorityFlag,
+4
View File
@@ -40,6 +40,10 @@ namespace Impostor.Server.Net
public ClientPlayer? Player { get; set; }
public string? FriendCode { get; set; }
public string? Puid { get; set; }
public ColorType? PreviousColor { get; set; } = null;
IClientPlayer? IClient.Player => Player;
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Impostor.Api;
using Impostor.Api.Events.Managers;
using Impostor.Api.Games;
using Impostor.Api.Innersloth;
@@ -59,6 +60,10 @@ namespace Impostor.Server.Net.Inner.Objects
public DeathReason LastDeathReason { get; internal set; }
public string? FriendCode { get; internal set; }
public string? Puid { get; internal set; }
public List<TaskInfo> Tasks { get; internal set; } = new List<TaskInfo>(0);
public DateTimeOffset LastMurder { get; set; }
@@ -128,12 +133,13 @@ namespace Impostor.Server.Net.Inner.Objects
Tasks[i].Serialize(writer);
}
writer.Write(string.Empty); // FriendCode
writer.Write(string.Empty); // PUID
// Resolved by the matchmaker and pushed onto the player by a plugin
writer.Write(FriendCode ?? string.Empty);
writer.Write(Puid ?? string.Empty);
return new ValueTask<bool>(true);
}
public override ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
public override async ValueTask DeserializeAsync(IClientPlayer sender, IClientPlayer? target, IMessageReader reader, bool initialState)
{
PlayerId = reader.ReadByte();
ClientId = reader.ReadPackedInt32();
@@ -175,11 +181,29 @@ namespace Impostor.Server.Net.Inner.Objects
Tasks[i].Deserialize(reader);
}
// Impostor doesn't expose fields that aren't properly validated
reader.ReadString(); // FriendCode
reader.ReadString(); // PUID
var friendCode = reader.ReadString();
var puid = reader.ReadString();
return ValueTask.CompletedTask;
if (Game.GetClientPlayer(ClientId) is { } owner)
{
FriendCode ??= owner.Client.FriendCode;
Puid ??= owner.Client.Puid;
}
await ValidateIdentifiersAsync(sender, friendCode, puid);
}
private async ValueTask ValidateIdentifiersAsync(IClientPlayer sender, string? friendCode, string? puid)
{
var mismatch = (!string.IsNullOrEmpty(friendCode) && FriendCode != null && FriendCode != friendCode)
|| (!string.IsNullOrEmpty(puid) && Puid != null && Puid != puid);
if (!mismatch)
{
return;
}
await sender.Client.ReportCheatAsync(CheatContext.Deserialize, CheatCategory.Identifiers, $"Claimed identifiers for player {ClientId} do not match the values known for that player");
}
public override async ValueTask<bool> HandleRpcAsync(ClientPlayer sender, ClientPlayer? target, RpcCalls call, IMessageReader reader)
@@ -496,6 +496,8 @@ namespace Impostor.Server.Net.State
playerInfo.NetId = _nextNetId++;
playerInfo.OwnerId = ServerOwned;
playerInfo.ClientId = sender.Client.Id;
playerInfo.FriendCode = sender.Client.FriendCode;
playerInfo.Puid = sender.Client.Puid;
playerInfo.PlayerId = GameNet.GameData.GetNextAvailablePlayerId();
// If player played a previous game, restore their color
+1
View File
@@ -21,6 +21,7 @@
"EnableOwnershipChecks": true,
"EnableRoleChecks": true,
"EnableTargetChecks": true,
"EnableIdentifierChecks": true,
"ForbidProtocolExtensions": true,
"EnablePacketSizeChecks": true,
"PacketSizeLimit": 1203