vpn check updates, fixed some issues,

"masked" status is now sensitive
discord link in webfront if configured
This commit is contained in:
RaidMax 2018-03-13 16:30:22 -05:00
parent 5c0aa7d14f
commit e974de8e63
27 changed files with 235 additions and 119 deletions

View File

@ -226,7 +226,7 @@ namespace StatsPlugin.Helpers
}; };
if (kill.DeathType == IW4Info.MeansOfDeath.MOD_SUICIDE && if (kill.DeathType == IW4Info.MeansOfDeath.MOD_SUICIDE &&
kill.Damage == 10000) kill.Damage == 100000)
{ {
// suicide by switching teams so let's not count it against them // suicide by switching teams so let's not count it against them
return; return;
@ -247,31 +247,33 @@ namespace StatsPlugin.Helpers
//statsSvc.KillStatsSvc.Insert(kill); //statsSvc.KillStatsSvc.Insert(kill);
//await statsSvc.KillStatsSvc.SaveChangesAsync(); //await statsSvc.KillStatsSvc.SaveChangesAsync();
if (attacker.CurrentServer.Config.EnableAntiCheat)
async Task executePenalty(Cheat.DetectionPenaltyResult penalty)
{ {
switch (penalty.ClientPenalty) async Task executePenalty(Cheat.DetectionPenaltyResult penalty)
{ {
case Penalty.PenaltyType.Ban: switch (penalty.ClientPenalty)
await attacker.Ban("You appear to be cheating", new Player() { ClientId = 1 }); {
break; case Penalty.PenaltyType.Ban:
case Penalty.PenaltyType.Flag: await attacker.Ban("You appear to be cheating", new Player() { ClientId = 1 });
if (attacker.Level != Player.Permission.User)
break; break;
var flagCmd = new CFlag(); case Penalty.PenaltyType.Flag:
await flagCmd.ExecuteAsync(new Event(Event.GType.Flag, $"{(int)penalty.Bone}-{Math.Round(penalty.RatioAmount, 2).ToString()}@{penalty.KillCount}", new Player() if (attacker.Level != Player.Permission.User)
{ break;
ClientId = 1, var flagCmd = new CFlag();
Level = Player.Permission.Console, await flagCmd.ExecuteAsync(new Event(Event.GType.Flag, $"{(int)penalty.Bone}-{Math.Round(penalty.RatioAmount, 2).ToString()}@{penalty.KillCount}", new Player()
ClientNumber = -1, {
CurrentServer = attacker.CurrentServer ClientId = 1,
}, attacker, attacker.CurrentServer)); Level = Player.Permission.Console,
break; ClientNumber = -1,
CurrentServer = attacker.CurrentServer
}, attacker, attacker.CurrentServer));
break;
}
} }
}
await executePenalty(playerDetection.ProcessKill(kill)); await executePenalty(playerDetection.ProcessKill(kill));
await executePenalty(playerDetection.ProcessTotalRatio(playerStats)); await executePenalty(playerDetection.ProcessTotalRatio(playerStats));
}
} }
public async Task AddStandardKill(Player attacker, Player victim) public async Task AddStandardKill(Player attacker, Player victim)

View File

@ -8,6 +8,9 @@ namespace SharedLibrary.Database
{ {
public static void Run(ILogger log) public static void Run(ILogger log)
{ {
if (!System.IO.File.Exists($"{Utilities.OperatingDirectory}Database.sdf"))
return;
SqlCeEngine engine = new SqlCeEngine(@"Data Source=|DataDirectory|\Database.sdf"); SqlCeEngine engine = new SqlCeEngine(@"Data Source=|DataDirectory|\Database.sdf");
if (false == engine.Verify()) if (false == engine.Verify())
{ {

View File

@ -42,7 +42,7 @@ namespace SharedLibrary
public Event(GType t, string d, Player O, Player T, Server S) public Event(GType t, string d, Player O, Player T, Server S)
{ {
Type = t; Type = t;
Data = d.Trim(); Data = d?.Trim();
Origin = O; Origin = O;
Target = T; Target = T;
Owner = S; Owner = S;

View File

@ -40,5 +40,12 @@ namespace SharedLibrary.Helpers
{ {
return Math.Round(Math.Sqrt(Math.Pow(b.X - a.X, 2) + Math.Pow(b.Y - a.Y, 2) + Math.Pow(b.Z - a.Z, 2)), 2); return Math.Round(Math.Sqrt(Math.Pow(b.X - a.X, 2) + Math.Pow(b.Y - a.Y, 2) + Math.Pow(b.Z - a.Z, 2)), 2);
} }
public double DotProduct(Vector3 a) => (a.X * this.X) + (a.Y * this.Y) + (a.Z * this.Z);
public double Magnitude() => Math.Sqrt((X * X) + (Y * Y) + (Z * Z));
public double AngleBetween(Vector3 a) => Math.Acos(this.DotProduct(a) / (a.Magnitude() * this.Magnitude()));
} }
} }

View File

@ -12,6 +12,8 @@ namespace SharedLibrary
public bool AllowTrustedRank; public bool AllowTrustedRank;
public string RestartUsername; public string RestartUsername;
public string RestartPassword; public string RestartPassword;
public bool EnableAntiCheat;
public bool AllowClientVpn;
public override string Filename() public override string Filename()
{ {

View File

@ -1,2 +0,0 @@
127.0.0.1
80

View File

@ -12,8 +12,6 @@ namespace IW4MAdmin
{ {
public class Program public class Program
{ {
[DllImport("kernel32.dll")]
public static extern bool AllocConsole();
static public double Version { get; private set; } static public double Version { get; private set; }
static public ApplicationManager ServerManager = ApplicationManager.GetInstance(); static public ApplicationManager ServerManager = ApplicationManager.GetInstance();
public static string OperatingDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + Path.DirectorySeparatorChar; public static string OperatingDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + Path.DirectorySeparatorChar;
@ -33,15 +31,20 @@ namespace IW4MAdmin
try try
{ {
/*var v1 = SharedLibrary.Helpers.Vector3.Parse("(737, 1117, 268)");
var v2 = SharedLibrary.Helpers.Vector3.Parse("(1510, 672.98, -228.66)");
double angleBetween = v1.AngleBetween(v2);*/
CheckDirectories(); CheckDirectories();
Task.Run(async () =>
{
ServerManager = ApplicationManager.GetInstance(); ServerManager = ApplicationManager.GetInstance();
SharedLibrary.Database.Repair.Run(ServerManager.Logger); SharedLibrary.Database.Repair.Run(ServerManager.Logger);
await ServerManager.Init(); ServerManager.Init().Wait();
ServerManager.Start(); Task.Run(() => ServerManager.Start());
});
Task.Run(() => Task.Run(() =>
{ {
@ -95,9 +98,6 @@ namespace IW4MAdmin
if (!Directory.Exists($"{curDirectory}Logs")) if (!Directory.Exists($"{curDirectory}Logs"))
Directory.CreateDirectory($"{curDirectory}Logs"); Directory.CreateDirectory($"{curDirectory}Logs");
if (!Directory.Exists($"{curDirectory}Database"))
Directory.CreateDirectory($"{curDirectory}Database");
if (!Directory.Exists($"{curDirectory}Plugins")) if (!Directory.Exists($"{curDirectory}Plugins"))
Directory.CreateDirectory($"{curDirectory}Plugins"); Directory.CreateDirectory($"{curDirectory}Plugins");
} }

View File

@ -104,40 +104,38 @@ namespace IW4MAdmin
{ {
var Conf = ServerConfiguration.Read(file); var Conf = ServerConfiguration.Read(file);
Task.Run(async () => try
{ {
try var ServerInstance = new IW4MServer(this, Conf);
await ServerInstance.Initialize();
lock (_servers)
{ {
var ServerInstance = new IW4MServer(this, Conf); _servers.Add(ServerInstance);
await ServerInstance.Initialize();
lock (_servers)
{
_servers.Add(ServerInstance);
}
Logger.WriteVerbose($"Now monitoring {ServerInstance.Hostname}");
// this way we can keep track of execution time and see if problems arise.
var Status = new AsyncStatus(ServerInstance, UPDATE_FREQUENCY);
lock (TaskStatuses)
{
TaskStatuses.Add(Status);
}
} }
catch (ServerException e) Logger.WriteVerbose($"Now monitoring {ServerInstance.Hostname}");
// this way we can keep track of execution time and see if problems arise.
var Status = new AsyncStatus(ServerInstance, UPDATE_FREQUENCY);
lock (TaskStatuses)
{ {
Logger.WriteError($"Not monitoring server {Conf.IP}:{Conf.Port} due to uncorrectable errors"); TaskStatuses.Add(Status);
if (e.GetType() == typeof(DvarException))
Logger.WriteDebug($"Could not get the dvar value for {(e as DvarException).Data["dvar_name"]} (ensure the server has a map loaded)");
else if (e.GetType() == typeof(NetworkException))
{
Logger.WriteDebug(e.Message);
Logger.WriteDebug($"Internal Exception: {e.Data["internal_exception"]}");
}
} }
}); }
catch (ServerException e)
{
Logger.WriteError($"Not monitoring server {Conf.IP}:{Conf.Port} due to uncorrectable errors");
if (e.GetType() == typeof(DvarException))
Logger.WriteDebug($"Could not get the dvar value for {(e as DvarException).Data["dvar_name"]} (ensure the server has a map loaded)");
else if (e.GetType() == typeof(NetworkException))
{
Logger.WriteDebug(e.Message);
Logger.WriteDebug($"Internal Exception: {e.Data["internal_exception"]}");
}
}
} }
#endregion #endregion

View File

@ -1,4 +1,6 @@
using System; using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -9,13 +11,18 @@ namespace WebfrontCore.Application.Misc
{ {
public static async Task<bool> UsingVPN(string ip) public static async Task<bool> UsingVPN(string ip)
{ {
#if DEBUG
return false;
#endif
try try
{ {
using (var RequestClient = new System.Net.Http.HttpClient()) using (var RequestClient = new System.Net.Http.HttpClient())
{ {
string response = await RequestClient.GetStringAsync($"http://check.getipintel.net/check.php?ip={ip}&contact=raidmax@live.com"); RequestClient.DefaultRequestHeaders.Add("X-Key", Startup.Configuration["VPN:APIKey"]);
double probability = Convert.ToDouble(response); string response = await RequestClient.GetStringAsync($"http://v2.api.iphub.info/ip/{ip}");
return probability > 0.9; var responseJson = JsonConvert.DeserializeObject<JObject>(response);
int blockType = Convert.ToInt32(responseJson["block"]);
return blockType == 1;
} }
} }

View File

@ -92,7 +92,7 @@ namespace IW4MAdmin
if (existingAlias == null) if (existingAlias == null)
{ {
Logger.WriteDebug($"Client {polledPlayer} has connected previously under a different ip/name"); Logger.WriteDebug($"Client {polledPlayer} has connected previously under a different ip/name");
client.CurrentAlias = new SharedLibrary.Database.Models.EFAlias() client.CurrentAlias = new EFAlias()
{ {
IPAddress = polledPlayer.IPAddress, IPAddress = polledPlayer.IPAddress,
Name = polledPlayer.Name, Name = polledPlayer.Name,
@ -143,7 +143,7 @@ namespace IW4MAdmin
await ExecuteEvent(new Event(Event.GType.Connect, "", player, null, this)); await ExecuteEvent(new Event(Event.GType.Connect, "", player, null, this));
if (await VPNCheck.UsingVPN(player.IPAddressString)) if (Config.AllowClientVpn && await VPNCheck.UsingVPN(player.IPAddressString))
{ {
await player.Kick("VPNs are not allowed on this server", new Player() { ClientId = 1 }); await player.Kick("VPNs are not allowed on this server", new Player() { ClientId = 1 });
} }
@ -288,10 +288,9 @@ namespace IW4MAdmin
{ {
E.Target = matchingPlayers.First(); E.Target = matchingPlayers.First();
E.Data = Regex.Replace(E.Data, Regex.Escape($"\"{E.Target.Name}\""), "", RegexOptions.IgnoreCase).Trim(); E.Data = Regex.Replace(E.Data, Regex.Escape($"\"{E.Target.Name}\""), "", RegexOptions.IgnoreCase).Trim();
E.Data = Regex.Replace(E.Data, Regex.Escape($"{E.Target.Name}"), "", RegexOptions.IgnoreCase).Trim();
if ((E.Data.ToLower().Trim() == E.Target.Name.ToLower().Trim() || if (E.Data.Length == 0 && C.RequiredArgumentCount > 1)
E.Data == String.Empty) &&
C.RequiresTarget)
{ {
await E.Origin.Tell($"Not enough arguments supplied!"); await E.Origin.Tell($"Not enough arguments supplied!");
await E.Origin.Tell(C.Syntax); await E.Origin.Tell(C.Syntax);
@ -375,7 +374,7 @@ namespace IW4MAdmin
#if DEBUG #if DEBUG
Logger.WriteInfo($"Polling players took {(DateTime.Now - now).TotalMilliseconds}ms"); Logger.WriteInfo($"Polling players took {(DateTime.Now - now).TotalMilliseconds}ms");
#endif #endif
Throttled = false;
for (int i = 0; i < Players.Count; i++) for (int i = 0; i < Players.Count; i++)
{ {
if (CurrentPlayers.Find(p => p.ClientNumber == i) == null && Players[i] != null) if (CurrentPlayers.Find(p => p.ClientNumber == i) == null && Players[i] != null)
@ -561,7 +560,20 @@ namespace IW4MAdmin
DVAR<int> onelog = null; DVAR<int> onelog = null;
if (GameName == Game.IW4) if (GameName == Game.IW4)
onelog = await this.GetDvarAsync<int>("iw4x_onelog"); {
try
{
onelog = await this.GetDvarAsync<int>("iw4x_onelog");
}
catch (Exception)
{
onelog = new DVAR<int>("iw4x_onelog")
{
Value = -1
};
}
}
try try
{ {
@ -580,8 +592,10 @@ namespace IW4MAdmin
this.FSGame = game.Value; this.FSGame = game.Value;
await this.SetDvarAsync("sv_kickbantime", 60); await this.SetDvarAsync("sv_kickbantime", 60);
await this.SetDvarAsync("sv_network_fps", 1000);
await this.SetDvarAsync("com_maxfps", 1000); // I don't think this belongs in an admin tool
/*await this.SetDvarAsync("sv_network_fps", 1000);
await this.SetDvarAsync("com_maxfps", 1000);*/
if (logsync.Value == 0 || logfile.Value == string.Empty) if (logsync.Value == 0 || logfile.Value == string.Empty)
{ {
@ -603,7 +617,7 @@ namespace IW4MAdmin
} }
#endif #endif
string mainPath = (GameName == Game.IW4) ? "userraw" : "main"; string mainPath = (GameName == Game.IW4 && onelog.Value >=0) ? "userraw" : "main";
string logPath = (game.Value == "" || onelog?.Value == 1) ? string logPath = (game.Value == "" || onelog?.Value == 1) ?
$"{ basepath.Value.Replace("\\", "/")}/{mainPath}/{logfile.Value}" : $"{ basepath.Value.Replace("\\", "/")}/{mainPath}/{logfile.Value}" :
@ -626,8 +640,8 @@ namespace IW4MAdmin
//#endif //#endif
Logger.WriteInfo($"Log file is {logPath}"); Logger.WriteInfo($"Log file is {logPath}");
#if !DEBUG #if !DEBUG
await Broadcast("IW4M Admin is now ^2ONLINE"); await Broadcast("IW4M Admin is now ^2ONLINE");
#endif #endif
} }

View File

@ -17,6 +17,8 @@ namespace IW4MAdmin
string Password; string Password;
bool AllowMultipleOwners; bool AllowMultipleOwners;
bool AllowTrustedRank; bool AllowTrustedRank;
bool AntiCheat;
bool AllowVpns;
while (IP == String.Empty) while (IP == String.Empty)
{ {
@ -57,13 +59,23 @@ namespace IW4MAdmin
Console.Write("Allow trusted rank? [y/n]: "); Console.Write("Allow trusted rank? [y/n]: ");
AllowTrustedRank = (Console.ReadLine().ToLower().FirstOrDefault() as char?) == 'y'; AllowTrustedRank = (Console.ReadLine().ToLower().FirstOrDefault() as char?) == 'y';
Console.Write("Allow server-side anti-cheat [y/n]: ");
AntiCheat = (Console.ReadLine().ToLower().FirstOrDefault() as char?) == 'y';
Console.Write("Allow client VPNS [y/n]: ");
AllowVpns = (Console.ReadLine().ToLower().FirstOrDefault() as char?) == 'y';
var config = new ServerConfiguration() var config = new ServerConfiguration()
{ {
IP = IP, IP = IP,
Password = Password, Password = Password,
Port = Port, Port = Port,
AllowMultipleOwners = AllowMultipleOwners, AllowMultipleOwners = AllowMultipleOwners,
AllowTrustedRank = AllowTrustedRank AllowTrustedRank = AllowTrustedRank,
RestartPassword = "",
RestartUsername = "",
EnableAntiCheat = AntiCheat,
AllowClientVpn = AllowVpns
}; };
config.Write(); config.Write();

View File

@ -21,6 +21,8 @@ namespace WebfrontCore.Controllers
Authorized = context.HttpContext.Connection.RemoteIpAddress.ToString() == "127.0.0.1" || Authorized = context.HttpContext.Connection.RemoteIpAddress.ToString() == "127.0.0.1" ||
Manager.AdministratorIPs.Contains(context.HttpContext.Connection.RemoteIpAddress.ToString().ConvertToIP()); Manager.AdministratorIPs.Contains(context.HttpContext.Connection.RemoteIpAddress.ToString().ConvertToIP());
ViewBag.Authorized = Authorized; ViewBag.Authorized = Authorized;
ViewBag.Url = Startup.Configuration["Web:Address"];
ViewBag.DiscordLink = Startup.Configuration["Discord:InviteLink"];
base.OnActionExecuting(context); base.OnActionExecuting(context);
} }
} }

View File

@ -50,7 +50,7 @@ namespace WebfrontCore.Controllers
{ {
Key = "Masked", Key = "Masked",
Value = client.Masked ? "Is" : "Is not", Value = client.Masked ? "Is" : "Is not",
Sensitive = false, Sensitive = true,
When = DateTime.MinValue When = DateTime.MinValue
}); });
@ -61,7 +61,12 @@ namespace WebfrontCore.Controllers
.OrderByDescending(m => m.When) .OrderByDescending(m => m.When)
.ToList(); .ToList();
ViewBag.Title = clientDto.Name; ViewBag.Title = clientDto.Name.Substring(clientDto.Name.Length - 1).ToLower()[0] == 's' ?
clientDto.Name + "'" :
clientDto.Name + "'s";
ViewBag.Title += " Profile";
ViewBag.Description = $"Client information for {clientDto.Name}";
ViewBag.Keywords = $"IW4MAdmin, client, profile, {clientDto.Name}";
return View("Profile/Index", clientDto); return View("Profile/Index", clientDto);
} }
@ -84,7 +89,10 @@ namespace WebfrontCore.Controllers
}); });
} }
ViewBag.Title = "Current Privileged Users"; ViewBag.Title = "Privileged Clients";
ViewBag.Description = "List of all privileged clients on IW4MAdmin";
ViewBag.Keywords = "IW4MAdmin, privileged, admins, clients, administrators";
return View("Privileged/Index", adminsDict); return View("Privileged/Index", adminsDict);
} }
@ -102,7 +110,7 @@ namespace WebfrontCore.Controllers
}) })
.ToList(); .ToList();
ViewBag.Name = $"Clients Matching \"{clientName}\""; ViewBag.Title = $"Clients Matching \"{clientName}\"";
return View("Find/Index", clientsDto); return View("Find/Index", clientsDto);
} }
} }

View File

@ -19,7 +19,10 @@ namespace WebfrontCore.Controllers
ID = s.GetHashCode(), ID = s.GetHashCode(),
}); });
ViewBag.Description = "Use the IW4MAdmin web console to execute commands";
ViewBag.Title = "Web Console"; ViewBag.Title = "Web Console";
ViewBag.Keywords = "IW4MAdmin, console, execute, commands";
return View(activeServers); return View(activeServers);
} }

View File

@ -12,14 +12,18 @@ namespace WebfrontCore.Controllers
{ {
public IActionResult Index() public IActionResult Index()
{ {
ViewBag.Description = "IW4MAdmin is a complete server administration tool for IW4x.";
ViewBag.Title = "Server Overview"; ViewBag.Title = "Server Overview";
ViewBag.Keywords = "IW4MAdmin, server, administration, IW4x, MW2, Modern Warfare 2";
return View(); return View();
} }
public IActionResult Error() public IActionResult Error()
{ {
// return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); ViewBag.Description = "IW4MAdmin encountered and error";
return null; ViewBag.Title = "Error!";
return View();
} }
} }
} }

View File

@ -1,6 +1,8 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using SharedLibrary; using SharedLibrary;
using SharedLibrary.Database.Models;
using SharedLibrary.Dtos; using SharedLibrary.Dtos;
using SharedLibrary.Services;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -13,7 +15,10 @@ namespace WebfrontCore.Controllers
{ {
public IActionResult List() public IActionResult List()
{ {
ViewBag.Title = "Penalty List"; ViewBag.Description = "List of all the recent penalties (bans, kicks, warnings) on IW4MAdmin";
ViewBag.Title = "Client Penalties";
ViewBag.Keywords = "IW4MAdmin, penalties, ban, kick, warns";
return View(); return View();
} }
@ -21,5 +26,23 @@ namespace WebfrontCore.Controllers
{ {
return View("_List", offset); return View("_List", offset);
} }
public async Task<IActionResult> PublicAsync()
{
var penalties = await (new GenericRepository<EFPenalty>())
.FindAsync(p => p.Type == SharedLibrary.Objects.Penalty.PenaltyType.Ban && p.Active);
var penaltiesDto = penalties.Select(p => new PenaltyInfo()
{
OffenderId = p.OffenderId,
Offense = p.Offense,
PunisherId = p.PunisherId,
Type = p.Type.ToString(),
TimePunished = p.When.ToString(),
TimeRemaining = p.Expires.ToString()
}).ToList();
return Json(penaltiesDto);
}
} }
} }

View File

@ -13,7 +13,7 @@ by editing this MSBuild file. In order to learn more about this please visit htt
<LaunchSiteAfterPublish>True</LaunchSiteAfterPublish> <LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
<ExcludeApp_Data>False</ExcludeApp_Data> <ExcludeApp_Data>False</ExcludeApp_Data>
<ProjectGuid>65340d7d-5831-406c-acad-b13ba634bde2</ProjectGuid> <ProjectGuid>65340d7d-5831-406c-acad-b13ba634bde2</ProjectGuid>
<publishUrl>C:\Users\User\Desktop\stuff\IW4M-Admin\IW4M-Admin\WebfrontCore\bin\x86\Release\PublishOutput</publishUrl> <publishUrl>C:\Projects\IW4M-Admin\Publish</publishUrl>
<DeleteExistingFiles>True</DeleteExistingFiles> <DeleteExistingFiles>True</DeleteExistingFiles>
<TargetFramework>net452</TargetFramework> <TargetFramework>net452</TargetFramework>
<RuntimeIdentifier>win7-x86</RuntimeIdentifier> <RuntimeIdentifier>win7-x86</RuntimeIdentifier>

View File

@ -1,4 +1,5 @@
@model Dictionary<SharedLibrary.Objects.Player.Permission, IList<SharedLibrary.Dtos.ClientInfo>> @model Dictionary<SharedLibrary.Objects.Player.Permission, IList<SharedLibrary.Dtos.ClientInfo>>
<h4 class="pb-2 text-center ">@ViewBag.Title</h4> <h4 class="pb-2 text-center ">@ViewBag.Title</h4>
<div class="row border-bottom"> <div class="row border-bottom">

View File

@ -1,9 +1,12 @@
@model SharedLibrary.Dtos.PlayerInfo @model SharedLibrary.Dtos.PlayerInfo
@{
string match = System.Text.RegularExpressions.Regex.Match(Model.Name.ToUpper(), "[A-Z]").Value;
string shortCode = match == string.Empty ? "?" : match;
}
<div id="profile_wrapper" class="row d-flex d-sm-inline-flex justify-content-center justify-content-left pb-3"> <div id="profile_wrapper" class="row d-flex d-sm-inline-flex justify-content-center justify-content-left pb-3">
<div class="mr-auto ml-auto ml-sm-0 mr-sm-0"> <div class="mr-auto ml-auto ml-sm-0 mr-sm-0">
<div id="profile_avatar" class="mb-4 mb-md-0 text-center level-bgcolor-@Model.Level.ToLower()"> <div id="profile_avatar" class="mb-4 mb-md-0 text-center level-bgcolor-@Model.Level.ToLower()">
<span class="profile-shortcode">@Model.Name[0].ToString().ToUpper()</span> <span class="profile-shortcode">@shortCode</span>
</div> </div>
</div> </div>
<div id="profile_info" class="text-center text-sm-left pr-3 pl-3"> <div id="profile_info" class="text-center text-sm-left pr-3 pl-3">
@ -29,7 +32,7 @@
{ {
foreach (string ip in Model.IPs) foreach (string ip in Model.IPs)
{ {
<a class="ip-locate-link" href="#" data-ip="@ip">@ip</a> <a class="ip-locate-link" href="#" data-ip="@ip">@ip</a><br/>
} }
} }

View File

@ -1,4 +1,5 @@
@model IEnumerable<SharedLibrary.Dtos.ServerInfo> @model IEnumerable<SharedLibrary.Dtos.ServerInfo>
<div class="row justify-content-center"> <div class="row justify-content-center">
<div id="console" class="col-md-8"> <div id="console" class="col-md-8">
@Html.DropDownList("Server", Model.Select(s => new SelectListItem() { Text = s.Name, Value = s.ID.ToString() }).ToList(), new { @class = "form-control bg-dark text-light", id="console_server_select" }) @Html.DropDownList("Server", Model.Select(s => new SelectListItem() { Text = s.Name, Value = s.ID.ToString() }).ToList(), new { @class = "form-control bg-dark text-light", id="console_server_select" })

View File

@ -3,6 +3,7 @@
@{ @{
Layout = null; Layout = null;
ViewBag.Description += Model.Name + ", ";
} }
<div class="row server-header"> <div class="row server-header">

View File

@ -1,22 +1,6 @@
@model ErrorViewModel @{
@{
ViewData["Title"] = "Error"; ViewData["Title"] = "Error";
} }
<h1 class="text-danger">Error.</h1> <h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2> <h2 class="text-danger">An error occurred while processing your request.</h2>
@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}
<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
<strong>Development environment should not be enabled in deployed applications</strong>, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>, and restarting the application.
</p>

View File

@ -3,7 +3,14 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>IW4MAdmin::@ViewBag.Title</title> <title>@ViewBag.Title | IW4MAdmin</title>
<meta property="og:title" content="@ViewBag.Title | IW4MAdmin">
<meta property="og:type" content="website">
<meta property="og:image" content="/favicon.ico">
<meta property="og:description" content="@ViewBag.Description">
<meta property="og:url" content="@ViewBag.Url">
<meta name="description" content="@ViewBag.Description">
<meta name="keywords" content="@ViewBag.Keywords">
<link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'> <link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
<environment names="Development"> <environment names="Development">
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" /> <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
@ -27,6 +34,10 @@
<li class="nav-item text-center text-md-left">@Html.ActionLink("Penalties", "List", "Penalty", new { area = "" }, new { @class = "nav-link" })</li> <li class="nav-item text-center text-md-left">@Html.ActionLink("Penalties", "List", "Penalty", new { area = "" }, new { @class = "nav-link" })</li>
<li class="nav-item text-center text-md-left">@Html.ActionLink("Admins", "PrivilegedAsync", "Client", new { area = "" }, new { @class = "nav-link" })</li> <li class="nav-item text-center text-md-left">@Html.ActionLink("Admins", "PrivilegedAsync", "Client", new { area = "" }, new { @class = "nav-link" })</li>
<li class="nav-item text-center text-md-left">@Html.ActionLink("Console", "Index", "Console", new { area = "" }, new { @class = "nav-link" })</li> <li class="nav-item text-center text-md-left">@Html.ActionLink("Console", "Index", "Console", new { area = "" }, new { @class = "nav-link" })</li>
@if (ViewBag.DiscordLink != string.Empty)
{
<li class="nav-item text-center text-md-left"><a href="@ViewBag.DiscordLink" target="_blank"></a></li>
}
</ul> </ul>
<form class="form-inline text-primary pt-3 pb-3" method="get" action="/Client/FindAsync"> <form class="form-inline text-primary pt-3 pb-3" method="get" action="/Client/FindAsync">
<input id="client_search" name="clientName" class="form-control mr-auto ml-auto mr-md-2" type="text" placeholder="Find Player" /> <input id="client_search" name="clientName" class="form-control mr-auto ml-auto mr-md-2" type="text" placeholder="Find Player" />
@ -41,14 +52,11 @@
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title" id="mainModalLabel"></h5> <h5 class="modal-title" id="mainModalLabel"></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"> <button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span> <span aria-hidden="true" class="text-danger">&times;</span>
</button> </button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
</div> </div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -69,4 +77,4 @@
</environment> </environment>
@RenderSection("scripts", required: false) @RenderSection("scripts", required: false)
</body> </body>
</html> </html>

View File

@ -0,0 +1,21 @@
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Trace",
"System": "Information",
"Microsoft": "None"
}
},
"Web": {
"Address": "127.0.0.1:5000"
},
"VPN": {
"APIKey": ""
},
"IW4MAdmin": {
},
"Discord": {
"InviteLink" : ""
}
}

View File

@ -9,5 +9,13 @@
}, },
"Web": { "Web": {
"Address": "127.0.0.1:5000" "Address": "127.0.0.1:5000"
},
"VPN": {
"APIKey": ""
},
"IW4MAdmin": {
},
"Discord": {
"InviteLink" : ""
} }
} }

View File

@ -53,10 +53,16 @@ $(document).ready(function () {
get ip geolocation info into modal get ip geolocation info into modal
*/ */
$('.ip-locate-link').click(function (e) { $('.ip-locate-link').click(function (e) {
$.getJSON("http://ip-api.com/json/" + $(this).data("ip")) e.preventDefault();
const ip = $(this).data("ip");
$.getJSON("http://ip-api.com/json/" + ip)
.done(function (response) { .done(function (response) {
$('.modal-title').text($(this).data("ip")); $('.modal-title').text(ip);
$('.modal-body').text(JSON.stringify(response, null, 4)); $('.modal-body').text("");
$('.modal-body').append("ASN &mdash; " + response["as"] + "<br/>");
$('.modal-body').append("ISP &mdash; " + response["isp"] + "<br/>");
$('.modal-body').append("Organization &mdash; " + response["org"] + "<br/>");
$('.modal-body').append("Location &mdash; " + response["city"] + ", " + response["regionName"] + ", " + response["country"] + "<br/>");
$('#mainModal').modal(); $('#mainModal').modal();
}); });

View File

@ -19,6 +19,6 @@ Callback_PlayerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vD
else if(!isPlayer(attacker) && sMeansOfDeath == "MOD_FALLING") else if(!isPlayer(attacker) && sMeansOfDeath == "MOD_FALLING")
_attacker = victim; _attacker = victim;
logPrint("ScriptKill;" + _attacker.guid + ";" + victim.guid + ";" + _attacker.origin + ";" + victim.origin + ";" + iDamage + ";" + sWeapon + ";" + sHitLoc + ";" + sMeansOfDeath + ";" + _attacker.angles + ";" + gettime() + "\n"); logPrint("ScriptKill;" + _attacker.guid + ";" + victim.guid + ";" + _attacker.origin + ";" + victim.origin + ";" + iDamage + ";" + sWeapon + ";" + sHitLoc + ";" + sMeansOfDeath + ";" + _attacker getPlayerAngles() + ";" + vDir + ";" + gettime() + "\n");
self maps\mp\gametypes\_damage::Callback_PlayerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration ); self maps\mp\gametypes\_damage::Callback_PlayerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration );
} }