token authentication

This commit is contained in:
jvyden 2021-10-13 20:07:56 -04:00
parent dc2c93647f
commit 05e4d513ea
No known key found for this signature in database
GPG key ID: 18BCF2BE0262B278
5 changed files with 76 additions and 15 deletions

View file

@ -1,6 +1,7 @@
#nullable enable
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Primitives;
using ProjectLighthouse.Types;
@ -15,19 +16,27 @@ namespace ProjectLighthouse.Controllers {
if(!this.Request.Query.TryGetValue("titleID", out StringValues _))
return this.BadRequest("");
// FIXME: this will not do, MM_AUTH is created by the client after POST /LOGIN
if(!this.Request.Cookies.TryGetValue("MM_AUTH", out string? mmAuth) || mmAuth == null)
return this.BadRequest(""); // TODO: send 403
await using Database database = new();
Token? token;
// ReSharper disable once InvertIf
if(!await database.IsUserAuthenticated(mmAuth)) {
if(!await database.AuthenticateUser(mmAuth)) return this.BadRequest(""); // TODO: send 403
token = await database.AuthenticateUser(mmAuth);
}
else {
token = await database.Tokens.FirstOrDefaultAsync(t => t.UserToken == mmAuth);
}
if(token == null) return this.BadRequest(""); // TODO: send 403
return this.Ok(new LoginResult {
AuthTicket = "d2c6bbec59162a1e786ed24ad95f2b73",
LbpEnvVer = "ProjectLighthouse"
AuthTicket = token.UserToken,
LbpEnvVer = ServerSettings.ServerName
}.Serialize());
}
}

View file

@ -38,28 +38,30 @@ namespace ProjectLighthouse {
// MM_AUTH=psn_name:?:timestamp, potentially a user creation date?:?:user id?:user's IP:?:password? SHA1
// just blindly trust the token for now while we get it working
public async Task<bool> AuthenticateUser(string mmAuth) {
if(!mmAuth.Contains(':')) return false;
public async Task<Token?> AuthenticateUser(string loginString) {
if(!loginString.Contains(':')) return null;
Token token = new() {
UserToken = mmAuth
};
string[] split = mmAuth.Split(":");
string[] split = loginString.Split(":");
// TODO: don't use psn name to authenticate
User user = await this.Users.FirstOrDefaultAsync(u => u.Username == split[0])
?? await this.CreateUser(split[0]);
token.UserId = user.UserId;
Token token = new() {
UserToken = HashHelper.GenerateAuthToken(),
UserId = user.UserId
};
return true;
this.Tokens.Add(token);
await this.SaveChangesAsync();
return token;
}
public async Task<bool> IsUserAuthenticated(string mmAuth) => await UserFromMMAuth(mmAuth) != null;
public async Task<bool> IsUserAuthenticated(string authToken) => await this.UserFromAuthToken(authToken) != null;
public async Task<User?> UserFromMMAuth(string mmAuth) {
Token? token = await Tokens.FirstOrDefaultAsync(t => t.UserToken == mmAuth);
public async Task<User?> UserFromAuthToken(string authToken) {
Token? token = await Tokens.FirstOrDefaultAsync(t => t.UserToken == authToken);
if(token == null) return null;
return await Users.FirstOrDefaultAsync(u => u.UserId == token.UserId);
}

View file

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
namespace ProjectLighthouse {
public static class HashHelper {
// private static readonly SHA1 sha1 = SHA1.Create();
private static readonly SHA256 sha256 = SHA256.Create();
private static readonly Random random = new();
#region Hash Functions
public static string Sha256Hash(string str) => Sha256Hash(Encoding.UTF8.GetBytes(str));
public static string Sha256Hash(byte[] bytes) {
byte[] hash = sha256.ComputeHash(bytes);
return Encoding.UTF8.GetString(hash, 0, hash.Length);
}
public static string BCryptHash(string str) => BCrypt.Net.BCrypt.HashPassword(str);
public static string BCryptHash(byte[] bytes) => BCrypt.Net.BCrypt.HashPassword(Encoding.UTF8.GetString(bytes));
#endregion
/// <summary>
/// Generates a specified amount of random bytes in an array.
/// </summary>
/// <param name="count">The amount of bytes to generate.</param>
/// <returns>The bytes generated</returns>
public static IEnumerable<byte> GenerateRandomBytes(int count) {
byte[] b = new byte[count];
random.NextBytes(b);
return b;
}
/// <summary>
/// Generates a random SHA256 & BCrypted token
/// </summary>
/// <returns>The token as a string.</returns>
public static string GenerateAuthToken() {
byte[] bytes = (byte[]) GenerateRandomBytes(256);
return BCryptHash(Sha256Hash(bytes));
}
}
}

View file

@ -6,6 +6,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BCrypt.Net-Next" Version="4.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.10" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="5.0.2" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />

View file

@ -10,6 +10,8 @@ namespace ProjectLighthouse.Types {
public const int ListsQuota = 20;
public const string ServerName = "ProjectLighthouse";
private static string? dbConnectionString;
public static string DbConnectionString {
get {