diff --git a/Application/Manager.cs b/Application/Manager.cs
index 661be03a..3c91eb48 100644
--- a/Application/Manager.cs
+++ b/Application/Manager.cs
@@ -233,6 +233,7 @@ namespace IW4MAdmin.Application
Commands.Add(new CPruneAdmins());
Commands.Add(new CKillServer());
Commands.Add(new CSetPassword());
+ Commands.Add(new CPing());
foreach (Command C in SharedLibraryCore.Plugins.PluginImporter.ActiveCommands)
Commands.Add(C);
diff --git a/Application/RconParsers/T6MRConParser.cs b/Application/RconParsers/T6MRConParser.cs
index feb1b1ff..bb9564ae 100644
--- a/Application/RconParsers/T6MRConParser.cs
+++ b/Application/RconParsers/T6MRConParser.cs
@@ -82,7 +82,7 @@ namespace Application.RconParsers
{
String responseLine = statusLine;
- if (Regex.Matches(responseLine, @"^\d+", RegexOptions.IgnoreCase).Count > 0) // its a client line!
+ if (Regex.Matches(responseLine, @"^ *\d+", RegexOptions.IgnoreCase).Count > 0) // its a client line!
{
String[] playerInfo = responseLine.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
int clientId = -1;
diff --git a/Application/Server.cs b/Application/Server.cs
index fe934c5e..da4a006c 100644
--- a/Application/Server.cs
+++ b/Application/Server.cs
@@ -16,6 +16,7 @@ using SharedLibraryCore.Configuration;
using IW4MAdmin.Application.Misc;
using Application.RconParsers;
using Application.EventParsers;
+using SharedLibraryCore.Exceptions;
namespace IW4MAdmin
{
@@ -31,7 +32,7 @@ namespace IW4MAdmin
int id = Math.Abs($"{IP}:{Port.ToString()}".Select(a => (int)a).Sum());
// this is a nasty fix for get hashcode being changed
- switch(id)
+ switch (id)
{
case 765:
return 886229536;
@@ -227,7 +228,7 @@ namespace IW4MAdmin
if (C == null)
{
await E.Origin.Tell("You entered an unknown command");
- throw new SharedLibraryCore.Exceptions.CommandException($"{E.Origin} entered unknown command \"{CommandString}\"");
+ throw new CommandException($"{E.Origin} entered unknown command \"{CommandString}\"");
}
E.Data = E.Data.RemoveWords(1);
@@ -236,14 +237,14 @@ namespace IW4MAdmin
if (E.Origin.Level < C.Permission)
{
await E.Origin.Tell("You do not have access to that command");
- throw new SharedLibraryCore.Exceptions.CommandException($"{E.Origin} does not have access to \"{C.Name}\"");
+ throw new CommandException($"{E.Origin} does not have access to \"{C.Name}\"");
}
if (Args.Length < (C.RequiredArgumentCount))
{
await E.Origin.Tell($"Not enough arguments supplied");
await E.Origin.Tell(C.Syntax);
- throw new SharedLibraryCore.Exceptions.CommandException($"{E.Origin} did not supply enough arguments for \"{C.Name}\"");
+ throw new CommandException($"{E.Origin} did not supply enough arguments for \"{C.Name}\"");
}
if (C.RequiresTarget || Args.Length > 0)
@@ -291,7 +292,7 @@ namespace IW4MAdmin
if (matchingPlayers.Count > 1)
{
await E.Origin.Tell("Multiple players match that name");
- throw new SharedLibraryCore.Exceptions.CommandException($"{E.Origin} had multiple players found for {C.Name}");
+ throw new CommandException($"{E.Origin} had multiple players found for {C.Name}");
}
else if (matchingPlayers.Count == 1)
{
@@ -305,7 +306,7 @@ namespace IW4MAdmin
{
await E.Origin.Tell($"Not enough arguments supplied!");
await E.Origin.Tell(C.Syntax);
- throw new SharedLibraryCore.Exceptions.CommandException($"{E.Origin} did not supply enough arguments for \"{C.Name}\"");
+ throw new CommandException($"{E.Origin} did not supply enough arguments for \"{C.Name}\"");
}
}
}
@@ -318,7 +319,7 @@ namespace IW4MAdmin
await E.Origin.Tell("Multiple players match that name");
foreach (var p in matchingPlayers)
await E.Origin.Tell($"[^3{p.ClientNumber}^7] {p.Name}");
- throw new SharedLibraryCore.Exceptions.CommandException($"{E.Origin} had multiple players found for {C.Name}");
+ throw new CommandException($"{E.Origin} had multiple players found for {C.Name}");
}
else if (matchingPlayers.Count == 1)
{
@@ -335,7 +336,7 @@ namespace IW4MAdmin
{
await E.Origin.Tell($"Not enough arguments supplied!");
await E.Origin.Tell(C.Syntax);
- throw new SharedLibraryCore.Exceptions.CommandException($"{E.Origin} did not supply enough arguments for \"{C.Name}\"");
+ throw new CommandException($"{E.Origin} did not supply enough arguments for \"{C.Name}\"");
}
}
}
@@ -343,7 +344,7 @@ namespace IW4MAdmin
if (E.Target == null && C.RequiresTarget)
{
await E.Origin.Tell("Unable to find specified player.");
- throw new SharedLibraryCore.Exceptions.CommandException($"{E.Origin} specified invalid player for \"{C.Name}\"");
+ throw new CommandException($"{E.Origin} specified invalid player for \"{C.Name}\"");
}
}
E.Data = E.Data.Trim();
@@ -397,7 +398,7 @@ namespace IW4MAdmin
}
// when the server has lost connection
- catch (SharedLibraryCore.Exceptions.NetworkException)
+ catch (NetworkException)
{
Throttled = true;
return ClientNum;
@@ -459,7 +460,7 @@ namespace IW4MAdmin
LastPoll = DateTime.Now;
}
- catch (SharedLibraryCore.Exceptions.NetworkException e)
+ catch (NetworkException e)
{
ConnectionErrors++;
if (ConnectionErrors == 1)
@@ -553,7 +554,7 @@ namespace IW4MAdmin
return true;
}
//#if !DEBUG
- catch (SharedLibraryCore.Exceptions.NetworkException)
+ catch (NetworkException)
{
Logger.WriteError($"Could not communicate with {IP}:{Port}");
return false;
@@ -649,7 +650,7 @@ namespace IW4MAdmin
// patch for T6M:PLUTONIUM
mainPath = (GameName == Game.T6M) ? $"t6r{Path.DirectorySeparatorChar}data" : mainPath;
#if DEBUG
- basepath.Value = @"\\192.168.88.253\Call of Duty Black Ops II";
+ // basepath.Value = @"\\192.168.88.253\Call of Duty Black Ops II";
#endif
string logPath = (game.Value == "" || onelog?.Value == 1) ?
$"{basepath.Value.Replace('\\', Path.DirectorySeparatorChar)}{Path.DirectorySeparatorChar}{mainPath}{Path.DirectorySeparatorChar}{logfile.Value}" :
@@ -717,7 +718,7 @@ namespace IW4MAdmin
C = await ValidateCommand(E);
}
- catch (SharedLibraryCore.Exceptions.CommandException e)
+ catch (CommandException e)
{
Logger.WriteInfo(e.Message);
}
@@ -731,9 +732,28 @@ namespace IW4MAdmin
try
{
+ if (!E.Remote && E.Origin.Level != Player.Permission.Console)
+ {
+ await ExecuteEvent(new GameEvent()
+ {
+ Type = GameEvent.EventType.Command,
+ Data = string.Empty,
+ Origin = E.Origin,
+ Target = E.Target,
+ Owner = this,
+ Extra = C,
+ Remote = E.Remote
+ });
+ }
+
await C.ExecuteAsync(E);
}
+ catch (AuthorizationException e)
+ {
+ await E.Origin.Tell($"You are not authorized to execute that command - {e.Message}");
+ }
+
catch (Exception Except)
{
Logger.WriteError(String.Format("A command request \"{0}\" generated an error.", C.Name));
diff --git a/IW4MAdmin.sln b/IW4MAdmin.sln
index dbeba8e5..2e76d4cf 100644
--- a/IW4MAdmin.sln
+++ b/IW4MAdmin.sln
@@ -24,7 +24,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stats", "Plugins\Stats\Stat
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Welcome", "Plugins\Welcome\Welcome.csproj", "{179140D3-97AA-4CB4-8BF6-A0C73CA75701}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProfanityDeterment", "Plugins\ProfanityDeterment\ProfanityDeterment.csproj", "{958FF7EC-0226-4E85-A85B-B84EC768197D}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProfanityDeterment", "Plugins\ProfanityDeterment\ProfanityDeterment.csproj", "{958FF7EC-0226-4E85-A85B-B84EC768197D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Login", "Plugins\Login\Login.csproj", "{D9F2ED28-6FA5-40CA-9912-E7A849147AB1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -150,6 +152,22 @@ Global
{958FF7EC-0226-4E85-A85B-B84EC768197D}.Release|x64.Build.0 = Release|Any CPU
{958FF7EC-0226-4E85-A85B-B84EC768197D}.Release|x86.ActiveCfg = Release|Any CPU
{958FF7EC-0226-4E85-A85B-B84EC768197D}.Release|x86.Build.0 = Release|Any CPU
+ {D9F2ED28-6FA5-40CA-9912-E7A849147AB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D9F2ED28-6FA5-40CA-9912-E7A849147AB1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D9F2ED28-6FA5-40CA-9912-E7A849147AB1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {D9F2ED28-6FA5-40CA-9912-E7A849147AB1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {D9F2ED28-6FA5-40CA-9912-E7A849147AB1}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {D9F2ED28-6FA5-40CA-9912-E7A849147AB1}.Debug|x64.Build.0 = Debug|Any CPU
+ {D9F2ED28-6FA5-40CA-9912-E7A849147AB1}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D9F2ED28-6FA5-40CA-9912-E7A849147AB1}.Debug|x86.Build.0 = Debug|Any CPU
+ {D9F2ED28-6FA5-40CA-9912-E7A849147AB1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D9F2ED28-6FA5-40CA-9912-E7A849147AB1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D9F2ED28-6FA5-40CA-9912-E7A849147AB1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {D9F2ED28-6FA5-40CA-9912-E7A849147AB1}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {D9F2ED28-6FA5-40CA-9912-E7A849147AB1}.Release|x64.ActiveCfg = Release|Any CPU
+ {D9F2ED28-6FA5-40CA-9912-E7A849147AB1}.Release|x64.Build.0 = Release|Any CPU
+ {D9F2ED28-6FA5-40CA-9912-E7A849147AB1}.Release|x86.ActiveCfg = Release|Any CPU
+ {D9F2ED28-6FA5-40CA-9912-E7A849147AB1}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -159,6 +177,7 @@ Global
{98BE4A81-8AFD-4957-83F7-009D353C6BCB} = {26E8B310-269E-46D4-A612-24601F16065F}
{179140D3-97AA-4CB4-8BF6-A0C73CA75701} = {26E8B310-269E-46D4-A612-24601F16065F}
{958FF7EC-0226-4E85-A85B-B84EC768197D} = {26E8B310-269E-46D4-A612-24601F16065F}
+ {D9F2ED28-6FA5-40CA-9912-E7A849147AB1} = {26E8B310-269E-46D4-A612-24601F16065F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {84F8F8E0-1F73-41E0-BD8D-BB6676E2EE87}
diff --git a/Plugins/Login/Commands/CLogin.cs b/Plugins/Login/Commands/CLogin.cs
new file mode 100644
index 00000000..332bbbfc
--- /dev/null
+++ b/Plugins/Login/Commands/CLogin.cs
@@ -0,0 +1,37 @@
+using SharedLibraryCore;
+using SharedLibraryCore.Objects;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace IW4MAdmin.Plugins.Login.Commands
+{
+ public class CLogin : Command
+ {
+ public CLogin() : base("login", "login using password", "l", Player.Permission.Trusted, false, new CommandArgument[]
+ {
+ new CommandArgument()
+ {
+ Name = "password",
+ Required = true
+ }
+ }){ }
+
+ public override async Task ExecuteAsync(GameEvent E)
+ {
+ var client = E.Owner.Manager.GetPrivilegedClients()[E.Origin.ClientId];
+ string[] hashedPassword = await Task.FromResult(SharedLibraryCore.Helpers.Hashing.Hash(E.Data, client.PasswordSalt));
+
+ if (hashedPassword[0] == client.Password)
+ {
+ Plugin.AuthorizedClients[E.Origin.ClientId] = true;
+ await E.Origin.Tell("You are now logged in");
+ }
+
+ else
+ {
+ await E.Origin.Tell("Your password is incorrect");
+ }
+ }
+ }
+}
diff --git a/Plugins/Login/Configuration.cs b/Plugins/Login/Configuration.cs
new file mode 100644
index 00000000..d7f3b99b
--- /dev/null
+++ b/Plugins/Login/Configuration.cs
@@ -0,0 +1,18 @@
+using SharedLibraryCore;
+using SharedLibraryCore.Interfaces;
+
+namespace IW4MAdmin.Plugins.Login
+{
+ class Configuration : IBaseConfiguration
+ {
+ public bool RequirePrivilegedClientLogin { get; set; }
+
+ public IBaseConfiguration Generate()
+ {
+ RequirePrivilegedClientLogin = Utilities.PromptBool("Require privileged client login");
+ return this;
+ }
+
+ public string Name() => "LoginConfiguration";
+ }
+}
diff --git a/Plugins/Login/Login.csproj b/Plugins/Login/Login.csproj
new file mode 100644
index 00000000..d42397a7
--- /dev/null
+++ b/Plugins/Login/Login.csproj
@@ -0,0 +1,22 @@
+
+
+
+ Library
+ netcoreapp2.0
+
+
+ RaidMax.IW4MAdmin.Plugins.Login
+ RaidMax
+ Forever None
+ Login Plugin for IW4MAdmin
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Plugins/Login/Plugin.cs b/Plugins/Login/Plugin.cs
new file mode 100644
index 00000000..c012b9a7
--- /dev/null
+++ b/Plugins/Login/Plugin.cs
@@ -0,0 +1,75 @@
+using System.Collections.Concurrent;
+using System.Reflection;
+using System.Threading.Tasks;
+using SharedLibraryCore;
+using SharedLibraryCore.Configuration;
+using SharedLibraryCore.Exceptions;
+using SharedLibraryCore.Interfaces;
+
+namespace IW4MAdmin.Plugins.Login
+{
+ public class Plugin : IPlugin
+ {
+ public string Name => "Login";
+
+ public float Version => Assembly.GetExecutingAssembly().GetName().Version.Major + Assembly.GetExecutingAssembly().GetName().Version.Minor / 10.0f;
+
+ public string Author => "RaidMax";
+
+ public static ConcurrentDictionary AuthorizedClients { get; private set; }
+ private Configuration Config;
+
+ public Task OnEventAsync(GameEvent E, Server S)
+ {
+ if (E.Remote || Config.RequirePrivilegedClientLogin == false)
+ return Task.CompletedTask;
+
+ if (E.Type == GameEvent.EventType.Connect)
+ {
+ AuthorizedClients.TryAdd(E.Origin.ClientId, false);
+ }
+
+ if (E.Type == GameEvent.EventType.Disconnect)
+ {
+ AuthorizedClients.TryRemove(E.Origin.ClientId, out bool value);
+ }
+
+ if (E.Type == GameEvent.EventType.Command)
+ {
+ if (((Command)E.Extra).Name == new SharedLibraryCore.Commands.CSetPassword().Name &&
+ E.Owner.Manager.GetPrivilegedClients()[E.Origin.ClientId].Password == null)
+ return Task.CompletedTask;
+
+ if (((Command)E.Extra).Name == new Commands.CLogin().Name)
+ return Task.CompletedTask;
+
+ if (!AuthorizedClients[E.Origin.ClientId])
+ throw new AuthorizationException("not logged in");
+ }
+
+ return Task.CompletedTask;
+ }
+
+ public async Task OnLoadAsync(IManager manager)
+ {
+ AuthorizedClients = new ConcurrentDictionary();
+
+ var cfg = new BaseConfigurationHandler("LoginPluginSettings");
+ if (cfg.Configuration() == null)
+ {
+ cfg.Set((Configuration)new Configuration().Generate());
+ await cfg.Save();
+ }
+
+ Config = cfg.Configuration();
+ }
+
+ public Task OnTickAsync(Server S) => Utilities.CompletedTask;
+
+ public Task OnUnloadAsync()
+ {
+ AuthorizedClients.Clear();
+ return Utilities.CompletedTask;
+ }
+ }
+}
diff --git a/SharedLibraryCore/Commands/NativeCommands.cs b/SharedLibraryCore/Commands/NativeCommands.cs
index 90ca1c48..093a9a49 100644
--- a/SharedLibraryCore/Commands/NativeCommands.cs
+++ b/SharedLibraryCore/Commands/NativeCommands.cs
@@ -937,7 +937,7 @@ namespace SharedLibraryCore.Commands
public class CPruneAdmins : Command
{
- public CPruneAdmins() : base("prune", "demote any admins that have not connected recently (defaults to 30 days)", "p", Player.Permission.Owner, false, new CommandArgument[]
+ public CPruneAdmins() : base("prune", "demote any admins that have not connected recently (defaults to 30 days)", "pa", Player.Permission.Owner, false, new CommandArgument[]
{
new CommandArgument()
{
@@ -1070,4 +1070,35 @@ namespace SharedLibraryCore.Commands
}
}
}
+
+
+ public class CPing : Command
+ {
+ public CPing() : base("ping", "get client's ping", "pi", Player.Permission.User, false, new CommandArgument[]
+ {
+ new CommandArgument()
+ {
+ Name = "client",
+ Required = false
+ }
+ }){}
+
+ public override async Task ExecuteAsync(GameEvent E)
+ {
+ if (E.Message.IsBroadcastCommand())
+ {
+ if (E.Target == null)
+ await E.Owner.Broadcast($"{E.Origin.Name}'s ping is ^5{E.Origin.Ping}^7ms");
+ else
+ await E.Owner.Broadcast($"{E.Target.Name}'s ping is ^5{E.Origin.Ping}^7ms");
+ }
+ else
+ {
+ if (E.Target == null)
+ await E.Origin.Tell($"Your ping is ^5{E.Origin.Ping}^7ms");
+ else
+ await E.Origin.Tell($"{E.Target.Name}'s ping is ^5{E.Origin.Ping}^7ms");
+ }
+ }
+ }
}
diff --git a/SharedLibraryCore/Event.cs b/SharedLibraryCore/Event.cs
index 326e9c3b..fe8fb262 100644
--- a/SharedLibraryCore/Event.cs
+++ b/SharedLibraryCore/Event.cs
@@ -31,6 +31,7 @@ namespace SharedLibraryCore
//FROM PLAYER
Report,
Flag,
+ Command,
// FROM GAME
Script,
@@ -57,5 +58,6 @@ namespace SharedLibraryCore
public Player Target;
public Server Owner;
public Boolean Remote = false;
+ public object Extra { get; set; }
}
}
diff --git a/SharedLibraryCore/Exceptions/AuthorizationException.cs b/SharedLibraryCore/Exceptions/AuthorizationException.cs
new file mode 100644
index 00000000..695a156f
--- /dev/null
+++ b/SharedLibraryCore/Exceptions/AuthorizationException.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace SharedLibraryCore.Exceptions
+{
+ public class AuthorizationException : Exception
+ {
+ public AuthorizationException(string message) : base (message) { }
+ }
+}
diff --git a/SharedLibraryCore/Services/PenaltyService.cs b/SharedLibraryCore/Services/PenaltyService.cs
index 2f52bfda..bc34f0e6 100644
--- a/SharedLibraryCore/Services/PenaltyService.cs
+++ b/SharedLibraryCore/Services/PenaltyService.cs
@@ -133,10 +133,6 @@ namespace SharedLibraryCore.Services
{
using (var context = new DatabaseContext())
{
- /*context.Configuration.LazyLoadingEnabled = false;
- context.Configuration.ProxyCreationEnabled = false;
- context.Configuration.AutoDetectChangesEnabled = false;*/
-
if (victim)
{
var now = DateTime.UtcNow;
@@ -162,7 +158,7 @@ namespace SharedLibraryCore.Services
PunisherId = penalty.PunisherId,
Offense = penalty.Offense,
Type = penalty.Type.ToString(),
- TimeRemaining = now > penalty.Expires ? "" : penalty.Expires.ToString()
+ TimeRemaining = now > penalty.Expires ? "" : penalty.Expires.ToString()
},
When = penalty.When,
Sensitive = penalty.Type == Objects.Penalty.PenaltyType.Flag
diff --git a/WebfrontCore/Controllers/ConsoleController.cs b/WebfrontCore/Controllers/ConsoleController.cs
index 0723cbda..c2143466 100644
--- a/WebfrontCore/Controllers/ConsoleController.cs
+++ b/WebfrontCore/Controllers/ConsoleController.cs
@@ -42,7 +42,8 @@ namespace WebfrontCore.Controllers
Type = GameEvent.EventType.Say,
Data = command,
Origin = client,
- Owner = server
+ Owner = server,
+ Remote = true
};
await server.ExecuteEvent(remoteEvent);