Skip to content
Permalink
Browse files Browse the repository at this point in the history
Merge pull request from GHSA-8qpf-wf2p-25vg
Stop persisting unconfirmed_email when generating a new confirmation token
  • Loading branch information
segiddins committed Sep 1, 2022
2 parents f4e4bf7 + 5d09d49 commit 90c9e6a
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 5 deletions.
4 changes: 2 additions & 2 deletions app/controllers/email_confirmations_controller.rb
Expand Up @@ -31,15 +31,15 @@ def create
user = find_user_for_create

if user
user.generate_confirmation_token
user.generate_confirmation_token(reset_unconfirmed_email: false)
Delayed::Job.enqueue(EmailConfirmationMailer.new(user.id)) if user.save
end
redirect_to root_path, notice: t(".promise_resend")
end

# used to resend confirmation mail for unconfirmed_email validation
def unconfirmed
if current_user.generate_confirmation_token && current_user.save
if current_user.generate_confirmation_token(reset_unconfirmed_email: false) && current_user.save
Delayed::Job.enqueue EmailResetMailer.new(current_user.id)
flash[:notice] = t("profiles.update.confirmation_mail_sent")
else
Expand Down
11 changes: 8 additions & 3 deletions app/models/user.rb
Expand Up @@ -15,8 +15,8 @@ class User < ApplicationRecord
twitter_username
].freeze

before_save :generate_confirmation_token, if: :will_save_change_to_unconfirmed_email?
before_create :generate_confirmation_token
before_save :_generate_confirmation_token_no_reset_unconfirmed_email, if: :will_save_change_to_unconfirmed_email?
before_create :_generate_confirmation_token_no_reset_unconfirmed_email
before_destroy :yank_gems

has_many :ownerships, -> { confirmed }, dependent: :destroy, inverse_of: :user
Expand Down Expand Up @@ -171,11 +171,16 @@ def valid_confirmation_token?
token_expires_at > Time.zone.now
end

def generate_confirmation_token
def generate_confirmation_token(reset_unconfirmed_email: true)
self.unconfirmed_email = nil if reset_unconfirmed_email
self.confirmation_token = Clearance::Token.new
self.token_expires_at = Time.zone.now + Gemcutter::EMAIL_TOKEN_EXPRIES_AFTER
end

def _generate_confirmation_token_no_reset_unconfirmed_email
generate_confirmation_token(reset_unconfirmed_email: false)
end

def unconfirmed?
!email_confirmed
end
Expand Down
32 changes: 32 additions & 0 deletions test/integration/password_reset_test.rb
Expand Up @@ -96,4 +96,36 @@ def forgot_password_with(email)

assert page.has_content?("Sign out")
end

test "resetting password with pending email change" do
visit sign_in_path

email = @user.email
new_email = "hijack@example.com"

fill_in "Email or Username", with: email
fill_in "Password", with: @user.password
click_button "Sign in"

visit edit_profile_path

fill_in "Username", with: "username"
fill_in "Email address", with: new_email
fill_in "Password", with: @user.password
perform_enqueued_jobs { click_button "Update" }

assert_equal new_email, @user.reload.unconfirmed_email

click_link "Sign out"

forgot_password_with email

assert_nil @user.reload.unconfirmed_email

token = /edit\?token=(.+)$/.match(password_reset_link)[1]
visit update_email_confirmations_path(token: token)

assert @user.reload.authenticated? PasswordHelpers::SECURE_TEST_PASSWORD
assert_equal email, @user.email
end
end

0 comments on commit 90c9e6a

Please sign in to comment.