Merge pull request #10741 from demarches-simplifiees/secu-improve-complexity-password-ldu
[sécu] Améliorer la complexité des mots de passe pour tous les users
This commit is contained in:
commit
3d50f9363f
50 changed files with 6528 additions and 5216 deletions
2
Gemfile
2
Gemfile
|
@ -111,7 +111,7 @@ gem 'webrick', require: false
|
|||
gem 'yabeda-prometheus'
|
||||
gem 'yabeda-sidekiq'
|
||||
gem 'zipline'
|
||||
gem 'zxcvbn-ruby', require: 'zxcvbn'
|
||||
gem 'zxcvbn'
|
||||
|
||||
group :test do
|
||||
gem 'axe-core-rspec' # accessibility rspec matchers
|
||||
|
|
|
@ -880,7 +880,7 @@ GEM
|
|||
actionpack (>= 6.0, < 8.0)
|
||||
content_disposition (~> 1.0)
|
||||
zip_tricks (>= 4.2.1, < 6.0)
|
||||
zxcvbn-ruby (1.2.0)
|
||||
zxcvbn (0.1.11)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
@ -1034,7 +1034,7 @@ DEPENDENCIES
|
|||
yabeda-prometheus
|
||||
yabeda-sidekiq
|
||||
zipline
|
||||
zxcvbn-ruby
|
||||
zxcvbn
|
||||
|
||||
BUNDLED WITH
|
||||
2.5.9
|
||||
|
|
|
@ -11,13 +11,16 @@
|
|||
.fr-fieldset__element
|
||||
%p.fr-text--sm= t('utils.mandatory_champs')
|
||||
|
||||
.fr-fieldset__element= render Dsfr::InputComponent.new(form: f, attribute: :email, input_type: :email_field, opts: { disabled: :disabled, class: 'fr-input-group--disabled', value: t('.email_disabled') })
|
||||
.fr-fieldset__element
|
||||
= render Dsfr::InputComponent.new(form: f, attribute: :email, input_type: :email_field, opts: { disabled: :disabled, class: 'fr-input-group--disabled' })
|
||||
|
||||
.fr-fieldset__element= render Dsfr::InputComponent.new(form: f, attribute: :password, input_type: :password_field, opts: { autocomplete: 'current-password' })
|
||||
.fr-fieldset__element
|
||||
= render Dsfr::InputComponent.new(form: f, attribute: :password, input_type: :password_field,
|
||||
opts: { autofocus: 'true', autocomplete: 'new-password', data: { controller: 'turbo-input', turbo_input_url_value: show_password_complexity_path }})
|
||||
|
||||
#password_complexity
|
||||
= render PasswordComplexityComponent.new
|
||||
|
||||
= f.hidden_field :reset_password_token, value: params[:token]
|
||||
|
||||
.fr-fieldset__element
|
||||
.fr-btns-group--right.fr-btns-group.fr-btns-group--inline.fr-btns-group.fr-btns-group--inline
|
||||
%ul
|
||||
%li= f.submit t('.submit'), class: 'fr-mt-2v fr-btn fr-btn'
|
||||
= f.submit t('.submit'), id: 'submit-password', disabled: :disabled, class: "fr-btn fr-btn--lg fr-mt-2w", data: { disabled: :disabled, disable_with: t('views.users.passwords.edit.submit_loading') }
|
||||
|
|
|
@ -7,4 +7,4 @@ en:
|
|||
strong: Congratulations! Password is strong and secure enough.
|
||||
weak: Vulnerable password.
|
||||
weakest: Very vulnerable password.
|
||||
hint: A short sentence with punctuation can be a very secure password.
|
||||
hint_html: <p>A short sentence with punctuation can be a very secure password.</p>
|
||||
|
|
|
@ -7,4 +7,4 @@ fr:
|
|||
strong: Félicitations ! Mot de passe suffisamment fort et sécurisé.
|
||||
weak: Mot de passe vulnérable.
|
||||
weakest: Mot de passe très vulnérable.
|
||||
hint: Une courte phrase avec ponctuation peut être un mot de passe très sécurisé.
|
||||
hint_html: <p>Pour un mot de passe sécurisé, éviter d'utiliser des suites ou des répétitions de mêmes caractères.</p><p>Vous pouvez par exemple choisir une phrase (avec des espaces) que vous retiendrez facilement.</p>
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
%div{ class: alert_classes }
|
||||
%h3.fr-alert__title= title
|
||||
- if !success?
|
||||
%p= t(".hint")
|
||||
= t(".hint_html")
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
class PasswordComplexityController < ApplicationController
|
||||
def show
|
||||
@score, @words, @length = ZxcvbnService.new(password_param).complexity
|
||||
@length = password_param.to_s.length
|
||||
@score = ZxcvbnService.complexity(password_param)
|
||||
@min_length = PASSWORD_MIN_LENGTH
|
||||
@min_complexity = PASSWORD_COMPLEXITY_FOR_ADMIN
|
||||
end
|
||||
|
|
|
@ -44,10 +44,6 @@ class User < ApplicationRecord
|
|||
# plug our custom validation a la devise (same options) https://github.com/heartcombo/devise/blob/main/lib/devise/models/validatable.rb#L30
|
||||
validates :email, strict_email: true, allow_blank: true, if: :devise_will_save_change_to_email?
|
||||
|
||||
def validate_password_complexity?
|
||||
administrateur?
|
||||
end
|
||||
|
||||
# Override of Devise::Models::Confirmable#send_confirmation_instructions
|
||||
def send_confirmation_instructions
|
||||
unless @raw_confirmation_token
|
||||
|
|
|
@ -3,51 +3,16 @@
|
|||
class ZxcvbnService
|
||||
@tester_mutex = Mutex.new
|
||||
|
||||
class << self
|
||||
# Returns an Zxcvbn instance cached between classes instances and between threads.
|
||||
#
|
||||
# The tester weights ~20 Mo, and we'd like to save some memory – so rather
|
||||
# that storing it in a per-thread accessor, we prefer to use a mutex
|
||||
# to cache it between threads.
|
||||
def tester
|
||||
@tester_mutex.synchronize do
|
||||
@tester ||= build_tester
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Returns a fully initializer tester from the on-disk dictionary.
|
||||
#
|
||||
# This is slow: loading and parsing the dictionary may take around 1s.
|
||||
def build_tester
|
||||
dictionaries = YAML.safe_load(Rails.root.join("config", "initializers", "zxcvbn_dictionnaries.yaml").read)
|
||||
|
||||
tester = Zxcvbn::Tester.new
|
||||
tester.add_word_lists(dictionaries)
|
||||
tester
|
||||
# Returns an Zxcvbn instance cached between classes instances and between threads.
|
||||
#
|
||||
# The tester weights ~20 Mo, and we'd like to save some memory – so rather
|
||||
# that storing it in a per-thread accessor, we prefer to use a mutex
|
||||
# to cache it between threads.
|
||||
def self.tester
|
||||
@tester_mutex.synchronize do
|
||||
@tester ||= Zxcvbn::Tester.new
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(password)
|
||||
@password = password
|
||||
end
|
||||
|
||||
def complexity
|
||||
wxcvbn = compute_zxcvbn
|
||||
score = wxcvbn.score
|
||||
length = @password.blank? ? 0 : @password.length
|
||||
vulnerabilities = wxcvbn.match_sequence.map { |m| m.matched_word.nil? ? m.token : m.matched_word }.filter { |s| s.length > 2 }.join(', ')
|
||||
[score, vulnerabilities, length]
|
||||
end
|
||||
|
||||
def score
|
||||
compute_zxcvbn.score
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def compute_zxcvbn
|
||||
self.class.tester.test(@password)
|
||||
end
|
||||
def self.complexity(password)= tester.test(password.to_s).score
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
class PasswordComplexityValidator < ActiveModel::EachValidator
|
||||
def validate_each(record, attribute, value)
|
||||
if value.present? && ZxcvbnService.new(value).score < PASSWORD_COMPLEXITY_FOR_ADMIN
|
||||
if value.present? && ZxcvbnService.complexity(value) < PASSWORD_COMPLEXITY_FOR_ADMIN
|
||||
record.errors.add(attribute, :not_strong)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -23,4 +23,4 @@
|
|||
#password_complexity
|
||||
= render PasswordComplexityComponent.new
|
||||
|
||||
= f.submit t('.continue'), id: 'submit-password', class: "fr-btn fr-btn--lg fr-mt-2w", data: { disable_with: t('views.users.passwords.edit.submit_loading') }
|
||||
= f.submit t('.continue'), id: 'submit-password', disabled: :disabled, class: "fr-btn fr-btn--lg fr-mt-2w", data: { disable_with: t('views.users.passwords.edit.submit_loading') }
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
.fr-messages-group{ "aria-live" => "off", id: id }
|
||||
%p.fr-message= t('views.registrations.new.password_message')
|
||||
%p.fr-message.fr-message--info= t('views.registrations.new.password_placeholder', min_length: PASSWORD_MIN_LENGTH)
|
|
@ -18,16 +18,13 @@
|
|||
|
||||
.fr-fieldset__element
|
||||
= render Dsfr::InputComponent.new(form: f, attribute: :password, input_type: :password_field,
|
||||
opts: { autofocus: 'true', autocomplete: 'new-password', minlength: PASSWORD_MIN_LENGTH, data: { controller: populated_resource.validate_password_complexity? ? 'turbo-input' : false, turbo_input_url_value: show_password_complexity_path }}) do |c|
|
||||
opts: { autofocus: 'true', autocomplete: 'new-password', minlength: PASSWORD_MIN_LENGTH, data: { controller: 'turbo-input', turbo_input_url_value: show_password_complexity_path }}) do |c|
|
||||
- c.with_describedby do
|
||||
- if populated_resource.validate_password_complexity?
|
||||
%div{ id: c.describedby_id }
|
||||
#password_complexity
|
||||
= render PasswordComplexityComponent.new
|
||||
- else
|
||||
= render partial: "devise/password_rules", locals: { id: c.describedby_id }
|
||||
%div{ id: c.describedby_id }
|
||||
#password_complexity
|
||||
= render PasswordComplexityComponent.new
|
||||
|
||||
.fr-fieldset__element
|
||||
= render Dsfr::InputComponent.new(form: f, attribute: :password_confirmation, input_type: :password_field, opts: { autocomplete: 'new-password' })
|
||||
|
||||
= f.submit t('views.users.passwords.edit.submit'), id: 'submit-password', class: "fr-btn fr-btn--lg fr-mt-2w", data: { disable_with: t('views.users.passwords.edit.submit_loading') }
|
||||
= f.submit t('views.users.passwords.edit.submit'), id: 'submit-password', disabled: :disabled, class: "fr-btn fr-btn--lg fr-mt-2w", data: { disable_with: t('views.users.passwords.edit.submit_loading') }
|
||||
|
|
|
@ -1,20 +1,22 @@
|
|||
.two-columns.avis-sign-up
|
||||
.columns-container
|
||||
.column.left
|
||||
%h2.fr-py-5w.text-center= @dossier.procedure.libelle
|
||||
%p.dossier Dossier nº #{@dossier.id}
|
||||
.column
|
||||
.fr-container.fr-my-5w
|
||||
.fr-grid-row.fr-grid-row--center
|
||||
.fr-col-lg-6
|
||||
= form_for(User.new(email: @email), url: sign_up_expert_avis_path(email: @email), method: :post, html: { class: "fr-py-5w" }) do |f|
|
||||
%h1.fr-h2= t('views.registrations.new.title', name: Current.application_name)
|
||||
|
||||
%h1.fr-h2
|
||||
= t('views.registrations.new.title', name: Current.application_name)
|
||||
%fieldset.fr-mb-0.fr-fieldset{ aria: { labelledby: 'create-account-legend' } }
|
||||
.fr-fieldset__element
|
||||
%p.fr-text--sm= t('utils.mandatory_champs')
|
||||
|
||||
.fr-fieldset__element= render Dsfr::InputComponent.new(form: f, attribute: :email, input_type: :email_field, opts: { disabled: true, autocomplete: 'email' })
|
||||
.fr-fieldset__element
|
||||
= render Dsfr::InputComponent.new(form: f, attribute: :password, input_type: :password_field, opts: { autocomplete: 'new-password', minlength: PASSWORD_MIN_LENGTH }) do |c|
|
||||
- c.with_describedby do
|
||||
= render partial: "devise/password_rules", locals: { id: c.describedby_id }
|
||||
= render Dsfr::InputComponent.new(form: f, attribute: :email, input_type: :email_field, opts: { disabled: true, autocomplete: 'email' })
|
||||
|
||||
%ul.fr-btns-group
|
||||
%li= f.submit t('views.shared.account.create'), class: "fr-btn"
|
||||
.fr-fieldset__element
|
||||
= render Dsfr::InputComponent.new(form: f, attribute: :password, input_type: :password_field,
|
||||
opts: { autofocus: 'true', autocomplete: 'new-password', data: { controller: 'turbo-input', turbo_input_url_value: show_password_complexity_path }})
|
||||
|
||||
#password_complexity
|
||||
= render PasswordComplexityComponent.new
|
||||
|
||||
= f.submit t('views.shared.account.create'), id: 'submit-password', disabled: :disabled, class: "fr-btn fr-btn--lg fr-mt-2w", data: { disable_with: t('views.users.passwords.edit.submit_loading') }
|
||||
|
|
|
@ -23,4 +23,4 @@
|
|||
#password_complexity
|
||||
= render PasswordComplexityComponent.new
|
||||
|
||||
= f.submit t('.continue'), id: 'submit-password', class: "fr-btn fr-btn--lg fr-mt-2w", data: { disable_with: t('views.users.passwords.edit.submit_loading') }
|
||||
= f.submit t('.continue'), id: 'submit-password', disabled: :disabled, class: "fr-btn fr-btn--lg fr-mt-2w", data: { disable_with: t('views.users.passwords.edit.submit_loading') }
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
= devise_error_messages!
|
||||
|
||||
#form-login
|
||||
%h2#instructeur_login Changement de mot de passe
|
||||
|
||||
%br
|
||||
%br
|
||||
#new-user
|
||||
= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f|
|
||||
= f.hidden_field :reset_password_token
|
||||
%h4
|
||||
= f.label 'Nouveau mot de passe'
|
||||
|
||||
.input-group
|
||||
.input-group-addon
|
||||
%span.fa.fa-asterisk
|
||||
= f.password_field :password, autofocus: true, autocomplete: "off", class: 'form-control'
|
||||
%br
|
||||
%h4
|
||||
= f.label 'Confirmez le nouveau mot de passe'
|
||||
.input-group
|
||||
.input-group-addon
|
||||
%span.fa.fa-asterisk
|
||||
= f.password_field :password_confirmation, autocomplete: "off", class: 'form-control'
|
||||
%br
|
||||
%br
|
||||
.actions
|
||||
= f.submit 'Changer le mot de passe', class: 'btn btn-primary'
|
||||
%br
|
|
@ -1,21 +0,0 @@
|
|||
= devise_error_messages!
|
||||
|
||||
%br
|
||||
#form-login
|
||||
%h2#instructeur_login Mot de passe oublié
|
||||
|
||||
%br
|
||||
%br
|
||||
#new-user
|
||||
= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f|
|
||||
%h4
|
||||
= f.label :email
|
||||
.input-group
|
||||
.input-group-addon
|
||||
%span.fa.fa-user
|
||||
= f.email_field :email, class: 'form-control', placeholder: 'Email'
|
||||
%br
|
||||
%br
|
||||
.actions
|
||||
= f.submit 'Demander un nouveau mot de passe', class: 'button large expand primary'
|
||||
%br
|
|
@ -18,9 +18,10 @@
|
|||
.fr-fieldset__element= render Dsfr::InputComponent.new(form: f, attribute: :email, input_type: :email_field, opts: { autocomplete: 'email', autofocus: true })
|
||||
|
||||
.fr-fieldset__element
|
||||
= render Dsfr::InputComponent.new(form: f, attribute: :password, input_type: :password_field, opts: { autocomplete: 'new-password', minlength: PASSWORD_MIN_LENGTH }) do |c|
|
||||
- c.with_describedby do
|
||||
= render partial: "devise/password_rules", locals: { id: c.describedby_id }
|
||||
= render Dsfr::InputComponent.new(form: f, attribute: :password, input_type: :password_field,
|
||||
opts: { autofocus: 'true', autocomplete: 'new-password', data: { controller: 'turbo-input', turbo_input_url_value: show_password_complexity_path }})
|
||||
|
||||
%ul.fr-btns-group
|
||||
%li= f.submit t('views.shared.account.create'), class: "fr-btn"
|
||||
#password_complexity
|
||||
= render PasswordComplexityComponent.new
|
||||
|
||||
= f.submit t('views.shared.account.create'), id: 'submit-password', disabled: :disabled, class: "fr-btn fr-btn--lg fr-mt-2w", data: { disable_with: t('views.users.passwords.edit.submit_loading') }
|
||||
|
|
|
@ -7,5 +7,5 @@ if !defined?(PASSWORD_MIN_LENGTH)
|
|||
# PASSWORD_COMPLEXITY_FOR_INSTRUCTEUR = ENV.fetch('PASSWORD_COMPLEXITY_FOR_INSTRUCTEUR', '3').to_i
|
||||
PASSWORD_COMPLEXITY_FOR_ADMIN = ENV.fetch('PASSWORD_COMPLEXITY_FOR_ADMIN', '4').to_i
|
||||
# password minimum length
|
||||
PASSWORD_MIN_LENGTH = ENV.fetch('PASSWORD_MIN_LENGTH', '8').to_i
|
||||
PASSWORD_MIN_LENGTH = ENV.fetch('PASSWORD_MIN_LENGTH', '12').to_i
|
||||
end
|
||||
|
|
11
config/initializers/zxcvbn.rb
Normal file
11
config/initializers/zxcvbn.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
new_frequency_lists = ['words_fr', 'passwords_fr', 'surnames_fr', 'female_names_fr', 'male_names_fr'].index_with do |n|
|
||||
Zxcvbn.file_enumerator(Rails.root.join("config/zxcvbn_frequency_lists/#{n}.txt"))
|
||||
end
|
||||
|
||||
new_ranked_dictionary = new_frequency_lists.transform_values do |lst|
|
||||
Zxcvbn::Matching.build_ranked_dict(lst)
|
||||
end
|
||||
|
||||
Zxcvbn::Matching::RANKED_DICTIONARIES.merge! new_ranked_dictionary
|
File diff suppressed because it is too large
Load diff
|
@ -311,8 +311,6 @@ en:
|
|||
subtitle: "Create an account using an email"
|
||||
email_label: 'Email (name@site.com)'
|
||||
password_label: "Password (%{min_length} characters minimum)"
|
||||
password_message: "Your password must have :"
|
||||
password_placeholder: "%{min_length} characters minimum"
|
||||
confirmation:
|
||||
new:
|
||||
title: 'Confirm your email address'
|
||||
|
@ -661,7 +659,7 @@ en:
|
|||
invalid: 'is invalid. Fill in a valid email address, example: address@mail.com'
|
||||
taken: 'already in use. Fill in another email'
|
||||
password:
|
||||
too_short: "is too short. Fill in a password with at least 8 characters"
|
||||
too_short: "is too short. Fill in a password with at least 12 characters"
|
||||
not_strong: "not strong enough. Fill in a stronger password"
|
||||
password_confirmation:
|
||||
confirmation: ": The two passwords do not match"
|
||||
|
|
|
@ -303,8 +303,6 @@ fr:
|
|||
subtitle: "Se créer un compte avec une adresse email"
|
||||
email_label: 'Email'
|
||||
password_label: "Mot de passe (%{min_length} caractères minimum)"
|
||||
password_message: "Votre mot de passe doit contenir :"
|
||||
password_placeholder: "%{min_length} caractères minimum"
|
||||
confirmation:
|
||||
new:
|
||||
title: 'Confirmez votre adresse email'
|
||||
|
@ -662,7 +660,7 @@ fr:
|
|||
invalid: 'est invalide. Saisir une adresse électronique valide, exemple : adresse@mail.com'
|
||||
taken: 'déjà utilisé. Saisir une autre adresse électronique.'
|
||||
password:
|
||||
too_short: "est trop court. Saisir un mot de passe avec au moins 8 caractères"
|
||||
too_short: "est trop court. Saisir un mot de passe avec au moins 12 caractères"
|
||||
not_strong: "n’est pas assez complexe. Saisir un mot de passe plus complexe"
|
||||
password_confirmation:
|
||||
confirmation: ': Les deux mots de passe ne correspondent pas'
|
||||
|
|
100
config/zxcvbn_frequency_lists/female_names_fr.txt
Normal file
100
config/zxcvbn_frequency_lists/female_names_fr.txt
Normal file
|
@ -0,0 +1,100 @@
|
|||
Marie
|
||||
Julie
|
||||
Camille
|
||||
Emilie
|
||||
Aurélie
|
||||
Léa
|
||||
Manon
|
||||
Elodie
|
||||
Laura
|
||||
Sarah
|
||||
Chloé
|
||||
Pauline
|
||||
Anaïs
|
||||
Céline
|
||||
Audrey
|
||||
Marine
|
||||
Marion
|
||||
Mélanie
|
||||
Emma
|
||||
Lucie
|
||||
Mathilde
|
||||
Charlotte
|
||||
Amandine
|
||||
Stéphanie
|
||||
Sophie
|
||||
Laetitia
|
||||
Justine
|
||||
Clara
|
||||
Océane
|
||||
Caroline
|
||||
Inès
|
||||
Claire
|
||||
Amélie
|
||||
Virginie
|
||||
Morgane
|
||||
Sabrina
|
||||
Jessica
|
||||
Fanny
|
||||
Jade
|
||||
Juliette
|
||||
Mélissa
|
||||
Jennifer
|
||||
Eva
|
||||
Vanessa
|
||||
Cindy
|
||||
Lisa
|
||||
Louise
|
||||
Alexandra
|
||||
Clémence
|
||||
Alice
|
||||
Lola
|
||||
Aurore
|
||||
Cécile
|
||||
Elise
|
||||
Delphine
|
||||
Noemie
|
||||
Margaux
|
||||
Coralie
|
||||
Hélène
|
||||
Célia
|
||||
Maeva
|
||||
Angelique
|
||||
Romane
|
||||
Sandra
|
||||
Estelle
|
||||
Adeline
|
||||
Alicia
|
||||
Zoé
|
||||
Sandrine
|
||||
Jeanne
|
||||
Laure
|
||||
Elisa
|
||||
Christell
|
||||
Anne
|
||||
Léna
|
||||
Nathalie
|
||||
Margot
|
||||
Julia
|
||||
Ludivine
|
||||
Ophélie
|
||||
Sonia
|
||||
Elsa
|
||||
Agathe
|
||||
Myriam
|
||||
Emmanuelle
|
||||
Lilou
|
||||
Alexia
|
||||
Charlène
|
||||
Emeline
|
||||
Marina
|
||||
Ambre
|
||||
Gaelle
|
||||
Lina
|
||||
Anna
|
||||
Lou
|
||||
Isabelle
|
||||
Solène
|
||||
Laurie
|
||||
Nina
|
||||
Maelys
|
100
config/zxcvbn_frequency_lists/male_names_fr.txt
Normal file
100
config/zxcvbn_frequency_lists/male_names_fr.txt
Normal file
|
@ -0,0 +1,100 @@
|
|||
Nicolas
|
||||
Julien
|
||||
Thomas
|
||||
Alexandre
|
||||
Maxime
|
||||
Romain
|
||||
Guillaume
|
||||
Anthony
|
||||
Kevin
|
||||
Antoine
|
||||
Lucas
|
||||
Sébastien
|
||||
Clément
|
||||
Benjamin
|
||||
Pierre
|
||||
Mathieu
|
||||
Quentin
|
||||
Florian
|
||||
Vincent
|
||||
Alexis
|
||||
David
|
||||
Hugo
|
||||
Jeremy
|
||||
Théo
|
||||
Jonathan
|
||||
Damien
|
||||
Adrien
|
||||
Enzo
|
||||
Valentin
|
||||
Louis
|
||||
Nathan
|
||||
Paul
|
||||
Baptiste
|
||||
Mickael
|
||||
Cedric
|
||||
Raphaël
|
||||
Arthur
|
||||
Christophe
|
||||
Loïc
|
||||
Aurélien
|
||||
Léo
|
||||
Arnaud
|
||||
Matthieu
|
||||
Fabien
|
||||
Tom
|
||||
Mathis
|
||||
Dylan
|
||||
Axel
|
||||
Ludovic
|
||||
Jerome
|
||||
Benoît
|
||||
Simon
|
||||
Gabriel
|
||||
Frédéric
|
||||
Olivier
|
||||
Rémi
|
||||
Samuel
|
||||
Jules
|
||||
Stéphane
|
||||
Sylvain
|
||||
Mohamed
|
||||
Jean
|
||||
Victor
|
||||
Jordan
|
||||
François
|
||||
Corentin
|
||||
Gregory
|
||||
Cyril
|
||||
Bastien
|
||||
Florent
|
||||
Yanis
|
||||
Thibault
|
||||
Maxence
|
||||
Yann
|
||||
Laurent
|
||||
Michael
|
||||
Mathéo
|
||||
Martin
|
||||
Gaëtan
|
||||
Mehdi
|
||||
Robin
|
||||
William
|
||||
Christopher
|
||||
Ethan
|
||||
Noah
|
||||
Charles
|
||||
Emmanuel
|
||||
Xavier
|
||||
Adam
|
||||
Tristan
|
||||
Yoann
|
||||
Tony
|
||||
Marc
|
||||
Dimitri
|
||||
Thibaut
|
||||
Rémy
|
||||
Evan
|
||||
Steven
|
||||
Dorian
|
||||
Franck
|
1000
config/zxcvbn_frequency_lists/passwords_fr.txt
Normal file
1000
config/zxcvbn_frequency_lists/passwords_fr.txt
Normal file
File diff suppressed because it is too large
Load diff
200
config/zxcvbn_frequency_lists/surnames_fr.txt
Normal file
200
config/zxcvbn_frequency_lists/surnames_fr.txt
Normal file
|
@ -0,0 +1,200 @@
|
|||
Martin
|
||||
Bernard
|
||||
Thomas
|
||||
Petit
|
||||
Robert
|
||||
Richard
|
||||
Dubois
|
||||
Durand
|
||||
Moreau
|
||||
Laurent
|
||||
Simon
|
||||
Michel
|
||||
Lefebvre
|
||||
Leroy
|
||||
David
|
||||
Roux
|
||||
Morel
|
||||
Bertrand
|
||||
Fournier
|
||||
Girard
|
||||
Fontaine
|
||||
Lambert
|
||||
Dupont
|
||||
Bonnet
|
||||
Rousseau
|
||||
Vincent
|
||||
Muller
|
||||
Lefevre
|
||||
Faure
|
||||
Andre
|
||||
Mercier
|
||||
Guerin
|
||||
Garcia
|
||||
Boyer
|
||||
Blanc
|
||||
Garnier
|
||||
Chevalier
|
||||
Francois
|
||||
Legrand
|
||||
Gauthier
|
||||
Perrin
|
||||
Robin
|
||||
Clement
|
||||
Morin
|
||||
Henry
|
||||
Nicolas
|
||||
Roussel
|
||||
Gautier
|
||||
Mathieu
|
||||
Masson
|
||||
Duval
|
||||
Marchand
|
||||
Denis
|
||||
Lemaire
|
||||
Dumont
|
||||
Marie
|
||||
Noel
|
||||
Meyer
|
||||
Dufour
|
||||
Meunier
|
||||
Martinez
|
||||
Blanchard
|
||||
Brun
|
||||
Riviere
|
||||
Lucas
|
||||
Joly
|
||||
Giraud
|
||||
Brunet
|
||||
Gaillard
|
||||
Barbier
|
||||
Gerard
|
||||
Arnaud
|
||||
Renard
|
||||
Roche
|
||||
Schmitt
|
||||
Roy
|
||||
Leroux
|
||||
Caron
|
||||
Colin
|
||||
Vidal
|
||||
Picard
|
||||
Roger
|
||||
Fabre
|
||||
Aubert
|
||||
Lemoine
|
||||
Renaud
|
||||
Dumas
|
||||
Payet
|
||||
Olivier
|
||||
Lacroix
|
||||
Philippe
|
||||
Pierre
|
||||
Bourgeois
|
||||
Lopez
|
||||
Benoit
|
||||
Leclerc
|
||||
Rey
|
||||
Leclercq
|
||||
Sanchez
|
||||
Lecomte
|
||||
Rolland
|
||||
Guillaume
|
||||
Jean
|
||||
Hubert
|
||||
Dupuy
|
||||
Carpentier
|
||||
Guillot
|
||||
Berger
|
||||
Perez
|
||||
Dupuis
|
||||
Louis
|
||||
Moulin
|
||||
Deschamps
|
||||
Vasseur
|
||||
Huet
|
||||
Boucher
|
||||
Fernandez
|
||||
Fleury
|
||||
Adam
|
||||
Royer
|
||||
Paris
|
||||
Jacquet
|
||||
Klein
|
||||
Poirier
|
||||
Charles
|
||||
Aubry
|
||||
Guyot
|
||||
Carre
|
||||
Renault
|
||||
Menard
|
||||
Maillard
|
||||
Charpentier
|
||||
Marty
|
||||
Bertin
|
||||
Baron
|
||||
Da Silva
|
||||
Bailly
|
||||
Herve
|
||||
Schneider
|
||||
Le Gall
|
||||
Collet
|
||||
Leger
|
||||
Bouvier
|
||||
Julien
|
||||
Prevost
|
||||
Millet
|
||||
Le Roux
|
||||
Daniel
|
||||
Perrot
|
||||
Cousin
|
||||
Germain
|
||||
Breton
|
||||
Rodriguez
|
||||
Langlois
|
||||
Remy
|
||||
Besson
|
||||
Leveque
|
||||
Le Goff
|
||||
Pelletier
|
||||
Leblanc
|
||||
Barre
|
||||
Lebrun
|
||||
Grondin
|
||||
Perrier
|
||||
Marchal
|
||||
Weber
|
||||
Boulanger
|
||||
Mallet
|
||||
Hamon
|
||||
Jacob
|
||||
Monnier
|
||||
Michaud
|
||||
Guichard
|
||||
Poulain
|
||||
Etienne
|
||||
Gillet
|
||||
Hoarau
|
||||
Tessier
|
||||
Chevallier
|
||||
Collin
|
||||
Lemaitre
|
||||
Benard
|
||||
Chauvin
|
||||
Bouchet
|
||||
Marechal
|
||||
Gay
|
||||
Humbert
|
||||
Gonzalez
|
||||
Antoine
|
||||
Perret
|
||||
Reynaud
|
||||
Cordier
|
||||
Lejeune
|
||||
Barthelemy
|
||||
Delaunay
|
||||
Carlier
|
||||
Pichon
|
||||
Pasquier
|
||||
Lamy
|
||||
Gilbert
|
4999
config/zxcvbn_frequency_lists/words_fr.txt
Normal file
4999
config/zxcvbn_frequency_lists/words_fr.txt
Normal file
File diff suppressed because it is too large
Load diff
|
@ -37,7 +37,7 @@ describe Administrateurs::ActivateController, type: :controller do
|
|||
end
|
||||
|
||||
context 'when the password is not strong' do
|
||||
let(:password) { 'another-password-ok?' }
|
||||
let(:password) { 'password-ok?' }
|
||||
|
||||
it { expect(administrateur.user.reload.valid_password?(password)).to be false }
|
||||
it { expect(response).to redirect_to(admin_activate_path(token: token)) }
|
||||
|
|
|
@ -61,7 +61,7 @@ end
|
|||
RSpec.describe "CSRF cleanup", type: :request do
|
||||
describe 'csrf_cleaner hook', :allow_forgery_protection do
|
||||
let(:user) { create(:user, password: password) }
|
||||
let(:password) { 'my-very-secure-password' }
|
||||
let(:password) { SECURE_PASSWORD }
|
||||
|
||||
it 'refreshes the long-lived cookie after authentication' do
|
||||
get new_user_session_path
|
||||
|
|
|
@ -598,7 +598,7 @@ describe Experts::AvisController, type: :controller do
|
|||
|
||||
context 'with a random avis, procedure and user' do
|
||||
let(:avis_id) { create(:avis).id }
|
||||
let(:random_user) { create(:user) }
|
||||
let(:random_user) { create(:user, password: '{Another-$3cure-p4ssWord}') }
|
||||
let(:email) { random_user.email }
|
||||
|
||||
it 'doesn’t change the random user password' do
|
||||
|
@ -613,7 +613,7 @@ describe Experts::AvisController, type: :controller do
|
|||
let(:avis) { create(:avis) }
|
||||
let(:avis_id) { avis.id }
|
||||
let(:procedure_id) { avis.procedure.id }
|
||||
let(:random_user) { create(:user) }
|
||||
let(:random_user) { create(:user, password: '{Another-$3cure-p4ssWord}') }
|
||||
let(:email) { random_user.email }
|
||||
|
||||
it 'doesn’t change the random user password' do
|
||||
|
@ -629,7 +629,7 @@ describe Experts::AvisController, type: :controller do
|
|||
|
||||
it 'doesn’t change the expert password' do
|
||||
subject
|
||||
expect(expert.user.reload.valid_password?(SECURE_PASSWORD)).to be false
|
||||
expect(expert.user.reload.valid_password?('{Another-$3cure-p4ssWord}')).to be false
|
||||
end
|
||||
|
||||
it { is_expected.to redirect_to new_user_session_url }
|
||||
|
|
|
@ -394,7 +394,7 @@ describe FranceConnect::ParticulierController, type: :controller do
|
|||
fci.update!(requested_email: email.downcase)
|
||||
end
|
||||
|
||||
let!(:user) { create(:user, email:, password: 'abcdefgh') }
|
||||
let!(:user) { create(:user, email:, password: SECURE_PASSWORD) }
|
||||
|
||||
it 'merges the account, signs in, and delete the merge token' do
|
||||
subject
|
||||
|
@ -408,7 +408,7 @@ describe FranceConnect::ParticulierController, type: :controller do
|
|||
end
|
||||
|
||||
context 'but the targeted user is an instructeur' do
|
||||
let!(:user) { create(:instructeur, email: email, password: 'abcdefgh').user }
|
||||
let!(:user) { create(:instructeur, email: email, password: SECURE_PASSWORD).user }
|
||||
|
||||
it 'redirects to the new session' do
|
||||
subject
|
||||
|
|
|
@ -23,7 +23,7 @@ describe Gestionnaires::ActivateController, type: :controller do
|
|||
describe '#create' do
|
||||
let!(:gestionnaire) { create(:gestionnaire) }
|
||||
let(:token) { gestionnaire.user.send(:set_reset_password_token) }
|
||||
let(:password) { 'another-password-ok?' }
|
||||
let(:password) { '{another-password-ok?}' }
|
||||
|
||||
before { post :create, params: { gestionnaire: { reset_password_token: token, password: password } } }
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
describe PasswordComplexityController, type: :controller do
|
||||
describe '#show' do
|
||||
let(:params) do
|
||||
{ user: { password: 'moderately complex password' } }
|
||||
{ user: { password: 'motDePasseTropFacile' } }
|
||||
end
|
||||
|
||||
subject { get :show, format: :turbo_stream, params: params }
|
||||
|
@ -15,7 +15,7 @@ describe PasswordComplexityController, type: :controller do
|
|||
|
||||
context 'with a different resource name' do
|
||||
let(:params) do
|
||||
{ super_admin: { password: 'moderately complex password' } }
|
||||
{ super_admin: { password: 'motDePasseTropFacile' } }
|
||||
end
|
||||
|
||||
it 'computes a password score' do
|
||||
|
|
|
@ -23,7 +23,7 @@ describe Users::ActivateController, type: :controller do
|
|||
describe '#create' do
|
||||
let!(:user) { create(:user) }
|
||||
let(:token) { user.send(:set_reset_password_token) }
|
||||
let(:password) { 'another-password-ok?' }
|
||||
let(:password) { '{another-password-ok?}' }
|
||||
|
||||
before { post :create, params: { user: { reset_password_token: token, password: password } } }
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ FactoryBot.define do
|
|||
|
||||
transient do
|
||||
email { generate(:expert_email) }
|
||||
password { 'somethingverycomplated!' }
|
||||
password { '{My-$3cure-p4ssWord}' }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,7 +8,7 @@ FactoryBot.define do
|
|||
|
||||
transient do
|
||||
email { generate(:gestionnaire_email) }
|
||||
password { 'somethingverycomplated!' }
|
||||
password { '{My-$3cure-p4ssWord}' }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,7 +10,7 @@ FactoryBot.define do
|
|||
|
||||
transient do
|
||||
email { generate(:instructeur_email) }
|
||||
password { '{my-%s3cure[]-p4$$w0rd' }
|
||||
password { '{My-$3cure-p4ssWord}' }
|
||||
end
|
||||
|
||||
trait :email_verified do
|
||||
|
|
|
@ -74,7 +74,7 @@ describe SuperAdmin, type: :model do
|
|||
# 2 - somewhat guessable: protection from unthrottled online attacks. (guesses < 10^8)
|
||||
# 3 - safely unguessable: moderate protection from offline slow-hash scenario. (guesses < 10^10)
|
||||
# 4 - very unguessable: strong protection from offline slow-hash scenario. (guesses >= 10^10)
|
||||
passwords = ['password', '12pass23', 'démarches ', 'démarches-simple', '{My-$3cure-p4ssWord}']
|
||||
passwords = ['000000000000', '123456789123', 'megapass2024', 'lesdémarches', '{My-$3cure-p4ssWord}']
|
||||
min_complexity = PASSWORD_COMPLEXITY_FOR_ADMIN
|
||||
|
||||
let(:email) { 'mail@beta.gouv.fr' }
|
||||
|
@ -89,7 +89,7 @@ describe SuperAdmin, type: :model do
|
|||
let(:password) { 's' * (PASSWORD_MIN_LENGTH - 1) }
|
||||
|
||||
it 'reports an error about password length (but not about complexity)' do
|
||||
expect(subject).to eq(["Le champ « Mot de passe » est trop court. Saisir un mot de passe avec au moins 8 caractères"])
|
||||
expect(subject).to eq(["Le champ « Mot de passe » est trop court. Saisir un mot de passe avec au moins 12 caractères"])
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -103,7 +103,7 @@ describe User, type: :model do
|
|||
|
||||
describe '.create_or_promote_to_instructeur' do
|
||||
let(:email) { 'inst1@gmail.com' }
|
||||
let(:password) { 'un super password !' }
|
||||
let(:password) { SECURE_PASSWORD }
|
||||
let(:admins) { [] }
|
||||
|
||||
subject { User.create_or_promote_to_instructeur(email, password, administrateurs: admins) }
|
||||
|
@ -390,7 +390,7 @@ describe User, type: :model do
|
|||
# 2 - somewhat guessable: protection from unthrottled online attacks. (guesses < 10^8)
|
||||
# 3 - safely unguessable: moderate protection from offline slow-hash scenario. (guesses < 10^10)
|
||||
# 4 - very unguessable: strong protection from offline slow-hash scenario. (guesses >= 10^10)
|
||||
passwords = ['password', '12pass23', 'démarches ', 'démarches-simple', '{My-$3cure-p4ssWord}']
|
||||
passwords = ['000000000000', '123456789123', '123456789 123', 'lesdémarches', '{My-$3cure-p4ssWord}']
|
||||
min_complexity = PASSWORD_COMPLEXITY_FOR_ADMIN
|
||||
|
||||
subject do
|
||||
|
@ -405,7 +405,7 @@ describe User, type: :model do
|
|||
let(:password) { 's' * (PASSWORD_MIN_LENGTH - 1) }
|
||||
|
||||
it 'reports an error about password length (but not about complexity)' do
|
||||
expect(subject).to eq(["Le champ « Mot de passe » est trop court. Saisir un mot de passe avec au moins 8 caractères"])
|
||||
expect(subject).to eq(["Le champ « Mot de passe » est trop court. Saisir un mot de passe avec au moins 12 caractères"])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -431,16 +431,19 @@ describe User, type: :model do
|
|||
let(:password) { 's' * (PASSWORD_MIN_LENGTH - 1) }
|
||||
|
||||
it 'reports an error about password length (but not about complexity)' do
|
||||
expect(subject).to eq(["Le champ « Mot de passe » est trop court. Saisir un mot de passe avec au moins 8 caractères"])
|
||||
expect(subject).to eq(["Le champ « Mot de passe » est trop court. Saisir un mot de passe avec au moins 12 caractères"])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the password is long enough, but simple' do
|
||||
let(:password) { 'simple-password' }
|
||||
it { expect(subject).to eq(["Le champ « Mot de passe » n’est pas assez complexe. Saisir un mot de passe plus complexe"]) }
|
||||
end
|
||||
|
||||
it 'doesn’t enforce the password complexity' do
|
||||
expect(subject).to be_empty
|
||||
end
|
||||
context 'when the password is long and complex' do
|
||||
let(:password) { passwords[min_complexity] }
|
||||
|
||||
it { expect(subject).to be_empty }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,18 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
describe ZxcvbnService do
|
||||
let(:password) { 'medium-strength-password' }
|
||||
subject(:service) { ZxcvbnService.new(password) }
|
||||
|
||||
describe '#score' do
|
||||
describe '.complexity' do
|
||||
it 'returns the password complexity score' do
|
||||
expect(service.score).to eq 3
|
||||
end
|
||||
end
|
||||
|
||||
describe '#complexity' do
|
||||
it 'returns the password score, vulnerability and length' do
|
||||
expect(service.complexity).to eq [3, 'medium, strength, password', 24]
|
||||
expect(ZxcvbnService.complexity(nil)).to eq 0
|
||||
expect(ZxcvbnService.complexity('motdepassefrançais')).to eq 1
|
||||
expect(ZxcvbnService.complexity(SECURE_PASSWORD)).to eq 4
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -21,12 +14,8 @@ describe ZxcvbnService do
|
|||
allow(Zxcvbn::Tester).to receive(:new).and_call_original
|
||||
allow(YAML).to receive(:safe_load).and_call_original
|
||||
|
||||
first_service = ZxcvbnService.new('some-password')
|
||||
first_service.score
|
||||
first_service.complexity
|
||||
other_service = ZxcvbnService.new('other-password')
|
||||
other_service.score
|
||||
other_service.complexity
|
||||
_first_call = ZxcvbnService.complexity('some-password')
|
||||
_other_call = ZxcvbnService.complexity('other-password')
|
||||
|
||||
expect(Zxcvbn::Tester).to have_received(:new).at_most(:once)
|
||||
expect(YAML).to have_received(:safe_load).at_most(:once)
|
||||
|
@ -37,12 +26,12 @@ describe ZxcvbnService do
|
|||
|
||||
threads = 1.upto(4).map do
|
||||
Thread.new do
|
||||
ZxcvbnService.new(password).score
|
||||
ZxcvbnService.complexity(SECURE_PASSWORD)
|
||||
end
|
||||
end.map(&:join)
|
||||
|
||||
scores = threads.map(&:value)
|
||||
expect(scores).to eq([3, 3, 3, 3])
|
||||
complexities = threads.map(&:value)
|
||||
expect(complexities).to eq([4, 4, 4, 4])
|
||||
expect(Zxcvbn::Tester).to have_received(:new).at_most(:once)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -24,7 +24,7 @@ require 'simplecov' if ENV["CI"] || ENV["COVERAGE"] # see config in .simplecov f
|
|||
|
||||
require 'rspec/retry'
|
||||
|
||||
SECURE_PASSWORD = 'my-s3cure-p4ssword'
|
||||
SECURE_PASSWORD = '{My-$3cure-p4ssWord}'
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.filter_run_excluding disable: true
|
||||
|
|
|
@ -61,7 +61,7 @@ module SystemHelpers
|
|||
confirmation_email = open_email(email)
|
||||
procedure_sign_in_link = confirmation_email.body.match(/href="([^"]*\/commencer\/[^"]*)"/)[1]
|
||||
|
||||
visit procedure_sign_in_link
|
||||
visit URI.parse(procedure_sign_in_link).path
|
||||
end
|
||||
|
||||
def click_reset_password_link_for(email)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
describe 'wcag rules for usager', chrome: true do
|
||||
let(:procedure) { create(:procedure, :published, :with_service, :for_individual) }
|
||||
let(:password) { 'a very complicated password' }
|
||||
let(:password) { SECURE_PASSWORD }
|
||||
let(:litteraire_user) { create(:user, password: password) }
|
||||
|
||||
def test_external_links_have_title_says_it_opens_in_a_new_tab
|
||||
|
|
|
@ -4,7 +4,7 @@ describe 'As an administrateur', js: true do
|
|||
let(:super_admin) { create(:super_admin) }
|
||||
let(:admin_email) { 'new_admin@gouv.fr' }
|
||||
let(:new_admin) { Administrateur.by_email(admin_email) }
|
||||
let(:weak_password) { '12345678' }
|
||||
let(:weak_password) { '000000000000' }
|
||||
let(:strong_password) { 'a new, long, and complicated password!' }
|
||||
|
||||
before do
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
describe 'Inviting an expert:' do
|
||||
describe 'Inviting an expert:', js: true do
|
||||
include ActiveJob::TestHelper
|
||||
include ActionView::Helpers
|
||||
|
||||
|
@ -34,7 +34,8 @@ describe 'Inviting an expert:' do
|
|||
end
|
||||
|
||||
scenario 'I can sign-in again afterwards' do
|
||||
click_on 'Se déconnecter'
|
||||
click_on(avis.expert.email.to_s, visible: true)
|
||||
click_on('Se déconnecter', visible: true)
|
||||
|
||||
visit new_user_session_path
|
||||
sign_in_with avis.expert.email, password
|
||||
|
@ -54,9 +55,10 @@ describe 'Inviting an expert:' do
|
|||
|
||||
expect(page).to have_current_path(new_user_session_path)
|
||||
login_as avis.expert.user, scope: :user
|
||||
sign_in_with(avis.expert.email, 'This is a very complicated password !')
|
||||
sign_in_with(avis.expert.email, '{My-$3cure-p4ssWord}')
|
||||
expect(page).to have_content("connecté en tant qu’expert")
|
||||
click_on 'Passer en usager'
|
||||
click_on(avis.expert.email.to_s, visible: true)
|
||||
click_on('Passer en usager', visible: true)
|
||||
expect(page).to have_current_path(dossiers_path)
|
||||
end
|
||||
end
|
||||
|
@ -111,10 +113,11 @@ describe 'Inviting an expert:' do
|
|||
expect(page).to have_text('Cet avis est confidentiel')
|
||||
|
||||
# check validation
|
||||
fill_in 'avis_answer', with: 'Ma réponse d’expert.'
|
||||
click_on 'Envoyer votre avis'
|
||||
expect(page).to have_content("Le champ « Réponse oui/non » n'est pas inclus(e) dans la liste")
|
||||
|
||||
choose 'non'
|
||||
find('label', text: 'non').click
|
||||
fill_in 'avis_answer', with: 'Ma réponse d’expert.'
|
||||
click_on 'Envoyer votre avis'
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
describe 'Protecting against request forgeries:', :allow_forgery_protection, :show_exception_pages do
|
||||
let(:user) { create(:user, password: password) }
|
||||
let(:password) { 'ThisIsTheUserPassword' }
|
||||
let(:password) { SECURE_PASSWORD }
|
||||
|
||||
before do
|
||||
visit new_user_session_path
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
describe 'The routing with rules', js: true do
|
||||
let(:password) { 'a very complicated password' }
|
||||
let(:password) { SECURE_PASSWORD }
|
||||
|
||||
let(:procedure) do
|
||||
create(:procedure, :with_service, :for_individual, :with_zone, types_de_champ_public: [
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
describe 'Managing password:', js: true do
|
||||
context 'for simple users' do
|
||||
let(:user) { create(:user) }
|
||||
let(:new_password) { 'a simple password' }
|
||||
let(:new_password) { 'a new, long, and complicated password!' }
|
||||
|
||||
scenario 'a simple user can reset their password' do
|
||||
visit root_path
|
||||
|
@ -33,7 +33,7 @@ describe 'Managing password:', js: true do
|
|||
context 'for admins' do
|
||||
let(:administrateur) { administrateurs(:default_admin) }
|
||||
let(:user) { administrateur.user }
|
||||
let(:weak_password) { '12345678' }
|
||||
let(:weak_password) { '000000000000' }
|
||||
let(:strong_password) { 'a new, long, and complicated password!' }
|
||||
|
||||
scenario 'an admin can reset their password' do
|
||||
|
@ -72,7 +72,7 @@ describe 'Managing password:', js: true do
|
|||
|
||||
context 'for super-admins' do
|
||||
let(:super_admin) { create(:super_admin) }
|
||||
let(:weak_password) { '12345678' }
|
||||
let(:weak_password) { '000000000000' }
|
||||
let(:strong_password) { 'a new, long, and complicated password!' }
|
||||
|
||||
scenario 'a super-admin can reset their password' do
|
||||
|
@ -109,8 +109,8 @@ describe 'Managing password:', js: true do
|
|||
visit edit_user_password_path(reset_password_token: 'invalid-password-token')
|
||||
expect(page).to have_content 'Changement de mot de passe'
|
||||
|
||||
fill_in 'user_password', with: 'SomePassword'
|
||||
fill_in 'user_password_confirmation', with: 'SomePassword'
|
||||
fill_in 'user_password', with: SECURE_PASSWORD
|
||||
fill_in 'user_password_confirmation', with: SECURE_PASSWORD
|
||||
click_on 'Changer le mot de passe'
|
||||
expect(page).to have_content('Votre lien de nouveau mot de passe a expiré')
|
||||
end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
describe 'Signing up:' do
|
||||
describe 'Signing up:', js: true do
|
||||
let(:user_email) { generate :user_email }
|
||||
let(:user_password) { SECURE_PASSWORD }
|
||||
let(:procedure) { create :simple_procedure, :with_service }
|
||||
|
@ -24,7 +24,7 @@ describe 'Signing up:' do
|
|||
click_on "Créer un compte #{APPLICATION_NAME}"
|
||||
expect(page).to have_selector('.suspect-email', visible: false)
|
||||
fill_in 'Adresse électronique', with: 'bidou@yahoo.rf'
|
||||
fill_in 'Mot de passe', with: '12345'
|
||||
fill_in 'Mot de passe', with: '1 2 3 4 5 6 '
|
||||
end
|
||||
|
||||
scenario 'they can accept the suggestion', js: true do
|
||||
|
@ -51,12 +51,12 @@ describe 'Signing up:' do
|
|||
|
||||
scenario 'a new user can’t sign-up with too short password when visiting a procedure' do
|
||||
visit commencer_path(path: procedure.path)
|
||||
click_on "Créer un compte #{APPLICATION_NAME}"
|
||||
click_on 'Créer un compte'
|
||||
|
||||
expect(page).to have_current_path new_user_registration_path
|
||||
sign_up_with user_email, '1234567'
|
||||
expect(page).to have_current_path user_registration_path
|
||||
expect(page).to have_content "Le champ « Mot de passe » est trop court. Saisir un mot de passe avec au moins 8 caractères"
|
||||
fill_in :user_email, with: user_email
|
||||
fill_in :user_password, with: '1234567'
|
||||
expect(page).to have_content "Le mot de passe doit faire au moins 12 caractères."
|
||||
|
||||
# Then with a good password
|
||||
sign_up_with user_email, user_password
|
||||
|
|
Loading…
Reference in a new issue