Online players as news?
This commit is contained in:
92
Account.cs
92
Account.cs
@ -20,6 +20,8 @@ namespace NightmareCoreWeb2
|
|||||||
public DateTime LastLogin { get; set; }
|
public DateTime LastLogin { get; set; }
|
||||||
public List<Character> Characters { get; set; }
|
public List<Character> Characters { get; set; }
|
||||||
public List<AccountAccess> Access { get; set; }
|
public List<AccountAccess> Access { get; set; }
|
||||||
|
private readonly BigInteger g = 7;
|
||||||
|
private readonly BigInteger N = BigInteger.Parse("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7", NumberStyles.HexNumber);
|
||||||
|
|
||||||
|
|
||||||
public static Account AccountByID(int id)
|
public static Account AccountByID(int id)
|
||||||
@ -149,59 +151,67 @@ namespace NightmareCoreWeb2
|
|||||||
MySqlCommand cmd = new MySqlCommand(sql, conn);
|
MySqlCommand cmd = new MySqlCommand(sql, conn);
|
||||||
cmd.Parameters.AddWithValue("username", this.Username);
|
cmd.Parameters.AddWithValue("username", this.Username);
|
||||||
MySqlDataReader rdr = cmd.ExecuteReader();
|
MySqlDataReader rdr = cmd.ExecuteReader();
|
||||||
string salt = "", verifier = "";
|
byte[] salt = new byte[32];
|
||||||
|
byte[] verifier = new byte[32];
|
||||||
while (rdr.Read())
|
while (rdr.Read())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
salt = rdr.GetString(0);
|
rdr.GetBytes(0, 0, salt, 0, 32);
|
||||||
verifier = rdr.GetString(1);
|
rdr.GetBytes(1, 0, verifier, 0, 32);
|
||||||
}
|
}
|
||||||
catch (Exception) { }
|
catch (Exception) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
return VerifySRP6Login(this.Username, password, Encoding.ASCII.GetBytes(salt), Encoding.ASCII.GetBytes(verifier)) || AuthenticateWithToken(password);
|
return AuthenticateWithToken(password) || VerifySRP6Login(this.Username, password, salt, verifier);
|
||||||
}
|
}
|
||||||
// https://gist.github.com/Rochet2/3bb0adaf6f3e9a9fbc78ba5ce9a43e09
|
public bool VerifySRP6Login(string username, string password, byte[] salt, byte[] verifier)
|
||||||
public static byte[] CalculateSRP6Verifier(string username, string password, byte[] salt_bytes)
|
|
||||||
{
|
|
||||||
// algorithm constants
|
|
||||||
BigInteger g = 7;
|
|
||||||
BigInteger N = BigInteger.Parse("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7", NumberStyles.HexNumber);
|
|
||||||
|
|
||||||
SHA1 sha1 = SHA1.Create();
|
|
||||||
|
|
||||||
// calculate first hash
|
|
||||||
byte[] login_bytes = Encoding.ASCII.GetBytes((username + ':' + password).ToUpper());
|
|
||||||
byte[] h1_bytes = sha1.ComputeHash(login_bytes);
|
|
||||||
|
|
||||||
// calculate second hash
|
|
||||||
byte[] h2_bytes = sha1.ComputeHash(salt_bytes.Concat(h1_bytes).ToArray());
|
|
||||||
|
|
||||||
// convert to integer (little-endian)
|
|
||||||
BigInteger h2 = new BigInteger(h2_bytes.Reverse().ToArray());
|
|
||||||
Console.WriteLine(h2);
|
|
||||||
|
|
||||||
// g^h2 mod N
|
|
||||||
BigInteger verifier = BigInteger.ModPow(g, h2, N);
|
|
||||||
|
|
||||||
// convert back to a byte array (little-endian)
|
|
||||||
byte[] verifier_bytes = verifier.ToByteArray().Reverse().ToArray();
|
|
||||||
|
|
||||||
// pad to 32 bytes, remember that zeros go on the end in little-endian!
|
|
||||||
byte[] verifier_bytes_padded = new byte[Math.Max(32, verifier_bytes.Length)];
|
|
||||||
Buffer.BlockCopy(verifier_bytes, 0, verifier_bytes_padded, 0, verifier_bytes.Length);
|
|
||||||
|
|
||||||
// done!
|
|
||||||
return verifier_bytes_padded;
|
|
||||||
}
|
|
||||||
public static bool VerifySRP6Login(string username, string password, byte[] salt, byte[] verifier)
|
|
||||||
{
|
{
|
||||||
// re-calculate the verifier using the provided username + password and the stored salt
|
// re-calculate the verifier using the provided username + password and the stored salt
|
||||||
byte[] checkVerifier = CalculateSRP6Verifier(username, password, salt);
|
byte[] checkVerifier = CalculateVerifier(username, password, salt);
|
||||||
Console.WriteLine($"{Encoding.ASCII.GetString(verifier)}\n{Encoding.ASCII.GetString(checkVerifier)}");
|
Console.WriteLine($"{Encoding.ASCII.GetString(verifier)} {verifier.Length} bytes\n{Encoding.ASCII.GetString(checkVerifier)} {checkVerifier.Length} bytes");
|
||||||
|
Console.WriteLine($"DB {new BigInteger(verifier)}\nTC {new BigInteger(CalculateVerifier(username, password, salt))}");
|
||||||
// compare it against the stored verifier
|
// compare it against the stored verifier
|
||||||
return verifier.SequenceEqual(checkVerifier);
|
return verifier.SequenceEqual(checkVerifier.Reverse().ToArray());
|
||||||
|
}
|
||||||
|
public byte[] Hash(byte[] componentOne, byte[] componentTwo)
|
||||||
|
{
|
||||||
|
if (componentOne == null) throw new ArgumentNullException(nameof(componentOne));
|
||||||
|
if (componentTwo == null) throw new ArgumentNullException(nameof(componentTwo));
|
||||||
|
return Hash(componentOne.Concat(componentTwo).ToArray());
|
||||||
|
}
|
||||||
|
public byte[] Hash(byte[] bytes)
|
||||||
|
{
|
||||||
|
if (bytes == null) throw new ArgumentNullException(nameof(bytes));
|
||||||
|
|
||||||
|
//WoW expects non-secure SHA1 hashing. SRP6 is deprecated too. We need to do it anyway
|
||||||
|
using (SHA1 shaProvider = SHA1.Create())
|
||||||
|
{
|
||||||
|
return shaProvider.ComputeHash(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public byte[] CalculateVerifier(string username, string password, byte[] salt)
|
||||||
|
{
|
||||||
|
using (SHA1 shaProvider = SHA1.Create())
|
||||||
|
{
|
||||||
|
if (BitConverter.IsLittleEndian)
|
||||||
|
{
|
||||||
|
return BigInteger.ModPow(
|
||||||
|
g,
|
||||||
|
new BigInteger(Hash(salt, Hash(Encoding.UTF8.GetBytes($"{username.ToUpper()}:{password.ToUpper()}")))),
|
||||||
|
N
|
||||||
|
).ToByteArray();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BigInteger.ModPow(
|
||||||
|
g,
|
||||||
|
new BigInteger(Hash(salt, Hash(Encoding.UTF8.GetBytes($"{username.ToUpper()}:{password.ToUpper()}")).Reverse().ToArray())),
|
||||||
|
N
|
||||||
|
).ToByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,6 +39,7 @@ namespace NightmareCoreWeb2.Pages
|
|||||||
c.AtLogin |= (Character.AtLoginOptions)action;
|
c.AtLogin |= (Character.AtLoginOptions)action;
|
||||||
}
|
}
|
||||||
c.SetAtLogin();
|
c.SetAtLogin();
|
||||||
|
OnGet();
|
||||||
|
|
||||||
}
|
}
|
||||||
public void OnGet()
|
public void OnGet()
|
||||||
@ -46,10 +47,23 @@ namespace NightmareCoreWeb2.Pages
|
|||||||
|
|
||||||
ViewData["Title"] = "Login";
|
ViewData["Title"] = "Login";
|
||||||
AuthToken = Request.Cookies["AuthToken"];
|
AuthToken = Request.Cookies["AuthToken"];
|
||||||
Username = Request.Cookies["Username"];
|
if (!string.IsNullOrEmpty(AuthToken))
|
||||||
if (!string.IsNullOrEmpty(Username))
|
|
||||||
{
|
{
|
||||||
SetupAccount(Username);
|
conn.Open();
|
||||||
|
string sql = "select email from tokens.active_tokens where token=@token";
|
||||||
|
MySqlCommand cmd = new MySqlCommand(sql, conn);
|
||||||
|
cmd.Parameters.AddWithValue("token", AuthToken);
|
||||||
|
MySqlDataReader rdr = cmd.ExecuteReader();
|
||||||
|
string email = "";
|
||||||
|
while (rdr.Read())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
email = rdr.GetString(0);
|
||||||
|
}
|
||||||
|
catch (Exception) { }
|
||||||
|
}
|
||||||
|
SetupAccount(email.Substring(0, email.IndexOf("@")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void SetupAccount(string Username)
|
public void SetupAccount(string Username)
|
||||||
@ -73,7 +87,6 @@ namespace NightmareCoreWeb2.Pages
|
|||||||
|
|
||||||
public void OnPostLogin()
|
public void OnPostLogin()
|
||||||
{
|
{
|
||||||
Console.WriteLine("Logging in!");
|
|
||||||
UserEmail = Request.Form["UserEmail"];
|
UserEmail = Request.Form["UserEmail"];
|
||||||
UserPassword = Request.Form["UserPassword"];
|
UserPassword = Request.Form["UserPassword"];
|
||||||
Username = UserEmail.Substring(0, UserEmail.IndexOf("@"));
|
Username = UserEmail.Substring(0, UserEmail.IndexOf("@"));
|
||||||
@ -81,10 +94,10 @@ namespace NightmareCoreWeb2.Pages
|
|||||||
if (a.AuthenticateAccount(UserPassword))
|
if (a.AuthenticateAccount(UserPassword))
|
||||||
{
|
{
|
||||||
Response.Cookies.Append("Username", Username);
|
Response.Cookies.Append("Username", Username);
|
||||||
Response.Cookies.Append("AuthToken", a.Verifier);
|
Response.Cookies.Append("AuthToken", UserPassword);
|
||||||
Response.Redirect("/Account");
|
Response.Redirect("/Account");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using MySql.Data.MySqlClient;
|
using MySql.Data.MySqlClient;
|
||||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace NightmareCoreWeb2.Pages
|
namespace NightmareCoreWeb2.Pages
|
||||||
@ -110,5 +111,20 @@ namespace NightmareCoreWeb2.Pages
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ActionResult OnGetAlert() {
|
||||||
|
string ret = "";
|
||||||
|
if (this.OnlineCharacters.Count > 0) {
|
||||||
|
ret += "SERVERALERT:\nOnline Characters:\n";
|
||||||
|
|
||||||
|
foreach (Character c in OnlineCharacters) {
|
||||||
|
ret += $"{c.Username} as {c.Name}\n";
|
||||||
|
}
|
||||||
|
ret += "\n\r";
|
||||||
|
}
|
||||||
|
return Content(ret);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user