From 95049fdd5e96e046e7ab8309a3a739d3cd94b497 Mon Sep 17 00:00:00 2001 From: erdgeist Date: Thu, 16 Jul 2026 19:45:42 +0200 Subject: Implement transparent password hash migration Add has_secure_password and bcrypt while retaining compatibility with legacy SHA-1 password hashes. Existing users are upgraded to password_digest on their next successful login. Add regression tests covering both legacy and modern authentication paths. --- app/models/user.rb | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) (limited to 'app/models/user.rb') diff --git a/app/models/user.rb b/app/models/user.rb index 92ac33a..5e47ae7 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,6 +1,10 @@ require 'digest/sha1' class User < ApplicationRecord + has_secure_password(validations: false) + + alias_method :authenticate_bcrypt, :authenticate + # Mixins and Plugins include Authentication include Authentication::ByPassword @@ -23,9 +27,30 @@ class User < ApplicationRecord # Authenticates a user by their login name and unencrypted password. Returns the user or nil. def self.authenticate(login, password) - return nil if login.blank? || password.blank? - u = find_by_login(login) # need to get the salt - u && u.authenticated?(password) ? u : nil + return if login.blank? || password.blank? + + user = find_by(login: login) + return unless user + + user&.authenticate(password) + end + + def authenticate(password) + if password_digest.present? + return self if authenticate_bcrypt(password) + return nil + end + + return nil unless authenticate_legacy(password) + + transaction do + self.password = password + self.crypted_password = nil + self.salt = nil + save!(validate: false) + end + + self end # TODO: Do we really want to have downcase logins only? -- cgit v1.3