From 33eee17c43e924aeda73beb76aa59e03ac9a56fa Mon Sep 17 00:00:00 2001 From: Cody Larkin Date: Thu, 30 Apr 2026 19:08:37 -0400 Subject: [PATCH 1/3] Beginnings of Core Auth --- RelayCore/Endpoints/AuthEndpoints.cs | 57 ++++++++++++++++++++++++++++ RelayCore/Program.cs | 24 +++++++++--- RelayCore/RelayCore.csproj | 7 +--- RelayCore/Services/APIAuthService.cs | 20 ++++++++++ 4 files changed, 98 insertions(+), 10 deletions(-) create mode 100644 RelayCore/Endpoints/AuthEndpoints.cs create mode 100644 RelayCore/Services/APIAuthService.cs diff --git a/RelayCore/Endpoints/AuthEndpoints.cs b/RelayCore/Endpoints/AuthEndpoints.cs new file mode 100644 index 0000000..47ff950 --- /dev/null +++ b/RelayCore/Endpoints/AuthEndpoints.cs @@ -0,0 +1,57 @@ +using RelayCore.Services; + +namespace RelayCore.Endpoints; + +public static class AuthEndpoints +{ + public static void MapAuthEndpoints(this WebApplication app) + { + app.MapPost("/user/signin", async (AuthSignin request, APIAuthService service) => + { + var token = await service.UserSigninAsync(request); + + return token != null ? Results.Ok(token) : Results.Unauthorized(); + }); + app.MapPost("/user/register", async (AuthRegister request, APIAuthService service) => + { + throw new NotImplementedException(); + return Results.Ok(); + }); + app.MapPost("/server/verify/user", async (AuthUserVerify request, APIAuthService service) => + { + throw new NotImplementedException(); + }); + app.MapPost("/server/user/profile", async (AuthUserVerify request, APIAuthService service) => + { + throw new NotImplementedException(); + }); + app.MapPost("/server/verify/license", async (AuthServerLicense request, APIAuthService service) => + { + throw new NotImplementedException(); + }); + } +} + +public class AuthSignin +{ + public string UserName { get; set; } + public string Password { get; set; } +} + +public class AuthRegister +{ + public string Username { get; set; } + public string Password { get; set; } + public string Email { get; set; } +} + +public class AuthUserVerify +{ + public string Username { get; set; } + public string Token { get; set; } +} + +public class AuthServerLicense +{ + public string License { get; set; } +} \ No newline at end of file diff --git a/RelayCore/Program.cs b/RelayCore/Program.cs index d7a0e2d..b1bb2d4 100644 --- a/RelayCore/Program.cs +++ b/RelayCore/Program.cs @@ -1,14 +1,13 @@ using SurrealDb.Net; using SurrealDb.Net.Models.Auth; using System.Text.Json; -using System; using System.Net; -using System.Threading.Tasks; using System.Text; -using System.Text.Json; using RelayCore.Enums; using RelayCore.Models; +using RelayCore.Endpoints; +using RelayCore.Services; await using var db = new SurrealDbClient("ws://127.0.0.1:8000/rpc"); @@ -25,8 +24,24 @@ Console.WriteLine($"Keeper created: {ToJsonString(keeper)}"); Console.WriteLine($"Kira created: {ToJsonString(kira)}"); Console.WriteLine($"Test created: {ToJsonString(test)}"); -await server.Main(db); +var builder = WebApplication.CreateBuilder(args); +builder.Services.AddSingleton(db); +builder.Services.AddScoped(); + +var app = builder.Build(); +app.MapGet("/", () => "Auth Server Running!"); +app.MapAuthEndpoints(); + +// await server.Main(db); + +await app.StartAsync(); +Console.WriteLine("API Started"); +Console.WriteLine("\n\n\n"); + +Console.Write("Press any key to stop."); Console.ReadKey(true); + +await app.StopAsync(); return; static string ToJsonString(object? o) @@ -65,7 +80,6 @@ static async Task CreateUserAsync(SurrealDbClient db, string username, st return updated; } - partial class Program { public async Task Main(SurrealDbClient db) diff --git a/RelayCore/RelayCore.csproj b/RelayCore/RelayCore.csproj index 94ae57d..3b7c5c1 100644 --- a/RelayCore/RelayCore.csproj +++ b/RelayCore/RelayCore.csproj @@ -1,4 +1,4 @@ - + Exe @@ -10,11 +10,8 @@ + - - - - diff --git a/RelayCore/Services/APIAuthService.cs b/RelayCore/Services/APIAuthService.cs new file mode 100644 index 0000000..481bf6c --- /dev/null +++ b/RelayCore/Services/APIAuthService.cs @@ -0,0 +1,20 @@ +using RelayCore.Endpoints; +using SurrealDb.Net; + +namespace RelayCore.Services; + +public class APIAuthService(SurrealDbClient db) +{ + private readonly SurrealDbClient _db = db; + + + public async Task GetUsersAsync() + { + throw new NotImplementedException(); + } + + public async Task UserSigninAsync(AuthSignin request) + { + throw new NotImplementedException(); + } +} \ No newline at end of file From ec6a8c446a7a9285087b663b3665efe4968a2fdc Mon Sep 17 00:00:00 2001 From: Cody Larkin Date: Sat, 2 May 2026 16:06:08 -0400 Subject: [PATCH 2/3] Auth setup continued --- RelayCore/Endpoints/AuthEndpoints.cs | 11 +++----- RelayCore/Models/PasswordHasher.cs | 2 +- RelayCore/Models/Sessions.cs | 2 +- RelayCore/Program.cs | 2 +- RelayCore/Services/APIAuthService.cs | 39 ++++++++++++++++++++++++---- 5 files changed, 41 insertions(+), 15 deletions(-) diff --git a/RelayCore/Endpoints/AuthEndpoints.cs b/RelayCore/Endpoints/AuthEndpoints.cs index 47ff950..debada4 100644 --- a/RelayCore/Endpoints/AuthEndpoints.cs +++ b/RelayCore/Endpoints/AuthEndpoints.cs @@ -14,16 +14,13 @@ public static class AuthEndpoints }); app.MapPost("/user/register", async (AuthRegister request, APIAuthService service) => { - throw new NotImplementedException(); - return Results.Ok(); + var token = await service.UserRegisterAsync(request); + return token != null ? Results.Ok(token) : Results.Unauthorized(); }); app.MapPost("/server/verify/user", async (AuthUserVerify request, APIAuthService service) => { - throw new NotImplementedException(); - }); - app.MapPost("/server/user/profile", async (AuthUserVerify request, APIAuthService service) => - { - throw new NotImplementedException(); + bool valid = await service.ServerVerifyUser(request); + return Results.Ok(valid); }); app.MapPost("/server/verify/license", async (AuthServerLicense request, APIAuthService service) => { diff --git a/RelayCore/Models/PasswordHasher.cs b/RelayCore/Models/PasswordHasher.cs index 866af9a..eecc9d6 100644 --- a/RelayCore/Models/PasswordHasher.cs +++ b/RelayCore/Models/PasswordHasher.cs @@ -22,7 +22,7 @@ namespace RelayCore.Models /// /// Number of threads to use for parallel computation /// - private const int DegreeOfParallelism = 1; + private const int DegreeOfParallelism = 2; /// /// Number of iterations for the Argon2id algorithm diff --git a/RelayCore/Models/Sessions.cs b/RelayCore/Models/Sessions.cs index 92da4ed..8443ba8 100644 --- a/RelayCore/Models/Sessions.cs +++ b/RelayCore/Models/Sessions.cs @@ -4,7 +4,7 @@ namespace RelayCore.Models; public class Sessions : Record { - public required string UserId { get; set; } + public required RecordId UserId { get; set; } public required string TokenHash { get; set; } public required DateTime IssuedAt { get; set; } public required DateTime ExpiresAt { get; set; } diff --git a/RelayCore/Program.cs b/RelayCore/Program.cs index b1bb2d4..44d0bed 100644 --- a/RelayCore/Program.cs +++ b/RelayCore/Program.cs @@ -66,7 +66,7 @@ static async Task CreateUserAsync(SurrealDbClient db, string username, st OnlineStatus = (int)OnlineStatuses.Online, }; - var created = await db.Create("users", user); + var created = await db.Create("auth_users", user); var hasher = new PasswordHasher(); var passwordHash = hasher.HashPassword(created.Id.ToString() + rawPassword); diff --git a/RelayCore/Services/APIAuthService.cs b/RelayCore/Services/APIAuthService.cs index 481bf6c..e271ff5 100644 --- a/RelayCore/Services/APIAuthService.cs +++ b/RelayCore/Services/APIAuthService.cs @@ -1,19 +1,48 @@ using RelayCore.Endpoints; +using RelayCore.Models; using SurrealDb.Net; +using SurrealDb.Net.Models; namespace RelayCore.Services; -public class APIAuthService(SurrealDbClient db) +public class APIAuthService(SurrealDbClient _db) { - private readonly SurrealDbClient _db = db; + + public async Task UserSigninAsync(AuthSignin request) + { + var hasher = new PasswordHasher(); + var users = await _db.Select("auth_users"); + var user = users.FirstOrDefault(x => (x.Username == request.UserName || x.Email == request.UserName) + && hasher.VerifyPassword(request.Password, x.Password)); + var tokens = await _db.Select("auth_sessions"); + var token = tokens.Where(x => x.UserId == user.Id && !x.Revoked).OrderByDescending(x => x.ExpiresAt).FirstOrDefault(); + if (token.ExpiresAt > DateTime.UtcNow) + return token.TokenHash; + + //TODO: Generate TOKEN + var newToken = hasher.HashPassword($"{user.Email}{user.Username}{user.Password}"); + //TODO: Store TOKEN and Username for verification + var sessionId = await _db.Create(new Sessions + { + UserId = user.Id, + TokenHash = newToken, + IssuedAt = DateTime.UtcNow, + ExpiresAt = DateTime.UtcNow.AddDays(30), + DeviceName = "", + Revoked = false, + IpAddress = "", + UserAgent = "" + }); + //TODO: Add invalidation to TOKENs + return newToken; + } - - public async Task GetUsersAsync() + public async Task UserRegisterAsync(AuthRegister request) { throw new NotImplementedException(); } - public async Task UserSigninAsync(AuthSignin request) + public async Task ServerVerifyUser(AuthUserVerify request) { throw new NotImplementedException(); } From 3460ce6b04478d5212718c0fc7cd1a20aeb9a5ad Mon Sep 17 00:00:00 2001 From: Cody Larkin Date: Sun, 3 May 2026 18:04:40 -0400 Subject: [PATCH 3/3] need server and core webapp to work at same time for testing purposes --- RelayCore/Endpoints/AuthEndpoints.cs | 13 +++++++++---- RelayCore/Program.cs | 1 + RelayCore/RelayCore.csproj | 4 ++++ RelayServer/Program.cs | 1 + 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/RelayCore/Endpoints/AuthEndpoints.cs b/RelayCore/Endpoints/AuthEndpoints.cs index debada4..6e35234 100644 --- a/RelayCore/Endpoints/AuthEndpoints.cs +++ b/RelayCore/Endpoints/AuthEndpoints.cs @@ -6,16 +6,21 @@ public static class AuthEndpoints { public static void MapAuthEndpoints(this WebApplication app) { - app.MapPost("/user/signin", async (AuthSignin request, APIAuthService service) => + app.MapPost("/user/signin", async (AuthSignin request, APIAuthService service, HttpContext context) => { - var token = await service.UserSigninAsync(request); + var ip = context.Connection.RemoteIpAddress?.MapToIPv4().ToString(); + context.Request.Headers.TryGetValue("User-Agent", out var userAgent); - return token != null ? Results.Ok(token) : Results.Unauthorized(); + Console.WriteLine($"IP:{ip}\nUserAgent:{userAgent}"); + // var token = await service.UserSigninAsync(request, ip, userAgent); + + // return token != null ? Results.Ok(token) : Results.Unauthorized(); + return Results.Ok(); }); app.MapPost("/user/register", async (AuthRegister request, APIAuthService service) => { var token = await service.UserRegisterAsync(request); - return token != null ? Results.Ok(token) : Results.Unauthorized(); + return token != null ? Results.Ok(token) : Results.Unauthorized(); }); app.MapPost("/server/verify/user", async (AuthUserVerify request, APIAuthService service) => { diff --git a/RelayCore/Program.cs b/RelayCore/Program.cs index 44d0bed..0b65ebc 100644 --- a/RelayCore/Program.cs +++ b/RelayCore/Program.cs @@ -25,6 +25,7 @@ Console.WriteLine($"Kira created: {ToJsonString(kira)}"); Console.WriteLine($"Test created: {ToJsonString(test)}"); var builder = WebApplication.CreateBuilder(args); +builder.WebHost.UseUrls("http://127.0.0.1:1337/"); builder.Services.AddSingleton(db); builder.Services.AddScoped(); diff --git a/RelayCore/RelayCore.csproj b/RelayCore/RelayCore.csproj index 3b7c5c1..56b48d9 100644 --- a/RelayCore/RelayCore.csproj +++ b/RelayCore/RelayCore.csproj @@ -14,4 +14,8 @@ + + + + diff --git a/RelayServer/Program.cs b/RelayServer/Program.cs index 24da678..02e5358 100644 --- a/RelayServer/Program.cs +++ b/RelayServer/Program.cs @@ -21,6 +21,7 @@ var bootstrapService = new ServerBootstrapService(db, coreClient, cryptoService) await bootstrapService.InitializeAsync(); var builder = WebApplication.CreateBuilder(args); +builder.WebHost.UseUrls("http://127.0.0.1:5000/"); builder.Services.AddSingleton(db); builder.Services.AddScoped();