devise-otp-rails5 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +42 -0
  3. data/.travis.yml +12 -0
  4. data/Gemfile +25 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +140 -0
  7. data/Rakefile +42 -0
  8. data/app/assets/javascripts/devise-otp.js +1 -0
  9. data/app/assets/javascripts/qrcode.js +609 -0
  10. data/app/controllers/devise_otp/credentials_controller.rb +106 -0
  11. data/app/controllers/devise_otp/tokens_controller.rb +111 -0
  12. data/app/views/devise_otp/credentials/refresh.html.erb +20 -0
  13. data/app/views/devise_otp/credentials/show.html.erb +23 -0
  14. data/app/views/devise_otp/tokens/_token_secret.html.erb +19 -0
  15. data/app/views/devise_otp/tokens/_trusted_devices.html.erb +10 -0
  16. data/app/views/devise_otp/tokens/recovery.html.erb +21 -0
  17. data/app/views/devise_otp/tokens/recovery_codes.text.erb +3 -0
  18. data/app/views/devise_otp/tokens/show.html.erb +19 -0
  19. data/config/locales/en.yml +66 -0
  20. data/devise-otp.gemspec +25 -0
  21. data/lib/devise-otp.rb +83 -0
  22. data/lib/devise-otp/version.rb +5 -0
  23. data/lib/devise_otp_authenticatable/controllers/helpers.rb +168 -0
  24. data/lib/devise_otp_authenticatable/controllers/url_helpers.rb +33 -0
  25. data/lib/devise_otp_authenticatable/engine.rb +23 -0
  26. data/lib/devise_otp_authenticatable/hooks.rb +13 -0
  27. data/lib/devise_otp_authenticatable/hooks/sessions.rb +59 -0
  28. data/lib/devise_otp_authenticatable/mapping.rb +19 -0
  29. data/lib/devise_otp_authenticatable/models/otp_authenticatable.rb +137 -0
  30. data/lib/devise_otp_authenticatable/routes.rb +32 -0
  31. data/lib/generators/active_record/devise_otp_generator.rb +13 -0
  32. data/lib/generators/active_record/templates/migration.rb +27 -0
  33. data/lib/generators/devise_otp/devise_otp_generator.rb +17 -0
  34. data/lib/generators/devise_otp/install_generator.rb +53 -0
  35. data/lib/generators/devise_otp/views_generator.rb +19 -0
  36. data/test/dummy/README.rdoc +261 -0
  37. data/test/dummy/Rakefile +7 -0
  38. data/test/dummy/app/assets/javascripts/application.js +13 -0
  39. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  40. data/test/dummy/app/controllers/application_controller.rb +4 -0
  41. data/test/dummy/app/controllers/posts_controller.rb +83 -0
  42. data/test/dummy/app/helpers/application_helper.rb +2 -0
  43. data/test/dummy/app/helpers/posts_helper.rb +2 -0
  44. data/test/dummy/app/mailers/.gitkeep +0 -0
  45. data/test/dummy/app/models/post.rb +2 -0
  46. data/test/dummy/app/models/user.rb +20 -0
  47. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  48. data/test/dummy/app/views/posts/_form.html.erb +25 -0
  49. data/test/dummy/app/views/posts/edit.html.erb +6 -0
  50. data/test/dummy/app/views/posts/index.html.erb +25 -0
  51. data/test/dummy/app/views/posts/new.html.erb +5 -0
  52. data/test/dummy/app/views/posts/show.html.erb +15 -0
  53. data/test/dummy/config.ru +4 -0
  54. data/test/dummy/config/application.rb +67 -0
  55. data/test/dummy/config/boot.rb +10 -0
  56. data/test/dummy/config/database.yml +25 -0
  57. data/test/dummy/config/environment.rb +5 -0
  58. data/test/dummy/config/environments/development.rb +30 -0
  59. data/test/dummy/config/environments/production.rb +69 -0
  60. data/test/dummy/config/environments/test.rb +36 -0
  61. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  62. data/test/dummy/config/initializers/devise.rb +253 -0
  63. data/test/dummy/config/initializers/inflections.rb +15 -0
  64. data/test/dummy/config/initializers/mime_types.rb +5 -0
  65. data/test/dummy/config/initializers/secret_token.rb +8 -0
  66. data/test/dummy/config/initializers/session_store.rb +8 -0
  67. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  68. data/test/dummy/config/locales/en.yml +5 -0
  69. data/test/dummy/config/routes.rb +6 -0
  70. data/test/dummy/db/migrate/20130125101430_create_users.rb +9 -0
  71. data/test/dummy/db/migrate/20130131092406_add_devise_to_users.rb +53 -0
  72. data/test/dummy/db/migrate/20130131142320_create_posts.rb +10 -0
  73. data/test/dummy/db/migrate/20130131160351_devise_otp_add_to_users.rb +28 -0
  74. data/test/dummy/lib/assets/.gitkeep +0 -0
  75. data/test/dummy/public/404.html +26 -0
  76. data/test/dummy/public/422.html +26 -0
  77. data/test/dummy/public/500.html +25 -0
  78. data/test/dummy/public/favicon.ico +0 -0
  79. data/test/dummy/script/rails +6 -0
  80. data/test/integration/persistence_test.rb +65 -0
  81. data/test/integration/refresh_test.rb +106 -0
  82. data/test/integration/sign_in_test.rb +87 -0
  83. data/test/integration/token_test.rb +34 -0
  84. data/test/integration_tests_helper.rb +66 -0
  85. data/test/model_tests_helper.rb +22 -0
  86. data/test/models/otp_authenticatable_test.rb +122 -0
  87. data/test/orm/active_record.rb +4 -0
  88. data/test/test_helper.rb +22 -0
  89. metadata +253 -0
@@ -0,0 +1,22 @@
1
+ class ActiveSupport::TestCase
2
+
3
+ #
4
+ # Helpers for creating new users
5
+ #
6
+ def unique_identity
7
+ @@unique_identity_count ||= 0
8
+ @@unique_identity_count += 1
9
+ "user-#{@@unique_identity_count}@mail.invalid"
10
+ end
11
+
12
+ def valid_attributes(attributes={})
13
+ { :email => unique_identity,
14
+ :password => '12345678',
15
+ :password_confirmation => '12345678' }.update(attributes)
16
+ end
17
+
18
+ def new_user(attributes={})
19
+ User.new(valid_attributes(attributes)).save
20
+ end
21
+
22
+ end
@@ -0,0 +1,122 @@
1
+ require 'test_helper'
2
+ require 'model_tests_helper'
3
+
4
+ class OtpAuthenticatableTest < ActiveSupport::TestCase
5
+
6
+ def setup
7
+ new_user
8
+ end
9
+
10
+ test 'new users have a non-nil secret set' do
11
+ assert_not_nil User.first.otp_auth_secret
12
+ end
13
+
14
+ test 'new users have OTP disabled by default' do
15
+ assert !User.first.otp_enabled
16
+ end
17
+
18
+ test 'users should have an instance of TOTP/ROTP objects' do
19
+ u = User.first
20
+ assert u.time_based_otp.is_a? ROTP::TOTP
21
+ assert u.recovery_otp.is_a? ROTP::HOTP
22
+ end
23
+
24
+ test 'users should have their otp_auth_secret/persistence_seed set on creation' do
25
+ assert User.first.otp_auth_secret
26
+ assert User.first.otp_persistence_seed
27
+ end
28
+
29
+ test 'reset_otp_credentials should generate new secrets and disable OTP' do
30
+ u = User.first
31
+ u.update_attribute(:otp_enabled, true)
32
+ assert u.otp_enabled
33
+ otp_auth_secret = u.otp_auth_secret
34
+ otp_persistence_seed = u.otp_persistence_seed
35
+
36
+ u.reset_otp_credentials!
37
+ assert !(otp_auth_secret == u.otp_auth_secret)
38
+ assert !(otp_persistence_seed == u.otp_persistence_seed)
39
+ assert !u.otp_enabled
40
+ end
41
+
42
+ test 'reset_otp_persistence should generate new persistence_seed but NOT change the otp_auth_secret' do
43
+ u = User.first
44
+ u.update_attribute(:otp_enabled, true)
45
+ assert u.otp_enabled
46
+ otp_auth_secret = u.otp_auth_secret
47
+ otp_persistence_seed = u.otp_persistence_seed
48
+
49
+ u.reset_otp_persistence!
50
+ assert (otp_auth_secret == u.otp_auth_secret)
51
+ assert !(otp_persistence_seed == u.otp_persistence_seed)
52
+ assert u.otp_enabled
53
+ end
54
+
55
+ test 'generating a challenge, should retrieve the user later' do
56
+ u = User.first
57
+ u.update_attribute(:otp_enabled, true)
58
+ challenge = u.generate_otp_challenge!
59
+
60
+ w = User.find_valid_otp_challenge(challenge)
61
+ assert w.is_a? User
62
+ assert_equal w,u
63
+ end
64
+
65
+ test 'expiring the challenge, should retrieve nothing' do
66
+ u = User.first
67
+ u.update_attribute(:otp_enabled, true)
68
+ challenge = u.generate_otp_challenge!(1.second)
69
+ sleep(2)
70
+
71
+ w = User.find_valid_otp_challenge(challenge)
72
+ assert_nil w
73
+ end
74
+
75
+ test 'expired challenges should not be valid' do
76
+ u = User.first
77
+ u.update_attribute(:otp_enabled, true)
78
+ challenge = u.generate_otp_challenge!(1.second)
79
+ sleep(2)
80
+ assert_equal false, u.otp_challenge_valid?
81
+ end
82
+
83
+ test 'null otp challenge' do
84
+ u = User.first
85
+ u.update_attribute(:otp_enabled, true)
86
+ assert_equal false, u.validate_otp_token('')
87
+ assert_equal false, u.validate_otp_token(nil)
88
+ end
89
+
90
+ test 'generated otp token should be valid for the user' do
91
+ u = User.first
92
+ u.update_attribute(:otp_enabled, true)
93
+
94
+ secret = u.otp_auth_secret
95
+ token = ROTP::TOTP.new(secret).now
96
+
97
+ assert_equal true, u.validate_otp_token(token)
98
+ end
99
+
100
+ test 'generated otp token, out of drift window, should be NOT valid for the user' do
101
+ u = User.first
102
+ u.update_attribute(:otp_enabled, true)
103
+
104
+ secret = u.otp_auth_secret
105
+
106
+ [3.minutes.from_now, 3.minutes.ago].each do |time|
107
+ token = ROTP::TOTP.new(secret).at(time)
108
+ assert_equal false, u.valid_otp_token?(token)
109
+ end
110
+ end
111
+
112
+ test 'recovery secrets should be valid, and valid only once' do
113
+ u = User.first
114
+ u.update_attribute(:otp_enabled, true)
115
+ recovery = u.next_otp_recovery_tokens
116
+
117
+ assert u.valid_otp_recovery_token? recovery.fetch(0)
118
+ assert_equal false, u.valid_otp_recovery_token?(recovery.fetch(0))
119
+ assert u.valid_otp_recovery_token? recovery.fetch(2)
120
+ end
121
+
122
+ end
@@ -0,0 +1,4 @@
1
+ ActiveRecord::Migration.verbose = false
2
+ ActiveRecord::Base.logger = Logger.new(nil)
3
+
4
+ ActiveRecord::Migrator.migrate(File.expand_path("../../dummy/db/migrate/", __FILE__))
@@ -0,0 +1,22 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+ DEVISE_ORM = (ENV["DEVISE_ORM"] || :active_record).to_sym
3
+
4
+ $:.unshift File.dirname(__FILE__)
5
+ puts "\n==> Devise.orm = #{DEVISE_ORM.inspect}"
6
+ require "dummy/config/environment"
7
+ require "orm/#{DEVISE_ORM}"
8
+ require 'rails/test_help'
9
+ require 'capybara/rails'
10
+ require 'minitest/reporters'
11
+
12
+ MiniTest::Reporters.use!
13
+
14
+ #I18n.load_path << File.expand_path("../support/locale/en.yml", __FILE__) if DEVISE_ORM == :mongoid
15
+
16
+ #ActiveSupport::Deprecation.silenced = true
17
+
18
+ #Capybara.default_driver = :selenium
19
+
20
+ class ActionDispatch::IntegrationTest
21
+ include Capybara::DSL
22
+ end
metadata ADDED
@@ -0,0 +1,253 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: devise-otp-rails5
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.4
5
+ platform: ruby
6
+ authors:
7
+ - Lele Forzani
8
+ - Josef Strzibny
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2016-09-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: 3.2.6
21
+ - - "<"
22
+ - !ruby/object:Gem::Version
23
+ version: '5.1'
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ version: 3.2.6
31
+ - - "<"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.1'
34
+ - !ruby/object:Gem::Dependency
35
+ name: devise
36
+ requirement: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 3.1.0
41
+ - - "<"
42
+ - !ruby/object:Gem::Version
43
+ version: 4.3.0
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 3.1.0
51
+ - - "<"
52
+ - !ruby/object:Gem::Version
53
+ version: 4.3.0
54
+ - !ruby/object:Gem::Dependency
55
+ name: rotp
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 2.0.0
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: 2.0.0
68
+ - !ruby/object:Gem::Dependency
69
+ name: sqlite3
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ description: Time Based OTP/rfc6238 compatible authentication for Devise with Devise
83
+ 4.2 and Rails 5 compatibility. Drop-in replacement for devise-otp.
84
+ email:
85
+ - strzibny@strzibny.name
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".travis.yml"
92
+ - Gemfile
93
+ - LICENSE.txt
94
+ - README.md
95
+ - Rakefile
96
+ - app/assets/javascripts/devise-otp.js
97
+ - app/assets/javascripts/qrcode.js
98
+ - app/controllers/devise_otp/credentials_controller.rb
99
+ - app/controllers/devise_otp/tokens_controller.rb
100
+ - app/views/devise_otp/credentials/refresh.html.erb
101
+ - app/views/devise_otp/credentials/show.html.erb
102
+ - app/views/devise_otp/tokens/_token_secret.html.erb
103
+ - app/views/devise_otp/tokens/_trusted_devices.html.erb
104
+ - app/views/devise_otp/tokens/recovery.html.erb
105
+ - app/views/devise_otp/tokens/recovery_codes.text.erb
106
+ - app/views/devise_otp/tokens/show.html.erb
107
+ - config/locales/en.yml
108
+ - devise-otp.gemspec
109
+ - lib/devise-otp.rb
110
+ - lib/devise-otp/version.rb
111
+ - lib/devise_otp_authenticatable/controllers/helpers.rb
112
+ - lib/devise_otp_authenticatable/controllers/url_helpers.rb
113
+ - lib/devise_otp_authenticatable/engine.rb
114
+ - lib/devise_otp_authenticatable/hooks.rb
115
+ - lib/devise_otp_authenticatable/hooks/sessions.rb
116
+ - lib/devise_otp_authenticatable/mapping.rb
117
+ - lib/devise_otp_authenticatable/models/otp_authenticatable.rb
118
+ - lib/devise_otp_authenticatable/routes.rb
119
+ - lib/generators/active_record/devise_otp_generator.rb
120
+ - lib/generators/active_record/templates/migration.rb
121
+ - lib/generators/devise_otp/devise_otp_generator.rb
122
+ - lib/generators/devise_otp/install_generator.rb
123
+ - lib/generators/devise_otp/views_generator.rb
124
+ - test/dummy/README.rdoc
125
+ - test/dummy/Rakefile
126
+ - test/dummy/app/assets/javascripts/application.js
127
+ - test/dummy/app/assets/stylesheets/application.css
128
+ - test/dummy/app/controllers/application_controller.rb
129
+ - test/dummy/app/controllers/posts_controller.rb
130
+ - test/dummy/app/helpers/application_helper.rb
131
+ - test/dummy/app/helpers/posts_helper.rb
132
+ - test/dummy/app/mailers/.gitkeep
133
+ - test/dummy/app/models/post.rb
134
+ - test/dummy/app/models/user.rb
135
+ - test/dummy/app/views/layouts/application.html.erb
136
+ - test/dummy/app/views/posts/_form.html.erb
137
+ - test/dummy/app/views/posts/edit.html.erb
138
+ - test/dummy/app/views/posts/index.html.erb
139
+ - test/dummy/app/views/posts/new.html.erb
140
+ - test/dummy/app/views/posts/show.html.erb
141
+ - test/dummy/config.ru
142
+ - test/dummy/config/application.rb
143
+ - test/dummy/config/boot.rb
144
+ - test/dummy/config/database.yml
145
+ - test/dummy/config/environment.rb
146
+ - test/dummy/config/environments/development.rb
147
+ - test/dummy/config/environments/production.rb
148
+ - test/dummy/config/environments/test.rb
149
+ - test/dummy/config/initializers/backtrace_silencers.rb
150
+ - test/dummy/config/initializers/devise.rb
151
+ - test/dummy/config/initializers/inflections.rb
152
+ - test/dummy/config/initializers/mime_types.rb
153
+ - test/dummy/config/initializers/secret_token.rb
154
+ - test/dummy/config/initializers/session_store.rb
155
+ - test/dummy/config/initializers/wrap_parameters.rb
156
+ - test/dummy/config/locales/en.yml
157
+ - test/dummy/config/routes.rb
158
+ - test/dummy/db/migrate/20130125101430_create_users.rb
159
+ - test/dummy/db/migrate/20130131092406_add_devise_to_users.rb
160
+ - test/dummy/db/migrate/20130131142320_create_posts.rb
161
+ - test/dummy/db/migrate/20130131160351_devise_otp_add_to_users.rb
162
+ - test/dummy/lib/assets/.gitkeep
163
+ - test/dummy/public/404.html
164
+ - test/dummy/public/422.html
165
+ - test/dummy/public/500.html
166
+ - test/dummy/public/favicon.ico
167
+ - test/dummy/script/rails
168
+ - test/integration/persistence_test.rb
169
+ - test/integration/refresh_test.rb
170
+ - test/integration/sign_in_test.rb
171
+ - test/integration/token_test.rb
172
+ - test/integration_tests_helper.rb
173
+ - test/model_tests_helper.rb
174
+ - test/models/otp_authenticatable_test.rb
175
+ - test/orm/active_record.rb
176
+ - test/test_helper.rb
177
+ homepage: ''
178
+ licenses: []
179
+ metadata: {}
180
+ post_install_message:
181
+ rdoc_options: []
182
+ require_paths:
183
+ - lib
184
+ required_ruby_version: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - ">="
187
+ - !ruby/object:Gem::Version
188
+ version: '0'
189
+ required_rubygems_version: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - ">="
192
+ - !ruby/object:Gem::Version
193
+ version: '0'
194
+ requirements: []
195
+ rubyforge_project:
196
+ rubygems_version: 2.5.1
197
+ signing_key:
198
+ specification_version: 4
199
+ summary: Time Based OTP/rfc6238 compatible authentication for Devise
200
+ test_files:
201
+ - test/dummy/README.rdoc
202
+ - test/dummy/Rakefile
203
+ - test/dummy/app/assets/javascripts/application.js
204
+ - test/dummy/app/assets/stylesheets/application.css
205
+ - test/dummy/app/controllers/application_controller.rb
206
+ - test/dummy/app/controllers/posts_controller.rb
207
+ - test/dummy/app/helpers/application_helper.rb
208
+ - test/dummy/app/helpers/posts_helper.rb
209
+ - test/dummy/app/mailers/.gitkeep
210
+ - test/dummy/app/models/post.rb
211
+ - test/dummy/app/models/user.rb
212
+ - test/dummy/app/views/layouts/application.html.erb
213
+ - test/dummy/app/views/posts/_form.html.erb
214
+ - test/dummy/app/views/posts/edit.html.erb
215
+ - test/dummy/app/views/posts/index.html.erb
216
+ - test/dummy/app/views/posts/new.html.erb
217
+ - test/dummy/app/views/posts/show.html.erb
218
+ - test/dummy/config.ru
219
+ - test/dummy/config/application.rb
220
+ - test/dummy/config/boot.rb
221
+ - test/dummy/config/database.yml
222
+ - test/dummy/config/environment.rb
223
+ - test/dummy/config/environments/development.rb
224
+ - test/dummy/config/environments/production.rb
225
+ - test/dummy/config/environments/test.rb
226
+ - test/dummy/config/initializers/backtrace_silencers.rb
227
+ - test/dummy/config/initializers/devise.rb
228
+ - test/dummy/config/initializers/inflections.rb
229
+ - test/dummy/config/initializers/mime_types.rb
230
+ - test/dummy/config/initializers/secret_token.rb
231
+ - test/dummy/config/initializers/session_store.rb
232
+ - test/dummy/config/initializers/wrap_parameters.rb
233
+ - test/dummy/config/locales/en.yml
234
+ - test/dummy/config/routes.rb
235
+ - test/dummy/db/migrate/20130125101430_create_users.rb
236
+ - test/dummy/db/migrate/20130131092406_add_devise_to_users.rb
237
+ - test/dummy/db/migrate/20130131142320_create_posts.rb
238
+ - test/dummy/db/migrate/20130131160351_devise_otp_add_to_users.rb
239
+ - test/dummy/lib/assets/.gitkeep
240
+ - test/dummy/public/404.html
241
+ - test/dummy/public/422.html
242
+ - test/dummy/public/500.html
243
+ - test/dummy/public/favicon.ico
244
+ - test/dummy/script/rails
245
+ - test/integration/persistence_test.rb
246
+ - test/integration/refresh_test.rb
247
+ - test/integration/sign_in_test.rb
248
+ - test/integration/token_test.rb
249
+ - test/integration_tests_helper.rb
250
+ - test/model_tests_helper.rb
251
+ - test/models/otp_authenticatable_test.rb
252
+ - test/orm/active_record.rb
253
+ - test/test_helper.rb