Fix IdCardConsoleSystem NRE (#40994)

This commit is contained in:
Leon Friedrich
2025-10-22 00:06:58 +13:00
committed by GitHub
parent 3b210fc28f
commit 0241a4855f

View File

@@ -1,3 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using Content.Server.Chat.Systems; using Content.Server.Chat.Systems;
using Content.Server.Containers; using Content.Server.Containers;
@@ -84,7 +85,7 @@ public sealed class IdCardConsoleSystem : SharedIdCardConsoleSystem
{ {
newState = new IdCardConsoleBoundUserInterfaceState( newState = new IdCardConsoleBoundUserInterfaceState(
component.PrivilegedIdSlot.HasItem, component.PrivilegedIdSlot.HasItem,
PrivilegedIdIsAuthorized(uid, component), PrivilegedIdIsAuthorized(uid, component, out _),
false, false,
null, null,
null, null,
@@ -109,7 +110,7 @@ public sealed class IdCardConsoleSystem : SharedIdCardConsoleSystem
newState = new IdCardConsoleBoundUserInterfaceState( newState = new IdCardConsoleBoundUserInterfaceState(
component.PrivilegedIdSlot.HasItem, component.PrivilegedIdSlot.HasItem,
PrivilegedIdIsAuthorized(uid, component), PrivilegedIdIsAuthorized(uid, component, out _),
true, true,
targetIdComponent.FullName, targetIdComponent.FullName,
targetIdComponent.LocalizedJobTitle, targetIdComponent.LocalizedJobTitle,
@@ -138,13 +139,13 @@ public sealed class IdCardConsoleSystem : SharedIdCardConsoleSystem
if (!Resolve(uid, ref component)) if (!Resolve(uid, ref component))
return; return;
if (component.TargetIdSlot.Item is not { Valid: true } targetId || !PrivilegedIdIsAuthorized(uid, component)) if (component.TargetIdSlot.Item is not { Valid: true } targetId || !PrivilegedIdIsAuthorized(uid, component, out var privilegedId))
return; return;
_idCard.TryChangeFullName(targetId, newFullName, player: player); _idCard.TryChangeFullName(targetId, newFullName, player: player);
_idCard.TryChangeJobTitle(targetId, newJobTitle, player: player); _idCard.TryChangeJobTitle(targetId, newJobTitle, player: player);
if (_prototype.TryIndex<JobPrototype>(newJobProto, out var job) if (_prototype.Resolve(newJobProto, out var job)
&& _prototype.Resolve(job.Icon, out var jobIcon)) && _prototype.Resolve(job.Icon, out var jobIcon))
{ {
_idCard.TryChangeJobIcon(targetId, jobIcon, player: player); _idCard.TryChangeJobIcon(targetId, jobIcon, player: player);
@@ -166,10 +167,7 @@ public sealed class IdCardConsoleSystem : SharedIdCardConsoleSystem
return; return;
} }
var oldTags = _access.TryGetTags(targetId) ?? new List<ProtoId<AccessLevelPrototype>>(); var oldTags = _access.TryGetTags(targetId)?.ToList() ?? new List<ProtoId<AccessLevelPrototype>>();
oldTags = oldTags.ToList();
var privilegedId = component.PrivilegedIdSlot.Item;
if (oldTags.SequenceEqual(newAccessList)) if (oldTags.SequenceEqual(newAccessList))
return; return;
@@ -177,8 +175,7 @@ public sealed class IdCardConsoleSystem : SharedIdCardConsoleSystem
// I hate that C# doesn't have an option for this and don't desire to write this out the hard way. // I hate that C# doesn't have an option for this and don't desire to write this out the hard way.
// var difference = newAccessList.Difference(oldTags); // var difference = newAccessList.Difference(oldTags);
var difference = newAccessList.Union(oldTags).Except(newAccessList.Intersect(oldTags)).ToHashSet(); var difference = newAccessList.Union(oldTags).Except(newAccessList.Intersect(oldTags)).ToHashSet();
// NULL SAFETY: PrivilegedIdIsAuthorized checked this earlier. var privilegedPerms = _accessReader.FindAccessTags(privilegedId.Value);
var privilegedPerms = _accessReader.FindAccessTags(privilegedId!.Value).ToHashSet();
if (!difference.IsSubsetOf(privilegedPerms)) if (!difference.IsSubsetOf(privilegedPerms))
{ {
_sawmill.Warning($"User {ToPrettyString(uid)} tried to modify permissions they could not give/take!"); _sawmill.Warning($"User {ToPrettyString(uid)} tried to modify permissions they could not give/take!");
@@ -191,26 +188,24 @@ public sealed class IdCardConsoleSystem : SharedIdCardConsoleSystem
/*TODO: ECS SharedIdCardConsoleComponent and then log on card ejection, together with the save. /*TODO: ECS SharedIdCardConsoleComponent and then log on card ejection, together with the save.
This current implementation is pretty shit as it logs 27 entries (27 lines) if someone decides to give themselves AA*/ This current implementation is pretty shit as it logs 27 entries (27 lines) if someone decides to give themselves AA*/
_adminLogger.Add(LogType.Action, LogImpact.Medium, _adminLogger.Add(LogType.Action,
$"{ToPrettyString(player):player} has modified {ToPrettyString(targetId):entity} with the following accesses: [{string.Join(", ", addedTags.Union(removedTags))}] [{string.Join(", ", newAccessList)}]"); $"{player} has modified {targetId} with the following accesses: [{string.Join(", ", addedTags.Union(removedTags))}] [{string.Join(", ", newAccessList)}]");
} }
/// <summary> /// <summary>
/// Returns true if there is an ID in <see cref="IdCardConsoleComponent.PrivilegedIdSlot"/> and said ID satisfies the requirements of <see cref="AccessReaderComponent"/>. /// Returns true if there is an ID in <see cref="IdCardConsoleComponent.PrivilegedIdSlot"/> and said ID satisfies the requirements of <see cref="AccessReaderComponent"/>.
/// </summary> /// </summary>
/// <remarks> private bool PrivilegedIdIsAuthorized(EntityUid uid, IdCardConsoleComponent component, [NotNullWhen(true)] out EntityUid? id)
/// Other code relies on the fact this returns false if privileged Id is null. Don't break that invariant.
/// </remarks>
private bool PrivilegedIdIsAuthorized(EntityUid uid, IdCardConsoleComponent? component = null)
{ {
if (!Resolve(uid, ref component)) id = null;
return true; if (component.PrivilegedIdSlot.Item == null)
return false;
id = component.PrivilegedIdSlot.Item;
if (!TryComp<AccessReaderComponent>(uid, out var reader)) if (!TryComp<AccessReaderComponent>(uid, out var reader))
return true; return true;
var privilegedId = component.PrivilegedIdSlot.Item; return _accessReader.IsAllowed(id.Value, uid, reader);
return privilegedId != null && _accessReader.IsAllowed(privilegedId.Value, uid, reader);
} }
private void UpdateStationRecord(EntityUid uid, EntityUid targetId, string newFullName, ProtoId<AccessLevelPrototype> newJobTitle, JobPrototype? newJobProto) private void UpdateStationRecord(EntityUid uid, EntityUid targetId, string newFullName, ProtoId<AccessLevelPrototype> newJobTitle, JobPrototype? newJobProto)