Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ gem 'american_date'
gem 'browserify-rails'
gem 'coffee-rails', '~> 4.1.0'
gem 'devise', '~> 4.1'
gem 'devise-encryptable'
gem 'devise-scrypt'
gem 'devise_zxcvbn'
gem 'dotiw'
gem 'figaro'
Expand Down
14 changes: 14 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,12 @@ GEM
railties (>= 4.1.0, < 5.1)
responders
warden (~> 1.2.3)
devise-encryptable (0.2.0)
devise (>= 2.1.0)
devise-scrypt (1.0.0)
devise (>= 2.1.0)
devise-encryptable (>= 0.1.1)
scrypt (>= 1.1.0)
devise_zxcvbn (2.1.2)
devise
zxcvbn-js (~> 4.2.0)
Expand Down Expand Up @@ -215,6 +221,9 @@ GEM
faker (1.6.6)
i18n (~> 0.5)
ffi (1.9.14)
ffi-compiler (1.0.1)
ffi (>= 1.0.0)
rake
figaro (1.1.1)
thor (~> 0.14)
formatador (0.2.5)
Expand Down Expand Up @@ -464,6 +473,9 @@ GEM
nokogiri (>= 1.4.0)
nori (~> 2.4)
wasabi (~> 3.4)
scrypt (3.0.3)
ffi-compiler (>= 1.0.0)
rake
secure_headers (3.4.0)
useragent
shellany (0.0.1)
Expand Down Expand Up @@ -619,6 +631,8 @@ DEPENDENCIES
database_cleaner
derailed
devise (~> 4.1)
devise-encryptable
devise-scrypt
devise_zxcvbn
dotiw
email_spec
Expand Down
2 changes: 1 addition & 1 deletion app/forms/recovery_code_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def submit
attr_reader :user, :code, :success

def valid_recovery_code?
Devise::Encryptor.compare(User, user.recovery_code, code)
RecoveryCodeGenerator.new(user).valid?(code)
end

def result
Expand Down
10 changes: 9 additions & 1 deletion app/services/recovery_code_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,20 @@ def create
raw_recovery_code
end

def valid?(raw_code)
SCrypt::Password.new(user.recovery_code) == peppered_code(raw_code)
end

private

attr_reader :length, :user

def peppered_code(raw_code = raw_recovery_code)
"#{raw_code}#{User.pepper}"
end

def hashed_code
Devise::Encryptor.digest(User, raw_recovery_code)
SCrypt::Password.create(peppered_code)
end

def raw_recovery_code
Expand Down
18 changes: 17 additions & 1 deletion config/initializers/devise.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,23 @@
config.sign_in_after_reset_password = false
config.sign_out_via = :delete
config.skip_session_storage = [:http_auth]
config.stretches = Rails.env.test? ? 1 : 12

# The scrypt encryptor ignores stretches but we keep for compatability.
# We can set the scrypt config directly.
# see https://github.com/pbhogan/scrypt
# and https://github.com/capita/devise-scrypt
# We set the test config much lower just to speed up tests.
config.encryptor = :scrypt
if Rails.env.test?
SCrypt::Engine::DEFAULTS[:key_len] = 16
SCrypt::Engine::DEFAULTS[:salt_size] = 8
config.stretches = 1
else
SCrypt::Engine::DEFAULTS[:key_len] = 64
SCrypt::Engine::DEFAULTS[:salt_size] = 32
config.stretches = 12
end

config.strip_whitespace_keys = [:email]
config.timeout_in = Figaro.env.session_timeout_in.to_i.minutes

Expand Down
2 changes: 1 addition & 1 deletion spec/factories/users.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

trait :signed_up do
with_phone
recovery_code '$2a$10$vOkU3l3j0aYgWbXVdwJA5.FICxwydpvPrzBuzjFZUXDnPeXkMHeLe'
recovery_code SCrypt::Password.create('recovery' + User.pepper)
end

trait :unconfirmed do
Expand Down
12 changes: 12 additions & 0 deletions spec/services/recovery_code_generator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,16 @@
expect(generator.create).to match(/\A[a-zA-Z0-9]{14}\z/)
end
end

describe '#valid?' do
it 'validates the raw recovery code against what is stored for the User' do
user = create(:user)
generator = RecoveryCodeGenerator.new(user)
raw_code = generator.create

generator2 = RecoveryCodeGenerator.new(user)

expect(generator2.valid?(raw_code)).to eq true
end
end
end