Client command perms cleanup. (#9599)
This commit is contained in:
committed by
GitHub
parent
d3c1c9b330
commit
221c23000e
@@ -1,13 +1,8 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Reflection;
|
|
||||||
using Content.Shared.Administration;
|
using Content.Shared.Administration;
|
||||||
using Robust.Client.Console;
|
using Robust.Client.Console;
|
||||||
using Robust.Shared.Console;
|
using Robust.Shared.ContentPack;
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Log;
|
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
using Robust.Shared.Reflection;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Client.Administration.Managers
|
namespace Content.Client.Administration.Managers
|
||||||
{
|
{
|
||||||
@@ -15,10 +10,13 @@ namespace Content.Client.Administration.Managers
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly IClientNetManager _netMgr = default!;
|
[Dependency] private readonly IClientNetManager _netMgr = default!;
|
||||||
[Dependency] private readonly IClientConGroupController _conGroup = default!;
|
[Dependency] private readonly IClientConGroupController _conGroup = default!;
|
||||||
|
[Dependency] private readonly IResourceManager _res = default!;
|
||||||
|
|
||||||
private AdminData? _adminData;
|
private AdminData? _adminData;
|
||||||
private readonly HashSet<string> _availableCommands = new();
|
private readonly HashSet<string> _availableCommands = new();
|
||||||
|
|
||||||
|
private readonly AdminCommandPermissions _localCommandPermissions = new();
|
||||||
|
|
||||||
public event Action? AdminStatusUpdated;
|
public event Action? AdminStatusUpdated;
|
||||||
|
|
||||||
public bool IsActive()
|
public bool IsActive()
|
||||||
@@ -33,6 +31,16 @@ namespace Content.Client.Administration.Managers
|
|||||||
|
|
||||||
public bool CanCommand(string cmdName)
|
public bool CanCommand(string cmdName)
|
||||||
{
|
{
|
||||||
|
if (_adminData != null && _adminData.HasFlag(AdminFlags.Host))
|
||||||
|
{
|
||||||
|
// Host can execute all commands when connected.
|
||||||
|
// Kind of a shortcut to avoid pains during development.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_localCommandPermissions.CanCommand(cmdName, _adminData))
|
||||||
|
return true;
|
||||||
|
|
||||||
return _availableCommands.Contains(cmdName);
|
return _availableCommands.Contains(cmdName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,6 +67,12 @@ namespace Content.Client.Administration.Managers
|
|||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
_netMgr.RegisterNetMessage<MsgUpdateAdminStatus>(UpdateMessageRx);
|
_netMgr.RegisterNetMessage<MsgUpdateAdminStatus>(UpdateMessageRx);
|
||||||
|
|
||||||
|
// Load flags for engine commands, since those don't have the attributes.
|
||||||
|
if (_res.TryContentFileRead(new ResourcePath("/clientCommandPerms.yml"), out var efs))
|
||||||
|
{
|
||||||
|
_localCommandPermissions.LoadPermissionsFromStream(efs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateMessageRx(MsgUpdateAdminStatus message)
|
private void UpdateMessageRx(MsgUpdateAdminStatus message)
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -15,7 +14,6 @@ using Robust.Shared.ContentPack;
|
|||||||
using Robust.Shared.Enums;
|
using Robust.Shared.Enums;
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using YamlDotNet.RepresentationModel;
|
|
||||||
|
|
||||||
|
|
||||||
namespace Content.Server.Administration.Managers
|
namespace Content.Server.Administration.Managers
|
||||||
@@ -42,10 +40,7 @@ namespace Content.Server.Administration.Managers
|
|||||||
|
|
||||||
public IEnumerable<IPlayerSession> AllAdmins => _admins.Select(p => p.Key);
|
public IEnumerable<IPlayerSession> AllAdmins => _admins.Select(p => p.Key);
|
||||||
|
|
||||||
// If a command isn't in this list it's server-console only.
|
private readonly AdminCommandPermissions _commandPermissions = new();
|
||||||
// if a command is in but the flags value is null it's available to everybody.
|
|
||||||
private readonly HashSet<string> _anyCommands = new();
|
|
||||||
private readonly Dictionary<string, AdminFlags[]> _adminCommands = new();
|
|
||||||
|
|
||||||
public bool IsAdmin(IPlayerSession session, bool includeDeAdmin = false)
|
public bool IsAdmin(IPlayerSession session, bool includeDeAdmin = false)
|
||||||
{
|
{
|
||||||
@@ -180,63 +175,19 @@ namespace Content.Server.Administration.Managers
|
|||||||
|
|
||||||
if (flagsReq.Length != 0)
|
if (flagsReq.Length != 0)
|
||||||
{
|
{
|
||||||
_adminCommands.Add(cmdName, flagsReq);
|
_commandPermissions.AdminCommands.Add(cmdName, flagsReq);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_anyCommands.Add(cmdName);
|
_commandPermissions.AnyCommands.Add(cmdName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load flags for engine commands, since those don't have the attributes.
|
// Load flags for engine commands, since those don't have the attributes.
|
||||||
if (_res.TryContentFileRead(new ResourcePath("/engineCommandPerms.yml"), out var efs))
|
if (_res.TryContentFileRead(new ResourcePath("/engineCommandPerms.yml"), out var efs))
|
||||||
{
|
{
|
||||||
LoadPermissionsFromStream(efs);
|
_commandPermissions.LoadPermissionsFromStream(efs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load flags for client-only commands, those don't have the flag attributes, only "AnyCommand".
|
|
||||||
if (_res.TryContentFileRead(new ResourcePath("/clientCommandPerms.yml"), out var cfs))
|
|
||||||
{
|
|
||||||
LoadPermissionsFromStream(cfs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LoadPermissionsFromStream(Stream fs)
|
|
||||||
{
|
|
||||||
using var reader = new StreamReader(fs, EncodingHelpers.UTF8);
|
|
||||||
var yStream = new YamlStream();
|
|
||||||
yStream.Load(reader);
|
|
||||||
var root = (YamlSequenceNode) yStream.Documents[0].RootNode;
|
|
||||||
|
|
||||||
foreach (var child in root)
|
|
||||||
{
|
|
||||||
var map = (YamlMappingNode) child;
|
|
||||||
var commands = map.GetNode<YamlSequenceNode>("Commands").Select(p => p.AsString());
|
|
||||||
if (map.TryGetNode("Flags", out var flagsNode))
|
|
||||||
{
|
|
||||||
var flagNames = flagsNode.AsString().Split(",", StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
var flags = AdminFlagsHelper.NamesToFlags(flagNames);
|
|
||||||
foreach (var cmd in commands)
|
|
||||||
{
|
|
||||||
if (!_adminCommands.TryGetValue(cmd, out var exFlags))
|
|
||||||
{
|
|
||||||
_adminCommands.Add(cmd, new[] {flags});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var newArr = new AdminFlags[exFlags.Length + 1];
|
|
||||||
exFlags.CopyTo(newArr, 0);
|
|
||||||
exFlags[^1] = flags;
|
|
||||||
_adminCommands[cmd] = newArr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_anyCommands.UnionWith(commands);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PromoteHost(IPlayerSession player)
|
public void PromoteHost(IPlayerSession player)
|
||||||
@@ -257,13 +208,13 @@ namespace Content.Server.Administration.Managers
|
|||||||
{
|
{
|
||||||
var msg = new MsgUpdateAdminStatus();
|
var msg = new MsgUpdateAdminStatus();
|
||||||
|
|
||||||
var commands = new List<string>(_anyCommands);
|
var commands = new List<string>(_commandPermissions.AnyCommands);
|
||||||
|
|
||||||
if (_admins.TryGetValue(session, out var adminData))
|
if (_admins.TryGetValue(session, out var adminData))
|
||||||
{
|
{
|
||||||
msg.Admin = adminData.Data;
|
msg.Admin = adminData.Data;
|
||||||
|
|
||||||
commands.AddRange(_adminCommands
|
commands.AddRange(_commandPermissions.AdminCommands
|
||||||
.Where(p => p.Value.Any(f => adminData.Data.HasFlag(f)))
|
.Where(p => p.Value.Any(f => adminData.Data.HasFlag(f)))
|
||||||
.Select(p => p.Key));
|
.Select(p => p.Key));
|
||||||
}
|
}
|
||||||
@@ -400,13 +351,13 @@ namespace Content.Server.Administration.Managers
|
|||||||
|
|
||||||
public bool CanCommand(IPlayerSession session, string cmdName)
|
public bool CanCommand(IPlayerSession session, string cmdName)
|
||||||
{
|
{
|
||||||
if (_anyCommands.Contains(cmdName))
|
if (_commandPermissions.AnyCommands.Contains(cmdName))
|
||||||
{
|
{
|
||||||
// Anybody can use this command.
|
// Anybody can use this command.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_adminCommands.TryGetValue(cmdName, out var flagsReq))
|
if (!_commandPermissions.AdminCommands.TryGetValue(cmdName, out var flagsReq))
|
||||||
{
|
{
|
||||||
// Server-console only.
|
// Server-console only.
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
83
Content.Shared/Administration/AdminCommandPermissions.cs
Normal file
83
Content.Shared/Administration/AdminCommandPermissions.cs
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
using YamlDotNet.RepresentationModel;
|
||||||
|
|
||||||
|
namespace Content.Shared.Administration;
|
||||||
|
|
||||||
|
public sealed class AdminCommandPermissions
|
||||||
|
{
|
||||||
|
// Commands executable by anybody.
|
||||||
|
public readonly HashSet<string> AnyCommands = new();
|
||||||
|
|
||||||
|
// Commands only executable by admins with one of the given flag masks.
|
||||||
|
public readonly Dictionary<string, AdminFlags[]> AdminCommands = new();
|
||||||
|
|
||||||
|
public void LoadPermissionsFromStream(Stream fs)
|
||||||
|
{
|
||||||
|
using var reader = new StreamReader(fs, EncodingHelpers.UTF8);
|
||||||
|
var yStream = new YamlStream();
|
||||||
|
yStream.Load(reader);
|
||||||
|
var root = (YamlSequenceNode) yStream.Documents[0].RootNode;
|
||||||
|
|
||||||
|
foreach (var child in root)
|
||||||
|
{
|
||||||
|
var map = (YamlMappingNode) child;
|
||||||
|
var commands = map.GetNode<YamlSequenceNode>("Commands").Select(p => p.AsString());
|
||||||
|
if (map.TryGetNode("Flags", out var flagsNode))
|
||||||
|
{
|
||||||
|
var flagNames = flagsNode.AsString().Split(",", StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
var flags = AdminFlagsHelper.NamesToFlags(flagNames);
|
||||||
|
foreach (var cmd in commands)
|
||||||
|
{
|
||||||
|
if (!AdminCommands.TryGetValue(cmd, out var exFlags))
|
||||||
|
{
|
||||||
|
AdminCommands.Add(cmd, new[] {flags});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var newArr = new AdminFlags[exFlags.Length + 1];
|
||||||
|
exFlags.CopyTo(newArr, 0);
|
||||||
|
exFlags[^1] = flags;
|
||||||
|
AdminCommands[cmd] = newArr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AnyCommands.UnionWith(commands);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanCommand(string cmdName, AdminData? admin)
|
||||||
|
{
|
||||||
|
if (AnyCommands.Contains(cmdName))
|
||||||
|
{
|
||||||
|
// Anybody can use this command.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!AdminCommands.TryGetValue(cmdName, out var flagsReq))
|
||||||
|
{
|
||||||
|
// Server-console only.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (admin == null)
|
||||||
|
{
|
||||||
|
// Player isn't an admin.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var flagReq in flagsReq)
|
||||||
|
{
|
||||||
|
if (admin.HasFlag(flagReq))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,31 @@
|
|||||||
|
# Available to everybody
|
||||||
|
- Commands:
|
||||||
|
- disconnect
|
||||||
|
- help
|
||||||
|
- list
|
||||||
|
- quit
|
||||||
|
- hardquit
|
||||||
|
- svbind
|
||||||
|
- bind
|
||||||
|
- exec # macro moment
|
||||||
|
- cls
|
||||||
|
- vram
|
||||||
|
- monitor
|
||||||
|
- setmonitor
|
||||||
|
- keyinfo
|
||||||
|
- setclipboard
|
||||||
|
- getclipboard
|
||||||
|
- net_graph
|
||||||
|
- net_watchent
|
||||||
|
- net_draw_interp
|
||||||
|
- devwindow
|
||||||
|
- fill
|
||||||
|
- dumpentities
|
||||||
|
- ">"
|
||||||
|
- gcf
|
||||||
|
- gc
|
||||||
|
- gc_mode
|
||||||
|
|
||||||
- Flags: DEBUG
|
- Flags: DEBUG
|
||||||
Commands:
|
Commands:
|
||||||
- atvrange
|
- atvrange
|
||||||
|
|||||||
@@ -1,32 +1,3 @@
|
|||||||
# Available to everybody
|
|
||||||
- Commands:
|
|
||||||
- disconnect
|
|
||||||
- help
|
|
||||||
- list
|
|
||||||
- quit
|
|
||||||
- hardquit
|
|
||||||
- cvar
|
|
||||||
- svbind
|
|
||||||
- bind
|
|
||||||
- exec # macro moment
|
|
||||||
- clear
|
|
||||||
- vram
|
|
||||||
- monitor
|
|
||||||
- setmonitor
|
|
||||||
- keyinfo
|
|
||||||
- setclipboard
|
|
||||||
- getclipboard
|
|
||||||
- gcf
|
|
||||||
- net_graph
|
|
||||||
- net_watchent
|
|
||||||
- net_draw_interp
|
|
||||||
- devwindow
|
|
||||||
- fill
|
|
||||||
- dumpentities
|
|
||||||
- getcomponentregistration
|
|
||||||
- fuck
|
|
||||||
- ">"
|
|
||||||
|
|
||||||
- Flags: VAREDIT
|
- Flags: VAREDIT
|
||||||
Commands:
|
Commands:
|
||||||
- addcomp
|
- addcomp
|
||||||
@@ -141,6 +112,10 @@
|
|||||||
- scsi
|
- scsi
|
||||||
- csi
|
- csi
|
||||||
- lsasm
|
- lsasm
|
||||||
|
- cvar
|
||||||
|
- gcf
|
||||||
|
- getcomponentregistration
|
||||||
|
- fuck
|
||||||
|
|
||||||
- Flags: QUERY
|
- Flags: QUERY
|
||||||
Commands:
|
Commands:
|
||||||
|
|||||||
Reference in New Issue
Block a user