two_factor_authentication 2.1.1 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +10 -11
- data/Gemfile +1 -2
- data/README.md +156 -19
- data/lib/two_factor_authentication.rb +1 -2
- data/lib/two_factor_authentication/controllers/helpers.rb +1 -1
- data/lib/two_factor_authentication/models/two_factor_authenticatable.rb +8 -1
- data/lib/two_factor_authentication/orm/active_record.rb +2 -0
- data/lib/two_factor_authentication/version.rb +1 -1
- data/spec/controllers/two_factor_authentication_controller_spec.rb +10 -2
- data/spec/lib/two_factor_authentication/models/two_factor_authenticatable_spec.rb +10 -5
- data/spec/rails_app/db/migrate/20140403184646_devise_create_users.rb +1 -1
- data/spec/rails_app/db/migrate/20140407172619_two_factor_authentication_add_to_users.rb +1 -1
- data/spec/rails_app/db/migrate/20140407215513_add_nickanme_to_users.rb +1 -1
- data/spec/rails_app/db/migrate/20151224171231_add_encrypted_columns_to_user.rb +1 -1
- data/spec/rails_app/db/migrate/20151224180310_populate_otp_column.rb +1 -1
- data/spec/rails_app/db/migrate/20151228230340_remove_otp_secret_key_from_user.rb +1 -1
- data/spec/rails_app/db/migrate/20160209032439_devise_create_admins.rb +1 -1
- data/spec/rails_app/db/schema.rb +27 -30
- data/spec/support/authenticated_model_helper.rb +1 -1
- data/spec/support/totp_helper.rb +1 -1
- data/two_factor_authentication.gemspec +2 -2
- metadata +8 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d6d6636a281220ef8fd5aee19a4c4aaa4129797
|
4
|
+
data.tar.gz: 4954c89fa183dcb47c3104bfb14035ceaf6d20f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
11
|
-
- 2.
|
12
|
-
- 2.3
|
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
|
-
|
18
|
-
- rvm: 2.1
|
19
|
-
env: RAILS_VERSION=master
|
17
|
+
include:
|
20
18
|
- rvm: 2.2
|
21
|
-
env: RAILS_VERSION=
|
19
|
+
env: RAILS_VERSION=4.2
|
22
20
|
|
23
21
|
before_install:
|
24
|
-
- gem
|
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:
|
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
|
-
"~>
|
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
|
-
`:
|
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,
|
@@ -225,24 +225,24 @@ steps:
|
|
225
225
|
Open the generated file, and replace its contents with the following:
|
226
226
|
```ruby
|
227
227
|
class PopulateEncryptedOtpFields < ActiveRecord::Migration
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
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
248
|
5. Generate a migration to remove the `:otp_secret_key` column:
|
@@ -263,6 +263,143 @@ after them):
|
|
263
263
|
bundle exec rake db:rollback STEP=3
|
264
264
|
```
|
265
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
|
+
|
266
343
|
### Example App
|
267
344
|
|
268
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
|
+
|
@@ -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
|
|
@@ -47,7 +46,7 @@ end
|
|
47
46
|
|
48
47
|
Devise.add_module :two_factor_authenticatable, :model => 'two_factor_authentication/models/two_factor_authenticatable', :controller => :two_factor_authentication, :route => :two_factor_authentication
|
49
48
|
|
50
|
-
require 'two_factor_authentication/orm/active_record'
|
49
|
+
require 'two_factor_authentication/orm/active_record' if defined?(ActiveRecord::Base)
|
51
50
|
require 'two_factor_authentication/routes'
|
52
51
|
require 'two_factor_authentication/models/two_factor_authenticatable'
|
53
52
|
require 'two_factor_authentication/rails'
|
@@ -39,7 +39,10 @@ module Devise
|
|
39
39
|
drift = options[:drift] || self.class.allowed_otp_drift_seconds
|
40
40
|
raise "authenticate_totp called with no otp_secret_key set" if totp_secret.nil?
|
41
41
|
totp = ROTP::TOTP.new(totp_secret, digits: digits)
|
42
|
-
new_timestamp = totp.
|
42
|
+
new_timestamp = totp.verify(
|
43
|
+
without_spaces(code),
|
44
|
+
drift_ahead: drift, drift_behind: drift, after: totp_timestamp
|
45
|
+
)
|
43
46
|
return false unless new_timestamp
|
44
47
|
self.totp_timestamp = new_timestamp
|
45
48
|
true
|
@@ -103,6 +106,10 @@ module Devise
|
|
103
106
|
|
104
107
|
private
|
105
108
|
|
109
|
+
def without_spaces(code)
|
110
|
+
code.gsub(/\s/, '')
|
111
|
+
end
|
112
|
+
|
106
113
|
def random_base10(digits)
|
107
114
|
SecureRandom.random_number(10**digits).to_s.rjust(digits, '0')
|
108
115
|
end
|
@@ -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
|
-
|
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
|
-
|
35
|
+
post_code '12345'
|
28
36
|
|
29
37
|
expect(subject.is_fully_authenticated?).to eq false
|
30
38
|
end
|
@@ -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{
|
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{
|
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{
|
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
|
171
|
+
it 'returns a 32 character string' do
|
167
172
|
secret = instance.generate_totp_secret
|
168
173
|
|
169
|
-
expect(secret).to match(/\w{
|
174
|
+
expect(secret).to match(/\w{32}/)
|
170
175
|
end
|
171
176
|
end
|
172
177
|
|
data/spec/rails_app/db/schema.rb
CHANGED
@@ -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:
|
13
|
+
ActiveRecord::Schema.define(version: 2016_02_09_032439) do
|
15
14
|
|
16
15
|
create_table "admins", force: :cascade do |t|
|
17
|
-
t.string
|
18
|
-
t.string
|
19
|
-
t.string
|
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
|
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
|
26
|
-
t.string
|
27
|
-
t.datetime "created_at",
|
28
|
-
t.datetime "updated_at",
|
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
|
36
|
-
t.string
|
37
|
-
t.string
|
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
|
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
|
44
|
-
t.string
|
45
|
-
t.datetime "created_at",
|
46
|
-
t.datetime "updated_at",
|
47
|
-
t.integer
|
48
|
-
t.string
|
49
|
-
t.string
|
50
|
-
t.string
|
51
|
-
t.string
|
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
|
-
|
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
|
data/spec/support/totp_helper.rb
CHANGED
@@ -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', '>=
|
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.
|
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.
|
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:
|
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:
|
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:
|
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.
|
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.
|
138
|
+
version: '2.5'
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: pry
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|