using Microsoft.AspNetCore.Authorization; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using System.Linq; using System.Security.Claims; using System.Text; using UnivateProperties_API.Containers; using UnivateProperties_API.Containers.Users; using UnivateProperties_API.Context; using UnivateProperties_API.Helpers; using UnivateProperties_API.Model.Users; namespace UnivateProperties_API.Repository.Users { public class RegisterRepository : IRegisterRepository { private readonly DataContext _dbContext; private readonly AppSettings _appSettings; public RegisterRepository(DataContext dbContext, IOptions appSettings) { _dbContext = dbContext; _appSettings = appSettings.Value; } public User Authenticate(string username, string password) { if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password)) return null; var user = _dbContext.Users.SingleOrDefault(x => x.Username == username); // check if username exists if (user == null) return null; // check if password is correct if (!VerifyPasswordHash(password, user.PasswordHash, user.PasswordSalt)) return null; // authentication successful return user; } public User Create(User user, string password, bool save) { // validation if (string.IsNullOrWhiteSpace(password)) throw new AppException("Password is required"); if (_dbContext.Users.Any(x => x.Username == user.Username)) throw new AppException("Username \"" + user.Username + "\" is already taken"); byte[] passwordHash, passwordSalt; CreatePasswordHash(password, out passwordHash, out passwordSalt); user.PasswordHash = passwordHash; user.PasswordSalt = passwordSalt; _dbContext.Users.Add(user); if (save) { _dbContext.SaveChanges(); } return user; } public Agency CreateAgency(AgencyDto agency) { // validation if (string.IsNullOrWhiteSpace(agency.EaabeffcNumber)) throw new AppException("eaabeffcNumber is required"); if (_dbContext.Agencies.Any(x => x.EAABEFFCNumber == agency.EaabeffcNumber)) throw new AppException("eaabeffcNumber \"" + agency.EaabeffcNumber + "\" already exists"); Agency a = new Agency() { AgencyName = agency.Name, EAABEFFCNumber = agency.EaabeffcNumber, CompanyRegNumber = agency.RegNo }; _dbContext.Agencies.Add(a); CreatePerson(agency.User, PersonType.Agent, false, a); _dbContext.SaveChanges(); return a; } public void CreatePerson(UserDto individual, PersonType personType, bool save, Agency agency) { // validation if (string.IsNullOrWhiteSpace(individual.Password)) throw new AppException("Password is required"); if (_dbContext.Users.Any(x => x.Username == individual.Username)) throw new AppException("Individual \"" + individual.Username + "\" is already taken"); byte[] passwordHash, passwordSalt; CreatePasswordHash(individual.Password, out passwordHash, out passwordSalt); User createUser = new User() { Username = individual.Username, PasswordHash = passwordHash, PasswordSalt = passwordSalt }; Create(createUser, individual.Password, save); Person person = new Person() { }; if (personType == PersonType.Agent) { Agent agent = new Agent() { Name = individual.Name, Surname = individual.Surname, User = createUser, Email = individual.Email, CellNumber = individual.CellNumber, Telephone = individual.Telephone, Agency = agency }; _dbContext.Agents.Add(agent); } else if (personType == PersonType.Individual) { Individual i = new Individual() { Name = individual.Name, Surname = individual.Surname, User = createUser, Email = individual.Email, CellNumber = individual.CellNumber, Telephone = individual.Telephone }; _dbContext.Individuals.Add(i); } if (save) { Save(); } } public void UpdatePerson(Person person, PersonType personType) { if (personType == PersonType.Agent) { var item = (person as Agent); _dbContext.Entry(item).State = EntityState.Modified; Save(); } else if (personType == PersonType.Individual) { var item = (person as Individual); _dbContext.Entry(item).State = EntityState.Modified; Save(); } } public void Update(User userParam, string password = null) { var user = _dbContext.Users.Find(userParam.Id); if (user == null) throw new AppException("User not found"); if (userParam.Username != user.Username) { // username has changed so check if the new username is already taken if (_dbContext.Users.Any(x => x.Username == userParam.Username)) throw new AppException("Username " + userParam.Username + " is already taken"); } // update user properties user.Name = userParam.Name; user.Surname = userParam.Surname; user.Username = userParam.Username; // update password if it was entered if (!string.IsNullOrWhiteSpace(password)) { byte[] passwordHash, passwordSalt; CreatePasswordHash(password, out passwordHash, out passwordSalt); user.PasswordHash = passwordHash; user.PasswordSalt = passwordSalt; } _dbContext.Users.Update(user); _dbContext.SaveChanges(); } public void UpdateAgency(Agency agencyParam, string agencyname = null) { var agency = _dbContext.Agencies.Find(agencyParam.Id); if (agency == null) throw new AppException("Agency not found"); if (agencyParam.AgencyName != agency.AgencyName) { // username has changed so check if the new username is already taken if (_dbContext.Agencies.Any(x => x.AgencyName == agencyParam.AgencyName)) throw new AppException("AgencyName " + agencyParam.AgencyName + " is already taken"); } // update user properties agency.AgencyName = agencyParam.AgencyName; agency.EAABEFFCNumber = agencyParam.EAABEFFCNumber; agency.CompanyRegNumber = agencyParam.CompanyRegNumber; // update password if it was entered _dbContext.Agencies.Update(agency); _dbContext.SaveChanges(); } [Authorize(Roles = Role.SuperAdmin)] public IEnumerable GetAllUsers() { return _dbContext.Users; } [Authorize(Roles = Role.SuperAdmin)] public IEnumerable GetAllAgencies() { return _dbContext.Agencies; } [Authorize(Roles = Role.SuperAdmin)] public IEnumerable GetAllIndividuals() { return _dbContext.Individuals; } public User GetById(int id) { return _dbContext.Users.Find(id); } public Agency GetByAgencyId(int id) { return _dbContext.Agencies.Find(id); } public Individual GetByIndividualId(int id) { return _dbContext.Individuals.Find(id); } public void Delete(int id) { var user = _dbContext.Users.Find(id); if (user != null) { _dbContext.Users.Remove(user); _dbContext.SaveChanges(); } } public void DeleteAgency(int id) { var agency = _dbContext.Agencies.Find(id); if (agency != null) { _dbContext.Remove(agency); _dbContext.SaveChanges(); } } public void DeleteIndividual(int id) { var individual = _dbContext.Individuals.Find(id); if (individual != null) { _dbContext.Individuals.Remove(individual); _dbContext.SaveChanges(); } } private void Save() { _dbContext.SaveChanges(); } private static void CreatePasswordHash(string password, out byte[] passwordHash, out byte[] passwordSalt) { if (password == null) throw new ArgumentNullException("password"); if (string.IsNullOrWhiteSpace(password)) throw new ArgumentException("Value cannot be empty or whitespace only string.", "password"); using (var hmac = new System.Security.Cryptography.HMACSHA512()) { passwordSalt = hmac.Key; passwordHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password)); } } private static bool VerifyPasswordHash(string password, byte[] storedHash, byte[] storedSalt) { if (password == null) throw new ArgumentNullException("password"); if (string.IsNullOrWhiteSpace(password)) throw new ArgumentException("Value cannot be empty or whitespace only string.", "password"); if (storedHash.Length != 64) throw new ArgumentException("Invalid length of password hash (64 bytes expected).", "passwordHash"); if (storedSalt.Length != 128) throw new ArgumentException("Invalid length of password salt (128 bytes expected).", "passwordHash"); using (var hmac = new System.Security.Cryptography.HMACSHA512(storedSalt)) { var computedHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password)); for (int i = 0; i < computedHash.Length; i++) { if (computedHash[i] != storedHash[i]) return false; } } return true; } } }