public async Task <WebStatus> AuthenticateLongCodeAsync(string longCode) { _logger.LogDebug("Begin long code (one time link) authentication"); var response = await _oneTimeCodeService.CheckOneTimeCodeAsync(longCode, _httpContext.Request.GetClientNonce()); switch (response.Status.StatusCode) { case CheckOneTimeCodeStatusCode.VerifiedWithoutNonce: case CheckOneTimeCodeStatusCode.VerifiedWithNonce: await _eventNotificationService.NotifyEventAsync(response.Result.SentTo, EventType.SignInSuccess, SignInType.LongCode.ToString()); var nonceWasValid = response.Status.StatusCode == CheckOneTimeCodeStatusCode.VerifiedWithNonce; return(await SignInAndRedirectAsync(SignInMethod.Link, response.Result.SentTo, null, response.Result.RedirectUrl, nonceWasValid)); case CheckOneTimeCodeStatusCode.Expired: await _eventNotificationService.NotifyEventAsync(response.Result.SentTo, EventType.SignInFail, SignInType.LongCode.ToString()); return(Unauthenticated(_localizer["The sign in link expired."])); case CheckOneTimeCodeStatusCode.CodeIncorrect: return(WebStatus.Error(_localizer["Not found."], HttpStatusCode.NotFound)); case CheckOneTimeCodeStatusCode.NotFound: return(Unauthenticated(_localizer["The sign in link is invalid."])); case CheckOneTimeCodeStatusCode.ServiceFailure: default: return(ServerError(_localizer["Something went wrong."])); } }
private void brsMain_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { WebStatus temp = FillHelper.GetPageStatus(brsMain); if (CurrentStatus != temp) { CurrentStatus = temp; WebStatusChange(this, null); } }
public async Task <WebStatus> SendPasswordResetMessageAsync(SendPasswordResetMessageInputModel model) { _logger.LogDebug("Begin send password reset message for {0}", model.Username); if (!ApplicationIdIsNullOrValid(model.ApplicationId)) { return(WebStatus.Error(_localizer["Invalid application id."], HttpStatusCode.BadRequest)); } var genericMessage = _localizer["Check your email for password reset instructions."]; var userResponse = await _userStore.GetUserByUsernameAsync(model.Username); if (userResponse.HasError) { _logger.LogInformation("User not found: {0}", model.Username); // if valid email or phone number, send a message inviting them to register if (model.Username.Contains("@")) { var status = await _messageService.SendAccountNotFoundMessageAsync(model.ApplicationId, model.Username); // NOTE: ignoring status, since it doesn't matter whether it succeeded or failed await _eventNotificationService.NotifyEventAsync(model.Username, EventType.AccountNotFound, nameof(SendPasswordResetMessageAsync)); } else { _logger.LogInformation("Account not found message was not sent because provided username is not an email address: {0}", model.Username); } return(WebStatus.Success(genericMessage)); } var user = userResponse.Result; var nextUrl = SendToSetPasswordFirst(!string.IsNullOrEmpty(model.NextUrl) ? model.NextUrl : _urlService.GetDefaultRedirectUrl()); var oneTimeCodeResponse = await _oneTimeCodeService.GetOneTimeCodeAsync( user.Email, TimeSpan.FromMinutes(_options.OneTimeCodeValidityMinutes), nextUrl); if (oneTimeCodeResponse.IsOk) { var status = await _messageService.SendPasswordResetMessageAsync(model.ApplicationId, user.Email, oneTimeCodeResponse.Result.ShortCode, oneTimeCodeResponse.Result.LongCode); await _eventNotificationService.NotifyEventAsync(user.Email, EventType.RequestPasswordReset); if (status.IsOk) { status = Status.Success(genericMessage); } SetNonce(oneTimeCodeResponse.Result.ClientNonce); return(new WebStatus(status)); } _logger.LogError("Password reset message was not sent due to error encountered while generating a one time link."); return(ServerError(_localizer["Hmm. Something went wrong. Please try again."])); }
public static JsonResult ToJsonResult(this WebStatus status) { return(new JsonResult(new { Message = status.Text, Messages = status.Messages, HasError = status.HasError, IsOK = status.IsOk }) { StatusCode = (int)status.StatusCode }); }
public static WebStatus CheckQueryAvailability() { WebStatus result = WebStatus.InternetAvailable; if (!NetworkConnection.IsInternetAvailable()) { result = WebStatus.NoInternet; } else if (NetworkConnection.IsInternetOnMeteredConnection()) { result = WebStatus.MeteredInternet; } return(result); }
public static WebStatus GetStatus(this ModelStateDictionary modelState, HttpStatusCode errorStatusCode = HttpStatusCode.BadRequest) { var status = new WebStatus(); foreach (var error in modelState.Values.SelectMany(modelStateEntry => modelStateEntry.Errors)) { status.AddError(error.ErrorMessage ?? "Internal Server Error"); // if an exception, don't leak the potentially sensitive details } if (status.HasError) { status.StatusCode = errorStatusCode; } return(status); }
private void DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { if (browser.ReadyState == WebBrowserReadyState.Complete) { string strCookie = browser.Document.Cookie; if (string.IsNullOrEmpty(strCookie)) { return; } if (browser.Url.ToString() == hostWithHead + webinfo.connectVerUrl) { if (currStatus == WebStatus.NoIn) { CookieContainer.SetCookies(new Uri(hostWithHead), strCookie); currStatus = WebStatus.InHost; browser.Navigate(loginPageUrl); return; } } string body = browser.Document.Body.OuterHtml; string key = webinfo.cookieKey; string keyval = null; HtmlTagClass htc = HtmlTagClass.getTagInfo(body, key); if (htc == null) { return; } cookieContainer.SetCookies(new Uri(hostWithHead), getCookie(htc.KeyValue, htc.AttValue, "/")); string[] arr = strCookie.Split(';'); for (int i = 0; i < arr.Length; i++) { string[] carr = arr[i].Split('='); CookieContainer.SetCookies(new Uri(hostWithHead), getCookie(carr[0], carr.Length == 1 ? "" : carr[1], "/")); } if (browser.Url.ToString() == loginPageUrl) { if (currStatus == WebStatus.InHost) { currStatus = WebStatus.InLogin; } } //Login(gc.ClientUserName, gc.ClientPassword, null); } }
private void InitializeProperties() { CurrentStatus = WebStatus.NotReady; cbbUriType.SelectedIndex = 0; BaseURI = NormalURI; lblUrlType.Text = "正常网址 |"; btnInput.Enabled = false; btnExamFirst.Enabled = false; btnExamSecond.Enabled = false; cbbUriType.SelectedIndexChanged += new EventHandler(cbbUriType_SelectedIndexChanged); this.WebStatusChange += new EventHandler(frmMain_WebStatusChange); pgbFinish.Maximum = 1; pgbFinish.Minimum = 0; FillHelper.FillCountChange += new FillUtility.FillCountEventHandle(FillHelper_FillCountChange); }
public async Task <Response <ChangeEmailViewModel, WebStatus> > CancelEmailAddressChangeAsync(string longCode) { _logger.LogTrace("Cancel email address change"); var response = await _oneTimeCodeService.CheckOneTimeCodeAsync(longCode, null); if (response.Status.StatusCode != CheckOneTimeCodeStatusCode.VerifiedWithoutNonce) // TODO: investigate if VerifiedWithNonce is possible and valid { return(Response.Web.Error <ChangeEmailViewModel>(_localizer["Invalid code."], HttpStatusCode.BadRequest)); } var userResponse = await _userStore.GetUserByPreviousEmailAsync(response.Result.SentTo); if (userResponse.HasError) { return(Response.Web.Error <ChangeEmailViewModel>(_localizer["User not found."], HttpStatusCode.BadRequest)); } var user = userResponse.Result; var changes = new Dictionary <string, string> { ["email"] = response.Result.SentTo, [PasswordlessLoginConstants.Security.PreviousEmailClaimType] = null }; var updateUserResponse = await _userStore.PatchUserAsync(user.SubjectId, changes.ToLookup(x => x.Key, x => x.Value), true); if (updateUserResponse.HasError) { var patchStatus = new WebStatus(updateUserResponse.Status); patchStatus.StatusCode = HttpStatusCode.BadRequest; return(new Response <ChangeEmailViewModel, WebStatus>(patchStatus)); } var updatedUser = updateUserResponse.Result; var viewModel = new ChangeEmailViewModel() { OldEmail = user.Email, NewEmail = updatedUser.Email, }; await _eventNotificationService.NotifyEventAsync(viewModel.OldEmail, EventType.CancelEmailChange, $"Reverted to {viewModel.NewEmail}"); return(Response.Web.Success(viewModel, _localizer["Email address change has been reverted."])); }
public async Task <IActionResult> Index() { var dbStatus = await StatusService.GetDbReport(); var activityStats = await UsersActivityStats.CreateAsync(DiscordClient); var data = new WebStatus() { Simple = StatusService.GetSimpleStatus(), ExecutedCommands = InternalStatistics.GetCommands(), DBStatus = dbStatus, LoggerStats = StatusService.GetLoggerStats(), TriggeredEvents = InternalStatistics.GetEvents(), Latency = DiscordClient.Latency, ConnectionState = DiscordClient.ConnectionState, LoginState = DiscordClient.LoginState, BotUser = DiscordClient.CurrentUser, ActivityStats = activityStats }; return(View(data)); }
public async Task <Response <User, WebStatus> > PatchUserAsync(PatchUserModel model) { _logger.LogTrace("Patch user {0}", _httpContext.User.GetSubjectId()); var userResponse = await GetUserAsync(); if (userResponse.HasError) { return(userResponse); } var updateUserResponse = await _userStore.PatchUserAsync(userResponse.Result.SubjectId, model.Properties); if (updateUserResponse.HasError) { var status = new WebStatus(updateUserResponse.Status); status.StatusCode = HttpStatusCode.BadRequest; return(new Response <User, WebStatus>(status)); } var updatedUser = updateUserResponse.Result; await _eventNotificationService.NotifyEventAsync(updatedUser.Email, EventType.UpdateAccount); return(Response.Web.Success(updatedUser)); }
private WebStatus Unauthenticated(string message = null) { return(WebStatus.Error(message, HttpStatusCode.Unauthorized)); }
private void brsMain_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { WebStatus temp= FillHelper.GetPageStatus(brsMain); if (CurrentStatus != temp) { CurrentStatus = temp; WebStatusChange(this, null); } }
public async Task <WebStatus> SendOneTimeCodeAsync(SendCodeInputModel model) { _logger.LogDebug("Begin send one time code for {0}", model.Username); if (!ApplicationIdIsNullOrValid(model.ApplicationId)) { return(WebStatus.Error(_localizer["Invalid application id."], HttpStatusCode.BadRequest)); } // Note: Need to keep messages generic as to not reveal whether an account exists or not. var usernameIsValidEmail = EmailAddressChecker.EmailIsValid(model.Username); var defaultMessage = usernameIsValidEmail ? _localizer["Message sent. Please check your email."] : _localizer["We sent a code to the email address asociated with your account (if found). Please check your email."]; // If the username provide is not an email address or phone number, tell the user "we sent you a code if you have an account" var userResponse = await _userStore.GetUserByUsernameAsync(model.Username); if (userResponse.HasError) { _logger.LogDebug("User not found"); if (!usernameIsValidEmail) { _logger.LogError("No valid email address found for user {0}", model.Username); return(WebStatus.Success(defaultMessage)); // generic message prevent account enumeration } var result = await _messageService.SendAccountNotFoundMessageAsync(model.ApplicationId, model.Username); if (result.HasError) { return(ServerError(result.Text)); } // the fact that the user doesn't have an account is communicated privately via email await _eventNotificationService.NotifyEventAsync(model.Username, EventType.AccountNotFound); return(WebStatus.Success(defaultMessage)); // generic message prevent account enumeration } var user = userResponse.Result; _logger.LogDebug("User found"); if (!EmailAddressChecker.EmailIsValid(user.Email)) { _logger.LogError("No valid email address found for user {0}", model.Username); return(WebStatus.Success(defaultMessage)); // generic message prevent account enumeration } var oneTimeCodeResponse = await _oneTimeCodeService.GetOneTimeCodeAsync( user.Email, TimeSpan.FromMinutes(_options.OneTimeCodeValidityMinutes), model.NextUrl); switch (oneTimeCodeResponse.Status.StatusCode) { case GetOneTimeCodeStatusCode.Success: var status = await _messageService.SendOneTimeCodeAndLinkMessageAsync(model.ApplicationId, model.Username, oneTimeCodeResponse.Result.ShortCode, oneTimeCodeResponse.Result.LongCode); await _eventNotificationService.NotifyEventAsync(model.Username, EventType.RequestOneTimeCode); if (status.IsOk) { status = Status.Success(defaultMessage); } SetNonce(oneTimeCodeResponse.Result.ClientNonce); return(new WebStatus(status)); case GetOneTimeCodeStatusCode.TooManyRequests: return(WebStatus.Error(_localizer["Please wait a few minutes before requesting a new code."], HttpStatusCode.TooManyRequests)); case GetOneTimeCodeStatusCode.ServiceFailure: default: return(ServerError(_localizer["Hmm. Something went wrong. Please try again."])); } }
public async Task <WebStatus> SignOutAsync() { await _signInService.SignOutAsync(); return(WebStatus.Success()); }
private async Task <WebStatus> SignInAndRedirectAsync(SignInMethod method, string username, bool?staySignedIn, string nextUrl, bool?nonceWasValid) { _logger.LogTrace("Begining sign in and redirect logic for {0}", username); /* * Do they have a partial sign in, and this was the second credential (code + password) or (password + code) [= 2 of 3] * Yes, skip to SIGN IN * Is this an trusted browser? [= 2 of 3] * Yes, skip to SIGN IN * Do they have NO trusted browsers? [= new account or someone who deleted all trusted browsers, 1 of 1|2] * Yes, skip to SIGN IN * Is 2FA enabled? (they have a password set and have chosen to require it when trusting a new browser) * Yes. Do partial sign in and prompt for the relevant second factor (automatically mailed code or password) * Used password to sign in? [= 1 of 2] * Yes, skip to SIGN IN * NonceWasValid [= 1 of 1|2] * No, back to sign in screen [prevents someone who passively observing code in transit/storage from using it undetected] * (local) SIGN IN * Is this a new browser? * Yes, redirect to TRUST NEW BROWSER * Is their account set to prompt them to choose a password * Yes, redirect to SET PASSWORD * Is their account set to prompt them to enable 2FA? * Yes, redirect to ENABLE 2FA * Has the application they are signing in to (if any) have required claims that have not been set? * Yes, redirect to COMPLETE PROFILE * Is their account set to prompt them to see/acknowledge any other screen? * Yes, redirect SOMEWHERE * FULL SIGN IN AND REDIRECT back to app (or to default post login page, apps page if none) * */ //do 2FA and figure out new browser, etc here var userResponse = await _userStore.GetUserByUsernameAsync(username, true); if (userResponse.HasError) { // this could only happen if an account was removed, but a method of signing in remained _logger.LogError("Strangely, there is no account for {0} anymore", username); return(Unauthenticated(_localizer["Account not found."])); } var user = userResponse.Result; var addTrustForThisBrowser = false; var trustedBrowserResponse = await _trustedBrowserStore.GetTrustedBrowserAsync(user.SubjectId, _httpContext.Request.GetBrowserId()); var browserIsTrusted = trustedBrowserResponse.IsOk; var authMethod = (method == SignInMethod.Password) ? "pwd" : "otp"; var authMethods = new string[] { authMethod }; if (browserIsTrusted) { authMethods.Append("cookie"); } if (_httpContext.User.Identity.IsAuthenticated && _httpContext.User.GetSubjectId() == user.SubjectId) { var previousAuthMethods = _httpContext.User.GetClaimValues("amr"); if (previousAuthMethods.Any() && !previousAuthMethods.Contains(authMethod)) { // If already signed in and now the user has authenticated with another // type of credential, this is now a multi-factor session authMethods = authMethods.Append("mfa").ToArray(); authMethods = previousAuthMethods.Union(authMethods).ToArray(); if (!browserIsTrusted) { _logger.LogInformation("Trusting browser because {0} performed multi-factor authentication", username); addTrustForThisBrowser = true; } } } var anyTrustedBrowsers = true; if (!browserIsTrusted && !addTrustForThisBrowser) { _logger.LogDebug("Browser user is signing in from is not trusted."); var trustedBrowsersResponse = await _trustedBrowserStore.GetTrustedBrowserAsync(user.SubjectId); anyTrustedBrowsers = trustedBrowsersResponse.Result?.Any() ?? false; if (anyTrustedBrowsers) { _logger.LogDebug("User has other browsers that are trusted."); // todo: if SecurityLevel == High OR first thing was a password, do a partial sign in and prompt for second thing if ((method == SignInMethod.OneTimeCode || method == SignInMethod.Link) && _options.NonceRequiredOnUntrustedBrowser && nonceWasValid == false) { _logger.LogWarning("Client nonce was missing or invalid. Perhaps the one time code has " + "been intercepted and an unathorized party is trying to user it. Authentication blocked."); return(Unauthenticated(_localizer["Your one time code has expired. Please request a new one."])); } } else if (method == SignInMethod.Link || method == SignInMethod.OneTimeCode) { // If no trusted browsers, trust the first browser that is used to verify a one time code _logger.LogInformation("Trusting first browser used by {0}", username); addTrustForThisBrowser = true; } else { _logger.LogDebug("User does not have any browsers that are trusted."); } } if (_options.AutoTrustBrowsers && addTrustForThisBrowser) { var description = _httpContext.Request.Headers["User-Agent"]; var trustBrowserResponse = await TrustBrowserAsync(user.SubjectId, description); if (trustBrowserResponse.IsOk) { browserIsTrusted = true; anyTrustedBrowsers = true; } } var authProps = new AuthenticationProperties { AllowRefresh = true, IsPersistent = false, }; if (staySignedIn == true || (method == SignInMethod.Link && browserIsTrusted)) { _logger.LogTrace("Using maximum session length of {0} minutes", _options.MaxSessionLengthMinutes); authProps.IsPersistent = true; authProps.ExpiresUtc = DateTimeOffset.UtcNow.Add(TimeSpan.FromMinutes(_options.MaxSessionLengthMinutes)); } else { _logger.LogTrace("Using default session length of {0} minutes", _options.DefaultSessionLengthMinutes); } if (method == SignInMethod.Link || method == SignInMethod.OneTimeCode) { // remove email unconfirmed claim, if present var removeClaims = new Dictionary <string, string>() { { PasswordlessLoginConstants.Security.EmailNotConfirmedClaimType, null } }.ToLookup(x => x.Key, x => x.Value); await _userStore.PatchUserAsync(user.SubjectId, removeClaims, true); } _logger.LogDebug("Signing user in: {0}", user.Email); _logger.LogTrace("SubjectId: {0}", user.SubjectId); var userName = _options.IdpUserNameClaim == "email" ? user.Email : user.Claims.FirstOrDefault(x => x.Type == _options.IdpUserNameClaim)?.Value; userName = userName ?? user.Email; var userClaims = user.Claims .Where(c => _options.IdpUserClaims.Contains(c.Type)) .Select(c => new Claim(c.Type, c.Value)) .ToArray(); if (_options.IdpUserClaims.Contains("email") && !userClaims.Any(c => c.Type == "email")) { userClaims = userClaims.Append(new Claim("email", user.Email)).ToArray(); } await _signInService.SignInAsync(user.SubjectId, userName, authMethods, authProps, userClaims); nextUrl = ValidatedNextUrl(nextUrl); _logger.LogDebug("Redirecting user to: {0}", nextUrl); return(WebStatus.Redirect(nextUrl)); }
public async Task <WebStatus> RegisterAsync(RegisterInputModel model) { var genericSuccessMessage = _localizer["Please check your email to complete the sign up process."]; _logger.LogDebug("Begin registration for {0}", model.Email); if (!ApplicationIdIsNullOrValid(model.ApplicationId)) { return(WebStatus.Error(_localizer["Invalid application id."], HttpStatusCode.BadRequest)); } if (!await _userStore.UsernameIsAvailable(model.Email)) { _logger.LogDebug("Existing user found."); var sendStatus = await _messageService.SendAccountAlreadyExistsMessageAsync(model.ApplicationId, model.Email); // Return a generic success message to prevent account discovery. Only the owner of // the email address will get a customized message. return(sendStatus.IsOk ? WebStatus.Success(genericSuccessMessage) : new WebStatus(sendStatus)); } if (await _oneTimeCodeService.UnexpiredOneTimeCodeExistsAsync(model.Email)) { // Although the username is available, there is a valid one time code // that can be used to cancel an email address change, so we can't // reuse the address quite yet return(WebStatus.Error(_localizer["Email address is temporarily reserved."], HttpStatusCode.Conflict)); } _logger.LogDebug("Email address not used by an existing user. Creating a new user."); // consider: in some cases may want to restricting claims to a list predefined by the system administrator var status = new WebStatus(); if (model.Claims == null) { model.Claims = new Dictionary <string, string>(); } var internalClaims = new KeyValuePair <string, string>[] { new KeyValuePair <string, string>( PasswordlessLoginConstants.Security.EmailNotConfirmedClaimType, "!") }; var newUser = new User() { Email = model.Email, Claims = model.Claims .Where(x => !PasswordlessLoginConstants.Security.ForbiddenClaims.Contains(x.Key) && !PasswordlessLoginConstants.Security.ProtectedClaims.Contains(x.Key)) .Union(internalClaims) .Select(x => new UserClaim() { Type = x.Key, Value = x.Value }) }; var newUserResponse = await _userStore.AddUserAsync(newUser); if (newUserResponse.HasError) { return(new WebStatus(newUserResponse.Status)); } newUser = newUserResponse.Result; await _eventNotificationService.NotifyEventAsync(newUser.Email, EventType.Register); if (!string.IsNullOrEmpty(model.Password)) { var setPasswordStatus = await _passwordService.SetPasswordAsync(newUser.SubjectId, model.Password); if (setPasswordStatus.IsOk) { await _eventNotificationService.NotifyEventAsync(newUser.Email, EventType.SetPassword); } else { status.AddWarning(_localizer["Password was not set."]); } } status.AddSuccess(genericSuccessMessage); var nextUrl = !string.IsNullOrEmpty(model.NextUrl) ? model.NextUrl : _urlService.GetDefaultRedirectUrl(); if (model.SetPassword) { _logger.LogTrace("The user will be asked to set their password after confirming the account."); nextUrl = SendToSetPasswordFirst(nextUrl); } var oneTimeCodeResponse = await _oneTimeCodeService.GetOneTimeCodeAsync(model.Email, TimeSpan.FromMinutes(_options.ConfirmAccountLinkValidityMinutes), nextUrl); switch (oneTimeCodeResponse.Status.StatusCode) { case GetOneTimeCodeStatusCode.Success: var result = await _messageService.SendWelcomeMessageAsync(model.ApplicationId, model.Email, oneTimeCodeResponse.Result.ShortCode, oneTimeCodeResponse.Result.LongCode, model.Claims); SetNonce(oneTimeCodeResponse.Result.ClientNonce); return(new WebStatus(status)); case GetOneTimeCodeStatusCode.TooManyRequests: return(WebStatus.Error(_localizer["Please wait a few minutes and try again."], HttpStatusCode.TooManyRequests)); case GetOneTimeCodeStatusCode.ServiceFailure: default: return(ServerError(_localizer["Hmm. Something went wrong. Please try again."])); } }
public async Task <Response <ChangeEmailViewModel, WebStatus> > ChangeEmailAddressAsync( string newEmail, string applicationId = null) { _logger.LogTrace("Change email for user {0} to {1}", _httpContext.User.GetSubjectId(), newEmail); var userResponse = await GetUserAsync(); if (userResponse.HasError) { return(Response.Web.Error <ChangeEmailViewModel>("User not found.", HttpStatusCode.NotFound)); } var user = userResponse.Result; // Check if a cancel email change code link is still valid. Note that the cancel email change code link does // not interfere with getting a one time code to sign in because it is associated with the OLD email address. var previouslyChangedEmail = user.Claims.FirstOrDefault(x => x.Type == PasswordlessLoginConstants.Security.PreviousEmailClaimType)?.Value; if (previouslyChangedEmail != null && (await _oneTimeCodeService.UnexpiredOneTimeCodeExistsAsync(previouslyChangedEmail))) { return(Response.Web.Error <ChangeEmailViewModel>(_localizer["You cannot change your email address again until the link to cancel the last email change (sent to your old email address) expires."], HttpStatusCode.Forbidden)); } var usernameAvailableStatus = await UsernameIsReallyAvailableAsync(newEmail, user.SubjectId); if (usernameAvailableStatus.HasError) { return(Response.Web.Error <ChangeEmailViewModel>(_localizer["Username is not available."], HttpStatusCode.Conflict)); } var oldEmail = user.Email; if (_passwordlessLoginOptions.SendCancelEmailChangeMessage) { var otcResponse = await _oneTimeCodeService.GetOneTimeCodeAsync(oldEmail, TimeSpan.FromHours(_passwordlessLoginOptions.CancelEmailChangeTimeWindowHours)); var status = await _messageService.SendEmailChangedNoticeAsync(applicationId, oldEmail, otcResponse.Result.LongCode); if (status.HasError) { // TODO: review to ensure that this will not prevent changing one's email address if the // old address is undeliverable return(Response.Web.Error <ChangeEmailViewModel>($"{_localizer["Change cancelled because of failure to send email notice:"]} {status.Text}")); } } var changes = new Dictionary <string, string> { ["email"] = newEmail, [PasswordlessLoginConstants.Security.PreviousEmailClaimType] = oldEmail }; var updateUserResponse = await _userStore.PatchUserAsync(user.SubjectId, changes.ToLookup(x => x.Key, x => x.Value), true); if (updateUserResponse.HasError) { var patchStatus = new WebStatus(updateUserResponse.Status); patchStatus.StatusCode = HttpStatusCode.BadRequest; return(new Response <ChangeEmailViewModel, WebStatus>(patchStatus)); } var updatedUser = updateUserResponse.Result; var viewModel = new ChangeEmailViewModel() { OldEmail = user.Email, NewEmail = updatedUser.Email, }; await _eventNotificationService.NotifyEventAsync(viewModel.OldEmail, EventType.EmailChange, $"Changed to {viewModel.NewEmail}"); return(Response.Web.Success(viewModel)); }
private WebStatus ServerError(string message = null) { return(WebStatus.Error(message, HttpStatusCode.InternalServerError)); }