using DysonNetwork.Shared.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.EntityFrameworkCore; using DysonNetwork.Pass.Auth; using DysonNetwork.Pass.Account; namespace DysonNetwork.Sphere.Pages.Auth; public class SelectFactorModel( DysonNetwork.Shared.Services.IAccountService accounts ) : PageModel { [BindProperty(SupportsGet = true)] public Guid Id { get; set; } [BindProperty(SupportsGet = true)] public string? ReturnUrl { get; set; } [BindProperty] public Guid SelectedFactorId { get; set; } [BindProperty] public string? Hint { get; set; } public Challenge? AuthChallenge { get; set; } public List AuthFactors { get; set; } = []; public async Task OnGetAsync() { await LoadChallengeAndFactors(); if (AuthChallenge == null) return NotFound(); if (AuthChallenge.StepRemain == 0) return await ExchangeTokenAndRedirect(); return Page(); } public async Task OnPostSelectFactorAsync() { var challenge = await accounts.GetAuthChallenge(Id); if (challenge == null) return NotFound(); var factor = await accounts.GetAccountAuthFactor(SelectedFactorId, challenge.Account.Id); if (factor?.EnabledAt == null || factor.Trustworthy <= 0) return BadRequest("Invalid authentication method."); // Store return URL in TempData to pass to the next step if (!string.IsNullOrEmpty(ReturnUrl)) { TempData["ReturnUrl"] = ReturnUrl; } // For OTP factors that require code delivery try { // For OTP factors that require code delivery if ( factor.Type == AccountAuthFactorType.EmailCode && string.IsNullOrWhiteSpace(Hint) ) { ModelState.AddModelError(string.Empty, $"Please provide a {factor.Type.ToString().ToLower().Replace("code", "")} to send the code to." ); await LoadChallengeAndFactors(); return Page(); } await accounts.SendFactorCode(challenge.Account, factor, Hint); } catch (Exception ex) { ModelState.AddModelError(string.Empty, $"An error occurred while sending the verification code: {ex.Message}"); await LoadChallengeAndFactors(); return Page(); } // Redirect to verify page with return URL if available return !string.IsNullOrEmpty(ReturnUrl) ? RedirectToPage("VerifyFactor", new { id = Id, factorId = factor.Id, returnUrl = ReturnUrl }) : RedirectToPage("VerifyFactor", new { id = Id, factorId = factor.Id }); } private async Task LoadChallengeAndFactors() { AuthChallenge = await accounts.GetAuthChallenge(Id); if (AuthChallenge != null) { AuthFactors = await accounts.GetAccountAuthFactors(AuthChallenge.Account.Id); } } private async Task ExchangeTokenAndRedirect() { // This method is kept for backward compatibility // The actual token exchange is now handled in the VerifyFactor page await Task.CompletedTask; // Add this to fix the async warning return RedirectToPage("/Account/Profile"); } }