refactor: simplify ZxcvbnService
This commit is contained in:
parent
214a0daca1
commit
c0fe06ceb7
4 changed files with 21 additions and 59 deletions
|
@ -2,7 +2,8 @@
|
|||
|
||||
class PasswordComplexityController < ApplicationController
|
||||
def show
|
||||
@score, @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
|
||||
|
|
|
@ -3,37 +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 ||= Zxcvbn::Tester.new
|
||||
end
|
||||
# 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
|
||||
[score, 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
|
||||
|
|
|
@ -1,25 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
describe ZxcvbnService do
|
||||
let(:password) { SECURE_PASSWORD }
|
||||
subject(:service) { ZxcvbnService.new(password) }
|
||||
|
||||
describe '#score' do
|
||||
describe '.complexity' do
|
||||
it 'returns the password complexity score' do
|
||||
expect(service.score).to eq 4
|
||||
end
|
||||
end
|
||||
|
||||
describe '#complexity for strong password' do
|
||||
it 'returns the password score and length' do
|
||||
expect(service.complexity).to eq [4, 20]
|
||||
end
|
||||
end
|
||||
|
||||
describe '#complexity for not strong password' do
|
||||
let(:password) { 'motdepassefrançais' }
|
||||
it 'returns the password score and length' do
|
||||
expect(service.complexity).to eq [1, 18]
|
||||
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
|
||||
|
||||
|
@ -28,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)
|
||||
|
@ -44,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([4, 4, 4, 4])
|
||||
complexities = threads.map(&:value)
|
||||
expect(complexities).to eq([4, 4, 4, 4])
|
||||
expect(Zxcvbn::Tester).to have_received(:new).at_most(:once)
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue