devise-otp2 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-otp2.gemspec +25 -0
  21. data/lib/devise-otp2.rb +83 -0
  22. data/lib/devise-otp2/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 +68 -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 +37 -0
  59. data/test/dummy/config/environments/production.rb +73 -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 +251 -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,251 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: devise-otp2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.4
5
+ platform: ruby
6
+ authors:
7
+ - Lele Forzani
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-11-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 3.2.6
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '5'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 3.2.6
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '5'
33
+ - !ruby/object:Gem::Dependency
34
+ name: devise
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 3.1.0
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: 4.0.0
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 3.1.0
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: 4.0.0
53
+ - !ruby/object:Gem::Dependency
54
+ name: rotp
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: 2.0.0
60
+ type: :runtime
61
+ prerelease: false
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: 2.0.0
67
+ - !ruby/object:Gem::Dependency
68
+ name: sqlite3
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ type: :development
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ description: Time Based OTP/rfc6238 compatible authentication for Devise
82
+ email:
83
+ - lele@windmill.it
84
+ executables: []
85
+ extensions: []
86
+ extra_rdoc_files: []
87
+ files:
88
+ - ".gitignore"
89
+ - ".travis.yml"
90
+ - Gemfile
91
+ - LICENSE.txt
92
+ - README.md
93
+ - Rakefile
94
+ - app/assets/javascripts/devise-otp.js
95
+ - app/assets/javascripts/qrcode.js
96
+ - app/controllers/devise_otp/credentials_controller.rb
97
+ - app/controllers/devise_otp/tokens_controller.rb
98
+ - app/views/devise_otp/credentials/refresh.html.erb
99
+ - app/views/devise_otp/credentials/show.html.erb
100
+ - app/views/devise_otp/tokens/_token_secret.html.erb
101
+ - app/views/devise_otp/tokens/_trusted_devices.html.erb
102
+ - app/views/devise_otp/tokens/recovery.html.erb
103
+ - app/views/devise_otp/tokens/recovery_codes.text.erb
104
+ - app/views/devise_otp/tokens/show.html.erb
105
+ - config/locales/en.yml
106
+ - devise-otp2.gemspec
107
+ - lib/devise-otp2.rb
108
+ - lib/devise-otp2/version.rb
109
+ - lib/devise_otp_authenticatable/controllers/helpers.rb
110
+ - lib/devise_otp_authenticatable/controllers/url_helpers.rb
111
+ - lib/devise_otp_authenticatable/engine.rb
112
+ - lib/devise_otp_authenticatable/hooks.rb
113
+ - lib/devise_otp_authenticatable/hooks/sessions.rb
114
+ - lib/devise_otp_authenticatable/mapping.rb
115
+ - lib/devise_otp_authenticatable/models/otp_authenticatable.rb
116
+ - lib/devise_otp_authenticatable/routes.rb
117
+ - lib/generators/active_record/devise_otp_generator.rb
118
+ - lib/generators/active_record/templates/migration.rb
119
+ - lib/generators/devise_otp/devise_otp_generator.rb
120
+ - lib/generators/devise_otp/install_generator.rb
121
+ - lib/generators/devise_otp/views_generator.rb
122
+ - test/dummy/README.rdoc
123
+ - test/dummy/Rakefile
124
+ - test/dummy/app/assets/javascripts/application.js
125
+ - test/dummy/app/assets/stylesheets/application.css
126
+ - test/dummy/app/controllers/application_controller.rb
127
+ - test/dummy/app/controllers/posts_controller.rb
128
+ - test/dummy/app/helpers/application_helper.rb
129
+ - test/dummy/app/helpers/posts_helper.rb
130
+ - test/dummy/app/mailers/.gitkeep
131
+ - test/dummy/app/models/post.rb
132
+ - test/dummy/app/models/user.rb
133
+ - test/dummy/app/views/layouts/application.html.erb
134
+ - test/dummy/app/views/posts/_form.html.erb
135
+ - test/dummy/app/views/posts/edit.html.erb
136
+ - test/dummy/app/views/posts/index.html.erb
137
+ - test/dummy/app/views/posts/new.html.erb
138
+ - test/dummy/app/views/posts/show.html.erb
139
+ - test/dummy/config.ru
140
+ - test/dummy/config/application.rb
141
+ - test/dummy/config/boot.rb
142
+ - test/dummy/config/database.yml
143
+ - test/dummy/config/environment.rb
144
+ - test/dummy/config/environments/development.rb
145
+ - test/dummy/config/environments/production.rb
146
+ - test/dummy/config/environments/test.rb
147
+ - test/dummy/config/initializers/backtrace_silencers.rb
148
+ - test/dummy/config/initializers/devise.rb
149
+ - test/dummy/config/initializers/inflections.rb
150
+ - test/dummy/config/initializers/mime_types.rb
151
+ - test/dummy/config/initializers/secret_token.rb
152
+ - test/dummy/config/initializers/session_store.rb
153
+ - test/dummy/config/initializers/wrap_parameters.rb
154
+ - test/dummy/config/locales/en.yml
155
+ - test/dummy/config/routes.rb
156
+ - test/dummy/db/migrate/20130125101430_create_users.rb
157
+ - test/dummy/db/migrate/20130131092406_add_devise_to_users.rb
158
+ - test/dummy/db/migrate/20130131142320_create_posts.rb
159
+ - test/dummy/db/migrate/20130131160351_devise_otp_add_to_users.rb
160
+ - test/dummy/lib/assets/.gitkeep
161
+ - test/dummy/public/404.html
162
+ - test/dummy/public/422.html
163
+ - test/dummy/public/500.html
164
+ - test/dummy/public/favicon.ico
165
+ - test/dummy/script/rails
166
+ - test/integration/persistence_test.rb
167
+ - test/integration/refresh_test.rb
168
+ - test/integration/sign_in_test.rb
169
+ - test/integration/token_test.rb
170
+ - test/integration_tests_helper.rb
171
+ - test/model_tests_helper.rb
172
+ - test/models/otp_authenticatable_test.rb
173
+ - test/orm/active_record.rb
174
+ - test/test_helper.rb
175
+ homepage: http://git.windmill.it/wm/devise-otp
176
+ licenses: []
177
+ metadata: {}
178
+ post_install_message:
179
+ rdoc_options: []
180
+ require_paths:
181
+ - lib
182
+ required_ruby_version: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: '0'
187
+ required_rubygems_version: !ruby/object:Gem::Requirement
188
+ requirements:
189
+ - - ">="
190
+ - !ruby/object:Gem::Version
191
+ version: '0'
192
+ requirements: []
193
+ rubyforge_project:
194
+ rubygems_version: 2.4.5.1
195
+ signing_key:
196
+ specification_version: 4
197
+ summary: Time Based OTP/rfc6238 compatible authentication for Devise
198
+ test_files:
199
+ - test/dummy/README.rdoc
200
+ - test/dummy/Rakefile
201
+ - test/dummy/app/assets/javascripts/application.js
202
+ - test/dummy/app/assets/stylesheets/application.css
203
+ - test/dummy/app/controllers/application_controller.rb
204
+ - test/dummy/app/controllers/posts_controller.rb
205
+ - test/dummy/app/helpers/application_helper.rb
206
+ - test/dummy/app/helpers/posts_helper.rb
207
+ - test/dummy/app/mailers/.gitkeep
208
+ - test/dummy/app/models/post.rb
209
+ - test/dummy/app/models/user.rb
210
+ - test/dummy/app/views/layouts/application.html.erb
211
+ - test/dummy/app/views/posts/_form.html.erb
212
+ - test/dummy/app/views/posts/edit.html.erb
213
+ - test/dummy/app/views/posts/index.html.erb
214
+ - test/dummy/app/views/posts/new.html.erb
215
+ - test/dummy/app/views/posts/show.html.erb
216
+ - test/dummy/config.ru
217
+ - test/dummy/config/application.rb
218
+ - test/dummy/config/boot.rb
219
+ - test/dummy/config/database.yml
220
+ - test/dummy/config/environment.rb
221
+ - test/dummy/config/environments/development.rb
222
+ - test/dummy/config/environments/production.rb
223
+ - test/dummy/config/environments/test.rb
224
+ - test/dummy/config/initializers/backtrace_silencers.rb
225
+ - test/dummy/config/initializers/devise.rb
226
+ - test/dummy/config/initializers/inflections.rb
227
+ - test/dummy/config/initializers/mime_types.rb
228
+ - test/dummy/config/initializers/secret_token.rb
229
+ - test/dummy/config/initializers/session_store.rb
230
+ - test/dummy/config/initializers/wrap_parameters.rb
231
+ - test/dummy/config/locales/en.yml
232
+ - test/dummy/config/routes.rb
233
+ - test/dummy/db/migrate/20130125101430_create_users.rb
234
+ - test/dummy/db/migrate/20130131092406_add_devise_to_users.rb
235
+ - test/dummy/db/migrate/20130131142320_create_posts.rb
236
+ - test/dummy/db/migrate/20130131160351_devise_otp_add_to_users.rb
237
+ - test/dummy/lib/assets/.gitkeep
238
+ - test/dummy/public/404.html
239
+ - test/dummy/public/422.html
240
+ - test/dummy/public/500.html
241
+ - test/dummy/public/favicon.ico
242
+ - test/dummy/script/rails
243
+ - test/integration/persistence_test.rb
244
+ - test/integration/refresh_test.rb
245
+ - test/integration/sign_in_test.rb
246
+ - test/integration/token_test.rb
247
+ - test/integration_tests_helper.rb
248
+ - test/model_tests_helper.rb
249
+ - test/models/otp_authenticatable_test.rb
250
+ - test/orm/active_record.rb
251
+ - test/test_helper.rb