rodauth 2.26.1 → 2.27.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f30e5f8dc756435bee2a6956764516d6697434f507e3226562659807a02b2f0a
4
- data.tar.gz: 71738c31b50b8f82f351eabf0743eb3439cf7519782a10483d16a32a3d0b709b
3
+ metadata.gz: eeb08d35b1a9cf7c0a5393bbcf831d41fa0ff1a9d822761ef63c149723d79db2
4
+ data.tar.gz: 8a890d1659b1a0634960420ab0546db1e76363dad7c43dc01a0b05dfe4cc85e3
5
5
  SHA512:
6
- metadata.gz: 7b28515139d2894a9a6164e6ef6f95aebe33b8be4b54548bb4d5c616dd380c7eeb7ff9470c1ac8dc044bbcafb373b596324286f48c860375ed3e1b85aebb6b84
7
- data.tar.gz: 20445419c0e2af068dc3141976cda754e71bfcd96204c1f97215e81764afe4376a58f03cbd6d53c524364e3b56e4ae20ff34904b876a4dcc7beb89254e698b80
6
+ metadata.gz: 1e27b99b1fa245aab6c600257fc82fcae6789d31105047d06d39eae185064d08917359ba8eb631b94dcfa7aa6a05be77e700a8935070b8467bcac25bbd3e2cb1
7
+ data.tar.gz: 71bfbebd641cc594889fa4d82086a17b250388796990d24b8240acb6e668fe41b52f9b1727b4b8b49846cc13574b398da0ae7c4f092436d027a4719df96f0e75
data/CHANGELOG CHANGED
@@ -1,3 +1,13 @@
1
+ === 2.27.0 (2023-01-24)
2
+
3
+ * Rename webauth_credentials_for_get to webauthn_credentials_for_get for consistency (janko) (#295)
4
+
5
+ * Hide WebAuthn text inputs by default when using Bootstrap (janko) (#294)
6
+
7
+ * Attempt to avoid database errors when invalid tokens are submitted (jeremyevans)
8
+
9
+ * Allow button template to be overridden just as other templates can be (jeremyevans) (#280)
10
+
1
11
  === 2.26.1 (2022-11-08)
2
12
 
3
13
  * Fix regression in QR code generation in otp feature causing all black QR code (janko) (#279)
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2015-2021 Jeremy Evans
1
+ Copyright (c) 2015-2023 Jeremy Evans
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to
data/doc/base.rdoc CHANGED
@@ -35,6 +35,7 @@ cache_templates :: Whether to cache templates. True by default. It may be worth
35
35
  check_csrf? :: Whether Rodauth should use Roda's +check_csrf!+ method for checking CSRF tokens before dispatching to Rodauth routes, true by default.
36
36
  check_csrf_opts :: Options to pass to Roda's +check_csrf!+ if Rodauth calls it before dispatching.
37
37
  check_csrf_block :: Proc for block to pass to Roda's +check_csrf!+ if Rodauth calls it before dispatching.
38
+ convert_token_id_to_integer? :: Whether token ids should be converted to a valid 64-bit integer value. If not set, defaults to true if +account_id_column+ uses an integer type, and false otherwise.
38
39
  default_field_attributes :: The default attributes to use for input field tags, if field_attributes returns nil for the field.
39
40
  default_redirect :: Where to redirect after most successful actions.
40
41
  field_attributes(field) :: The attributes to use for the input field tags for the given field (parameter name).
@@ -96,6 +97,7 @@ before_login_attempt :: Run arbitrary code after an account has been located, bu
96
97
  before_rodauth :: Run arbitrary code before handling any rodauth route, but after CSRF checks if Rodauth is doing CSRF checks.
97
98
  check_csrf :: Checks CSRF token using Roda's +check_csrf!+ method.
98
99
  clear_session :: Clears the current session.
100
+ convert_token_id(id) :: Convert the token id string to an appropriate object to use for the token id (or return +nil+ to signal an invalid token id). By default, converts to a 64-bit signed integer if +convert_token_id_to_integer?+ is true.
99
101
  csrf_tag(path=request.path) :: The HTML fragment containing the CSRF tag to use, if any.
100
102
  function_name(name) :: The name of the database function to call. It's passed either :rodauth_get_salt or :rodauth_valid_password_hash.
101
103
  logged_in? :: Whether the current session is logged in.
@@ -0,0 +1,35 @@
1
+ = Improvements
2
+
3
+ * Token ids submitting in requests are now converted to integers if
4
+ the configuration uses an integer primary key for the accounts
5
+ table. If the configuration uses a non-integer primary key for
6
+ the accounts table, the convert_token_id configuration method can
7
+ be used, which should return the token id converted to the
8
+ appropriate type, or nil if the token id is not valid for the type.
9
+
10
+ This revised handling avoids raising a database error when an
11
+ invalid token is submitted.
12
+
13
+ * The button template can now be overridden in the same way that
14
+ other Rodauth templates can be overridden.
15
+
16
+ * When using the Bootstrap CSS framework, the text field in the
17
+ Webauthn setup and auth forms is automatically hidden. The text
18
+ field already had a rodauth-hidden class to make it easy to hide
19
+ when using other CSS frameworks.
20
+
21
+ * The email_from and email_to methods are now public instead of
22
+ private.
23
+
24
+ * A nicer error is raised if the Sequel Database object is missing.
25
+
26
+ * A regression in the TOTP QR output that resulted in the QR codes
27
+ being solid black squares has been fixed (this was fixed in
28
+ Rodauth 2.26.1).
29
+
30
+ = Backwards Compatibility
31
+
32
+ * The webauth_credentials_for_get method in the webauthn feature has
33
+ been renamed to webauthn_credentials_for_get for consistency with
34
+ other methods. The webauth_credentials_for_get method will still
35
+ work until Rodauth 3, but will issue deprecation warnings.
data/doc/webauthn.rdoc CHANGED
@@ -104,7 +104,7 @@ remove_all_webauthn_keys_and_user_ids :: Remove all WebAuthn credentials and the
104
104
  remove_webauthn_key(webauthn_id) :: Remove the WebAuthn credential with the given WebAuthn ID from the current account.
105
105
  valid_new_webauthn_credential?(webauthn_credential) :: Check wheck the WebAuthn credential provided by the client during registration is valid.
106
106
  valid_webauthn_credential_auth?(webauthn_credential) :: Check wheck the WebAuthn credential provided by the client during authentication is valid.
107
- webauth_credential_options_for_get :: WebAuthn credential options to provide to the client during WebAuthn authentication.
107
+ webauthn_credential_options_for_get :: WebAuthn credential options to provide to the client during WebAuthn authentication.
108
108
  webauthn_auth_js_path :: The path to the WebAuthn authentication javascript.
109
109
  webauthn_auth_view :: The HTML to use for the page for authenticating via WebAuthn.
110
110
  webauthn_remove_authenticated_session :: Remove the authenticated WebAuthn ID, used when removing the WebAuthn credential with the ID after authenticating with it.
@@ -24,6 +24,7 @@ module Rodauth
24
24
  auth_value_method :check_csrf_block, nil
25
25
  auth_value_method :check_csrf_opts, {}.freeze
26
26
  auth_value_method :default_redirect, '/'
27
+ auth_value_method :convert_token_id_to_integer?, nil
27
28
  flash_key :flash_error_key, :error
28
29
  flash_key :flash_notice_key, :notice
29
30
  auth_value_method :hmac_secret, nil
@@ -115,6 +116,7 @@ module Rodauth
115
116
  auth_private_methods(
116
117
  :account_from_login,
117
118
  :account_from_session,
119
+ :convert_token_id,
118
120
  :field_attributes,
119
121
  :field_error_attributes,
120
122
  :formatted_field_error,
@@ -264,7 +266,7 @@ module Rodauth
264
266
  end
265
267
 
266
268
  def db
267
- Sequel::DATABASES.first
269
+ Sequel::DATABASES.first or raise "Sequel database connection is missing"
268
270
  end
269
271
 
270
272
  def password_field_autocomplete_value
@@ -376,10 +378,9 @@ module Rodauth
376
378
  def button_opts(value, opts)
377
379
  opts = Hash[template_opts].merge!(opts)
378
380
  opts[:locals] = {:value=>value, :opts=>opts}
379
- opts[:path] = template_path('button')
380
381
  opts[:cache] = cache_templates
381
382
  opts[:cache_key] = :rodauth_button
382
- opts
383
+ _template_opts(opts, 'button')
383
384
  end
384
385
 
385
386
  def button(value, opts={})
@@ -402,6 +403,11 @@ module Rodauth
402
403
  def post_configure
403
404
  require 'bcrypt' if require_bcrypt?
404
405
  db.extension :date_arithmetic if use_date_arithmetic?
406
+
407
+ if convert_token_id_to_integer?.nil? && (db rescue false) && db.table_exists?(accounts_table) && db.schema(accounts_table).find{|col, v| break v[:type] == :integer if col == account_id_column}
408
+ self.class.send(:define_method, :convert_token_id_to_integer?){true}
409
+ end
410
+
405
411
  route_hash= {}
406
412
  self.class.routes.each do |meth|
407
413
  route_meth = "#{meth.to_s.sub(/\Ahandle_/, '')}_route"
@@ -521,6 +527,25 @@ module Rodauth
521
527
  token.split(token_separator, 2)
522
528
  end
523
529
 
530
+ def convert_token_id(id)
531
+ if convert_token_id_to_integer?
532
+ convert_token_id_to_integer(id)
533
+ else
534
+ id
535
+ end
536
+ end
537
+
538
+ def convert_token_id_to_integer(id)
539
+ if id = (Integer(id, 10) rescue nil)
540
+ if id > 9223372036854775807 || id < -9223372036854775808
541
+ # Only allow 64-bit signed integer range to avoid problems on PostgreSQL
542
+ id = nil
543
+ end
544
+ end
545
+
546
+ id
547
+ end
548
+
524
549
  def redirect(path)
525
550
  request.redirect(path)
526
551
  end
@@ -817,12 +842,16 @@ module Rodauth
817
842
  opts[:locals][:rodauth] = self
818
843
  opts[:cache] = cache_templates
819
844
  opts[:cache_key] = :"rodauth_#{page}"
845
+ _template_opts(opts, page)
846
+ end
820
847
 
848
+ # Set the template path only if there isn't an overridden template in the application.
849
+ # Result should replace existing template opts.
850
+ def _template_opts(opts, page)
821
851
  opts = scope.send(:find_template, scope.send(:parse_template_opts, page, opts))
822
852
  unless File.file?(scope.send(:template_path, opts))
823
853
  opts[:path] = template_path(page)
824
854
  end
825
-
826
855
  opts
827
856
  end
828
857
 
@@ -23,6 +23,14 @@ module Rodauth
23
23
  require 'mail' if require_mail?
24
24
  end
25
25
 
26
+ def email_from
27
+ "webmaster@#{domain}"
28
+ end
29
+
30
+ def email_to
31
+ account[login_column]
32
+ end
33
+
26
34
  private
27
35
 
28
36
  def send_email(email)
@@ -42,14 +50,6 @@ module Rodauth
42
50
  m
43
51
  end
44
52
 
45
- def email_from
46
- "webmaster@#{domain}"
47
- end
48
-
49
- def email_to
50
- account[login_column]
51
- end
52
-
53
53
  def token_link(route, param, key)
54
54
  route_url(route, param => token_param_value(key))
55
55
  end
@@ -64,6 +64,7 @@ module Rodauth
64
64
 
65
65
  def account_from_key(token, status_id=nil)
66
66
  id, key = split_token(token)
67
+ id = convert_token_id(id)
67
68
  return unless id && key
68
69
 
69
70
  return unless actual = yield(id)
@@ -107,7 +107,7 @@ module Rodauth
107
107
  def before_webauthn_auth_route
108
108
  super if defined?(super)
109
109
  if use_json? && !param_or_nil(webauthn_auth_param)
110
- cred = webauth_credential_options_for_get
110
+ cred = webauthn_credential_options_for_get
111
111
  json_response[webauthn_auth_param] = cred.as_json
112
112
  json_response[webauthn_auth_challenge_param] = cred.challenge
113
113
  json_response[webauthn_auth_challenge_hmac_param] = compute_hmac(cred.challenge)
@@ -117,7 +117,7 @@ module Rodauth
117
117
  def before_webauthn_login_route
118
118
  super if defined?(super)
119
119
  if use_json? && !param_or_nil(webauthn_auth_param) && account_from_login(param(login_param))
120
- cred = webauth_credential_options_for_get
120
+ cred = webauthn_credential_options_for_get
121
121
  json_response[webauthn_auth_param] = cred.as_json
122
122
  json_response[webauthn_auth_challenge_param] = cred.challenge
123
123
  json_response[webauthn_auth_challenge_hmac_param] = compute_hmac(cred.challenge)
@@ -112,7 +112,7 @@ module Rodauth
112
112
  id, token_id, key = _account_refresh_token_split(token)
113
113
 
114
114
  unless key &&
115
- (id == session_value.to_s) &&
115
+ (id.to_s == session_value.to_s) &&
116
116
  (actual = get_active_refresh_token(id, token_id)) &&
117
117
  timing_safe_eql?(key, convert_token_key(actual)) &&
118
118
  jwt_refresh_token_match?(key)
@@ -126,9 +126,11 @@ module Rodauth
126
126
 
127
127
  def _account_refresh_token_split(token)
128
128
  id, token = split_token(token)
129
+ id = convert_token_id(id)
129
130
  return unless id && token
130
131
 
131
132
  token_id, key = split_token(token)
133
+ token_id = convert_token_id(token_id)
132
134
  return unless token_id && key
133
135
 
134
136
  [id, token_id, key]
@@ -102,13 +102,15 @@ module Rodauth
102
102
  :valid_new_webauthn_credential?,
103
103
  :valid_webauthn_credential_auth?,
104
104
  :webauthn_auth_js_path,
105
- :webauth_credential_options_for_get,
105
+ :webauthn_credential_options_for_get,
106
106
  :webauthn_remove_authenticated_session,
107
107
  :webauthn_setup_js_path,
108
108
  :webauthn_update_session,
109
109
  :webauthn_user_name,
110
110
  )
111
111
 
112
+ def_deprecated_alias :webauthn_credential_options_for_get, :webauth_credential_options_for_get
113
+
112
114
  route(:webauthn_auth_js) do |r|
113
115
  before_webauthn_auth_js_route
114
116
  r.get do
@@ -315,7 +317,7 @@ module Rodauth
315
317
  webauthn_credential.verify(challenge)
316
318
  end
317
319
 
318
- def webauth_credential_options_for_get
320
+ def webauthn_credential_options_for_get
319
321
  WebAuthn::Credential.options_for_get(
320
322
  :allow => account_webauthn_ids,
321
323
  :timeout => webauthn_auth_timeout,
@@ -6,11 +6,11 @@ module Rodauth
6
6
  MAJOR = 2
7
7
 
8
8
  # The minor version of Rodauth, updated for new feature releases of Rodauth.
9
- MINOR = 26
9
+ MINOR = 27
10
10
 
11
11
  # The patch version of Rodauth, updated only for bug fixes from the last
12
12
  # feature release.
13
- TINY = 1
13
+ TINY = 0
14
14
 
15
15
  # The full version of Rodauth as a string
16
16
  VERSION = "#{MAJOR}.#{MINOR}.#{TINY}".freeze
@@ -1,9 +1,9 @@
1
- <form method="post" action="#{rodauth.webauthn_auth_form_path}" class="rodauth" role="form" id="webauthn-auth-form" data-credential-options="#{h((cred = rodauth.webauth_credential_options_for_get).as_json.to_json)}">
1
+ <form method="post" action="#{rodauth.webauthn_auth_form_path}" class="rodauth" role="form" id="webauthn-auth-form" data-credential-options="#{h((cred = rodauth.webauthn_credential_options_for_get).as_json.to_json)}">
2
2
  #{rodauth.webauthn_auth_additional_form_tags}
3
3
  #{rodauth.csrf_tag(rodauth.webauthn_auth_form_path)}
4
4
  <input type="hidden" name="#{rodauth.webauthn_auth_challenge_param}" value="#{cred.challenge}" />
5
5
  <input type="hidden" name="#{rodauth.webauthn_auth_challenge_hmac_param}" value="#{rodauth.compute_hmac(cred.challenge)}" />
6
- <input class="rodauth_hidden" aria-hidden="true" type="text" name="#{rodauth.webauthn_auth_param}" id="webauthn-auth" value="" />
6
+ <input class="rodauth_hidden d-none" aria-hidden="true" type="text" name="#{rodauth.webauthn_auth_param}" id="webauthn-auth" value="" />
7
7
  <div id="webauthn-auth-button">
8
8
  #{rodauth.button(rodauth.webauthn_auth_button)}
9
9
  </div>
@@ -3,7 +3,7 @@
3
3
  #{rodauth.csrf_tag}
4
4
  <input type="hidden" name="#{rodauth.webauthn_setup_challenge_param}" value="#{cred.challenge}" />
5
5
  <input type="hidden" name="#{rodauth.webauthn_setup_challenge_hmac_param}" value="#{rodauth.compute_hmac(cred.challenge)}" />
6
- <input class="rodauth_hidden" aria-hidden="true" type="text" name="#{rodauth.webauthn_setup_param}" id="webauthn-setup" value="" />
6
+ <input class="rodauth_hidden d-none" aria-hidden="true" type="text" name="#{rodauth.webauthn_setup_param}" id="webauthn-setup" value="" />
7
7
  #{rodauth.render('password-field') if rodauth.two_factor_modifications_require_password?}
8
8
  <div id="webauthn-setup-button">
9
9
  #{rodauth.button(rodauth.webauthn_setup_button)}
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rodauth
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.26.1
4
+ version: 2.27.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-08 00:00:00.000000000 Z
11
+ date: 2023-01-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sequel
@@ -342,6 +342,7 @@ extra_rdoc_files:
342
342
  - doc/release_notes/2.24.0.txt
343
343
  - doc/release_notes/2.25.0.txt
344
344
  - doc/release_notes/2.26.0.txt
345
+ - doc/release_notes/2.27.0.txt
345
346
  - doc/release_notes/2.3.0.txt
346
347
  - doc/release_notes/2.4.0.txt
347
348
  - doc/release_notes/2.5.0.txt
@@ -455,6 +456,7 @@ files:
455
456
  - doc/release_notes/2.24.0.txt
456
457
  - doc/release_notes/2.25.0.txt
457
458
  - doc/release_notes/2.26.0.txt
459
+ - doc/release_notes/2.27.0.txt
458
460
  - doc/release_notes/2.3.0.txt
459
461
  - doc/release_notes/2.4.0.txt
460
462
  - doc/release_notes/2.5.0.txt
@@ -612,7 +614,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
612
614
  - !ruby/object:Gem::Version
613
615
  version: '0'
614
616
  requirements: []
615
- rubygems_version: 3.3.7
617
+ rubygems_version: 3.4.1
616
618
  signing_key:
617
619
  specification_version: 4
618
620
  summary: Authentication and Account Management Framework for Rack Applications