devise-otp 0.6.0 → 0.8.0

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +7 -10
  3. data/.gitignore +3 -1
  4. data/CHANGELOG.md +54 -8
  5. data/Gemfile +10 -0
  6. data/README.md +8 -2
  7. data/app/controllers/devise_otp/devise/otp_credentials_controller.rb +46 -27
  8. data/app/controllers/devise_otp/devise/otp_tokens_controller.rb +28 -10
  9. data/app/views/devise/otp_credentials/show.html.erb +6 -6
  10. data/app/views/devise/otp_tokens/_token_secret.html.erb +3 -4
  11. data/app/views/devise/otp_tokens/edit.html.erb +26 -0
  12. data/app/views/devise/otp_tokens/show.html.erb +7 -14
  13. data/config/locales/en.yml +23 -14
  14. data/devise-otp.gemspec +3 -13
  15. data/docs/QR_CODES.md +1 -40
  16. data/lib/devise/strategies/database_authenticatable.rb +64 -0
  17. data/lib/devise-otp/version.rb +1 -1
  18. data/lib/devise-otp.rb +31 -11
  19. data/lib/devise_otp_authenticatable/controllers/helpers.rb +9 -10
  20. data/lib/devise_otp_authenticatable/controllers/public_helpers.rb +39 -0
  21. data/lib/devise_otp_authenticatable/controllers/url_helpers.rb +10 -0
  22. data/lib/devise_otp_authenticatable/engine.rb +2 -5
  23. data/lib/devise_otp_authenticatable/hooks/refreshable.rb +5 -0
  24. data/lib/devise_otp_authenticatable/models/otp_authenticatable.rb +22 -20
  25. data/lib/devise_otp_authenticatable/routes.rb +3 -1
  26. data/lib/generators/active_record/templates/migration.rb +1 -1
  27. data/test/dummy/app/controllers/admin_posts_controller.rb +85 -0
  28. data/test/dummy/app/controllers/application_controller.rb +0 -1
  29. data/test/dummy/app/controllers/base_controller.rb +6 -0
  30. data/test/dummy/app/models/admin.rb +25 -0
  31. data/test/dummy/app/views/admin_posts/_form.html.erb +25 -0
  32. data/test/dummy/app/views/admin_posts/edit.html.erb +6 -0
  33. data/test/dummy/app/views/admin_posts/index.html.erb +25 -0
  34. data/test/dummy/app/views/admin_posts/new.html.erb +5 -0
  35. data/test/dummy/app/views/admin_posts/show.html.erb +15 -0
  36. data/test/dummy/app/views/base/home.html.erb +1 -0
  37. data/test/dummy/config/application.rb +0 -2
  38. data/test/dummy/config/routes.rb +4 -1
  39. data/test/dummy/db/migrate/20240604000001_create_admins.rb +9 -0
  40. data/test/dummy/db/migrate/20240604000002_add_devise_to_admins.rb +52 -0
  41. data/test/dummy/db/migrate/20240604000003_devise_otp_add_to_admins.rb +28 -0
  42. data/test/integration/disable_token_test.rb +53 -0
  43. data/test/integration/enable_otp_form_test.rb +57 -0
  44. data/test/integration/persistence_test.rb +3 -6
  45. data/test/integration/refresh_test.rb +32 -0
  46. data/test/integration/reset_token_test.rb +45 -0
  47. data/test/integration/sign_in_test.rb +10 -14
  48. data/test/integration/trackable_test.rb +50 -0
  49. data/test/integration_tests_helper.rb +24 -6
  50. data/test/models/otp_authenticatable_test.rb +62 -27
  51. data/test/orm/active_record.rb +6 -1
  52. data/test/test_helper.rb +1 -71
  53. metadata +26 -135
  54. data/lib/devise_otp_authenticatable/hooks/sessions.rb +0 -58
  55. data/lib/devise_otp_authenticatable/hooks.rb +0 -11
  56. data/test/integration/token_test.rb +0 -30
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devise-otp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lele Forzani
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-07-06 00:00:00.000000000 Z
12
+ date: 2024-09-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -17,20 +17,20 @@ dependencies:
17
17
  requirements:
18
18
  - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: '6.1'
20
+ version: '7.0'
21
21
  - - "<"
22
22
  - !ruby/object:Gem::Version
23
- version: '7.2'
23
+ version: '8.0'
24
24
  type: :runtime
25
25
  prerelease: false
26
26
  version_requirements: !ruby/object:Gem::Requirement
27
27
  requirements:
28
28
  - - ">="
29
29
  - !ruby/object:Gem::Version
30
- version: '6.1'
30
+ version: '7.0'
31
31
  - - "<"
32
32
  - !ruby/object:Gem::Version
33
- version: '7.2'
33
+ version: '8.0'
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: devise
36
36
  requirement: !ruby/object:Gem::Requirement
@@ -65,132 +65,6 @@ dependencies:
65
65
  - - ">="
66
66
  - !ruby/object:Gem::Version
67
67
  version: 2.0.0
68
- - !ruby/object:Gem::Dependency
69
- name: capybara
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
- - !ruby/object:Gem::Dependency
83
- name: cuprite
84
- requirement: !ruby/object:Gem::Requirement
85
- requirements:
86
- - - ">="
87
- - !ruby/object:Gem::Version
88
- version: '0'
89
- type: :development
90
- prerelease: false
91
- version_requirements: !ruby/object:Gem::Requirement
92
- requirements:
93
- - - ">="
94
- - !ruby/object:Gem::Version
95
- version: '0'
96
- - !ruby/object:Gem::Dependency
97
- name: minitest-reporters
98
- requirement: !ruby/object:Gem::Requirement
99
- requirements:
100
- - - ">="
101
- - !ruby/object:Gem::Version
102
- version: 0.5.0
103
- type: :development
104
- prerelease: false
105
- version_requirements: !ruby/object:Gem::Requirement
106
- requirements:
107
- - - ">="
108
- - !ruby/object:Gem::Version
109
- version: 0.5.0
110
- - !ruby/object:Gem::Dependency
111
- name: puma
112
- requirement: !ruby/object:Gem::Requirement
113
- requirements:
114
- - - ">="
115
- - !ruby/object:Gem::Version
116
- version: '0'
117
- type: :development
118
- prerelease: false
119
- version_requirements: !ruby/object:Gem::Requirement
120
- requirements:
121
- - - ">="
122
- - !ruby/object:Gem::Version
123
- version: '0'
124
- - !ruby/object:Gem::Dependency
125
- name: rdoc
126
- requirement: !ruby/object:Gem::Requirement
127
- requirements:
128
- - - ">="
129
- - !ruby/object:Gem::Version
130
- version: '0'
131
- type: :development
132
- prerelease: false
133
- version_requirements: !ruby/object:Gem::Requirement
134
- requirements:
135
- - - ">="
136
- - !ruby/object:Gem::Version
137
- version: '0'
138
- - !ruby/object:Gem::Dependency
139
- name: shoulda
140
- requirement: !ruby/object:Gem::Requirement
141
- requirements:
142
- - - ">="
143
- - !ruby/object:Gem::Version
144
- version: '0'
145
- type: :development
146
- prerelease: false
147
- version_requirements: !ruby/object:Gem::Requirement
148
- requirements:
149
- - - ">="
150
- - !ruby/object:Gem::Version
151
- version: '0'
152
- - !ruby/object:Gem::Dependency
153
- name: sprockets-rails
154
- requirement: !ruby/object:Gem::Requirement
155
- requirements:
156
- - - ">="
157
- - !ruby/object:Gem::Version
158
- version: '0'
159
- type: :development
160
- prerelease: false
161
- version_requirements: !ruby/object:Gem::Requirement
162
- requirements:
163
- - - ">="
164
- - !ruby/object:Gem::Version
165
- version: '0'
166
- - !ruby/object:Gem::Dependency
167
- name: sqlite3
168
- requirement: !ruby/object:Gem::Requirement
169
- requirements:
170
- - - ">="
171
- - !ruby/object:Gem::Version
172
- version: '0'
173
- type: :development
174
- prerelease: false
175
- version_requirements: !ruby/object:Gem::Requirement
176
- requirements:
177
- - - ">="
178
- - !ruby/object:Gem::Version
179
- version: '0'
180
- - !ruby/object:Gem::Dependency
181
- name: standardrb
182
- requirement: !ruby/object:Gem::Requirement
183
- requirements:
184
- - - ">="
185
- - !ruby/object:Gem::Version
186
- version: '0'
187
- type: :development
188
- prerelease: false
189
- version_requirements: !ruby/object:Gem::Requirement
190
- requirements:
191
- - - ">="
192
- - !ruby/object:Gem::Version
193
- version: '0'
194
68
  description: Time Based OTP/rfc6238 compatible authentication for Devise
195
69
  email:
196
70
  - lele@windmill.it
@@ -214,6 +88,7 @@ files:
214
88
  - app/views/devise/otp_credentials/show.html.erb
215
89
  - app/views/devise/otp_tokens/_token_secret.html.erb
216
90
  - app/views/devise/otp_tokens/_trusted_devices.html.erb
91
+ - app/views/devise/otp_tokens/edit.html.erb
217
92
  - app/views/devise/otp_tokens/recovery.html.erb
218
93
  - app/views/devise/otp_tokens/recovery_codes.text.erb
219
94
  - app/views/devise/otp_tokens/show.html.erb
@@ -222,11 +97,12 @@ files:
222
97
  - docs/QR_CODES.md
223
98
  - lib/devise-otp.rb
224
99
  - lib/devise-otp/version.rb
100
+ - lib/devise/strategies/database_authenticatable.rb
225
101
  - lib/devise_otp_authenticatable/controllers/helpers.rb
102
+ - lib/devise_otp_authenticatable/controllers/public_helpers.rb
226
103
  - lib/devise_otp_authenticatable/controllers/url_helpers.rb
227
104
  - lib/devise_otp_authenticatable/engine.rb
228
- - lib/devise_otp_authenticatable/hooks.rb
229
- - lib/devise_otp_authenticatable/hooks/sessions.rb
105
+ - lib/devise_otp_authenticatable/hooks/refreshable.rb
230
106
  - lib/devise_otp_authenticatable/models/otp_authenticatable.rb
231
107
  - lib/devise_otp_authenticatable/routes.rb
232
108
  - lib/generators/active_record/devise_otp_generator.rb
@@ -239,13 +115,22 @@ files:
239
115
  - test/dummy/app/assets/config/manifest.js
240
116
  - test/dummy/app/assets/javascripts/application.js
241
117
  - test/dummy/app/assets/stylesheets/application.css
118
+ - test/dummy/app/controllers/admin_posts_controller.rb
242
119
  - test/dummy/app/controllers/application_controller.rb
120
+ - test/dummy/app/controllers/base_controller.rb
243
121
  - test/dummy/app/controllers/posts_controller.rb
244
122
  - test/dummy/app/helpers/application_helper.rb
245
123
  - test/dummy/app/helpers/posts_helper.rb
246
124
  - test/dummy/app/mailers/.gitkeep
125
+ - test/dummy/app/models/admin.rb
247
126
  - test/dummy/app/models/post.rb
248
127
  - test/dummy/app/models/user.rb
128
+ - test/dummy/app/views/admin_posts/_form.html.erb
129
+ - test/dummy/app/views/admin_posts/edit.html.erb
130
+ - test/dummy/app/views/admin_posts/index.html.erb
131
+ - test/dummy/app/views/admin_posts/new.html.erb
132
+ - test/dummy/app/views/admin_posts/show.html.erb
133
+ - test/dummy/app/views/base/home.html.erb
249
134
  - test/dummy/app/views/layouts/application.html.erb
250
135
  - test/dummy/app/views/posts/_form.html.erb
251
136
  - test/dummy/app/views/posts/edit.html.erb
@@ -273,16 +158,22 @@ files:
273
158
  - test/dummy/db/migrate/20130131092406_add_devise_to_users.rb
274
159
  - test/dummy/db/migrate/20130131142320_create_posts.rb
275
160
  - test/dummy/db/migrate/20130131160351_devise_otp_add_to_users.rb
161
+ - test/dummy/db/migrate/20240604000001_create_admins.rb
162
+ - test/dummy/db/migrate/20240604000002_add_devise_to_admins.rb
163
+ - test/dummy/db/migrate/20240604000003_devise_otp_add_to_admins.rb
276
164
  - test/dummy/lib/assets/.gitkeep
277
165
  - test/dummy/public/404.html
278
166
  - test/dummy/public/422.html
279
167
  - test/dummy/public/500.html
280
168
  - test/dummy/public/favicon.ico
281
169
  - test/dummy/script/rails
170
+ - test/integration/disable_token_test.rb
171
+ - test/integration/enable_otp_form_test.rb
282
172
  - test/integration/persistence_test.rb
283
173
  - test/integration/refresh_test.rb
174
+ - test/integration/reset_token_test.rb
284
175
  - test/integration/sign_in_test.rb
285
- - test/integration/token_test.rb
176
+ - test/integration/trackable_test.rb
286
177
  - test/integration_tests_helper.rb
287
178
  - test/model_tests_helper.rb
288
179
  - test/models/otp_authenticatable_test.rb
@@ -1,58 +0,0 @@
1
- module DeviseOtpAuthenticatable::Hooks
2
- module Sessions
3
- extend ActiveSupport::Concern
4
- include DeviseOtpAuthenticatable::Controllers::UrlHelpers
5
-
6
- included do
7
- alias_method :create, :create_with_otp
8
- end
9
-
10
- #
11
- # replaces Devise::SessionsController#create
12
- #
13
- def create_with_otp
14
- resource = warden.authenticate!(auth_options)
15
-
16
- devise_stored_location = stored_location_for(resource) # Grab the current stored location before it gets lost by warden.logout
17
- store_location_for(resource, devise_stored_location) # Restore it since #stored_location_for removes it
18
-
19
- otp_refresh_credentials_for(resource)
20
-
21
- yield resource if block_given?
22
- if otp_challenge_required_on?(resource)
23
- challenge = resource.generate_otp_challenge!
24
- warden.logout
25
- store_location_for(resource, devise_stored_location) # restore the stored location
26
- respond_with resource, location: otp_credential_path_for(resource, {challenge: challenge})
27
- elsif otp_mandatory_on?(resource) # if mandatory, log in user but send him to the must activate otp
28
- set_flash_message(:notice, :signed_in_but_otp) if is_navigational_format?
29
- sign_in(resource_name, resource)
30
- respond_with resource, location: otp_token_path_for(resource)
31
- else
32
- sign_in(resource_name, resource)
33
- respond_with resource, location: after_sign_in_path_for(resource)
34
- end
35
- end
36
-
37
- private
38
-
39
- #
40
- # resource should be challenged for otp
41
- #
42
- def otp_challenge_required_on?(resource)
43
- return false unless resource.respond_to?(:otp_enabled) && resource.respond_to?(:otp_auth_secret)
44
-
45
- resource.otp_enabled && !is_otp_trusted_browser_for?(resource)
46
- end
47
-
48
- #
49
- # the resource -should- have otp turned on, but it isn't
50
- #
51
- def otp_mandatory_on?(resource)
52
- return true if resource.class.otp_mandatory && !resource.otp_enabled
53
- return false unless resource.respond_to?(:otp_mandatory)
54
-
55
- resource.otp_mandatory && !resource.otp_enabled
56
- end
57
- end
58
- end
@@ -1,11 +0,0 @@
1
- module DeviseOtpAuthenticatable
2
- module Hooks
3
- autoload :Sessions, "devise_otp_authenticatable/hooks/sessions.rb"
4
-
5
- class << self
6
- def apply
7
- ::Devise::SessionsController.send(:include, Hooks::Sessions)
8
- end
9
- end
10
- end
11
- end
@@ -1,30 +0,0 @@
1
- require "test_helper"
2
- require "integration_tests_helper"
3
-
4
- class TokenTest < ActionDispatch::IntegrationTest
5
- def teardown
6
- Capybara.reset_sessions!
7
- end
8
-
9
- test "disabling OTP after successfully enabling" do
10
- # log in 1fa
11
- user = enable_otp_and_sign_in
12
- assert_equal user_otp_credential_path, current_path
13
-
14
- # otp 2fa
15
- fill_in "user_token", with: ROTP::TOTP.new(user.otp_auth_secret).at(Time.now)
16
- click_button "Submit Token"
17
- assert_equal root_path, current_path
18
-
19
- # disable OTP
20
- disable_otp
21
-
22
- # logout
23
- sign_out
24
-
25
- # log back in 1fa
26
- sign_user_in(user)
27
-
28
- assert_equal root_path, current_path
29
- end
30
- end