two_factor_authentication 2.0.1 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (27) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +10 -11
  3. data/Gemfile +1 -2
  4. data/README.md +158 -20
  5. data/app/controllers/devise/two_factor_authentication_controller.rb +1 -1
  6. data/app/views/devise/two_factor_authentication/show.html.erb +3 -3
  7. data/lib/two_factor_authentication/controllers/helpers.rb +1 -1
  8. data/lib/two_factor_authentication/hooks/two_factor_authenticatable.rb +5 -1
  9. data/lib/two_factor_authentication/models/two_factor_authenticatable.rb +14 -2
  10. data/lib/two_factor_authentication/orm/active_record.rb +2 -0
  11. data/lib/two_factor_authentication/version.rb +1 -1
  12. data/lib/two_factor_authentication.rb +4 -2
  13. data/spec/controllers/two_factor_authentication_controller_spec.rb +10 -2
  14. data/spec/features/two_factor_authenticatable_spec.rb +12 -0
  15. data/spec/lib/two_factor_authentication/models/two_factor_authenticatable_spec.rb +10 -5
  16. data/spec/rails_app/db/migrate/20140403184646_devise_create_users.rb +1 -1
  17. data/spec/rails_app/db/migrate/20140407172619_two_factor_authentication_add_to_users.rb +1 -1
  18. data/spec/rails_app/db/migrate/20140407215513_add_nickanme_to_users.rb +1 -1
  19. data/spec/rails_app/db/migrate/20151224171231_add_encrypted_columns_to_user.rb +1 -1
  20. data/spec/rails_app/db/migrate/20151224180310_populate_otp_column.rb +1 -1
  21. data/spec/rails_app/db/migrate/20151228230340_remove_otp_secret_key_from_user.rb +1 -1
  22. data/spec/rails_app/db/migrate/20160209032439_devise_create_admins.rb +1 -1
  23. data/spec/rails_app/db/schema.rb +27 -30
  24. data/spec/support/authenticated_model_helper.rb +1 -1
  25. data/spec/support/totp_helper.rb +1 -1
  26. data/two_factor_authentication.gemspec +2 -2
  27. metadata +9 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dec5112783c16117a3f498bed06abb05be9b2206
4
- data.tar.gz: 6a637bc5a895b60da9b46360a799cd0a54d7da59
3
+ metadata.gz: 3d6d6636a281220ef8fd5aee19a4c4aaa4129797
4
+ data.tar.gz: 4954c89fa183dcb47c3104bfb14035ceaf6d20f4
5
5
  SHA512:
6
- metadata.gz: 796540a1cc3c572de0a121f90da0d1c1981689a53c7560e1b6cc2f2e192a9bdca46d9c2cdb6b34a625afbd5ce972959ae58244fb513f79278c122ae8bcb8f962
7
- data.tar.gz: 53685bf09da5ed84bc2a1c8fb2bae730e4b2fb6438afdf871f8f3db0cd8a7e37351d6a581738ea9143bd61267ac9fa9943694443acc0c03776f6651060d04c34
6
+ metadata.gz: c559cf0c9c2c21519efdf25ce615ca5930dfc657564e4209b77298944ea3a2342414e7772b493db65c657c617641d0af4398a31bca0d3fbf81025e417fb688c2
7
+ data.tar.gz: 7e0d5abb909bb53f04d3d0cb887a4e869944eda656318c7e782562ecdf7bd635c8079d144506b1633e71c83368604b989dd9b4a21f2d8c21cb41d1f2849b3b58
data/.travis.yml CHANGED
@@ -1,29 +1,28 @@
1
1
  language: ruby
2
2
 
3
3
  env:
4
- - "RAILS_VERSION=4.0"
5
- - "RAILS_VERSION=4.1"
6
4
  - "RAILS_VERSION=4.2"
5
+ - "RAILS_VERSION=5.2"
7
6
  - "RAILS_VERSION=master"
8
7
 
9
8
  rvm:
10
- - 2.1
11
- - 2.2
12
- - 2.3.1
9
+ - 2.3.8
10
+ - 2.4.5
11
+ - 2.5.3
13
12
 
14
13
  matrix:
14
+ fast_finish: true
15
15
  allow_failures:
16
16
  - env: "RAILS_VERSION=master"
17
- exclude:
18
- - rvm: 2.1
19
- env: RAILS_VERSION=master
17
+ include:
20
18
  - rvm: 2.2
21
- env: RAILS_VERSION=master
19
+ env: RAILS_VERSION=4.2
22
20
 
23
21
  before_install:
24
- - gem update bundler
22
+ - gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true
23
+ - gem install bundler -v '< 2'
25
24
 
26
25
  before_script:
27
- - bundle exec rake app:db:migrate
26
+ - bundle exec rake app:db:setup
28
27
 
29
28
  script: bundle exec rake spec
data/Gemfile CHANGED
@@ -9,7 +9,7 @@ rails = case rails_version
9
9
  when "master"
10
10
  {github: "rails/rails"}
11
11
  when "default"
12
- "~> 4.1"
12
+ "~> 5.2"
13
13
  else
14
14
  "~> #{rails_version}"
15
15
  end
@@ -27,5 +27,4 @@ end
27
27
  group :test do
28
28
  gem 'rack_session_access'
29
29
  gem 'ammeter'
30
- gem 'pry'
31
30
  end
data/README.md CHANGED
@@ -54,7 +54,7 @@ migration in `db/migrate/`, which will add the following columns to your table:
54
54
  #### Manual initial setup
55
55
 
56
56
  If you prefer to set up the model and migration manually, add the
57
- `:two_factor_authentication` option to your existing devise options, such as:
57
+ `:two_factor_authenticatable` option to your existing devise options, such as:
58
58
 
59
59
  ```ruby
60
60
  devise :database_authenticatable, :registerable, :recoverable, :rememberable,
@@ -97,6 +97,7 @@ config.direct_otp_length = 6 # Direct OTP code length
97
97
  config.remember_otp_session_for_seconds = 30.days # Time before browser has to perform 2fA again. Default is 0.
98
98
  config.otp_secret_encryption_key = ENV['OTP_SECRET_ENCRYPTION_KEY']
99
99
  config.second_factor_resource_id = 'id' # Field or method name used to set value for 2fA remember cookie
100
+ config.delete_cookie_on_logout = false # Delete cookie when user signs out, to force 2fA again on login
100
101
  ```
101
102
  The `otp_secret_encryption_key` must be a random key that is not stored in the
102
103
  DB, and is not checked in to your repo. It is recommended to store it in an
@@ -224,25 +225,25 @@ steps:
224
225
  Open the generated file, and replace its contents with the following:
225
226
  ```ruby
226
227
  class PopulateEncryptedOtpFields < ActiveRecord::Migration
227
- def up
228
- User.reset_column_information
229
-
230
- User.find_each do |user|
231
- user.otp_secret_key = user.read_attribute('otp_secret_key')
232
- user.save!
233
- end
234
- end
235
-
236
- def down
237
- User.reset_column_information
238
-
239
- User.find_each do |user|
240
- user.otp_secret_key = ROTP::Base32.random_base32
241
- user.save!
242
- end
243
- end
244
- end
245
- ```
228
+ def up
229
+ User.reset_column_information
230
+
231
+ User.find_each do |user|
232
+ user.otp_secret_key = user.read_attribute('otp_secret_key')
233
+ user.save!
234
+ end
235
+ end
236
+
237
+ def down
238
+ User.reset_column_information
239
+
240
+ User.find_each do |user|
241
+ user.otp_secret_key = ROTP::Base32.random_base32
242
+ user.save!
243
+ end
244
+ end
245
+ end
246
+ ```
246
247
 
247
248
  5. Generate a migration to remove the `:otp_secret_key` column:
248
249
  ```
@@ -262,6 +263,143 @@ after them):
262
263
  bundle exec rake db:rollback STEP=3
263
264
  ```
264
265
 
266
+ #### Critical Security Note! Add before_action to your user registration controllers
267
+
268
+ You should have a file registrations_controller.rb in your controllers folder
269
+ to overwrite/customize user registrations. It should include the lines below, for 2FA protection of user model updates, meaning that users can only access the users/edit page after confirming 2FA fully, not simply by logging in. Otherwise the entire 2FA system can be bypassed!
270
+
271
+ ```ruby
272
+ class RegistrationsController < Devise::RegistrationsController
273
+ before_action :confirm_two_factor_authenticated, except: [:new, :create, :cancel]
274
+
275
+ protected
276
+
277
+ def confirm_two_factor_authenticated
278
+ return if is_fully_authenticated?
279
+
280
+ flash[:error] = t('devise.errors.messages.user_not_authenticated')
281
+ redirect_to user_two_factor_authentication_url
282
+ end
283
+ end
284
+ ```
285
+
286
+ #### Critical Security Note! Add 2FA validation to your custom user actions
287
+
288
+ Make sure you are passing the 2FA secret codes securely and checking for them upon critical user actions, such as API key updates, user email or pgp pubkey updates, or any other changess to private/secure account-related details. Validate the secret during the initial 2FA key/secret verification by the user also, of course.
289
+
290
+ For example, a simple account_controller.rb may look something like this:
291
+
292
+ ```
293
+ require 'json'
294
+
295
+ class AccountController < ApplicationController
296
+ before_action :require_signed_in!
297
+ before_action :authenticate_user!
298
+ respond_to :html, :json
299
+
300
+ def account_API
301
+ resp = {}
302
+ begin
303
+ if(account_params["twoFAKey"] && account_params["twoFASecret"])
304
+ current_user.otp_secret_key = account_params["twoFAKey"]
305
+ if(current_user.authenticate_totp(account_params["twoFASecret"]))
306
+ # user has validated their temporary 2FA code, save it to their account, enable 2FA on this account
307
+ current_user.save!
308
+ resp['success'] = "passed 2FA validation!"
309
+ else
310
+ resp['error'] = "failed 2FA validation!"
311
+ end
312
+ elsif(param[:userAccountStuff] && param[:userAccountWidget])
313
+ #before updating important user account stuff and widgets,
314
+ #check to see that the 2FA secret has also been passed in, and verify it...
315
+ if(account_params["twoFASecret"] && current_user.totp_enabled? && current_user.authenticate_totp(account_params["twoFASecret"]))
316
+ # user has passed 2FA checks, do cool user account stuff here
317
+ ...
318
+ else
319
+ # user failed 2FA check! No cool user stuff happens!
320
+ resp[error] = 'You failed 2FA validation!'
321
+ end
322
+
323
+ ...
324
+ end
325
+ else
326
+ resp['error'] = 'unknown format error, not saved!'
327
+ end
328
+ rescue Exception => e
329
+ puts "WARNING: account api threw error : '#{e}' for user #{current_user.username}"
330
+ #print "error trace: #{e.backtrace}\n"
331
+ resp['error'] = "unanticipated server response"
332
+ end
333
+ render json: resp.to_json
334
+ end
335
+
336
+ def account_params
337
+ params.require(:twoFA).permit(:userAccountStuff, :userAcountWidget, :twoFAKey, :twoFASecret)
338
+ end
339
+ end
340
+ ```
341
+
342
+
265
343
  ### Example App
266
344
 
267
345
  [TwoFactorAuthenticationExample](https://github.com/Houdini/TwoFactorAuthenticationExample)
346
+
347
+
348
+ ### Example user actions
349
+
350
+ to use an ENV VAR for the 2FA encryption key:
351
+
352
+ config.otp_secret_encryption_key = ENV['OTP_SECRET_ENCRYPTION_KEY']
353
+
354
+ to set up TOTP for Google Authenticator for user:
355
+
356
+ ```
357
+ current_user.otp_secret_key = current_user.generate_totp_secret
358
+ current_user.save!
359
+ ```
360
+
361
+ ( encrypted db fields are set upon user model save action,
362
+ rails c access relies on setting env var: OTP_SECRET_ENCRYPTION_KEY )
363
+
364
+ to check if user has input the correct code (from the QR display page)
365
+ before saving the user model:
366
+
367
+ ```
368
+ current_user.authenticate_totp('123456')
369
+ ```
370
+
371
+ additional note:
372
+
373
+ ```
374
+ current_user.otp_secret_key
375
+ ```
376
+
377
+ This returns the OTP secret key in plaintext for the user (if you have set the env var) in the console
378
+ the string used for generating the QR given to the user for their Google Auth is something like:
379
+
380
+ otpauth://totp/LABEL?secret=p6wwetjnkjnrcmpd (example secret used here)
381
+
382
+ where LABEL should be something like "example.com (Username)", which shows up in their GA app to remind them the code is for example.com
383
+
384
+ this returns true or false with an allowed_otp_drift_seconds 'grace period'
385
+
386
+ to set TOTP to DISABLED for a user account:
387
+
388
+ ```
389
+ current_user.second_factor_attempts_count=nil
390
+ current_user.encrypted_otp_secret_key=nil
391
+ current_user.encrypted_otp_secret_key_iv=nil
392
+ current_user.encrypted_otp_secret_key_salt=nil
393
+ current_user.direct_otp=nil
394
+ current_user.direct_otp_sent_at=nil
395
+ current_user.totp_timestamp=nil
396
+ current_user.direct_otp=nil
397
+ current_user.otp_secret_key=nil
398
+ current_user.otp_confirmed=nil
399
+ current_user.save! (if in ruby code instead of console)
400
+ current_user.direct_otp? => false
401
+ current_user.totp_enabled? => false
402
+ ```
403
+
404
+
405
+
@@ -47,7 +47,7 @@ class Devise::TwoFactorAuthenticationController < DeviseController
47
47
  if expires_seconds && expires_seconds > 0
48
48
  cookies.signed[TwoFactorAuthentication::REMEMBER_TFA_COOKIE_NAME] = {
49
49
  value: "#{resource.class}-#{resource.public_send(Devise.second_factor_resource_id)}",
50
- expires: expires_seconds.from_now
50
+ expires: expires_seconds.seconds.from_now
51
51
  }
52
52
  end
53
53
  end
@@ -12,8 +12,8 @@
12
12
  <% end %>
13
13
 
14
14
  <% if resource.direct_otp %>
15
- <%= link_to "Resend Code", resend_code_user_two_factor_authentication_path, action: :get %>
15
+ <%= link_to "Resend Code", send("resend_code_#{resource_name}_two_factor_authentication_path"), action: :get %>
16
16
  <% else %>
17
- <%= link_to "Send me a code instead", resend_code_user_two_factor_authentication_path, action: :get %>
17
+ <%= link_to "Send me a code instead", send("resend_code_#{resource_name}_two_factor_authentication_path"), action: :get %>
18
18
  <% end %>
19
- <%= link_to "Sign out", destroy_user_session_path, :method => :delete %>
19
+ <%= link_to "Sign out", send("destroy_#{resource_name}_session_path"), :method => :delete %>
@@ -24,7 +24,7 @@ module TwoFactorAuthentication
24
24
  session["#{scope}_return_to"] = request.original_fullpath if request.get?
25
25
  redirect_to two_factor_authentication_path_for(scope)
26
26
  else
27
- render nothing: true, status: :unauthorized
27
+ head :unauthorized
28
28
  end
29
29
  end
30
30
 
@@ -7,7 +7,11 @@ Warden::Manager.after_authentication do |user, auth, options|
7
7
 
8
8
  if user.respond_to?(:need_two_factor_authentication?) && !bypass_by_cookie
9
9
  if auth.session(options[:scope])[TwoFactorAuthentication::NEED_AUTHENTICATION] = user.need_two_factor_authentication?(auth.request)
10
- user.send_new_otp unless user.totp_enabled?
10
+ user.send_new_otp if user.send_new_otp_after_login?
11
11
  end
12
12
  end
13
13
  end
14
+
15
+ Warden::Manager.before_logout do |user, auth, _options|
16
+ auth.cookies.delete TwoFactorAuthentication::REMEMBER_TFA_COOKIE_NAME if Devise.delete_cookie_on_logout
17
+ end
@@ -16,7 +16,8 @@ module Devise
16
16
  ::Devise::Models.config(
17
17
  self, :max_login_attempts, :allowed_otp_drift_seconds, :otp_length,
18
18
  :remember_otp_session_for_seconds, :otp_secret_encryption_key,
19
- :direct_otp_length, :direct_otp_valid_for, :totp_timestamp)
19
+ :direct_otp_length, :direct_otp_valid_for, :totp_timestamp, :delete_cookie_on_logout
20
+ )
20
21
  end
21
22
 
22
23
  module InstanceMethodsOnActivation
@@ -38,7 +39,10 @@ module Devise
38
39
  drift = options[:drift] || self.class.allowed_otp_drift_seconds
39
40
  raise "authenticate_totp called with no otp_secret_key set" if totp_secret.nil?
40
41
  totp = ROTP::TOTP.new(totp_secret, digits: digits)
41
- new_timestamp = totp.verify_with_drift_and_prior(code, drift, totp_timestamp)
42
+ new_timestamp = totp.verify(
43
+ without_spaces(code),
44
+ drift_ahead: drift, drift_behind: drift, after: totp_timestamp
45
+ )
42
46
  return false unless new_timestamp
43
47
  self.totp_timestamp = new_timestamp
44
48
  true
@@ -61,6 +65,10 @@ module Devise
61
65
  send_two_factor_authentication_code(direct_otp)
62
66
  end
63
67
 
68
+ def send_new_otp_after_login?
69
+ !totp_enabled?
70
+ end
71
+
64
72
  def send_two_factor_authentication_code(code)
65
73
  raise NotImplementedError.new("No default implementation - please define in your class.")
66
74
  end
@@ -98,6 +106,10 @@ module Devise
98
106
 
99
107
  private
100
108
 
109
+ def without_spaces(code)
110
+ code.gsub(/\s/, '')
111
+ end
112
+
101
113
  def random_base10(digits)
102
114
  SecureRandom.random_number(10**digits).to_s.rjust(digits, '0')
103
115
  end
@@ -1,3 +1,5 @@
1
+ require "active_record"
2
+
1
3
  module TwoFactorAuthentication
2
4
  module Orm
3
5
  module ActiveRecord
@@ -1,3 +1,3 @@
1
1
  module TwoFactorAuthentication
2
- VERSION = "2.0.1".freeze
2
+ VERSION = "2.2.0".freeze
3
3
  end
@@ -2,7 +2,6 @@ require 'two_factor_authentication/version'
2
2
  require 'devise'
3
3
  require 'active_support/concern'
4
4
  require "active_model"
5
- require "active_record"
6
5
  require "active_support/core_ext/class/attribute_accessors"
7
6
  require "cgi"
8
7
 
@@ -30,6 +29,9 @@ module Devise
30
29
 
31
30
  mattr_accessor :second_factor_resource_id
32
31
  @@second_factor_resource_id = 'id'
32
+
33
+ mattr_accessor :delete_cookie_on_logout
34
+ @@delete_cookie_on_logout = false
33
35
  end
34
36
 
35
37
  module TwoFactorAuthentication
@@ -44,7 +46,7 @@ end
44
46
 
45
47
  Devise.add_module :two_factor_authenticatable, :model => 'two_factor_authentication/models/two_factor_authenticatable', :controller => :two_factor_authentication, :route => :two_factor_authentication
46
48
 
47
- require 'two_factor_authentication/orm/active_record'
49
+ require 'two_factor_authentication/orm/active_record' if defined?(ActiveRecord::Base)
48
50
  require 'two_factor_authentication/routes'
49
51
  require 'two_factor_authentication/models/two_factor_authenticatable'
50
52
  require 'two_factor_authentication/rails'
@@ -2,6 +2,14 @@ require 'spec_helper'
2
2
 
3
3
  describe Devise::TwoFactorAuthenticationController, type: :controller do
4
4
  describe 'is_fully_authenticated? helper' do
5
+ def post_code(code)
6
+ if Rails::VERSION::MAJOR >= 5
7
+ post :update, params: { code: code }
8
+ else
9
+ post :update, code: code
10
+ end
11
+ end
12
+
5
13
  before do
6
14
  sign_in
7
15
  end
@@ -9,7 +17,7 @@ describe Devise::TwoFactorAuthenticationController, type: :controller do
9
17
  context 'after user enters valid OTP code' do
10
18
  it 'returns true' do
11
19
  controller.current_user.send_new_otp
12
- post :update, code: controller.current_user.direct_otp
20
+ post_code controller.current_user.direct_otp
13
21
  expect(subject.is_fully_authenticated?).to eq true
14
22
  end
15
23
  end
@@ -24,7 +32,7 @@ describe Devise::TwoFactorAuthenticationController, type: :controller do
24
32
 
25
33
  context 'when user enters an invalid OTP' do
26
34
  it 'returns false' do
27
- post :update, code: '12345'
35
+ post_code '12345'
28
36
 
29
37
  expect(subject.is_fully_authenticated?).to eq false
30
38
  end
@@ -174,6 +174,18 @@ feature "User of two factor authentication" do
174
174
  visit dashboard_path
175
175
  expect(page).to have_content("Enter the code that was sent to you")
176
176
  end
177
+
178
+ scenario 'Delete cookie when user logs out if enabled' do
179
+ user.class.delete_cookie_on_logout = true
180
+
181
+ login_as user
182
+ logout
183
+
184
+ login_as user
185
+
186
+ visit dashboard_path
187
+ expect(page).to have_content("Enter the code that was sent to you")
188
+ end
177
189
  end
178
190
 
179
191
  it 'sets the warden session need_two_factor_authentication key to true' do
@@ -86,6 +86,11 @@ describe Devise::Models::TwoFactorAuthenticatable do
86
86
  expect(do_invoke(code, instance)).to eq(true)
87
87
  end
88
88
 
89
+ it 'authenticates a code entered with a space' do
90
+ code = @totp_helper.totp_code.insert(3, ' ')
91
+ expect(do_invoke(code, instance)).to eq(true)
92
+ end
93
+
89
94
  it 'does not authenticate an old code' do
90
95
  code = @totp_helper.totp_code(1.minutes.ago.to_i)
91
96
  expect(do_invoke(code, instance)).to eq(false)
@@ -133,12 +138,12 @@ describe Devise::Models::TwoFactorAuthenticatable do
133
138
 
134
139
  it "returns uri with user's email" do
135
140
  expect(instance.provisioning_uri).
136
- to match(%r{otpauth://totp/houdini@example.com\?secret=\w{16}})
141
+ to match(%r{otpauth://totp/houdini@example.com\?secret=\w{32}})
137
142
  end
138
143
 
139
144
  it 'returns uri with issuer option' do
140
145
  expect(instance.provisioning_uri('houdini')).
141
- to match(%r{otpauth://totp/houdini\?secret=\w{16}$})
146
+ to match(%r{otpauth://totp/houdini\?secret=\w{32}$})
142
147
  end
143
148
 
144
149
  it 'returns uri with issuer option' do
@@ -150,7 +155,7 @@ describe Devise::Models::TwoFactorAuthenticatable do
150
155
  expect(uri.host).to eq('totp')
151
156
  expect(uri.path).to eq('/Magic:houdini')
152
157
  expect(params['issuer'].shift).to eq('Magic')
153
- expect(params['secret'].shift).to match(/\w{16}/)
158
+ expect(params['secret'].shift).to match(/\w{32}/)
154
159
  end
155
160
  end
156
161
  end
@@ -163,10 +168,10 @@ describe Devise::Models::TwoFactorAuthenticatable do
163
168
  shared_examples 'generate_totp_secret' do |klass|
164
169
  let(:instance) { klass.new }
165
170
 
166
- it 'returns a 16 character string' do
171
+ it 'returns a 32 character string' do
167
172
  secret = instance.generate_totp_secret
168
173
 
169
- expect(secret).to match(/\w{16}/)
174
+ expect(secret).to match(/\w{32}/)
170
175
  end
171
176
  end
172
177
 
@@ -1,4 +1,4 @@
1
- class DeviseCreateUsers < ActiveRecord::Migration
1
+ class DeviseCreateUsers < ActiveRecord::Migration[4.2]
2
2
  def change
3
3
  create_table(:users) do |t|
4
4
  ## Database authenticatable
@@ -1,4 +1,4 @@
1
- class TwoFactorAuthenticationAddToUsers < ActiveRecord::Migration
1
+ class TwoFactorAuthenticationAddToUsers < ActiveRecord::Migration[4.2]
2
2
  def up
3
3
  change_table :users do |t|
4
4
  t.string :otp_secret_key
@@ -1,4 +1,4 @@
1
- class AddNickanmeToUsers < ActiveRecord::Migration
1
+ class AddNickanmeToUsers < ActiveRecord::Migration[4.2]
2
2
  def change
3
3
  change_table :users do |t|
4
4
  t.column :nickname, :string, limit: 64
@@ -1,4 +1,4 @@
1
- class AddEncryptedColumnsToUser < ActiveRecord::Migration
1
+ class AddEncryptedColumnsToUser < ActiveRecord::Migration[4.2]
2
2
  def change
3
3
  add_column :users, :encrypted_otp_secret_key, :string
4
4
  add_column :users, :encrypted_otp_secret_key_iv, :string
@@ -1,4 +1,4 @@
1
- class PopulateOtpColumn < ActiveRecord::Migration
1
+ class PopulateOtpColumn < ActiveRecord::Migration[4.2]
2
2
  def up
3
3
  User.reset_column_information
4
4
 
@@ -1,4 +1,4 @@
1
- class RemoveOtpSecretKeyFromUser < ActiveRecord::Migration
1
+ class RemoveOtpSecretKeyFromUser < ActiveRecord::Migration[4.2]
2
2
  def change
3
3
  remove_column :users, :otp_secret_key, :string
4
4
  end
@@ -1,4 +1,4 @@
1
- class DeviseCreateAdmins < ActiveRecord::Migration
1
+ class DeviseCreateAdmins < ActiveRecord::Migration[4.2]
2
2
  def change
3
3
  create_table(:admins) do |t|
4
4
  ## Database authenticatable
@@ -1,4 +1,3 @@
1
- # encoding: UTF-8
2
1
  # This file is auto-generated from the current state of the database. Instead
3
2
  # of editing this file, please use the migrations feature of Active Record to
4
3
  # incrementally modify your database, and then regenerate this schema definition.
@@ -11,48 +10,46 @@
11
10
  #
12
11
  # It's strongly recommended that you check this file into your version control system.
13
12
 
14
- ActiveRecord::Schema.define(version: 20160209032439) do
13
+ ActiveRecord::Schema.define(version: 2016_02_09_032439) do
15
14
 
16
15
  create_table "admins", force: :cascade do |t|
17
- t.string "email", default: "", null: false
18
- t.string "encrypted_password", default: "", null: false
19
- t.string "reset_password_token"
16
+ t.string "email", default: "", null: false
17
+ t.string "encrypted_password", default: "", null: false
18
+ t.string "reset_password_token"
20
19
  t.datetime "reset_password_sent_at"
21
20
  t.datetime "remember_created_at"
22
- t.integer "sign_in_count", default: 0, null: false
21
+ t.integer "sign_in_count", default: 0, null: false
23
22
  t.datetime "current_sign_in_at"
24
23
  t.datetime "last_sign_in_at"
25
- t.string "current_sign_in_ip"
26
- t.string "last_sign_in_ip"
27
- t.datetime "created_at", null: false
28
- t.datetime "updated_at", null: false
24
+ t.string "current_sign_in_ip"
25
+ t.string "last_sign_in_ip"
26
+ t.datetime "created_at", null: false
27
+ t.datetime "updated_at", null: false
28
+ t.index ["email"], name: "index_admins_on_email", unique: true
29
+ t.index ["reset_password_token"], name: "index_admins_on_reset_password_token", unique: true
29
30
  end
30
31
 
31
- add_index "admins", ["email"], name: "index_admins_on_email", unique: true
32
- add_index "admins", ["reset_password_token"], name: "index_admins_on_reset_password_token", unique: true
33
-
34
32
  create_table "users", force: :cascade do |t|
35
- t.string "email", default: "", null: false
36
- t.string "encrypted_password", default: "", null: false
37
- t.string "reset_password_token"
33
+ t.string "email", default: "", null: false
34
+ t.string "encrypted_password", default: "", null: false
35
+ t.string "reset_password_token"
38
36
  t.datetime "reset_password_sent_at"
39
37
  t.datetime "remember_created_at"
40
- t.integer "sign_in_count", default: 0, null: false
38
+ t.integer "sign_in_count", default: 0, null: false
41
39
  t.datetime "current_sign_in_at"
42
40
  t.datetime "last_sign_in_at"
43
- t.string "current_sign_in_ip"
44
- t.string "last_sign_in_ip"
45
- t.datetime "created_at", null: false
46
- t.datetime "updated_at", null: false
47
- t.integer "second_factor_attempts_count", default: 0
48
- t.string "nickname", limit: 64
49
- t.string "encrypted_otp_secret_key"
50
- t.string "encrypted_otp_secret_key_iv"
51
- t.string "encrypted_otp_secret_key_salt"
41
+ t.string "current_sign_in_ip"
42
+ t.string "last_sign_in_ip"
43
+ t.datetime "created_at", null: false
44
+ t.datetime "updated_at", null: false
45
+ t.integer "second_factor_attempts_count", default: 0
46
+ t.string "nickname", limit: 64
47
+ t.string "encrypted_otp_secret_key"
48
+ t.string "encrypted_otp_secret_key_iv"
49
+ t.string "encrypted_otp_secret_key_salt"
50
+ t.index ["email"], name: "index_users_on_email", unique: true
51
+ t.index ["encrypted_otp_secret_key"], name: "index_users_on_encrypted_otp_secret_key", unique: true
52
+ t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
52
53
  end
53
54
 
54
- add_index "users", ["email"], name: "index_users_on_email", unique: true
55
- add_index "users", ["encrypted_otp_secret_key"], name: "index_users_on_encrypted_otp_secret_key", unique: true
56
- add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
57
-
58
55
  end
@@ -29,7 +29,7 @@ module AuthenticatedModelHelper
29
29
  end
30
30
 
31
31
  def create_table_for_nonencrypted_user
32
- silence_stream(STDOUT) do
32
+ ActiveRecord::Migration.suppress_messages do
33
33
  ActiveRecord::Schema.define(version: 1) do
34
34
  create_table 'users', force: :cascade do |t|
35
35
  t.string 'email', default: '', null: false
@@ -6,6 +6,6 @@ class TotpHelper
6
6
  end
7
7
 
8
8
  def totp_code(time = Time.now)
9
- ROTP::TOTP.new(@secret_key, digits: @otp_length).at(time, true)
9
+ ROTP::TOTP.new(@secret_key, digits: @otp_length).at(time)
10
10
  end
11
11
  end
@@ -27,13 +27,13 @@ Gem::Specification.new do |s|
27
27
  s.add_runtime_dependency 'rails', '>= 3.1.1'
28
28
  s.add_runtime_dependency 'devise'
29
29
  s.add_runtime_dependency 'randexp'
30
- s.add_runtime_dependency 'rotp', '>= 3.2.0'
30
+ s.add_runtime_dependency 'rotp', '>= 4.0.0'
31
31
  s.add_runtime_dependency 'encryptor'
32
32
 
33
33
  s.add_development_dependency 'bundler'
34
34
  s.add_development_dependency 'rake'
35
35
  s.add_development_dependency 'rspec-rails', '>= 3.0.1'
36
- s.add_development_dependency 'capybara', '2.4.1'
36
+ s.add_development_dependency 'capybara', '~> 2.5'
37
37
  s.add_development_dependency 'pry'
38
38
  s.add_development_dependency 'timecop'
39
39
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: two_factor_authentication
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitrii Golub
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-18 00:00:00.000000000 Z
11
+ date: 2019-01-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: 3.2.0
61
+ version: 4.0.0
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: 3.2.0
68
+ version: 4.0.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: encryptor
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -126,16 +126,16 @@ dependencies:
126
126
  name: capybara
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - '='
129
+ - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: 2.4.1
131
+ version: '2.5'
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - '='
136
+ - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: 2.4.1
138
+ version: '2.5'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: pry
141
141
  requirement: !ruby/object:Gem::Requirement
@@ -286,7 +286,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
286
286
  version: '0'
287
287
  requirements: []
288
288
  rubyforge_project: two_factor_authentication
289
- rubygems_version: 2.6.12
289
+ rubygems_version: 2.6.14
290
290
  signing_key:
291
291
  specification_version: 4
292
292
  summary: Two factor authentication plugin for devise