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 List<Character> Characters { 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)
|
||||
@ -149,59 +151,67 @@ namespace NightmareCoreWeb2
|
||||
MySqlCommand cmd = new MySqlCommand(sql, conn);
|
||||
cmd.Parameters.AddWithValue("username", this.Username);
|
||||
MySqlDataReader rdr = cmd.ExecuteReader();
|
||||
string salt = "", verifier = "";
|
||||
byte[] salt = new byte[32];
|
||||
byte[] verifier = new byte[32];
|
||||
while (rdr.Read())
|
||||
{
|
||||
try
|
||||
{
|
||||
salt = rdr.GetString(0);
|
||||
verifier = rdr.GetString(1);
|
||||
rdr.GetBytes(0, 0, salt, 0, 32);
|
||||
rdr.GetBytes(1, 0, verifier, 0, 32);
|
||||
}
|
||||
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 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)
|
||||
public bool VerifySRP6Login(string username, string password, byte[] salt, byte[] verifier)
|
||||
{
|
||||
// re-calculate the verifier using the provided username + password and the stored salt
|
||||
byte[] checkVerifier = CalculateSRP6Verifier(username, password, salt);
|
||||
Console.WriteLine($"{Encoding.ASCII.GetString(verifier)}\n{Encoding.ASCII.GetString(checkVerifier)}");
|
||||
byte[] checkVerifier = CalculateVerifier(username, password, salt);
|
||||
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
|
||||
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.SetAtLogin();
|
||||
OnGet();
|
||||
|
||||
}
|
||||
public void OnGet()
|
||||
@ -46,10 +47,23 @@ namespace NightmareCoreWeb2.Pages
|
||||
|
||||
ViewData["Title"] = "Login";
|
||||
AuthToken = Request.Cookies["AuthToken"];
|
||||
Username = Request.Cookies["Username"];
|
||||
if (!string.IsNullOrEmpty(Username))
|
||||
if (!string.IsNullOrEmpty(AuthToken))
|
||||
{
|
||||
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)
|
||||
@ -73,7 +87,6 @@ namespace NightmareCoreWeb2.Pages
|
||||
|
||||
public void OnPostLogin()
|
||||
{
|
||||
Console.WriteLine("Logging in!");
|
||||
UserEmail = Request.Form["UserEmail"];
|
||||
UserPassword = Request.Form["UserPassword"];
|
||||
Username = UserEmail.Substring(0, UserEmail.IndexOf("@"));
|
||||
@ -81,7 +94,7 @@ namespace NightmareCoreWeb2.Pages
|
||||
if (a.AuthenticateAccount(UserPassword))
|
||||
{
|
||||
Response.Cookies.Append("Username", Username);
|
||||
Response.Cookies.Append("AuthToken", a.Verifier);
|
||||
Response.Cookies.Append("AuthToken", UserPassword);
|
||||
Response.Redirect("/Account");
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using MySql.Data.MySqlClient;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace NightmareCoreWeb2.Pages
|
||||
@ -110,5 +111,20 @@ namespace NightmareCoreWeb2.Pages
|
||||
{
|
||||
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