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.
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