devise-otp-rails5 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
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,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,3 @@
1
+ <% resource.next_otp_recovery_tokens.each do |seq, code| %>
2
+ <%= code %>
3
+ <% end %>
@@ -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'
@@ -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
@@ -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