using System.IdentityModel.Tokens; using System.IdentityModel.Tokens.Jwt; using System.Linq; using System.Security.Claims; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.IdentityModel.Tokens; using Newtonsoft.Json; using TextSender_API.Models; using TextSender_API.Repositories; namespace TextSender_API.Controllers; [ApiController] [Route("api/v1/user")] public class UsersController : ControllerBase { #region Fields private readonly ILogger _logger; private IConfiguration _config; #endregion #region Constructors public UsersController(ILogger logger, IConfiguration config) { this._logger = logger; this._config = config; } #endregion #region Methods private string AllScopes() { var allScopes = new List() { "create:contact" }; var scopes = string.Empty; for (var i = 0; i < allScopes.Count; i++) { if (i == allScopes.Count - 1) { scopes += allScopes[i]; } else { scopes += allScopes[i] + " "; } } return scopes; } private List Payload() { var expLimit = 30; var currentDate = DateTime.Now; var expiredDate = currentDate.AddMinutes(expLimit); var issued = Math.Floor((currentDate - DateTime.UnixEpoch).TotalSeconds); var expires = Math.Floor((expiredDate - DateTime.UnixEpoch).TotalSeconds); var issuer = this._config["JWT:Issuer"]; var audience = this._config["JWT:Audience"]; var subject = this._config["JWT:Subject"]; var claim = new List() { new System.Security.Claims.Claim("scope", AllScopes(), "string"), new System.Security.Claims.Claim(JwtRegisteredClaimNames.Exp, expiredDate.ToString(), "string"), new System.Security.Claims.Claim(JwtRegisteredClaimNames.Aud, audience!), new System.Security.Claims.Claim(JwtRegisteredClaimNames.Iss, issuer!), new Claim(JwtRegisteredClaimNames.Sub, subject!) }; return claim; } [HttpPost("login")] public IActionResult Login([FromBody] User userRequest) { var response = new LoginResponse(); try { var connString = this._config.GetConnectionString("MongoDBURI"); var userRepo = new UsersRepository(connString!); var saltRepo = new SaltRepository(connString!); var pwdVerify = new PasswordVerification(userRepo, saltRepo); var result = userRepo.Exists(userRequest); if (result.Item1 && pwdVerify.VerifyPassword(result.Item2, userRequest.Password!)) { var user = result.Item2; var token = new Token(); token.Issued = DateTime.Now; token.UserId = user.Id; token.TokenType = "JWT"; var payload = Payload(); payload.Add(new System.Security.Claims.Claim("user_id", user.Id!, ClaimValueTypes.String)); var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(this._config["JWT:Secret"]!)); var signIn = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var tok = new JwtSecurityToken( this._config["JWT:Issuer"], this._config["JWT:Audience"], payload, expires: DateTime.UtcNow.AddMinutes(30), signingCredentials: signIn); token.AccessToken = new JwtSecurityTokenHandler().WriteToken(tok); var expClaim = payload.FirstOrDefault(cl => { return cl.Type.Equals("exp"); }); if (expClaim != null) { var expiredDate = DateTime.Parse(expClaim!.Value); var exp = Math.Floor((expiredDate - DateTime.UnixEpoch).TotalSeconds); } response.Data.Add(token); Ok(response); } else { return NotFound(response); } } catch (Exception ex) { this._logger.LogError($"An error occurred: {ex.Message}"); } return Ok(response); } [HttpPost("register"), DisableRequestSizeLimit] public IActionResult Upload([FromBody] User userRequest) { var response = new RegisterUserResponse(); try { var connString = this._config.GetConnectionString("MongoDBURI"); var userRepo = new UsersRepository(connString!); var saltRepo = new SaltRepository(connString!); var allUsers = userRepo.RetrieveAllUsers(); var result = allUsers.Exists(ea => ea.Username!.Equals(userRequest.Username)); if (!result) { var pwdVerify = new PasswordVerification(userRepo, saltRepo); var salt = pwdVerify.CreateSalt(userRequest); var hashedPassword = pwdVerify.HashPassword(userRequest, salt); this._logger.LogInformation("Creating user"); userRequest.Password = hashedPassword; userRequest.DateCreated = DateTime.Now; userRepo.CreateUser(userRequest); response.Data.Add(userRequest); salt.UserId = userRequest.Id; saltRepo.Create(salt); } else { this._logger.LogInformation("User already exists"); } } catch (Exception ex) { this._logger.LogError($"An error occurred: {ex.Message}"); } return Ok(response); } #endregion #region Responses public class LoginResponse { #region Properties [JsonProperty("data")] public List Data { get; set; } #endregion #region Constructors public LoginResponse() { this.Data = new List(); } #endregion #region Methods #endregion } public class RegisterUserResponse { #region Properties [JsonProperty("data")] public List Data { get; set; } #endregion #region Constructors public RegisterUserResponse() { this.Data = new List(); } #endregion #region Methods #endregion } #endregion }