using DeluxeBackend.Models; using Microsoft.IdentityModel.Tokens; using System.IdentityModel.Tokens.Jwt; using System.Numerics; using System.Security.Claims; using static DeluxeBackend.Enums; namespace DeluxeBackend.Services { public class LoginWithInfoResult { public required Account Account { get; set; } public PlatformType Platform { get; set; } public required string PlatformId { get; set; } public DeviceClassType DeviceClass { get; set; } public required string Locale { get; set; } public required string AppVersion { get; set; } } public interface IJwtService { Task GenAccessToken(Account account, List roles, Dictionary? customeClaims = null); Task GenRefreshToken(Account acc); Task GetLogin(ClaimsPrincipal? User); Task GetLoginWithInfo(ClaimsPrincipal? User); } public class JwtService : IJwtService { private readonly ILiteDbService db; private readonly IConfiguration configuration; private readonly DiscordBotService discord; public JwtService(ILiteDbService _db, IConfiguration _configuration, DiscordBotService _discord) { db = _db; configuration = _configuration; discord = _discord; } public async Task GenAccessToken(Account account, List roles, Dictionary? customeClaims = null) { var issuer = configuration["JwtConfig:Issuer"]; var key = new SymmetricSecurityKey(Convert.FromBase64String(configuration["JwtConfig:Key"])); var exp = DateTime.UtcNow.AddHours(1).AddMinutes(10); roles.AddRange(account.Roles); if (account.DiscordId.HasValue) { roles.AddRange(await discord.UserRoles(account.DiscordId.Value)); } if (account.IsJunior == null || account.IsJunior == true) { roles.Add("junior"); } roles = roles.Distinct().ToList(); var claimsDictionary = new Dictionary { ["role"] = roles }; if (customeClaims != null) { foreach (var claim in customeClaims) { claimsDictionary[claim.Key] = claim.Value; } } var tokenDect = new SecurityTokenDescriptor { Subject = new ClaimsIdentity( [ new Claim("sub", account.Id.ToString()) ]), IssuedAt = DateTime.UtcNow, Claims = claimsDictionary, Expires = exp, Issuer = issuer, SigningCredentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256Signature), }; var tokenHandler = new JwtSecurityTokenHandler(); var token = tokenHandler.WriteToken(tokenHandler.CreateToken(tokenDect)); return token; } public Task GenRefreshToken(Account acc) { RefreshToken refreshToken = new() { Token = Convert.ToBase64String(Guid.NewGuid().ToByteArray()), Expires = DateTime.UtcNow.AddDays(2), Account = acc }; db.RefreshTokens.Insert(refreshToken); return Task.FromResult(refreshToken.Token); } public Task GetLogin(ClaimsPrincipal? User = null) { Console.WriteLine(User); if (User == null) return Task.FromResult(null); string? rawPlayerId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? User.FindFirst("sub")?.Value; if (string.IsNullOrEmpty(rawPlayerId)) return Task.FromResult(null); if (!long.TryParse(rawPlayerId, out long playerId)) return Task.FromResult(null); Account? player = db.Accounts.FindById(playerId); return Task.FromResult(player); } public Task GetLoginWithInfo(ClaimsPrincipal? User = null) { if (User == null) return Task.FromResult(null); string? rawPlayerId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? User.FindFirst("sub")?.Value; if (string.IsNullOrEmpty(rawPlayerId) || !long.TryParse(rawPlayerId, out long playerId)) return Task.FromResult(null); Account? player = db.Accounts.FindById(playerId); if (player == null) return Task.FromResult(null); var result = new LoginWithInfoResult { Account = player, PlatformId = User.FindFirst("db.platform.id")?.Value, Locale = User.FindFirst("db.locale")?.Value, AppVersion= User.FindFirst("db.appver")?.Value, }; string? rawPlatform = User.FindFirst("db.platform")?.Value; if (Enum.TryParse(rawPlatform, out var platform)) { result.Platform = platform; } string? rawDeviceClass = User.FindFirst("db.deviceclass")?.Value; if (Enum.TryParse(rawDeviceClass, out var deviceClass)) { result.DeviceClass = deviceClass; } return Task.FromResult(result); } } }