devise-otp 0.4.0 → 0.5.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.
- checksums.yaml +4 -4
- data/Rakefile +17 -18
- data/app/controllers/devise_otp/devise/otp_credentials_controller.rb +15 -19
- data/app/controllers/devise_otp/devise/otp_tokens_controller.rb +7 -11
- data/app/views/devise/otp_credentials/show.html.erb +1 -1
- data/app/views/devise/otp_tokens/_token_secret.html.erb +4 -4
- data/app/views/devise/otp_tokens/recovery.html.erb +4 -4
- data/app/views/devise/otp_tokens/show.html.erb +5 -5
- data/config/locales/en.yml +4 -12
- data/devise-otp.gemspec +13 -13
- data/lib/devise-otp/version.rb +1 -1
- data/lib/devise-otp.rb +15 -29
- data/lib/devise_otp_authenticatable/controllers/helpers.rb +21 -23
- data/lib/devise_otp_authenticatable/controllers/url_helpers.rb +0 -2
- data/lib/devise_otp_authenticatable/engine.rb +6 -4
- data/lib/devise_otp_authenticatable/hooks/sessions.rb +4 -5
- data/lib/devise_otp_authenticatable/hooks.rb +1 -3
- data/lib/devise_otp_authenticatable/models/otp_authenticatable.rb +19 -25
- data/lib/devise_otp_authenticatable/routes.rb +11 -14
- data/lib/generators/active_record/devise_otp_generator.rb +1 -1
- data/lib/generators/devise_otp/devise_otp_generator.rb +12 -13
- data/lib/generators/devise_otp/install_generator.rb +3 -4
- data/lib/generators/devise_otp/views_generator.rb +5 -5
- data/test/dummy/Rakefile +1 -1
- data/test/dummy/app/controllers/posts_controller.rb +2 -2
- data/test/dummy/app/models/user.rb +8 -8
- data/test/dummy/config/application.rb +4 -4
- data/test/dummy/config/boot.rb +5 -5
- data/test/dummy/config/environment.rb +1 -1
- data/test/dummy/config/environments/development.rb +1 -1
- data/test/dummy/config/environments/production.rb +1 -1
- data/test/dummy/config/environments/test.rb +2 -2
- data/test/dummy/config/initializers/devise.rb +6 -8
- data/test/dummy/config/initializers/secret_token.rb +2 -2
- data/test/dummy/config/initializers/session_store.rb +1 -1
- data/test/dummy/config/initializers/wrap_parameters.rb +1 -1
- data/test/dummy/config/routes.rb +1 -1
- data/test/dummy/config.ru +1 -1
- data/test/dummy/db/migrate/20130131092406_add_devise_to_users.rb +12 -13
- data/test/dummy/db/migrate/20130131160351_devise_otp_add_to_users.rb +13 -13
- data/test/dummy/script/rails +3 -3
- data/test/integration/persistence_test.rb +11 -12
- data/test/integration/refresh_test.rb +13 -14
- data/test/integration/sign_in_test.rb +24 -26
- data/test/integration/token_test.rb +5 -6
- data/test/integration_tests_helper.rb +16 -17
- data/test/model_tests_helper.rb +5 -7
- data/test/models/otp_authenticatable_test.rb +18 -19
- data/test/test_helper.rb +10 -10
- metadata +22 -62
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 40f03e3fee5939da23d1f583390f794a2e4e456a08fd311d53a605e94ba77075
|
4
|
+
data.tar.gz: cc3e95dcebf0186cbb7a5f3552184093dc6e2209e421b359c6384f788f8ccaed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a62beac8100a3f98a60b6b19f279d795d1f942dc0b44b5d7ad345527b315363185439630b3df7e34dce8d0c0bb154329b882965f45cabbb50ff1a93c7c7cdb09
|
7
|
+
data.tar.gz: 651d1dc15b3444db54eb8e2d14d6273858d2ec66ac7feee0ce314085175d5d3722f7062e914979b2b05a647ba8470a873179d962aadcb0657bcf8bd9bd814c66
|
data/Rakefile
CHANGED
@@ -1,42 +1,41 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
2
|
begin
|
3
|
-
require
|
3
|
+
require "bundler/setup"
|
4
4
|
rescue LoadError
|
5
|
-
puts
|
5
|
+
puts "You must `gem install bundler` and `bundle install` to run rake tasks"
|
6
6
|
end
|
7
7
|
begin
|
8
|
-
require
|
8
|
+
require "rdoc/task"
|
9
9
|
rescue LoadError
|
10
|
-
require
|
11
|
-
require
|
10
|
+
require "rdoc/rdoc"
|
11
|
+
require "rake/rdoctask"
|
12
12
|
RDoc::Task = Rake::RDocTask
|
13
13
|
end
|
14
14
|
|
15
15
|
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
-
rdoc.rdoc_dir =
|
17
|
-
rdoc.title
|
18
|
-
rdoc.options <<
|
19
|
-
rdoc.rdoc_files.include(
|
20
|
-
rdoc.rdoc_files.include(
|
16
|
+
rdoc.rdoc_dir = "rdoc"
|
17
|
+
rdoc.title = "Foobar"
|
18
|
+
rdoc.options << "--line-numbers"
|
19
|
+
rdoc.rdoc_files.include("README.rdoc")
|
20
|
+
rdoc.rdoc_files.include("lib/**/*.rb")
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
23
|
Bundler::GemHelper.install_tasks
|
25
24
|
|
26
|
-
require
|
25
|
+
require "rake/testtask"
|
27
26
|
Rake::TestTask.new(:test) do |test|
|
28
|
-
test.libs <<
|
29
|
-
test.pattern =
|
27
|
+
test.libs << "lib" << "test"
|
28
|
+
test.pattern = "test/**/*_test.rb"
|
30
29
|
test.verbose = true
|
31
30
|
end
|
32
31
|
|
33
|
-
desc
|
32
|
+
desc "Run Devise tests for all ORMs."
|
34
33
|
task :tests do
|
35
|
-
Dir[File.join(File.dirname(__FILE__),
|
34
|
+
Dir[File.join(File.dirname(__FILE__), "test", "orm", "*.rb")].each do |file|
|
36
35
|
orm = File.basename(file).split(".").first
|
37
36
|
system "rake test DEVISE_ORM=#{orm}"
|
38
37
|
end
|
39
38
|
end
|
40
39
|
|
41
|
-
desc
|
42
|
-
task :
|
40
|
+
desc "Default: run tests for all ORMs."
|
41
|
+
task default: :tests
|
@@ -3,15 +3,15 @@ module DeviseOtp
|
|
3
3
|
class OtpCredentialsController < DeviseController
|
4
4
|
helper_method :new_session_path
|
5
5
|
|
6
|
-
prepend_before_action :authenticate_scope!, :
|
7
|
-
prepend_before_action :require_no_authentication, :
|
6
|
+
prepend_before_action :authenticate_scope!, only: [:get_refresh, :set_refresh]
|
7
|
+
prepend_before_action :require_no_authentication, only: [:show, :update]
|
8
8
|
|
9
9
|
#
|
10
10
|
# show a request for the OTP token
|
11
11
|
#
|
12
12
|
def show
|
13
13
|
@challenge = params[:challenge]
|
14
|
-
@recovery =
|
14
|
+
@recovery = (params[:recovery] == "true") && recovery_enabled?
|
15
15
|
|
16
16
|
if @challenge.nil?
|
17
17
|
redirect_to :root
|
@@ -33,28 +33,25 @@ module DeviseOtp
|
|
33
33
|
#
|
34
34
|
def update
|
35
35
|
resource = resource_class.find_valid_otp_challenge(params[resource_name][:challenge])
|
36
|
-
recovery = (params[resource_name][:recovery] ==
|
36
|
+
recovery = (params[resource_name][:recovery] == "true") && recovery_enabled?
|
37
37
|
token = params[resource_name][:token]
|
38
38
|
|
39
39
|
if token.blank?
|
40
40
|
otp_set_flash_message(:alert, :token_blank)
|
41
|
-
redirect_to otp_credential_path_for(resource_name, :
|
42
|
-
|
41
|
+
redirect_to otp_credential_path_for(resource_name, challenge: params[resource_name][:challenge],
|
42
|
+
recovery: recovery)
|
43
43
|
elsif resource.nil?
|
44
44
|
otp_set_flash_message(:alert, :otp_session_invalid)
|
45
45
|
redirect_to new_session_path(resource_name)
|
46
|
-
|
47
|
-
|
48
|
-
set_flash_message(:success, :signed_in) if is_navigational_format?
|
49
|
-
sign_in(resource_name, resource)
|
46
|
+
elsif resource.otp_challenge_valid? && resource.validate_otp_token(params[resource_name][:token], recovery)
|
47
|
+
sign_in(resource_name, resource)
|
50
48
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
end
|
49
|
+
otp_set_trusted_device_for(resource) if params[:enable_persistence] == "true"
|
50
|
+
otp_refresh_credentials_for(resource)
|
51
|
+
respond_with resource, location: after_sign_in_path_for(resource)
|
52
|
+
else
|
53
|
+
otp_set_flash_message :alert, :token_invalid
|
54
|
+
redirect_to new_session_path(resource_name)
|
58
55
|
end
|
59
56
|
end
|
60
57
|
|
@@ -85,7 +82,7 @@ module DeviseOtp
|
|
85
82
|
otp_refresh_credentials_for(resource)
|
86
83
|
otp_set_flash_message :success, :valid_refresh if is_navigational_format?
|
87
84
|
|
88
|
-
respond_with resource, :
|
85
|
+
respond_with resource, location: otp_fetch_refresh_return_url
|
89
86
|
end
|
90
87
|
|
91
88
|
def failed_refresh
|
@@ -96,7 +93,6 @@ module DeviseOtp
|
|
96
93
|
def self.controller_path
|
97
94
|
"#{::Devise.otp_controller_path}/otp_credentials"
|
98
95
|
end
|
99
|
-
|
100
96
|
end
|
101
97
|
end
|
102
98
|
end
|
@@ -6,7 +6,7 @@ module DeviseOtp
|
|
6
6
|
prepend_before_action :ensure_credentials_refresh
|
7
7
|
prepend_before_action :authenticate_scope!
|
8
8
|
|
9
|
-
protect_from_forgery :
|
9
|
+
protect_from_forgery except: [:clear_persistence, :delete_persistence]
|
10
10
|
|
11
11
|
#
|
12
12
|
# Displays the status of OTP authentication
|
@@ -23,8 +23,8 @@ module DeviseOtp
|
|
23
23
|
# Updates the status of OTP authentication
|
24
24
|
#
|
25
25
|
def update
|
26
|
-
enabled = params[resource_name][:otp_enabled] ==
|
27
|
-
if
|
26
|
+
enabled = params[resource_name][:otp_enabled] == "1"
|
27
|
+
if enabled ? resource.enable_otp! : resource.disable_otp!
|
28
28
|
otp_set_flash_message :success, :successfully_updated
|
29
29
|
end
|
30
30
|
|
@@ -39,7 +39,7 @@ module DeviseOtp
|
|
39
39
|
otp_set_flash_message :success, :successfully_reset_creds
|
40
40
|
end
|
41
41
|
|
42
|
-
redirect_to :
|
42
|
+
redirect_to action: :show
|
43
43
|
end
|
44
44
|
|
45
45
|
#
|
@@ -50,7 +50,7 @@ module DeviseOtp
|
|
50
50
|
otp_set_flash_message :success, :successfully_set_persistence
|
51
51
|
end
|
52
52
|
|
53
|
-
redirect_to :
|
53
|
+
redirect_to action: :show
|
54
54
|
end
|
55
55
|
|
56
56
|
#
|
@@ -61,7 +61,7 @@ module DeviseOtp
|
|
61
61
|
otp_set_flash_message :success, :successfully_cleared_persistence
|
62
62
|
end
|
63
63
|
|
64
|
-
redirect_to :
|
64
|
+
redirect_to action: :show
|
65
65
|
end
|
66
66
|
|
67
67
|
#
|
@@ -72,12 +72,9 @@ module DeviseOtp
|
|
72
72
|
otp_set_flash_message :notice, :successfully_reset_persistence
|
73
73
|
end
|
74
74
|
|
75
|
-
redirect_to :
|
75
|
+
redirect_to action: :show
|
76
76
|
end
|
77
77
|
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
78
|
def recovery
|
82
79
|
respond_to do |format|
|
83
80
|
format.html
|
@@ -106,7 +103,6 @@ module DeviseOtp
|
|
106
103
|
def self.controller_path
|
107
104
|
"#{::Devise.otp_controller_path}/otp_tokens"
|
108
105
|
end
|
109
|
-
|
110
106
|
end
|
111
107
|
end
|
112
108
|
end
|
@@ -20,7 +20,7 @@
|
|
20
20
|
<%= f.text_field :token, :autocomplete => :off, :autofocus => true, :size => 6, :value => '' %><br>
|
21
21
|
|
22
22
|
<%= label_tag :enable_persistence do %>
|
23
|
-
<%= check_box_tag :enable_persistence, true, false %>
|
23
|
+
<%= check_box_tag :enable_persistence, true, false %> <%= I18n.t('remember', :scope => 'devise.otp.general') %>
|
24
24
|
<% end %>
|
25
25
|
|
26
26
|
<p><%= f.submit I18n.t('submit', :scope => 'devise.otp.submit_token') %></p>
|
@@ -16,8 +16,8 @@
|
|
16
16
|
</p>
|
17
17
|
|
18
18
|
<%- if recovery_enabled? %>
|
19
|
-
<h3><%= I18n.t('title', :scope => 'devise.otp.
|
20
|
-
<p><%= I18n.t('explain', :scope => 'devise.otp.
|
21
|
-
<p><%= link_to I18n.t('codes_list', :scope => 'devise.otp.
|
22
|
-
<p><%= link_to I18n.t('download_codes', :scope => 'devise.otp.
|
19
|
+
<h3><%= I18n.t('title', :scope => 'devise.otp.otp_tokens.recovery') %></h3>
|
20
|
+
<p><%= I18n.t('explain', :scope => 'devise.otp.otp_tokens.recovery') %></p>
|
21
|
+
<p><%= link_to I18n.t('codes_list', :scope => 'devise.otp.otp_tokens.recovery'), recovery_otp_token_for(resource_name) %></p>
|
22
|
+
<p><%= link_to I18n.t('download_codes', :scope => 'devise.otp.otp_tokens.recovery'), recovery_otp_token_for(resource_name, format: :text) %></p>
|
23
23
|
<% end %>
|
@@ -1,12 +1,12 @@
|
|
1
|
-
<h2><%= I18n.t('title', :scope => 'devise.otp.
|
2
|
-
<p><%= I18n.t('explain', :scope => 'devise.otp.
|
1
|
+
<h2><%= I18n.t('title', :scope => 'devise.otp.otp_tokens.recovery') %></h2>
|
2
|
+
<p><%= I18n.t('explain', :scope => 'devise.otp.otp_tokens.recovery') %></p>
|
3
3
|
|
4
4
|
<table>
|
5
5
|
<caption>
|
6
6
|
<thead>
|
7
7
|
<tr>
|
8
|
-
<th><%= I18n.t('sequence', :scope => 'devise.otp.
|
9
|
-
<th><%= I18n.t('code', :scope => 'devise.otp.
|
8
|
+
<th><%= I18n.t('sequence', :scope => 'devise.otp.otp_tokens.recovery') %></th>
|
9
|
+
<th><%= I18n.t('code', :scope => 'devise.otp.otp_tokens.recovery') %></th>
|
10
10
|
</tr>
|
11
11
|
</thead>
|
12
12
|
<tbody>
|
@@ -1,18 +1,18 @@
|
|
1
|
-
<h2><%= I18n.t('title', :scope => 'devise.otp.
|
2
|
-
<p><%= I18n.t('explain', :scope => 'devise.otp.
|
1
|
+
<h2><%= I18n.t('title', :scope => 'devise.otp.otp_tokens') %></h2>
|
2
|
+
<p><%= I18n.t('explain', :scope => 'devise.otp.otp_tokens') %></p>
|
3
3
|
|
4
4
|
<%= form_for(resource, :as => resource_name, :url => [resource_name, :otp_token], :html => { :method => :put, "data-turbo" => false }) do |f| %>
|
5
5
|
|
6
6
|
<%= render "devise/shared/error_messages", resource: resource %>
|
7
7
|
|
8
|
-
<h3><%= I18n.t('enable_request', :scope => 'devise.otp.
|
8
|
+
<h3><%= I18n.t('enable_request', :scope => 'devise.otp.otp_tokens') %></h3>
|
9
9
|
|
10
10
|
<p>
|
11
|
-
<%= f.label :otp_enabled, I18n.t('status', :scope => 'devise.otp.
|
11
|
+
<%= f.label :otp_enabled, I18n.t('status', :scope => 'devise.otp.otp_tokens') %><br />
|
12
12
|
<%= f.check_box :otp_enabled %>
|
13
13
|
</p>
|
14
14
|
|
15
|
-
<p><%= f.submit I18n.t('submit', :scope => 'devise.otp.
|
15
|
+
<p><%= f.submit I18n.t('submit', :scope => 'devise.otp.otp_tokens') %></p>
|
16
16
|
<% end %>
|
17
17
|
|
18
18
|
<%- if resource.otp_enabled? %>
|
data/config/locales/en.yml
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
en:
|
2
2
|
devise:
|
3
|
-
|
4
3
|
otp:
|
4
|
+
general:
|
5
|
+
remember: Remember me
|
5
6
|
submit_token:
|
6
7
|
title: 'Check Token'
|
7
8
|
explain: "You're getting this because you enabled two-factors authentication on your account"
|
@@ -9,21 +10,18 @@ en:
|
|
9
10
|
recovery_prompt: 'Please enter your recovery code:'
|
10
11
|
submit: 'Submit Token'
|
11
12
|
recovery_link: "I don't have my device, I want to use a recovery code"
|
12
|
-
|
13
|
-
credentials:
|
13
|
+
otp_credentials:
|
14
14
|
token_invalid: 'The token you provided was invalid.'
|
15
15
|
token_blank: 'You need to type in the token you generated with your device.'
|
16
16
|
need_to_refresh_credentials: 'We need to check your credentials before you can change these settings.'
|
17
17
|
valid_refresh: 'Thank you, your credentials were accepted.'
|
18
18
|
invalid_refresh: 'Sorry, you provided the wrong credentials.'
|
19
|
-
|
20
19
|
credentials_refresh:
|
21
20
|
title: 'Please enter your password again.'
|
22
21
|
explain: 'In order to ensure this is safe, please enter your password again.'
|
23
22
|
go_on: 'Continue...'
|
24
23
|
identity: 'Identity:'
|
25
24
|
token: 'Your two-factors authentication token'
|
26
|
-
|
27
25
|
token_secret:
|
28
26
|
title: 'Your token secret'
|
29
27
|
explain: 'Take a photo of this QR code with your mobile'
|
@@ -31,23 +29,18 @@ en:
|
|
31
29
|
reset_otp: 'Reset your Two Factors Authentication status'
|
32
30
|
reset_explain: 'This will reset your credentials, and disable two-factors authentication.'
|
33
31
|
reset_explain_warn: 'You will need to enroll your mobile device again.'
|
34
|
-
|
35
|
-
tokens:
|
32
|
+
otp_tokens:
|
36
33
|
title: 'Two-factors Authentication:'
|
37
34
|
explain: 'Two factors authentication adds an additional layer of security to your account. When logging in you will be asked for a code that you can generate on a physical device, like your phone.'
|
38
35
|
enable_request: 'Would you like to enable Two Factors Authenticator?'
|
39
|
-
|
40
36
|
status: 'Enable Two-Factors Authentication.'
|
41
37
|
submit: 'Continue...'
|
42
|
-
|
43
38
|
successfully_updated: 'Your two-factors authentication settings have been updated.'
|
44
39
|
successfully_reset_creds: 'Your two-factors credentials has been reset.'
|
45
40
|
successfully_set_persistence: 'Your device is now trusted.'
|
46
41
|
successfully_cleared_persistence: 'Your device has been removed from the list of trusted devices.'
|
47
42
|
successfully_reset_persistence: 'Your list of trusted devices has been cleared.'
|
48
|
-
|
49
43
|
need_to_refresh_credentials: 'We need to check your credentials before you can change these settings.'
|
50
|
-
|
51
44
|
recovery:
|
52
45
|
title: 'Your Emergency Recovery Codes'
|
53
46
|
explain: 'Take note or print these recovery codes. The will allow you to log back in in case your token device is lost, stolen, or unavailable.'
|
@@ -55,7 +48,6 @@ en:
|
|
55
48
|
code: 'Recovery Code'
|
56
49
|
codes_list: 'Here is the list of your recovery codes'
|
57
50
|
download_codes: 'Download recovery codes'
|
58
|
-
|
59
51
|
trusted_browsers:
|
60
52
|
title: 'Trusted Browsers'
|
61
53
|
explain: 'If you set your browser as trusted, you will not be asked to provide a Two-factor authentication token when logging in from that browser.'
|
data/devise-otp.gemspec
CHANGED
@@ -1,23 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative "lib/devise-otp/version"
|
4
4
|
|
5
5
|
Gem::Specification.new do |gem|
|
6
|
-
gem.name
|
7
|
-
gem.version
|
8
|
-
gem.authors
|
9
|
-
gem.email
|
10
|
-
gem.description
|
11
|
-
gem.summary
|
12
|
-
gem.homepage
|
6
|
+
gem.name = "devise-otp"
|
7
|
+
gem.version = Devise::OTP::VERSION
|
8
|
+
gem.authors = ["Lele Forzani", "Josef Strzibny"]
|
9
|
+
gem.email = ["lele@windmill.it", "strzibny@strzibny.name"]
|
10
|
+
gem.description = "Time Based OTP/rfc6238 compatible authentication for Devise"
|
11
|
+
gem.summary = "Time Based OTP/rfc6238 compatible authentication for Devise"
|
12
|
+
gem.homepage = "http://git.windmill.it/wm/devise-otp"
|
13
13
|
|
14
|
-
gem.files
|
15
|
-
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.files = `git ls-files`.split($/)
|
16
15
|
gem.require_paths = ["lib"]
|
17
16
|
|
18
|
-
gem.add_runtime_dependency
|
19
|
-
gem.add_runtime_dependency
|
20
|
-
gem.add_runtime_dependency
|
17
|
+
gem.add_runtime_dependency "rails", ">= 7.0", "< 7.2"
|
18
|
+
gem.add_runtime_dependency "devise", ">= 4.8.0", "< 5.0"
|
19
|
+
gem.add_runtime_dependency "rotp", ">= 2.0.0"
|
21
20
|
|
22
21
|
gem.add_development_dependency "capybara"
|
23
22
|
gem.add_development_dependency "cuprite"
|
@@ -27,4 +26,5 @@ Gem::Specification.new do |gem|
|
|
27
26
|
gem.add_development_dependency "shoulda"
|
28
27
|
gem.add_development_dependency "sprockets-rails"
|
29
28
|
gem.add_development_dependency "sqlite3"
|
29
|
+
gem.add_development_dependency "standardrb"
|
30
30
|
end
|
data/lib/devise-otp/version.rb
CHANGED
data/lib/devise-otp.rb
CHANGED
@@ -1,31 +1,21 @@
|
|
1
1
|
require "devise-otp/version"
|
2
2
|
|
3
3
|
# cherry pick active-support extensions
|
4
|
-
#require 'active_record/connection_adapters/abstract/schema_definitions'
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
4
|
+
# require 'active_record/connection_adapters/abstract/schema_definitions'
|
5
|
+
require "active_support/core_ext/integer"
|
6
|
+
require "active_support/core_ext/string"
|
7
|
+
require "active_support/ordered_hash"
|
8
|
+
require "active_support/concern"
|
9
9
|
|
10
|
-
require
|
10
|
+
require "devise"
|
11
11
|
|
12
12
|
module Devise
|
13
|
-
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
13
|
mattr_accessor :otp_mandatory
|
18
14
|
@@otp_mandatory = false
|
19
15
|
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
16
|
mattr_accessor :otp_authentication_timeout
|
24
17
|
@@otp_authentication_timeout = 3.minutes
|
25
18
|
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
19
|
mattr_accessor :otp_recovery_tokens
|
30
20
|
@@otp_recovery_tokens = 10 ## false to disable
|
31
21
|
|
@@ -36,11 +26,8 @@ module Devise
|
|
36
26
|
mattr_accessor :otp_trust_persistence
|
37
27
|
@@otp_trust_persistence = 30.days
|
38
28
|
|
39
|
-
|
40
|
-
#
|
41
|
-
#
|
42
|
-
mattr_accessor :otp_drift_window
|
43
|
-
@@otp_drift_window = 3 # in minutes
|
29
|
+
mattr_accessor :otp_drift_window
|
30
|
+
@@otp_drift_window = 3 # in minutes
|
44
31
|
|
45
32
|
#
|
46
33
|
# if the user wants to change Otp settings,
|
@@ -56,7 +43,6 @@ module Devise
|
|
56
43
|
mattr_accessor :otp_issuer
|
57
44
|
@@otp_issuer = Rails.application.class.module_parent_name
|
58
45
|
|
59
|
-
|
60
46
|
#
|
61
47
|
# custom view path
|
62
48
|
#
|
@@ -68,17 +54,17 @@ module Devise
|
|
68
54
|
end
|
69
55
|
|
70
56
|
module DeviseOtpAuthenticatable
|
71
|
-
autoload :Hooks,
|
57
|
+
autoload :Hooks, "devise_otp_authenticatable/hooks"
|
72
58
|
|
73
59
|
module Controllers
|
74
|
-
autoload :Helpers,
|
75
|
-
autoload :UrlHelpers,
|
60
|
+
autoload :Helpers, "devise_otp_authenticatable/controllers/helpers"
|
61
|
+
autoload :UrlHelpers, "devise_otp_authenticatable/controllers/url_helpers"
|
76
62
|
end
|
77
63
|
end
|
78
64
|
|
79
|
-
require
|
80
|
-
require
|
65
|
+
require "devise_otp_authenticatable/routes"
|
66
|
+
require "devise_otp_authenticatable/engine"
|
81
67
|
|
82
68
|
Devise.add_module :otp_authenticatable,
|
83
|
-
|
84
|
-
|
69
|
+
controller: :tokens,
|
70
|
+
model: "devise_otp_authenticatable/models/otp_authenticatable", route: :otp
|
@@ -1,9 +1,8 @@
|
|
1
1
|
module DeviseOtpAuthenticatable
|
2
2
|
module Controllers
|
3
3
|
module Helpers
|
4
|
-
|
5
4
|
def authenticate_scope!
|
6
|
-
send(:"authenticate_#{resource_name}!", :
|
5
|
+
send(:"authenticate_#{resource_name}!", force: true)
|
7
6
|
self.resource = send("current_#{resource_name}")
|
8
7
|
end
|
9
8
|
|
@@ -11,7 +10,7 @@ module DeviseOtpAuthenticatable
|
|
11
10
|
# similar to DeviseController#set_flash_message, but sets the scope inside
|
12
11
|
# the otp controller
|
13
12
|
#
|
14
|
-
def otp_set_flash_message(key, kind, options={})
|
13
|
+
def otp_set_flash_message(key, kind, options = {})
|
15
14
|
options[:scope] ||= "devise.otp.#{controller_name}"
|
16
15
|
options[:default] = Array(options[:default]).unshift(kind.to_sym)
|
17
16
|
options[:resource_name] = resource_name
|
@@ -20,7 +19,7 @@ module DeviseOtpAuthenticatable
|
|
20
19
|
flash[key] = message if message.present?
|
21
20
|
end
|
22
21
|
|
23
|
-
def otp_t
|
22
|
+
def otp_t
|
24
23
|
end
|
25
24
|
|
26
25
|
def trusted_devices_enabled?
|
@@ -67,7 +66,7 @@ module DeviseOtpAuthenticatable
|
|
67
66
|
return false unless resource.class.otp_trust_persistence
|
68
67
|
if cookies[otp_scoped_persistence_cookie].present?
|
69
68
|
cookies.signed[otp_scoped_persistence_cookie] ==
|
70
|
-
|
69
|
+
[resource.to_key, resource.authenticatable_salt, resource.otp_persistence_seed]
|
71
70
|
else
|
72
71
|
false
|
73
72
|
end
|
@@ -79,9 +78,9 @@ module DeviseOtpAuthenticatable
|
|
79
78
|
def otp_set_trusted_device_for(resource)
|
80
79
|
return unless resource.class.otp_trust_persistence
|
81
80
|
cookies.signed[otp_scoped_persistence_cookie] = {
|
82
|
-
|
83
|
-
|
84
|
-
|
81
|
+
httponly: true,
|
82
|
+
expires: Time.now + resource.class.otp_trust_persistence,
|
83
|
+
value: [resource.to_key, resource.authenticatable_salt, resource.otp_persistence_seed]
|
85
84
|
}
|
86
85
|
end
|
87
86
|
|
@@ -91,7 +90,6 @@ module DeviseOtpAuthenticatable
|
|
91
90
|
|
92
91
|
def otp_fetch_refresh_return_url
|
93
92
|
session.delete(otp_scoped_refresh_return_url_property) { :root }
|
94
|
-
|
95
93
|
end
|
96
94
|
|
97
95
|
def otp_scoped_refresh_return_url_property
|
@@ -131,27 +129,27 @@ module DeviseOtpAuthenticatable
|
|
131
129
|
private
|
132
130
|
|
133
131
|
def otp_authenticator_token_image_js(otp_url)
|
134
|
-
content_tag(:div, :
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
132
|
+
content_tag(:div, class: "qrcode-container") do
|
133
|
+
content_tag(:div, id: "qrcode", class: "qrcode") do
|
134
|
+
javascript_tag(%[
|
135
|
+
new QRCode("qrcode", {
|
136
|
+
text: "#{otp_url}",
|
137
|
+
width: 256,
|
138
|
+
height: 256,
|
139
|
+
colorDark : "#000000",
|
140
|
+
colorLight : "#ffffff",
|
141
|
+
correctLevel : QRCode.CorrectLevel.H
|
142
|
+
});
|
143
|
+
])
|
144
|
+
end
|
146
145
|
end
|
147
146
|
end
|
148
147
|
|
149
148
|
def otp_authenticator_token_image_google(otp_url)
|
150
149
|
otp_url = Rack::Utils.escape(otp_url)
|
151
150
|
url = "https://chart.googleapis.com/chart?chs=200x200&chld=M|0&cht=qr&chl=#{otp_url}"
|
152
|
-
image_tag(url, :
|
151
|
+
image_tag(url, alt: "OTP Url QRCode")
|
153
152
|
end
|
154
|
-
|
155
153
|
end
|
156
154
|
end
|
157
155
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module DeviseOtpAuthenticatable
|
2
2
|
module Controllers
|
3
3
|
module UrlHelpers
|
4
|
-
|
5
4
|
def recovery_otp_token_for(resource_or_scope, opts = {})
|
6
5
|
scope = ::Devise::Mapping.find_scope!(resource_or_scope)
|
7
6
|
send("recovery_#{scope}_otp_token_path", opts)
|
@@ -26,7 +25,6 @@ module DeviseOtpAuthenticatable
|
|
26
25
|
scope = ::Devise::Mapping.find_scope!(resource_or_scope)
|
27
26
|
send("#{scope}_otp_credential_path", opts)
|
28
27
|
end
|
29
|
-
|
30
28
|
end
|
31
29
|
end
|
32
30
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module DeviseOtpAuthenticatable
|
2
2
|
class Engine < ::Rails::Engine
|
3
|
+
config.devise_otp = ActiveSupport::OrderedOptions.new
|
4
|
+
config.devise_otp.precompile_assets = true
|
3
5
|
|
4
6
|
# We use to_prepare instead of after_initialize here because Devise is a Rails engine;
|
5
7
|
config.to_prepare do
|
@@ -19,12 +21,12 @@ module DeviseOtpAuthenticatable
|
|
19
21
|
|
20
22
|
# See: https://guides.rubyonrails.org/engines.html#separate-assets-and-precompiling
|
21
23
|
# check if Rails api mode
|
22
|
-
if app.config.respond_to?(:assets)
|
23
|
-
if defined?(Sprockets) && Sprockets::VERSION >= "4"
|
24
|
-
|
24
|
+
if app.config.respond_to?(:assets) && app.config.devise_otp.precompile_assets
|
25
|
+
app.config.assets.precompile << if defined?(Sprockets) && Sprockets::VERSION >= "4"
|
26
|
+
"devise-otp.js"
|
25
27
|
else
|
26
28
|
# use a proc instead of a string
|
27
|
-
|
29
|
+
proc { |path| path == "devise-otp.js" }
|
28
30
|
end
|
29
31
|
end
|
30
32
|
end
|
@@ -4,7 +4,7 @@ module DeviseOtpAuthenticatable::Hooks
|
|
4
4
|
include DeviseOtpAuthenticatable::Controllers::UrlHelpers
|
5
5
|
|
6
6
|
included do
|
7
|
-
alias_method
|
7
|
+
alias_method :create, :create_with_otp
|
8
8
|
end
|
9
9
|
|
10
10
|
#
|
@@ -22,15 +22,14 @@ module DeviseOtpAuthenticatable::Hooks
|
|
22
22
|
challenge = resource.generate_otp_challenge!
|
23
23
|
warden.logout
|
24
24
|
store_location_for(resource, devise_stored_location) # restore the stored location
|
25
|
-
respond_with resource, :
|
25
|
+
respond_with resource, location: otp_credential_path_for(resource, {challenge: challenge})
|
26
26
|
elsif otp_mandatory_on?(resource) # if mandatory, log in user but send him to the must activate otp
|
27
27
|
set_flash_message(:notice, :signed_in_but_otp) if is_navigational_format?
|
28
28
|
sign_in(resource_name, resource)
|
29
|
-
respond_with resource, :
|
29
|
+
respond_with resource, location: otp_token_path_for(resource)
|
30
30
|
else
|
31
|
-
set_flash_message(:notice, :signed_in) if is_navigational_format?
|
32
31
|
sign_in(resource_name, resource)
|
33
|
-
respond_with resource, :
|
32
|
+
respond_with resource, location: after_sign_in_path_for(resource)
|
34
33
|
end
|
35
34
|
end
|
36
35
|
|