As mentioned in
https://github.com/rails/rails/pull/40770#issuecomment-748347066 we
should default to SHA256 where SHA1 is used today. This switches over
the ActiveSupport::Digest to use SHA256 for new applications.
It also updates the constants to always refer to and use the OpenSSL
constants as well, as also discussed in that PR.
This change allows for configuration of the hash digest that is used in
the key generator for key derivation.
SHA1 is an outdated algorithm and security auditors tend to frown on
its usage. By allowing this to be configured, it becomes possible to
move to a more up to date hash mechanism.
While I don't think this has any current relevant security implications,
especially not with a proper random secret base, moving away from SHA1
makes conversations with auditors and FIPS compliance checks easier
since the best answer is always that an approved algorithm is used.
A rotation can be built using this change with an approach like the
following for encrypted cookies:
```ruby
Rails.application.config.active_support.key_generator_hash_digest_class = OpenSSL::Digest::SHA256
Rails.application.config.action_dispatch.cookies_rotations.tap do |cookies|
salt = Rails.application.config.action_dispatch.authenticated_encrypted_cookie_salt
secret_key_base = Rails.application.secrets.secret_key_base
key_generator = ActiveSupport::KeyGenerator.new(secret_key_base, iterations: 1000, hash_digest_class: OpenSSL::Digest::SHA1)
key_len = ActiveSupport::MessageEncryptor.key_len
secret = key_generator.generate_key(salt, key_len)
cookies.rotate :encrypted, secret
end
```
This turns the default into using SHA256 but also still accepts secrets
derived using SHA1.
The defaults for new apps is here changed to use SHA256. Existing apps
will keep using SHA1.
This test was originally written with the intention of asserting that
a runtime error related to XXE will be raised by the parser. However,
because initial whitespace is present before the doctype,
XmlMini_NokogiriSAX::HashBuilder has been raising an unrelated error
in this test.
Related to #41015
---
Using Nokogiri v1.10.10, the error being raised without this change
is:
> XML declaration allowed only at the start of the document
but with this change we see the expected exception from the libxml2
SAX parser:
> Entity 'a' not defined
Using Nokogiri v1.11.0, in which error handling is broken (see
sparklemotion/nokogiri#2168), without this change we see an exception
being raised by HashBuilder because `characters` is called before
`start_element` and so the content hash isn't initialized (see
The error being raised with this change is:
> Parse stack not empty!
which is not the error we want (because of
sparklemotion/nokogiri#2168), but the test still passes.
Using Nokogiri with the fix from sparklemotion/nokogiri#2169, the
error being raised without this change is:
> XML declaration allowed only at the start of the document
but with this change will be:
> Entity 'a' not defined
and we're back to the expected behavior.
`rescue_from` works for rescuing exceptions in controller actions, but it's not specific to ActionController.
This change updates the docs to clarify the specifics of how `rescue_from` is used and that its use goes beyond controller actions.
Note: I believe the original addition of this documentation was added as part of the move from [`ActionController::Rescue` to `ActiveSupport::Rescuable`](259a7a844b (diff-2276a3674b84e1262c94cc36346f9fbd8d00e0a4542bb991a8846c06d86335b1R12))
The `expires_in` option is easy to misremember or mistype as `expire_in`
or `expired_in`, with potentially harmful results. If a developer wants
to cache a value for only 2 seconds but mistakenly types
`expire_in: 2.seconds`, that value will instead be cached for the
default time, likely 6 hours, meaning that users of the site will see
the same data for much longer than they should, and the only recovery
(short of waiting for the 6 hours to elapse) is to manually expire all
relevant keys. This commit allows cache stores to recognize these common
typos as aliases by normalizing them before consuming the options.
In general, we should be careful about adding too many aliases for
options to the cache stores, since each option key used by the base
Cache::Store class is one fewer key that each cache implementation can
customize for itself. This case was approved because of the similarity
of the aliases to the root key and the potential damage caused by
mistaking them.
Fixes#39850.
While the warning is useful in itself, it doesn't tell you what file is
specifically causing the issue which can make resolving it harder than
it should be. As we've got the path already, we can simply include the
location of the problematic file in the warning message.
The docs for Time#xmlschema note "You must require 'time' to use this
method." -- see
https://ruby-doc.org/stdlib-2.7.2/libdoc/time/rdoc/Time.html#method-i-xmlschema
Apparently in most cases, by the time `core_ext/time/conversions.rb` is
loaded, "time" has already been required, however that is not a
guarantee. If it isn't, you'll get a "NameError (undefined method
`xmlschema' for class `Time')". A simple repro is to launch `irb` and
do:
> require 'active_support'
> require 'active_support/core_ext/date_time'
This can even happen on some systems with just a:
> require 'active_support'
> require 'active_support/core_ext'
That is because `active_support/core_ext.rb` uses `Dir.glob` to
enumerate and then require all ruby files in the `core_ext` directory,
but "the order in which the results are returned [from Dir.glob]
depends on your system" -- see
https://ruby-doc.org/core-2.7.2/Dir.html#method-c-glob
Therefore this commit also sorts those results to make the load order
deterministic and system-agnostic.
`#dup` resets the extended Logger methods that could come from enabling broadcasting. That would mean if we create a tagged logger from a Logger with broadcasting enabled (usually to stdout), the new tagged logger will not perform broadcasting.
Making the fork method private by calling `private :fork` raises a
"no superclass method `fork'" error when calling super in a subclass on
ruby <= 2.5.3. The error doesn't occur on ruby 2.5.4 and higher.
Making the method private by redefining doesn't raise the error.
The possible fix on 2.5.4 is 75aba10d7a
The error can be reproduced with the following script on ruby 2.5.3:
```
class Cluster
def start
fork { puts "forked!" }
end
end
module CoreExt
def fork(*)
super
end
end
module CoreExtPrivate
include CoreExt
private :fork
end
::Object.prepend(CoreExtPrivate)
Cluster.new.start
```
Fixes#40603
Fixes#39976
Prior to this commit it was possible to pass a single argument block to
`ActiveSupport::Notifications.subscribe`, rather than 5 separate
arguments:
```rb
ActiveSupport::Notifications.subscribe('some_event') do |event|
puts "Reacting to #{event.name}"
end
```
But it was not possible to do the same with a lambda, since the lambda
parameter is a required (`:req`) parameter, but we were checking only
for an optional (`:opt`) parameter.
```rb
listener = ->(event) do
puts "Reacting to #{event.name}"
end
ActiveSupport::Notifications.subscribe('some_event', &listener)
```
It was also not possible to do this with a custom callable object, since
the custom callable does not respond directly to `:parameters` (although
it's `:call` method object does).
```rb
class CustomListener
def call(event)
puts "Reacting to #{event.name}"
end
end
ActiveSupport::Notifications.subscribe('some_event', CustomListener.new)
```
Prior to this commit these examples would have raised `ArgumentError:
wrong number of arguments (given 5, expected 1)`.
With this commit the single argument lambda and custom callable work
like the single argument block.
did_you_mean 1.5.0 will add suggestions to `LoadError`. This means that
`LoadError#message` will now return a new string on each invocation, and
mutating the result will no longer modify the error's message.
For example PG refers to https://www.ietf.org/rfc/rfc3339.txt when converting(Ref: https://www.postgresql.org/docs/current/datatype-datetime.html)
According to the ref there is no explicit mention of allowing sign before the parts, which reads as below:
Durations:
dur-second = 1*DIGIT "S"
dur-minute = 1*DIGIT "M" [dur-second]
dur-hour = 1*DIGIT "H" [dur-minute]
dur-time = "T" (dur-hour / dur-minute / dur-second)
dur-day = 1*DIGIT "D"
dur-week = 1*DIGIT "W"
dur-month = 1*DIGIT "M" [dur-day]
dur-year = 1*DIGIT "Y" [dur-month]
dur-date = (dur-day / dur-month / dur-year) [dur-time]
duration = "P" (dur-date / dur-time / dur-week)
We should not attempt to move sign forward in this case.