diff --git a/doc/reset_password.rdoc b/doc/reset_password.rdoc index 63bd94ae..293a572e 100644 --- a/doc/reset_password.rdoc +++ b/doc/reset_password.rdoc @@ -23,6 +23,7 @@ reset_password_email_subject :: The subject to use for the reset password reques reset_password_error_flash :: The flash error to show after resetting a password. reset_password_explanatory_text :: The text to display above the button to request a password reset. reset_password_id_column :: The id column in the +reset_password_table+, should be a foreign key referencing the accounts table. +reset_password_implicitly_verifies? :: Whether resetting a password for an unverified account implicitly verifies the account, false by default. reset_password_key_column :: The reset password key/token column in the +reset_password_table+. reset_password_key_param :: The parameter name to use for the reset password key. reset_password_notice_flash :: The flash notice to show after resetting a password. diff --git a/lib/rodauth/features/reset_password.rb b/lib/rodauth/features/reset_password.rb index 17703335..ab7351e9 100644 --- a/lib/rodauth/features/reset_password.rb +++ b/lib/rodauth/features/reset_password.rb @@ -32,6 +32,7 @@ module Rodauth auth_value_method :reset_password_deadline_interval, {:days=>1}.freeze auth_value_method :reset_password_key_param, 'key' auth_value_method :reset_password_autologin?, false + auth_value_method :reset_password_implicitly_verifies?, false auth_value_method :reset_password_table, :account_password_reset_keys auth_value_method :reset_password_id_column, :id auth_value_method :reset_password_key_column, :key @@ -174,7 +175,7 @@ def create_reset_password_key end def reset_password_request_for_unverified_account - throw_error_reason(:unverified_account, unopen_account_error_status, login_param, unverified_account_message) + throw_error_reason(:unverified_account, unopen_account_error_status, login_param, unverified_account_message) unless reset_password_implicitly_verifies? end def remove_reset_password_key @@ -231,6 +232,14 @@ def after_login_failure super end + def after_reset_password + super if defined?(super) + if reset_password_implicitly_verifies? && !open_account? + verify_account + remove_verify_account_key + end + end + def generate_reset_password_key_value @reset_password_key_value = random_key end @@ -254,7 +263,13 @@ def password_reset_ds(id=account_id) end def _account_from_reset_password_key(token) - account_from_key(token, account_open_status_value){|id| get_password_reset_key(id)} + account_from_key(token, reset_password_account_status_value){|id| get_password_reset_key(id)} + end + + def reset_password_account_status_value + statuses = [account_open_status_value] + statuses << account_unverified_status_value if reset_password_implicitly_verifies? + statuses end end end diff --git a/spec/reset_password_spec.rb b/spec/reset_password_spec.rb index aad73b24..3e697f50 100644 --- a/spec/reset_password_spec.rb +++ b/spec/reset_password_spec.rb @@ -226,6 +226,37 @@ page.current_path.must_equal '/reset-password-request' end + it "should support implicit verification when resetting passwords for unverified accounts" do + rodauth do + enable :login, :reset_password, :verify_account + reset_password_implicitly_verifies? true + reset_password_autologin? true + end + roda do |r| + r.rodauth + r.root{view :content=>rodauth.logged_in? ? "Logged In" : "Not Logged"} + end + + DB[:accounts].update(:status_id=>1) + DB[:account_verification_keys].insert(:id=>DB[:accounts].get(:id), :key=>'test') + + visit '/reset-password-request' + fill_in 'Login', :with=>'foo@example.com' + click_button 'Request Password Reset' + page.find('#notice_flash').text.must_equal "An email has been sent to you with a link to reset the password for your account" + + link = email_link(/(\/reset-password\?key=.+)$/) + visit link + fill_in 'Password', :with=>'0123456' + fill_in 'Confirm Password', :with=>'0123456' + click_button 'Reset Password' + page.find('#notice_flash').text.must_equal "Your password has been reset" + page.body.must_include("Logged In") + + DB[:accounts].get(:status_id).must_equal 2 + DB[:account_verification_keys].count.must_equal 0 + end + [true, false].each do |before| it "should clear reset password token when closing account, when loading reset_password #{before ? "before" : "after"}" do rodauth do