using System; using System.Collections.Generic; using System.Linq; using Backend.Entitys; using Backend.LogicResults; using Backend.Options; using Backend.Repositorys; using Backend.Security; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Options; namespace Backend.Logic; public class UserLogic { private UserRepository _users; private TokenRepository _tokens; private GroupRepository _groups; private UserMessageOptions _messages; private IHttpContextAccessor _contextAccessor; private ITokenContext _context; public UserLogic( UserRepository users, TokenRepository tokens, GroupRepository groups, IOptions messages, IHttpContextAccessor contextAccessor, ITokenContext context) { _users = users; _tokens = tokens; _groups = groups; _messages = messages.Value; _contextAccessor = contextAccessor; _context = context; } public ILogicResult> GetUsers() { var users = _users.GetUsers() .Select(user => new User { Id = user.Id, Created = user.Created, Email = user.Email, FirstName = user.FirstName, LastName = user.LastName, Username = user.Username }); return LogicResult>.Ok(users); } public ILogicResult GetUser(Guid userId) { var user = _users.GetUser(userId); if (user is null) return LogicResult.NotFound(_messages.NotFound); return LogicResult.Ok(new User { Id = user.Id, Created = user.Created, Email = user.Email, FirstName = user.FirstName, LastName = user.LastName, Username = user.Username }); } public ILogicResult EditUser(Guid userId, UserEditor editor) { if (!ValidateEdit(editor)) return LogicResult.BadRequest(_messages.InvalidEditData); if (_users.GetUser(userId) is null) return LogicResult.NotFound(_messages.NotFound); _users.EditUser(userId, editor); return LogicResult.Ok(); } public ILogicResult DeleteUser(Guid userId) { if (_users.GetUser(userId) is null) return LogicResult.NotFound(_messages.NotFound); _tokens.DeleteUserTokens(userId); _users.DeleteUser(userId); return LogicResult.Ok(); } public ILogicResult> GetPermissions(Guid userId) { if (_users.GetUser(userId) is null) return LogicResult>.NotFound(_messages.NotFound); return LogicResult>.Ok(_groups.GetUserPermissions(userId).Select(perm => perm.PermissionKey)); } public ILogicResult> GetPermissionsRaw(Guid userId) { if (_users.GetUser(userId) is null) return LogicResult>.NotFound(_messages.NotFound); return LogicResult>.Ok(_groups.GetUserPermissionsRaw(userId).Select(perm => perm.PermissionKey)); } public ILogicResult AddPermissions(Guid userId, params string[] permissions) { if (_users.GetUser(userId) is null) return LogicResult.NotFound(_messages.NotFound); _groups.AddPermissions(userId, permissions); return LogicResult.Ok(); } public ILogicResult DeletePermissions(Guid userId, params string[] permissions) { if (_users.GetUser(userId) is null) return LogicResult.NotFound(_messages.NotFound); _groups.DeletePermissions(userId, permissions); return LogicResult.Ok(); } public ILogicResult Login(UserLogin login) { var user = _users.GetUsers().SingleOrDefault(user => user.Username == login.UsernameOrEmail || user.Email == login.UsernameOrEmail); if (user is null) return LogicResult.NotFound(_messages.NotFound); if (user.Password != TokenRepository.Hash128(login.Password, user.Email)) return LogicResult.BadRequest(_messages.WrongPassword); _tokens.DeleteUserTokens(user.Id); var refreshToken = _tokens.CreateRefreshToken(user.Id); var accessToken = _tokens.CreateAccessToken(refreshToken.Id); SetRefreshToken(refreshToken); return LogicResult.Ok(accessToken); } public ILogicResult Register(UserEditor editor) { var users = _users.GetUsers(); if (users.Any(user => user.Email == editor.Email || user.Username == editor.Username)) return LogicResult.Conflict(_messages.UsernameOrEmailExist); if (!ValidateUserdata(editor)) return LogicResult.BadRequest(_messages.InvalidRegisterData); var user = _users.CreateUser(editor); var refreshToken = _tokens.CreateRefreshToken(user.Id); var accessToken = _tokens.CreateAccessToken(refreshToken.Id); SetRefreshToken(refreshToken); return LogicResult.Ok(accessToken); } public ILogicResult Logout(Guid userId) { if (_users.GetUser(userId) is null) return LogicResult.NotFound(_messages.NotFound); _tokens.DeleteUserTokens(userId); if (_context.UserId == userId) DeleteRefreshToken(); return LogicResult.Ok(); } public ILogicResult GenerateToken(Guid refreshTokenId) { if (!_tokens.ValidateRefreshToken(refreshTokenId)) return LogicResult.Conflict(_messages.InvalidRefreshToken); var token = _tokens.GetAccessTokens(refreshTokenId).ToArray().FirstOrDefault(token => _tokens.ValidateAccessToken(token.Id)); if (token is not null) return LogicResult.Ok(token); return LogicResult.Ok(_tokens.CreateAccessToken(refreshTokenId)); } public Guid GetCurrentUserRefreshToken() { var token = _contextAccessor.HttpContext?.Request.Cookies["refresh_token"]; if (token == null) return Guid.Empty; return Guid.Parse(token); } private bool ValidateUserdata(UserEditor editor) { if (string.IsNullOrEmpty(editor.FirstName)) return false; if (string.IsNullOrEmpty(editor.LastName)) return false; if (string.IsNullOrEmpty(editor.Email)) return false; if (string.IsNullOrEmpty(editor.Username)) return false; if (string.IsNullOrEmpty(editor.Password)) return false; if (editor.FirstName.Length > 255) return false; if (editor.LastName.Length > 255) return false; if (editor.Email.Length > 255) return false; if (editor.Username.Length > 255) return false; if (editor.Password.Length > 255) return false; if (!editor.Email.Contains('@') || !editor.Email.Contains('.')) return false; if (editor.Username.Contains('@')) return false; if (editor.Password.Length < 8) return false; return true; } private bool ValidateEdit(UserEditor editor) { if (editor.FirstName?.Length > 255) return false; if (editor.LastName?.Length > 255) return false; if (editor.Email?.Length > 255) return false; if (editor.Username?.Length > 255) return false; if (editor.Password?.Length > 255) return false; if (!string.IsNullOrEmpty(editor.Email)) { if (!editor.Email.Contains('@') || !editor.Email.Contains('.')) return false; } if (!string.IsNullOrEmpty(editor.Username)) { if (editor.Username.Contains('@')) return false; } if (!string.IsNullOrEmpty(editor.Password)) { if (editor.Password.Length < 8) return false; } return true; } private void DeleteRefreshToken() { _contextAccessor.HttpContext?.Response.Cookies.Delete("refresh_token"); } private void SetRefreshToken(RefreshToken token) { _contextAccessor.HttpContext?.Response.Cookies.Append("refresh_token", token.Id.ToString(), new CookieOptions { MaxAge = token.ExpirationDate - DateTime.Now, HttpOnly = true, Secure = true }); } }