Rifiuta il riuso della password attuale in cambio e reset.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -24,6 +24,11 @@ module Admin
|
|||||||
return render :edit, status: :unprocessable_entity
|
return render :edit, status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if PasswordComplexity.same_as_current?(current_admin_account, params[:password])
|
||||||
|
flash.now[:alert] = t("admin.flash.password_same_as_current")
|
||||||
|
return render :edit, status: :unprocessable_entity
|
||||||
|
end
|
||||||
|
|
||||||
if current_admin_account.update(password: params[:password])
|
if current_admin_account.update(password: params[:password])
|
||||||
redirect_to admin_root_path, notice: t("admin.flash.password_updated")
|
redirect_to admin_root_path, notice: t("admin.flash.password_updated")
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ module Api
|
|||||||
when :too_long then "Password cannot exceed 72 characters"
|
when :too_long then "Password cannot exceed 72 characters"
|
||||||
when :too_weak
|
when :too_weak
|
||||||
"Password must include at least 3 of: lowercase, uppercase, number, symbol"
|
"Password must include at least 3 of: lowercase, uppercase, number, symbol"
|
||||||
|
when :same_as_current then "New password must be different from the current password"
|
||||||
when :mismatch then "Passwords do not match"
|
when :mismatch then "Passwords do not match"
|
||||||
else "Unable to update password"
|
else "Unable to update password"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -40,6 +40,12 @@ module Public
|
|||||||
return render :edit, status: :unprocessable_entity
|
return render :edit, status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if PasswordComplexity.same_as_current?(@user, params[:password])
|
||||||
|
flash.now[:alert] = t("flash.password_resets.password_same_as_current")
|
||||||
|
@token = params[:token]
|
||||||
|
return render :edit, status: :unprocessable_entity
|
||||||
|
end
|
||||||
|
|
||||||
@user.update!(password: params[:password])
|
@user.update!(password: params[:password])
|
||||||
@user.clear_password_reset!
|
@user.clear_password_reset!
|
||||||
redirect_to public_login_path, notice: t("flash.password_resets.password_updated")
|
redirect_to public_login_path, notice: t("flash.password_resets.password_updated")
|
||||||
|
|||||||
@@ -31,6 +31,13 @@ module PasswordComplexity
|
|||||||
matched >= REQUIRED_CLASSES
|
matched >= REQUIRED_CLASSES
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Confronta con il digest già salvato (prima di assegnare la nuova password).
|
||||||
|
def same_as_current?(record, password)
|
||||||
|
return false if password.blank? || !record.respond_to?(:authenticate)
|
||||||
|
|
||||||
|
record.authenticate(password).present?
|
||||||
|
end
|
||||||
|
|
||||||
def requirement_summary
|
def requirement_summary
|
||||||
I18n.t("password_policy.hint")
|
I18n.t("password_policy.hint")
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ module Users
|
|||||||
return Result.new(ok?: false, error: code == :blank ? :too_short : code)
|
return Result.new(ok?: false, error: code == :blank ? :too_short : code)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if PasswordComplexity.same_as_current?(@user, @password)
|
||||||
|
return Result.new(ok?: false, error: :same_as_current)
|
||||||
|
end
|
||||||
|
|
||||||
unless @user.update(password: @password)
|
unless @user.update(password: @password)
|
||||||
complexity_error = @user.errors.details[:password]&.any? { |d| d[:error] == :complexity }
|
complexity_error = @user.errors.details[:password]&.any? { |d| d[:error] == :complexity }
|
||||||
return Result.new(ok?: false, error: complexity_error ? :too_weak : :too_short)
|
return Result.new(ok?: false, error: complexity_error ? :too_weak : :too_short)
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ de:
|
|||||||
password_too_short: Das neue Passwort muss mindestens 8 Zeichen lang sein
|
password_too_short: Das neue Passwort muss mindestens 8 Zeichen lang sein
|
||||||
password_too_long: Das neue Passwort darf höchstens 72 Zeichen lang sein
|
password_too_long: Das neue Passwort darf höchstens 72 Zeichen lang sein
|
||||||
password_too_weak: Das neue Passwort muss mindestens 3 aus Kleinbuchstaben, Großbuchstaben, Zahlen und Symbolen enthalten
|
password_too_weak: Das neue Passwort muss mindestens 3 aus Kleinbuchstaben, Großbuchstaben, Zahlen und Symbolen enthalten
|
||||||
|
password_same_as_current: Das neue Passwort muss sich vom aktuellen unterscheiden
|
||||||
password_mismatch: Die Passwörter stimmen nicht überein
|
password_mismatch: Die Passwörter stimmen nicht überein
|
||||||
password_updated: Passwort aktualisiert
|
password_updated: Passwort aktualisiert
|
||||||
ops_acknowledged: Vorfall übernommen
|
ops_acknowledged: Vorfall übernommen
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ en:
|
|||||||
password_too_short: The new password must be at least 8 characters long
|
password_too_short: The new password must be at least 8 characters long
|
||||||
password_too_long: New password cannot exceed 72 characters
|
password_too_long: New password cannot exceed 72 characters
|
||||||
password_too_weak: "New password must include at least 3 of: lowercase, uppercase, numbers and symbols"
|
password_too_weak: "New password must include at least 3 of: lowercase, uppercase, numbers and symbols"
|
||||||
|
password_same_as_current: New password must be different from the current password
|
||||||
password_mismatch: Passwords do not match
|
password_mismatch: Passwords do not match
|
||||||
password_updated: Password updated
|
password_updated: Password updated
|
||||||
ops_acknowledged: Incident acknowledged
|
ops_acknowledged: Incident acknowledged
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ es:
|
|||||||
password_too_short: La nueva contraseña debe tener al menos 8 caracteres
|
password_too_short: La nueva contraseña debe tener al menos 8 caracteres
|
||||||
password_too_long: La nueva contraseña no puede superar los 72 caracteres
|
password_too_long: La nueva contraseña no puede superar los 72 caracteres
|
||||||
password_too_weak: "La nueva contraseña debe incluir al menos 3 entre: minúsculas, mayúsculas, números y símbolos"
|
password_too_weak: "La nueva contraseña debe incluir al menos 3 entre: minúsculas, mayúsculas, números y símbolos"
|
||||||
|
password_same_as_current: La nueva contraseña debe ser distinta de la actual
|
||||||
password_mismatch: Las contraseñas no coinciden
|
password_mismatch: Las contraseñas no coinciden
|
||||||
password_updated: Contraseña actualizada
|
password_updated: Contraseña actualizada
|
||||||
ops_acknowledged: Incidencia asumida
|
ops_acknowledged: Incidencia asumida
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ fr:
|
|||||||
password_too_short: Le nouveau mot de passe doit contenir au moins 8 caractères
|
password_too_short: Le nouveau mot de passe doit contenir au moins 8 caractères
|
||||||
password_too_long: Le nouveau mot de passe ne peut pas dépasser 72 caractères
|
password_too_long: Le nouveau mot de passe ne peut pas dépasser 72 caractères
|
||||||
password_too_weak: "Le nouveau mot de passe doit inclure au moins 3 parmi : minuscules, majuscules, chiffres et symboles"
|
password_too_weak: "Le nouveau mot de passe doit inclure au moins 3 parmi : minuscules, majuscules, chiffres et symboles"
|
||||||
|
password_same_as_current: "Le nouveau mot de passe doit être différent de l'actuel"
|
||||||
password_mismatch: Les mots de passe ne correspondent pas
|
password_mismatch: Les mots de passe ne correspondent pas
|
||||||
password_updated: Mot de passe mis à jour
|
password_updated: Mot de passe mis à jour
|
||||||
ops_acknowledged: Incident pris en charge
|
ops_acknowledged: Incident pris en charge
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ it:
|
|||||||
password_too_short: La nuova password deve avere almeno 8 caratteri
|
password_too_short: La nuova password deve avere almeno 8 caratteri
|
||||||
password_too_long: La nuova password non può superare i 72 caratteri
|
password_too_long: La nuova password non può superare i 72 caratteri
|
||||||
password_too_weak: "La nuova password deve includere almeno 3 tra: minuscole, maiuscole, numeri e simboli"
|
password_too_weak: "La nuova password deve includere almeno 3 tra: minuscole, maiuscole, numeri e simboli"
|
||||||
|
password_same_as_current: La nuova password deve essere diversa da quella attuale
|
||||||
password_mismatch: Le password non coincidono
|
password_mismatch: Le password non coincidono
|
||||||
password_updated: Password aggiornata
|
password_updated: Password aggiornata
|
||||||
ops_acknowledged: Incidente preso in carico
|
ops_acknowledged: Incidente preso in carico
|
||||||
|
|||||||
@@ -624,6 +624,7 @@ de:
|
|||||||
password_too_short: Das Passwort muss mindestens 8 Zeichen lang sein
|
password_too_short: Das Passwort muss mindestens 8 Zeichen lang sein
|
||||||
password_too_long: Das Passwort darf höchstens 72 Zeichen lang sein
|
password_too_long: Das Passwort darf höchstens 72 Zeichen lang sein
|
||||||
password_too_weak: Das Passwort muss mindestens 3 aus Kleinbuchstaben, Großbuchstaben, Zahlen und Symbolen enthalten
|
password_too_weak: Das Passwort muss mindestens 3 aus Kleinbuchstaben, Großbuchstaben, Zahlen und Symbolen enthalten
|
||||||
|
password_same_as_current: Das neue Passwort muss sich vom aktuellen unterscheiden
|
||||||
password_mismatch: Die Passwörter stimmen nicht überein
|
password_mismatch: Die Passwörter stimmen nicht überein
|
||||||
password_updated: Passwort aktualisiert. Du kannst dich jetzt anmelden.
|
password_updated: Passwort aktualisiert. Du kannst dich jetzt anmelden.
|
||||||
accounts:
|
accounts:
|
||||||
@@ -633,6 +634,7 @@ de:
|
|||||||
password_too_short: Das Passwort muss mindestens 8 Zeichen haben
|
password_too_short: Das Passwort muss mindestens 8 Zeichen haben
|
||||||
password_too_long: Das Passwort darf höchstens 72 Zeichen lang sein
|
password_too_long: Das Passwort darf höchstens 72 Zeichen lang sein
|
||||||
password_too_weak: Das Passwort muss mindestens 3 aus Kleinbuchstaben, Großbuchstaben, Zahlen und Symbolen enthalten
|
password_too_weak: Das Passwort muss mindestens 3 aus Kleinbuchstaben, Großbuchstaben, Zahlen und Symbolen enthalten
|
||||||
|
password_same_as_current: Das neue Passwort muss sich vom aktuellen unterscheiden
|
||||||
password_mismatch: Die Passwörter stimmen nicht überein
|
password_mismatch: Die Passwörter stimmen nicht überein
|
||||||
password_updated: Passwort aktualisiert.
|
password_updated: Passwort aktualisiert.
|
||||||
replay:
|
replay:
|
||||||
|
|||||||
@@ -624,6 +624,7 @@ en:
|
|||||||
password_too_short: Password must be at least 8 characters
|
password_too_short: Password must be at least 8 characters
|
||||||
password_too_long: Password cannot exceed 72 characters
|
password_too_long: Password cannot exceed 72 characters
|
||||||
password_too_weak: "Password must include at least 3 of: lowercase, uppercase, numbers and symbols"
|
password_too_weak: "Password must include at least 3 of: lowercase, uppercase, numbers and symbols"
|
||||||
|
password_same_as_current: New password must be different from the current password
|
||||||
password_mismatch: Passwords don't match
|
password_mismatch: Passwords don't match
|
||||||
password_updated: Password updated. You can now log in.
|
password_updated: Password updated. You can now log in.
|
||||||
accounts:
|
accounts:
|
||||||
@@ -633,6 +634,7 @@ en:
|
|||||||
password_too_short: Password must be at least 8 characters
|
password_too_short: Password must be at least 8 characters
|
||||||
password_too_long: Password cannot exceed 72 characters
|
password_too_long: Password cannot exceed 72 characters
|
||||||
password_too_weak: "Password must include at least 3 of: lowercase, uppercase, numbers and symbols"
|
password_too_weak: "Password must include at least 3 of: lowercase, uppercase, numbers and symbols"
|
||||||
|
password_same_as_current: New password must be different from the current password
|
||||||
password_mismatch: Passwords do not match
|
password_mismatch: Passwords do not match
|
||||||
password_updated: Password updated.
|
password_updated: Password updated.
|
||||||
replay:
|
replay:
|
||||||
|
|||||||
@@ -624,6 +624,7 @@ es:
|
|||||||
password_too_short: La contraseña debe tener al menos 8 caracteres
|
password_too_short: La contraseña debe tener al menos 8 caracteres
|
||||||
password_too_long: La contraseña no puede superar los 72 caracteres
|
password_too_long: La contraseña no puede superar los 72 caracteres
|
||||||
password_too_weak: "La contraseña debe incluir al menos 3 entre: minúsculas, mayúsculas, números y símbolos"
|
password_too_weak: "La contraseña debe incluir al menos 3 entre: minúsculas, mayúsculas, números y símbolos"
|
||||||
|
password_same_as_current: La nueva contraseña debe ser distinta de la actual
|
||||||
password_mismatch: Las contraseñas no coinciden
|
password_mismatch: Las contraseñas no coinciden
|
||||||
password_updated: Contraseña actualizada. Ya puedes iniciar sesión.
|
password_updated: Contraseña actualizada. Ya puedes iniciar sesión.
|
||||||
accounts:
|
accounts:
|
||||||
@@ -633,6 +634,7 @@ es:
|
|||||||
password_too_short: La contraseña debe tener al menos 8 caracteres
|
password_too_short: La contraseña debe tener al menos 8 caracteres
|
||||||
password_too_long: La contraseña no puede superar los 72 caracteres
|
password_too_long: La contraseña no puede superar los 72 caracteres
|
||||||
password_too_weak: "La contraseña debe incluir al menos 3 entre: minúsculas, mayúsculas, números y símbolos"
|
password_too_weak: "La contraseña debe incluir al menos 3 entre: minúsculas, mayúsculas, números y símbolos"
|
||||||
|
password_same_as_current: La nueva contraseña debe ser distinta de la actual
|
||||||
password_mismatch: Las contraseñas no coinciden
|
password_mismatch: Las contraseñas no coinciden
|
||||||
password_updated: Contraseña actualizada.
|
password_updated: Contraseña actualizada.
|
||||||
replay:
|
replay:
|
||||||
|
|||||||
@@ -624,6 +624,7 @@ fr:
|
|||||||
password_too_short: Le mot de passe doit comporter au moins 8 caractères
|
password_too_short: Le mot de passe doit comporter au moins 8 caractères
|
||||||
password_too_long: Le mot de passe ne peut pas dépasser 72 caractères
|
password_too_long: Le mot de passe ne peut pas dépasser 72 caractères
|
||||||
password_too_weak: "Le mot de passe doit inclure au moins 3 parmi : minuscules, majuscules, chiffres et symboles"
|
password_too_weak: "Le mot de passe doit inclure au moins 3 parmi : minuscules, majuscules, chiffres et symboles"
|
||||||
|
password_same_as_current: "Le nouveau mot de passe doit être différent de l'actuel"
|
||||||
password_mismatch: Les mots de passe ne correspondent pas
|
password_mismatch: Les mots de passe ne correspondent pas
|
||||||
password_updated: Mot de passe mis à jour. Tu peux maintenant te connecter.
|
password_updated: Mot de passe mis à jour. Tu peux maintenant te connecter.
|
||||||
accounts:
|
accounts:
|
||||||
@@ -633,6 +634,7 @@ fr:
|
|||||||
password_too_short: Le mot de passe doit contenir au moins 8 caractères
|
password_too_short: Le mot de passe doit contenir au moins 8 caractères
|
||||||
password_too_long: Le mot de passe ne peut pas dépasser 72 caractères
|
password_too_long: Le mot de passe ne peut pas dépasser 72 caractères
|
||||||
password_too_weak: "Le mot de passe doit inclure au moins 3 parmi : minuscules, majuscules, chiffres et symboles"
|
password_too_weak: "Le mot de passe doit inclure au moins 3 parmi : minuscules, majuscules, chiffres et symboles"
|
||||||
|
password_same_as_current: "Le nouveau mot de passe doit être différent de l'actuel"
|
||||||
password_mismatch: Les mots de passe ne correspondent pas
|
password_mismatch: Les mots de passe ne correspondent pas
|
||||||
password_updated: Mot de passe mis à jour.
|
password_updated: Mot de passe mis à jour.
|
||||||
replay:
|
replay:
|
||||||
|
|||||||
@@ -624,6 +624,7 @@ it:
|
|||||||
password_too_short: La password deve avere almeno 8 caratteri
|
password_too_short: La password deve avere almeno 8 caratteri
|
||||||
password_too_long: La password non può superare i 72 caratteri
|
password_too_long: La password non può superare i 72 caratteri
|
||||||
password_too_weak: "La password deve includere almeno 3 tra: minuscole, maiuscole, numeri e simboli"
|
password_too_weak: "La password deve includere almeno 3 tra: minuscole, maiuscole, numeri e simboli"
|
||||||
|
password_same_as_current: La nuova password deve essere diversa da quella attuale
|
||||||
password_too_short: La password deve avere almeno 8 caratteri
|
password_too_short: La password deve avere almeno 8 caratteri
|
||||||
password_too_long: La password non può superare i 72 caratteri
|
password_too_long: La password non può superare i 72 caratteri
|
||||||
password_too_weak: "La password deve includere almeno 3 tra: minuscole, maiuscole, numeri e simboli"
|
password_too_weak: "La password deve includere almeno 3 tra: minuscole, maiuscole, numeri e simboli"
|
||||||
@@ -636,6 +637,7 @@ it:
|
|||||||
password_too_short: La password deve avere almeno 8 caratteri
|
password_too_short: La password deve avere almeno 8 caratteri
|
||||||
password_too_long: La password non può superare i 72 caratteri
|
password_too_long: La password non può superare i 72 caratteri
|
||||||
password_too_weak: "La password deve includere almeno 3 tra: minuscole, maiuscole, numeri e simboli"
|
password_too_weak: "La password deve includere almeno 3 tra: minuscole, maiuscole, numeri e simboli"
|
||||||
|
password_same_as_current: La nuova password deve essere diversa da quella attuale
|
||||||
password_too_long: La password non può superare i 72 caratteri
|
password_too_long: La password non può superare i 72 caratteri
|
||||||
password_too_weak: "La password deve includere almeno 3 tra: minuscole, maiuscole, numeri e simboli"
|
password_too_weak: "La password deve includere almeno 3 tra: minuscole, maiuscole, numeri e simboli"
|
||||||
password_mismatch: Le password non coincidono
|
password_mismatch: Le password non coincidono
|
||||||
|
|||||||
@@ -21,6 +21,15 @@ RSpec.describe PasswordComplexity do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe ".same_as_current?" do
|
||||||
|
let!(:user) { User.create!(email: "same@example.com", name: "Same", password: "Password123", role: "coach") }
|
||||||
|
|
||||||
|
it "detects when the new password matches the current one" do
|
||||||
|
expect(described_class.same_as_current?(user, "Password123")).to eq(true)
|
||||||
|
expect(described_class.same_as_current?(user, "OtherPass123")).to eq(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "User validation" do
|
describe "User validation" do
|
||||||
it "blocks weak passwords on create" do
|
it "blocks weak passwords on create" do
|
||||||
user = User.new(email: "weak@example.com", name: "Weak", password: "password123", role: "coach")
|
user = User.new(email: "weak@example.com", name: "Weak", password: "password123", role: "coach")
|
||||||
|
|||||||
@@ -73,6 +73,19 @@ RSpec.describe "Account API", type: :request do
|
|||||||
expect(JSON.parse(response.body)["error"]).to match(/3 of/i)
|
expect(JSON.parse(response.body)["error"]).to match(/3 of/i)
|
||||||
expect(user.reload.authenticate("Password123")).to be_truthy
|
expect(user.reload.authenticate("Password123")).to be_truthy
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "rejects reusing the current password" do
|
||||||
|
patch "/api/v1/account/password",
|
||||||
|
params: {
|
||||||
|
current_password: "Password123",
|
||||||
|
password: "Password123",
|
||||||
|
password_confirmation: "Password123"
|
||||||
|
},
|
||||||
|
headers: auth_headers
|
||||||
|
expect(response).to have_http_status(:unprocessable_entity)
|
||||||
|
expect(JSON.parse(response.body)["error"]).to match(/different/i)
|
||||||
|
expect(user.reload.authenticate("Password123")).to be_truthy
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "POST /api/v1/auth/password/forgot" do
|
describe "POST /api/v1/auth/password/forgot" do
|
||||||
|
|||||||
Reference in New Issue
Block a user