fix damage event not including log line
complete initiall implementation for "2FA" issue #52 issue #66
This commit is contained in:
parent
2bbf2988da
commit
40f1697c97
@ -10,7 +10,7 @@
|
||||
<Authors>RaidMax</Authors>
|
||||
<Company>Forever None</Company>
|
||||
<Product>IW4MAdmin</Product>
|
||||
<Description>IW4MAdmin is a complete server administration tool for IW4x and most Call of Duty® dedicated server</Description>
|
||||
<Description>IW4MAdmin is a complete server administration tool for IW4x and most Call of Duty® dedicated servers</Description>
|
||||
<Copyright>2019</Copyright>
|
||||
<PackageLicenseUrl>https://github.com/RaidMax/IW4M-Admin/blob/master/LICENSE</PackageLicenseUrl>
|
||||
<PackageProjectUrl>https://raidmax.org/IW4MAdmin</PackageProjectUrl>
|
||||
|
@ -376,7 +376,7 @@ namespace IW4MAdmin.Application
|
||||
Commands.Add(new CPing());
|
||||
Commands.Add(new CSetGravatar());
|
||||
Commands.Add(new CNextMap());
|
||||
Commands.Add(new GenerateTokenCommand());
|
||||
Commands.Add(new RequestTokenCommand());
|
||||
|
||||
foreach (Command C in SharedLibraryCore.Plugins.PluginImporter.ActiveCommands)
|
||||
{
|
||||
|
@ -87,7 +87,7 @@ namespace IW4MAdmin.Application.EventParsers
|
||||
return new GameEvent()
|
||||
{
|
||||
Type = GameEvent.EventType.JoinTeam,
|
||||
Data = eventType,
|
||||
Data = logLine,
|
||||
Origin = origin,
|
||||
Owner = server
|
||||
};
|
||||
@ -203,7 +203,7 @@ namespace IW4MAdmin.Application.EventParsers
|
||||
return new GameEvent()
|
||||
{
|
||||
Type = GameEvent.EventType.Damage,
|
||||
Data = eventType,
|
||||
Data = logLine,
|
||||
Origin = origin,
|
||||
Target = target,
|
||||
Owner = server
|
||||
|
@ -1,4 +1,5 @@
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using SharedLibraryCore.Helpers;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Security.Cryptography;
|
||||
@ -10,16 +11,9 @@ namespace IW4MAdmin.Application.Misc
|
||||
{
|
||||
private readonly ConcurrentDictionary<long, TokenState> _tokens;
|
||||
private readonly RNGCryptoServiceProvider _random;
|
||||
private readonly static TimeSpan _timeoutPeriod = new TimeSpan(0, 0, 30);
|
||||
private readonly static TimeSpan _timeoutPeriod = new TimeSpan(0, 0, 120);
|
||||
private const short TOKEN_LENGTH = 4;
|
||||
|
||||
private class TokenState
|
||||
{
|
||||
public long NetworkId { get; set; }
|
||||
public DateTime RequestTime { get; set; } = DateTime.Now;
|
||||
public string Token { get; set; }
|
||||
}
|
||||
|
||||
public TokenAuthentication()
|
||||
{
|
||||
_tokens = new ConcurrentDictionary<long, TokenState>();
|
||||
@ -38,32 +32,44 @@ namespace IW4MAdmin.Application.Misc
|
||||
return authorizeSuccessful;
|
||||
}
|
||||
|
||||
public string GenerateNextToken(long networkId)
|
||||
public TokenState GenerateNextToken(long networkId)
|
||||
{
|
||||
TokenState state = null;
|
||||
|
||||
if (_tokens.ContainsKey(networkId))
|
||||
{
|
||||
state = _tokens[networkId];
|
||||
|
||||
if ((DateTime.Now - state.RequestTime) < _timeoutPeriod)
|
||||
if ((DateTime.Now - state.RequestTime) > _timeoutPeriod)
|
||||
{
|
||||
return null;
|
||||
_tokens.TryRemove(networkId, out TokenState _);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
_tokens.TryRemove(networkId, out TokenState _);
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
state = new TokenState()
|
||||
{
|
||||
NetworkId = networkId,
|
||||
Token = _generateToken()
|
||||
Token = _generateToken(),
|
||||
TokenDuration = _timeoutPeriod
|
||||
};
|
||||
|
||||
_tokens.TryAdd(networkId, state);
|
||||
return state.Token;
|
||||
|
||||
// perform some housekeeping so we don't have built up tokens if they're not ever used
|
||||
foreach (var (key, value) in _tokens)
|
||||
{
|
||||
if ((DateTime.Now - value.RequestTime) > _timeoutPeriod)
|
||||
{
|
||||
_tokens.TryRemove(key, out TokenState _);
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
public string _generateToken()
|
||||
|
@ -1,8 +1,5 @@
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Database.Models;
|
||||
using SharedLibraryCore.Objects;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IW4MAdmin.Plugins.Login.Commands
|
||||
@ -22,18 +19,22 @@ namespace IW4MAdmin.Plugins.Login.Commands
|
||||
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));
|
||||
bool success = E.Owner.Manager.TokenAuthenticator.AuthorizeToken(E.Origin.NetworkId, E.Data);
|
||||
|
||||
if (hashedPassword[0] == client.Password)
|
||||
if (!success)
|
||||
{
|
||||
Plugin.AuthorizedClients[E.Origin.ClientId] = true;
|
||||
E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_LOGIN_COMMANDS_LOGIN_SUCCESS"]);
|
||||
string[] hashedPassword = await Task.FromResult(SharedLibraryCore.Helpers.Hashing.Hash(E.Data, client.PasswordSalt));
|
||||
|
||||
if (hashedPassword[0] == client.Password)
|
||||
{
|
||||
success = true;
|
||||
Plugin.AuthorizedClients[E.Origin.ClientId] = true;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
_ = success ?
|
||||
E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_LOGIN_COMMANDS_LOGIN_SUCCESS"]) :
|
||||
E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_LOGIN_COMMANDS_LOGIN_FAIL"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -427,19 +427,20 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||
|
||||
public void AddDamageEvent(string eventLine, int attackerClientId, int victimClientId, long serverId)
|
||||
{
|
||||
string regex = @"^(D);(.+);([0-9]+);(allies|axis);(.+);([0-9]+);(allies|axis);(.+);(.+);([0-9]+);(.+);(.+)$";
|
||||
var match = Regex.Match(eventLine, regex, RegexOptions.IgnoreCase);
|
||||
// todo: maybe do something with this
|
||||
//string regex = @"^(D);(.+);([0-9]+);(allies|axis);(.+);([0-9]+);(allies|axis);(.+);(.+);([0-9]+);(.+);(.+)$";
|
||||
//var match = Regex.Match(eventLine, regex, RegexOptions.IgnoreCase);
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
// this gives us what team the player is on
|
||||
var attackerStats = Servers[serverId].PlayerStats[attackerClientId];
|
||||
var victimStats = Servers[serverId].PlayerStats[victimClientId];
|
||||
IW4Info.Team victimTeam = (IW4Info.Team)Enum.Parse(typeof(IW4Info.Team), match.Groups[4].ToString());
|
||||
IW4Info.Team attackerTeam = (IW4Info.Team)Enum.Parse(typeof(IW4Info.Team), match.Groups[7].ToString());
|
||||
attackerStats.Team = attackerTeam;
|
||||
victimStats.Team = victimTeam;
|
||||
}
|
||||
//if (match.Success)
|
||||
//{
|
||||
// // this gives us what team the player is on
|
||||
// var attackerStats = Servers[serverId].PlayerStats[attackerClientId];
|
||||
// var victimStats = Servers[serverId].PlayerStats[victimClientId];
|
||||
// IW4Info.Team victimTeam = (IW4Info.Team)Enum.Parse(typeof(IW4Info.Team), match.Groups[4].ToString(), true);
|
||||
// IW4Info.Team attackerTeam = (IW4Info.Team)Enum.Parse(typeof(IW4Info.Team), match.Groups[7].ToString(), true);
|
||||
// attackerStats.Team = attackerTeam;
|
||||
// victimStats.Team = victimTeam;
|
||||
//}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1,22 +0,0 @@
|
||||
using SharedLibraryCore.Database.Models;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharedLibraryCore.Commands
|
||||
{
|
||||
public class GenerateTokenCommand : Command
|
||||
{
|
||||
public GenerateTokenCommand() :
|
||||
base("generatetoken", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_GENERATETOKEN_DESC"], "gt", EFClient.Permission.Trusted, false)
|
||||
{ }
|
||||
|
||||
public override Task ExecuteAsync(GameEvent E)
|
||||
{
|
||||
string token = E.Owner.Manager.TokenAuthenticator.GenerateNextToken(E.Origin.NetworkId);
|
||||
var _event = token == null ?
|
||||
E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_GENERATETOKEN_FAIL"]) :
|
||||
E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_GENERATETOKEN_SUCCESS"]} {token}");
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
20
SharedLibraryCore/Commands/RequestTokenCommand.cs
Normal file
20
SharedLibraryCore/Commands/RequestTokenCommand.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using SharedLibraryCore.Database.Models;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharedLibraryCore.Commands
|
||||
{
|
||||
public class RequestTokenCommand : Command
|
||||
{
|
||||
public RequestTokenCommand() :
|
||||
base("requesttoken", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_GENERATETOKEN_DESC"], "rt", EFClient.Permission.Trusted, false)
|
||||
{ }
|
||||
|
||||
public override Task ExecuteAsync(GameEvent E)
|
||||
{
|
||||
var state = E.Owner.Manager.TokenAuthenticator.GenerateNextToken(E.Origin.NetworkId);
|
||||
E.Origin.Tell(string.Format(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_GENERATETOKEN_SUCCESS"], state.Token, $"{state.RemainingTime} {Utilities.CurrentLocalization.LocalizationIndex["GLOBAL_MINUTES"]}", E.Origin.ClientId));
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
15
SharedLibraryCore/Helpers/TokenState.cs
Normal file
15
SharedLibraryCore/Helpers/TokenState.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SharedLibraryCore.Helpers
|
||||
{
|
||||
public sealed class TokenState
|
||||
{
|
||||
public long NetworkId { get; set; }
|
||||
public DateTime RequestTime { get; set; } = DateTime.Now;
|
||||
public TimeSpan TokenDuration { get; set; }
|
||||
public string Token { get; set; }
|
||||
public string RemainingTime => Math.Round(-(DateTime.Now - RequestTime).Subtract(TokenDuration).TotalMinutes, 1).ToString();
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using SharedLibraryCore.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
@ -11,7 +12,7 @@ namespace SharedLibraryCore.Interfaces
|
||||
/// </summary>
|
||||
/// <param name="networkId">network id of the players to generate the token for</param>
|
||||
/// <returns>4 character string token</returns>
|
||||
string GenerateNextToken(long networkId);
|
||||
TokenState GenerateNextToken(long networkId);
|
||||
|
||||
/// <summary>
|
||||
/// authorizes given token
|
||||
|
@ -21,9 +21,11 @@ namespace WebfrontCore.Controllers
|
||||
try
|
||||
{
|
||||
var client = Manager.GetPrivilegedClients()[clientId];
|
||||
string[] hashedPassword = await Task.FromResult(SharedLibraryCore.Helpers.Hashing.Hash(password, client.PasswordSalt));
|
||||
|
||||
if (hashedPassword[0] == client.Password)
|
||||
// string[] hashedPassword = await Task.FromResult(SharedLibraryCore.Helpers.Hashing.Hash(password, client.PasswordSalt));
|
||||
//if (hashedPassword[0] == client.Password)
|
||||
|
||||
if (Manager.TokenAuthenticator.AuthorizeToken(client.NetworkId, password))
|
||||
{
|
||||
var claims = new[]
|
||||
{
|
||||
@ -61,12 +63,5 @@ namespace WebfrontCore.Controllers
|
||||
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
return RedirectToAction("Index", "Home");
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> GenerateLoginTokenAsync()
|
||||
{
|
||||
return Json(new { token = Manager.TokenAuthenticator.GenerateNextToken(Client.NetworkId) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using SharedLibraryCore;
|
||||
using WebfrontCore.ViewModels;
|
||||
@ -182,5 +183,25 @@ namespace WebfrontCore.Controllers
|
||||
command = $"!setlevel @{targetId} {level}"
|
||||
}));
|
||||
}
|
||||
|
||||
public async Task<IActionResult> GenerateLoginTokenForm()
|
||||
{
|
||||
var info = new ActionInfo()
|
||||
{
|
||||
ActionButtonLabel = "Generate",
|
||||
Name = "GenerateLoginToken",
|
||||
Action = "GenerateLoginTokenAsync",
|
||||
Inputs = new List<InputInfo>()
|
||||
};
|
||||
|
||||
return View("_ActionForm", info);
|
||||
}
|
||||
|
||||
[Authorize]
|
||||
public string GenerateLoginTokenAsync()
|
||||
{
|
||||
var state = Manager.TokenAuthenticator.GenerateNextToken(Client.NetworkId);
|
||||
return string.Format(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_GENERATETOKEN_SUCCESS"], state.Token, $"{state.RemainingTime} {Utilities.CurrentLocalization.LocalizationIndex["GLOBAL_MINUTES"]}", Client.ClientId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,6 +70,7 @@
|
||||
@class = "dropdown-item bg-dark text-muted text-center text-md-left",
|
||||
title = "Logout of account"
|
||||
})
|
||||
<a class="dropdown-item bg-dark text-muted text-center text-md-left profile-action" href="#" data-action="GenerateLoginToken" aria-hidden="true" title="@loc["WEBFRONT_ACTION_TOKEN"]">@loc["WEBFRONT_ACTION_TOKEN"]</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item text-center text-md-left"></li>
|
||||
|
@ -1,18 +0,0 @@
|
||||
<environment include="Development">
|
||||
<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
|
||||
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
|
||||
</environment>
|
||||
<environment exclude="Development">
|
||||
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.14.0/jquery.validate.min.js"
|
||||
asp-fallback-src="~/lib/jquery-validation/dist/jquery.validate.min.js"
|
||||
asp-fallback-test="window.jQuery && window.jQuery.validator"
|
||||
crossorigin="anonymous"
|
||||
integrity="sha384-Fnqn3nxp3506LP/7Y3j/25BlWeA3PXTyT1l78LjECcPaKCV12TsZP7yyMxOe/G/k">
|
||||
</script>
|
||||
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.6/jquery.validate.unobtrusive.min.js"
|
||||
asp-fallback-src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"
|
||||
asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive"
|
||||
crossorigin="anonymous"
|
||||
integrity="sha384-JrXK+k53HACyavUKOsL+NkmSesD2P+73eDMrbTtTk0h4RmOF8hF8apPlkp26JlyH">
|
||||
</script>
|
||||
</environment>
|
@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||
<RuntimeFrameworkVersion>2.2.2</RuntimeFrameworkVersion>
|
||||
<RazorCompileOnBuild>true</RazorCompileOnBuild>
|
||||
<RazorCompileOnBuild>false</RazorCompileOnBuild>
|
||||
<RazorCompileOnPublish>true</RazorCompileOnPublish>
|
||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||
<TypeScriptToolsVersion>2.6</TypeScriptToolsVersion>
|
||||
@ -12,7 +12,7 @@
|
||||
<Authors>RaidMax</Authors>
|
||||
<Company>Forever None</Company>
|
||||
<Product>IW4MAdmin</Product>
|
||||
<Description>IW4MAdmin is a complete server administration tool for IW4x and most Call of Duty® dedicated server</Description>
|
||||
<Description>IW4MAdmin is a complete server administration tool for IW4x and most Call of Duty® dedicated servers</Description>
|
||||
<Copyright>2019</Copyright>
|
||||
<PackageLicenseUrl>https://github.com/RaidMax/IW4M-Admin/blob/master/LICENSE</PackageLicenseUrl>
|
||||
<PackageProjectUrl>https://raidmax.org/IW4MAdmin</PackageProjectUrl>
|
||||
@ -74,7 +74,5 @@
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ProjectExtensions><VisualStudio><UserProperties /></VisualStudio></ProjectExtensions>
|
||||
|
||||
</Project>
|
||||
|
@ -6416,4 +6416,3 @@ form *, select {
|
||||
position: fixed;
|
||||
bottom: 1em;
|
||||
right: 1em; }
|
||||
|
||||
|
@ -178,7 +178,6 @@
|
||||
}
|
||||
|
||||
.profile-action {
|
||||
padding-left: 0.25em;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user