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.
- checksums.yaml +7 -0
- data/.gitignore +42 -0
- data/.travis.yml +12 -0
- data/Gemfile +25 -0
- data/LICENSE.txt +22 -0
- data/README.md +140 -0
- data/Rakefile +42 -0
- data/app/assets/javascripts/devise-otp.js +1 -0
- data/app/assets/javascripts/qrcode.js +609 -0
- data/app/controllers/devise_otp/credentials_controller.rb +106 -0
- data/app/controllers/devise_otp/tokens_controller.rb +111 -0
- data/app/views/devise_otp/credentials/refresh.html.erb +20 -0
- data/app/views/devise_otp/credentials/show.html.erb +23 -0
- data/app/views/devise_otp/tokens/_token_secret.html.erb +19 -0
- data/app/views/devise_otp/tokens/_trusted_devices.html.erb +10 -0
- data/app/views/devise_otp/tokens/recovery.html.erb +21 -0
- data/app/views/devise_otp/tokens/recovery_codes.text.erb +3 -0
- data/app/views/devise_otp/tokens/show.html.erb +19 -0
- data/config/locales/en.yml +66 -0
- data/devise-otp.gemspec +25 -0
- data/lib/devise-otp.rb +83 -0
- data/lib/devise-otp/version.rb +5 -0
- data/lib/devise_otp_authenticatable/controllers/helpers.rb +168 -0
- data/lib/devise_otp_authenticatable/controllers/url_helpers.rb +33 -0
- data/lib/devise_otp_authenticatable/engine.rb +23 -0
- data/lib/devise_otp_authenticatable/hooks.rb +13 -0
- data/lib/devise_otp_authenticatable/hooks/sessions.rb +59 -0
- data/lib/devise_otp_authenticatable/mapping.rb +19 -0
- data/lib/devise_otp_authenticatable/models/otp_authenticatable.rb +137 -0
- data/lib/devise_otp_authenticatable/routes.rb +32 -0
- data/lib/generators/active_record/devise_otp_generator.rb +13 -0
- data/lib/generators/active_record/templates/migration.rb +27 -0
- data/lib/generators/devise_otp/devise_otp_generator.rb +17 -0
- data/lib/generators/devise_otp/install_generator.rb +53 -0
- data/lib/generators/devise_otp/views_generator.rb +19 -0
- data/test/dummy/README.rdoc +261 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/application_controller.rb +4 -0
- data/test/dummy/app/controllers/posts_controller.rb +83 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/helpers/posts_helper.rb +2 -0
- data/test/dummy/app/mailers/.gitkeep +0 -0
- data/test/dummy/app/models/post.rb +2 -0
- data/test/dummy/app/models/user.rb +20 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/app/views/posts/_form.html.erb +25 -0
- data/test/dummy/app/views/posts/edit.html.erb +6 -0
- data/test/dummy/app/views/posts/index.html.erb +25 -0
- data/test/dummy/app/views/posts/new.html.erb +5 -0
- data/test/dummy/app/views/posts/show.html.erb +15 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +67 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +30 -0
- data/test/dummy/config/environments/production.rb +69 -0
- data/test/dummy/config/environments/test.rb +36 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/devise.rb +253 -0
- data/test/dummy/config/initializers/inflections.rb +15 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +8 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +6 -0
- data/test/dummy/db/migrate/20130125101430_create_users.rb +9 -0
- data/test/dummy/db/migrate/20130131092406_add_devise_to_users.rb +53 -0
- data/test/dummy/db/migrate/20130131142320_create_posts.rb +10 -0
- data/test/dummy/db/migrate/20130131160351_devise_otp_add_to_users.rb +28 -0
- data/test/dummy/lib/assets/.gitkeep +0 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +25 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/integration/persistence_test.rb +65 -0
- data/test/integration/refresh_test.rb +106 -0
- data/test/integration/sign_in_test.rb +87 -0
- data/test/integration/token_test.rb +34 -0
- data/test/integration_tests_helper.rb +66 -0
- data/test/model_tests_helper.rb +22 -0
- data/test/models/otp_authenticatable_test.rb +122 -0
- data/test/orm/active_record.rb +4 -0
- data/test/test_helper.rb +22 -0
- metadata +253 -0
@@ -0,0 +1,106 @@
|
|
1
|
+
class DeviseOtp::CredentialsController < DeviseController
|
2
|
+
helper_method :new_session_path
|
3
|
+
|
4
|
+
prepend_before_action :authenticate_scope!, :only => [:get_refresh, :set_refresh]
|
5
|
+
prepend_before_action :require_no_authentication, :only => [ :show, :update ]
|
6
|
+
|
7
|
+
#
|
8
|
+
# show a request for the OTP token
|
9
|
+
#
|
10
|
+
def show
|
11
|
+
@challenge = params[:challenge]
|
12
|
+
@recovery = (params[:recovery] == 'true') && recovery_enabled?
|
13
|
+
|
14
|
+
if @challenge.nil?
|
15
|
+
redirect_to :root
|
16
|
+
|
17
|
+
else
|
18
|
+
self.resource = resource_class.find_valid_otp_challenge(@challenge)
|
19
|
+
if resource.nil?
|
20
|
+
redirect_to :root
|
21
|
+
elsif @recovery
|
22
|
+
@recovery_count = resource.otp_recovery_counter
|
23
|
+
render :show
|
24
|
+
else
|
25
|
+
render :show
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
# signs the resource in, if the OTP token is valid and the user has a valid challenge
|
32
|
+
#
|
33
|
+
def update
|
34
|
+
|
35
|
+
resource = resource_class.find_valid_otp_challenge(params[resource_name][:challenge])
|
36
|
+
recovery = (params[resource_name][:recovery] == 'true') && recovery_enabled?
|
37
|
+
token = params[resource_name][:token]
|
38
|
+
|
39
|
+
if token.blank?
|
40
|
+
otp_set_flash_message(:alert, :token_blank)
|
41
|
+
redirect_to otp_credential_path_for(resource_name, :challenge => params[resource_name][:challenge],
|
42
|
+
:recovery => recovery)
|
43
|
+
elsif resource.nil?
|
44
|
+
otp_set_flash_message(:alert, :otp_session_invalid)
|
45
|
+
redirect_to new_session_path(resource_name)
|
46
|
+
else
|
47
|
+
if resource.otp_challenge_valid? && resource.validate_otp_token(params[resource_name][:token], recovery)
|
48
|
+
set_flash_message(:success, :signed_in) if is_navigational_format?
|
49
|
+
sign_in(resource_name, resource)
|
50
|
+
|
51
|
+
otp_refresh_credentials_for(resource)
|
52
|
+
respond_with resource, :location => after_sign_in_path_for(resource)
|
53
|
+
else
|
54
|
+
otp_set_flash_message :alert, :token_invalid
|
55
|
+
redirect_to new_session_path(resource_name)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
#
|
62
|
+
# displays the request for a credentials refresh
|
63
|
+
#
|
64
|
+
def get_refresh
|
65
|
+
ensure_resource!
|
66
|
+
render :refresh
|
67
|
+
end
|
68
|
+
|
69
|
+
#
|
70
|
+
# lets the user through is the refresh is valid
|
71
|
+
#
|
72
|
+
def set_refresh
|
73
|
+
|
74
|
+
ensure_resource!
|
75
|
+
# I am sure there's a much better way
|
76
|
+
if resource.valid_password?(params[resource_name][:refresh_password])
|
77
|
+
if resource.otp_enabled?
|
78
|
+
if resource.validate_otp_token(params[resource_name][:token])
|
79
|
+
done_valid_refresh
|
80
|
+
else
|
81
|
+
failed_refresh
|
82
|
+
end
|
83
|
+
else
|
84
|
+
done_valid_refresh
|
85
|
+
end
|
86
|
+
else
|
87
|
+
failed_refresh
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def done_valid_refresh
|
95
|
+
otp_refresh_credentials_for(resource)
|
96
|
+
otp_set_flash_message :success, :valid_refresh if is_navigational_format?
|
97
|
+
|
98
|
+
respond_with resource, :location => otp_fetch_refresh_return_url
|
99
|
+
end
|
100
|
+
|
101
|
+
def failed_refresh
|
102
|
+
otp_set_flash_message :alert, :invalid_refresh
|
103
|
+
render :refresh
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
class DeviseOtp::TokensController < DeviseController
|
2
|
+
include Devise::Controllers::Helpers
|
3
|
+
|
4
|
+
prepend_before_action :ensure_credentials_refresh
|
5
|
+
prepend_before_action :authenticate_scope!
|
6
|
+
|
7
|
+
protect_from_forgery :except => [:clear_persistence, :delete_persistence]
|
8
|
+
|
9
|
+
#
|
10
|
+
# Displays the status of OTP authentication
|
11
|
+
#
|
12
|
+
def show
|
13
|
+
if resource.nil?
|
14
|
+
redirect_to stored_location_for(scope) || :root
|
15
|
+
else
|
16
|
+
render :show
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# Updates the status of OTP authentication
|
22
|
+
#
|
23
|
+
def update
|
24
|
+
|
25
|
+
enabled = (params[resource_name][:otp_enabled] == '1')
|
26
|
+
if (enabled ? resource.enable_otp! : resource.disable_otp!)
|
27
|
+
|
28
|
+
otp_set_flash_message :success, :successfully_updated
|
29
|
+
end
|
30
|
+
render :show
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# Resets OTP authentication, generates new credentials, sets it to off
|
35
|
+
#
|
36
|
+
def destroy
|
37
|
+
|
38
|
+
if resource.reset_otp_credentials!
|
39
|
+
otp_set_flash_message :success, :successfully_reset_creds
|
40
|
+
end
|
41
|
+
render :show
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
#
|
46
|
+
# makes the current browser persistent
|
47
|
+
#
|
48
|
+
def get_persistence
|
49
|
+
|
50
|
+
|
51
|
+
if otp_set_trusted_device_for(resource)
|
52
|
+
otp_set_flash_message :success, :successfully_set_persistence
|
53
|
+
end
|
54
|
+
redirect_to :action => :show
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
#
|
59
|
+
# clears persistence for the current browser
|
60
|
+
#
|
61
|
+
def clear_persistence
|
62
|
+
if otp_clear_trusted_device_for(resource)
|
63
|
+
otp_set_flash_message :success, :successfully_cleared_persistence
|
64
|
+
end
|
65
|
+
|
66
|
+
redirect_to :action => :show
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
#
|
71
|
+
# rehash the persistence secret, thus, making all the persistence cookies invalid
|
72
|
+
#
|
73
|
+
def delete_persistence
|
74
|
+
if otp_reset_persistence_for(resource)
|
75
|
+
otp_set_flash_message :notice, :successfully_reset_persistence
|
76
|
+
end
|
77
|
+
|
78
|
+
redirect_to :action => :show
|
79
|
+
end
|
80
|
+
|
81
|
+
#
|
82
|
+
#
|
83
|
+
#
|
84
|
+
def recovery
|
85
|
+
respond_to do |format|
|
86
|
+
format.html
|
87
|
+
format.js
|
88
|
+
format.text do
|
89
|
+
send_data render_to_string(template: "devise_otp/tokens/recovery_codes.text.erb"), filename: "recovery-codes.txt"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def ensure_credentials_refresh
|
98
|
+
|
99
|
+
ensure_resource!
|
100
|
+
if needs_credentials_refresh?(resource)
|
101
|
+
otp_set_flash_message :notice, :need_to_refresh_credentials
|
102
|
+
redirect_to refresh_otp_credential_path_for(resource)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def scope
|
107
|
+
resource_name.to_sym
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<h2><%= I18n.t('title', {:scope => 'devise.otp.credentials_refresh'}) %></h2>
|
2
|
+
<p><%= I18n.t('explain', {:scope => 'devise.otp.credentials_refresh'}) %></p>
|
3
|
+
|
4
|
+
<%= form_for(resource, :as => resource_name, :url => [:refresh, resource_name, :otp_credential], :html => { :method => :put }) do |f| %>
|
5
|
+
|
6
|
+
<%= devise_error_messages! %>
|
7
|
+
|
8
|
+
<div><%= f.label :email %><br />
|
9
|
+
<%= f.text_field :email, :disabled => :true%></div>
|
10
|
+
|
11
|
+
<div><%= f.label :password %><br />
|
12
|
+
<%= f.password_field :refresh_password, :autocomplete => :off, :autofocus => true %></div>
|
13
|
+
|
14
|
+
<%- if resource.otp_enabled? %>
|
15
|
+
<div><%= f.label :token, I18n.t(:token, {:scope => 'devise.otp.credentials_refresh'}) %></p><br />
|
16
|
+
<%= f.password_field :token, :autocomplete => :off%></div>
|
17
|
+
<% end %>
|
18
|
+
|
19
|
+
<div><%= f.submit I18n.t(:go_on, {:scope => 'devise.otp.credentials_refresh'}) %></div>
|
20
|
+
<% end %>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<h2><%= I18n.t('title', {:scope => 'devise.otp.submit_token'}) %></h2>
|
2
|
+
<p><%= I18n.t('explain', {:scope => 'devise.otp.submit_token'}) %></p>
|
3
|
+
|
4
|
+
<%= form_for(resource, :as => resource_name, :url => [resource_name, :otp_credential], :html => { :method => :put }) do |f| %>
|
5
|
+
|
6
|
+
<%= f.hidden_field :challenge, {:value => @challenge} %>
|
7
|
+
<%= f.hidden_field :recovery, {:value => @recovery} %>
|
8
|
+
|
9
|
+
<%- if @recovery %>
|
10
|
+
<p><%= f.label :token, I18n.t('recovery_prompt', {:scope => 'devise.otp.submit_token'}) %><br />
|
11
|
+
<%= f.text_field :otp_recovery_counter, :autocomplete => :off, :disabled => true, :size => 4 %>
|
12
|
+
<% else %>
|
13
|
+
<p><%= f.label :token, I18n.t('prompt', {:scope => 'devise.otp.submit_token'}) %><br />
|
14
|
+
<% end %>
|
15
|
+
|
16
|
+
<%= f.text_field :token, :autocomplete => :off, :autofocus => true, :size => 6, :value => '' %>
|
17
|
+
</p>
|
18
|
+
|
19
|
+
<p><%= f.submit I18n.t('submit', {:scope => 'devise.otp.submit_token'}) %></p>
|
20
|
+
<%- if !@recovery && recovery_enabled? %>
|
21
|
+
<p><%= link_to I18n.t('recovery_link', {:scope => 'devise.otp.submit_token'}), otp_credential_path_for(resource_name, :challenge => @challenge, :recovery => true) %></p>
|
22
|
+
<% end %>
|
23
|
+
<% end %>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<h3><%= I18n.t('title', {:scope => 'devise.otp.token_secret'}) %></h3>
|
2
|
+
<p><%= I18n.t('explain', {:scope => 'devise.otp.token_secret'}) %></p>
|
3
|
+
|
4
|
+
<%= otp_authenticator_token_image(resource) %>
|
5
|
+
|
6
|
+
<p><strong><%= I18n.t('manual_provisioning', {:scope => 'devise.otp.token_secret'}) %>:</strong>
|
7
|
+
<code><%= resource.otp_auth_secret %></code></p>
|
8
|
+
|
9
|
+
<p><%= link_to I18n.t('reset_otp', {:scope => 'devise.otp.token_secret'}), @resource, :method => :delete %></p>
|
10
|
+
<p><%= I18n.t('reset_explain', {:scope => 'devise.otp.token_secret'}) %>
|
11
|
+
<strong><%= I18n.t('reset_explain_warn', {:scope => 'devise.otp.token_secret'}) %></strong></p>
|
12
|
+
|
13
|
+
<%- if recovery_enabled? %>
|
14
|
+
<h3><%= I18n.t('title', {:scope => 'devise.otp.tokens.recovery'}) %></h3>
|
15
|
+
<p><%= I18n.t('explain', {:scope => 'devise.otp.tokens.recovery'}) %></p>
|
16
|
+
<p><%= link_to I18n.t('codes_list', {:scope => 'devise.otp.tokens.recovery'}), recovery_otp_token_for(resource_name) %></p>
|
17
|
+
<p><%= link_to I18n.t('download_codes', {:scope => 'devise.otp.tokens.recovery'}), recovery_otp_token_for(resource_name, format: :text) %></p>
|
18
|
+
|
19
|
+
<% end %>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<h3><%= I18n.t('title', {:scope => 'devise.otp.trusted_devices'}) %></h3>
|
2
|
+
<p><%= I18n.t('explain', {:scope => 'devise.otp.trusted_devices'}) %></p>
|
3
|
+
<%- if is_otp_trusted_device_for? resource %>
|
4
|
+
<p><em><%= I18n.t('device_trusted', {:scope => 'devise.otp.trusted_devices'}) %></em></p>
|
5
|
+
<p><%= link_to I18n.t('trust_remove', {:scope => 'devise.otp.trusted_devices'}), persistence_otp_token_path_for(resource_name), :method => :post %></p>
|
6
|
+
<% else %>
|
7
|
+
<p><%= I18n.t('device_not_trusted', {:scope => 'devise.otp.trusted_devices'}) %></p>
|
8
|
+
<p><%= link_to I18n.t('trust_add', {:scope => 'devise.otp.trusted_devices'}), persistence_otp_token_path_for(resource_name) %></p>
|
9
|
+
<% end %>
|
10
|
+
<p><%= link_to I18n.t('trust_clear', {:scope => 'devise.otp.trusted_devices'}), persistence_otp_token_path_for(resource_name), :method => :delete %></p>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<h2><%= I18n.t('title', {:scope => 'devise.otp.tokens.recovery'}) %></h2>
|
2
|
+
<p><%= I18n.t('explain', {:scope => 'devise.otp.tokens.recovery'}) %></p>
|
3
|
+
|
4
|
+
<table>
|
5
|
+
<caption>
|
6
|
+
<thead>
|
7
|
+
<tr>
|
8
|
+
<th><%= I18n.t('sequence', {:scope => 'devise.otp.tokens.recovery'}) %></th>
|
9
|
+
<th><%= I18n.t('code', {:scope => 'devise.otp.tokens.recovery'}) %></th>
|
10
|
+
</tr>
|
11
|
+
</thead>
|
12
|
+
<tbody>
|
13
|
+
<%- resource.next_otp_recovery_tokens.each do |seq, code| %>
|
14
|
+
<tr>
|
15
|
+
<td><%= seq %></td>
|
16
|
+
<td><%= code %></td>
|
17
|
+
</tr>
|
18
|
+
<% end %>
|
19
|
+
</tbody>
|
20
|
+
</caption>
|
21
|
+
</table>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<h2><%= I18n.t('title', {:scope => 'devise.otp.tokens'}) %></h2>
|
2
|
+
<p><%= I18n.t('explain', {:scope => 'devise.otp.tokens'}) %></p>
|
3
|
+
|
4
|
+
<%= form_for(resource, :as => resource_name, :url => [resource_name, :otp_token], :html => { :method => :put }) do |f| %>
|
5
|
+
|
6
|
+
<%= devise_error_messages! %>
|
7
|
+
|
8
|
+
<h3><%= I18n.t('enable_request', {:scope => 'devise.otp.tokens'}) %></h3>
|
9
|
+
|
10
|
+
<p><%= f.label :otp_enabled, I18n.t('status', {:scope => 'devise.otp.tokens'}) %><br />
|
11
|
+
<%= f.check_box :otp_enabled %></p>
|
12
|
+
|
13
|
+
<p><%= f.submit I18n.t('submit', {:scope => 'devise.otp.tokens'}) %></p>
|
14
|
+
<% end %>
|
15
|
+
|
16
|
+
<%- if resource.otp_enabled? %>
|
17
|
+
<%= render :partial => 'token_secret' if resource.otp_enabled? %>
|
18
|
+
<%= render :partial => 'trusted_devices' if trusted_devices_enabled? %>
|
19
|
+
<% end %>
|
@@ -0,0 +1,66 @@
|
|
1
|
+
en:
|
2
|
+
devise:
|
3
|
+
|
4
|
+
otp:
|
5
|
+
submit_token:
|
6
|
+
title: 'Check Token'
|
7
|
+
explain: "You're getting this because you enabled two-factors authentication on your account"
|
8
|
+
prompt: 'Please enter your two-factors authentication token:'
|
9
|
+
recovery_prompt: 'Please enter your recovery code:'
|
10
|
+
submit: 'Submit Token'
|
11
|
+
recovery_link: "I don't have my device, I want to use a recovery code"
|
12
|
+
|
13
|
+
credentials:
|
14
|
+
token_invalid: 'The token you provided was invalid.'
|
15
|
+
token_blank: 'You need to type in the token you generated with your device.'
|
16
|
+
need_to_refresh_credentials: 'We need to check your credentials before you can change these settings.'
|
17
|
+
valid_refresh: 'Thank you, your credentials were accepted.'
|
18
|
+
invalid_refresh: 'Sorry, you provided the wrong credentials.'
|
19
|
+
|
20
|
+
credentials_refresh:
|
21
|
+
title: 'Please enter your password again.'
|
22
|
+
explain: 'In order to ensure this is safe, please enter your password again.'
|
23
|
+
go_on: 'Continue...'
|
24
|
+
identity: 'Identity:'
|
25
|
+
token: 'Your two-factors authentication token'
|
26
|
+
|
27
|
+
token_secret:
|
28
|
+
title: 'Your token secret'
|
29
|
+
explain: 'Take a photo of this QR code with your mobile'
|
30
|
+
manual_provisioning: 'Manual provisioning code'
|
31
|
+
reset_otp: 'Reset your Two Factors Authentication status'
|
32
|
+
reset_explain: 'This will reset your credentials, and disable two-factors authentication.'
|
33
|
+
reset_explain_warn: 'You will need to enroll your mobile device again.'
|
34
|
+
|
35
|
+
tokens:
|
36
|
+
title: 'Two-factors Authentication:'
|
37
|
+
explain: 'Two factors authentication adds 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
|
+
enable_request: 'Would you like to enable Two Factors Authenticator?'
|
39
|
+
|
40
|
+
status: 'Enable Two-Factors Authentication.'
|
41
|
+
submit: 'Continue...'
|
42
|
+
|
43
|
+
successfully_updated: 'Your two-factors authentication settings have been updated.'
|
44
|
+
successfully_reset_creds: 'Your two-factors credentials has been reset.'
|
45
|
+
successfully_set_persistence: 'Your device is now trusted.'
|
46
|
+
successfully_cleared_persistence: 'Your device has been removed from the list of trusted devices.'
|
47
|
+
successfully_reset_persistence: 'Your list of trusted devices has been cleared.'
|
48
|
+
|
49
|
+
need_to_refresh_credentials: 'We need to check your credentials before you can change these settings.'
|
50
|
+
|
51
|
+
recovery:
|
52
|
+
title: 'Your Emergency Recovery Codes'
|
53
|
+
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.'
|
54
|
+
sequence: 'Sequence'
|
55
|
+
code: 'Recovery Code'
|
56
|
+
codes_list: 'Here is the list of your recovery codes'
|
57
|
+
download_codes: 'Download recovery codes'
|
58
|
+
|
59
|
+
trusted_devices:
|
60
|
+
title: 'Trusted Browsers'
|
61
|
+
explain: 'If you set your browser as trusted, you will not be asked to perform a 2-factors authentication when logging in from that browser, for a time of one month.'
|
62
|
+
device_trusted: 'Your browser is trusted.'
|
63
|
+
device_not_trusted: 'Your browser is not trusted.'
|
64
|
+
trust_remove: 'Remove this device from the list of trusted browsers'
|
65
|
+
trust_add: 'Trust this browser'
|
66
|
+
trust_clear: 'Clear the list of trusted browser'
|
data/devise-otp.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'devise-otp/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "devise-otp-rails5"
|
8
|
+
gem.version = Devise::Otp::VERSION
|
9
|
+
gem.authors = ["Lele Forzani", "Josef Strzibny"]
|
10
|
+
gem.email = ["strzibny@strzibny.name"]
|
11
|
+
gem.description = %q{Time Based OTP/rfc6238 compatible authentication for Devise with Devise 4.2 and Rails 5 compatibility. Drop-in replacement for devise-otp.}
|
12
|
+
gem.summary = %q{Time Based OTP/rfc6238 compatible authentication for Devise}
|
13
|
+
gem.homepage = ""
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_runtime_dependency 'rails', '>= 3.2.6', '< 5.1'
|
21
|
+
gem.add_runtime_dependency 'devise', '>= 3.1.0', '< 4.3.0'
|
22
|
+
gem.add_runtime_dependency 'rotp', '>= 2.0.0'
|
23
|
+
|
24
|
+
gem.add_development_dependency "sqlite3"
|
25
|
+
end
|
data/lib/devise-otp.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require "devise-otp/version"
|
2
|
+
|
3
|
+
# cherry pick active-support extensions
|
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
|
+
|
10
|
+
require 'devise'
|
11
|
+
|
12
|
+
|
13
|
+
module Devise
|
14
|
+
|
15
|
+
|
16
|
+
#
|
17
|
+
#
|
18
|
+
#
|
19
|
+
mattr_accessor :otp_mandatory
|
20
|
+
@@otp_mandatory = false
|
21
|
+
|
22
|
+
#
|
23
|
+
#
|
24
|
+
#
|
25
|
+
mattr_accessor :otp_authentication_timeout
|
26
|
+
@@otp_authentication_timeout = 3.minutes
|
27
|
+
|
28
|
+
#
|
29
|
+
#
|
30
|
+
#
|
31
|
+
mattr_accessor :otp_recovery_tokens
|
32
|
+
@@otp_recovery_tokens = 10 ## false to disable
|
33
|
+
|
34
|
+
#
|
35
|
+
# If the user is given the chance to set his browser as trusted, how long will it stay trusted.
|
36
|
+
# set to nil/false to disable the ability to set a device as trusted
|
37
|
+
#
|
38
|
+
mattr_accessor :otp_trust_persistence
|
39
|
+
@@otp_trust_persistence = 30.days
|
40
|
+
|
41
|
+
#
|
42
|
+
#
|
43
|
+
#
|
44
|
+
mattr_accessor :otp_drift_window
|
45
|
+
@@otp_drift_window = 3 # in minutes
|
46
|
+
|
47
|
+
#
|
48
|
+
# if the user wants to change Otp settings,
|
49
|
+
# ask the password (and the token) again if this time has passed since the last
|
50
|
+
# time the user has provided valid credentials
|
51
|
+
#
|
52
|
+
mattr_accessor :otp_credentials_refresh
|
53
|
+
@@otp_credentials_refresh = 15.minutes # or like 15.minutes, false to disable
|
54
|
+
|
55
|
+
#
|
56
|
+
# the name of the token issuer
|
57
|
+
#
|
58
|
+
mattr_accessor :otp_issuer
|
59
|
+
@@otp_issuer = Rails.application.class.parent_name
|
60
|
+
|
61
|
+
module Otp
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
module DeviseOtpAuthenticatable
|
67
|
+
|
68
|
+
autoload :Hooks, 'devise_otp_authenticatable/hooks'
|
69
|
+
autoload :Mapping, 'devise_otp_authenticatable/mapping'
|
70
|
+
|
71
|
+
module Controllers
|
72
|
+
autoload :Helpers, 'devise_otp_authenticatable/controllers/helpers'
|
73
|
+
autoload :UrlHelpers, 'devise_otp_authenticatable/controllers/url_helpers'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
require 'devise_otp_authenticatable/routes'
|
79
|
+
require 'devise_otp_authenticatable/engine'
|
80
|
+
|
81
|
+
Devise.add_module :otp_authenticatable,
|
82
|
+
:controller => :otp_tokens,
|
83
|
+
:model => 'devise_otp_authenticatable/models/otp_authenticatable', :route => :otp
|