FEATURE: improve email change workflow

- Show old and new email address during the process
- Ensure correct user is logged on when attempting to make email changes
- Support reloading a page during the email reset process without resubmit
of form
- Improve tests
- Fixed issue where redirect back to site was not linking correctly in
subfolder setups

Internal refactor of single action into 4 distinct actions that are simpler
to reason about.

This also removes the step that logs on an account after you confirm an
email change, since it is no longer needed which leaves us with safer
internals.

This left me no choice but to amend translations cause the old route was
removed.
This commit is contained in:
Sam Saffron 2019-11-20 18:31:25 +11:00
parent 423ad5f0a4
commit b57e108e84
29 changed files with 409 additions and 185 deletions

View File

@ -687,6 +687,25 @@ class ApplicationController < ActionController::Base
request.original_url unless request.original_url =~ /uploads/ request.original_url unless request.original_url =~ /uploads/
end end
def redirect_to_login
dont_cache_page
if SiteSetting.enable_sso?
# save original URL in a session so we can redirect after login
session[:destination_url] = destination_url
redirect_to path('/session/sso')
elsif !SiteSetting.enable_local_logins && Discourse.enabled_authenticators.length == 1 && !cookies[:authentication_data]
# Only one authentication provider, direct straight to it.
# If authentication_data is present, then we are halfway though registration. Don't redirect offsite
cookies[:destination_url] = destination_url
redirect_to path("/auth/#{Discourse.enabled_authenticators.first.name}")
else
# save original URL in a cookie (javascript redirects after login in this case)
cookies[:destination_url] = destination_url
redirect_to path("/login")
end
end
def redirect_to_login_if_required def redirect_to_login_if_required
return if request.format.json? && is_api? return if request.format.json? && is_api?
@ -715,24 +734,8 @@ class ApplicationController < ActionController::Base
if !current_user && SiteSetting.login_required? if !current_user && SiteSetting.login_required?
flash.keep flash.keep
dont_cache_page redirect_to_login
if SiteSetting.enable_sso?
# save original URL in a session so we can redirect after login
session[:destination_url] = destination_url
redirect_to path('/session/sso')
return return
elsif !SiteSetting.enable_local_logins && Discourse.enabled_authenticators.length == 1 && !cookies[:authentication_data]
# Only one authentication provider, direct straight to it.
# If authentication_data is present, then we are halfway though registration. Don't redirect offsite
cookies[:destination_url] = destination_url
redirect_to path("/auth/#{Discourse.enabled_authenticators.first.name}")
else
# save original URL in a cookie (javascript redirects after login in this case)
cookies[:destination_url] = destination_url
redirect_to path("/login")
return
end
end end
check_totp = current_user && check_totp = current_user &&

View File

@ -4,8 +4,26 @@ class UsersEmailController < ApplicationController
requires_login only: [:index, :update] requires_login only: [:index, :update]
skip_before_action :check_xhr, only: [:confirm] skip_before_action :check_xhr, only: [
skip_before_action :redirect_to_login_if_required, only: [:confirm] :confirm_old_email,
:show_confirm_old_email,
:confirm_new_email,
:show_confirm_new_email
]
skip_before_action :redirect_to_login_if_required, only: [
:confirm_old_email,
:show_confirm_old_email,
:confirm_new_email,
:show_confirm_new_email
]
before_action :require_login, only: [
:confirm_old_email,
:show_confirm_old_email,
:confirm_new_email,
:show_confirm_new_email
]
def index def index
end end
@ -29,38 +47,141 @@ class UsersEmailController < ApplicationController
render_json_error(I18n.t("rate_limiter.slow_down")) render_json_error(I18n.t("rate_limiter.slow_down"))
end end
def confirm def confirm_new_email
expires_now load_change_request(:new)
token = EmailToken.confirmable(params[:token]) if @change_request&.change_state != EmailChangeRequest.states[:authorizing_new]
user = token&.user @error = I18n.t("change_email.already_done")
change_request =
if user
user.email_change_requests.where(new_email_token_id: token.id).first
end end
if change_request&.change_state == EmailChangeRequest.states[:authorizing_new] && redirect_url = path("/u/confirm-new-email/#{params[:token]}")
user.totp_enabled? && !user.authenticate_second_factor(params[:second_factor_token], params[:second_factor_method].to_i)
@update_result = :invalid_second_factor if !@error && @user.totp_enabled? && !@user.authenticate_second_factor(params[:second_factor_token], params[:second_factor_method].to_i)
@backup_codes_enabled = true if user.backup_codes_enabled?
if params[:second_factor_token].present?
RateLimiter.new(nil, "second-factor-min-#{request.remote_ip}", 3, 1.minute).performed! RateLimiter.new(nil, "second-factor-min-#{request.remote_ip}", 3, 1.minute).performed!
@show_invalid_second_factor_error = true flash[:invalid_second_factor] = true
redirect_to redirect_url
return
end end
else
updater = EmailUpdater.new
@update_result = updater.confirm(params[:token])
if @update_result == :complete if !@error
updater = EmailUpdater.new
if updater.confirm(params[:token]) == :complete
updater.user.user_stat.reset_bounce_score! updater.user.user_stat.reset_bounce_score!
log_on_user(updater.user) else
@error = I18n.t("change_email.already_done")
end end
end end
if @error
flash[:error] = @error
redirect_to redirect_url
else
redirect_to "#{redirect_url}?done=true"
end
end
def show_confirm_new_email
load_change_request(:new)
if params[:done].to_s == "true"
@done = true
end
if @change_request&.change_state != EmailChangeRequest.states[:authorizing_new]
@error = I18n.t("change_email.already_done")
end
@show_invalid_second_factor_error = flash[:invalid_second_factor]
if !@error
if @user.totp_enabled?
@backup_codes_enabled = @user.backup_codes_enabled?
if params[:show_backup].to_s == "true" && @backup_codes_enabled
@show_backup_codes = true
else
@show_second_factor = true
end
end
@to_email = @change_request.new_email
end
render layout: 'no_ember' render layout: 'no_ember'
end end
def confirm_old_email
load_change_request(:old)
if @change_request&.change_state != EmailChangeRequest.states[:authorizing_old]
@error = I18n.t("change_email.already_done")
end
redirect_url = path("/u/confirm-old-email/#{params[:token]}")
if !@error
updater = EmailUpdater.new
if updater.confirm(params[:token]) != :authorizing_new
@error = I18n.t("change_email.already_done")
end
end
if @error
flash[:error] = @error
redirect_to redirect_url
else
redirect_to "#{redirect_url}?done=true"
end
end
def show_confirm_old_email
load_change_request(:old)
if @change_request&.change_state != EmailChangeRequest.states[:authorizing_old]
@error = I18n.t("change_email.already_done")
end
if params[:done].to_s == "true"
@almost_done = true
end
if !@error
@from_email = @user.email
@to_email = @change_request.new_email
end
render layout: 'no_ember'
end
private
def load_change_request(type)
expires_now
@token = EmailToken.confirmable(params[:token])
if @token
if type == :old
@change_request = @token.user&.email_change_requests.where(old_email_token_id: @token.id).first
elsif type == :new
@change_request = @token.user&.email_change_requests.where(new_email_token_id: @token.id).first
end
end
@user = @token&.user
if (!@user || !@change_request)
@error = I18n.t("change_email.already_done")
end
if current_user.id != @user&.id
@error = I18n.t 'change_email.wrong_account_error'
end
end
def require_login
if !current_user
redirect_to_login
end
end
end end

View File

@ -1,47 +0,0 @@
<div id="simple-container">
<% if @update_result == :authorizing_new %>
<h2><%= t 'change_email.authorizing_old.title' %></h2>
<br>
<p><%= t 'change_email.authorizing_old.description' %></p>
<% elsif @update_result == :complete %>
<h2><%= t 'change_email.confirmed' %></h2>
<br>
<a class="btn" href="/"><%= t('change_email.please_continue', site_name: SiteSetting.title) %></a>
<% elsif @update_result == :invalid_second_factor%>
<% if !params[:show_backup] || params[:show_backup] == "false" %>
<div id="primary-second-factor-form">
<h2><%= t('login.second_factor_title') %></h2>
<br>
<%=form_tag({}, method: :put) do %>
<%= label_tag(:second_factor_token, t('login.second_factor_description')) %>
<div><%= render 'common/second_factor_text_field' %></div>
<% if @show_invalid_second_factor_error %>
<div class='alert alert-error'><%= t('login.invalid_second_factor_code') %></div>
<% end %>
<%= submit_tag t('submit'), class: "btn btn-primary" %>
<% end %>
</div>
<% if @backup_codes_enabled %>
<%= link_to t("login.second_factor_toggle.backup_code"), show_backup: "true" %>
<% end %>
<% end %>
<% if @backup_codes_enabled && params[:show_backup] == "true" %>
<div id="backup-second-factor-form" style="">
<h2><%= t('login.second_factor_backup_title') %></h2>
<br>
<%= form_tag({}, method: :put) do%>
<%= label_tag(:second_factor_token, t("login.second_factor_backup_description")) %>
<div><%= render 'common/second_factor_backup_input' %></div>
<%= submit_tag(t("submit"), class: "btn btn-primary") %>
<%end%>
</div>
<%= link_to t("login.second_factor_toggle.totp"), show_backup: "false" %>
<%end%>
<% else %>
<div class='alert alert-error'>
<%=t 'change_email.already_done' %>
</div>
<% end %>
</div>

View File

@ -0,0 +1,51 @@
<div id="simple-container">
<% if @done %>
<h2>
<%= t 'change_email.confirmed' %>
</h2>
<p>
<a class="btn" href="<%= path "/" %>"><%= t('change_email.please_continue', site_name: SiteSetting.title) %></a>
</p>
<% elsif @error %>
<div class='alert alert-error'>
<%= @error %>
</div>
<% else %>
<h2><%= t 'change_email.authorizing_new.title' %></h2>
<p>
<%= t 'change_email.authorizing_new.description' %>
</p>
<p>
<%= @to_email %>
</p>
<%=form_tag(u_confirm_new_email_path, method: :put) do %>
<%= hidden_field_tag 'token', @token.token %>
<% if @show_backup_codes %>
<div id="backup-second-factor-form" style="">
<h3><%= t('login.second_factor_backup_title') %></h3>
<%= label_tag(:second_factor_token, t("login.second_factor_backup_description")) %>
<div><%= render 'common/second_factor_backup_input' %></div>
<%= submit_tag(t("submit"), class: "btn btn-primary") %>
</div>
<%= link_to t("login.second_factor_toggle.totp"), show_backup: "false" %>
<% elsif @show_second_factor %>
<div id="primary-second-factor-form">
<h3><%= t('login.second_factor_title') %></h3>
<%= label_tag(:second_factor_token, t('login.second_factor_description')) %>
<div><%= render 'common/second_factor_text_field' %></div>
<% if @show_invalid_second_factor_error %>
<div class='alert alert-error'><%= t('login.invalid_second_factor_code') %></div>
<% end %>
<%= submit_tag t('submit'), class: "btn btn-primary" %>
</div>
<% if @backup_codes_enabled %>
<%= link_to t("login.second_factor_toggle.backup_code"), show_backup: "true" %>
<% end %>
<% else %>
<%= submit_tag t('change_email.confirm'), class: "btn btn-primary" %>
<% end %>
<%end%>
<% end%>
</div>

View File

@ -0,0 +1,27 @@
<div id="simple-container">
<% if @almost_done %>
<h2><%= t 'change_email.authorizing_old.almost_done_title' %></h2>
<p>
<%= t 'change_email.authorizing_old.almost_done_description' %>
</p>
<% elsif @error %>
<div class='alert alert-error'>
<%= @error %>
</div>
<% else %>
<h2><%= t 'change_email.authorizing_old.title' %></h2>
<p>
<%= t 'change_email.authorizing_old.description' %>
<br>
<br>
<%= t 'change_email.authorizing_old.old_email', email: @from_email %>
<br>
<%= t 'change_email.authorizing_old.new_email', email: @to_email %>
</p>
<%=form_tag(u_confirm_old_email_path, method: :put) do %>
<%= hidden_field_tag 'token', @token.token %>
<%= submit_tag t('change_email.confirm'), class: "btn btn-primary" %>
<% end %>
<% end %>
</div>

View File

@ -1456,7 +1456,7 @@ ar:
text_body_template: | text_body_template: |
أكد عنوان بريدك الإلكتروني لـ %{site_name} بالضغط على الرابط التالي : أكد عنوان بريدك الإلكتروني لـ %{site_name} بالضغط على الرابط التالي :
%{email_token}/u/authorize-email/%{base_url} %{email_token}/u/confirm-new-email/%{base_url}
confirm_old_email: confirm_old_email:
subject_template: "أكّد عنوان بريد الإلكتروني الحالي %{email_prefix}" subject_template: "أكّد عنوان بريد الإلكتروني الحالي %{email_prefix}"
text_body_template: | text_body_template: |
@ -1466,7 +1466,7 @@ ar:
أكّد عنوان بريدك الإلكتروني الحالي لـ %{site_name} بالضغط على الرابط التالي : أكّد عنوان بريدك الإلكتروني الحالي لـ %{site_name} بالضغط على الرابط التالي :
%{email_token}/u/authorize-email/%{base_url} %{email_token}/u/confirm-old-email/%{base_url}
notify_old_email: notify_old_email:
subject_template: "عنوان بريد الإلكتروني تم تغييرة %{email_prefix}" subject_template: "عنوان بريد الإلكتروني تم تغييرة %{email_prefix}"
signup_after_approval: signup_after_approval:

View File

@ -2745,7 +2745,7 @@ ca:
text_body_template: | text_body_template: |
Confirmeu la vostra nova adreça de correu per a %{site_name} fent clic en l'enllaç següent: Confirmeu la vostra nova adreça de correu per a %{site_name} fent clic en l'enllaç següent:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-new-email/%{email_token}
confirm_old_email: confirm_old_email:
title: "Confirmeu l'adreça de correu antiga" title: "Confirmeu l'adreça de correu antiga"
subject_template: "[%{email_prefix}] Confirmeu la vostra adreça de correu actual" subject_template: "[%{email_prefix}] Confirmeu la vostra adreça de correu actual"
@ -2756,7 +2756,7 @@ ca:
Confirmeu la vostra adreça actual per a %{site_name} fent clic en l'enllaç següent: Confirmeu la vostra adreça actual per a %{site_name} fent clic en l'enllaç següent:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-old-email/%{email_token}
notify_old_email: notify_old_email:
title: "Notifica l'adreça de correu antiga" title: "Notifica l'adreça de correu antiga"
subject_template: "[%{email_prefix}] La vostra adreça de correu ha canviat" subject_template: "[%{email_prefix}] La vostra adreça de correu ha canviat"

View File

@ -3019,7 +3019,7 @@ de:
text_body_template: | text_body_template: |
Bestätige deine neue E-Mail-Adresse für %{site_name}, indem du dem diesem Link folgst: Bestätige deine neue E-Mail-Adresse für %{site_name}, indem du dem diesem Link folgst:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-new-email/%{email_token}
confirm_old_email: confirm_old_email:
title: "E-Mail-Adresse bestätigen (an alte)" title: "E-Mail-Adresse bestätigen (an alte)"
subject_template: "[%{email_prefix}] Bestätige deine aktuelle E-Mail-Adresse" subject_template: "[%{email_prefix}] Bestätige deine aktuelle E-Mail-Adresse"
@ -3028,7 +3028,7 @@ de:
Bestätige deine aktuelle E-Mail-Adresse für %{site_name}, indem du diesem Link folgst: Bestätige deine aktuelle E-Mail-Adresse für %{site_name}, indem du diesem Link folgst:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-old-email/%{email_token}
notify_old_email: notify_old_email:
title: "Benachrichtigung an alte E-Mail-Adresse" title: "Benachrichtigung an alte E-Mail-Adresse"
subject_template: "[%{email_prefix}] Deine E-Mail-Adresse wurde geändert" subject_template: "[%{email_prefix}] Deine E-Mail-Adresse wurde geändert"

View File

@ -2084,7 +2084,7 @@ el:
Επικυρώστε την νέα σας διεύθυνση email στην %{site_name} κάνοντας κλικ στον παρακάτω σύνδεσμο: Επικυρώστε την νέα σας διεύθυνση email στην %{site_name} κάνοντας κλικ στον παρακάτω σύνδεσμο:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-new-email/%{email_token}
confirm_old_email: confirm_old_email:
title: "Επιβεβαίωση παλιάς διεύθυνσης email" title: "Επιβεβαίωση παλιάς διεύθυνσης email"
subject_template: "[%{email_prefix}] Επικυρώστε την νέα σας διεύθυνση email" subject_template: "[%{email_prefix}] Επικυρώστε την νέα σας διεύθυνση email"
@ -2098,7 +2098,7 @@ el:
Επιβεβαιώστε την τρέχουσα διεύθυνση email στην%{site_name} κάνοντας κλικ στον παρακάτω σύνδεσμο: Επιβεβαιώστε την τρέχουσα διεύθυνση email στην%{site_name} κάνοντας κλικ στον παρακάτω σύνδεσμο:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-old-email/%{email_token}
notify_old_email: notify_old_email:
title: "Ειδοποίηση παλιάς διεύθυνσης email" title: "Ειδοποίηση παλιάς διεύθυνσης email"
subject_template: "[%{email_prefix}] Η διεύθυνση email σας έχει αλλαχθεί" subject_template: "[%{email_prefix}] Η διεύθυνση email σας έχει αλλαχθεί"

View File

@ -805,14 +805,25 @@ en:
unknown: "unknown operating system" unknown: "unknown operating system"
change_email: change_email:
wrong_account_error: "You are logged in the wrong account, please log out and try again."
confirmed: "Your email has been updated." confirmed: "Your email has been updated."
please_continue: "Continue to %{site_name}" please_continue: "Continue to %{site_name}"
error: "There was an error changing your email address. Perhaps the address is already in use?" error: "There was an error changing your email address. Perhaps the address is already in use?"
error_staged: "There was an error changing your email address. The address is already in use by a staged user." error_staged: "There was an error changing your email address. The address is already in use by a staged user."
already_done: "Sorry, this confirmation link is no longer valid. Perhaps your email was already changed?" already_done: "Sorry, this confirmation link is no longer valid. Perhaps your email was already changed?"
confirm: "Confirm"
authorizing_new:
title: "Confirm your new email"
description: "Please confirm you would like your new email address changed to:"
authorizing_old: authorizing_old:
title: "Thanks for confirming your current email address" title: "Change your email address"
description: "We're now emailing your new address for confirmation." description: "Please confirm your email address change"
old_email: "Old email: %{email}"
new_email: "New email: %{email}"
almost_done_title: "Confirming new email address"
almost_done_description: "We have sent an email to your new email address to confirm the change!"
associated_accounts: associated_accounts:
revoke_failed: "Failed to revoke your account with %{provider_name}." revoke_failed: "Failed to revoke your account with %{provider_name}."
@ -3545,7 +3556,7 @@ en:
text_body_template: | text_body_template: |
Confirm your new email address for %{site_name} by clicking on the following link: Confirm your new email address for %{site_name} by clicking on the following link:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-new-email/%{email_token}
confirm_old_email: confirm_old_email:
title: "Confirm Old Email" title: "Confirm Old Email"
@ -3557,7 +3568,7 @@ en:
Confirm your current email address for %{site_name} by clicking on the following link: Confirm your current email address for %{site_name} by clicking on the following link:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-old-email/%{email_token}
notify_old_email: notify_old_email:
title: "Notify Old Email" title: "Notify Old Email"

View File

@ -3144,7 +3144,7 @@ es:
text_body_template: | text_body_template: |
Confirma tu nueva dirección de correo electrónico para %{site_name} haciendo clic en el siguiente enlace: Confirma tu nueva dirección de correo electrónico para %{site_name} haciendo clic en el siguiente enlace:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-new-email/%{email_token}
confirm_old_email: confirm_old_email:
title: "Confirmar correo electrónico antiguo" title: "Confirmar correo electrónico antiguo"
subject_template: "[%{email_prefix}] Confirma tu dirección actual de correo electrónico" subject_template: "[%{email_prefix}] Confirma tu dirección actual de correo electrónico"
@ -3155,7 +3155,7 @@ es:
Confirma tu correo electrónico actual para %{site_name} haciendo clic en el siguiente enlace: Confirma tu correo electrónico actual para %{site_name} haciendo clic en el siguiente enlace:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-new-email/%{email_token}
notify_old_email: notify_old_email:
title: "Antiguo correo electrónico de notificaciones" title: "Antiguo correo electrónico de notificaciones"
subject_template: "[%{email_prefix}] Tu dirección de correo electrónico ha sido cambiada" subject_template: "[%{email_prefix}] Tu dirección de correo electrónico ha sido cambiada"

View File

@ -1896,7 +1896,7 @@ fa_IR:
text_body_template: | text_body_template: |
ایمیل جدید خود را برای %{site_name} با کلیک روی لینک زیر تایید کنید: ایمیل جدید خود را برای %{site_name} با کلیک روی لینک زیر تایید کنید:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-new-email/%{email_token}
confirm_old_email: confirm_old_email:
title: "تایید ایمیل قبلی" title: "تایید ایمیل قبلی"
subject_template: "[%{email_prefix}] ایمیل فعلی خود را تایید کنید" subject_template: "[%{email_prefix}] ایمیل فعلی خود را تایید کنید"
@ -1907,7 +1907,7 @@ fa_IR:
ایمیل فعلی خود در سایت %{site_name} را با کلیکل روی لینک زیر تعیید کنید: ایمیل فعلی خود در سایت %{site_name} را با کلیکل روی لینک زیر تعیید کنید:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-old-email/%{email_token}
notify_old_email: notify_old_email:
title: "اعلام ایمیل قبلی" title: "اعلام ایمیل قبلی"
subject_template: "[%{email_prefix}] ایمیل شما تغییر کرده است" subject_template: "[%{email_prefix}] ایمیل شما تغییر کرده است"

View File

@ -2879,7 +2879,7 @@ fi:
text_body_template: | text_body_template: |
Vahvista uusi sähköpostiosoitteesi sivustolla %{site_name} klikkaamalla linkkiä: Vahvista uusi sähköpostiosoitteesi sivustolla %{site_name} klikkaamalla linkkiä:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-new-email/%{email_token}
confirm_old_email: confirm_old_email:
title: "Vahvista vanha sähköpostiosoite" title: "Vahvista vanha sähköpostiosoite"
subject_template: "[%{email_prefix}] Vahvista nykyinen sähköpostiosoitteesi" subject_template: "[%{email_prefix}] Vahvista nykyinen sähköpostiosoitteesi"
@ -2888,7 +2888,7 @@ fi:
Vahvista nykyinen sähköpostiosoitteesi sivustolla %{site_name} klikkaamalla linkkiä: Vahvista nykyinen sähköpostiosoitteesi sivustolla %{site_name} klikkaamalla linkkiä:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-old-email/%{email_token}
notify_old_email: notify_old_email:
title: "Ilmoita vanhaan sähköpostiosoitteeseen" title: "Ilmoita vanhaan sähköpostiosoitteeseen"
subject_template: "[%{email_prefix}] Sähköpostiosoitteesi on vaihdettu" subject_template: "[%{email_prefix}] Sähköpostiosoitteesi on vaihdettu"

View File

@ -3009,7 +3009,7 @@ fr:
text_body_template: | text_body_template: |
Confirmez votre nouvelle adresse email pour %{site_name} en cliquant sur le lien suivant : Confirmez votre nouvelle adresse email pour %{site_name} en cliquant sur le lien suivant :
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-new-email/%{email_token}
confirm_old_email: confirm_old_email:
title: "Confirmez votre ancienne adresse email" title: "Confirmez votre ancienne adresse email"
subject_template: "[%{email_prefix}] Confirmez votre adresse email actuelle" subject_template: "[%{email_prefix}] Confirmez votre adresse email actuelle"
@ -3018,7 +3018,7 @@ fr:
Confirmez votre adresse email actuelle pour %{site_name} en cliquant sur le lien suivant : Confirmez votre adresse email actuelle pour %{site_name} en cliquant sur le lien suivant :
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-old-email/%{email_token}
notify_old_email: notify_old_email:
title: "Notifier l'ancienne adresse courriel" title: "Notifier l'ancienne adresse courriel"
subject_template: "[%{email_prefix}] Votre adresse email a été modifié" subject_template: "[%{email_prefix}] Votre adresse email a été modifié"

View File

@ -3259,7 +3259,7 @@ he:
text_body_template: | text_body_template: |
אשרו את כתובת המייל החדשה שלכם עבור %{site_name} על ידי לחיצה על הקישור הבא: אשרו את כתובת המייל החדשה שלכם עבור %{site_name} על ידי לחיצה על הקישור הבא:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-new-email/%{email_token}
confirm_old_email: confirm_old_email:
title: "אישור מייל ישן" title: "אישור מייל ישן"
subject_template: "[%{email_prefix}] אשרו את כתובת המייל הנוכחית שלכם" subject_template: "[%{email_prefix}] אשרו את כתובת המייל הנוכחית שלכם"
@ -3269,7 +3269,7 @@ he:
אשרו את כתובת המייל הנוכחית עבור %{site_name} על ידי לחיצה על הקישור הבא: אשרו את כתובת המייל הנוכחית עבור %{site_name} על ידי לחיצה על הקישור הבא:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-old-email/%{email_token}
notify_old_email: notify_old_email:
title: "התראת דוא״ל ישן" title: "התראת דוא״ל ישן"
subject_template: "[%{email_prefix}] כתובת הדוא״ל שלך הוחלפה" subject_template: "[%{email_prefix}] כתובת הדוא״ל שלך הוחלפה"

View File

@ -2701,7 +2701,7 @@ hy:
text_body_template: | text_body_template: |
Հաստատեք Ձեր նոր էլ. հասցեն %{site_name} -ի համար՝ սեղմելով հետևյալ հղումը. Հաստատեք Ձեր նոր էլ. հասցեն %{site_name} -ի համար՝ սեղմելով հետևյալ հղումը.
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-new-email/%{email_token}
confirm_old_email: confirm_old_email:
title: "Հաստատել Հին Էլ. Հասցեն" title: "Հաստատել Հին Էլ. Հասցեն"
subject_template: "[%{email_prefix}] Հաստատել Ձեր ընթացիկ էլ. հասցեն" subject_template: "[%{email_prefix}] Հաստատել Ձեր ընթացիկ էլ. հասցեն"

View File

@ -2862,7 +2862,7 @@ it:
text_body_template: | text_body_template: |
Conferma il tuo nuovo indirizzo email su %{site_name} cliccando il seguente collegamento: Conferma il tuo nuovo indirizzo email su %{site_name} cliccando il seguente collegamento:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-new-email/%{email_token}
confirm_old_email: confirm_old_email:
title: "Conferma Vecchia Email" title: "Conferma Vecchia Email"
subject_template: "[%{email_prefix}] Conferma il tuo attuale indirizzo email" subject_template: "[%{email_prefix}] Conferma il tuo attuale indirizzo email"
@ -2873,7 +2873,7 @@ it:
Conferma il tuo attuale indirizzo email su %{site_name} cliccando il seguente collegamento: Conferma il tuo attuale indirizzo email su %{site_name} cliccando il seguente collegamento:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-old-email/%{email_token}
notify_old_email: notify_old_email:
title: "Notifica Vecchia Email" title: "Notifica Vecchia Email"
subject_template: "[%{email_prefix}] Il tuo indirizzo email è stato cambiato" subject_template: "[%{email_prefix}] Il tuo indirizzo email è stato cambiato"

View File

@ -1300,7 +1300,7 @@ ja:
text_body_template: | text_body_template: |
%{site_name}への新しいメールアドレスを下のリンクから確認してください。 %{site_name}への新しいメールアドレスを下のリンクから確認してください。
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-new-email/%{email_token}
confirm_old_email: confirm_old_email:
title: "古いメールの確認" title: "古いメールの確認"
subject_template: "[%{email_prefix}]現在のメールアドレスの確認" subject_template: "[%{email_prefix}]現在のメールアドレスの確認"

View File

@ -2313,7 +2313,7 @@ pl_PL:
text_body_template: | text_body_template: |
Potwierdź swój nowy adres email dla %{site_name} poprzez kliknięcia na następujący link: Potwierdź swój nowy adres email dla %{site_name} poprzez kliknięcia na następujący link:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-new-email/%{email_token}
confirm_old_email: confirm_old_email:
title: "Potwierdź stary email" title: "Potwierdź stary email"
subject_template: "[%{site_name}] Potwierdź aktualny adres email" subject_template: "[%{site_name}] Potwierdź aktualny adres email"
@ -2322,7 +2322,7 @@ pl_PL:
Potwierdź obecny adres email dla %{site_name}poprzez naciśnięcie na następujący link: Potwierdź obecny adres email dla %{site_name}poprzez naciśnięcie na następujący link:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-old-email/%{email_token}
notify_old_email: notify_old_email:
title: "Powiadom Stary Email" title: "Powiadom Stary Email"
subject_template: "[%{site_name}] Twój adres email został zmieniony" subject_template: "[%{site_name}] Twój adres email został zmieniony"

View File

@ -2925,11 +2925,11 @@ pt_BR:
text_body_template: | text_body_template: |
Confirme seu novo endereço de e-mail para %{site_name} clicando no seguinte link: Confirme seu novo endereço de e-mail para %{site_name} clicando no seguinte link:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-new-email/%{email_token}
confirm_old_email: confirm_old_email:
title: "Confirmar Antigo e-mail" title: "Confirmar Antigo e-mail"
subject_template: "[%{email_prefix}] Confirme seu endereço de e-mail atual" subject_template: "[%{email_prefix}] Confirme seu endereço de e-mail atual"
text_body_template: "Antes que possamos alterar seu endereço de e-mail, precisamos que você confirme que você controla a conta de e-mail atual. \nDepois de concluir esta etapa, você terá que confirmar\no novo endereço de e-mail.\n\nConfirme seu endereço de e-mail atual para %{site_name} clicando no seguinte link:\n\n%{base_url}/u/authorize-email/%{email_token}\n" text_body_template: "Antes que possamos alterar seu endereço de e-mail, precisamos que você confirme que você controla a conta de e-mail atual. \nDepois de concluir esta etapa, você terá que confirmar\no novo endereço de e-mail.\n\nConfirme seu endereço de e-mail atual para %{site_name} clicando no seguinte link:\n\n%{base_url}/u/confirm-old-email/%{email_token}\n"
notify_old_email: notify_old_email:
title: "Notificar e-mail antigo" title: "Notificar e-mail antigo"
subject_template: "[%{email_prefix}] Seu endereço de e-mail foi alterado" subject_template: "[%{email_prefix}] Seu endereço de e-mail foi alterado"

View File

@ -2217,7 +2217,7 @@ ru:
text_body_template: | text_body_template: |
Подтвердите ваш новый адрес e-mail почты для %{site_name} нажав на следующую ссылку: Подтвердите ваш новый адрес e-mail почты для %{site_name} нажав на следующую ссылку:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-new-email/%{email_token}
confirm_old_email: confirm_old_email:
text_body_template: | text_body_template: |
Прежде чем мы сможем изменить ваш адрес электронной почты, нам нужно, чтобы вы подтвердили, что вы контролируете Прежде чем мы сможем изменить ваш адрес электронной почты, нам нужно, чтобы вы подтвердили, что вы контролируете
@ -2226,7 +2226,7 @@ ru:
Подтвердите свой текущий адрес e-mail почты для %{site_name} нажав на следующую ссылку: Подтвердите свой текущий адрес e-mail почты для %{site_name} нажав на следующую ссылку:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-old-email/%{email_token}
signup_after_approval: signup_after_approval:
title: "Регистрация После Утверждения" title: "Регистрация После Утверждения"
subject_template: "Ваша учетная запись на сайте %{site_name} одобрена!" subject_template: "Ваша учетная запись на сайте %{site_name} одобрена!"

View File

@ -1659,7 +1659,7 @@ sl:
text_body_template: | text_body_template: |
Potrdite vaš nov e-naslov pri %{site_name} tako da sledite povezavi: Potrdite vaš nov e-naslov pri %{site_name} tako da sledite povezavi:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-new-email/%{email_token}
confirm_old_email: confirm_old_email:
title: "Potrdite star e-naslov" title: "Potrdite star e-naslov"
subject_template: "[%{email_prefix}] Potrdite vaš trenutni e-naslov" subject_template: "[%{email_prefix}] Potrdite vaš trenutni e-naslov"
@ -1668,7 +1668,7 @@ sl:
Potrdite vaš trenutni e-naslov pri %{site_name} tako da sledite povezavi: Potrdite vaš trenutni e-naslov pri %{site_name} tako da sledite povezavi:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-old-email/%{email_token}
notify_old_email: notify_old_email:
title: "Obvesti stari e-naslov" title: "Obvesti stari e-naslov"
subject_template: "[%{email_prefix}] Vaš e-naslov je bil spremenjen" subject_template: "[%{email_prefix}] Vaš e-naslov je bil spremenjen"

View File

@ -1163,7 +1163,7 @@ sq:
text_body_template: | text_body_template: |
Konfirmoni adresën tuaj të re të emailit për "%{site_name}" duke klikuar linkun më poshtë: Konfirmoni adresën tuaj të re të emailit për "%{site_name}" duke klikuar linkun më poshtë:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-new-email/%{email_token}
confirm_old_email: confirm_old_email:
subject_template: "[%{email_prefix}] Konfirmoni adresën e tanishme të emailit " subject_template: "[%{email_prefix}] Konfirmoni adresën e tanishme të emailit "
notify_old_email: notify_old_email:

View File

@ -2434,7 +2434,7 @@ uk:
text_body_template: | text_body_template: |
Підтвердіть свою нову електронну адресу для %{site_name} натиснувши наступне посилання: Підтвердіть свою нову електронну адресу для %{site_name} натиснувши наступне посилання:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-new-email/%{email_token}
confirm_old_email: confirm_old_email:
title: "Підтвердіть стару електронну пошту" title: "Підтвердіть стару електронну пошту"
subject_template: "[%{email_prefix}] Підтвердіть свою поточну адресу електроної пошти" subject_template: "[%{email_prefix}] Підтвердіть свою поточну адресу електроної пошти"

View File

@ -3033,7 +3033,7 @@ ur:
text_body_template: | text_body_template: |
%{site_name} پر اپنے نئے ای میل ایڈریس کی تصدیق کرنے کیلئے مندرجہ ذیل لِنک پر کلِک کریں: %{site_name} پر اپنے نئے ای میل ایڈریس کی تصدیق کرنے کیلئے مندرجہ ذیل لِنک پر کلِک کریں:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-new-email/%{email_token}
confirm_old_email: confirm_old_email:
title: "پرانی ای میل تصدیق" title: "پرانی ای میل تصدیق"
subject_template: "[%{email_prefix}] اپنا موجودہ ای میل ایڈریس تصدیق کریں" subject_template: "[%{email_prefix}] اپنا موجودہ ای میل ایڈریس تصدیق کریں"
@ -3044,7 +3044,7 @@ ur:
%{site_name} پر اپنے موجودہ ای میل ایڈریس کی تصدیق کرنے کیلئے مندرجہ ذیل لِنک پر کلک کریں: %{site_name} پر اپنے موجودہ ای میل ایڈریس کی تصدیق کرنے کیلئے مندرجہ ذیل لِنک پر کلک کریں:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-old-email/%{email_token}
notify_old_email: notify_old_email:
title: "پرانا ای میل مطلع" title: "پرانا ای میل مطلع"
subject_template: "[%{email_prefix}] آپ کا ای میل ایڈریس تبدیل ہوگیا ہے" subject_template: "[%{email_prefix}] آپ کا ای میل ایڈریس تبدیل ہوگیا ہے"

View File

@ -3013,7 +3013,7 @@ zh_CN:
text_body_template: | text_body_template: |
点击下面的链接来确认你在%{site_name}上的新电子邮箱地址: 点击下面的链接来确认你在%{site_name}上的新电子邮箱地址:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-new-email/%{email_token}
confirm_old_email: confirm_old_email:
title: "确认旧邮箱" title: "确认旧邮箱"
subject_template: "[%{email_prefix}] 确认你现在的电子邮箱地址" subject_template: "[%{email_prefix}] 确认你现在的电子邮箱地址"
@ -3022,7 +3022,7 @@ zh_CN:
点击下面的链接来确认你在%{site_name}正使用的邮件: 点击下面的链接来确认你在%{site_name}正使用的邮件:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-old-email/%{email_token}
notify_old_email: notify_old_email:
title: "通知旧邮箱" title: "通知旧邮箱"
subject_template: "[%{email_prefix}] 你的邮箱已经修改成功" subject_template: "[%{email_prefix}] 你的邮箱已经修改成功"

View File

@ -2810,7 +2810,7 @@ zh_TW:
text_body_template: | text_body_template: |
點擊以下連結,確認你 %{site_name} 的新郵件地址: 點擊以下連結,確認你 %{site_name} 的新郵件地址:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-new-email/%{email_token}
confirm_old_email: confirm_old_email:
title: "確認原郵件地址" title: "確認原郵件地址"
subject_template: "[%{email_prefix}] 確認你的現行郵件地址" subject_template: "[%{email_prefix}] 確認你的現行郵件地址"
@ -2820,7 +2820,7 @@ zh_TW:
點擊下面的連結,以確認你當前在 %{site_name} 的郵件地址: 點擊下面的連結,以確認你當前在 %{site_name} 的郵件地址:
%{base_url}/u/authorize-email/%{email_token} %{base_url}/u/confirm-old-email/%{email_token}
notify_old_email: notify_old_email:
title: "通知原郵件地址" title: "通知原郵件地址"
subject_template: "[%{email_prefix}] 已變更你的郵件地址" subject_template: "[%{email_prefix}] 已變更你的郵件地址"

View File

@ -408,8 +408,13 @@ Discourse::Application.routes.draw do
put "#{root_path}/password-reset/:token" => "users#password_reset" put "#{root_path}/password-reset/:token" => "users#password_reset"
get "#{root_path}/activate-account/:token" => "users#activate_account" get "#{root_path}/activate-account/:token" => "users#activate_account"
put({ "#{root_path}/activate-account/:token" => "users#perform_account_activation" }.merge(index == 1 ? { as: 'perform_activate_account' } : {})) put({ "#{root_path}/activate-account/:token" => "users#perform_account_activation" }.merge(index == 1 ? { as: 'perform_activate_account' } : {}))
get "#{root_path}/authorize-email/:token" => "users_email#confirm"
put "#{root_path}/authorize-email/:token" => "users_email#confirm" get "#{root_path}/confirm-old-email/:token" => "users_email#show_confirm_old_email"
put "#{root_path}/confirm-old-email" => "users_email#confirm_old_email"
get "#{root_path}/confirm-new-email/:token" => "users_email#show_confirm_new_email"
put "#{root_path}/confirm-new-email" => "users_email#confirm_new_email"
get({ get({
"#{root_path}/confirm-admin/:token" => "users#confirm_admin", "#{root_path}/confirm-admin/:token" => "users#confirm_admin",
constraints: { token: /[0-9a-f]+/ } constraints: { token: /[0-9a-f]+/ }

View File

@ -4,72 +4,65 @@ require 'rails_helper'
describe UsersEmailController do describe UsersEmailController do
describe '#confirm' do fab!(:user) { Fabricate(:user) }
fab!(:moderator) { Fabricate(:moderator) }
describe "#confirm-new-email" do
it 'redirects to login for signed out accounts' do
get "/u/confirm-new-email/asdfasdf"
expect(response.status).to eq(302)
expect(response.redirect_url).to eq("http://test.localhost/login")
end
it 'errors out for invalid tokens' do it 'errors out for invalid tokens' do
get "/u/authorize-email/asdfasdf" sign_in(user)
get "/u/confirm-new-email/asdfasdf"
expect(response.status).to eq(200) expect(response.status).to eq(200)
expect(response.body).to include(I18n.t('change_email.already_done')) expect(response.body).to include(I18n.t('change_email.already_done'))
end end
context 'valid old address token' do it 'does not change email if accounts mismatch' do
fab!(:user) { Fabricate(:moderator) } updater = EmailUpdater.new(user.guardian, user)
let(:updater) { EmailUpdater.new(user.guardian, user) }
before do
updater.change_to('new.n.cool@example.com') updater.change_to('new.n.cool@example.com')
old_email = user.email
sign_in(moderator)
put "/u/confirm-new-email", params: {
token: "#{user.email_tokens.last.token}"
}
user.reload
expect(user.email).to eq(old_email)
end end
it 'confirms with a correct token' do context "with a valid user" do
get "/u/authorize-email/#{user.email_tokens.last.token}"
expect(response.status).to eq(200)
body = CGI.unescapeHTML(response.body)
expect(body)
.to include(I18n.t('change_email.authorizing_old.title'))
expect(body)
.to include(I18n.t('change_email.authorizing_old.description'))
end
end
context 'valid new address token' do
fab!(:user) { Fabricate(:user) }
let(:updater) { EmailUpdater.new(user.guardian, user) } let(:updater) { EmailUpdater.new(user.guardian, user) }
before do before do
sign_in(user)
updater.change_to('new.n.cool@example.com') updater.change_to('new.n.cool@example.com')
end end
it 'confirms with a correct token' do it 'confirms with a correct token' do
user.user_stat.update_columns(bounce_score: 42, reset_bounce_score_after: 1.week.from_now) user.user_stat.update_columns(bounce_score: 42, reset_bounce_score_after: 1.week.from_now)
events = DiscourseEvent.track_events do put "/u/confirm-new-email", params: {
get "/u/authorize-email/#{user.email_tokens.last.token}" token: "#{user.email_tokens.last.token}"
end }
expect(events.map { |event| event[:event_name] }).to include( expect(response.status).to eq(302)
:user_logged_in, :user_first_logged_in expect(response.redirect_url).to include("done")
)
expect(response.status).to eq(200)
expect(response.body).to include(I18n.t('change_email.confirmed'))
user.reload user.reload
expect(user.user_stat.bounce_score).to eq(0) expect(user.user_stat.bounce_score).to eq(0)
expect(user.user_stat.reset_bounce_score_after).to eq(nil) expect(user.user_stat.reset_bounce_score_after).to eq(nil)
end expect(user.email).to eq("new.n.cool@example.com")
it 'automatically adds the user to a group when the email matches' do
group = Fabricate(:group, automatic_membership_email_domains: "example.com")
get "/u/authorize-email/#{user.email_tokens.last.token}"
expect(response.status).to eq(200)
expect(group.reload.users.include?(user)).to eq(true)
end end
context 'second factor required' do context 'second factor required' do
@ -77,7 +70,7 @@ describe UsersEmailController do
fab!(:backup_code) { Fabricate(:user_second_factor_backup, user: user) } fab!(:backup_code) { Fabricate(:user_second_factor_backup, user: user) }
it 'requires a second factor token' do it 'requires a second factor token' do
get "/u/authorize-email/#{user.email_tokens.last.token}" get "/u/confirm-new-email/#{user.email_tokens.last.token}"
expect(response.status).to eq(200) expect(response.status).to eq(200)
@ -88,7 +81,7 @@ describe UsersEmailController do
end end
it 'requires a backup token' do it 'requires a backup token' do
get "/u/authorize-email/#{user.email_tokens.last.token}?show_backup=true" get "/u/confirm-new-email/#{user.email_tokens.last.token}?show_backup=true"
expect(response.status).to eq(200) expect(response.status).to eq(200)
@ -98,34 +91,94 @@ describe UsersEmailController do
end end
it 'adds an error on a second factor attempt' do it 'adds an error on a second factor attempt' do
get "/u/authorize-email/#{user.email_tokens.last.token}", params: { put "/u/confirm-new-email", params: {
token: user.email_tokens.last.token,
second_factor_token: "000000", second_factor_token: "000000",
second_factor_method: UserSecondFactor.methods[:totp] second_factor_method: UserSecondFactor.methods[:totp]
} }
expect(response.status).to eq(200) expect(response.status).to eq(302)
expect(response.body).to include(I18n.t("login.invalid_second_factor_code")) expect(flash[:invalid_second_factor]).to eq(true)
end end
it 'confirms with a correct second token' do it 'confirms with a correct second token' do
get "/u/authorize-email/#{user.email_tokens.last.token}", params: { put "/u/confirm-new-email", params: {
second_factor_token: ROTP::TOTP.new(second_factor.data).now, second_factor_token: ROTP::TOTP.new(second_factor.data).now,
second_factor_method: UserSecondFactor.methods[:totp] second_factor_method: UserSecondFactor.methods[:totp],
token: user.email_tokens.last.token
} }
expect(response.status).to eq(302)
user.reload
expect(user.email).to eq("new.n.cool@example.com")
end
end
end
end
describe '#confirm-old-email' do
it 'redirects to login for signed out accounts' do
get "/u/confirm-old-email/asdfasdf"
expect(response.status).to eq(302)
expect(response.redirect_url).to eq("http://test.localhost/login")
end
it 'errors out for invalid tokens' do
sign_in(user)
get "/u/confirm-old-email/asdfasdf"
expect(response.status).to eq(200)
expect(response.body).to include(I18n.t('change_email.already_done'))
end
it 'bans change when accounts do not match' do
sign_in(user)
updater = EmailUpdater.new(moderator.guardian, moderator)
updater.change_to('new.n.cool@example.com')
get "/u/confirm-old-email/#{moderator.email_tokens.last.token}"
expect(response.status).to eq(200)
expect(body).to include("alert-error")
end
context 'valid old address token' do
it 'confirms with a correct token' do
# NOTE: only moderators need to confirm both old and new
sign_in(moderator)
updater = EmailUpdater.new(moderator.guardian, moderator)
updater.change_to('new.n.cool@example.com')
get "/u/confirm-old-email/#{moderator.email_tokens.last.token}"
expect(response.status).to eq(200) expect(response.status).to eq(200)
response_body = response.body body = CGI.unescapeHTML(response.body)
expect(body)
.to include(I18n.t('change_email.authorizing_old.title'))
expect(body)
.to include(I18n.t('change_email.authorizing_old.description'))
put "/u/confirm-old-email", params: {
token: moderator.email_tokens.last.token
}
expect(response.status).to eq(302)
expect(response.redirect_url).to include("done=true")
expect(response_body).not_to include(I18n.t("login.second_factor_title"))
expect(response_body).not_to include(I18n.t("login.invalid_second_factor_code"))
end
end end
end end
end end
describe '#update' do describe '#update' do
fab!(:user) { Fabricate(:user) }
let(:new_email) { 'bubblegum@adventuretime.ooo' } let(:new_email) { 'bubblegum@adventuretime.ooo' }
it "requires you to be logged in" do it "requires you to be logged in" do