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 &&
kill.Damage == 10000)
kill.Damage == 100000)
{
// suicide by switching teams so let's not count it against them
return;
@ -247,7 +247,8 @@ namespace StatsPlugin.Helpers
//statsSvc.KillStatsSvc.Insert(kill);
//await statsSvc.KillStatsSvc.SaveChangesAsync();
if (attacker.CurrentServer.Config.EnableAntiCheat)
{
async Task executePenalty(Cheat.DetectionPenaltyResult penalty)
{
switch (penalty.ClientPenalty)
@ -273,6 +274,7 @@ namespace StatsPlugin.Helpers
await executePenalty(playerDetection.ProcessKill(kill));
await executePenalty(playerDetection.ProcessTotalRatio(playerStats));
}
}
public async Task AddStandardKill(Player attacker, Player victim)
{

View File

@ -8,6 +8,9 @@ namespace SharedLibrary.Database
{
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");
if (false == engine.Verify())
{

View File

@ -42,7 +42,7 @@ namespace SharedLibrary
public Event(GType t, string d, Player O, Player T, Server S)
{
Type = t;
Data = d.Trim();
Data = d?.Trim();
Origin = O;
Target = T;
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);
}
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 string RestartUsername;
public string RestartPassword;
public bool EnableAntiCheat;
public bool AllowClientVpn;
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
{
[DllImport("kernel32.dll")]
public static extern bool AllocConsole();
static public double Version { get; private set; }
static public ApplicationManager ServerManager = ApplicationManager.GetInstance();
public static string OperatingDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + Path.DirectorySeparatorChar;
@ -33,15 +31,20 @@ namespace IW4MAdmin
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();
Task.Run(async () =>
{
ServerManager = ApplicationManager.GetInstance();
SharedLibrary.Database.Repair.Run(ServerManager.Logger);
await ServerManager.Init();
ServerManager.Start();
});
ServerManager.Init().Wait();
Task.Run(() => ServerManager.Start());
Task.Run(() =>
{
@ -95,9 +98,6 @@ namespace IW4MAdmin
if (!Directory.Exists($"{curDirectory}Logs"))
Directory.CreateDirectory($"{curDirectory}Logs");
if (!Directory.Exists($"{curDirectory}Database"))
Directory.CreateDirectory($"{curDirectory}Database");
if (!Directory.Exists($"{curDirectory}Plugins"))
Directory.CreateDirectory($"{curDirectory}Plugins");
}

View File

@ -104,8 +104,6 @@ namespace IW4MAdmin
{
var Conf = ServerConfiguration.Read(file);
Task.Run(async () =>
{
try
{
var ServerInstance = new IW4MServer(this, Conf);
@ -137,7 +135,7 @@ namespace IW4MAdmin
Logger.WriteDebug($"Internal Exception: {e.Data["internal_exception"]}");
}
}
});
}
#endregion

View File

@ -1,4 +1,6 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@ -9,13 +11,18 @@ namespace WebfrontCore.Application.Misc
{
public static async Task<bool> UsingVPN(string ip)
{
#if DEBUG
return false;
#endif
try
{
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");
double probability = Convert.ToDouble(response);
return probability > 0.9;
RequestClient.DefaultRequestHeaders.Add("X-Key", Startup.Configuration["VPN:APIKey"]);
string response = await RequestClient.GetStringAsync($"http://v2.api.iphub.info/ip/{ip}");
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)
{
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,
Name = polledPlayer.Name,
@ -143,7 +143,7 @@ namespace IW4MAdmin
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 });
}
@ -288,10 +288,9 @@ namespace IW4MAdmin
{
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();
if ((E.Data.ToLower().Trim() == E.Target.Name.ToLower().Trim() ||
E.Data == String.Empty) &&
C.RequiresTarget)
if (E.Data.Length == 0 && C.RequiredArgumentCount > 1)
{
await E.Origin.Tell($"Not enough arguments supplied!");
await E.Origin.Tell(C.Syntax);
@ -375,7 +374,7 @@ namespace IW4MAdmin
#if DEBUG
Logger.WriteInfo($"Polling players took {(DateTime.Now - now).TotalMilliseconds}ms");
#endif
Throttled = false;
for (int i = 0; i < Players.Count; i++)
{
if (CurrentPlayers.Find(p => p.ClientNumber == i) == null && Players[i] != null)
@ -561,7 +560,20 @@ namespace IW4MAdmin
DVAR<int> onelog = null;
if (GameName == Game.IW4)
{
try
{
onelog = await this.GetDvarAsync<int>("iw4x_onelog");
}
catch (Exception)
{
onelog = new DVAR<int>("iw4x_onelog")
{
Value = -1
};
}
}
try
{
@ -580,8 +592,10 @@ namespace IW4MAdmin
this.FSGame = game.Value;
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)
{
@ -603,7 +617,7 @@ namespace IW4MAdmin
}
#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) ?
$"{ basepath.Value.Replace("\\", "/")}/{mainPath}/{logfile.Value}" :

View File

@ -17,6 +17,8 @@ namespace IW4MAdmin
string Password;
bool AllowMultipleOwners;
bool AllowTrustedRank;
bool AntiCheat;
bool AllowVpns;
while (IP == String.Empty)
{
@ -57,13 +59,23 @@ namespace IW4MAdmin
Console.Write("Allow trusted rank? [y/n]: ");
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()
{
IP = IP,
Password = Password,
Port = Port,
AllowMultipleOwners = AllowMultipleOwners,
AllowTrustedRank = AllowTrustedRank
AllowTrustedRank = AllowTrustedRank,
RestartPassword = "",
RestartUsername = "",
EnableAntiCheat = AntiCheat,
AllowClientVpn = AllowVpns
};
config.Write();

View File

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

View File

@ -50,7 +50,7 @@ namespace WebfrontCore.Controllers
{
Key = "Masked",
Value = client.Masked ? "Is" : "Is not",
Sensitive = false,
Sensitive = true,
When = DateTime.MinValue
});
@ -61,7 +61,12 @@ namespace WebfrontCore.Controllers
.OrderByDescending(m => m.When)
.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);
}
@ -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);
}
@ -102,7 +110,7 @@ namespace WebfrontCore.Controllers
})
.ToList();
ViewBag.Name = $"Clients Matching \"{clientName}\"";
ViewBag.Title = $"Clients Matching \"{clientName}\"";
return View("Find/Index", clientsDto);
}
}

View File

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

View File

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

View File

@ -1,6 +1,8 @@
using Microsoft.AspNetCore.Mvc;
using SharedLibrary;
using SharedLibrary.Database.Models;
using SharedLibrary.Dtos;
using SharedLibrary.Services;
using System;
using System.Collections.Generic;
using System.Linq;
@ -13,7 +15,10 @@ namespace WebfrontCore.Controllers
{
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();
}
@ -21,5 +26,23 @@ namespace WebfrontCore.Controllers
{
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>
<ExcludeApp_Data>False</ExcludeApp_Data>
<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>
<TargetFramework>net452</TargetFramework>
<RuntimeIdentifier>win7-x86</RuntimeIdentifier>

View File

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

View File

@ -1,9 +1,12 @@
@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 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()">
<span class="profile-shortcode">@Model.Name[0].ToString().ToUpper()</span>
<span class="profile-shortcode">@shortCode</span>
</div>
</div>
<div id="profile_info" class="text-center text-sm-left pr-3 pl-3">
@ -29,7 +32,7 @@
{
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>
<div class="row justify-content-center">
<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" })

View File

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

View File

@ -1,22 +1,6 @@
@model ErrorViewModel
@{
@{
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<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>
<meta charset="utf-8" />
<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'>
<environment names="Development">
<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("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>
@if (ViewBag.DiscordLink != string.Empty)
{
<li class="nav-item text-center text-md-left"><a href="@ViewBag.DiscordLink" target="_blank"></a></li>
}
</ul>
<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" />
@ -41,14 +52,11 @@
<div class="modal-header">
<h5 class="modal-title" id="mainModalLabel"></h5>
<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>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>

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": {
"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
*/
$('.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) {
$('.modal-title').text($(this).data("ip"));
$('.modal-body').text(JSON.stringify(response, null, 4));
$('.modal-title').text(ip);
$('.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();
});

View File

@ -19,6 +19,6 @@ Callback_PlayerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vD
else if(!isPlayer(attacker) && sMeansOfDeath == "MOD_FALLING")
_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 );
}