aboutsummaryrefslogtreecommitdiff
path: root/src/DevHive.Services/Services/UserService.cs
blob: 24f74f5601742f0a1ae944e21e999fed37d480c7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
using AutoMapper;
using DevHive.Data.Repositories;
using DevHive.Services.Options;
using DevHive.Services.Models.Identity.User;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using DevHive.Data.Models;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.IdentityModel.Tokens;
using System.Security.Cryptography;
using System.Text;
using System.Collections.Generic;

namespace DevHive.Services.Services
{
	public class UserService
	{
		private readonly UserRepository _userRepository;
		private readonly IMapper _userMapper;
		private readonly JWTOptions _jwtOptions;

		public UserService(DevHiveContext context, IMapper mapper, JWTOptions jwtOptions)
		{
			this._userRepository = new UserRepository(context);
			this._userMapper = mapper;
			this._jwtOptions = jwtOptions;
		}

		public async Task<TokenServiceModel> LoginUser(LoginServiceModel loginModel)
		{
			if (!await this._userRepository.IsUsernameValid(loginModel.UserName))
				throw new ArgumentException("Invalid username!");

			User user = await this._userRepository.GetByUsername(loginModel.UserName);

			if (user.PasswordHash != GeneratePasswordHash(loginModel.Password))
				throw new ArgumentException("Incorrect password!");

			return new TokenServiceModel(WriteJWTSecurityToken(user.Role));
		}

		public async Task<TokenServiceModel> RegisterUser(RegisterServiceModel registerModel)
		{
			if (await this._userRepository.DoesUsernameExist(registerModel.UserName))
				throw new ArgumentException("Username already exists!");

			if (await this._userRepository.DoesEmailExist(registerModel.Email))
				throw new ArgumentException("Email already exists!");

			User user = this._userMapper.Map<User>(registerModel);
			user.Role = Role.DefaultRole;
			user.PasswordHash = GeneratePasswordHash(registerModel.Password);

			await this._userRepository.AddAsync(user);

			return new TokenServiceModel(WriteJWTSecurityToken(user.Role));
		}

		public async Task<UserServiceModel> GetUserById(Guid id)
		{
			User user = await this._userRepository.GetByIdAsync(id)
				?? throw new ArgumentException("User does not exist!");

			return this._userMapper.Map<UserServiceModel>(user);
		}

		public async Task<UserServiceModel> UpdateUser(UpdateUserServiceModel updateModel)
		{
			if (!this._userRepository.DoesUserExist(updateModel.Id))
				throw new ArgumentException("User does not exist!");

			if (!this._userRepository.DoesUserHaveThisUsername(updateModel.Id, updateModel.UserName)
					&& await this._userRepository.IsUsernameValid(updateModel.UserName))
				throw new ArgumentException("Username already exists!");

			User user = this._userMapper.Map<User>(updateModel);
			await this._userRepository.EditAsync(user);

			return this._userMapper.Map<UserServiceModel>(user);;
		}

		public async Task DeleteUser(Guid id)
		{
			if (!this._userRepository.DoesUserExist(id))
				throw new ArgumentException("User does not exist!");

			User user = await this._userRepository.GetByIdAsync(id);
			await this._userRepository.DeleteAsync(user);
		}

		private string GeneratePasswordHash(string password)
		{
			return string.Join(string.Empty, SHA512.HashData(Encoding.ASCII.GetBytes(password)));
		}

		private string WriteJWTSecurityToken(string role)
		{
			//TODO: Try generating the key
			byte[] signingKey = Encoding.ASCII.GetBytes(_jwtOptions.Secret);

			List<Claim> claims = new List<Claim>()
			{
				new Claim(ClaimTypes.Role, role)
			};

			SecurityTokenDescriptor tokenDescriptor = new()
			{
				Subject = new ClaimsIdentity(claims),
				Expires = DateTime.Today.AddDays(7),
				SigningCredentials = new SigningCredentials(
					new SymmetricSecurityKey(signingKey),
					SecurityAlgorithms.HmacSha512Signature)
			};

			JwtSecurityTokenHandler tokenHandler = new();
			SecurityToken token = tokenHandler.CreateToken(tokenDescriptor);
			return tokenHandler.WriteToken(token);
		}
	}
}