actionpack 5.2.4 → 5.2.4.5
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.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +27 -0
- data/lib/action_controller/metal/request_forgery_protection.rb +29 -4
- data/lib/action_controller/metal/strong_parameters.rb +2 -0
- data/lib/action_dispatch.rb +5 -4
- data/lib/action_dispatch/middleware/session/abstract_store.rb +14 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +11 -6
- data/lib/action_dispatch/middleware/session/cookie_store.rb +17 -7
- data/lib/action_dispatch/request/session.rb +7 -1
- data/lib/action_pack/gem_version.rb +1 -1
- metadata +16 -10
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 8458248b602da029b1e9113db9f0305888fdf99bf83ea4fe679ad0ed49b22175
         | 
| 4 | 
            +
              data.tar.gz: '085825f1ed9d286aa92cf5fa06fb039534331030d5b70da304c237a492f7ded9'
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 7a6b62b3afeeb992a981128fbfab64944e897f20a0e75cbef6fd3d972108321ff440f7344935c8d196c1d1e6d3e08d64f040c6c5aa9ad63f06e9b78875da0c54
         | 
| 7 | 
            +
              data.tar.gz: 27a049710288451664d3672a6fb18fe505003d9bb91826408ab507d9de06fa9f1a877a2dfc6b9a9b91e32c0f122cdfd33b1bcd3802e64966e4388c17dcad08e6
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,3 +1,30 @@ | |
| 1 | 
            +
            ## Rails 5.2.4.5 (February 10, 2021) ##
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            *   No changes.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
             | 
| 6 | 
            +
            ## Rails 5.2.4.4 (September 09, 2020) ##
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            *   No changes.
         | 
| 9 | 
            +
             | 
| 10 | 
            +
             | 
| 11 | 
            +
            ## Rails 5.2.4.3 (May 18, 2020) ##
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            *   [CVE-2020-8166] HMAC raw CSRF token before masking it, so it cannot be used to reconstruct a per-form token
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            *   [CVE-2020-8164] Return self when calling #each, #each_pair, and #each_value instead of the raw @parameters hash
         | 
| 16 | 
            +
             | 
| 17 | 
            +
             | 
| 18 | 
            +
            ## Rails 5.2.4.1 (December 18, 2019) ##
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            *   Fix possible information leak / session hijacking vulnerability.
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                The `ActionDispatch::Session::MemcacheStore` is still vulnerable given it requires the
         | 
| 23 | 
            +
                gem dalli to be updated as well.
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                CVE-2019-16782.
         | 
| 26 | 
            +
             | 
| 27 | 
            +
             | 
| 1 28 | 
             
            ## Rails 5.2.4 (November 27, 2019) ##
         | 
| 2 29 |  | 
| 3 30 | 
             
            *   No changes.
         | 
| @@ -318,13 +318,15 @@ module ActionController #:nodoc: | |
| 318 318 | 
             
                      action_path = normalize_action_path(action)
         | 
| 319 319 | 
             
                      per_form_csrf_token(session, action_path, method)
         | 
| 320 320 | 
             
                    else
         | 
| 321 | 
            -
                       | 
| 321 | 
            +
                      global_csrf_token(session)
         | 
| 322 322 | 
             
                    end
         | 
| 323 323 |  | 
| 324 324 | 
             
                    one_time_pad = SecureRandom.random_bytes(AUTHENTICITY_TOKEN_LENGTH)
         | 
| 325 325 | 
             
                    encrypted_csrf_token = xor_byte_strings(one_time_pad, raw_token)
         | 
| 326 326 | 
             
                    masked_token = one_time_pad + encrypted_csrf_token
         | 
| 327 | 
            -
                    Base64. | 
| 327 | 
            +
                    Base64.urlsafe_encode64(masked_token, padding: false)
         | 
| 328 | 
            +
             | 
| 329 | 
            +
                    mask_token(raw_token)
         | 
| 328 330 | 
             
                  end
         | 
| 329 331 |  | 
| 330 332 | 
             
                  # Checks the client's masked token to see if it matches the
         | 
| @@ -354,7 +356,8 @@ module ActionController #:nodoc: | |
| 354 356 | 
             
                    elsif masked_token.length == AUTHENTICITY_TOKEN_LENGTH * 2
         | 
| 355 357 | 
             
                      csrf_token = unmask_token(masked_token)
         | 
| 356 358 |  | 
| 357 | 
            -
                       | 
| 359 | 
            +
                      compare_with_global_token(csrf_token, session) ||
         | 
| 360 | 
            +
                        compare_with_real_token(csrf_token, session) ||
         | 
| 358 361 | 
             
                        valid_per_form_csrf_token?(csrf_token, session)
         | 
| 359 362 | 
             
                    else
         | 
| 360 363 | 
             
                      false # Token is malformed.
         | 
| @@ -369,10 +372,21 @@ module ActionController #:nodoc: | |
| 369 372 | 
             
                    xor_byte_strings(one_time_pad, encrypted_csrf_token)
         | 
| 370 373 | 
             
                  end
         | 
| 371 374 |  | 
| 375 | 
            +
                  def mask_token(raw_token) # :doc:
         | 
| 376 | 
            +
                    one_time_pad = SecureRandom.random_bytes(AUTHENTICITY_TOKEN_LENGTH)
         | 
| 377 | 
            +
                    encrypted_csrf_token = xor_byte_strings(one_time_pad, raw_token)
         | 
| 378 | 
            +
                    masked_token = one_time_pad + encrypted_csrf_token
         | 
| 379 | 
            +
                    Base64.strict_encode64(masked_token)
         | 
| 380 | 
            +
                  end
         | 
| 381 | 
            +
             | 
| 372 382 | 
             
                  def compare_with_real_token(token, session) # :doc:
         | 
| 373 383 | 
             
                    ActiveSupport::SecurityUtils.fixed_length_secure_compare(token, real_csrf_token(session))
         | 
| 374 384 | 
             
                  end
         | 
| 375 385 |  | 
| 386 | 
            +
                  def compare_with_global_token(token, session) # :doc:
         | 
| 387 | 
            +
                    ActiveSupport::SecurityUtils.fixed_length_secure_compare(token, global_csrf_token(session))
         | 
| 388 | 
            +
                  end
         | 
| 389 | 
            +
             | 
| 376 390 | 
             
                  def valid_per_form_csrf_token?(token, session) # :doc:
         | 
| 377 391 | 
             
                    if per_form_csrf_tokens
         | 
| 378 392 | 
             
                      correct_token = per_form_csrf_token(
         | 
| @@ -393,10 +407,21 @@ module ActionController #:nodoc: | |
| 393 407 | 
             
                  end
         | 
| 394 408 |  | 
| 395 409 | 
             
                  def per_form_csrf_token(session, action_path, method) # :doc:
         | 
| 410 | 
            +
                    csrf_token_hmac(session, [action_path, method.downcase].join("#"))
         | 
| 411 | 
            +
                  end
         | 
| 412 | 
            +
             | 
| 413 | 
            +
                  GLOBAL_CSRF_TOKEN_IDENTIFIER = "!real_csrf_token"
         | 
| 414 | 
            +
                  private_constant :GLOBAL_CSRF_TOKEN_IDENTIFIER
         | 
| 415 | 
            +
             | 
| 416 | 
            +
                  def global_csrf_token(session) # :doc:
         | 
| 417 | 
            +
                    csrf_token_hmac(session, GLOBAL_CSRF_TOKEN_IDENTIFIER)
         | 
| 418 | 
            +
                  end
         | 
| 419 | 
            +
             | 
| 420 | 
            +
                  def csrf_token_hmac(session, identifier) # :doc:
         | 
| 396 421 | 
             
                    OpenSSL::HMAC.digest(
         | 
| 397 422 | 
             
                      OpenSSL::Digest::SHA256.new,
         | 
| 398 423 | 
             
                      real_csrf_token(session),
         | 
| 399 | 
            -
                       | 
| 424 | 
            +
                      identifier
         | 
| 400 425 | 
             
                    )
         | 
| 401 426 | 
             
                  end
         | 
| 402 427 |  | 
    
        data/lib/action_dispatch.rb
    CHANGED
    
    | @@ -83,10 +83,11 @@ module ActionDispatch | |
| 83 83 | 
             
              end
         | 
| 84 84 |  | 
| 85 85 | 
             
              module Session
         | 
| 86 | 
            -
                autoload :AbstractStore, | 
| 87 | 
            -
                autoload : | 
| 88 | 
            -
                autoload : | 
| 89 | 
            -
                autoload : | 
| 86 | 
            +
                autoload :AbstractStore,       "action_dispatch/middleware/session/abstract_store"
         | 
| 87 | 
            +
                autoload :AbstractSecureStore, "action_dispatch/middleware/session/abstract_store"
         | 
| 88 | 
            +
                autoload :CookieStore,         "action_dispatch/middleware/session/cookie_store"
         | 
| 89 | 
            +
                autoload :MemCacheStore,       "action_dispatch/middleware/session/mem_cache_store"
         | 
| 90 | 
            +
                autoload :CacheStore,          "action_dispatch/middleware/session/cache_store"
         | 
| 90 91 | 
             
              end
         | 
| 91 92 |  | 
| 92 93 | 
             
              mattr_accessor :test_app
         | 
| @@ -83,7 +83,21 @@ module ActionDispatch | |
| 83 83 | 
             
                  include SessionObject
         | 
| 84 84 |  | 
| 85 85 | 
             
                  private
         | 
| 86 | 
            +
                    def set_cookie(request, session_id, cookie)
         | 
| 87 | 
            +
                      request.cookie_jar[key] = cookie
         | 
| 88 | 
            +
                    end
         | 
| 89 | 
            +
                end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                class AbstractSecureStore < Rack::Session::Abstract::PersistedSecure
         | 
| 92 | 
            +
                  include Compatibility
         | 
| 93 | 
            +
                  include StaleSessionCheck
         | 
| 94 | 
            +
                  include SessionObject
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                  def generate_sid
         | 
| 97 | 
            +
                    Rack::Session::SessionId.new(super)
         | 
| 98 | 
            +
                  end
         | 
| 86 99 |  | 
| 100 | 
            +
                  private
         | 
| 87 101 | 
             
                    def set_cookie(request, session_id, cookie)
         | 
| 88 102 | 
             
                      request.cookie_jar[key] = cookie
         | 
| 89 103 | 
             
                    end
         | 
| @@ -12,7 +12,7 @@ module ActionDispatch | |
| 12 12 | 
             
                # * <tt>cache</tt>         - The cache to use. If it is not specified, <tt>Rails.cache</tt> will be used.
         | 
| 13 13 | 
             
                # * <tt>expire_after</tt>  - The length of time a session will be stored before automatically expiring.
         | 
| 14 14 | 
             
                #   By default, the <tt>:expires_in</tt> option of the cache is used.
         | 
| 15 | 
            -
                class CacheStore <  | 
| 15 | 
            +
                class CacheStore < AbstractSecureStore
         | 
| 16 16 | 
             
                  def initialize(app, options = {})
         | 
| 17 17 | 
             
                    @cache = options[:cache] || Rails.cache
         | 
| 18 18 | 
             
                    options[:expire_after] ||= @cache.options[:expires_in]
         | 
| @@ -21,7 +21,7 @@ module ActionDispatch | |
| 21 21 |  | 
| 22 22 | 
             
                  # Get a session from the cache.
         | 
| 23 23 | 
             
                  def find_session(env, sid)
         | 
| 24 | 
            -
                    unless sid && (session =  | 
| 24 | 
            +
                    unless sid && (session = get_session_with_fallback(sid))
         | 
| 25 25 | 
             
                      sid, session = generate_sid, {}
         | 
| 26 26 | 
             
                    end
         | 
| 27 27 | 
             
                    [sid, session]
         | 
| @@ -29,7 +29,7 @@ module ActionDispatch | |
| 29 29 |  | 
| 30 30 | 
             
                  # Set a session in the cache.
         | 
| 31 31 | 
             
                  def write_session(env, sid, session, options)
         | 
| 32 | 
            -
                    key = cache_key(sid)
         | 
| 32 | 
            +
                    key = cache_key(sid.private_id)
         | 
| 33 33 | 
             
                    if session
         | 
| 34 34 | 
             
                      @cache.write(key, session, expires_in: options[:expire_after])
         | 
| 35 35 | 
             
                    else
         | 
| @@ -40,14 +40,19 @@ module ActionDispatch | |
| 40 40 |  | 
| 41 41 | 
             
                  # Remove a session from the cache.
         | 
| 42 42 | 
             
                  def delete_session(env, sid, options)
         | 
| 43 | 
            -
                    @cache.delete(cache_key(sid))
         | 
| 43 | 
            +
                    @cache.delete(cache_key(sid.private_id))
         | 
| 44 | 
            +
                    @cache.delete(cache_key(sid.public_id))
         | 
| 44 45 | 
             
                    generate_sid
         | 
| 45 46 | 
             
                  end
         | 
| 46 47 |  | 
| 47 48 | 
             
                  private
         | 
| 48 49 | 
             
                    # Turn the session id into a cache key.
         | 
| 49 | 
            -
                    def cache_key( | 
| 50 | 
            -
                      "_session_id:#{ | 
| 50 | 
            +
                    def cache_key(id)
         | 
| 51 | 
            +
                      "_session_id:#{id}"
         | 
| 52 | 
            +
                    end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                    def get_session_with_fallback(sid)
         | 
| 55 | 
            +
                      @cache.read(cache_key(sid.private_id)) || @cache.read(cache_key(sid.public_id))
         | 
| 51 56 | 
             
                    end
         | 
| 52 57 | 
             
                end
         | 
| 53 58 | 
             
              end
         | 
| @@ -51,7 +51,16 @@ module ActionDispatch | |
| 51 51 | 
             
                # would set the session cookie to expire automatically 14 days after creation.
         | 
| 52 52 | 
             
                # Other useful options include <tt>:key</tt>, <tt>:secure</tt> and
         | 
| 53 53 | 
             
                # <tt>:httponly</tt>.
         | 
| 54 | 
            -
                class CookieStore <  | 
| 54 | 
            +
                class CookieStore < AbstractSecureStore
         | 
| 55 | 
            +
                  class SessionId < DelegateClass(Rack::Session::SessionId)
         | 
| 56 | 
            +
                    attr_reader :cookie_value
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                    def initialize(session_id, cookie_value = {})
         | 
| 59 | 
            +
                      super(session_id)
         | 
| 60 | 
            +
                      @cookie_value = cookie_value
         | 
| 61 | 
            +
                    end
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
             | 
| 55 64 | 
             
                  def initialize(app, options = {})
         | 
| 56 65 | 
             
                    super(app, options.merge!(cookie_only: true))
         | 
| 57 66 | 
             
                  end
         | 
| @@ -59,7 +68,7 @@ module ActionDispatch | |
| 59 68 | 
             
                  def delete_session(req, session_id, options)
         | 
| 60 69 | 
             
                    new_sid = generate_sid unless options[:drop]
         | 
| 61 70 | 
             
                    # Reset hash and Assign the new session id
         | 
| 62 | 
            -
                    req.set_header("action_dispatch.request.unsigned_session_cookie", new_sid ? { "session_id" => new_sid } : {})
         | 
| 71 | 
            +
                    req.set_header("action_dispatch.request.unsigned_session_cookie", new_sid ? { "session_id" => new_sid.public_id } : {})
         | 
| 63 72 | 
             
                    new_sid
         | 
| 64 73 | 
             
                  end
         | 
| 65 74 |  | 
| @@ -67,7 +76,7 @@ module ActionDispatch | |
| 67 76 | 
             
                    stale_session_check! do
         | 
| 68 77 | 
             
                      data = unpacked_cookie_data(req)
         | 
| 69 78 | 
             
                      data = persistent_session_id!(data)
         | 
| 70 | 
            -
                      [data["session_id"], data]
         | 
| 79 | 
            +
                      [Rack::Session::SessionId.new(data["session_id"]), data]
         | 
| 71 80 | 
             
                    end
         | 
| 72 81 | 
             
                  end
         | 
| 73 82 |  | 
| @@ -75,7 +84,8 @@ module ActionDispatch | |
| 75 84 |  | 
| 76 85 | 
             
                    def extract_session_id(req)
         | 
| 77 86 | 
             
                      stale_session_check! do
         | 
| 78 | 
            -
                        unpacked_cookie_data(req)["session_id"]
         | 
| 87 | 
            +
                        sid = unpacked_cookie_data(req)["session_id"]
         | 
| 88 | 
            +
                        sid && Rack::Session::SessionId.new(sid)
         | 
| 79 89 | 
             
                      end
         | 
| 80 90 | 
             
                    end
         | 
| 81 91 |  | 
| @@ -93,13 +103,13 @@ module ActionDispatch | |
| 93 103 |  | 
| 94 104 | 
             
                    def persistent_session_id!(data, sid = nil)
         | 
| 95 105 | 
             
                      data ||= {}
         | 
| 96 | 
            -
                      data["session_id"] ||= sid || generate_sid
         | 
| 106 | 
            +
                      data["session_id"] ||= sid || generate_sid.public_id
         | 
| 97 107 | 
             
                      data
         | 
| 98 108 | 
             
                    end
         | 
| 99 109 |  | 
| 100 110 | 
             
                    def write_session(req, sid, session_data, options)
         | 
| 101 | 
            -
                      session_data["session_id"] = sid
         | 
| 102 | 
            -
                      session_data
         | 
| 111 | 
            +
                      session_data["session_id"] = sid.public_id
         | 
| 112 | 
            +
                      SessionId.new(sid, session_data)
         | 
| 103 113 | 
             
                    end
         | 
| 104 114 |  | 
| 105 115 | 
             
                    def set_cookie(request, session_id, cookie)
         | 
| @@ -90,7 +90,13 @@ module ActionDispatch | |
| 90 90 | 
             
                  # +nil+ if the given key is not found in the session.
         | 
| 91 91 | 
             
                  def [](key)
         | 
| 92 92 | 
             
                    load_for_read!
         | 
| 93 | 
            -
                     | 
| 93 | 
            +
                    key = key.to_s
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                    if key == "session_id"
         | 
| 96 | 
            +
                      id&.public_id
         | 
| 97 | 
            +
                    else
         | 
| 98 | 
            +
                      @delegate[key]
         | 
| 99 | 
            +
                    end
         | 
| 94 100 | 
             
                  end
         | 
| 95 101 |  | 
| 96 102 | 
             
                  # Returns true if the session has the given key or false.
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: actionpack
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 5.2.4
         | 
| 4 | 
            +
              version: 5.2.4.5
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - David Heinemeier Hansson
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 11 | 
            +
            date: 2021-02-10 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: activesupport
         | 
| @@ -16,14 +16,14 @@ dependencies: | |
| 16 16 | 
             
                requirements:
         | 
| 17 17 | 
             
                - - '='
         | 
| 18 18 | 
             
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            -
                    version: 5.2.4
         | 
| 19 | 
            +
                    version: 5.2.4.5
         | 
| 20 20 | 
             
              type: :runtime
         | 
| 21 21 | 
             
              prerelease: false
         | 
| 22 22 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 23 | 
             
                requirements:
         | 
| 24 24 | 
             
                - - '='
         | 
| 25 25 | 
             
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            -
                    version: 5.2.4
         | 
| 26 | 
            +
                    version: 5.2.4.5
         | 
| 27 27 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 28 28 | 
             
              name: rack
         | 
| 29 29 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -31,6 +31,9 @@ dependencies: | |
| 31 31 | 
             
                - - "~>"
         | 
| 32 32 | 
             
                  - !ruby/object:Gem::Version
         | 
| 33 33 | 
             
                    version: '2.0'
         | 
| 34 | 
            +
                - - ">="
         | 
| 35 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 36 | 
            +
                    version: 2.0.8
         | 
| 34 37 | 
             
              type: :runtime
         | 
| 35 38 | 
             
              prerelease: false
         | 
| 36 39 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| @@ -38,6 +41,9 @@ dependencies: | |
| 38 41 | 
             
                - - "~>"
         | 
| 39 42 | 
             
                  - !ruby/object:Gem::Version
         | 
| 40 43 | 
             
                    version: '2.0'
         | 
| 44 | 
            +
                - - ">="
         | 
| 45 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 46 | 
            +
                    version: 2.0.8
         | 
| 41 47 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 42 48 | 
             
              name: rack-test
         | 
| 43 49 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -92,28 +98,28 @@ dependencies: | |
| 92 98 | 
             
                requirements:
         | 
| 93 99 | 
             
                - - '='
         | 
| 94 100 | 
             
                  - !ruby/object:Gem::Version
         | 
| 95 | 
            -
                    version: 5.2.4
         | 
| 101 | 
            +
                    version: 5.2.4.5
         | 
| 96 102 | 
             
              type: :runtime
         | 
| 97 103 | 
             
              prerelease: false
         | 
| 98 104 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 99 105 | 
             
                requirements:
         | 
| 100 106 | 
             
                - - '='
         | 
| 101 107 | 
             
                  - !ruby/object:Gem::Version
         | 
| 102 | 
            -
                    version: 5.2.4
         | 
| 108 | 
            +
                    version: 5.2.4.5
         | 
| 103 109 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 104 110 | 
             
              name: activemodel
         | 
| 105 111 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 106 112 | 
             
                requirements:
         | 
| 107 113 | 
             
                - - '='
         | 
| 108 114 | 
             
                  - !ruby/object:Gem::Version
         | 
| 109 | 
            -
                    version: 5.2.4
         | 
| 115 | 
            +
                    version: 5.2.4.5
         | 
| 110 116 | 
             
              type: :development
         | 
| 111 117 | 
             
              prerelease: false
         | 
| 112 118 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 113 119 | 
             
                requirements:
         | 
| 114 120 | 
             
                - - '='
         | 
| 115 121 | 
             
                  - !ruby/object:Gem::Version
         | 
| 116 | 
            -
                    version: 5.2.4
         | 
| 122 | 
            +
                    version: 5.2.4.5
         | 
| 117 123 | 
             
            description: Web apps on Rails. Simple, battle-tested conventions for building and
         | 
| 118 124 | 
             
              testing MVC web applications. Works with any Rack-compatible server.
         | 
| 119 125 | 
             
            email: david@loudthinking.com
         | 
| @@ -293,8 +299,8 @@ homepage: http://rubyonrails.org | |
| 293 299 | 
             
            licenses:
         | 
| 294 300 | 
             
            - MIT
         | 
| 295 301 | 
             
            metadata:
         | 
| 296 | 
            -
              source_code_uri: https://github.com/rails/rails/tree/v5.2.4/actionpack
         | 
| 297 | 
            -
              changelog_uri: https://github.com/rails/rails/blob/v5.2.4/actionpack/CHANGELOG.md
         | 
| 302 | 
            +
              source_code_uri: https://github.com/rails/rails/tree/v5.2.4.5/actionpack
         | 
| 303 | 
            +
              changelog_uri: https://github.com/rails/rails/blob/v5.2.4.5/actionpack/CHANGELOG.md
         | 
| 298 304 | 
             
            post_install_message: 
         | 
| 299 305 | 
             
            rdoc_options: []
         | 
| 300 306 | 
             
            require_paths:
         |