diff --git a/Admin/Application.csproj b/Admin/Application.csproj
index ece9d59f..6f64bf84 100644
--- a/Admin/Application.csproj
+++ b/Admin/Application.csproj
@@ -158,6 +158,9 @@
Always
+
+ PreserveNewest
+
PreserveNewest
diff --git a/Admin/Kayak.cs b/Admin/Kayak.cs
index 1a62ccbc..12dc5213 100644
--- a/Admin/Kayak.cs
+++ b/Admin/Kayak.cs
@@ -45,23 +45,41 @@ namespace IW4MAdmin
querySet = System.Web.HttpUtility.ParseQueryString(SharedLibrary.Utilities.StripIllegalCharacters(request.QueryString));
querySet.Set("IP", IP);
- SharedLibrary.HttpResponse requestedPage = WebService.GetPage(request.Path, querySet, request.Headers);
- var headers = new HttpResponseHead()
+ try
{
- Status = "200 OK",
- Headers = new Dictionary()
+ SharedLibrary.HttpResponse requestedPage = WebService.GetPage(request.Path, querySet, request.Headers);
+
+ var headers = new HttpResponseHead()
+ {
+ Status = "200 OK",
+ Headers = new Dictionary()
{
{ "Content-Type", requestedPage.contentType },
{ "Content-Length", requestedPage.content.Length.ToString() },
{ "Access-Control-Allow-Origin", "*" },
}
- };
+ };
- foreach (var key in requestedPage.additionalHeaders.Keys)
- headers.Headers.Add(key, requestedPage.additionalHeaders[key]);
+ foreach (var key in requestedPage.additionalHeaders.Keys)
+ headers.Headers.Add(key, requestedPage.additionalHeaders[key]);
- response.OnResponse(headers, new BufferedProducer(requestedPage.content));
+ response.OnResponse(headers, new BufferedProducer(requestedPage.content));
+ }
+
+ catch (Exception e)
+ {
+ ApplicationManager.GetInstance().Logger.WriteError($"Webfront error during request: {e.Message}");
+ response.OnResponse(new HttpResponseHead()
+ {
+ Status = "500 Internal Server Error",
+ Headers = new Dictionary()
+ {
+ { "Content-Type", "text/html" },
+ { "Content-Length", "0"},
+ }
+ }, new BufferedProducer(""));
+ }
}
}
diff --git a/Admin/Manager.cs b/Admin/Manager.cs
index 13f40b20..7a90b3b7 100644
--- a/Admin/Manager.cs
+++ b/Admin/Manager.cs
@@ -161,6 +161,7 @@ namespace IW4MAdmin
Commands.Add(new CExecuteRCON("rcon", "send rcon command to server. syntax: !rcon ", "rcon", Player.Permission.Owner, 1, false));
Commands.Add(new CFindAllPlayers("findall", "find a player by their aliase(s). syntax: !findall ", "fa", Player.Permission.Moderator, 1, false));
Commands.Add(new CPlugins("plugins", "view all loaded plugins. syntax: !plugins", "p", Player.Permission.Administrator, 0, false));
+ Commands.Add(new CIP("ip", "view your external IP address. syntax: !ip", "getexternalip", Player.Permission.User, 0, false));
foreach (Command C in SharedLibrary.Plugins.PluginImporter.ActiveCommands)
Commands.Add(C);
@@ -247,5 +248,49 @@ namespace IW4MAdmin
return ActiveClients;
}
+
+ public IList GetAliasClients(Player Origin)
+ {
+ List databaseIDs = new List();
+
+ foreach (Aliases A in GetAliases(Origin))
+ databaseIDs.Add(A.Number);
+
+ return GetClientDatabase().GetPlayers(databaseIDs);
+ }
+
+ public IList GetAliases(Player Origin)
+ {
+ List allAliases = new List();
+
+ if (Origin == null)
+ return allAliases;
+
+ Aliases currentIdentityAliases = GetAliasesDatabase().GetPlayerAliases(Origin.DatabaseID);
+
+ if (currentIdentityAliases == null)
+ return allAliases;
+
+ GetAliases(allAliases, currentIdentityAliases);
+ if (Origin.Alias != null)
+ allAliases.Add(Origin.Alias);
+ return allAliases;
+ }
+
+ private void GetAliases(List returnAliases, Aliases currentAlias)
+ {
+ foreach (String IP in currentAlias.IPS)
+ {
+ List Matching = GetAliasesDatabase().GetPlayerAliases(IP);
+ foreach (Aliases I in Matching)
+ {
+ if (!returnAliases.Contains(I) && returnAliases.Find(x => x.Number == I.Number) == null)
+ {
+ returnAliases.Add(I);
+ GetAliases(returnAliases, I);
+ }
+ }
+ }
+ }
}
}
diff --git a/Admin/Server.cs b/Admin/Server.cs
index 5252fabb..d576a746 100644
--- a/Admin/Server.cs
+++ b/Admin/Server.cs
@@ -15,40 +15,6 @@ namespace IW4MAdmin
{
public IW4MServer(IManager mgr, ServerConfiguration cfg) : base(mgr, cfg) { }
- private void GetAliases(List returnAliases, Aliases currentAlias)
- {
- foreach(String IP in currentAlias.IPS)
- {
- List Matching = Manager.GetAliasesDatabase().GetPlayerAliases(IP);
- foreach(Aliases I in Matching)
- {
- if (!returnAliases.Contains(I) && returnAliases.Find(x => x.Number == I.Number) == null)
- {
- returnAliases.Add(I);
- GetAliases(returnAliases, I);
- }
- }
- }
- }
-
- public override List GetAliases(Player Origin)
- {
- List allAliases = new List();
-
- if (Origin == null)
- return allAliases;
-
- Aliases currentIdentityAliases = Manager.GetAliasesDatabase().GetPlayerAliases(Origin.DatabaseID);
-
- if (currentIdentityAliases == null)
- return allAliases;
-
- GetAliases(allAliases, currentIdentityAliases);
- if (Origin.Alias != null)
- allAliases.Add(Origin.Alias);
- return allAliases;
- }
-
override public async Task AddPlayer(Player P)
{
if (P.ClientID < 0 || P.ClientID > (Players.Count-1) || P.Ping < 1 || P.Ping == 999) // invalid index
@@ -123,7 +89,7 @@ namespace IW4MAdmin
return true;
}
- var newPlayerAliases = GetPlayerAliases(NewPlayer);
+ var newPlayerAliases = Manager.GetAliasClients(NewPlayer);
foreach (Player aP in newPlayerAliases) // lets check their aliases
{
@@ -153,7 +119,6 @@ namespace IW4MAdmin
if (NewPlayer.Level > Player.Permission.Moderator)
await NewPlayer.Tell("There are ^5" + Reports.Count + " ^7recent reports!");
- ClientNum++;
return true;
}
@@ -168,7 +133,7 @@ namespace IW4MAdmin
//Remove player by CLIENT NUMBER
override public async Task RemovePlayer(int cNum)
{
- if (cNum >= 0 && cNum < Players.Count)
+ if (cNum >= 0)
{
Player Leaving = Players[cNum];
Leaving.Connections++;
@@ -177,8 +142,6 @@ namespace IW4MAdmin
Logger.WriteInfo($"Client {Leaving.Name}::{Leaving.NetworkID} disconnecting...");
await ExecuteEvent(new Event(Event.GType.Disconnect, "", Leaving, null, this));
Players[cNum] = null;
-
- ClientNum--;
}
}
@@ -315,7 +278,7 @@ namespace IW4MAdmin
}
}
- async Task PollPlayersAsync()
+ async Task PollPlayersAsync()
{
var CurrentPlayers = await this.GetStatusAsync();
@@ -327,6 +290,8 @@ namespace IW4MAdmin
foreach (var P in CurrentPlayers)
await AddPlayer(P);
+
+ return CurrentPlayers.Count;
}
long l_size = -1;
@@ -349,7 +314,7 @@ namespace IW4MAdmin
try
{
- await PollPlayersAsync();
+ ClientNum = await PollPlayersAsync();
if (ConnectionErrors > 0)
{
@@ -389,10 +354,10 @@ namespace IW4MAdmin
playerCountStart = DateTime.Now;
}
- if (LastMessage.TotalSeconds > MessageTime && BroadcastMessages.Count > 0 && Players.Count > 0)
+ if (LastMessage.TotalSeconds > MessageTime && BroadcastMessages.Count > 0 && ClientNum > 0)
{
- await Broadcast(Utilities.ProcessMessageToken(Manager.GetMessageTokens(), BroadcastMessages[NextMessage]));
- NextMessage = NextMessage == (BroadcastMessages.Count - 1) ? 0 : NextMessage++;
+ Console.WriteLine(Utilities.ProcessMessageToken(Manager.GetMessageTokens(), BroadcastMessages[NextMessage]));
+ NextMessage = NextMessage == (BroadcastMessages.Count - 1) ? 0 : NextMessage + 1;
start = DateTime.Now;
}
diff --git a/Admin/WebService.cs b/Admin/WebService.cs
index 11ad1d4b..ada77871 100644
--- a/Admin/WebService.cs
+++ b/Admin/WebService.cs
@@ -29,6 +29,8 @@ namespace IW4MAdmin
SharedLibrary.WebService.PageList.Add(new WebConsole());
SharedLibrary.WebService.PageList.Add(new ConsoleJSON());
SharedLibrary.WebService.PageList.Add(new PubbansJSON());
+ SharedLibrary.WebService.PageList.Add(new AdminsJSON());
+ SharedLibrary.WebService.PageList.Add(new Admins());
Thread scheduleThread = new Thread(() => { ScheduleThreadStart(webScheduler, webService); })
{
@@ -521,6 +523,69 @@ namespace IW4MAdmin
}
}
+
+ class Admins : HTMLPage
+ {
+ public override string GetName()
+ {
+ return "Admins";
+ }
+
+ public override string GetPath()
+ {
+ return "/Admins";
+ }
+
+ public override string GetContent(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers)
+ {
+ StringBuilder S = new StringBuilder();
+ S.Append(LoadHeader());
+
+ IFile admins = new IFile("webfront\\admins.html");
+ S.Append(admins.GetText());
+ admins.Close();
+
+ S.Append(LoadFooter());
+
+ return S.ToString();
+ }
+ }
+
+ class AdminsJSON : IPage
+ {
+ public string GetName()
+ {
+ return "Admins Json";
+ }
+
+ public string GetPath()
+ {
+ return "/GetAdmins";
+ }
+
+ public HttpResponse GetPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary headers)
+ {
+ var Admins = ApplicationManager.GetInstance().GetClientDatabase().GetAdmins().OrderByDescending(a => a.Level);
+ HttpResponse resp = new HttpResponse()
+ {
+ contentType = GetContentType(),
+ content = Newtonsoft.Json.JsonConvert.SerializeObject(Admins, Newtonsoft.Json.Formatting.Indented),
+ additionalHeaders = new Dictionary()
+ };
+ return resp;
+ }
+
+ public string GetContentType()
+ {
+ return "application/json";
+ }
+
+ public bool Visible()
+ {
+ return false;
+ }
+ }
+
class PubbansJSON : IPage
{
public string GetName()
@@ -604,7 +669,7 @@ namespace IW4MAdmin
return false;
}
}
-
+
class GetPlayer : IPage
{
public string GetContentType()
@@ -631,7 +696,8 @@ namespace IW4MAdmin
contentType = GetContentType(),
additionalHeaders = new Dictionary()
};
- bool authed = ApplicationManager.GetInstance().GetClientDatabase().GetAdmins().FindAll(x => x.IP == querySet["IP"]).Count > 0;
+ bool authed = ApplicationManager.GetInstance().GetClientDatabase().GetAdmins().FindAll(x => x.IP == querySet["IP"] && x.Level > Player.Permission.Trusted).Count > 0
+ || querySet["IP"] == "127.0.0.1";
bool recent = false;
if (querySet["id"] != null)
@@ -675,7 +741,7 @@ namespace IW4MAdmin
if (!recent)
{
- foreach (var a in ApplicationManager.GetInstance().Servers.First().GetAliases(pp))
+ foreach (var a in ApplicationManager.GetInstance().GetAliases(pp))
{
eachPlayer.playerAliases = a.Names;
eachPlayer.playerIPs = a.IPS;
@@ -765,4 +831,11 @@ namespace IW4MAdmin
{
public List Result;
}
+
+ [Serializable]
+ class PrivilegedUsers
+ {
+ public Player.Permission Permission { get; set; }
+ public List Players { get; set; }
+ }
}
\ No newline at end of file
diff --git a/Admin/lib/SharedLibrary.dll b/Admin/lib/SharedLibrary.dll
index 8d35f982..3421cb94 100644
Binary files a/Admin/lib/SharedLibrary.dll and b/Admin/lib/SharedLibrary.dll differ
diff --git a/Admin/version.txt b/Admin/version.txt
index 7fb91705..b3056056 100644
--- a/Admin/version.txt
+++ b/Admin/version.txt
@@ -3,8 +3,13 @@ CHANGELOG:
-works: with COD, WaW, MW3, BO1 (preliminary without extensive testing)
-fixed the issue with webfront chat history
-fixed console issue of spamming 'polling rate decreased' when server goes offline
--'unknown' admin in webfront defaults to 'IW4MAdmin'
+-'unknown' admin in webfront defaults to 'IW4MAdmin' (refactoring mistake)
-streamlined the async server initialization
+-added !ip command (prints a client's external IP)
+-fixed up the findall command
+-moved aliases to the manager
+-added admins page to view privileged users
+-fixed refactoring mistake with messages
VERSION 1.3
diff --git a/Admin/webfront/admins.html b/Admin/webfront/admins.html
new file mode 100644
index 00000000..80f8886e
--- /dev/null
+++ b/Admin/webfront/admins.html
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/README.md b/README.md
index fbef347f..679cf820 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# IW4MAdmin
### Quick Start Guide
-### Version 1.2
+### Version 1.4
_______
### Setup
@@ -46,7 +46,6 @@ ___
|owner |claim ownership of your server | False | 0 | None |
|setlevel |set player to specified administration level | True | 2 | Owner |
|rcon |send rcon command to server | False | 1 | Owner |
-|reserve |give player reserved status to join on full server | True | 1 | Owner |
|ban |permanently ban a player from the server | True | 2 | SeniorAdmin |
|unban |unban player by database id | True | 1 | SeniorAdmin |
|find |find player in the database | False | 1 | SeniorAdmin |
diff --git a/SharedLibrary/Commands/NativeCommands.cs b/SharedLibrary/Commands/NativeCommands.cs
index 35eaea8e..935eb7f2 100644
--- a/SharedLibrary/Commands/NativeCommands.cs
+++ b/SharedLibrary/Commands/NativeCommands.cs
@@ -18,7 +18,7 @@ namespace SharedLibrary.Commands
}
public class COwner : Command
- {
+ {
public COwner(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override async Task ExecuteAsync(Event E)
@@ -44,7 +44,7 @@ namespace SharedLibrary.Commands
if (E.Origin.Level <= E.Target.Level)
await E.Origin.Tell($"You do not have the required privileges to warn {E.Target.Name}");
else
- await E.Target.Warn(E.Target.lastOffense, E.Origin);
+ await E.Target.Warn(E.Target.lastOffense, E.Origin);
}
}
@@ -74,7 +74,7 @@ namespace SharedLibrary.Commands
await E.Target.Kick(E.Target.lastOffense, E.Origin);
}
else
- await E.Origin.Tell($"You do not have the required privileges to kick {E.Target.Name}");
+ await E.Origin.Tell($"You do not have the required privileges to kick {E.Target.Name}");
}
}
@@ -216,7 +216,7 @@ namespace SharedLibrary.Commands
List CommandList = E.Owner.Manager.GetCommands();
foreach (Command C in CommandList)
- {
+ {
if (E.Origin.Level >= C.Permission)
{
helpResponse.Append(" [^3" + C.Name + "^7] ");
@@ -390,7 +390,7 @@ namespace SharedLibrary.Commands
}
foreach (Player P in db_players)
- {
+ {
String mesg = String.Format("[^3{0}^7] [^3@{1}^7] - [{2}^7] - {3} | last seen {4} ago", P.Name, P.DatabaseID, Utilities.ConvertLevelToColor(P.Level), P.IP, P.GetLastConnection());
await E.Origin.Tell(mesg);
}
@@ -426,7 +426,7 @@ namespace SharedLibrary.Commands
String lookingFor = String.Empty;
- foreach(String S in P.Names)
+ foreach (String S in P.Names)
{
if (S.Contains(E.Data))
lookingFor = S;
@@ -434,7 +434,7 @@ namespace SharedLibrary.Commands
Player Current = E.Owner.Manager.GetClientDatabase().GetPlayer(P.Number);
- if (Current != null)
+ if (Current != null && Current.Name != lookingFor)
{
String mesg = String.Format("^1{0} ^7now goes by ^5{1}^7 [^3{2}^7]", lookingFor, Current.Name, Current.DatabaseID);
await E.Origin.Tell(mesg);
@@ -487,7 +487,7 @@ namespace SharedLibrary.Commands
public CReload(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
public override async Task ExecuteAsync(Event E)
- {
+ {
if (E.Owner.Reload())
await E.Origin.Tell("Sucessfully reloaded configuration files");
else
@@ -655,7 +655,7 @@ namespace SharedLibrary.Commands
StringBuilder message = new StringBuilder();
var playerAliases = E.Owner.GetAliases(E.Target);
-
+
message.Append("Aliases: ");
var names = new List();
@@ -705,5 +705,16 @@ namespace SharedLibrary.Commands
}
}
}
+
+ public class CIP : Command
+ {
+ public CIP(String N, String D, String U, Player.Permission P, int args, bool nT) : base(N, D, U, P, args, nT) { }
+
+ public override async Task ExecuteAsync(Event E)
+ {
+ await E.Origin.Tell($"Your external IP is ^5{E.Origin.IP}");
+ }
+ }
}
+
\ No newline at end of file
diff --git a/SharedLibrary/Database.cs b/SharedLibrary/Database.cs
index 7d29d065..40385f49 100644
--- a/SharedLibrary/Database.cs
+++ b/SharedLibrary/Database.cs
@@ -485,11 +485,11 @@ namespace SharedLibrary
public List GetAdmins()
{
List Admins = new List();
- String Query = String.Format("SELECT * FROM CLIENTS WHERE Level >= '{0}'", (int)Player.Permission.Moderator);
+ String Query = String.Format("SELECT * FROM CLIENTS WHERE Level >= '{0}' ORDER BY Name", (int)Player.Permission.Trusted);
DataTable Result = GetDataTable(Query);
foreach (DataRow P in Result.Rows)
- Admins.Add(new Player(P["Name"].ToString(), P["npID"].ToString(), (Player.Permission)P["Level"], P["IP"].ToString(), P["UID"].ToString()));
+ Admins.Add(new Player(P["Name"].ToString(), P["npID"].ToString(), (Player.Permission)P["Level"], P["IP"].ToString(), P["UID"].ToString(), Convert.ToInt32(P["Number"].ToString())));
return Admins;
}
@@ -634,8 +634,8 @@ namespace SharedLibrary
{
CommandText = "SELECT * FROM ALIASES WHERE NAMES LIKE @name OR IPS LIKE @ip LIMIT 15"
};
- cmd.Parameters.AddWithValue("@name", name);
- cmd.Parameters.AddWithValue("@ip", DefaultIP);
+ cmd.Parameters.AddWithValue("@name", '%' + name + '%');
+ cmd.Parameters.AddWithValue("@ip", '%' + DefaultIP + '%');
var Result = GetDataTable(cmd);
diff --git a/SharedLibrary/Interfaces/IManager.cs b/SharedLibrary/Interfaces/IManager.cs
index 27f8ea4d..99913c33 100644
--- a/SharedLibrary/Interfaces/IManager.cs
+++ b/SharedLibrary/Interfaces/IManager.cs
@@ -15,5 +15,7 @@ namespace SharedLibrary.Interfaces
AliasesDB GetAliasesDatabase();
IList GetMessageTokens();
IList GetActiveClients();
+ IList GetAliasClients(Player player);
+ IList GetAliases(Player player);
}
}
diff --git a/SharedLibrary/Player.cs b/SharedLibrary/Player.cs
index c9f51837..9a1e55fc 100644
--- a/SharedLibrary/Player.cs
+++ b/SharedLibrary/Player.cs
@@ -69,7 +69,7 @@ namespace SharedLibrary
LastConnection = DateTime.Now;
}
- public Player(String n, String id, Player.Permission P, String I, String UID)
+ public Player(String n, String id, Player.Permission P, String I, String UID, int dbid)
{
Name = n;
NetworkID = id;
@@ -77,6 +77,7 @@ namespace SharedLibrary
IP = I;
ClientID = -1;
this.UID = UID;
+ DatabaseID = dbid;
}
public Player(string n, string id, int num, Player.Permission l, int cind, String lo, int con, String IP2)
diff --git a/SharedLibrary/RCON.cs b/SharedLibrary/RCON.cs
index 9da08094..b47e1480 100644
--- a/SharedLibrary/RCON.cs
+++ b/SharedLibrary/RCON.cs
@@ -22,9 +22,6 @@ namespace SharedLibrary.Network
static string[] SendQuery(QueryType Type, Server QueryServer, string Parameters = "")
{
- if (QueryServer.Throttled)
- throw new Exceptions.DvarException("Server is RCON throttled");
-
var ServerOOBConnection = new UdpClient();
ServerOOBConnection.Client.SendTimeout = 1000;
ServerOOBConnection.Client.ReceiveTimeout = 1000;
@@ -97,9 +94,6 @@ namespace SharedLibrary.Network
public static async Task> GetDvarAsync(this Server server, string dvarName)
{
- if (server.Throttled)
- throw new Exceptions.DvarException("Server is RCON throttled");
-
string[] LineSplit = await Task.FromResult(SendQuery(QueryType.DVAR, server, dvarName));
if (LineSplit.Length != 3)
@@ -113,7 +107,7 @@ namespace SharedLibrary.Network
if (ValueSplit.Length != 5)
{
- var e = new Exceptions.DvarException("DVAR does not exist");
+ var e = new Exceptions.DvarException($"DVAR \"{dvarName}\" does not exist");
e.Data["dvar_name"] = dvarName;
throw e;
}
@@ -127,25 +121,16 @@ namespace SharedLibrary.Network
public static async Task SetDvarAsync(this Server server, string dvarName, object dvarValue)
{
- if (server.Throttled)
- throw new Exceptions.DvarException("Server is RCON throttled");
-
await Task.FromResult(SendQuery(QueryType.DVAR, server, $"set {dvarName} {dvarValue}"));
}
public static async Task ExecuteCommandAsync(this Server server, string commandName)
{
- if (server.Throttled)
- throw new Exceptions.DvarException("Server is RCON throttled");
-
return await Task.FromResult(SendQuery(QueryType.COMMAND, server, commandName).Skip(1).ToArray());
}
public static async Task> GetStatusAsync(this Server server)
{
- if (server.Throttled)
- throw new Exceptions.DvarException("Server is RCON throttled");
-
string[] response = await Task.FromResult(SendQuery(QueryType.DVAR, server, "status"));
return Utilities.PlayersFromStatus(response);
}
diff --git a/SharedLibrary/Server.cs b/SharedLibrary/Server.cs
index 6781629e..b7abea14 100644
--- a/SharedLibrary/Server.cs
+++ b/SharedLibrary/Server.cs
@@ -63,23 +63,6 @@ namespace SharedLibrary
return Players.FindAll(x => x != null);
}
-
- ///
- /// Get any know aliases ( name or ip based ) from the database
- ///
- /// Player to scan for aliases
- abstract public List GetAliases(Player Origin);
-
- public List GetPlayerAliases(Player Origin)
- {
- List databaseIDs = new List();
-
- foreach (Aliases A in GetAliases(Origin))
- databaseIDs.Add(A.Number);
-
- return Manager.GetClientDatabase().GetPlayers(databaseIDs);
- }
-
///
/// Add a player to the server's player list
///
@@ -134,6 +117,16 @@ namespace SharedLibrary
{
return null;
}
+
+ ///
+ /// Legacy method for the alias command
+ ///
+ ///
+ ///
+ public IList GetAliases(Player P)
+ {
+ return Manager.GetAliases(P);
+ }
///
/// Process any server event