diff --git a/RelayCore/Endpoints/AuthEndpoints.cs b/RelayCore/Endpoints/AuthEndpoints.cs new file mode 100644 index 0000000..6e35234 --- /dev/null +++ b/RelayCore/Endpoints/AuthEndpoints.cs @@ -0,0 +1,59 @@ +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, HttpContext context) => + { + var ip = context.Connection.RemoteIpAddress?.MapToIPv4().ToString(); + context.Request.Headers.TryGetValue("User-Agent", out var userAgent); + + 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(); + }); + app.MapPost("/server/verify/user", async (AuthUserVerify request, APIAuthService service) => + { + bool valid = await service.ServerVerifyUser(request); + return Results.Ok(valid); + }); + 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/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 d7a0e2d..0b65ebc 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,25 @@ 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.WebHost.UseUrls("http://127.0.0.1:1337/"); +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) @@ -51,7 +67,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); @@ -65,7 +81,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..56b48d9 100644 --- a/RelayCore/RelayCore.csproj +++ b/RelayCore/RelayCore.csproj @@ -1,4 +1,4 @@ - + Exe @@ -10,11 +10,12 @@ + - + diff --git a/RelayCore/Services/APIAuthService.cs b/RelayCore/Services/APIAuthService.cs new file mode 100644 index 0000000..e271ff5 --- /dev/null +++ b/RelayCore/Services/APIAuthService.cs @@ -0,0 +1,49 @@ +using RelayCore.Endpoints; +using RelayCore.Models; +using SurrealDb.Net; +using SurrealDb.Net.Models; + +namespace RelayCore.Services; + +public class APIAuthService(SurrealDbClient _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 UserRegisterAsync(AuthRegister request) + { + throw new NotImplementedException(); + } + + public async Task ServerVerifyUser(AuthUserVerify request) + { + throw new NotImplementedException(); + } +} \ No newline at end of file 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();