using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; using BubbleSocketCore.Library; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Microsoft.IdentityModel.Tokens; namespace BubbleSocketCore.Controllers { [ApiController] [Route("jwt")] [Produces("application/json")] public class JwtAuthController : ControllerBase { private readonly ILogger Logger; private readonly IConfiguration Configuration; private readonly SHA256HashGenerator sha256HashGenerator; private readonly JsonFileManager JsonFileManager; public JwtAuthController(ILogger logger, IConfiguration configuration) { Logger = logger; Configuration = configuration; sha256HashGenerator = SHA256HashGenerator.GetInstance(); JsonFileManager = new JsonFileManager(configuration); } [HttpPost] [Route("login")] public IActionResult Login([FromBody] LoginModel model) { if (!DoesPasswordMatch(model.Username, model.Password)) { return Unauthorized(); } var authClaims = new List { new Claim(ClaimTypes.Name, model.Username), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), }; var authSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtSettings:SecretKey"])); var token = new JwtSecurityToken( issuer: Configuration["JwtSettings:Issuer"], audience: Configuration["JwtSettings:Audience"], expires: DateTime.Now.AddHours(Configuration.GetValue("JwtSettings:ExpirationInHours")), claims: authClaims, signingCredentials: new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256) ); Logger.LogInformation($"User '{model.Username}' logged in."); return Ok(new { token = new JwtSecurityTokenHandler().WriteToken(token), expiration = token.ValidTo }); } private bool DoesPasswordMatch(string username, string password) { if (!JsonFileManager.DoesAccountAlreadyExist(username)) { return false; } var accountInfo = JsonFileManager.ReadAccountFile(username); var hashedPassword = accountInfo.GetProperty("Password").GetString(); var inputPasswordHashed = sha256HashGenerator.Get(password + Configuration.GetValue("ServerSalt")); return hashedPassword.Equals(inputPasswordHashed); } [HttpPost] [Route("register")] public IActionResult Register([FromBody] RegisterModel model) { if (JsonFileManager.DoesAccountAlreadyExist(model.Username)) { dynamic errorObject = new { errorCode = StatusCodes.Status409Conflict, errorMessage = "409 Error: That user is already registered.", username = model.Username }; return StatusCode(errorObject.errorCode, errorObject); } var data = new { Username = model.Username, Password = sha256HashGenerator.Get(model.Password + Configuration.GetValue("ServerSalt")), Email = model.Email, AccountId = Guid.NewGuid().ToString() }; JsonFileManager.WriteAccountFile(model.Username, data); Logger.LogInformation($"User '{model.Username}' registered."); return Ok("Account Created"); } public class LoginModel { public LoginModel() { } public LoginModel(string username, string password) { Username = username; Password = password; } public string Username { get; set; } public string Password { get; set; } } public class RegisterModel { public RegisterModel() { } public RegisterModel(string username, string password, string email) { Username = username; Password = password; Email = email; } public string Username { get; set; } public string Password { get; set; } public string Email { get; set; } } } }