mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-07-24 22:21:30 +00:00
token authentication
This commit is contained in:
parent
dc2c93647f
commit
05e4d513ea
5 changed files with 76 additions and 15 deletions
|
@ -1,6 +1,7 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
using ProjectLighthouse.Types;
|
using ProjectLighthouse.Types;
|
||||||
|
|
||||||
|
@ -15,19 +16,27 @@ namespace ProjectLighthouse.Controllers {
|
||||||
if(!this.Request.Query.TryGetValue("titleID", out StringValues _))
|
if(!this.Request.Query.TryGetValue("titleID", out StringValues _))
|
||||||
return this.BadRequest("");
|
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)
|
if(!this.Request.Cookies.TryGetValue("MM_AUTH", out string? mmAuth) || mmAuth == null)
|
||||||
return this.BadRequest(""); // TODO: send 403
|
return this.BadRequest(""); // TODO: send 403
|
||||||
|
|
||||||
await using Database database = new();
|
await using Database database = new();
|
||||||
|
|
||||||
|
Token? token;
|
||||||
|
|
||||||
// ReSharper disable once InvertIf
|
// ReSharper disable once InvertIf
|
||||||
if(!await database.IsUserAuthenticated(mmAuth)) {
|
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 {
|
return this.Ok(new LoginResult {
|
||||||
AuthTicket = "d2c6bbec59162a1e786ed24ad95f2b73",
|
AuthTicket = token.UserToken,
|
||||||
LbpEnvVer = "ProjectLighthouse"
|
LbpEnvVer = ServerSettings.ServerName
|
||||||
}.Serialize());
|
}.Serialize());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,28 +38,30 @@ namespace ProjectLighthouse {
|
||||||
|
|
||||||
// MM_AUTH=psn_name:?:timestamp, potentially a user creation date?:?:user id?:user's IP:?:password? SHA1
|
// 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
|
// just blindly trust the token for now while we get it working
|
||||||
public async Task<bool> AuthenticateUser(string mmAuth) {
|
public async Task<Token?> AuthenticateUser(string loginString) {
|
||||||
if(!mmAuth.Contains(':')) return false;
|
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
|
// TODO: don't use psn name to authenticate
|
||||||
User user = await this.Users.FirstOrDefaultAsync(u => u.Username == split[0])
|
User user = await this.Users.FirstOrDefaultAsync(u => u.Username == split[0])
|
||||||
?? await this.CreateUser(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) {
|
public async Task<User?> UserFromAuthToken(string authToken) {
|
||||||
Token? token = await Tokens.FirstOrDefaultAsync(t => t.UserToken == mmAuth);
|
Token? token = await Tokens.FirstOrDefaultAsync(t => t.UserToken == authToken);
|
||||||
if(token == null) return null;
|
if(token == null) return null;
|
||||||
return await Users.FirstOrDefaultAsync(u => u.UserId == token.UserId);
|
return await Users.FirstOrDefaultAsync(u => u.UserId == token.UserId);
|
||||||
}
|
}
|
||||||
|
|
47
ProjectLighthouse/HashHelper.cs
Normal file
47
ProjectLighthouse/HashHelper.cs
Normal 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="BCrypt.Net-Next" Version="4.0.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.10" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.10" />
|
||||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="5.0.2" />
|
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="5.0.2" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
|
||||||
|
|
|
@ -10,6 +10,8 @@ namespace ProjectLighthouse.Types {
|
||||||
|
|
||||||
public const int ListsQuota = 20;
|
public const int ListsQuota = 20;
|
||||||
|
|
||||||
|
public const string ServerName = "ProjectLighthouse";
|
||||||
|
|
||||||
private static string? dbConnectionString;
|
private static string? dbConnectionString;
|
||||||
public static string DbConnectionString {
|
public static string DbConnectionString {
|
||||||
get {
|
get {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue