rodauth 2.26.1 → 2.27.0

Sign up to get free protection for your applications and to get access to all the features.
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