sendEmailChange sends out an email change token to the new email.
(r *http.Request, tx *storage.Connection, u *models.User, email string, flowType models.FlowType)
| 521 | |
| 522 | // sendEmailChange sends out an email change token to the new email. |
| 523 | func (a *API) sendEmailChange(r *http.Request, tx *storage.Connection, u *models.User, email string, flowType models.FlowType) error { |
| 524 | config := a.config |
| 525 | otpLength := config.Mailer.OtpLength |
| 526 | |
| 527 | if err := validateSentWithinFrequencyLimit(u.EmailChangeSentAt, config.SMTP.MaxFrequency); err != nil { |
| 528 | return err |
| 529 | } |
| 530 | |
| 531 | otpNew := crypto.GenerateOtp(otpLength) |
| 532 | |
| 533 | u.EmailChange = email |
| 534 | token := crypto.GenerateTokenHash(u.EmailChange, otpNew) |
| 535 | u.EmailChangeTokenNew = addFlowPrefixToToken(token, flowType) |
| 536 | |
| 537 | otpCurrent := "" |
| 538 | if config.Mailer.SecureEmailChangeEnabled && u.GetEmail() != "" { |
| 539 | otpCurrent = crypto.GenerateOtp(otpLength) |
| 540 | |
| 541 | currentToken := crypto.GenerateTokenHash(u.GetEmail(), otpCurrent) |
| 542 | u.EmailChangeTokenCurrent = addFlowPrefixToToken(currentToken, flowType) |
| 543 | } |
| 544 | |
| 545 | u.EmailChangeConfirmStatus = zeroConfirmation |
| 546 | now := time.Now() |
| 547 | |
| 548 | err := a.sendEmail(r, tx, u, sendEmailParams{ |
| 549 | emailActionType: mail.EmailChangeVerification, |
| 550 | otp: otpCurrent, |
| 551 | otpNew: otpNew, |
| 552 | tokenHashWithPrefix: u.EmailChangeTokenNew, |
| 553 | }) |
| 554 | if err != nil { |
| 555 | if errors.Is(err, EmailRateLimitExceeded) { |
| 556 | return apierrors.NewTooManyRequestsError(apierrors.ErrorCodeOverEmailSendRateLimit, "%s", EmailRateLimitExceeded.Error()) |
| 557 | } else if herr, ok := err.(*HTTPError); ok { |
| 558 | return herr |
| 559 | } |
| 560 | return apierrors.NewInternalServerError("Error sending email change email").WithInternalError(err) |
| 561 | } |
| 562 | |
| 563 | u.EmailChangeSentAt = &now |
| 564 | if err := tx.UpdateOnly( |
| 565 | u, |
| 566 | "email_change_token_current", |
| 567 | "email_change_token_new", |
| 568 | "email_change", |
| 569 | "email_change_sent_at", |
| 570 | "email_change_confirm_status", |
| 571 | ); err != nil { |
| 572 | return apierrors.NewInternalServerError("Error sending email change email").WithInternalError(errors.Wrap(err, "Database error updating user for email change")) |
| 573 | } |
| 574 | |
| 575 | if u.EmailChangeTokenCurrent != "" { |
| 576 | if err := models.CreateOneTimeToken(tx, u.ID, u.GetEmail(), u.EmailChangeTokenCurrent, models.EmailChangeTokenCurrent); err != nil { |
| 577 | return apierrors.NewInternalServerError("Error sending email change email").WithInternalError(errors.Wrap(err, "Database error creating email change token current")) |
| 578 | } |
| 579 | } |
| 580 |
no test coverage detected