using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using eprintServer.Data; using eprintServer.Requests; using eprintServer.Responses; using eprintServer.Entities; using eprintServer.Services; using eprintServer.Enums; using eprintServer.DTOs; using System.Security.Claims; namespace eprintServer.Controllers; [ApiController] [Route("api/[controller]")] [AllowAnonymous] public class AuthController : ControllerBase { private readonly DataContext _context; private readonly UserService _userService; private readonly TokenService _tokenService; private readonly GoogleOAuthService _googleOAuthService; private readonly FacebookOAuthService _facebookOAuthService; private readonly InstagramOAuthService _instagramOAuthService; private readonly LinkedInOAuthService _linkedInOAuthService; public AuthController( UserService userService, TokenService tokenService, GoogleOAuthService googleOAuthService, FacebookOAuthService facebookOAuthService, InstagramOAuthService instagramOAuthService, LinkedInOAuthService linkedInOAuthService, DataContext context) { _userService = userService; _tokenService = tokenService; _googleOAuthService = googleOAuthService; _facebookOAuthService = facebookOAuthService; _instagramOAuthService = instagramOAuthService; _linkedInOAuthService = linkedInOAuthService; _context = context; } [HttpPost("signin")] public async Task> SignIn([FromBody] SignInRequest signInRequest) { var user = await _userService.FindByLoginIdentifierAsync(signInRequest.Username); if (user == null) { return BadRequest("Invalid username or password."); } if(signInRequest.Password != user.LastOtp){ if (!BCrypt.Net.BCrypt.Verify(signInRequest.Password, user.Password)) { return BadRequest("Wrong password."); } } bool isOtpMatch = !string.IsNullOrEmpty(user.LastOtp) && signInRequest.Password.Trim() == user.LastOtp.Trim(); if (!isOtpMatch) { if (!BCrypt.Net.BCrypt.Verify(signInRequest.Password, user.Password)) { return BadRequest("Wrong password."); } } if (!user.Active) { return Unauthorized("Your account is disabled."); } if (user.Deleted) { return StatusCode(StatusCodes.Status406NotAcceptable, "This user is deleted."); } var accessToken = _tokenService.CreateToken(user); var device = new UserDevice { DeviceType = signInRequest.DeviceType, DeviceId = signInRequest.DeviceId, Ip = signInRequest.Ip, LastJwt = accessToken, PushNotificationToken = signInRequest.Tokendevice }; user.Device = device; var updatedUser = await _userService.UpdateUserAsync(user); if (updatedUser.Device == null) { return StatusCode(StatusCodes.Status406NotAcceptable, "Failed to save device information."); } var response = new JwtResponse( accessToken, user.Role, updatedUser.Device.DeviceId, updatedUser.Device.DeviceType, updatedUser.Device.Ip, DateTime.UtcNow.AddDays(7) ); return Ok(response); } [HttpPost("signup_user")] [Authorize(Roles = "ADMIN")] public async Task> AddEmployee([FromBody] SignUpRequest request) { // 1. Validation Logic if (string.IsNullOrEmpty(request.Password) || string.IsNullOrEmpty(request.Email)) { return StatusCode(StatusCodes.Status406NotAcceptable, "Email and password can't be null or empty."); } if (await _userService.ExistByEmailAsync(request.Email.ToLower())) { return StatusCode(StatusCodes.Status406NotAcceptable, "Email already exists."); } if (!string.IsNullOrEmpty(request.PhoneNumber) && await _userService.ExistByPhoneNumberAsync(request.PhoneNumber)) { return StatusCode(StatusCodes.Status406NotAcceptable, "Phone number already exists."); } try { var userCount = await _userService.GetUserCountAsync(); var Username = _userService.GenerateUsername(request.Name, userCount); var newUser = new User { Name = request.Name, Email = request.Email, Username = Username, PhoneNumber = request.PhoneNumber, City = request.City, Country = request.Country, Password = request.Password, Active = true, }; var result = await _userService.SaveUserAsync(newUser); return Ok(result); } catch (Exception e) { return StatusCode(StatusCodes.Status500InternalServerError, $"An error occurred while saving: {e.Message}"); } } [HttpGet("get_ip")] public IActionResult GetClientIp() { string ip = string.Empty; var forwardedHeader = HttpContext.Request.Headers["X-Forwarded-For"]; if (!string.IsNullOrEmpty(forwardedHeader)) { ip = forwardedHeader.ToString().Split(',').FirstOrDefault()?.Trim(); } if (string.IsNullOrEmpty(ip)) { ip = HttpContext.Connection.RemoteIpAddress?.ToString(); } return Ok(ip ?? "IP Not Found"); } [HttpPatch("update_user_role")] public async Task> UpdateUserRole([FromQuery] int userId, [FromQuery] RoleEnum newRole) { var user = await _userService.FindByIdAsync(userId); if (user == null) { return NotFound($"User with ID {userId} not found."); } try { var updatedUser = await _userService.UpdateUserRoleAsync(user, newRole); return Ok(updatedUser); } catch (Exception ex) { return StatusCode(500, $"An error occurred while updating the role: {ex.Message}"); } } [HttpPost("logout")] [Authorize] // Requires authentication to logout public async Task Logout([FromBody] LogoutRequest logoutRequest) { try { // Get the username/email from the claims var userName = User.FindFirst(ClaimTypes.Name)?.Value ?? User.FindFirst("unique_name")?.Value; if (string.IsNullOrEmpty(userName)) { return Unauthorized("User not found in token."); } // Find user by username/email var currentUser = await _userService.FindByLoginIdentifierAsync(userName); if (currentUser == null) { return Unauthorized("User not found or not authenticated."); } // Extract device information from request var deviceId = logoutRequest.DeviceInfo?.DeviceId; var token = logoutRequest.Token; // Find and update the user's device information if (currentUser.Device != null && currentUser.Device.DeviceId == deviceId) { // Clear the JWT token for this device currentUser.Device.LastJwt = null; currentUser.Device.PushNotificationToken = null; // Update the user await _userService.UpdateUserAsync(currentUser); } else { // Log device mismatch (optional) Console.WriteLine($"Device mismatch for user {currentUser.Id}. DeviceId: {deviceId}"); } // Revoke the token if (!string.IsNullOrEmpty(token)) { await _tokenService.RevokeTokenAsync(token); } return Ok(new { message = "Logout successful", success = true }); } catch (Exception ex) { return StatusCode(500, new { message = "An error occurred during logout", error = ex.Message, success = false }); } } }