2024-01-30 18:32:42 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
describe "Changing email", type: :system do
|
|
|
|
fab!(:password) { "mysupersecurepassword" }
|
|
|
|
fab!(:user) { Fabricate(:user, active: true, password: password) }
|
|
|
|
let(:new_email) { "newemail@example.com" }
|
|
|
|
let(:user_preferences_security_page) { PageObjects::Pages::UserPreferencesSecurity.new }
|
2024-02-22 10:46:37 +08:00
|
|
|
let(:user_preferences_page) { PageObjects::Pages::UserPreferences.new }
|
2024-01-30 18:32:42 +08:00
|
|
|
|
|
|
|
before { Jobs.run_immediately! }
|
|
|
|
|
|
|
|
def generate_confirm_link
|
|
|
|
visit "/my/preferences/account"
|
|
|
|
|
|
|
|
email_dropdown = PageObjects::Components::SelectKit.new(".email-dropdown")
|
|
|
|
expect(email_dropdown.visible?).to eq(true)
|
|
|
|
email_dropdown.select_row_by_value("updateEmail")
|
|
|
|
|
|
|
|
find("#change-email").fill_in with: "newemail@example.com"
|
|
|
|
|
|
|
|
find(".save-button button").click
|
|
|
|
|
2024-02-01 22:11:37 +08:00
|
|
|
wait_for(timeout: Capybara.default_max_wait_time) { ActionMailer::Base.deliveries.count === 1 }
|
2024-01-30 18:32:42 +08:00
|
|
|
|
|
|
|
if user.admin?
|
|
|
|
get_link_from_email(:old)
|
|
|
|
else
|
|
|
|
get_link_from_email(:new)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def get_link_from_email(type)
|
|
|
|
mail = ActionMailer::Base.deliveries.last
|
|
|
|
expect(mail.to).to contain_exactly(type == :new ? new_email : user.email)
|
|
|
|
|
|
|
|
mail.body.to_s[%r{/u/confirm-#{type}-email/\S+}, 0]
|
|
|
|
end
|
|
|
|
|
|
|
|
it "allows regular user to change their email" do
|
|
|
|
sign_in user
|
|
|
|
|
|
|
|
visit generate_confirm_link
|
|
|
|
|
|
|
|
find(".confirm-new-email .btn-primary").click
|
|
|
|
|
|
|
|
expect(page).to have_css(".dialog-body", text: I18n.t("js.user.change_email.confirm_success"))
|
|
|
|
find(".dialog-footer .btn-primary").click
|
|
|
|
|
2024-02-22 10:46:37 +08:00
|
|
|
expect(page).to have_current_path("/u/#{user.username}/preferences/account")
|
|
|
|
expect(user_preferences_page).to have_primary_email(new_email)
|
2024-01-30 18:32:42 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it "works when user has totp 2fa" do
|
|
|
|
second_factor = Fabricate(:user_second_factor_totp, user: user)
|
|
|
|
sign_in user
|
|
|
|
|
|
|
|
visit generate_confirm_link
|
|
|
|
|
|
|
|
find(".confirm-new-email .btn-primary").click
|
|
|
|
|
|
|
|
find(".second-factor-token-input").fill_in with: second_factor.totp_object.now
|
|
|
|
|
|
|
|
find("button[type=submit]").click
|
|
|
|
|
2024-02-22 10:46:37 +08:00
|
|
|
expect(page).to have_current_path("/u/#{user.username}/preferences/account")
|
|
|
|
expect(user_preferences_page).to have_primary_email(new_email)
|
2024-01-30 18:32:42 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it "works when user has webauthn 2fa" do
|
2024-02-16 01:29:16 +08:00
|
|
|
# enforced 2FA flow needs a user created > 5 minutes ago
|
|
|
|
user.created_at = 6.minutes.ago
|
|
|
|
user.save!
|
|
|
|
|
2024-01-30 18:32:42 +08:00
|
|
|
sign_in user
|
|
|
|
|
|
|
|
DiscourseWebauthn.stubs(:origin).returns(current_host + ":" + Capybara.server_port.to_s)
|
|
|
|
options =
|
|
|
|
::Selenium::WebDriver::VirtualAuthenticatorOptions.new(
|
|
|
|
user_verification: true,
|
|
|
|
user_verified: true,
|
|
|
|
resident_key: true,
|
|
|
|
)
|
|
|
|
authenticator = page.driver.browser.add_virtual_authenticator(options)
|
|
|
|
|
|
|
|
user_preferences_security_page.visit(user)
|
|
|
|
user_preferences_security_page.visit_second_factor(password)
|
|
|
|
|
|
|
|
find(".security-key .new-security-key").click
|
|
|
|
expect(user_preferences_security_page).to have_css("input#security-key-name")
|
|
|
|
|
|
|
|
find(".d-modal__body input#security-key-name").fill_in(with: "First Key")
|
|
|
|
find(".add-security-key").click
|
|
|
|
|
|
|
|
expect(user_preferences_security_page).to have_css(".security-key .second-factor-item")
|
|
|
|
|
|
|
|
visit generate_confirm_link
|
|
|
|
|
|
|
|
find(".confirm-new-email .btn-primary").click
|
|
|
|
|
|
|
|
find("#security-key-authenticate-button").click
|
|
|
|
|
2024-02-22 10:46:37 +08:00
|
|
|
expect(page).to have_current_path("/u/#{user.username}/preferences/account")
|
|
|
|
expect(user_preferences_page).to have_primary_email(new_email)
|
2024-02-01 22:11:18 +08:00
|
|
|
ensure
|
2024-06-06 14:30:42 +08:00
|
|
|
authenticator&.remove!
|
2024-01-30 18:32:42 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
it "does not require login to verify" do
|
|
|
|
second_factor = Fabricate(:user_second_factor_totp, user: user)
|
|
|
|
sign_in user
|
|
|
|
|
|
|
|
confirm_link = generate_confirm_link
|
|
|
|
|
|
|
|
Capybara.reset_sessions! # log out
|
|
|
|
|
|
|
|
visit confirm_link
|
|
|
|
|
|
|
|
find(".confirm-new-email .btn-primary").click
|
|
|
|
|
|
|
|
find(".second-factor-token-input").fill_in with: second_factor.totp_object.now
|
|
|
|
|
|
|
|
find("button[type=submit]").click
|
|
|
|
|
2024-02-22 10:46:37 +08:00
|
|
|
expect(page).to have_current_path("/latest")
|
2024-01-30 18:32:42 +08:00
|
|
|
expect(user.reload.email).to eq(new_email)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "makes admins verify old email" do
|
|
|
|
user.update!(admin: true)
|
|
|
|
sign_in user
|
|
|
|
|
|
|
|
confirm_old_link = generate_confirm_link
|
|
|
|
|
|
|
|
# Confirm old email
|
|
|
|
visit confirm_old_link
|
|
|
|
find(".confirm-old-email .btn-primary").click
|
|
|
|
expect(page).to have_css(
|
|
|
|
".dialog-body",
|
|
|
|
text: I18n.t("js.user.change_email.authorizing_old.confirm_success"),
|
|
|
|
)
|
|
|
|
find(".dialog-footer .btn-primary").click
|
|
|
|
|
|
|
|
# Confirm new email
|
2024-02-01 22:11:37 +08:00
|
|
|
wait_for(timeout: Capybara.default_max_wait_time) { ActionMailer::Base.deliveries.count === 2 }
|
2024-01-30 18:32:42 +08:00
|
|
|
confirm_new_link = get_link_from_email(:new)
|
|
|
|
|
|
|
|
visit confirm_new_link
|
|
|
|
|
|
|
|
find(".confirm-new-email .btn-primary").click
|
|
|
|
|
|
|
|
expect(page).to have_css(".dialog-body", text: I18n.t("js.user.change_email.confirm_success"))
|
|
|
|
find(".dialog-footer .btn-primary").click
|
|
|
|
|
|
|
|
expect(user.reload.email).to eq(new_email)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "allows admin to verify old email while logged out" do
|
|
|
|
user.update!(admin: true)
|
|
|
|
sign_in user
|
|
|
|
|
|
|
|
confirm_old_link = generate_confirm_link
|
|
|
|
|
|
|
|
Capybara.reset_sessions! # log out
|
|
|
|
|
|
|
|
# Confirm old email
|
|
|
|
visit confirm_old_link
|
|
|
|
find(".confirm-old-email .btn-primary").click
|
|
|
|
expect(page).to have_css(
|
|
|
|
".dialog-body",
|
|
|
|
text: I18n.t("js.user.change_email.authorizing_old.confirm_success"),
|
|
|
|
)
|
|
|
|
find(".dialog-footer .btn-primary").click
|
|
|
|
|
|
|
|
# Confirm new email
|
2024-02-01 22:11:37 +08:00
|
|
|
wait_for(timeout: Capybara.default_max_wait_time) { ActionMailer::Base.deliveries.count === 2 }
|
2024-01-30 18:32:42 +08:00
|
|
|
confirm_new_link = get_link_from_email(:new)
|
|
|
|
|
|
|
|
visit confirm_new_link
|
|
|
|
|
|
|
|
find(".confirm-new-email .btn-primary").click
|
|
|
|
|
|
|
|
expect(page).to have_css(".dialog-body", text: I18n.t("js.user.change_email.confirm_success"))
|
|
|
|
find(".dialog-footer .btn-primary").click
|
|
|
|
|
|
|
|
expect(user.reload.email).to eq(new_email)
|
|
|
|
end
|
|
|
|
end
|