rodauth 1.19.1 → 1.20.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +72 -0
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +100 -7
  5. data/doc/base.rdoc +25 -0
  6. data/doc/email_auth.rdoc +1 -1
  7. data/doc/email_base.rdoc +5 -1
  8. data/doc/internals.rdoc +2 -2
  9. data/doc/jwt_refresh.rdoc +35 -0
  10. data/doc/lockout.rdoc +3 -0
  11. data/doc/login_password_requirements_base.rdoc +4 -1
  12. data/doc/otp.rdoc +22 -39
  13. data/doc/recovery_codes.rdoc +15 -28
  14. data/doc/release_notes/1.20.0.txt +175 -0
  15. data/doc/remember.rdoc +3 -0
  16. data/doc/reset_password.rdoc +2 -1
  17. data/doc/single_session.rdoc +3 -0
  18. data/doc/verify_account.rdoc +4 -3
  19. data/doc/verify_login_change.rdoc +1 -1
  20. data/lib/rodauth.rb +33 -4
  21. data/lib/rodauth/features/base.rb +93 -10
  22. data/lib/rodauth/features/change_login.rb +1 -1
  23. data/lib/rodauth/features/confirm_password.rb +1 -1
  24. data/lib/rodauth/features/create_account.rb +2 -2
  25. data/lib/rodauth/features/disallow_password_reuse.rb +5 -3
  26. data/lib/rodauth/features/email_auth.rb +4 -2
  27. data/lib/rodauth/features/email_base.rb +12 -6
  28. data/lib/rodauth/features/jwt.rb +9 -0
  29. data/lib/rodauth/features/jwt_refresh.rb +142 -0
  30. data/lib/rodauth/features/lockout.rb +8 -4
  31. data/lib/rodauth/features/login_password_requirements_base.rb +1 -0
  32. data/lib/rodauth/features/otp.rb +63 -6
  33. data/lib/rodauth/features/recovery_codes.rb +1 -0
  34. data/lib/rodauth/features/remember.rb +20 -2
  35. data/lib/rodauth/features/reset_password.rb +5 -2
  36. data/lib/rodauth/features/single_session.rb +15 -2
  37. data/lib/rodauth/features/verify_account.rb +11 -6
  38. data/lib/rodauth/features/verify_login_change.rb +5 -3
  39. data/lib/rodauth/version.rb +2 -2
  40. data/spec/disallow_password_reuse_spec.rb +115 -28
  41. data/spec/email_auth_spec.rb +2 -2
  42. data/spec/jwt_refresh_spec.rb +256 -0
  43. data/spec/lockout_spec.rb +4 -4
  44. data/spec/login_spec.rb +52 -11
  45. data/spec/migrate/001_tables.rb +10 -0
  46. data/spec/migrate_travis/001_tables.rb +8 -0
  47. data/spec/remember_spec.rb +27 -0
  48. data/spec/reset_password_spec.rb +2 -2
  49. data/spec/rodauth_spec.rb +25 -1
  50. data/spec/single_session_spec.rb +20 -0
  51. data/spec/spec_helper.rb +29 -0
  52. data/spec/two_factor_spec.rb +57 -3
  53. data/spec/verify_account_spec.rb +18 -1
  54. data/spec/verify_login_change_spec.rb +2 -2
  55. data/templates/add-recovery-codes.str +1 -1
  56. data/templates/change-password.str +2 -2
  57. data/templates/login-confirm-field.str +2 -2
  58. data/templates/login-field.str +2 -2
  59. data/templates/otp-auth-code-field.str +2 -2
  60. data/templates/otp-setup.str +4 -3
  61. data/templates/password-confirm-field.str +2 -2
  62. data/templates/password-field.str +2 -2
  63. data/templates/recovery-auth.str +2 -2
  64. data/templates/reset-password-request.str +1 -1
  65. data/templates/sms-code-field.str +2 -2
  66. data/templates/sms-setup.str +2 -2
  67. data/templates/unlock-account-request.str +1 -1
  68. data/templates/unlock-account.str +1 -1
  69. data/templates/verify-account-resend.str +1 -1
  70. metadata +15 -5
@@ -13,38 +13,27 @@ of them being required due to a missing / lost device.
13
13
 
14
14
  add_recovery_codes_button :: Text to use for button on form to add recovery codes.
15
15
  add_recovery_codes_error_flash :: The flash error to show when adding recovery codes.
16
+ add_recovery_codes_heading :: Text to use for heading above form to add recovery codes.
16
17
  add_recovery_codes_param :: The parameter name to use for adding recovery codes.
17
- add_recovery_auth_redirect :: Where to redirect to add recovery codes if recovery codes
18
- are the primary 2nd factor and have not been setup yet.
19
- invalid_recovery_code_error_flash :: The flash error to show when an invalid recovery
20
- code is used.
21
- invalid_recovery_code_message :: The error message to show when an invalid recovery code
22
- is used.
23
- recovery_auth_additional_form_tags :: HTML fragment containing additional form tags when
24
- authenticating via a recovery code.
18
+ add_recovery_auth_redirect :: Where to redirect to add recovery codes if recovery codes are the primary 2nd factor and have not been setup yet.
19
+ invalid_recovery_code_error_flash :: The flash error to show when an invalid recovery code is used.
20
+ invalid_recovery_code_message :: The error message to show when an invalid recovery code is used.
21
+ recovery_auth_additional_form_tags :: HTML fragment containing additional form tags when authenticating via a recovery code.
25
22
  recovery_auth_button :: The text to use for the button when authenticating via a recovery code.
26
23
  recovery_auth_redirect :: Where to redirect after authenticating via an recovery code.
27
- recovery_auth_route :: The route to the recovery code authentication action.
28
- Defaults to +recovery-auth+.
29
- recovery_codes_added_notice_flash :: The flash notice to show when recovery codes
30
- were added.
31
- recovery_codes_additional_form_tags :: HTML fragment containing additional form tags when
32
- adding recovery codes.
33
- recovery_codes_column :: The column in the recovery_codes_table containing the recovery
34
- code.
35
- recovery_codes_id_column :: The column in the recovery_codes_table containing the
36
- account id.
24
+ recovery_auth_route :: The route to the recovery code authentication action. Defaults to +recovery-auth+.
25
+ recovery_codes_added_notice_flash :: The flash notice to show when recovery codes were added.
26
+ recovery_codes_additional_form_tags :: HTML fragment containing additional form tags when adding recovery codes.
27
+ recovery_codes_column :: The column in the recovery_codes_table containing the recovery code.
28
+ recovery_codes_id_column :: The column in the recovery_codes_table containing the account id.
37
29
  recovery_codes_label :: The label for recovery codes.
38
30
  recovery_codes_limit :: The number of recovery codes to allow.
39
31
  recovery_codes_param :: The parameter name for the recovery code.
40
- recovery_codes_primary? :: Whether recovery codes are the primary second factor, true by
41
- default if neither the otp or sms_codes features are enabled.
42
- recovery_codes_route :: The route to the view recovery codes action. Defaults to
43
- +recovery-codes+.
32
+ recovery_codes_primary? :: Whether recovery codes are the primary second factor, true by default if neither the otp or sms_codes features are enabled.
33
+ recovery_codes_route :: The route to the view recovery codes action. Defaults to +recovery-codes+.
44
34
  recovery_codes_table :: The table storing the recovery codes.
45
35
  view_recovery_codes_button :: Text for the button to view recovery codes.
46
- view_recovery_codes_error_flash :: The flash error to show when viewing recovery codes
47
- was not successful.
36
+ view_recovery_codes_error_flash :: The flash error to show when viewing recovery codes was not successful.
48
37
 
49
38
  == Auth Methods
50
39
 
@@ -59,8 +48,6 @@ before_view_recovery_codes :: Run arbitrary code before viewing recovery codes.
59
48
  can_add_recovery_codes? :: Whether the current account can add more recovery codes.
60
49
  new_recovery_code :: A new recovery code to insert into the recovery codes table.
61
50
  recovery_auth_view :: The HTML to use for the form to authenticate via a recovery code.
62
- recovery_code_match?(code) :: Whether the given code matches any of the existing
63
- recovery_codes.
64
- recovery_codes :: An array containing all valid recovery codes for the current
65
- account.
51
+ recovery_code_match?(code) :: Whether the given code matches any of the existing recovery_codes.
52
+ recovery_codes :: An array containing all valid recovery codes for the current account.
66
53
  recovery_codes_view :: The HTML to use for the form to view recovery codes.
@@ -0,0 +1,175 @@
1
+ = New Features
2
+
3
+ * An hmac_secret configuration method has been added. If set,
4
+ Rodauth will use HMACs for all of the tokens that Rodauth creates.
5
+ By using HMACs for the tokens, even if the database storing the
6
+ tokens is compromised (e.g. via an SQL injection vulnerability), the
7
+ tokens stored in the database will not be usable without knowledge
8
+ of the HMAC secret.
9
+
10
+ The following features are affected by setting the hmac_secret
11
+ configuration method:
12
+
13
+ * email_auth
14
+ * lockout
15
+ * otp
16
+ * remember
17
+ * reset_password
18
+ * single_session
19
+ * verify_account
20
+ * verify_login_change
21
+
22
+ To allow for graceful transition when adding hmac_secret to an
23
+ existing Rodauth installation, you can use the
24
+ allow_raw_email_token? configuration method to keep allowing
25
+ raw tokens. However, you should remove the allow_raw_email_token?
26
+ setting after the existing tokens have expired (most tokens expire
27
+ after 1 day by default). Verify account tokens do not expire,
28
+ but users can request a new verify account token if their token has
29
+ expired.
30
+
31
+ For remember tokens, the raw_remember_token_deadline configuration
32
+ method can be used, which will only allow the use of raw remember
33
+ tokens before the given deadline, which should be the time in the
34
+ future when you want to no longer accept raw remember tokens. You
35
+ can remove this configuration method after the deadline has passed.
36
+ By default, the deadline should be set to 14 days after the time
37
+ you enable hmac_secret, since remember tokens expire in 14 days by
38
+ default.
39
+
40
+ Similarly, in the single_session feature, you can use the
41
+ allow_raw_single_session_key? configuration method to allow raw
42
+ single session keys.
43
+
44
+ In the otp feature, you cannot mix HMAC and non-HMAC tokens. If
45
+ the hmac_secret setting is enabled and there are any existing
46
+ otp tokens already setup, they will stop working. If you are
47
+ already using the otp feature and would like to use the hmac_secret
48
+ configuration method, you need to set the otp_keys_use_hmac?
49
+ configuration method to false unless you want to invalidate all
50
+ existing otp tokens.
51
+
52
+ The hmac_secret configuration is also used during OTP setup
53
+ in the otp feature, to ensure that the OTP secrets for two factor
54
+ authentication came from the server and were not modified by the
55
+ user. If hmac_secret is used, setting up OTP via JSON requires
56
+ sending a POST request to the otp-setup route. This request will
57
+ fail, but included in the response will be the OTP secret and raw
58
+ OTP secret to use. Submitting a POST request including the OTP
59
+ secret and raw OTP secret will allow OTP setup to complete.
60
+
61
+ * A jwt_refresh feature has been added. This uses the jwt feature,
62
+ and issuing short-lived JWTs with exp, iat, and nbf claims, with a
63
+ database-backed refresh token for issuing another short-lived JWT.
64
+ The refresh tokens will automatically use HMACs if the hmac_secret
65
+ configuration method is set.
66
+
67
+ * Rodauth's handling of form errors is now accessible by default.
68
+ aria-invalid attributes are now used on all input fields with
69
+ errors, and aria-describedby attributes are used to tie the input
70
+ fields to the error messages.
71
+
72
+ * All hard coded strings are now overridable via configuration
73
+ methods, with the following configuration methods added:
74
+
75
+ * lockout feature
76
+ * unlock_account_explanatory_text
77
+ * unlock_account_request_explanatory_text
78
+ * login_password_requirements_base feature
79
+ * already_an_account_with_this_login_message
80
+ * otp feature
81
+ * otp_provisioning_uri_label
82
+ * otp_secret_label
83
+ * recovery_codes feature
84
+ * add_recovery_codes_heading
85
+ * reset_password feature
86
+ * reset_password_explanatory_text
87
+ * verify_account feature
88
+ * verify_account_resend_explanatory_text
89
+
90
+ * The following configuration methods have been added to the base
91
+ feature, related to customization of input fields in Rodauth forms:
92
+
93
+ default_field_attributes :: The default attributes to use for input
94
+ field tags, if field_attributes does not
95
+ handle the field.
96
+ field_attributes(field) :: The attributes to use for input fields
97
+ with the given parameter name.
98
+ field_error_attributes(field) :: The attributes to use for input
99
+ fields with the given parameter
100
+ name if the field has an error.
101
+ formatted_field_error(field, error) :: HTML to use for the given
102
+ parameter name and error
103
+ text. Uses a span by
104
+ default.
105
+ input_field_error_class :: The CSS class to add for input fields
106
+ with errors.
107
+ input_field_error_message_class :: The CSS class to add for error
108
+ message spans.
109
+ input_field_label_suffix :: Adds suffix to all input field labels
110
+ login_input_type :: The input type to use for login fields.
111
+ Defaults to text, but can be set to email,
112
+ though that is currently a bad idea if you
113
+ want the login fields to have accessible error
114
+ handling.
115
+ mark_input_fields_as_required? :: Whether to mark all input fields
116
+ as required by default. Note that
117
+ this is currently a bad idea if
118
+ you want the fields to have
119
+ accessible error handling.
120
+
121
+ = Other Improvements
122
+
123
+ * rotp 5 is now supported in the otp feature. Previous rotp versions
124
+ down to rotp 2.1.1 remain supported.
125
+
126
+ * Performance of Rodauth routes has been improved by using defined
127
+ methods instead of instance_exec for route dispatching. Internal
128
+ unnecessary uses of instance_exec have also been removed for
129
+ performance reasons.
130
+
131
+ * When the disallow_password_reuse feature is used without the
132
+ verify_account feature, and account_password_hash_column
133
+ configuration is not used, Rodauth no longer tries to call a method
134
+ that does not exist.
135
+
136
+ * When using the disallow_password_reuse and verify_account features,
137
+ with verify_account_set_password? set to true, Rodauth skips adding
138
+ an empty password to the list of previous passwords.
139
+
140
+ * Rodauth now avoids an unnecessary DELETE query in the
141
+ disallow_password_reuse feature if there are no previous passwords.
142
+
143
+ * The otp-auth-code field now has an autocomplete=off attribute.
144
+
145
+ * On Ruby 1.8, new tokens now use URL safe base64 encoding, instead
146
+ of hex encoding. Rodauth has always used URL safe base64 encoding
147
+ for new tokens on Ruby 1.9+.
148
+
149
+ = Backwards Compatibility
150
+
151
+ * The following configuration methods have been renamed:
152
+
153
+ * email_auth feature
154
+ * no_matching_email_auth_key_message =>
155
+ no_matching_email_auth_key_error_flash
156
+ * lockout feature
157
+ * no_matching_unlock_account_key_message =>
158
+ no_matching_unlock_account_key_error_flash
159
+ * reset_password feature
160
+ * no_matching_reset_password_key_message =>
161
+ no_matching_reset_password_key_error_flash
162
+ * verify_account feature
163
+ * attempt_to_create_unverified_account_notice_message =>
164
+ attempt_to_create_unverified_account_error_flash
165
+ * attempt_to_login_to_unverified_account_notice_message =>
166
+ attempt_to_login_to_unverified_account_error_flash
167
+ * no_matching_verify_account_key_message =>
168
+ no_matching_verify_account_key_error_flash
169
+ * verify_login_change feature
170
+ * no_matching_verify_login_change_key_message =>
171
+ no_matching_verify_login_change_key_error_flash
172
+
173
+ Attempts to use the old method at configuration time, or calling
174
+ the method on the rodauth object at runtime, will result in a
175
+ deprecation warning.
data/doc/remember.rdoc CHANGED
@@ -23,6 +23,9 @@ remembering on login, you can do that via:
23
23
 
24
24
  extend_remember_deadline? :: Whether to extend the remember token deadline
25
25
  when the user is autologged in via token.
26
+ raw_remember_token_deadline :: A deadline before which to allow a raw remember
27
+ token to be used. Allows for graceful transition
28
+ for when +hmac_secret+ is first set.
26
29
  remember_additional_form_tags :: HTML fragment containing additional
27
30
  form tags to use on the change remember
28
31
  setting form.
@@ -8,7 +8,7 @@ the login feature.
8
8
 
9
9
  == Auth Value Methods
10
10
 
11
- no_matching_reset_password_key_message :: The flash error message to show if attempting to access the reset password form with an invalid key.
11
+ no_matching_reset_password_key_error_flash :: The flash error message to show if attempting to access the reset password form with an invalid key.
12
12
  reset_password_additional_form_tags :: HTML fragment containing additional form tags to use on the reset password form.
13
13
  reset_password_autologin? :: Whether to autologin the user after successfully resetting a password.
14
14
  reset_password_button :: The text to use for the reset password button.
@@ -21,6 +21,7 @@ reset_password_email_sent_redirect :: Where to redirect after sending a reset pa
21
21
  reset_password_email_subject :: The subject to use for reset password emails.
22
22
  reset_password_error_flash :: The flash error to show after resetting a password.
23
23
  reset_password_email_last_sent_column :: The email last sent column in the reset password keys table. nil by default, so a reset password email is always sent when requested by default.
24
+ reset_password_explanatory_text :: The text to display above the button to request a password reset.
24
25
  reset_password_id_column :: The id column in the reset password keys table, should be a foreign key referencing the accounts table.
25
26
  reset_password_key_column :: The reset password key/token column in the reset password keys table.
26
27
  reset_password_key_param :: The parameter name to use for the reset password key.
@@ -18,6 +18,9 @@ the previous session after logout no longer work.
18
18
 
19
19
  == Auth Value Methods
20
20
 
21
+ allow_raw_single_session_key? :: Whether to allow a raw single session key to
22
+ be accepted, should only be enabled for graceful
23
+ transition when +hmac_secret+ is first set.
21
24
  single_session_id_column :: The column in the +single_session_table+ containing
22
25
  the account id.
23
26
  single_session_key_column :: The column in the +single_session_table+ containing
@@ -7,9 +7,9 @@ after verifying the account. Depends on the login and create account features.
7
7
 
8
8
  == Auth Value Methods
9
9
 
10
- attempt_to_create_unverified_account_notice_message :: Message displayed when attempting to create an account awaiting verification.
11
- attempt_to_login_to_unverified_account_notice_message :: Message displayed when attempting to login to an account awaiting verification.
12
- no_matching_verify_account_key_message :: The flash error message to show when an invalid verify account key is used.
10
+ attempt_to_create_unverified_account_error_flash :: The flash error message to show when attempting to create an account awaiting verification.
11
+ attempt_to_login_to_unverified_account_error_flash :: The flash error message to show when attempting to login to an account awaiting verification.
12
+ no_matching_verify_account_key_error_flash :: The flash error message to show when an invalid verify account key is used.
13
13
  verify_account_additional_form_tags :: HTML fragment containing additional form tags to use on the verify account form.
14
14
  verify_account_autologin? :: Whether to autologin the user after successful account verification, true by default.
15
15
  verify_account_button :: The text to use for the verify account button.
@@ -28,6 +28,7 @@ verify_account_resend_additional_form_tags :: HTML fragment containing additiona
28
28
  verify_account_resend_button :: The text to use for the verify account resend button.
29
29
  verify_account_redirect :: Where to redirect after verifying the account.
30
30
  verify_account_resend_error_flash :: The flash error to show if unable to resend a verify account email.
31
+ verify_account_resend_explanatory_text :: The text to display above the button to resend the verify account email.
31
32
  verify_account_resend_link :: The HTML to use for a link to the page to request the account verification email be resent.
32
33
  verify_account_resend_route :: The route to the verify account resend action. Defaults to +verify-account-resend+.
33
34
  verify_account_route :: The route to the verify account action. Defaults to +verify-account+.
@@ -13,7 +13,7 @@ control. Depends on the change login and email base features.
13
13
 
14
14
  == Auth Value Methods
15
15
 
16
- no_matching_verify_login_change_key_message :: The flash error message to show when an invalid verify login change key is used.
16
+ no_matching_verify_login_change_key_error_flash :: The flash error message to show when an invalid verify login change key is used.
17
17
  verify_login_change_additional_form_tags :: HTML fragment containing additional form tags to use on the verify login change form.
18
18
  verify_login_change_autologin? :: Whether to autologin the user after successful login change verification, false by default.
19
19
  verify_login_change_button :: The text to use for the verify login change button.
data/lib/rodauth.rb CHANGED
@@ -18,11 +18,11 @@ module Rodauth
18
18
  when false
19
19
  # nothing
20
20
  when :route_csrf
21
- # :nocov:
22
21
  app.plugin :route_csrf
23
- # :nocov:
24
22
  else
23
+ # :nocov:
25
24
  app.plugin :csrf
25
+ # :nocov:
26
26
  end
27
27
 
28
28
  app.plugin :flash unless opts[:flash] == false
@@ -103,14 +103,23 @@ module Rodauth
103
103
  def route(name=feature_name, default=name.to_s.tr('_', '-'), &block)
104
104
  auth_value_method "#{name}_route", default
105
105
 
106
- handle_meth = "handle_#{name}"
106
+ handle_meth = :"handle_#{name}"
107
+ internal_handle_meth = :"_#{handle_meth}"
107
108
  route_meth = :"#{name}_route"
108
109
  before route_meth
109
110
 
111
+ unless block.arity == 1
112
+ # :nocov:
113
+ b = block
114
+ block = lambda{|r| instance_exec(r, &b)}
115
+ # :nocov:
116
+ end
117
+ define_method(internal_handle_meth, &block)
118
+
110
119
  define_method(handle_meth) do
111
120
  request.is send(route_meth) do
112
121
  before_rodauth
113
- instance_exec(request, &block)
122
+ send(internal_handle_meth, request)
114
123
  end
115
124
  end
116
125
 
@@ -138,6 +147,26 @@ module Rodauth
138
147
  configuration.module_eval(&block)
139
148
  end
140
149
 
150
+ if RUBY_VERSION >= '2.5'
151
+ DEPRECATED_ARGS = [{:uplevel=>1}]
152
+ else
153
+ # :nocov:
154
+ DEPRECATED_ARGS = []
155
+ # :nocov:
156
+ end
157
+ def def_deprecated_alias(new, old)
158
+ configuration_module_eval do
159
+ define_method(old) do |*a, &block|
160
+ warn("Deprecated #{old} method used during configuration, switch to using #{new}", *DEPRECATED_ARGS)
161
+ send(new, *a, &block)
162
+ end
163
+ end
164
+ define_method(old) do
165
+ warn("Deprecated #{old} method called at runtime, switch to using #{new}", *DEPRECATED_ARGS)
166
+ send(new)
167
+ end
168
+ end
169
+
141
170
  DEFAULT_REDIRECT_BLOCK = proc{default_redirect}
142
171
  def redirect(name=feature_name, &block)
143
172
  meth = :"#{name}_redirect"
@@ -21,6 +21,10 @@ module Rodauth
21
21
  auth_value_method :default_redirect, '/'
22
22
  session_key :flash_error_key, :error
23
23
  session_key :flash_notice_key, :notice
24
+ auth_value_method :hmac_secret, nil
25
+ auth_value_method :input_field_label_suffix, ''
26
+ auth_value_method :input_field_error_class, 'error'
27
+ auth_value_method :input_field_error_message_class, 'error_message'
24
28
  auth_value_method :invalid_field_error_status, 422
25
29
  auth_value_method :invalid_key_error_status, 401
26
30
  auth_value_method :invalid_password_error_status, 401
@@ -35,15 +39,18 @@ module Rodauth
35
39
  auth_value_method :no_matching_login_message, "no matching login"
36
40
  auth_value_method :login_param, 'login'
37
41
  auth_value_method :login_label, 'Login'
42
+ auth_value_method :login_input_type, 'text'
38
43
  auth_value_method :password_label, 'Password'
39
44
  auth_value_method :password_param, 'password'
40
45
  auth_value_method :modifications_require_password?, true
41
46
  session_key :session_key, :account_id
42
47
  auth_value_method :prefix, ''
43
48
  auth_value_method :require_bcrypt?, true
49
+ auth_value_method :mark_input_fields_as_required?, false
44
50
  auth_value_method :skip_status_checks?, true
45
51
  auth_value_method :template_opts, {}
46
52
  auth_value_method :title_instance_variable, nil
53
+ auth_value_method :token_separator, "_"
47
54
  auth_value_method :unmatched_field_error_status, 422
48
55
  auth_value_method :unopen_account_error_status, 403
49
56
  auth_value_method :unverified_account_message, "unverified account, please verify account before logging in"
@@ -52,6 +59,7 @@ module Rodauth
52
59
 
53
60
  auth_value_methods(
54
61
  :db,
62
+ :default_field_attributes,
55
63
  :set_deadline_values?,
56
64
  :use_date_arithmetic?,
57
65
  :use_database_authentication_functions?,
@@ -84,7 +92,10 @@ module Rodauth
84
92
 
85
93
  auth_private_methods(
86
94
  :account_from_login,
87
- :account_from_session
95
+ :account_from_session,
96
+ :field_attributes,
97
+ :field_error_attributes,
98
+ :formatted_field_error
88
99
  )
89
100
 
90
101
  configuration_module_eval do
@@ -144,6 +155,51 @@ module Rodauth
144
155
  @field_errors[field]
145
156
  end
146
157
 
158
+ def add_field_error_class(field)
159
+ if field_error(field)
160
+ " #{input_field_error_class}"
161
+ end
162
+ end
163
+
164
+ def input_field_string(param, id, opts={})
165
+ type = opts.fetch(:type, "text")
166
+
167
+ unless type == "password"
168
+ value = opts.fetch(:value){scope.h param(param)}
169
+ end
170
+
171
+ "<input #{opts[:attr]} #{field_attributes(param)} #{field_error_attributes(param)} type=\"#{type}\" class=\"form-control#{add_field_error_class(param)}\" name=\"#{param}\" id=\"#{id}\" value=\"#{value}\"/> #{formatted_field_error(param)}"
172
+ end
173
+
174
+ def default_field_attributes
175
+ if mark_input_fields_as_required?
176
+ "required=\"required\""
177
+ end
178
+ end
179
+
180
+ def field_attributes(field)
181
+ _field_attributes(field) || default_field_attributes
182
+ end
183
+
184
+ def field_error_attributes(field)
185
+ if field_error(field)
186
+ _field_error_attributes(field)
187
+ end
188
+ end
189
+
190
+ def formatted_field_error(field)
191
+ if error = field_error(field)
192
+ _formatted_field_error(field, error)
193
+ end
194
+ end
195
+
196
+ # Return urlsafe base64 HMAC for data, assumes hmac_secret is set.
197
+ def compute_hmac(data)
198
+ s = [compute_raw_hmac(data)].pack('m').chomp!("=\n")
199
+ s.tr!('+/', '-_')
200
+ s
201
+ end
202
+
147
203
  def account_id
148
204
  account[account_id_column]
149
205
  end
@@ -241,11 +297,11 @@ module Rodauth
241
297
  return unless scope.respond_to?(:csrf_tag)
242
298
 
243
299
  if use_request_specific_csrf_tokens?
244
- # :nocov:
245
300
  scope.csrf_tag(path)
246
- # :nocov:
247
301
  else
302
+ # :nocov:
248
303
  scope.csrf_tag
304
+ # :nocov:
249
305
  end
250
306
  end
251
307
 
@@ -315,6 +371,18 @@ module Rodauth
315
371
 
316
372
  private
317
373
 
374
+ def convert_token_key(key)
375
+ if key && hmac_secret
376
+ compute_hmac(key)
377
+ else
378
+ key
379
+ end
380
+ end
381
+
382
+ def split_token(token)
383
+ token.split(token_separator, 2)
384
+ end
385
+
318
386
  def redirect(path)
319
387
  request.redirect(path)
320
388
  end
@@ -330,7 +398,9 @@ module Rodauth
330
398
  else
331
399
  # :nocov:
332
400
  def random_key
333
- SecureRandom.hex(32)
401
+ s = [SecureRandom.random_bytes(32)].pack('m').chomp!("=\n")
402
+ s.tr!('+/', '-_')
403
+ s
334
404
  end
335
405
  # :nocov:
336
406
  end
@@ -438,6 +508,22 @@ module Rodauth
438
508
  ds.first
439
509
  end
440
510
 
511
+ def compute_raw_hmac(data)
512
+ OpenSSL::HMAC.digest(OpenSSL::Digest::SHA256.new, hmac_secret, data)
513
+ end
514
+
515
+ def _field_attributes(field)
516
+ nil
517
+ end
518
+
519
+ def _field_error_attributes(field)
520
+ " aria-invalid=\"true\" aria-describedby=\"#{field}_error_message\" "
521
+ end
522
+
523
+ def _formatted_field_error(field, error)
524
+ "<span class=\"#{input_field_error_message_class}\" id=\"#{field}_error_message\">#{error}</span>"
525
+ end
526
+
441
527
  def account_session_status_filter
442
528
  {account_status_column=>account_open_status_value}
443
529
  end
@@ -536,18 +622,15 @@ module Rodauth
536
622
  end
537
623
 
538
624
  def _view_opts(page)
539
- auth_template_path = template_path(page)
540
625
  opts = template_opts.dup
541
626
  opts[:locals] = opts[:locals] ? opts[:locals].dup : {}
542
627
  opts[:locals][:rodauth] = self
543
628
  opts[:cache] = cache_templates
544
629
  opts[:cache_key] = :"rodauth_#{page}"
545
630
 
546
- scope.instance_exec do
547
- opts = find_template(parse_template_opts(page, opts))
548
- unless File.file?(template_path(opts))
549
- opts[:path] = auth_template_path
550
- end
631
+ opts = scope.send(:find_template, scope.send(:parse_template_opts, page, opts))
632
+ unless File.file?(scope.send(:template_path, opts))
633
+ opts[:path] = template_path(page)
551
634
  end
552
635
 
553
636
  opts