5202af9...3ea33fb
This commit is contained in:
@@ -116,22 +116,12 @@ namespace Barotrauma.Networking
|
||||
ChatMessageType messageType = CanUseRadio(orderMsg.Sender) ? ChatMessageType.Radio : ChatMessageType.Default;
|
||||
if (orderMsg.Order.TargetAllCharacters)
|
||||
{
|
||||
#if CLIENT
|
||||
//add the order to the crewmanager only if the host is not controlling a character
|
||||
//OR the character is close enough to hear it
|
||||
if (Character.Controlled == null ||
|
||||
!string.IsNullOrEmpty(ApplyDistanceEffect(orderMsg.Text, messageType, orderMsg.Sender, Character.Controlled)))
|
||||
{
|
||||
GameMain.GameSession?.CrewManager?.AddOrder(
|
||||
new Order(orderMsg.Order.Prefab, orderTargetEntity, (orderTargetEntity as Item)?.GetComponent<ItemComponent>()),
|
||||
orderMsg.Order.Prefab.FadeOutTime);
|
||||
}
|
||||
#endif
|
||||
//do nothing
|
||||
}
|
||||
else if (orderTargetCharacter != null)
|
||||
{
|
||||
orderTargetCharacter.SetOrder(
|
||||
new Order(orderMsg.Order.Prefab, orderTargetEntity, (orderTargetEntity as Item)?.GetComponent<ItemComponent>()),
|
||||
new Order(orderMsg.Order.Prefab, orderTargetEntity, (orderTargetEntity as Item)?.Components.FirstOrDefault(ic => ic.GetType() == orderMsg.Order.ItemComponentType)),
|
||||
orderMsg.OrderOption, orderMsg.Sender);
|
||||
}
|
||||
|
||||
|
||||
@@ -483,7 +483,7 @@ namespace Barotrauma.Networking
|
||||
(OwnerConnection == null || c.Connection != OwnerConnection));
|
||||
foreach (Client c in kickAFK)
|
||||
{
|
||||
KickClient(c, TextManager.Get("DisconnectMessage.AFK"));
|
||||
KickClient(c, "DisconnectMessage.AFK");
|
||||
}
|
||||
|
||||
NetIncomingMessage inc = null;
|
||||
@@ -956,11 +956,11 @@ namespace Barotrauma.Networking
|
||||
Log("Client \"" + sender.Name + "\" banned \"" + bannedClient.Name + "\".", ServerLog.MessageType.ServerMessage);
|
||||
if (durationSeconds > 0)
|
||||
{
|
||||
BanClient(bannedClient, string.IsNullOrEmpty(banReason) ? "Banned by " + sender.Name : banReason, range, TimeSpan.FromSeconds(durationSeconds));
|
||||
BanClient(bannedClient, string.IsNullOrEmpty(banReason) ? $"ServerMessage.BannedBy_[initiator]={sender.Name}" : banReason, range, TimeSpan.FromSeconds(durationSeconds));
|
||||
}
|
||||
else
|
||||
{
|
||||
BanClient(bannedClient, string.IsNullOrEmpty(banReason) ? "Banned by " + sender.Name : banReason, range);
|
||||
BanClient(bannedClient, string.IsNullOrEmpty(banReason) ? $"ServerMessage.BannedBy_[initiator]={sender.Name}" : banReason, range);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1981,14 +1981,14 @@ namespace Barotrauma.Networking
|
||||
client.HasSpawned = false;
|
||||
client.InGame = false;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(msg))
|
||||
if (string.IsNullOrWhiteSpace(msg)) msg = $"ServerMessage.ClientLeftServer_[client]={client.Name}";
|
||||
if (string.IsNullOrWhiteSpace(targetmsg)) targetmsg = "ServerMessage.YouLeftServer";
|
||||
if (!string.IsNullOrWhiteSpace(reason))
|
||||
{
|
||||
msg = $"ServerMessage.ClientLeftServer_[client]={client.Name}";
|
||||
msg += $"; ;ServerMessage.Reason;: ;{reason}";
|
||||
targetmsg += $";\n;ServerMessage.Reason;: ;{reason}";
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(targetmsg)) targetmsg = "ServerMessage.YouLeftServer";
|
||||
if (!string.IsNullOrWhiteSpace(reason)) msg += $";ServerMessage.Reason;{reason}";
|
||||
|
||||
Log(msg, ServerLog.MessageType.ServerMessage);
|
||||
|
||||
if (client.SteamID > 0) { SteamManager.StopAuthSession(client.SteamID); }
|
||||
@@ -2236,7 +2236,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (type.Value != ChatMessageType.MessageBox)
|
||||
{
|
||||
string myReceivedMessage = message;
|
||||
string myReceivedMessage = TextManager.GetServerMessage(message);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(myReceivedMessage) &&
|
||||
(targetClient == null || senderClient == null))
|
||||
|
||||
@@ -0,0 +1,511 @@
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
class UnauthenticatedClient
|
||||
{
|
||||
public readonly NetConnection Connection;
|
||||
public readonly ulong SteamID;
|
||||
public Facepunch.Steamworks.ServerAuth.Status? SteamAuthStatus = null;
|
||||
public readonly int Nonce;
|
||||
|
||||
public int FailedAttempts;
|
||||
|
||||
public float AuthTimer;
|
||||
|
||||
public UnauthenticatedClient(NetConnection connection, int nonce, ulong steamID = 0)
|
||||
{
|
||||
Connection = connection;
|
||||
SteamID = steamID;
|
||||
Nonce = nonce;
|
||||
AuthTimer = 10.0f;
|
||||
FailedAttempts = 0;
|
||||
}
|
||||
}
|
||||
|
||||
partial class GameServer : NetworkMember
|
||||
{
|
||||
private Int32 ownerKey = 0;
|
||||
|
||||
List<UnauthenticatedClient> unauthenticatedClients = new List<UnauthenticatedClient>();
|
||||
|
||||
private void ReadClientSteamAuthRequest(NetIncomingMessage inc, NetConnection senderConnection, out ulong clientSteamID)
|
||||
{
|
||||
clientSteamID = 0;
|
||||
if (!Steam.SteamManager.USE_STEAM)
|
||||
{
|
||||
DebugConsole.Log("Received a Steam auth request from " + senderConnection.RemoteEndPoint + ". Steam authentication not required, handling auth normally.");
|
||||
//not using steam, handle auth normally
|
||||
HandleClientAuthRequest(senderConnection, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (senderConnection == OwnerConnection)
|
||||
{
|
||||
//the client is the owner of the server, no need for authentication
|
||||
//(it would fail with a "duplicate request" error anyway)
|
||||
HandleClientAuthRequest(senderConnection, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
clientSteamID = inc.ReadUInt64();
|
||||
int authTicketLength = inc.ReadInt32();
|
||||
inc.ReadBytes(authTicketLength, out byte[] authTicketData);
|
||||
|
||||
DebugConsole.Log("Received a Steam auth request");
|
||||
DebugConsole.Log(" Steam ID: "+ clientSteamID);
|
||||
DebugConsole.Log(" Auth ticket length: " + authTicketLength);
|
||||
DebugConsole.Log(" Auth ticket data: " +
|
||||
((authTicketData == null) ? "null" : ToolBox.LimitString(string.Concat(authTicketData.Select(b => b.ToString("X2"))), 16)));
|
||||
|
||||
if (senderConnection != OwnerConnection &&
|
||||
serverSettings.BanList.IsBanned(senderConnection.RemoteEndPoint.Address, clientSteamID))
|
||||
{
|
||||
return;
|
||||
}
|
||||
ulong steamID = clientSteamID;
|
||||
if (unauthenticatedClients.Any(uc => uc.Connection == inc.SenderConnection))
|
||||
{
|
||||
var steamAuthedClient = unauthenticatedClients.Find(uc =>
|
||||
uc.Connection == inc.SenderConnection &&
|
||||
uc.SteamID == steamID &&
|
||||
uc.SteamAuthStatus == Facepunch.Steamworks.ServerAuth.Status.OK);
|
||||
if (steamAuthedClient != null)
|
||||
{
|
||||
DebugConsole.Log("Client already authenticated, sending AUTH_RESPONSE again...");
|
||||
HandleClientAuthRequest(inc.SenderConnection, steamID);
|
||||
}
|
||||
DebugConsole.Log("Steam authentication already pending...");
|
||||
return;
|
||||
}
|
||||
|
||||
if (authTicketData == null)
|
||||
{
|
||||
DebugConsole.Log("Invalid request");
|
||||
return;
|
||||
}
|
||||
|
||||
unauthenticatedClients.RemoveAll(uc => uc.Connection == senderConnection);
|
||||
int nonce = CryptoRandom.Instance.Next();
|
||||
var unauthClient = new UnauthenticatedClient(senderConnection, nonce, clientSteamID)
|
||||
{
|
||||
AuthTimer = 20
|
||||
};
|
||||
unauthenticatedClients.Add(unauthClient);
|
||||
|
||||
if (!Steam.SteamManager.StartAuthSession(authTicketData, clientSteamID))
|
||||
{
|
||||
unauthenticatedClients.Remove(unauthClient);
|
||||
if (GameMain.Config.RequireSteamAuthentication)
|
||||
{
|
||||
unauthClient.Connection.Disconnect(DisconnectReason.SteamAuthenticationFailed.ToString());
|
||||
Log("Disconnected unauthenticated client (Steam ID: " + steamID + "). Steam authentication failed.", ServerLog.MessageType.ServerMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.Log("Steam authentication failed, skipping to basic auth...");
|
||||
HandleClientAuthRequest(senderConnection);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public void OnAuthChange(ulong steamID, ulong ownerID, Facepunch.Steamworks.ServerAuth.Status status)
|
||||
{
|
||||
DebugConsole.Log("************ OnAuthChange");
|
||||
DebugConsole.Log(" Steam ID: " + steamID);
|
||||
DebugConsole.Log(" Owner ID: " + ownerID);
|
||||
DebugConsole.Log(" Status: " + status);
|
||||
|
||||
UnauthenticatedClient unauthClient = unauthenticatedClients.Find(uc => uc.SteamID == ownerID);
|
||||
if (unauthClient != null)
|
||||
{
|
||||
unauthClient.SteamAuthStatus = status;
|
||||
switch (status)
|
||||
{
|
||||
case Facepunch.Steamworks.ServerAuth.Status.OK:
|
||||
////steam authentication done, check password next
|
||||
Log("Successfully authenticated client via Steam (Steam ID: " + steamID + ").", ServerLog.MessageType.ServerMessage);
|
||||
HandleClientAuthRequest(unauthClient.Connection, unauthClient.SteamID);
|
||||
break;
|
||||
default:
|
||||
unauthenticatedClients.Remove(unauthClient);
|
||||
if (GameMain.Config.RequireSteamAuthentication)
|
||||
{
|
||||
Log("Disconnected unauthenticated client (Steam ID: " + steamID + "). Steam authentication failed, (" + status + ").", ServerLog.MessageType.ServerMessage);
|
||||
unauthClient.Connection.Disconnect(DisconnectReason.SteamAuthenticationFailed.ToString() + "; (" + status.ToString() + ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.Log("Steam authentication failed (" + status.ToString() + "), skipping to basic auth...");
|
||||
HandleClientAuthRequest(unauthClient.Connection);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.Log(" No unauthenticated clients found with the Steam ID " + steamID);
|
||||
}
|
||||
|
||||
//kick connected client if status becomes invalid (e.g. VAC banned, not connected to steam)
|
||||
if (status != Facepunch.Steamworks.ServerAuth.Status.OK && GameMain.Config.RequireSteamAuthentication)
|
||||
{
|
||||
var connectedClient = connectedClients.Find(c => c.SteamID == ownerID);
|
||||
if (connectedClient != null)
|
||||
{
|
||||
Log("Disconnecting client " + connectedClient.Name + " (Steam ID: " + steamID + "). Steam authentication no longer valid (" + status + ").", ServerLog.MessageType.ServerMessage);
|
||||
KickClient(connectedClient, $"DisconnectMessage.SteamAuthNoLongerValid_[status]={status.ToString()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsServerOwner(NetIncomingMessage inc, NetConnection senderConnection)
|
||||
{
|
||||
string address = senderConnection.RemoteEndPoint.Address.MapToIPv4().ToString();
|
||||
int incKey = inc.ReadInt32();
|
||||
|
||||
if (ownerKey == 0)
|
||||
{
|
||||
return false; //ownership key has been destroyed or has never existed
|
||||
}
|
||||
if (address.ToString() != "127.0.0.1")
|
||||
{
|
||||
return false; //not localhost
|
||||
}
|
||||
|
||||
if (incKey != ownerKey)
|
||||
{
|
||||
return false; //incorrect owner key, how did this even happen
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void HandleOwnership(NetIncomingMessage inc, NetConnection senderConnection)
|
||||
{
|
||||
DebugConsole.Log("HandleOwnership (" + senderConnection.RemoteEndPoint.Address + ")");
|
||||
if (IsServerOwner(inc, senderConnection))
|
||||
{
|
||||
ownerKey = 0; //destroy owner key so nobody else can take ownership of the server
|
||||
OwnerConnection = senderConnection;
|
||||
DebugConsole.NewMessage("Successfully set up server owner", Color.Lime);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleClientAuthRequest(NetConnection connection, ulong steamID = 0)
|
||||
{
|
||||
DebugConsole.Log("HandleClientAuthRequest (steamID " + steamID + ")");
|
||||
|
||||
if (GameMain.Config.RequireSteamAuthentication && connection != OwnerConnection && steamID == 0)
|
||||
{
|
||||
DebugConsole.Log("Disconnecting " + connection.RemoteEndPoint + ", Steam authentication required.");
|
||||
connection.Disconnect(DisconnectReason.SteamAuthenticationRequired.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
//client wants to know if server requires password
|
||||
if (ConnectedClients.Find(c => c.Connection == connection) != null)
|
||||
{
|
||||
//this client has already been authenticated
|
||||
return;
|
||||
}
|
||||
|
||||
UnauthenticatedClient unauthClient = unauthenticatedClients.Find(uc => uc.Connection == connection);
|
||||
if (unauthClient == null)
|
||||
{
|
||||
DebugConsole.Log("Unauthed client, generating a nonce...");
|
||||
//new client, generate nonce and add to unauth queue
|
||||
if (ConnectedClients.Count >= serverSettings.MaxPlayers)
|
||||
{
|
||||
//server is full, can't allow new connection
|
||||
connection.Disconnect(DisconnectReason.ServerFull.ToString());
|
||||
if (steamID > 0) { Steam.SteamManager.StopAuthSession(steamID); }
|
||||
return;
|
||||
}
|
||||
|
||||
int nonce = CryptoRandom.Instance.Next();
|
||||
unauthClient = new UnauthenticatedClient(connection, nonce, steamID);
|
||||
unauthenticatedClients.Add(unauthClient);
|
||||
}
|
||||
unauthClient.AuthTimer = 10.0f;
|
||||
//if the client is already in the queue, getting another unauth request means that our response was lost; resend
|
||||
NetOutgoingMessage nonceMsg = server.CreateMessage();
|
||||
nonceMsg.Write((byte)ServerPacketHeader.AUTH_RESPONSE);
|
||||
if (serverSettings.HasPassword && connection != OwnerConnection)
|
||||
{
|
||||
nonceMsg.Write(true); //true = password
|
||||
nonceMsg.Write((Int32)unauthClient.Nonce); //here's nonce, encrypt with this
|
||||
}
|
||||
else
|
||||
{
|
||||
nonceMsg.Write(false); //false = no password
|
||||
}
|
||||
CompressOutgoingMessage(nonceMsg);
|
||||
DebugConsole.Log("Sending auth response...");
|
||||
server.SendMessage(nonceMsg, connection, NetDeliveryMethod.Unreliable);
|
||||
}
|
||||
|
||||
private void ClientInitRequest(NetIncomingMessage inc)
|
||||
{
|
||||
DebugConsole.Log("Received client init request");
|
||||
if (ConnectedClients.Find(c => c.Connection == inc.SenderConnection) != null)
|
||||
{
|
||||
//this client was already authenticated
|
||||
//another init request means they didn't get any update packets yet
|
||||
DebugConsole.Log("Client already connected, ignoring...");
|
||||
return;
|
||||
}
|
||||
|
||||
UnauthenticatedClient unauthClient = unauthenticatedClients.Find(uc => uc.Connection == inc.SenderConnection);
|
||||
if (unauthClient == null)
|
||||
{
|
||||
//client did not ask for nonce first, can't authorize
|
||||
inc.SenderConnection.Disconnect(DisconnectReason.AuthenticationRequired.ToString());
|
||||
if (unauthClient.SteamID > 0) { Steam.SteamManager.StopAuthSession(unauthClient.SteamID); }
|
||||
return;
|
||||
}
|
||||
|
||||
if (serverSettings.HasPassword && inc.SenderConnection != OwnerConnection)
|
||||
{
|
||||
//decrypt message and compare password
|
||||
string clPw = inc.ReadString();
|
||||
if (!serverSettings.IsPasswordCorrect(clPw, unauthClient.Nonce))
|
||||
{
|
||||
unauthClient.FailedAttempts++;
|
||||
if (unauthClient.FailedAttempts > 3)
|
||||
{
|
||||
//disconnect and ban after too many failed attempts
|
||||
serverSettings.BanList.BanPlayer("Unnamed", unauthClient.Connection.RemoteEndPoint.Address, "DisconnectMessage.TooManyFailedLogins", duration: null);
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.TooManyFailedLogins, "");
|
||||
|
||||
Log(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " has been banned from the server (too many wrong passwords)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " has been banned from the server (too many wrong passwords)", Color.Red);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
//not disconnecting the player here, because they'll still use the same connection and nonce if they try logging in again
|
||||
NetOutgoingMessage reject = server.CreateMessage();
|
||||
reject.Write((byte)ServerPacketHeader.AUTH_FAILURE);
|
||||
reject.Write("Wrong password! You have " + Convert.ToString(4 - unauthClient.FailedAttempts) + " more attempts before you're banned from the server.");
|
||||
Log(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " failed to join the server (incorrect password)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " failed to join the server (incorrect password)", Color.Red);
|
||||
CompressOutgoingMessage(reject);
|
||||
server.SendMessage(reject, unauthClient.Connection, NetDeliveryMethod.Unreliable);
|
||||
unauthClient.AuthTimer = 10.0f;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
string clVersion = inc.ReadString();
|
||||
|
||||
UInt16 contentPackageCount = inc.ReadUInt16();
|
||||
List<string> contentPackageNames = new List<string>();
|
||||
List<string> contentPackageHashes = new List<string>();
|
||||
for (int i = 0; i < contentPackageCount; i++)
|
||||
{
|
||||
string packageName = inc.ReadString();
|
||||
string packageHash = inc.ReadString();
|
||||
contentPackageNames.Add(packageName);
|
||||
contentPackageHashes.Add(packageHash);
|
||||
if (contentPackageCount == 0)
|
||||
{
|
||||
DebugConsole.Log("Client is using content package " +
|
||||
(packageName ?? "null") + " (" + (packageHash ?? "null" + ")"));
|
||||
}
|
||||
}
|
||||
|
||||
if (contentPackageCount == 0)
|
||||
{
|
||||
DebugConsole.Log("Client did not list any content packages.");
|
||||
}
|
||||
|
||||
string clName = Client.SanitizeName(inc.ReadString());
|
||||
if (string.IsNullOrWhiteSpace(clName))
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.NoName, "");
|
||||
|
||||
Log(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " couldn't join the server (no name given)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(inc.SenderConnection.RemoteEndPoint.Address.ToString() + " couldn't join the server (no name given)", Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
if (clVersion != GameMain.Version.ToString())
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.InvalidVersion,
|
||||
$"DisconnectMessage.InvalidVersion_[version]={GameMain.Version.ToString()}_[clientversion]={clVersion}");
|
||||
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong game version)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (wrong game version)", Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
//check if the client is missing any of the content packages the server requires
|
||||
List<ContentPackage> missingPackages = new List<ContentPackage>();
|
||||
foreach (ContentPackage contentPackage in GameMain.SelectedPackages)
|
||||
{
|
||||
if (!contentPackage.HasMultiplayerIncompatibleContent) continue;
|
||||
bool packageFound = false;
|
||||
for (int i = 0; i < contentPackageCount; i++)
|
||||
{
|
||||
if (contentPackageNames[i] == contentPackage.Name && contentPackageHashes[i] == contentPackage.MD5hash.Hash)
|
||||
{
|
||||
packageFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!packageFound) missingPackages.Add(contentPackage);
|
||||
}
|
||||
|
||||
if (missingPackages.Count == 1)
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.MissingContentPackage, $"DisconnectMessage.MissingContentPackage_[missingcontentpackage]={GetPackageStr(missingPackages[0])}");
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (missing content package " + GetPackageStr(missingPackages[0]) + ")", ServerLog.MessageType.Error);
|
||||
return;
|
||||
}
|
||||
else if (missingPackages.Count > 1)
|
||||
{
|
||||
List<string> packageStrs = new List<string>();
|
||||
missingPackages.ForEach(cp => packageStrs.Add(GetPackageStr(cp)));
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.MissingContentPackage, $"DisconnectMessage.MissingContentPackages_[missingcontentpackages]={string.Join(", ", packageStrs)}");
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (missing content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
string GetPackageStr(ContentPackage contentPackage)
|
||||
{
|
||||
return "\"" + contentPackage.Name + "\" (hash " + contentPackage.MD5hash.ShortHash + ")";
|
||||
}
|
||||
|
||||
//check if the client is using any contentpackages that are not compatible with the server
|
||||
List<Pair<string, string>> incompatiblePackages = new List<Pair<string, string>>();
|
||||
for (int i = 0; i < contentPackageNames.Count; i++)
|
||||
{
|
||||
if (!GameMain.Config.SelectedContentPackages.Any(cp => cp.Name == contentPackageNames[i] && cp.MD5hash.Hash == contentPackageHashes[i]))
|
||||
{
|
||||
incompatiblePackages.Add(new Pair<string, string>(contentPackageNames[i], contentPackageHashes[i]));
|
||||
}
|
||||
}
|
||||
|
||||
if (incompatiblePackages.Count == 1)
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.IncompatibleContentPackage,
|
||||
$"DisconnectMessage.IncompatibleContentPackage_[incompatiblecontentpackage]={GetPackageStr2(incompatiblePackages[0])}");
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible content package " + GetPackageStr2(incompatiblePackages[0]) + ")", ServerLog.MessageType.Error);
|
||||
return;
|
||||
}
|
||||
else if (incompatiblePackages.Count > 1)
|
||||
{
|
||||
List<string> packageStrs = new List<string>();
|
||||
incompatiblePackages.ForEach(cp => packageStrs.Add(GetPackageStr2(cp)));
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.IncompatibleContentPackage,
|
||||
$"DisconnectMessage.IncompatibleContentPackages_[incompatiblecontentpackages]={string.Join(", ", packageStrs)}");
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (incompatible content packages " + string.Join(", ", packageStrs) + ")", ServerLog.MessageType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
string GetPackageStr2(Pair<string, string> nameAndHash)
|
||||
{
|
||||
return "\"" + nameAndHash.First + "\" (hash " + Md5Hash.GetShortHash(nameAndHash.Second) + ")";
|
||||
}
|
||||
|
||||
if (!serverSettings.Whitelist.IsWhiteListed(clName, inc.SenderConnection.RemoteEndPoint.Address))
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.NotOnWhitelist, "");
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (not in whitelist)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (not in whitelist)", Color.Red);
|
||||
return;
|
||||
}
|
||||
if (!Client.IsValidName(clName, this))
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.InvalidName, "");
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (invalid name)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (invalid name)", Color.Red);
|
||||
return;
|
||||
}
|
||||
if (inc.SenderConnection != OwnerConnection && Homoglyphs.Compare(clName.ToLower(),Name.ToLower()))
|
||||
{
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.NameTaken, "");
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name taken by the server)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name taken by the server)", Color.Red);
|
||||
return;
|
||||
}
|
||||
Client nameTaken = ConnectedClients.Find(c => Homoglyphs.Compare(c.Name.ToLower(), clName.ToLower()));
|
||||
if (nameTaken != null)
|
||||
{
|
||||
if (nameTaken.Connection.RemoteEndPoint.Address.ToString() == inc.SenderEndPoint.Address.ToString())
|
||||
{
|
||||
//both name and IP address match, replace this player's connection
|
||||
nameTaken.Connection.Disconnect(DisconnectReason.SessionTaken.ToString());
|
||||
nameTaken.Connection = unauthClient.Connection;
|
||||
nameTaken.InitClientSync(); //reinitialize sync ids because this is a new connection
|
||||
unauthenticatedClients.Remove(unauthClient);
|
||||
unauthClient = null;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
//can't authorize this client
|
||||
DisconnectUnauthClient(inc, unauthClient, DisconnectReason.NameTaken, "");
|
||||
Log(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name already taken)", ServerLog.MessageType.Error);
|
||||
DebugConsole.NewMessage(clName + " (" + inc.SenderConnection.RemoteEndPoint.Address.ToString() + ") couldn't join the server (name already taken)", Color.Red);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//new client
|
||||
Client newClient = new Client(clName, GetNewClientID());
|
||||
newClient.InitClientSync();
|
||||
newClient.Connection = unauthClient.Connection;
|
||||
newClient.SteamID = unauthClient.SteamID;
|
||||
unauthenticatedClients.Remove(unauthClient);
|
||||
unauthClient = null;
|
||||
ConnectedClients.Add(newClient);
|
||||
LastClientListUpdateID++;
|
||||
|
||||
if (newClient.Connection == OwnerConnection)
|
||||
{
|
||||
newClient.GivePermission(ClientPermissions.All);
|
||||
newClient.PermittedConsoleCommands.AddRange(DebugConsole.Commands);
|
||||
|
||||
GameMain.Server.UpdateClientPermissions(newClient);
|
||||
GameMain.Server.SendConsoleMessage("Granted all permissions to " + newClient.Name + ".", newClient);
|
||||
}
|
||||
|
||||
GameMain.Server.SendChatMessage($"ServerMessage.JoinedServer_[client]={clName}", ChatMessageType.Server, null);
|
||||
|
||||
var savedPermissions = serverSettings.ClientPermissions.Find(cp =>
|
||||
cp.SteamID > 0 ?
|
||||
cp.SteamID == newClient.SteamID :
|
||||
newClient.IPMatches(cp.IP));
|
||||
|
||||
if (savedPermissions != null)
|
||||
{
|
||||
newClient.SetPermissions(savedPermissions.Permissions, savedPermissions.PermittedCommands);
|
||||
}
|
||||
else
|
||||
{
|
||||
newClient.SetPermissions(ClientPermissions.None, new List<DebugConsole.Command>());
|
||||
}
|
||||
}
|
||||
|
||||
private void DisconnectUnauthClient(NetIncomingMessage inc, UnauthenticatedClient unauthClient, DisconnectReason reason, string message)
|
||||
{
|
||||
inc.SenderConnection.Disconnect(reason.ToString() + "; " + message);
|
||||
if (unauthClient.SteamID > 0) { Steam.SteamManager.StopAuthSession(unauthClient.SteamID); }
|
||||
if (unauthClient != null)
|
||||
{
|
||||
unauthenticatedClients.Remove(unauthClient);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,482 @@
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
partial class ServerSettings
|
||||
{
|
||||
public const string SettingsFile = "serversettings.xml";
|
||||
public static readonly string ClientPermissionsFile = "Data" + Path.DirectorySeparatorChar + "clientpermissions.xml";
|
||||
|
||||
partial void InitProjSpecific()
|
||||
{
|
||||
LoadSettings();
|
||||
LoadClientPermissions();
|
||||
}
|
||||
|
||||
private void WriteNetProperties(NetBuffer outMsg)
|
||||
{
|
||||
outMsg.Write((UInt16)netProperties.Keys.Count);
|
||||
foreach (UInt32 key in netProperties.Keys)
|
||||
{
|
||||
outMsg.Write(key);
|
||||
netProperties[key].Write(outMsg);
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerAdminWrite(NetBuffer outMsg, Client c)
|
||||
{
|
||||
//outMsg.Write(isPublic);
|
||||
//outMsg.Write(EnableUPnP);
|
||||
//outMsg.WritePadBits();
|
||||
//outMsg.Write((UInt16)QueryPort);
|
||||
|
||||
WriteNetProperties(outMsg);
|
||||
WriteMonsterEnabled(outMsg);
|
||||
BanList.ServerAdminWrite(outMsg, c);
|
||||
Whitelist.ServerAdminWrite(outMsg, c);
|
||||
}
|
||||
|
||||
public void ServerWrite(NetBuffer outMsg,Client c)
|
||||
{
|
||||
outMsg.Write(ServerName);
|
||||
outMsg.Write(ServerMessageText);
|
||||
outMsg.WriteRangedInteger(1, 60, TickRate);
|
||||
|
||||
WriteExtraCargo(outMsg);
|
||||
|
||||
Voting.ServerWrite(outMsg);
|
||||
|
||||
if (c.HasPermission(Networking.ClientPermissions.ManageSettings))
|
||||
{
|
||||
outMsg.Write(true);
|
||||
outMsg.WritePadBits();
|
||||
|
||||
ServerAdminWrite(outMsg, c);
|
||||
}
|
||||
else
|
||||
{
|
||||
outMsg.Write(false);
|
||||
outMsg.WritePadBits();
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerRead(NetIncomingMessage incMsg,Client c)
|
||||
{
|
||||
if (!c.HasPermission(Networking.ClientPermissions.ManageSettings)) return;
|
||||
|
||||
NetFlags flags = (NetFlags)incMsg.ReadByte();
|
||||
|
||||
bool changed = false;
|
||||
|
||||
if (flags.HasFlag(NetFlags.Name))
|
||||
{
|
||||
string serverName = incMsg.ReadString();
|
||||
if (ServerName != serverName) changed = true;
|
||||
ServerName = serverName;
|
||||
}
|
||||
|
||||
if (flags.HasFlag(NetFlags.Message))
|
||||
{
|
||||
string serverMessageText = incMsg.ReadString();
|
||||
if (ServerMessageText != serverMessageText) changed = true;
|
||||
ServerMessageText = serverMessageText;
|
||||
}
|
||||
|
||||
if (flags.HasFlag(NetFlags.Properties))
|
||||
{
|
||||
changed |= ReadExtraCargo(incMsg);
|
||||
|
||||
UInt32 count = incMsg.ReadUInt32();
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
UInt32 key = incMsg.ReadUInt32();
|
||||
|
||||
if (netProperties.ContainsKey(key))
|
||||
{
|
||||
netProperties[key].Read(incMsg);
|
||||
GameServer.Log(c.Name + " changed " + netProperties[key].Name + " to " + netProperties[key].Value.ToString(), ServerLog.MessageType.ServerMessage);
|
||||
changed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 size = incMsg.ReadVariableUInt32();
|
||||
incMsg.Position += 8 * size;
|
||||
}
|
||||
}
|
||||
|
||||
bool changedMonsterSettings = incMsg.ReadBoolean(); incMsg.ReadPadBits();
|
||||
changed |= changedMonsterSettings;
|
||||
if (changedMonsterSettings) ReadMonsterEnabled(incMsg);
|
||||
changed |= BanList.ServerAdminRead(incMsg, c);
|
||||
changed |= Whitelist.ServerAdminRead(incMsg, c);
|
||||
}
|
||||
|
||||
if (flags.HasFlag(NetFlags.Misc))
|
||||
{
|
||||
int missionType = GameMain.NetLobbyScreen.MissionTypeIndex + incMsg.ReadByte() - 1;
|
||||
while (missionType < 0) missionType += Enum.GetValues(typeof(MissionType)).Length;
|
||||
while (missionType >= Enum.GetValues(typeof(MissionType)).Length) missionType -= Enum.GetValues(typeof(MissionType)).Length;
|
||||
GameMain.NetLobbyScreen.MissionTypeIndex = missionType;
|
||||
|
||||
int traitorSetting = (int)TraitorsEnabled + incMsg.ReadByte() - 1;
|
||||
if (traitorSetting < 0) traitorSetting = 2;
|
||||
if (traitorSetting > 2) traitorSetting = 0;
|
||||
TraitorsEnabled = (YesNoMaybe)traitorSetting;
|
||||
|
||||
int botCount = BotCount + incMsg.ReadByte() - 1;
|
||||
if (botCount < 0) botCount = MaxBotCount;
|
||||
if (botCount > MaxBotCount) botCount = 0;
|
||||
BotCount = botCount;
|
||||
|
||||
int botSpawnMode = (int)BotSpawnMode + incMsg.ReadByte() - 1;
|
||||
if (botSpawnMode < 0) botSpawnMode = 1;
|
||||
if (botSpawnMode > 1) botSpawnMode = 0;
|
||||
BotSpawnMode = (BotSpawnMode)botSpawnMode;
|
||||
|
||||
float levelDifficulty = incMsg.ReadFloat();
|
||||
if (levelDifficulty >= 0.0f) SelectedLevelDifficulty = levelDifficulty;
|
||||
|
||||
bool changedAutoRestart = incMsg.ReadBoolean();
|
||||
bool autoRestart = incMsg.ReadBoolean();
|
||||
if (changedAutoRestart)
|
||||
{
|
||||
AutoRestart = autoRestart;
|
||||
}
|
||||
|
||||
changed |= true;
|
||||
}
|
||||
|
||||
if (flags.HasFlag(NetFlags.LevelSeed))
|
||||
{
|
||||
GameMain.NetLobbyScreen.LevelSeed = incMsg.ReadString();
|
||||
changed |= true;
|
||||
}
|
||||
|
||||
if (changed) GameMain.NetLobbyScreen.LastUpdateID++;
|
||||
}
|
||||
|
||||
public void SaveSettings()
|
||||
{
|
||||
XDocument doc = new XDocument(new XElement("serversettings"));
|
||||
|
||||
SerializableProperty.SerializeProperties(this, doc.Root, true);
|
||||
|
||||
doc.Root.SetAttributeValue("name", ServerName);
|
||||
doc.Root.SetAttributeValue("public", isPublic);
|
||||
doc.Root.SetAttributeValue("port", GameMain.Server.NetPeerConfiguration.Port);
|
||||
if (Steam.SteamManager.USE_STEAM) doc.Root.SetAttributeValue("queryport", QueryPort);
|
||||
doc.Root.SetAttributeValue("maxplayers", maxPlayers);
|
||||
doc.Root.SetAttributeValue("enableupnp", GameMain.Server.NetPeerConfiguration.EnableUPnP);
|
||||
|
||||
doc.Root.SetAttributeValue("autorestart", autoRestart);
|
||||
|
||||
doc.Root.SetAttributeValue("SubSelection", SubSelectionMode.ToString());
|
||||
doc.Root.SetAttributeValue("ModeSelection", ModeSelectionMode.ToString());
|
||||
doc.Root.SetAttributeValue("LevelDifficulty", ((int)selectedLevelDifficulty).ToString());
|
||||
doc.Root.SetAttributeValue("TraitorsEnabled", TraitorsEnabled.ToString());
|
||||
|
||||
/*doc.Root.SetAttributeValue("BotCount", BotCount);
|
||||
doc.Root.SetAttributeValue("MaxBotCount", MaxBotCount);*/
|
||||
doc.Root.SetAttributeValue("BotSpawnMode", BotSpawnMode.ToString());
|
||||
|
||||
doc.Root.SetAttributeValue("AllowedRandomMissionTypes", string.Join(",", AllowedRandomMissionTypes));
|
||||
|
||||
doc.Root.SetAttributeValue("AllowedClientNameChars", string.Join(",", AllowedClientNameChars.Select(c => c.First + "-" + c.Second)));
|
||||
|
||||
doc.Root.SetAttributeValue("ServerMessage", ServerMessageText);
|
||||
|
||||
XmlWriterSettings settings = new XmlWriterSettings
|
||||
{
|
||||
Indent = true,
|
||||
NewLineOnAttributes = true
|
||||
};
|
||||
|
||||
using (var writer = XmlWriter.Create(SettingsFile, settings))
|
||||
{
|
||||
doc.Save(writer);
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadSettings()
|
||||
{
|
||||
XDocument doc = null;
|
||||
if (File.Exists(SettingsFile))
|
||||
{
|
||||
doc = XMLExtensions.TryLoadXml(SettingsFile);
|
||||
}
|
||||
|
||||
if (doc == null || doc.Root == null)
|
||||
{
|
||||
doc = new XDocument(new XElement("serversettings"));
|
||||
}
|
||||
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, doc.Root);
|
||||
|
||||
AutoRestart = doc.Root.GetAttributeBool("autorestart", false);
|
||||
|
||||
Voting.AllowSubVoting = SubSelectionMode == SelectionMode.Vote;
|
||||
Voting.AllowModeVoting = ModeSelectionMode == SelectionMode.Vote;
|
||||
|
||||
selectedLevelDifficulty = doc.Root.GetAttributeFloat("LevelDifficulty", 20.0f);
|
||||
GameMain.NetLobbyScreen.SetLevelDifficulty(selectedLevelDifficulty);
|
||||
|
||||
var traitorsEnabled = TraitorsEnabled;
|
||||
Enum.TryParse(doc.Root.GetAttributeString("TraitorsEnabled", "No"), out traitorsEnabled);
|
||||
TraitorsEnabled = traitorsEnabled;
|
||||
GameMain.NetLobbyScreen.SetTraitorsEnabled(traitorsEnabled);
|
||||
|
||||
var botSpawnMode = BotSpawnMode.Fill;
|
||||
Enum.TryParse(doc.Root.GetAttributeString("BotSpawnMode", "Fill"), out botSpawnMode);
|
||||
BotSpawnMode = botSpawnMode;
|
||||
|
||||
//"65-90", "97-122", "48-59" = upper and lower case english alphabet and numbers
|
||||
string[] allowedClientNameCharsStr = doc.Root.GetAttributeStringArray("AllowedClientNameChars", new string[] { "65-90", "97-122", "48-59" });
|
||||
foreach (string allowedClientNameCharRange in allowedClientNameCharsStr)
|
||||
{
|
||||
string[] splitRange = allowedClientNameCharRange.Split('-');
|
||||
if (splitRange.Length == 0 || splitRange.Length > 2)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in server settings - " + allowedClientNameCharRange + " is not a valid range for characters allowed in client names.");
|
||||
continue;
|
||||
}
|
||||
|
||||
int min = -1;
|
||||
if (!int.TryParse(splitRange[0], out min))
|
||||
{
|
||||
DebugConsole.ThrowError("Error in server settings - " + allowedClientNameCharRange + " is not a valid range for characters allowed in client names.");
|
||||
continue;
|
||||
}
|
||||
int max = min;
|
||||
if (splitRange.Length == 2)
|
||||
{
|
||||
if (!int.TryParse(splitRange[1], out max))
|
||||
{
|
||||
DebugConsole.ThrowError("Error in server settings - " + allowedClientNameCharRange + " is not a valid range for characters allowed in client names.");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (min > -1 && max > -1) AllowedClientNameChars.Add(new Pair<int, int>(min, max));
|
||||
}
|
||||
|
||||
AllowedRandomMissionTypes = new List<MissionType>();
|
||||
string[] allowedMissionTypeNames = doc.Root.GetAttributeStringArray(
|
||||
"AllowedRandomMissionTypes", Enum.GetValues(typeof(MissionType)).Cast<MissionType>().Select(m => m.ToString()).ToArray());
|
||||
foreach (string missionTypeName in allowedMissionTypeNames)
|
||||
{
|
||||
if (Enum.TryParse(missionTypeName, out MissionType missionType))
|
||||
{
|
||||
if (missionType == Barotrauma.MissionType.None) continue;
|
||||
AllowedRandomMissionTypes.Add(missionType);
|
||||
}
|
||||
}
|
||||
|
||||
ServerName = doc.Root.GetAttributeString("name", "");
|
||||
ServerMessageText = doc.Root.GetAttributeString("ServerMessage", "");
|
||||
|
||||
GameMain.NetLobbyScreen.SelectedModeIdentifier = GameModeIdentifier;
|
||||
GameMain.NetLobbyScreen.MissionTypeName = MissionType;
|
||||
|
||||
GameMain.NetLobbyScreen.SetBotSpawnMode(BotSpawnMode);
|
||||
GameMain.NetLobbyScreen.SetBotCount(BotCount);
|
||||
|
||||
List<string> monsterNames = GameMain.Instance.GetFilesOfType(ContentType.Character).ToList();
|
||||
for (int i = 0; i < monsterNames.Count; i++)
|
||||
{
|
||||
monsterNames[i] = Path.GetFileName(Path.GetDirectoryName(monsterNames[i]));
|
||||
}
|
||||
MonsterEnabled = new Dictionary<string, bool>();
|
||||
foreach (string s in monsterNames)
|
||||
{
|
||||
if (!MonsterEnabled.ContainsKey(s)) MonsterEnabled.Add(s, true);
|
||||
}
|
||||
|
||||
AutoBanTime = doc.Root.GetAttributeFloat("autobantime", 60);
|
||||
MaxAutoBanTime = doc.Root.GetAttributeFloat("maxautobantime", 360);
|
||||
}
|
||||
|
||||
public void LoadClientPermissions()
|
||||
{
|
||||
ClientPermissions.Clear();
|
||||
|
||||
if (!File.Exists(ClientPermissionsFile))
|
||||
{
|
||||
if (File.Exists("Data/clientpermissions.txt"))
|
||||
{
|
||||
LoadClientPermissionsOld("Data/clientpermissions.txt");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
XDocument doc = XMLExtensions.TryLoadXml(ClientPermissionsFile);
|
||||
foreach (XElement clientElement in doc.Root.Elements())
|
||||
{
|
||||
string clientName = clientElement.GetAttributeString("name", "");
|
||||
string clientIP = clientElement.GetAttributeString("ip", "");
|
||||
string steamIdStr = clientElement.GetAttributeString("steamid", "");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(clientName))
|
||||
{
|
||||
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - all clients must have a name and an IP address.");
|
||||
continue;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(clientIP) && string.IsNullOrWhiteSpace(steamIdStr))
|
||||
{
|
||||
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - all clients must have an IP address or a Steam ID.");
|
||||
continue;
|
||||
}
|
||||
|
||||
string permissionsStr = clientElement.GetAttributeString("permissions", "");
|
||||
ClientPermissions permissions = Networking.ClientPermissions.None;
|
||||
if (permissionsStr.ToLowerInvariant() == "all")
|
||||
{
|
||||
foreach (ClientPermissions permission in Enum.GetValues(typeof(ClientPermissions)))
|
||||
{
|
||||
permissions |= permission;
|
||||
}
|
||||
}
|
||||
else if (!Enum.TryParse(permissionsStr, out permissions))
|
||||
{
|
||||
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - \"" + permissionsStr + "\" is not a valid client permission.");
|
||||
continue;
|
||||
}
|
||||
|
||||
List<DebugConsole.Command> permittedCommands = new List<DebugConsole.Command>();
|
||||
if (permissions.HasFlag(Networking.ClientPermissions.ConsoleCommands))
|
||||
{
|
||||
foreach (XElement commandElement in clientElement.Elements())
|
||||
{
|
||||
if (commandElement.Name.ToString().ToLowerInvariant() != "command") continue;
|
||||
|
||||
string commandName = commandElement.GetAttributeString("name", "");
|
||||
DebugConsole.Command command = DebugConsole.FindCommand(commandName);
|
||||
if (command == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - \"" + commandName + "\" is not a valid console command.");
|
||||
continue;
|
||||
}
|
||||
|
||||
permittedCommands.Add(command);
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(steamIdStr))
|
||||
{
|
||||
if (ulong.TryParse(steamIdStr, out ulong steamID))
|
||||
{
|
||||
ClientPermissions.Add(new SavedClientPermission(clientName, steamID, permissions, permittedCommands));
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - \"" + steamIdStr + "\" is not a valid Steam ID.");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ClientPermissions.Add(new SavedClientPermission(clientName, clientIP, permissions, permittedCommands));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method for loading old .txt client permission files to provide backwards compatibility
|
||||
/// </summary>
|
||||
private void LoadClientPermissionsOld(string file)
|
||||
{
|
||||
if (!File.Exists(file)) return;
|
||||
|
||||
string[] lines;
|
||||
try
|
||||
{
|
||||
lines = File.ReadAllLines(file);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to open client permission file " + ClientPermissionsFile, e);
|
||||
return;
|
||||
}
|
||||
|
||||
ClientPermissions.Clear();
|
||||
|
||||
foreach (string line in lines)
|
||||
{
|
||||
string[] separatedLine = line.Split('|');
|
||||
if (separatedLine.Length < 3) continue;
|
||||
|
||||
string name = string.Join("|", separatedLine.Take(separatedLine.Length - 2));
|
||||
string ip = separatedLine[separatedLine.Length - 2];
|
||||
|
||||
ClientPermissions permissions = Networking.ClientPermissions.None;
|
||||
if (Enum.TryParse(separatedLine.Last(), out permissions))
|
||||
{
|
||||
ClientPermissions.Add(new SavedClientPermission(name, ip, permissions, new List<DebugConsole.Command>()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveClientPermissions()
|
||||
{
|
||||
//delete old client permission file
|
||||
if (File.Exists("Data/clientpermissions.txt"))
|
||||
{
|
||||
File.Delete("Data/clientpermissions.txt");
|
||||
}
|
||||
|
||||
GameServer.Log("Saving client permissions", ServerLog.MessageType.ServerMessage);
|
||||
|
||||
XDocument doc = new XDocument(new XElement("ClientPermissions"));
|
||||
|
||||
foreach (SavedClientPermission clientPermission in ClientPermissions)
|
||||
{
|
||||
XElement clientElement = new XElement("Client",
|
||||
new XAttribute("name", clientPermission.Name),
|
||||
new XAttribute("permissions", clientPermission.Permissions.ToString()));
|
||||
|
||||
if (clientPermission.SteamID > 0)
|
||||
{
|
||||
clientElement.Add(new XAttribute("steamid", clientPermission.SteamID));
|
||||
}
|
||||
else
|
||||
{
|
||||
clientElement.Add(new XAttribute("ip", clientPermission.IP));
|
||||
}
|
||||
|
||||
if (clientPermission.Permissions.HasFlag(Barotrauma.Networking.ClientPermissions.ConsoleCommands))
|
||||
{
|
||||
foreach (DebugConsole.Command command in clientPermission.PermittedCommands)
|
||||
{
|
||||
clientElement.Add(new XElement("command", new XAttribute("name", command.names[0])));
|
||||
}
|
||||
}
|
||||
|
||||
doc.Root.Add(clientElement);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
XmlWriterSettings settings = new XmlWriterSettings();
|
||||
settings.Indent = true;
|
||||
settings.NewLineOnAttributes = true;
|
||||
|
||||
using (var writer = XmlWriter.Create(ClientPermissionsFile, settings))
|
||||
{
|
||||
doc.Save(writer);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Saving client permissions to " + ClientPermissionsFile + " failed", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user