Started overhauling the client permission system to make it a bit more flexible. Now the clients can have the permission to use specific console commands (atm these commands are relayed to the server as-is).

TODO: make it possible to give clients console command permissions via the menus and the console, save command permissions, deal with commands that don't work as intended when simply relayed to the server and executed server-side, add "ranks" (preconfigured or custom sets of permissions, e.g. moderator, admin, etc).
This commit is contained in:
Joonas Rikkonen
2017-12-03 22:54:28 +02:00
parent f0225e4312
commit 0840a29ff3
6 changed files with 80 additions and 13 deletions
@@ -134,7 +134,7 @@ namespace Barotrauma
case "entitylist": case "entitylist":
return true; return true;
default: default:
return false; return client.HasConsoleCommandPermission(command);
} }
} }
@@ -19,6 +19,7 @@ namespace Barotrauma.Networking
private GUITickBox endVoteTickBox; private GUITickBox endVoteTickBox;
private ClientPermissions permissions = ClientPermissions.None; private ClientPermissions permissions = ClientPermissions.None;
private List<string> permittedConsoleCommands = new List<string>();
private bool connected; private bool connected;
@@ -596,14 +597,24 @@ namespace Barotrauma.Networking
private void ReadPermissions(NetIncomingMessage inc) private void ReadPermissions(NetIncomingMessage inc)
{ {
List<string> permittedConsoleCommands = new List<string>();
ClientPermissions newPermissions = (ClientPermissions)inc.ReadByte(); ClientPermissions newPermissions = (ClientPermissions)inc.ReadByte();
if (newPermissions.HasFlag(ClientPermissions.ConsoleCommands))
{
UInt16 consoleCommandCount = inc.ReadUInt16();
for (int i = 0; i < consoleCommandCount; i++)
{
permittedConsoleCommands.Add(inc.ReadString());
}
}
if (newPermissions != permissions) if (newPermissions != permissions)
{ {
SetPermissions(newPermissions); SetPermissions(newPermissions, permittedConsoleCommands);
} }
} }
private void SetPermissions(ClientPermissions newPermissions) private void SetPermissions(ClientPermissions newPermissions, List<string> permittedConsoleCommands)
{ {
if (newPermissions == permissions) return; if (newPermissions == permissions) return;
GUIMessageBox.MessageBoxes.RemoveAll(mb => mb.UserData as string == "permissions"); GUIMessageBox.MessageBoxes.RemoveAll(mb => mb.UserData as string == "permissions");
@@ -623,6 +634,8 @@ namespace Barotrauma.Networking
DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false); DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
msg += " - " + attributes[0].Description + "\n"; msg += " - " + attributes[0].Description + "\n";
} }
//TODO: display permitted console commands
} }
permissions = newPermissions; permissions = newPermissions;
new GUIMessageBox("Permissions changed", msg).UserData = "permissions"; new GUIMessageBox("Permissions changed", msg).UserData = "permissions";
@@ -800,7 +813,7 @@ namespace Barotrauma.Networking
gameStarted = inc.ReadBoolean(); gameStarted = inc.ReadBoolean();
bool allowSpectating = inc.ReadBoolean(); bool allowSpectating = inc.ReadBoolean();
SetPermissions((ClientPermissions)inc.ReadByte()); ReadPermissions(inc);
if (gameStarted) if (gameStarted)
{ {
@@ -1161,6 +1174,14 @@ namespace Barotrauma.Networking
return permissions.HasFlag(permission); return permissions.HasFlag(permission);
} }
public bool HasConsoleCommandPermission(string command)
{
if (!permissions.HasFlag(ClientPermissions.ConsoleCommands)) return false;
command = command.ToLowerInvariant();
return permittedConsoleCommands.Any(c => c.ToLowerInvariant() == command);
}
public override void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch) public override void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch)
{ {
base.Draw(spriteBatch); base.Draw(spriteBatch);
@@ -1351,6 +1372,22 @@ namespace Barotrauma.Networking
client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered); client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered);
} }
public void SendConsoleCommand(string command)
{
if (string.IsNullOrWhiteSpace(command))
{
DebugConsole.ThrowError("Cannot send an empty console command to the server!\n" + Environment.StackTrace);
return;
}
NetOutgoingMessage msg = client.CreateMessage();
msg.Write((byte)ClientPacketHeader.SERVER_COMMAND);
msg.Write((byte)ClientPermissions.ConsoleCommands);
msg.Write(command);
client.SendMessage(msg, NetDeliveryMethod.ReliableUnordered);
}
/// <summary> /// <summary>
/// Tell the server to select a submarine (permission required) /// Tell the server to select a submarine (permission required)
/// </summary> /// </summary>
@@ -27,12 +27,14 @@ namespace Barotrauma
static partial class DebugConsole static partial class DebugConsole
{ {
class Command public class Command
{ {
public readonly string[] names; public readonly string[] names;
public readonly string help; public readonly string help;
private Action<string[]> onExecute; private Action<string[]> onExecute;
private bool relayToServer;
public Command(string name, string help, Action<string[]> onExecute) public Command(string name, string help, Action<string[]> onExecute)
{ {
names = name.Split('|'); names = name.Split('|');
@@ -967,10 +969,19 @@ namespace Barotrauma
} }
#if !DEBUG && CLIENT #if !DEBUG && CLIENT
if (GameMain.Client != null && !IsCommandPermitted(splitCommand[0].ToLowerInvariant(), GameMain.Client)) if (GameMain.Client != null)
{ {
ThrowError("You're not permitted to use the command \"" + splitCommand[0].ToLowerInvariant() + "\"!"); if (GameMain.Client.HasConsoleCommandPermission(splitCommand[0].ToLowerInvariant()))
return; {
GameMain.Client.SendConsoleCommand(command);
NewMessage("Server command: "+command, Color.White);
return;
}
if (!IsCommandPermitted(splitCommand[0].ToLowerInvariant(), GameMain.Client))
{
ThrowError("You're not permitted to use the command \"" + splitCommand[0].ToLowerInvariant() + "\"!");
return;
}
} }
#endif #endif
@@ -987,7 +998,7 @@ namespace Barotrauma
if (!commandFound) if (!commandFound)
{ {
ThrowError("Command \""+splitCommand[0]+"\" not found."); ThrowError("Command \"" + splitCommand[0] + "\" not found.");
} }
} }
@@ -21,7 +21,9 @@ namespace Barotrauma.Networking
[Description("Select game mode")] [Description("Select game mode")]
SelectMode = 16, SelectMode = 16,
[Description("Manage campaign")] [Description("Manage campaign")]
ManageCampaign = 32 ManageCampaign = 32,
[Description("Console commands")]
ConsoleCommands = 64
} }
class Client class Client
@@ -79,6 +81,7 @@ namespace Barotrauma.Networking
public float DeleteDisconnectedTimer; public float DeleteDisconnectedTimer;
public ClientPermissions Permissions = ClientPermissions.None; public ClientPermissions Permissions = ClientPermissions.None;
public List<DebugConsole.Command> PermittedConsoleCommands = new List<DebugConsole.Command>();
public bool SpectateOnly; public bool SpectateOnly;
@@ -1928,6 +1928,18 @@ namespace Barotrauma.Networking
var msg = server.CreateMessage(); var msg = server.CreateMessage();
msg.Write((byte)ServerPacketHeader.PERMISSIONS); msg.Write((byte)ServerPacketHeader.PERMISSIONS);
msg.Write((byte)client.Permissions); msg.Write((byte)client.Permissions);
if (client.Permissions.HasFlag(ClientPermissions.ConsoleCommands))
{
msg.Write((UInt16)client.PermittedConsoleCommands.Sum(c => c.names.Length));
foreach (DebugConsole.Command command in client.PermittedConsoleCommands)
{
foreach (string commandName in command.names)
{
msg.Write(commandName);
}
}
}
server.SendMessage(msg, client.Connection, NetDeliveryMethod.ReliableUnordered); server.SendMessage(msg, client.Connection, NetDeliveryMethod.ReliableUnordered);
SaveClientPermissions(); SaveClientPermissions();
@@ -316,6 +316,8 @@ namespace Barotrauma.Networking
public void LoadClientPermissions() public void LoadClientPermissions()
{ {
//TODO: load console command permissions
if (!File.Exists(ClientPermissionsFile)) return; if (!File.Exists(ClientPermissionsFile)) return;
string[] lines; string[] lines;
@@ -348,13 +350,15 @@ namespace Barotrauma.Networking
public void SaveClientPermissions() public void SaveClientPermissions()
{ {
GameServer.Log("Saving client permissions", ServerLog.MessageType.ServerMessage); //TODO: save console command permissions
Log("Saving client permissions", ServerLog.MessageType.ServerMessage);
List<string> lines = new List<string>(); List<string> lines = new List<string>();
foreach (SavedClientPermission clientPermission in clientPermissions) foreach (SavedClientPermission clientPermission in clientPermissions)
{ {
lines.Add(clientPermission.Name + "|" + clientPermission.IP+"|"+clientPermission.Permissions.ToString()); lines.Add(clientPermission.Name + "|" + clientPermission.IP + "|" + clientPermission.Permissions.ToString());
} }
try try