RCon error handling is clearer
Show chat on mobile view of server overview basic authentication switched to extreme-ip-lookup for ip lookups (SSL)
This commit is contained in:
parent
a0c1d9b1bc
commit
c0865b82a0
@ -975,6 +975,29 @@ namespace SharedLibrary.Commands
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class CSetPassword : Command
|
||||||
|
{
|
||||||
|
public CSetPassword() : base("setpassword", "set your authentication password", "sp", Player.Permission.Moderator, false, new CommandArgument[]
|
||||||
|
{
|
||||||
|
new CommandArgument()
|
||||||
|
{
|
||||||
|
Name = "password",
|
||||||
|
Required = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public override async Task ExecuteAsync(Event E)
|
||||||
|
{
|
||||||
|
string[] hashedPassword = Helpers.Hashing.Hash(E.Data);
|
||||||
|
|
||||||
|
E.Origin.Password = hashedPassword[0];
|
||||||
|
E.Origin.PasswordSalt = hashedPassword[1];
|
||||||
|
|
||||||
|
await E.Owner.Manager.GetClientService().Update(E.Origin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class CKillServer : Command
|
public class CKillServer : Command
|
||||||
{
|
{
|
||||||
public CKillServer() : base("killserver", "kill the game server", "kill", Player.Permission.Administrator, false)
|
public CKillServer() : base("killserver", "kill the game server", "kill", Player.Permission.Administrator, false)
|
||||||
|
@ -36,6 +36,9 @@ namespace SharedLibrary.Database.Models
|
|||||||
[ForeignKey("CurrentAliasId")]
|
[ForeignKey("CurrentAliasId")]
|
||||||
public virtual EFAlias CurrentAlias { get; set; }
|
public virtual EFAlias CurrentAlias { get; set; }
|
||||||
|
|
||||||
|
public string Password { get; set; }
|
||||||
|
public string PasswordSalt { get; set; }
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public virtual string Name
|
public virtual string Name
|
||||||
{
|
{
|
||||||
|
77
SharedLibrary/Helpers/Hashing.cs
Normal file
77
SharedLibrary/Helpers/Hashing.cs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
using System;
|
||||||
|
using SimpleCrypto;
|
||||||
|
|
||||||
|
namespace SharedLibrary.Helpers
|
||||||
|
{
|
||||||
|
public class Hashing
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Generate password hash and salt
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="password">plaintext password</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string[] Hash(string password, string saltStr = null)
|
||||||
|
{
|
||||||
|
|
||||||
|
string hash;
|
||||||
|
string salt;
|
||||||
|
var CryptoSvc = new PBKDF2();
|
||||||
|
|
||||||
|
// generate new hash
|
||||||
|
if (saltStr == null)
|
||||||
|
{
|
||||||
|
hash = CryptoSvc.Compute(password);
|
||||||
|
salt = CryptoSvc.Salt;
|
||||||
|
return new string[]
|
||||||
|
{
|
||||||
|
hash,
|
||||||
|
salt
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hash = CryptoSvc.Compute(password, saltStr);
|
||||||
|
return new string[]
|
||||||
|
{
|
||||||
|
hash,
|
||||||
|
""
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*//https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/consumer-apis/password-hashing
|
||||||
|
|
||||||
|
byte[] salt;
|
||||||
|
|
||||||
|
if (saltStr == null)
|
||||||
|
{
|
||||||
|
salt = new byte[128 / 8];
|
||||||
|
using (var rng = RandomNumberGenerator.Create())
|
||||||
|
{
|
||||||
|
rng.GetBytes(salt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
salt = Convert.FromBase64String(saltStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// derive a 256-bit subkey (use HMACSHA1 with 10,000 iterations)
|
||||||
|
string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
|
||||||
|
password: password,
|
||||||
|
salt: salt,
|
||||||
|
prf: KeyDerivationPrf.HMACSHA1,
|
||||||
|
iterationCount: 10000,
|
||||||
|
numBytesRequested: 256 / 8));
|
||||||
|
|
||||||
|
return new string[]
|
||||||
|
{
|
||||||
|
hashed,
|
||||||
|
Convert.ToBase64String(salt)
|
||||||
|
};*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,10 +11,24 @@ namespace SharedLibrary.RCon
|
|||||||
{
|
{
|
||||||
class ConnectionState
|
class ConnectionState
|
||||||
{
|
{
|
||||||
public Socket Client { get; set; }
|
public Socket Client { get; private set; }
|
||||||
public const int BufferSize = 8192;
|
public int BufferSize { get; private set; }
|
||||||
public byte[] Buffer = new byte[BufferSize];
|
public byte[] Buffer { get; private set; }
|
||||||
public readonly StringBuilder ResponseString = new StringBuilder();
|
|
||||||
|
private readonly StringBuilder sb;
|
||||||
|
|
||||||
|
public StringBuilder ResponseString
|
||||||
|
{
|
||||||
|
get => sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConnectionState(Socket cl)
|
||||||
|
{
|
||||||
|
BufferSize = 8192;
|
||||||
|
Buffer = new byte[BufferSize];
|
||||||
|
Client = cl;
|
||||||
|
sb = new StringBuilder();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Connection
|
public class Connection
|
||||||
@ -26,6 +40,7 @@ namespace SharedLibrary.RCon
|
|||||||
int FailedSends;
|
int FailedSends;
|
||||||
int FailedReceives;
|
int FailedReceives;
|
||||||
DateTime LastQuery;
|
DateTime LastQuery;
|
||||||
|
string response;
|
||||||
|
|
||||||
ManualResetEvent OnConnected;
|
ManualResetEvent OnConnected;
|
||||||
ManualResetEvent OnSent;
|
ManualResetEvent OnSent;
|
||||||
@ -92,14 +107,11 @@ namespace SharedLibrary.RCon
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
Log.WriteDebug($"Sent {sentByteNum} bytes to {ServerConnection.RemoteEndPoint}");
|
Log.WriteDebug($"Sent {sentByteNum} bytes to {ServerConnection.RemoteEndPoint}");
|
||||||
#endif
|
#endif
|
||||||
FailedSends = 0;
|
|
||||||
OnSent.Set();
|
OnSent.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception e)
|
catch (SocketException)
|
||||||
{
|
{
|
||||||
FailedSends++;
|
|
||||||
Log.WriteWarning($"Could not send RCon data to server - {e.Message}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,31 +138,33 @@ namespace SharedLibrary.RCon
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FailedReceives = 0;
|
response = connectionState.ResponseString.ToString();
|
||||||
OnReceived.Set();
|
OnReceived.Set();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
response = connectionState.ResponseString.ToString();
|
||||||
OnReceived.Set();
|
OnReceived.Set();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception)
|
catch (SocketException)
|
||||||
{
|
{
|
||||||
FailedReceives++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string[]> SendQueryAsync(StaticHelpers.QueryType type, string parameters = "")
|
public async Task<string[]> SendQueryAsync(StaticHelpers.QueryType type, string parameters = "")
|
||||||
{
|
{
|
||||||
// will this really prevent flooding?
|
// will this really prevent flooding?
|
||||||
if ((DateTime.Now - LastQuery).TotalMilliseconds < 300)
|
if ((DateTime.Now - LastQuery).TotalMilliseconds < 150)
|
||||||
{
|
{
|
||||||
await Task.Delay(300);
|
await Task.Delay(150);
|
||||||
LastQuery = DateTime.Now;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LastQuery = DateTime.Now;
|
||||||
|
|
||||||
OnSent.Reset();
|
OnSent.Reset();
|
||||||
OnReceived.Reset();
|
OnReceived.Reset();
|
||||||
string queryString = "";
|
string queryString = "";
|
||||||
@ -168,66 +182,103 @@ namespace SharedLibrary.RCon
|
|||||||
|
|
||||||
byte[] payload = Encoding.Default.GetBytes(queryString);
|
byte[] payload = Encoding.Default.GetBytes(queryString);
|
||||||
|
|
||||||
|
retrySend:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
retrySend:
|
|
||||||
ServerConnection.BeginSend(payload, 0, payload.Length, 0, new AsyncCallback(OnSentCallback), ServerConnection);
|
ServerConnection.BeginSend(payload, 0, payload.Length, 0, new AsyncCallback(OnSentCallback), ServerConnection);
|
||||||
bool success = await Task.FromResult(OnSent.WaitOne(StaticHelpers.SocketTimeout));
|
bool success = await Task.FromResult(OnSent.WaitOne(StaticHelpers.SocketTimeout));
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
|
FailedSends++;
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Log.WriteDebug($"{FailedSends} failed sends to {ServerConnection.RemoteEndPoint.ToString()}");
|
Log.WriteDebug($"{FailedSends} failed sends to {ServerConnection.RemoteEndPoint.ToString()}");
|
||||||
#endif
|
#endif
|
||||||
if (FailedSends < 4)
|
if (FailedSends < 4)
|
||||||
goto retrySend;
|
goto retrySend;
|
||||||
|
else if (FailedSends == 4)
|
||||||
|
Log.WriteError($"Failed to send data to {ServerConnection.RemoteEndPoint}");
|
||||||
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
throw new NetworkException($"Could not send data to server - {new SocketException((int)SocketError.TimedOut).Message}");
|
{
|
||||||
|
if (FailedSends >= 4)
|
||||||
|
{
|
||||||
|
Log.WriteVerbose($"Resumed send RCon connection with {ServerConnection.RemoteEndPoint}");
|
||||||
|
FailedSends = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (SocketException e)
|
catch (SocketException e)
|
||||||
{
|
{
|
||||||
// this result is normal if the server is not listening
|
// this result is normal if the server is not listening
|
||||||
if (e.HResult != (int)SocketError.ConnectionReset)
|
if (e.NativeErrorCode != (int)SocketError.ConnectionReset &&
|
||||||
|
e.NativeErrorCode != (int)SocketError.TimedOut)
|
||||||
throw new NetworkException($"Unexpected error while sending data to server - {e.Message}");
|
throw new NetworkException($"Unexpected error while sending data to server - {e.Message}");
|
||||||
}
|
}
|
||||||
|
|
||||||
var connectionState = new ConnectionState
|
var connectionState = new ConnectionState(ServerConnection);
|
||||||
{
|
|
||||||
Client = ServerConnection
|
|
||||||
};
|
|
||||||
|
|
||||||
|
retryReceive:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
retryReceive:
|
|
||||||
ServerConnection.BeginReceive(connectionState.Buffer, 0, connectionState.Buffer.Length, 0,
|
ServerConnection.BeginReceive(connectionState.Buffer, 0, connectionState.Buffer.Length, 0,
|
||||||
new AsyncCallback(OnReceivedCallback), connectionState);
|
new AsyncCallback(OnReceivedCallback), connectionState);
|
||||||
bool success = await Task.FromResult(OnReceived.WaitOne(StaticHelpers.SocketTimeout));
|
bool success = await Task.FromResult(OnReceived.WaitOne(StaticHelpers.SocketTimeout));
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
|
FailedReceives++;
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Log.WriteDebug($"{FailedReceives} failed receives from {ServerConnection.RemoteEndPoint.ToString()}");
|
Log.WriteDebug($"{FailedReceives} failed receives from {ServerConnection.RemoteEndPoint.ToString()}");
|
||||||
#endif
|
#endif
|
||||||
FailedReceives++;
|
|
||||||
if (FailedReceives < 4)
|
if (FailedReceives < 4)
|
||||||
goto retryReceive;
|
goto retrySend;
|
||||||
else if (FailedReceives == 4)
|
else if (FailedReceives == 4)
|
||||||
Log.WriteError($"Failed to receive data from {ServerConnection.RemoteEndPoint}");
|
{
|
||||||
|
Log.WriteError($"Failed to receive data from {ServerConnection.RemoteEndPoint} after {FailedReceives} tries");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FailedReceives >= 4)
|
||||||
|
{
|
||||||
|
throw new NetworkException($"Could not receive data from the {ServerConnection.RemoteEndPoint}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
throw new NetworkException($"Could not receive data from the server - {new SocketException((int)SocketError.TimedOut).Message}");
|
{
|
||||||
|
if (FailedReceives >= 4)
|
||||||
|
{
|
||||||
|
Log.WriteVerbose($"Resumed receive RCon connection from {ServerConnection.RemoteEndPoint}");
|
||||||
|
FailedReceives = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (SocketException e)
|
catch (SocketException e)
|
||||||
{
|
{
|
||||||
// this result is normal if the server is not listening
|
// this result is normal if the server is not listening
|
||||||
if (e.HResult != (int)SocketError.ConnectionReset)
|
if (e.NativeErrorCode != (int)SocketError.ConnectionReset &&
|
||||||
|
e.NativeErrorCode != (int)SocketError.TimedOut)
|
||||||
throw new NetworkException($"Unexpected error while receiving data from server - {e.Message}");
|
throw new NetworkException($"Unexpected error while receiving data from server - {e.Message}");
|
||||||
|
else if (FailedReceives < 4)
|
||||||
|
{
|
||||||
|
goto retryReceive;
|
||||||
}
|
}
|
||||||
|
|
||||||
string queryResponse = connectionState.ResponseString.ToString();
|
else if (FailedReceives == 4)
|
||||||
|
{
|
||||||
|
Log.WriteError($"Failed to receive data from {ServerConnection.RemoteEndPoint} after {FailedReceives} tries");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FailedReceives >= 4)
|
||||||
|
{
|
||||||
|
throw new NetworkException(e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string queryResponse = response;
|
||||||
|
|
||||||
if (queryResponse.Contains("Invalid password"))
|
if (queryResponse.Contains("Invalid password"))
|
||||||
throw new NetworkException("RCON password is invalid");
|
throw new NetworkException("RCON password is invalid");
|
||||||
|
@ -65,7 +65,7 @@ namespace SharedLibrary.Services
|
|||||||
Masked = false,
|
Masked = false,
|
||||||
NetworkId = entity.NetworkId,
|
NetworkId = entity.NetworkId,
|
||||||
AliasLink = aliasLink,
|
AliasLink = aliasLink,
|
||||||
CurrentAlias = existingAlias
|
CurrentAlias = existingAlias,
|
||||||
};
|
};
|
||||||
|
|
||||||
context.Clients.Add(client);
|
context.Clients.Add(client);
|
||||||
@ -180,6 +180,8 @@ namespace SharedLibrary.Services
|
|||||||
client.FirstConnection = entity.FirstConnection;
|
client.FirstConnection = entity.FirstConnection;
|
||||||
client.Masked = entity.Masked;
|
client.Masked = entity.Masked;
|
||||||
client.TotalConnectionTime = entity.TotalConnectionTime;
|
client.TotalConnectionTime = entity.TotalConnectionTime;
|
||||||
|
client.Password = entity.Password;
|
||||||
|
client.PasswordSalt = entity.PasswordSalt;
|
||||||
|
|
||||||
// update in database
|
// update in database
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
|
@ -173,6 +173,7 @@
|
|||||||
<Compile Include="Exceptions\SerializationException.cs" />
|
<Compile Include="Exceptions\SerializationException.cs" />
|
||||||
<Compile Include="Exceptions\ServerException.cs" />
|
<Compile Include="Exceptions\ServerException.cs" />
|
||||||
<Compile Include="Helpers\BaseConfigurationHandler.cs" />
|
<Compile Include="Helpers\BaseConfigurationHandler.cs" />
|
||||||
|
<Compile Include="Helpers\Hashing.cs" />
|
||||||
<Compile Include="Helpers\ParseEnum.cs" />
|
<Compile Include="Helpers\ParseEnum.cs" />
|
||||||
<Compile Include="Helpers\Vector3.cs" />
|
<Compile Include="Helpers\Vector3.cs" />
|
||||||
<Compile Include="Interfaces\IBaseConfiguration.cs" />
|
<Compile Include="Interfaces\IBaseConfiguration.cs" />
|
||||||
@ -242,6 +243,9 @@
|
|||||||
<PackageReference Include="Newtonsoft.Json">
|
<PackageReference Include="Newtonsoft.Json">
|
||||||
<Version>11.0.1</Version>
|
<Version>11.0.1</Version>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
<PackageReference Include="SimpleCrypto">
|
||||||
|
<Version>0.3.30.26</Version>
|
||||||
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<BootstrapperPackage Include=".NETFramework,Version=v4.5.2">
|
<BootstrapperPackage Include=".NETFramework,Version=v4.5.2">
|
||||||
|
@ -78,16 +78,26 @@ namespace IW4MAdmin
|
|||||||
{
|
{
|
||||||
#region DATABASE
|
#region DATABASE
|
||||||
var ipList = (await ClientSvc.Find(c => c.Level > Player.Permission.Trusted))
|
var ipList = (await ClientSvc.Find(c => c.Level > Player.Permission.Trusted))
|
||||||
.Select(c => new { c.IPAddress, c.ClientId, c.Level });
|
.Select(c => new
|
||||||
|
{
|
||||||
|
c.Password,
|
||||||
|
c.PasswordSalt,
|
||||||
|
c.ClientId,
|
||||||
|
c.Level,
|
||||||
|
c.Name
|
||||||
|
});
|
||||||
|
|
||||||
foreach (var a in ipList)
|
foreach (var a in ipList)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
PrivilegedClients.Add(a.IPAddress, new Player()
|
PrivilegedClients.Add(a.ClientId, new Player()
|
||||||
{
|
{
|
||||||
|
Name = a.Name,
|
||||||
ClientId = a.ClientId,
|
ClientId = a.ClientId,
|
||||||
Level = a.Level
|
Level = a.Level,
|
||||||
|
PasswordSalt = a.PasswordSalt,
|
||||||
|
Password = a.Password
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,6 +223,7 @@ namespace IW4MAdmin
|
|||||||
Commands.Add(new CMask());
|
Commands.Add(new CMask());
|
||||||
Commands.Add(new CPruneAdmins());
|
Commands.Add(new CPruneAdmins());
|
||||||
Commands.Add(new CKillServer());
|
Commands.Add(new CKillServer());
|
||||||
|
Commands.Add(new CSetPassword());
|
||||||
|
|
||||||
foreach (Command C in SharedLibrary.Plugins.PluginImporter.ActiveCommands)
|
foreach (Command C in SharedLibrary.Plugins.PluginImporter.ActiveCommands)
|
||||||
Commands.Add(C);
|
Commands.Add(C);
|
||||||
|
@ -791,16 +791,26 @@ namespace IW4MAdmin
|
|||||||
((ApplicationManager)(Manager)).PrivilegedClients = new Dictionary<int, Player>();
|
((ApplicationManager)(Manager)).PrivilegedClients = new Dictionary<int, Player>();
|
||||||
var ClientSvc = new ClientService();
|
var ClientSvc = new ClientService();
|
||||||
var ipList = (await ClientSvc.Find(c => c.Level > Player.Permission.Trusted))
|
var ipList = (await ClientSvc.Find(c => c.Level > Player.Permission.Trusted))
|
||||||
.Select(c => new { c.IPAddress, c.ClientId, c.Level });
|
.Select(c => new
|
||||||
|
{
|
||||||
|
c.Password,
|
||||||
|
c.PasswordSalt,
|
||||||
|
c.ClientId,
|
||||||
|
c.Level,
|
||||||
|
c.Name
|
||||||
|
});
|
||||||
|
|
||||||
foreach (var a in ipList)
|
foreach (var a in ipList)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
((ApplicationManager)(Manager)).PrivilegedClients.Add(a.IPAddress, new Player()
|
((ApplicationManager)(Manager)).PrivilegedClients.Add(a.ClientId, new Player()
|
||||||
{
|
{
|
||||||
|
Name = a.Name,
|
||||||
ClientId = a.ClientId,
|
ClientId = a.ClientId,
|
||||||
Level = a.Level
|
Level = a.Level,
|
||||||
|
PasswordSalt = a.PasswordSalt,
|
||||||
|
Password = a.Password
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
40
WebfrontCore/Controllers/AccountController.cs
Normal file
40
WebfrontCore/Controllers/AccountController.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
|
namespace WebfrontCore.Controllers
|
||||||
|
{
|
||||||
|
public class AccountController : BaseController
|
||||||
|
{
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> Login(int userId, string password)
|
||||||
|
{
|
||||||
|
if (userId == 0 || string.IsNullOrEmpty(password))
|
||||||
|
{
|
||||||
|
return Unauthorized();
|
||||||
|
}
|
||||||
|
|
||||||
|
var client = IW4MAdmin.Program.ServerManager.PrivilegedClients[userId];
|
||||||
|
string[] hashedPassword = await Task.FromResult(SharedLibrary.Helpers.Hashing.Hash(password, client.PasswordSalt));
|
||||||
|
|
||||||
|
if (hashedPassword[0] == client.Password)
|
||||||
|
{
|
||||||
|
var claims = new[]
|
||||||
|
{
|
||||||
|
new Claim(ClaimTypes.NameIdentifier, client.Name),
|
||||||
|
new Claim(ClaimTypes.Role, client.Level.ToString()),
|
||||||
|
new Claim(ClaimTypes.Sid, client.ClientId.ToString())
|
||||||
|
};
|
||||||
|
|
||||||
|
var claimsIdentity = new ClaimsIdentity(claims, "login");
|
||||||
|
var claimsPrinciple = new ClaimsPrincipal(claimsIdentity);
|
||||||
|
await HttpContext.Authentication.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrinciple);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Unauthorized();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -71,5 +71,34 @@ namespace WebfrontCore.Controllers
|
|||||||
command = $"!unban @{targetId} {Reason}"
|
command = $"!unban @{targetId} {Reason}"
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IActionResult LoginForm()
|
||||||
|
{
|
||||||
|
var login = new ActionInfo()
|
||||||
|
{
|
||||||
|
ActionButtonLabel = "Login",
|
||||||
|
Name = "Login",
|
||||||
|
Inputs = new List<InputInfo>()
|
||||||
|
{
|
||||||
|
new InputInfo()
|
||||||
|
{
|
||||||
|
Name = "UserID"
|
||||||
|
},
|
||||||
|
new InputInfo()
|
||||||
|
{
|
||||||
|
Name = "Password",
|
||||||
|
Type = "password",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Action = "Login"
|
||||||
|
};
|
||||||
|
|
||||||
|
return View("_ActionForm", login);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IActionResult Login(int userId, string password)
|
||||||
|
{
|
||||||
|
return RedirectToAction("Login", "Account", new { userId, password });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,11 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using SharedLibrary;
|
using SharedLibrary;
|
||||||
using SharedLibrary.Database.Models;
|
using SharedLibrary.Database.Models;
|
||||||
|
using SharedLibrary.Objects;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
namespace WebfrontCore.Controllers
|
namespace WebfrontCore.Controllers
|
||||||
{
|
{
|
||||||
@ -24,18 +28,17 @@ namespace WebfrontCore.Controllers
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var client = Manager.PrivilegedClients[context.HttpContext.Connection.RemoteIpAddress.ToString().ConvertToIP()];
|
User.ClientId = Convert.ToInt32(base.User.Claims.First(c => c.Type == ClaimTypes.Sid).Value);
|
||||||
User.ClientId = client.ClientId;
|
User.Level = (Player.Permission)Enum.Parse(typeof(Player.Permission), base.User.Claims.First(c => c.Type == ClaimTypes.Role).Value);
|
||||||
User.Level = client.Level;
|
User.CurrentAlias = new EFAlias() { Name = base.User.Claims.First(c => c.Type == ClaimTypes.NameIdentifier).Value };
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (KeyNotFoundException)
|
catch (InvalidOperationException)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Authorized = context.HttpContext.Connection.RemoteIpAddress.ToString() == "127.0.0.1" ||
|
Authorized = User.ClientId >= 0;
|
||||||
User.ClientId >= 0;
|
|
||||||
ViewBag.Authorized = Authorized;
|
ViewBag.Authorized = Authorized;
|
||||||
ViewBag.Url = Startup.Configuration["Web:Address"];
|
ViewBag.Url = Startup.Configuration["Web:Address"];
|
||||||
ViewBag.User = User;
|
ViewBag.User = User;
|
||||||
|
@ -63,7 +63,7 @@ namespace WebfrontCore.Controllers
|
|||||||
.Select(a => new ProfileMeta()
|
.Select(a => new ProfileMeta()
|
||||||
{
|
{
|
||||||
Key = "AliasEvent",
|
Key = "AliasEvent",
|
||||||
Value = $"Connected with name {a.Name}",
|
Value = $"Joined with alias {a.Name}",
|
||||||
Sensitive = true,
|
Sensitive = true,
|
||||||
When = a.DateAdded
|
When = a.DateAdded
|
||||||
}));
|
}));
|
||||||
|
@ -28,29 +28,16 @@ namespace WebfrontCore.Controllers
|
|||||||
|
|
||||||
public async Task<IActionResult> ExecuteAsync(int serverId, string command)
|
public async Task<IActionResult> ExecuteAsync(int serverId, string command)
|
||||||
{
|
{
|
||||||
var requestIPAddress = Request.HttpContext.Connection.RemoteIpAddress;
|
|
||||||
var intIP = requestIPAddress.ToString().ConvertToIP();
|
|
||||||
|
|
||||||
#if !DEBUG
|
|
||||||
var origin = (await IW4MAdmin.ApplicationManager.GetInstance().GetClientService().GetClientByIP(intIP))
|
|
||||||
.OrderByDescending(c => c.Level)
|
|
||||||
.FirstOrDefault()?.AsPlayer() ?? new Player()
|
|
||||||
{
|
|
||||||
Name = "WebConsoleUser",
|
|
||||||
Level = Player.Permission.User,
|
|
||||||
IPAddress = intIP
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
var origin = (await Manager.GetClientService().GetUnique(0)).AsPlayer();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
var server = Manager.Servers.First(s => s.GetHashCode() == serverId);
|
var server = Manager.Servers.First(s => s.GetHashCode() == serverId);
|
||||||
origin.CurrentServer = server;
|
var client = User.AsPlayer();
|
||||||
var remoteEvent = new Event(Event.GType.Say, command, origin, null, server);
|
client.CurrentServer = server;
|
||||||
|
|
||||||
|
var remoteEvent = new Event(Event.GType.Say, command, client, null, server);
|
||||||
|
|
||||||
await server.ExecuteEvent(remoteEvent);
|
await server.ExecuteEvent(remoteEvent);
|
||||||
|
|
||||||
var response = server.CommandResult.Where(c => c.ClientId == origin.ClientId).ToList();
|
var response = server.CommandResult.Where(c => c.ClientId == client.ClientId).ToList();
|
||||||
|
|
||||||
// remove the added command response
|
// remove the added command response
|
||||||
for (int i = 0; i < response.Count; i++)
|
for (int i = 0; i < response.Count; i++)
|
||||||
|
@ -21,7 +21,7 @@ namespace WebfrontCore.Controllers
|
|||||||
|
|
||||||
public IActionResult Error()
|
public IActionResult Error()
|
||||||
{
|
{
|
||||||
ViewBag.Description = "IW4MAdmin encountered and error";
|
ViewBag.Description = "IW4MAdmin encountered an error";
|
||||||
ViewBag.Title = "Error!";
|
ViewBag.Title = "Error!";
|
||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using SharedLibrary.Configuration;
|
|
||||||
|
|
||||||
namespace WebfrontCore
|
namespace WebfrontCore
|
||||||
{
|
{
|
||||||
@ -52,12 +49,23 @@ namespace WebfrontCore
|
|||||||
|
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
|
|
||||||
|
app.UseCookieAuthentication(new CookieAuthenticationOptions()
|
||||||
|
{
|
||||||
|
AccessDeniedPath = "/Account/Login/",
|
||||||
|
AuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme,
|
||||||
|
AutomaticAuthenticate = true,
|
||||||
|
AutomaticChallenge = true,
|
||||||
|
LoginPath = "/Account/Login/"
|
||||||
|
});
|
||||||
|
|
||||||
app.UseMvc(routes =>
|
app.UseMvc(routes =>
|
||||||
{
|
{
|
||||||
routes.MapRoute(
|
routes.MapRoute(
|
||||||
name: "default",
|
name: "default",
|
||||||
template: "{controller=Home}/{action=Index}/{id?}");
|
template: "{controller=Home}/{action=Index}/{id?}");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//app.UseBasicAuthentication(Authentication.Basic.Generate());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,8 @@ namespace WebfrontCore.ViewComponents
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var a = IW4MAdmin.ApplicationManager.GetInstance()
|
// var a = IW4MAdmin.ApplicationManager.GetInstance()
|
||||||
.PrivilegedClients[HttpContext.Connection.RemoteIpAddress.ToString().ConvertToIP()];
|
//.PrivilegedClients[HttpContext.Connection.RemoteIpAddress.ToString().ConvertToIP()];
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (KeyNotFoundException)
|
catch (KeyNotFoundException)
|
||||||
|
@ -3,20 +3,21 @@
|
|||||||
Layout = null;
|
Layout = null;
|
||||||
}
|
}
|
||||||
<form class="action-form" action="/Action/@Model.Action">
|
<form class="action-form" action="/Action/@Model.Action">
|
||||||
<div class="input-group mb-3">
|
|
||||||
@foreach (var input in Model.Inputs)
|
@foreach (var input in Model.Inputs)
|
||||||
{
|
{
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
<span class="input-group-text" id="basic-addon-@input.Name">@input.Name</span>
|
<span class="input-group-text" id="basic-addon-@input.Name">@input.Name</span>
|
||||||
</div>
|
</div>
|
||||||
{
|
@{
|
||||||
string inputType = input.Type ?? "text";
|
string inputType = input.Type ?? "text";
|
||||||
string value = input.Value ?? "";
|
string value = input.Value ?? "";
|
||||||
|
|
||||||
<input type="@inputType" name="@input.Name" value="@value" class="form-control" placeholder="@input.Placeholder" aria-label="@input.Name" aria-describedby="basic-addon-@input.Name">
|
<input type="@inputType" name="@input.Name" value="@value" class="form-control" placeholder="@input.Placeholder" aria-label="@input.Name" aria-describedby="basic-addon-@input.Name">
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
<button type="submit" class="btn btn-block btn-primary">@Model.ActionButtonLabel</button>
|
<button type="submit" class="btn btn-block btn-primary">@Model.ActionButtonLabel</button>
|
||||||
</form>
|
</form>
|
@ -23,13 +23,13 @@
|
|||||||
@if (Model.LevelInt < (int)ViewBag.User.Level &&
|
@if (Model.LevelInt < (int)ViewBag.User.Level &&
|
||||||
(SharedLibrary.Objects.Player.Permission)Model.LevelInt != SharedLibrary.Objects.Player.Permission.Banned)
|
(SharedLibrary.Objects.Player.Permission)Model.LevelInt != SharedLibrary.Objects.Player.Permission.Banned)
|
||||||
{
|
{
|
||||||
<div id="profile_action_ban_btn" class="profile-action oi oi-ban text-danger h3 ml-2" title="Ban Client" data-action="ban" aria-hidden="true"></div>
|
<div id="profile_action_ban_btn" class="profile-action oi oi-lock-unlocked text-success h3 ml-2" title="Ban Client" data-action="ban" aria-hidden="true"></div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (Model.LevelInt < (int)ViewBag.User.Level &&
|
@if (Model.LevelInt < (int)ViewBag.User.Level &&
|
||||||
(SharedLibrary.Objects.Player.Permission)Model.LevelInt == SharedLibrary.Objects.Player.Permission.Banned)
|
(SharedLibrary.Objects.Player.Permission)Model.LevelInt == SharedLibrary.Objects.Player.Permission.Banned)
|
||||||
{
|
{
|
||||||
<div id="profile_action_unban_btn" class="profile-action oi oi-action-undo text-success h3 ml-2" title="Unban Client" data-action="unban" aria-hidden="true"></div>
|
<div id="profile_action_unban_btn" class="profile-action oi oi-lock-locked text-danger h3 ml-2" title="Unban Client" data-action="unban" aria-hidden="true"></div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -47,3 +47,28 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@if (Model.ChatHistory.Length > 0)
|
||||||
|
{
|
||||||
|
<div class="w-100 border-bottom d-md-none d-block mt-1 mb-1"></div>
|
||||||
|
}
|
||||||
|
<div class="col-12 col-md-8 d-md-none d-block text-left">
|
||||||
|
@{
|
||||||
|
for (int i = 0; i < Model.ChatHistory.Length; i++)
|
||||||
|
{
|
||||||
|
string message = @Model.ChatHistory[i].Message;
|
||||||
|
if (Model.ChatHistory[i].Message == "CONNECTED")
|
||||||
|
{
|
||||||
|
<span class="text-light"><span class="oi oi-account-login mr-2 text-success"> </span>@Model.ChatHistory[i].Name</span><br />
|
||||||
|
}
|
||||||
|
if (Model.ChatHistory[i].Message == "DISCONNECTED")
|
||||||
|
{
|
||||||
|
|
||||||
|
<span class="text-light"><span class="oi oi-account-logout mr-2 text-danger"> </span>@Model.ChatHistory[i].Name</span><br />
|
||||||
|
}
|
||||||
|
if (Model.ChatHistory[i].Message != "CONNECTED" && Model.ChatHistory[i].Message != "DISCONNECTED")
|
||||||
|
{
|
||||||
|
<span class="text-light">@Model.ChatHistory[i].Name</span><span> — @message.Substring(0, Math.Min(65, message.Length)) </span><br />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
@ -38,6 +38,15 @@
|
|||||||
{
|
{
|
||||||
<li class="nav-item text-center text-md-left"><a href="@ViewBag.DiscordLink" class="nav-link" target="_blank">Discord</a></li>
|
<li class="nav-item text-center text-md-left"><a href="@ViewBag.DiscordLink" class="nav-link" target="_blank">Discord</a></li>
|
||||||
}
|
}
|
||||||
|
@if (ViewBag.Authorized)
|
||||||
|
{
|
||||||
|
<li class="nav-item text-center text-md-left">@Html.ActionLink("", "ProfileAsync", "Client", new { id = ViewBag.User.ClientId }, new { @class = "nav-link oi oi-person oi-fix-navbar w-100", title = "Client Profile" })</li>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
<li class="nav-item text-center text-md-left"><a href="#" id="profile_action_login_btn" class="nav-link profile-action oi oi-key oi-fix-navbar w-100" title="Login" data-action="login" aria-hidden="true"></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" />
|
||||||
@ -62,7 +71,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- End Main Modal -->
|
<!-- End Main Modal -->
|
||||||
|
|
||||||
<!-- Action Modal -->
|
<!-- Action Modal -->
|
||||||
<div class="modal fade" id="actionModal" tabindex="-1" role="dialog" aria-labelledby="actionModalLabel" aria-hidden="true">
|
<div class="modal fade" id="actionModal" tabindex="-1" role="dialog" aria-labelledby="actionModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog" role="document">
|
<div class="modal-dialog" role="document">
|
||||||
@ -97,6 +105,7 @@
|
|||||||
<script type="text/javascript" src="~/lib/moment-timezone/builds/moment-timezone-with-data.js"></script>
|
<script type="text/javascript" src="~/lib/moment-timezone/builds/moment-timezone-with-data.js"></script>
|
||||||
<!--<script type="text/javascript" src="~/lib/popper.js/dist/popper.js"></script>-->
|
<!--<script type="text/javascript" src="~/lib/popper.js/dist/popper.js"></script>-->
|
||||||
<script type="text/javascript" src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
|
<script type="text/javascript" src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
|
||||||
|
<script type="text/javascript" src="~/js/global.js"></script>
|
||||||
</environment>
|
</environment>
|
||||||
<environment names="Production">
|
<environment names="Production">
|
||||||
<script type="text/javascript" src="~/lib/jQuery/dist/jquery.min.js"></script>
|
<script type="text/javascript" src="~/lib/jQuery/dist/jquery.min.js"></script>
|
||||||
@ -104,6 +113,7 @@
|
|||||||
<script type="text/javascript" src="~/lib/moment-timezone/builds/moment-timezone.min.js"></script>
|
<script type="text/javascript" src="~/lib/moment-timezone/builds/moment-timezone.min.js"></script>
|
||||||
<!--<script type="text/javascript" src="~/lib/popper.js/dist/popper.min.js"></script>-->
|
<!--<script type="text/javascript" src="~/lib/popper.js/dist/popper.min.js"></script>-->
|
||||||
<script type="text/javascript" src="~/lib/bootstrap/dist/js/bootstrap.min.js"></script>
|
<script type="text/javascript" src="~/lib/bootstrap/dist/js/bootstrap.min.js"></script>
|
||||||
|
<script type="text/javascript" src="~/js/global.js"></script>
|
||||||
</environment>
|
</environment>
|
||||||
@RenderSection("scripts", required: false)
|
@RenderSection("scripts", required: false)
|
||||||
</body>
|
</body>
|
||||||
|
@ -5,10 +5,20 @@
|
|||||||
<PreserveCompilationContext>true</PreserveCompilationContext>
|
<PreserveCompilationContext>true</PreserveCompilationContext>
|
||||||
<AssemblyName>IW4MAdmin</AssemblyName>
|
<AssemblyName>IW4MAdmin</AssemblyName>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<PackageId>WebfrontCore</PackageId>
|
<PackageId>RaidMax.IW4MAdmin.WebfrontCore</PackageId>
|
||||||
<Platforms>AnyCPU;x86</Platforms>
|
<Platforms>AnyCPU;x86</Platforms>
|
||||||
<ApplicationIcon>wwwroot\favicon.ico</ApplicationIcon>
|
<ApplicationIcon>wwwroot\favicon.ico</ApplicationIcon>
|
||||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
|
<Version>1.6.0</Version>
|
||||||
|
<Authors>RaidMax</Authors>
|
||||||
|
<Company>ForeverNone</Company>
|
||||||
|
<Copyright>2018</Copyright>
|
||||||
|
<PackageLicenseUrl>https://github.com/RaidMax/IW4M-Admin/blob/master/LICENSE</PackageLicenseUrl>
|
||||||
|
<Description>Complete administration tool designed for IW4x and compatible with most Call Of Duty® dedicated servers</Description>
|
||||||
|
<PackageProjectUrl>https://raidmax.org/IW4Madmin/</PackageProjectUrl>
|
||||||
|
<PackageIconUrl>https://raidmax.org/IW4Madmin/img/iw4adminicon-3.png</PackageIconUrl>
|
||||||
|
<RepositoryUrl>https://github.com/RaidMax/IW4M-Admin</RepositoryUrl>
|
||||||
|
<NeutralLanguage>en</NeutralLanguage>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
@ -23,6 +33,7 @@
|
|||||||
<Content Remove="bower.json" />
|
<Content Remove="bower.json" />
|
||||||
<Content Remove="bundleconfig.json" />
|
<Content Remove="bundleconfig.json" />
|
||||||
<Content Remove="compilerconfig.json" />
|
<Content Remove="compilerconfig.json" />
|
||||||
|
<Content Remove="web.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -32,6 +43,8 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="1.1.3" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="1.1.3" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="1.1.5" />
|
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="1.1.5" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.7" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.7" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Routing" Version="1.1.2" />
|
<PackageReference Include="Microsoft.AspNetCore.Routing" Version="1.1.2" />
|
||||||
@ -64,6 +77,7 @@
|
|||||||
<None Include="bower.json" />
|
<None Include="bower.json" />
|
||||||
<None Include="bundleconfig.json" />
|
<None Include="bundleconfig.json" />
|
||||||
<None Include="compilerconfig.json" />
|
<None Include="compilerconfig.json" />
|
||||||
|
<None Include="web.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -78,6 +92,10 @@
|
|||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Views\Account\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
|
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
|
||||||
<Exec Command="if not "$(SolutionDir)"=="*Undefined*" (
 xcopy /Y "$(SolutionDir)BUILD\Plugins" "$(TargetDir)Plugins\"
)" />
|
<Exec Command="if not "$(SolutionDir)"=="*Undefined*" (
 xcopy /Y "$(SolutionDir)BUILD\Plugins" "$(TargetDir)Plugins\"
)" />
|
||||||
</Target>
|
</Target>
|
||||||
|
@ -42,7 +42,7 @@ a.nav-link {
|
|||||||
.server-activity,
|
.server-activity,
|
||||||
#mobile_seperator,
|
#mobile_seperator,
|
||||||
.border-bottom {
|
.border-bottom {
|
||||||
border-bottom: 1px solid $primary !important;
|
border-bottom: 2px solid $primary !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#client_search {
|
#client_search {
|
||||||
@ -92,3 +92,9 @@ a.link-inverse:hover {
|
|||||||
form * {
|
form * {
|
||||||
border-radius: 0 !important;
|
border-radius: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.oi-fix-navbar {
|
||||||
|
line-height: 1.5 !important;
|
||||||
|
top: 0 !important;
|
||||||
|
font-size: 1rem !important;
|
||||||
|
}
|
BIN
WebfrontCore/wwwroot/js.zip
Normal file
BIN
WebfrontCore/wwwroot/js.zip
Normal file
Binary file not shown.
46
WebfrontCore/wwwroot/js/global.js
Normal file
46
WebfrontCore/wwwroot/js/global.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
$(document).ready(function () {
|
||||||
|
/*
|
||||||
|
* handle action modal
|
||||||
|
*/
|
||||||
|
$('.profile-action').click(function (e) {
|
||||||
|
const actionType = $(this).data('action');
|
||||||
|
$.get('/Action/' + actionType + 'Form')
|
||||||
|
.done(function (response) {
|
||||||
|
$('#actionModal .modal-body').html(response);
|
||||||
|
$('#actionModal').modal();
|
||||||
|
})
|
||||||
|
.fail(function (jqxhr, textStatus, error) {
|
||||||
|
$('#actionModal .modal-body').html('<span class="text-danger">' + error + '</span>');
|
||||||
|
$('#actionModal').modal();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/*
|
||||||
|
* handle action submit
|
||||||
|
*/
|
||||||
|
$(document).on('submit', '.action-form', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
$(this).append($('#target_id input'));
|
||||||
|
const data = $(this).serialize();
|
||||||
|
$.get($(this).attr('action') + '/?' + data)
|
||||||
|
.done(function (response) {
|
||||||
|
// success without content
|
||||||
|
if (response.length === 0) {
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$('#actionModal .modal-body').html(response);
|
||||||
|
$('#actionModal').modal();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.fail(function (jqxhr, textStatus, error) {
|
||||||
|
if (jqxhr.status == 401) {
|
||||||
|
$('#actionModal .modal-body').removeClass('text-danger');
|
||||||
|
$('#actionModal .modal-body').prepend('<div class="text-danger mb-3">Invalid login credentials</div>');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$('#actionModal .modal-body').html('<span class="text-danger">Error — ' + error + '</span>');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -56,14 +56,41 @@ $(document).ready(function () {
|
|||||||
$('.ip-locate-link').click(function (e) {
|
$('.ip-locate-link').click(function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const ip = $(this).data("ip");
|
const ip = $(this).data("ip");
|
||||||
$.getJSON("http://ip-api.com/json/" + ip)
|
$.getJSON('https://extreme-ip-lookup.com/json/' + ip)
|
||||||
.done(function (response) {
|
.done(function (response) {
|
||||||
$('#mainModal .modal-title').text(ip);
|
$('#mainModal .modal-title').text(ip);
|
||||||
$('#mainModal .modal-body').text("");
|
$('#mainModal .modal-body').text("");
|
||||||
$('#mainModal .modal-body').append("ASN — " + response["as"] + "<br/>");
|
if (response.ipName.length > 0) {
|
||||||
$('#mainModal .modal-body').append("ISP — " + response["isp"] + "<br/>");
|
$('#mainModal .modal-body').append("Hostname — " + response.ipName + '<br/>');
|
||||||
$('#mainModal .modal-body').append("Organization — " + response["org"] + "<br/>");
|
}
|
||||||
$('#mainModal .modal-body').append("Location — " + response["city"] + ", " + response["regionName"] + ", " + response["country"] + "<br/>");
|
if (response.isp.length > 0) {
|
||||||
|
$('#mainModal .modal-body').append("ISP — " + response.isp + '<br/>');
|
||||||
|
}
|
||||||
|
if (response.ipType.length > 0) {
|
||||||
|
$('#mainModal .modal-body').append("Type — " + response.ipType + '<br/>');
|
||||||
|
}
|
||||||
|
if (response.org.length > 0) {
|
||||||
|
$('#mainModal .modal-body').append("Organization — " + response.org + '<br/>');
|
||||||
|
}
|
||||||
|
if (response['businessName'].length > 0) {
|
||||||
|
$('#mainModal .modal-body').append("Business — " + response.businessName + '<br/>');
|
||||||
|
}
|
||||||
|
if (response['businessWebsite'].length > 0) {
|
||||||
|
$('#mainModal .modal-body').append("Website — " + response.businessWebsite + '<br/>');
|
||||||
|
}
|
||||||
|
if (response.city.length > 0 || response.region.length > 0 || response.country.length > 0) {
|
||||||
|
$('#mainModal .modal-body').append("Location — ");
|
||||||
|
}
|
||||||
|
if (response.city.length > 0) {
|
||||||
|
$('#mainModal .modal-body').append(response.city);
|
||||||
|
}
|
||||||
|
if (response.region.length > 0) {
|
||||||
|
$('#mainModal .modal-body').append(', ' + response.region);
|
||||||
|
}
|
||||||
|
if (response.country.length > 0) {
|
||||||
|
$('#mainModal .modal-body').append(', ' + response.country);
|
||||||
|
}
|
||||||
|
|
||||||
$('#mainModal').modal();
|
$('#mainModal').modal();
|
||||||
})
|
})
|
||||||
.fail(function (jqxhr, textStatus, error) {
|
.fail(function (jqxhr, textStatus, error) {
|
||||||
@ -72,39 +99,6 @@ $(document).ready(function () {
|
|||||||
$('#mainModal').modal();
|
$('#mainModal').modal();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
|
||||||
* handle action modal
|
|
||||||
*/
|
|
||||||
$('.profile-action').click(function (e) {
|
|
||||||
const actionType = $(this).data('action');
|
|
||||||
$.get('/Action/' + actionType + 'Form')
|
|
||||||
.done(function (response) {
|
|
||||||
$('#actionModal .modal-body').html(response);
|
|
||||||
$('#actionModal').modal();
|
|
||||||
})
|
|
||||||
.fail(function (jqxhr, textStatus, error) {
|
|
||||||
$('#actionModal .modal-body').html('<span class="text-danger">' + error + '</span>');
|
|
||||||
$('#actionModal').modal();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
|
||||||
* handle action submit
|
|
||||||
*/
|
|
||||||
$(document).on('submit', '.action-form', function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
$(this).append($('#target_id input'));
|
|
||||||
const data = $(this).serialize();
|
|
||||||
$.get($(this).attr('action') + '/?' + data)
|
|
||||||
.done(function (response) {
|
|
||||||
$('#actionModal .modal-body').html(response);
|
|
||||||
$('#actionModal').modal();
|
|
||||||
})
|
|
||||||
.fail(function (jqxhr, textStatus, error) {
|
|
||||||
$('#actionModal .modal-body').html('<span class="text-danger">Error' + error + '</span>');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function penaltyToName(penaltyName) {
|
function penaltyToName(penaltyName) {
|
||||||
@ -179,7 +173,7 @@ function loadMeta(meta) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (meta.key.includes("Alias")) {
|
else if (meta.key.includes("Alias")) {
|
||||||
eventString = `<div><span class="text-primary">${meta.value}</span></div>`;
|
eventString = `<div><span class="text-success">${meta.value}</span></div>`;
|
||||||
}
|
}
|
||||||
// it's a message
|
// it's a message
|
||||||
else if (meta.key.includes("Event")) {
|
else if (meta.key.includes("Event")) {
|
||||||
|
@ -6058,7 +6058,7 @@ a.nav-link {
|
|||||||
.server-activity,
|
.server-activity,
|
||||||
#mobile_seperator,
|
#mobile_seperator,
|
||||||
.border-bottom {
|
.border-bottom {
|
||||||
border-bottom: 1px solid #007ACC !important; }
|
border-bottom: 2px solid #007ACC !important; }
|
||||||
|
|
||||||
#client_search {
|
#client_search {
|
||||||
background-color: #222222 !important;
|
background-color: #222222 !important;
|
||||||
@ -6097,3 +6097,8 @@ a.link-inverse:hover {
|
|||||||
form * {
|
form * {
|
||||||
border-radius: 0 !important; }
|
border-radius: 0 !important; }
|
||||||
|
|
||||||
|
.oi-fix-navbar {
|
||||||
|
line-height: 1.5 !important;
|
||||||
|
top: 0 !important;
|
||||||
|
font-size: 1rem !important; }
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user