]> git.openstreetmap.org Git - rails.git/commitdiff
Use rails tokens for password resets
authorTom Hughes <tom@compton.nu>
Thu, 7 Dec 2023 18:30:12 +0000 (18:30 +0000)
committerTom Hughes <tom@compton.nu>
Sat, 24 Feb 2024 13:23:19 +0000 (13:23 +0000)
.rubocop_todo.yml
app/controllers/passwords_controller.rb
app/mailers/user_mailer.rb
app/models/user.rb
test/controllers/passwords_controller_test.rb

index 9874aa3793a18cb1e65b2e9f7374ce6eabeeaeee..8c24079900b5877a2c0909c4f7a908d8e387a990 100644 (file)
@@ -66,7 +66,7 @@ Metrics/BlockNesting:
 # Offense count: 26
 # Configuration parameters: CountComments, CountAsOne.
 Metrics/ClassLength:
-  Max: 305
+  Max: 307
 
 # Offense count: 59
 # Configuration parameters: AllowedMethods, AllowedPatterns.
index 87d25df68037599c8b70d058ffbe6b257c6cf963..8025fd700977d35f82ba267c2dd9136dee2d80a4 100644 (file)
@@ -19,11 +19,10 @@ class PasswordsController < ApplicationController
     @title = t ".title"
 
     if params[:token]
-      token = UserToken.find_by(:token => params[:token])
+      self.current_user = User.find_by_token_for(:password_reset, params[:token]) ||
+                          UserToken.unexpired.find_by(:token => params[:token])&.user
 
-      if token
-        self.current_user = token.user
-      else
+      if current_user.nil?
         flash[:error] = t ".flash token bad"
         redirect_to :action => "new"
       end
@@ -42,7 +41,7 @@ class PasswordsController < ApplicationController
     end
 
     if user
-      token = user.tokens.create
+      token = user.generate_token_for(:password_reset)
       UserMailer.lost_password(user, token).deliver_later
       flash[:notice] = t ".notice email on way"
       redirect_to login_path
@@ -54,11 +53,10 @@ class PasswordsController < ApplicationController
 
   def update
     if params[:token]
-      token = UserToken.find_by(:token => params[:token])
-
-      if token
-        self.current_user = token.user
+      self.current_user = User.find_by_token_for(:password_reset, params[:token]) ||
+                          UserToken.unexpired.find_by(:token => params[:token])&.user
 
+      if current_user
         if params[:user]
           current_user.pass_crypt = params[:user][:pass_crypt]
           current_user.pass_crypt_confirmation = params[:user][:pass_crypt_confirmation]
@@ -66,7 +64,7 @@ class PasswordsController < ApplicationController
           current_user.email_valid = true
 
           if current_user.save
-            token.destroy
+            UserToken.delete_by(:token => params[:token])
             session[:fingerprint] = current_user.fingerprint
             flash[:notice] = t ".flash changed"
             successful_login(current_user)
index 0894b972d7e0735d2e146054636d93a923f0b7ef..160dc1996e1cc8134bea00262a1a2c4c78c75150 100644 (file)
@@ -34,7 +34,7 @@ class UserMailer < ApplicationMailer
 
   def lost_password(user, token)
     with_recipient_locale user do
-      @url = user_reset_password_url(:token => token.token)
+      @url = user_reset_password_url(:token => token)
 
       mail :to => user.email,
            :subject => t(".subject")
index 7faf748cd8afdb5866af50915e8dcd033a8dd2c2..28a8d051ac73ee4c7f8694d58004a18871e299e7 100644 (file)
@@ -124,6 +124,10 @@ class User < ApplicationRecord
   before_save :update_tile
   after_save :spam_check
 
+  generates_token_for :password_reset, :expires_in => 1.week do
+    fingerprint
+  end
+
   def display_name_cannot_be_user_id_with_other_id
     display_name&.match(/^user_(\d+)$/i) do |m|
       errors.add :display_name, I18n.t("activerecord.errors.messages.display_name_is_user_n") unless m[1].to_i == id
index c39e8465bdcb6a73b4d75c4e9c57016406e772ac..25cfdd4e5068c87c6022533fc6c8bb4b45a0ce3a 100644 (file)
@@ -127,21 +127,21 @@ class PasswordsControllerTest < ActionDispatch::IntegrationTest
     assert_redirected_to :action => :new
 
     # Create a valid token for a user
-    token = user.tokens.create
+    token = user.generate_token_for(:password_reset)
 
     # Test a request with a valid token
-    get user_reset_password_path, :params => { :token => token.token }
+    get user_reset_password_path, :params => { :token => token }
     assert_response :success
     assert_template :edit
 
     # Test that errors are reported for erroneous submissions
-    post user_reset_password_path, :params => { :token => token.token, :user => { :pass_crypt => "new_password", :pass_crypt_confirmation => "different_password" } }
+    post user_reset_password_path, :params => { :token => token, :user => { :pass_crypt => "new_password", :pass_crypt_confirmation => "different_password" } }
     assert_response :success
     assert_template :edit
     assert_select "div.invalid-feedback"
 
     # Test setting a new password
-    post user_reset_password_path, :params => { :token => token.token, :user => { :pass_crypt => "new_password", :pass_crypt_confirmation => "new_password" } }
+    post user_reset_password_path, :params => { :token => token, :user => { :pass_crypt => "new_password", :pass_crypt_confirmation => "new_password" } }
     assert_response :redirect
     assert_redirected_to root_path
     assert_equal user.id, session[:user]