devise-otp 1.1.0 → 2.0.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/.erb_lint.yml +30 -0
- data/.rubocop.yml +18 -0
- data/CHANGELOG.md +42 -1
- data/Gemfile +7 -1
- data/README.md +5 -1
- data/app/controllers/devise_otp/devise/otp_credentials_controller.rb +30 -7
- data/app/controllers/devise_otp/devise/otp_persistence_controller.rb +53 -0
- data/app/controllers/devise_otp/devise/otp_tokens_controller.rb +2 -37
- data/app/views/devise/otp_credentials/refresh.html.erb +6 -6
- data/app/views/devise/otp_credentials/show.html.erb +10 -13
- data/app/views/devise/otp_tokens/_token_secret.html.erb +9 -9
- data/app/views/devise/otp_tokens/_trusted_devices.html.erb +7 -7
- data/app/views/devise/otp_tokens/edit.html.erb +9 -9
- data/app/views/devise/otp_tokens/recovery.html.erb +6 -6
- data/app/views/devise/otp_tokens/show.html.erb +6 -6
- data/bin/erb_lint +27 -0
- data/bin/rubocop +27 -0
- data/config/locales/en.yml +9 -7
- data/devise-otp.gemspec +3 -1
- data/lib/devise/strategies/database_authenticatable.rb +4 -17
- data/lib/devise-otp/version.rb +1 -1
- data/lib/devise-otp.rb +0 -1
- data/lib/devise_otp_authenticatable/controllers/helpers.rb +1 -2
- data/lib/devise_otp_authenticatable/controllers/public_helpers.rb +1 -2
- data/lib/devise_otp_authenticatable/controllers/url_helpers.rb +7 -2
- data/lib/devise_otp_authenticatable/hooks/refreshable.rb +0 -1
- data/lib/devise_otp_authenticatable/models/otp_authenticatable.rb +18 -12
- data/lib/devise_otp_authenticatable/routes.rb +7 -7
- data/test/dummy/app/controllers/admin_posts_controller.rb +0 -1
- data/test/dummy/app/controllers/base_controller.rb +0 -2
- data/test/dummy/app/controllers/non_otp_posts_controller.rb +0 -1
- data/test/dummy/app/models/admin.rb +0 -1
- data/test/dummy/app/models/lockable_user.rb +8 -0
- data/test/dummy/app/models/non_otp_user.rb +0 -1
- data/test/dummy/app/models/rememberable_user.rb +8 -0
- data/test/dummy/app/views/layouts/application.html.erb +4 -2
- data/test/dummy/app/views/posts/show.html.erb +0 -1
- data/test/dummy/app/views/shared/_navbar.html.erb +15 -0
- data/test/dummy/config/application.rb +3 -0
- data/test/dummy/config/initializers/devise.rb +2 -2
- data/test/dummy/config/routes.rb +3 -0
- data/test/dummy/db/migrate/20250731000001_create_lockable_users.rb +9 -0
- data/test/dummy/db/migrate/20250731000002_add_devise_to_lockable_users.rb +52 -0
- data/test/dummy/db/migrate/20250731000003_devise_otp_add_to_lockable_users.rb +28 -0
- data/test/dummy/db/migrate/20250817221304_create_rememberable_users.rb +50 -0
- data/test/dummy/db/migrate/20250818030305_add_devise_otp_to_rememberable_users.rb +28 -0
- data/test/dummy/db/schema.rb +67 -1
- data/test/integration/disable_token_test.rb +0 -2
- data/test/integration/enable_otp_form_test.rb +12 -1
- data/test/integration/lockable_test.rb +143 -0
- data/test/integration/non_otp_user_models_test.rb +0 -2
- data/test/integration/otp_drift_test.rb +35 -0
- data/test/integration/persistence_test.rb +59 -4
- data/test/integration/refresh_test.rb +23 -14
- data/test/integration/rememberable_test.rb +143 -0
- data/test/integration/reset_token_test.rb +0 -2
- data/test/integration/sign_in_test.rb +15 -8
- data/test/integration/trackable_test.rb +0 -2
- data/test/integration_tests_helper.rb +22 -1
- data/test/models/otp_authenticatable_test.rb +48 -11
- data/test/test_helper.rb +1 -0
- metadata +34 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: afd51a7a5178b6da891987b166c3f838833ec6c6c506ceb457c49c743b925244
|
4
|
+
data.tar.gz: 20e043c52ed71c4d6e8c5b9dd309badbf656d6d0d386cdae1269d8440a91d09e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: faee3c01bdf932a07843ea991f87cffa40081a1339647960382e7ad6532302aeb02cd0ac39de8a643a5b3a33f87a134a3bf11a30969b3c5a3d64c6bea3cb0a6f
|
7
|
+
data.tar.gz: f08c0a495128b23816751a3386082bf250d3791ce2dc25c0f4e4facd6e911053900aad3664f75938d3ab67c3757811f189f9a22f5b535c8095a679de3f901c60
|
data/.erb_lint.yml
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
---
|
2
|
+
EnableDefaultLinters: true
|
3
|
+
glob: "**/*.{html,text,js}{+*,}.erb"
|
4
|
+
linters:
|
5
|
+
# ErbSafety:
|
6
|
+
# enabled: true
|
7
|
+
# better_html_config: .better-html.yml
|
8
|
+
SelfClosingTag:
|
9
|
+
enabled: false
|
10
|
+
Rubocop:
|
11
|
+
enabled: true
|
12
|
+
rubocop_config:
|
13
|
+
inherit_from:
|
14
|
+
- .rubocop.yml
|
15
|
+
Layout/InitialIndentation:
|
16
|
+
Enabled: false
|
17
|
+
Layout/LineLength:
|
18
|
+
Enabled: false
|
19
|
+
Layout/TrailingEmptyLines:
|
20
|
+
Enabled: false
|
21
|
+
Layout/TrailingWhitespace:
|
22
|
+
Enabled: false
|
23
|
+
Naming/FileName:
|
24
|
+
Enabled: false
|
25
|
+
Style/FrozenStringLiteralComment:
|
26
|
+
Enabled: false
|
27
|
+
Lint/UselessAssignment:
|
28
|
+
Enabled: false
|
29
|
+
Rails/OutputSafety:
|
30
|
+
Enabled: false
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# Omakase Ruby styling for Rails
|
2
|
+
inherit_gem:
|
3
|
+
rubocop-rails-omakase: rubocop.yml
|
4
|
+
|
5
|
+
# Excluded directories
|
6
|
+
AllCops:
|
7
|
+
Exclude:
|
8
|
+
- "lib/generators/active_record/templates/migration.rb"
|
9
|
+
|
10
|
+
# Disabled checks
|
11
|
+
Style/StringLiterals:
|
12
|
+
Enabled: false
|
13
|
+
|
14
|
+
Layout/SpaceInsideArrayLiteralBrackets:
|
15
|
+
Enabled: false
|
16
|
+
|
17
|
+
Layout/SpaceInsideHashLiteralBraces:
|
18
|
+
Enabled: false
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,47 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
##
|
3
|
+
## v2.0.0
|
4
|
+
|
5
|
+
Bug fixes:
|
6
|
+
- Fixed an issue where Turbo/Hotwire enabled applications return a JS error for failed OTP authentication;
|
7
|
+
- Fixed an issue with the "Remember me" functionality for users with OTP enabled;
|
8
|
+
|
9
|
+
Improvements:
|
10
|
+
- Add support for Lockable strategy to OTP credentials form;
|
11
|
+
- Use locales for "Enabled/Disabled" status;
|
12
|
+
- Fix spelling, spacing, and grammatical issues in the default locales file;
|
13
|
+
|
14
|
+
Code Quality:
|
15
|
+
- Use built-in functionality from rotp gem for handling the TOTP drift window;
|
16
|
+
- Use standard URL Helpers in database\_authenticatable;
|
17
|
+
- Refactor code for otp\_issuer method;
|
18
|
+
- Cleanup Ruby syntax in ERB views;
|
19
|
+
- Add Timecop for testing time based functionality;
|
20
|
+
- Add Rubocop and ERB Lint;
|
21
|
+
|
22
|
+
Maintenance
|
23
|
+
- Bump rqrcode to 3.0.0
|
24
|
+
|
25
|
+
Breaking changes
|
26
|
+
- Move browser persistence actions to dedicated controller
|
27
|
+
- Standardize browser persistence routes, and use buttons for controls
|
28
|
+
|
29
|
+
### Upgrading
|
30
|
+
|
31
|
+
If you have customized the otp_tokens controller/views, or the locales file for browser persistence:
|
32
|
+
1. Regenerate the "otp_tokens" controller and views
|
33
|
+
|
34
|
+
```
|
35
|
+
rails g devise_otp:controllers
|
36
|
+
rails g devise_otp:views
|
37
|
+
```
|
38
|
+
|
39
|
+
2. Reapply any desired changes
|
40
|
+
- Note that the browser persistence controls now use "button_to", rather than "link_to"
|
41
|
+
|
42
|
+
3. Update your locales file
|
43
|
+
- Move any \*\_persistence keys from devise.otp.otp_tokens/ to devise.otp.otp_persistence/
|
44
|
+
|
4
45
|
|
5
46
|
## 1.1.0
|
6
47
|
|
data/Gemfile
CHANGED
@@ -13,4 +13,10 @@ gem "rdoc"
|
|
13
13
|
gem "shoulda"
|
14
14
|
gem "sprockets-rails"
|
15
15
|
gem "sqlite3", "~> 2.1"
|
16
|
-
|
16
|
+
|
17
|
+
# Formatting gems
|
18
|
+
gem "standardrb", require: false
|
19
|
+
gem "rubocop-rails-omakase", require: false
|
20
|
+
gem "erb_lint", require: false
|
21
|
+
|
22
|
+
gem "debug"
|
data/README.md
CHANGED
@@ -88,7 +88,7 @@ The install generator adds some options to the end of your Devise config file (`
|
|
88
88
|
|
89
89
|
* `config.otp_mandatory`: OTP is mandatory, users are going to be asked to enroll the next time they sign in, before they can successfully complete the session establishment.
|
90
90
|
* `config.otp_authentication_timeout`: How long the user has to authenticate with their token. (defaults to `3.minutes`)
|
91
|
-
* `config.otp_drift_window`: A window which provides allowance for drift between a user's token device clock (and therefore their OTP tokens) and the authentication server's clock. Expressed in
|
91
|
+
* `config.otp_drift_window`: A window which provides allowance for drift between a user's token device clock (and therefore their OTP tokens) and the authentication server's clock. Expressed in "steps" of 30 second increments. (default: `3`)
|
92
92
|
* `config.otp_credentials_refresh`: Users that have logged in longer than this time ago, are going to be asked their password (and an OTP challenge, if enabled) before they can see or change their otp informations. (defaults to `15.minutes`)
|
93
93
|
* `config.otp_recovery_tokens`: Whether the users are given a list of one-time recovery tokens, for emergency access (default: `10`, set to `false` to disable)
|
94
94
|
* `config.otp_trust_persistence`: The user is allowed to set his browser as "trusted", no more OTP challenges will be asked for that browser, for a limited time. (default: `1.month`, set to false to disable setting the browser as trusted)
|
@@ -115,6 +115,10 @@ To run the tests for devise-otp against your current Ruby/Rails configuration:
|
|
115
115
|
- Return to the root directory of devise-otp
|
116
116
|
- Run "rake test"
|
117
117
|
|
118
|
+
To check Ruby syntax and formatting:
|
119
|
+
- Rubocop: "./bin/rubocop"
|
120
|
+
- ERB Lint (for views): "./bin/erb\_lint -a --lint-all"
|
121
|
+
|
118
122
|
## Authors
|
119
123
|
|
120
124
|
The project was originally started by Lele Forzani by forking [devise_google_authenticator](https://github.com/AsteriskLabs/devise_google_authenticator) and still contains some devise_google_authenticator code. It's now maintained by [Josef Strzibny](https://github.com/strzibny/) and [Laney Stroup](https://github.com/strouptl).
|
@@ -1,11 +1,13 @@
|
|
1
1
|
module DeviseOtp
|
2
2
|
module Devise
|
3
3
|
class OtpCredentialsController < DeviseController
|
4
|
+
include ::Devise::Controllers::Rememberable
|
4
5
|
helper_method :new_session_path
|
5
6
|
|
6
7
|
prepend_before_action :authenticate_scope!, only: [:get_refresh, :set_refresh]
|
7
8
|
prepend_before_action :require_no_authentication, only: [:show, :update]
|
8
9
|
before_action :set_challenge, only: [:show, :update]
|
10
|
+
before_action :set_remember_me, only: [:show, :update]
|
9
11
|
before_action :set_recovery, only: [:show, :update]
|
10
12
|
before_action :set_resource, only: [:show, :update]
|
11
13
|
before_action :set_token, only: [:update]
|
@@ -26,16 +28,31 @@ module DeviseOtp
|
|
26
28
|
# signs the resource in, if the OTP token is valid and the user has a valid challenge
|
27
29
|
#
|
28
30
|
def update
|
29
|
-
|
31
|
+
# The valid_for_authentication? method must be executed with the validation result as
|
32
|
+
# a block (as the DatabaseAuthenticatable strategy does via the validate method of the
|
33
|
+
# Authenticatable strategy). If true, and the account is not locked, then
|
34
|
+
# authentication will proceed as normal. If false, then the valid_for_authentication?
|
35
|
+
# method will increment the failed attempts and/or lock the account as specified.
|
36
|
+
|
37
|
+
if resource.valid_for_authentication? { resource.validate_otp_token(@token, @recovery) }
|
30
38
|
sign_in(resource_name, resource)
|
31
39
|
|
32
|
-
|
40
|
+
remember_me(resource) if resource.devise_modules.include?(:rememberable) and @remember_me
|
33
41
|
otp_refresh_credentials_for(resource)
|
34
42
|
respond_with resource, location: after_sign_in_path_for(resource)
|
43
|
+
elsif resource.devise_modules.include?(:lockable) and resource.access_locked?
|
44
|
+
otp_set_flash_message :alert, resource.unauthenticated_message, scope: "devise.failure"
|
45
|
+
redirect_to new_session_path(resource_name)
|
35
46
|
else
|
36
|
-
|
37
|
-
|
38
|
-
|
47
|
+
if resource.devise_modules.include?(:lockable) and resource.unauthenticated_message == :last_attempt
|
48
|
+
otp_set_flash_message :alert, :last_attempt, scope: "devise.failure", now: true
|
49
|
+
elsif @token.blank?
|
50
|
+
otp_set_flash_message :alert, :token_blank, now: true
|
51
|
+
else
|
52
|
+
otp_set_flash_message :alert, :token_invalid, now: true
|
53
|
+
end
|
54
|
+
|
55
|
+
render :show, status: :unprocessable_entity
|
39
56
|
end
|
40
57
|
end
|
41
58
|
|
@@ -70,6 +87,10 @@ module DeviseOtp
|
|
70
87
|
end
|
71
88
|
end
|
72
89
|
|
90
|
+
def set_remember_me
|
91
|
+
@remember_me = (params[:remember_me] == "true")
|
92
|
+
end
|
93
|
+
|
73
94
|
def set_recovery
|
74
95
|
@recovery = (recovery_enabled? && params[:recovery] == "true")
|
75
96
|
end
|
@@ -90,6 +111,8 @@ module DeviseOtp
|
|
90
111
|
def skip_challenge_if_trusted_browser
|
91
112
|
if is_otp_trusted_browser_for?(resource)
|
92
113
|
sign_in(resource_name, resource)
|
114
|
+
|
115
|
+
remember_me(resource) if resource.devise_modules.include?(:rememberable) and @remember_me
|
93
116
|
otp_refresh_credentials_for(resource)
|
94
117
|
redirect_to after_sign_in_path_for(resource)
|
95
118
|
end
|
@@ -101,8 +124,8 @@ module DeviseOtp
|
|
101
124
|
end
|
102
125
|
|
103
126
|
def failed_refresh
|
104
|
-
otp_set_flash_message :alert, :invalid_refresh, :
|
105
|
-
render :refresh
|
127
|
+
otp_set_flash_message :alert, :invalid_refresh, now: true
|
128
|
+
render :refresh, status: :unprocessable_entity
|
106
129
|
end
|
107
130
|
|
108
131
|
def self.controller_path
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module DeviseOtp
|
2
|
+
module Devise
|
3
|
+
class OtpPersistenceController < DeviseController
|
4
|
+
include ::Devise::Controllers::Helpers
|
5
|
+
|
6
|
+
prepend_before_action :ensure_credentials_refresh
|
7
|
+
prepend_before_action :authenticate_scope!
|
8
|
+
|
9
|
+
#
|
10
|
+
# makes the current browser persistent
|
11
|
+
#
|
12
|
+
def create
|
13
|
+
if otp_set_trusted_device_for(resource)
|
14
|
+
otp_set_flash_message :success, :successfully_set_persistence
|
15
|
+
end
|
16
|
+
|
17
|
+
redirect_to otp_token_path_for(resource)
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# clears persistence for the current browser
|
22
|
+
#
|
23
|
+
def destroy
|
24
|
+
if otp_clear_trusted_device_for(resource)
|
25
|
+
otp_set_flash_message :success, :successfully_cleared_persistence
|
26
|
+
end
|
27
|
+
|
28
|
+
redirect_to otp_token_path_for(resource)
|
29
|
+
end
|
30
|
+
|
31
|
+
#
|
32
|
+
# rehash the persistence secret, thus, making all the persistence cookies invalid
|
33
|
+
#
|
34
|
+
def reset
|
35
|
+
if otp_reset_persistence_for(resource)
|
36
|
+
otp_set_flash_message :notice, :successfully_reset_persistence
|
37
|
+
end
|
38
|
+
|
39
|
+
redirect_to otp_token_path_for(resource)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def ensure_credentials_refresh
|
45
|
+
ensure_resource!
|
46
|
+
|
47
|
+
if needs_credentials_refresh?(resource)
|
48
|
+
redirect_to refresh_otp_credential_path_for(resource)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -6,8 +6,6 @@ module DeviseOtp
|
|
6
6
|
prepend_before_action :ensure_credentials_refresh
|
7
7
|
prepend_before_action :authenticate_scope!
|
8
8
|
|
9
|
-
protect_from_forgery except: [:clear_persistence, :delete_persistence]
|
10
|
-
|
11
9
|
#
|
12
10
|
# Displays the status of OTP authentication
|
13
11
|
#
|
@@ -35,8 +33,8 @@ module DeviseOtp
|
|
35
33
|
otp_set_flash_message :success, :successfully_updated
|
36
34
|
redirect_to otp_token_path_for(resource)
|
37
35
|
else
|
38
|
-
otp_set_flash_message :danger, :could_not_confirm, :
|
39
|
-
render :edit
|
36
|
+
otp_set_flash_message :danger, :could_not_confirm, now: true
|
37
|
+
render :edit, status: :unprocessable_entity
|
40
38
|
end
|
41
39
|
end
|
42
40
|
|
@@ -51,39 +49,6 @@ module DeviseOtp
|
|
51
49
|
redirect_to otp_token_path_for(resource)
|
52
50
|
end
|
53
51
|
|
54
|
-
#
|
55
|
-
# makes the current browser persistent
|
56
|
-
#
|
57
|
-
def get_persistence
|
58
|
-
if otp_set_trusted_device_for(resource)
|
59
|
-
otp_set_flash_message :success, :successfully_set_persistence
|
60
|
-
end
|
61
|
-
|
62
|
-
redirect_to otp_token_path_for(resource)
|
63
|
-
end
|
64
|
-
|
65
|
-
#
|
66
|
-
# clears persistence for the current browser
|
67
|
-
#
|
68
|
-
def clear_persistence
|
69
|
-
if otp_clear_trusted_device_for(resource)
|
70
|
-
otp_set_flash_message :success, :successfully_cleared_persistence
|
71
|
-
end
|
72
|
-
|
73
|
-
redirect_to otp_token_path_for(resource)
|
74
|
-
end
|
75
|
-
|
76
|
-
#
|
77
|
-
# rehash the persistence secret, thus, making all the persistence cookies invalid
|
78
|
-
#
|
79
|
-
def delete_persistence
|
80
|
-
if otp_reset_persistence_for(resource)
|
81
|
-
otp_set_flash_message :notice, :successfully_reset_persistence
|
82
|
-
end
|
83
|
-
|
84
|
-
redirect_to otp_token_path_for(resource)
|
85
|
-
end
|
86
|
-
|
87
52
|
def recovery
|
88
53
|
respond_to do |format|
|
89
54
|
format.html
|
@@ -1,19 +1,19 @@
|
|
1
|
-
<h2><%=
|
2
|
-
<p><%=
|
1
|
+
<h2><%= t('title', scope: 'devise.otp.credentials_refresh') %></h2>
|
2
|
+
<p><%= t('explain', scope: 'devise.otp.credentials_refresh') %></p>
|
3
3
|
|
4
|
-
<%= form_for(resource, :
|
4
|
+
<%= form_for(resource, as: resource_name, url: [:refresh, resource_name, :otp_credential], html: { method: :put }) do |f| %>
|
5
5
|
|
6
6
|
<%= render "devise/shared/error_messages", resource: resource %>
|
7
7
|
|
8
8
|
<div>
|
9
9
|
<%= f.label :email %><br />
|
10
|
-
<%= f.text_field :email, :
|
10
|
+
<%= f.text_field :email, disabled: true %>
|
11
11
|
</div>
|
12
12
|
|
13
13
|
<div>
|
14
14
|
<%= f.label :password %><br />
|
15
|
-
<%= f.password_field :refresh_password, :
|
15
|
+
<%= f.password_field :refresh_password, autocomplete: :off, autofocus: true %>
|
16
16
|
</div>
|
17
17
|
|
18
|
-
<div><%= f.submit
|
18
|
+
<div><%= f.submit t(:go_on, scope: 'devise.otp.credentials_refresh') %></div>
|
19
19
|
<% end %>
|
@@ -1,31 +1,28 @@
|
|
1
|
-
<h2><%=
|
2
|
-
<p><%=
|
1
|
+
<h2><%= t('title', scope: 'devise.otp.submit_token') %></h2>
|
2
|
+
<p><%= t('explain', scope: 'devise.otp.submit_token') %></p>
|
3
3
|
|
4
|
-
<%= form_for(resource, :
|
4
|
+
<%= form_for(resource, as: resource_name, url: [resource_name, :otp_credential], html: { method: :put }) do |f| %>
|
5
5
|
|
6
6
|
<%= hidden_field_tag :challenge, @challenge %>
|
7
7
|
<%= hidden_field_tag :recovery, @recovery %>
|
8
|
+
<%= hidden_field_tag :remember_me, @remember_me %>
|
8
9
|
|
9
10
|
<% if @recovery %>
|
10
11
|
<p>
|
11
|
-
<%= label_tag :token,
|
12
|
-
<%= text_field_tag :otp_recovery_counter, resource.otp_recovery_counter, :
|
12
|
+
<%= label_tag :token, t('recovery_prompt', scope: 'devise.otp.submit_token') %><br />
|
13
|
+
<%= text_field_tag :otp_recovery_counter, resource.otp_recovery_counter, autocomplete: :off, disabled: true, size: 4 %>
|
13
14
|
</p>
|
14
15
|
<% else %>
|
15
16
|
<p>
|
16
|
-
<%= label_tag :token,
|
17
|
+
<%= label_tag :token, t('prompt', scope: 'devise.otp.submit_token') %><br />
|
17
18
|
</p>
|
18
19
|
<% end %>
|
19
20
|
|
20
|
-
<%= text_field_tag :token, nil, :
|
21
|
+
<%= text_field_tag :token, nil, autocomplete: :off, autofocus: true, size: 6 %><br>
|
21
22
|
|
22
|
-
|
23
|
-
<%= check_box_tag :enable_persistence, true, false %> <%= I18n.t('remember', :scope => 'devise.otp.general') %>
|
24
|
-
<% end %>
|
25
|
-
|
26
|
-
<p><%= f.submit I18n.t('submit', :scope => 'devise.otp.submit_token') %></p>
|
23
|
+
<p><%= f.submit t('submit', scope: 'devise.otp.submit_token') %></p>
|
27
24
|
|
28
25
|
<% if !@recovery && recovery_enabled? %>
|
29
|
-
<p><%= link_to
|
26
|
+
<p><%= link_to t('recovery_link', scope: 'devise.otp.submit_token'), otp_credential_path_for(resource_name, challenge: @challenge, recovery: true) %></p>
|
30
27
|
<% end %>
|
31
28
|
<% end %>
|
@@ -1,22 +1,22 @@
|
|
1
|
-
<h3><%=
|
1
|
+
<h3><%= t('title', scope: 'devise.otp.token_secret') %></h3>
|
2
2
|
|
3
3
|
<%= otp_authenticator_token_image(resource) %>
|
4
4
|
|
5
5
|
<p>
|
6
|
-
<strong><%=
|
6
|
+
<strong><%= t('manual_provisioning', scope: 'devise.otp.token_secret') %>:</strong>
|
7
7
|
<code><%= resource.otp_auth_secret %></code>
|
8
8
|
</p>
|
9
9
|
|
10
|
-
<p><%= button_to
|
10
|
+
<p><%= button_to t('reset_link', scope: 'devise.otp.otp_tokens'), reset_otp_token_path_for(resource), method: :post, data: { turbo_method: :post } %></p>
|
11
11
|
|
12
12
|
<p>
|
13
|
-
<%=
|
14
|
-
<strong><%=
|
13
|
+
<%= t('reset_explain', scope: 'devise.otp.otp_tokens') %>
|
14
|
+
<strong><%= t('reset_explain_warn', scope: 'devise.otp.otp_tokens') %></strong>
|
15
15
|
</p>
|
16
16
|
|
17
17
|
<%- if recovery_enabled? %>
|
18
|
-
<h3><%=
|
19
|
-
<p><%=
|
20
|
-
<p><%= link_to
|
21
|
-
<p><%= link_to
|
18
|
+
<h3><%= t('title', scope: 'devise.otp.otp_tokens.recovery') %></h3>
|
19
|
+
<p><%= t('explain', scope: 'devise.otp.otp_tokens.recovery') %></p>
|
20
|
+
<p><%= link_to t('codes_list', scope: 'devise.otp.otp_tokens.recovery'), recovery_otp_token_for(resource_name) %></p>
|
21
|
+
<p><%= link_to t('download_codes', scope: 'devise.otp.otp_tokens.recovery'), recovery_otp_token_for(resource_name, format: :text) %></p>
|
22
22
|
<% end %>
|
@@ -1,12 +1,12 @@
|
|
1
|
-
<h3><%=
|
2
|
-
<p><%=
|
1
|
+
<h3><%= t('title', scope: 'devise.otp.trusted_browsers') %></h3>
|
2
|
+
<p><%= t('explain', scope: 'devise.otp.trusted_browsers') %></p>
|
3
3
|
|
4
4
|
<%- if is_otp_trusted_browser_for? resource %>
|
5
|
-
<p><em><%=
|
6
|
-
<p><%=
|
5
|
+
<p><em><%= t('browser_trusted', scope: 'devise.otp.trusted_browsers') %></em></p>
|
6
|
+
<p><%= button_to t('trust_remove', scope: 'devise.otp.trusted_browsers'), otp_persistence_path_for(resource_name), method: :delete %></p>
|
7
7
|
<% else %>
|
8
|
-
<p><%=
|
9
|
-
<p><%=
|
8
|
+
<p><%= t('browser_not_trusted', scope: 'devise.otp.trusted_browsers') %></p>
|
9
|
+
<p><%= button_to t('trust_add', scope: 'devise.otp.trusted_browsers'), otp_persistence_path_for(resource_name) %></p>
|
10
10
|
<% end %>
|
11
11
|
|
12
|
-
<p><%= button_to
|
12
|
+
<p><%= button_to t('trust_clear', scope: 'devise.otp.trusted_browsers'), reset_otp_persistence_path_for(resource_name), method: :delete %></p>
|
@@ -1,26 +1,26 @@
|
|
1
|
-
<h2><%=
|
2
|
-
<p><%=
|
1
|
+
<h2><%= t('title', scope: 'devise.otp.edit_otp_token') %></h2>
|
2
|
+
<p><%= t('explain', scope: 'devise.otp.edit_otp_token') %></p>
|
3
3
|
|
4
|
-
<h2><%=
|
4
|
+
<h2><%= t('lead_in', scope: 'devise.otp.edit_otp_token') %></h2>
|
5
5
|
|
6
|
-
<p><%=
|
6
|
+
<p><%= t('step_1', scope: 'devise.otp.edit_otp_token') %></p>
|
7
7
|
|
8
8
|
<%= otp_authenticator_token_image(resource) %>
|
9
9
|
|
10
10
|
<p>
|
11
|
-
<strong><%=
|
11
|
+
<strong><%= t('manual_provisioning', scope: 'devise.otp.token_secret') %>:</strong>
|
12
12
|
<code><%= resource.otp_auth_secret %></code>
|
13
13
|
</p>
|
14
14
|
|
15
|
-
<p><%=
|
15
|
+
<p><%= t('step_2', scope: 'devise.otp.edit_otp_token') %></p>
|
16
16
|
|
17
|
-
<%= form_with(:
|
17
|
+
<%= form_with(url: [resource_name, :otp_token], method: :put) do |f| %>
|
18
18
|
|
19
19
|
<p>
|
20
|
-
<%= f.label :confirmation_code,
|
20
|
+
<%= f.label :confirmation_code, t('confirmation_code', scope: 'devise.otp.edit_otp_token') %>
|
21
21
|
<%= f.text_field :confirmation_code %>
|
22
22
|
</p>
|
23
23
|
|
24
|
-
<p><%= f.submit
|
24
|
+
<p><%= f.submit t('submit', scope: 'devise.otp.edit_otp_token') %></p>
|
25
25
|
|
26
26
|
<% end %>
|
@@ -1,13 +1,13 @@
|
|
1
|
-
<h2><%=
|
2
|
-
<p><%=
|
1
|
+
<h2><%= t('title', scope: 'devise.otp.otp_tokens.recovery') %></h2>
|
2
|
+
<p><%= t('explain', scope: 'devise.otp.otp_tokens.recovery') %></p>
|
3
3
|
|
4
4
|
<table>
|
5
5
|
<caption>
|
6
6
|
<thead>
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
<tr>
|
8
|
+
<th><%= t('sequence', scope: 'devise.otp.otp_tokens.recovery') %></th>
|
9
|
+
<th><%= t('code', scope: 'devise.otp.otp_tokens.recovery') %></th>
|
10
|
+
</tr>
|
11
11
|
</thead>
|
12
12
|
<tbody>
|
13
13
|
<%- resource.next_otp_recovery_tokens.each do |seq, code| %>
|
@@ -1,14 +1,14 @@
|
|
1
|
-
<h2><%=
|
1
|
+
<h2><%= t('title', scope: 'devise.otp.otp_tokens') %></h2>
|
2
2
|
|
3
|
-
<p><strong>Status:</strong> <%= resource.otp_enabled? ?
|
3
|
+
<p><strong>Status:</strong> <%= t(resource.otp_enabled? ? :enabled : :disabled, scope: 'devise.otp.general') %></p>
|
4
4
|
|
5
5
|
<%- if resource.otp_enabled? %>
|
6
|
-
<%= render :
|
7
|
-
<%= render :
|
6
|
+
<%= render partial: 'token_secret' if resource.otp_enabled? %>
|
7
|
+
<%= render partial: 'trusted_devices' if trusted_devices_enabled? %>
|
8
8
|
|
9
9
|
<% unless otp_mandatory_on?(resource) %>
|
10
|
-
<%= button_to
|
10
|
+
<%= button_to t('disable_link', scope: 'devise.otp.otp_tokens'), otp_token_path_for(resource), method: :delete, data: { turbo_method: :delete } %>
|
11
11
|
<% end %>
|
12
12
|
<% else %>
|
13
|
-
<%= link_to
|
13
|
+
<%= link_to t('enable_link', scope: 'devise.otp.otp_tokens'), edit_otp_token_path_for(resource) %>
|
14
14
|
<% end %>
|
data/bin/erb_lint
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'erb_lint' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
12
|
+
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
14
|
+
|
15
|
+
if File.file?(bundle_binstub)
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
17
|
+
load(bundle_binstub)
|
18
|
+
else
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
require "rubygems"
|
25
|
+
require "bundler/setup"
|
26
|
+
|
27
|
+
load Gem.bin_path("erb_lint", "erb_lint")
|
data/bin/rubocop
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'rubocop' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
12
|
+
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
14
|
+
|
15
|
+
if File.file?(bundle_binstub)
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
17
|
+
load(bundle_binstub)
|
18
|
+
else
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
require "rubygems"
|
25
|
+
require "bundler/setup"
|
26
|
+
|
27
|
+
load Gem.bin_path("rubocop", "rubocop")
|