1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-01-30 19:52:20 +01:00

improvement: add complexity check of the user password

This commit is contained in:
Nicolas Florentin 2022-07-29 17:37:42 +02:00
parent acbd327f6d
commit 1d6a59dd67
11 changed files with 40 additions and 13 deletions

View File

@ -142,7 +142,7 @@
class="form-control"
id="user_password"
placeholder="{{ 'app.shared.user.new_password' | translate }}"
ng-minlength="8"
ng-minlength="12"
required/>
</div>
<span class="help-block" ng-show="userForm['user[password]'].$dirty && userForm['user[password]'].$error.required" translate>{{ 'app.shared.user.password_is_required' }}</span>
@ -158,7 +158,7 @@
class="form-control"
id="user_password_confirmation"
placeholder="{{ 'app.shared.user.confirmation_of_new_password' | translate }}"
ng-minlength="8"
ng-minlength="12"
required
match="user.password"/>
</div>

View File

@ -18,7 +18,7 @@
class="form-control"
placeholder="{{ 'app.public.common.your_new_password' | translate }}"
required
ng-minlength="8">
ng-minlength="12">
</div>
<span class="help-block" ng-show="passwordEditForm.password.$dirty && passwordEditForm.password.$error.required" translate>{{ 'app.public.common.password_is_required' }}</span>
<span class="help-block" ng-show="passwordEditForm.password.$dirty && passwordEditForm.password.$error.minlength" translate>{{ 'app.public.common.password_is_too_short' }}</span>
@ -35,7 +35,7 @@
class="form-control"
placeholder="{{ 'app.public.common.type_your_password_again' | translate }}"
required
ng-minlength="8"
ng-minlength="12"
match="user.password">
</div>
<span class="help-block" ng-show="passwordEditForm.password_confirmation.$dirty && passwordEditForm.password_confirmation.$error.required" translate>{{ 'app.public.common.password_confirmation_is_required' }}</span>

View File

@ -96,7 +96,7 @@
class="form-control"
placeholder="{{ 'app.public.common.your_password' | translate }}"
required
ng-minlength="8">
ng-minlength="12">
</div>
<span class="exponent"><i class="fa fa-asterisk" aria-hidden="true"></i></span>
<span class="help-block" ng-show="signupForm.password.$dirty && signupForm.password.$error.required" translate>{{ 'app.public.common.password_is_required' }}</span>

View File

@ -161,7 +161,7 @@ module SingleSignOnConcern
user.set_data_from_sso_mapping(key, value)
end
logger.debug 'generating a new password'
user.password = Devise.friendly_token[0, 20]
user.password = SecurePassword.generate
end
end
end

View File

@ -78,6 +78,7 @@ class User < ApplicationRecord
validate :cgu_must_accept, if: :new_record?
validates :username, presence: true, uniqueness: true, length: { maximum: 30 }
validate :password_complexity
scope :active, -> { where(is_active: true) }
scope :without_subscription, -> { includes(statistic_profile: [:subscriptions]).where(subscriptions: { statistic_profile_id: nil }) }
@ -347,4 +348,10 @@ class User < ApplicationRecord
last_name: last_name
)
end
def password_complexity
return if password.blank? || SecurePassword.is_secured?(password)
errors.add I18n.t("app.public.common.password_is_too_weak"), I18n.t("app.public.common.password_is_too_weak_explanations")
end
end

View File

@ -128,7 +128,7 @@ class Members::MembersService
def password(params)
if !params[:password] && !params[:password_confirmation]
Devise.friendly_token.first(8)
SecurePassword.generate
else
params[:password]
end

View File

@ -0,0 +1,18 @@
class SecurePassword
LOWER_LETTERS = ('a'..'z').to_a
UPPER_LETTERS = ('A'..'Z').to_a
DIGITS = ('0'..'9').to_a
SPECIAL_CHARS = ["!", "#", "$", "%", "&", "(", ")", "*", "+", ",", "-", ".", "/", ":", ";", "<", "=", ">", "?", "@", "[", "]", "^", "_", "{", "|", "}", "~", "'", "`", '"']
def self.generate
(LOWER_LETTERS.shuffle.first(4) + UPPER_LETTERS.shuffle.first(4) + DIGITS.shuffle.first(4) + SPECIAL_CHARS.shuffle.first(4)).shuffle.join
end
def self.is_secured?(password)
password_as_array = password.split("")
password_as_array.any? {|c| c.in? LOWER_LETTERS } &&
password_as_array.any? {|c| c.in? UPPER_LETTERS } &&
password_as_array.any? {|c| c.in? DIGITS } &&
password_as_array.any? {|c| c.in? SPECIAL_CHARS }
end
end

View File

@ -3,7 +3,7 @@
# helpers for managing users with special roles
class UserService
def self.create_partner(params)
generated_password = Devise.friendly_token.first(8)
generated_password = SecurePassword.generate
group_id = Group.first.id
user = User.new(
email: params[:email],
@ -31,7 +31,7 @@ class UserService
end
def self.create_admin(params)
generated_password = Devise.friendly_token.first(8)
generated_password = SecurePassword.generate
admin = User.new(params.merge(password: generated_password))
admin.send :set_slug
@ -52,7 +52,7 @@ class UserService
end
def self.create_manager(params)
generated_password = Devise.friendly_token.first(8)
generated_password = SecurePassword.generate
manager = User.new(params.merge(password: generated_password))
manager.send :set_slug

View File

@ -134,7 +134,7 @@ Devise.setup do |config|
# ==> Configuration for :validatable
# Range for password length.
config.password_length = 8..128
config.password_length = 12..128
# Email regex used to validate email formats. It simply asserts that
# one (and only one) @ exists in the given string. This is mainly

View File

@ -71,7 +71,9 @@ en:
email_is_required: "E-mail address is required."
your_password: "Your password"
password_is_required: "Password is required."
password_is_too_short: "Password is too short (minimum 8 characters)"
password_is_too_short: "Password is too short (minimum 12 characters)"
password_is_too_weak: "Password is too weak:"
password_is_too_weak_explanations: "minimum 12 characters, at least one uppercase letter, one lowercase letter, one number and one special character"
type_your_password_again: "Type your password again"
password_confirmation_is_required: "Password confirmation is required."
password_does_not_match_with_confirmation: "Password does not match with confirmation."

View File

@ -4,7 +4,7 @@ require 'test_helper'
class UserTest < ActiveSupport::TestCase
test 'must create wallet and profiles after create user' do
u = User.create(username: 'user', email: 'userwallet@fabmanager.com', password: 'testpassword', password_confirmation: 'testpassword',
u = User.create(username: 'user', email: 'userwallet@fabmanager.com', password: 'Testpassword1$', password_confirmation: 'Testpassword1$',
profile_attributes: { first_name: 'user', last_name: 'wallet', phone: '0123456789' },
statistic_profile_attributes: { gender: true, birthday: 18.years.ago })
assert u.wallet.present?