diff options
-rw-r--r-- | actionpack/lib/action_dispatch/middleware/cookies.rb | 5 | ||||
-rw-r--r-- | activerecord/lib/active_record/reflection.rb | 11 | ||||
-rw-r--r-- | activesupport/test/message_encryptor_test.rb | 2 | ||||
-rw-r--r-- | guides/source/engines.md | 2 | ||||
-rw-r--r-- | guides/source/plugins.md | 4 | ||||
-rw-r--r-- | railties/lib/rails/generators/rails/app/app_generator.rb | 6 | ||||
-rw-r--r-- | railties/lib/rails/generators/rails/master_key/master_key_generator.rb | 26 | ||||
-rw-r--r-- | railties/test/application/middleware/cookies_test.rb | 64 | ||||
-rw-r--r-- | railties/test/application/middleware/session_test.rb | 2 | ||||
-rw-r--r-- | railties/test/generators/app_generator_test.rb | 7 |
10 files changed, 65 insertions, 64 deletions
diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb index baffe200bc..0213987c99 100644 --- a/actionpack/lib/action_dispatch/middleware/cookies.rb +++ b/actionpack/lib/action_dispatch/middleware/cookies.rb @@ -608,10 +608,11 @@ module ActionDispatch end if upgrade_legacy_hmac_aes_cbc_cookies? - secret = request.key_generator.generate_key(request.encrypted_cookie_salt) + legacy_cipher = "aes-256-cbc" + secret = request.key_generator.generate_key(request.encrypted_cookie_salt, ActiveSupport::MessageEncryptor.key_len(legacy_cipher)) sign_secret = request.key_generator.generate_key(request.encrypted_signed_cookie_salt) - @encryptor.rotate secret, sign_secret, cipher: "aes-256-cbc", digest: digest, serializer: SERIALIZER + @encryptor.rotate(secret, sign_secret, cipher: legacy_cipher, digest: digest, serializer: SERIALIZER) end if upgrade_legacy_signed_cookies? diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 82ab2415e1..032df925bf 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -425,7 +425,6 @@ module ActiveRecord def initialize(name, scope, options, active_record) super - @automatic_inverse_of = nil @type = options[:as] && (options[:foreign_type] || "#{options[:as]}_type") @foreign_type = options[:foreign_type] || "#{name}_type" @constructable = calculate_constructable(macro, options) @@ -609,12 +608,14 @@ module ActiveRecord # If it cannot find a suitable inverse association name, it returns # +nil+. def inverse_name - options.fetch(:inverse_of) do - @automatic_inverse_of ||= automatic_inverse_of + unless defined?(@inverse_name) + @inverse_name = options.fetch(:inverse_of) { automatic_inverse_of } end + + @inverse_name end - # returns either false or the inverse association name that it finds. + # returns either +nil+ or the inverse association name that it finds. def automatic_inverse_of if can_find_inverse_of_automatically?(self) inverse_name = ActiveSupport::Inflector.underscore(options[:as] || active_record.name.demodulize).to_sym @@ -631,8 +632,6 @@ module ActiveRecord return inverse_name end end - - false end # Checks if the inverse reflection that is returned from the diff --git a/activesupport/test/message_encryptor_test.rb b/activesupport/test/message_encryptor_test.rb index 8fde3928dc..9edf07f762 100644 --- a/activesupport/test/message_encryptor_test.rb +++ b/activesupport/test/message_encryptor_test.rb @@ -201,7 +201,7 @@ class MessageEncryptorTest < ActiveSupport::TestCase end def secrets - @secrets ||= Hash.new { |h,k| h[k] = SecureRandom.random_bytes(32) } + @secrets ||= Hash.new { |h, k| h[k] = SecureRandom.random_bytes(32) } end def munge(base64_string) diff --git a/guides/source/engines.md b/guides/source/engines.md index c7331b6ca4..343c224a7c 100644 --- a/guides/source/engines.md +++ b/guides/source/engines.md @@ -1322,7 +1322,7 @@ engine. Assets within an engine work in an identical way to a full application. Because the engine class inherits from `Rails::Engine`, the application will know to -look up assets in the engine's 'app/assets' and 'lib/assets' directories. +look up assets in the engine's `app/assets` and `lib/assets` directories. Like all of the other components of an engine, the assets should be namespaced. This means that if you have an asset called `style.css`, it should be placed at diff --git a/guides/source/plugins.md b/guides/source/plugins.md index b3a7f544f5..5048444cb2 100644 --- a/guides/source/plugins.md +++ b/guides/source/plugins.md @@ -359,7 +359,7 @@ When you run `bin/test`, you should see the tests all pass: ### Add an Instance Method -This plugin will add a method named 'squawk' to any Active Record object that calls 'acts_as_yaffle'. The 'squawk' +This plugin will add a method named 'squawk' to any Active Record object that calls `acts_as_yaffle`. The 'squawk' method will simply set the value of one of the fields in the database. To start out, write a failing test that shows the behavior you'd like: @@ -392,7 +392,7 @@ end ``` Run the test to make sure the last two tests fail with an error that contains "NoMethodError: undefined method `squawk'", -then update 'acts_as_yaffle.rb' to look like this: +then update `acts_as_yaffle.rb` to look like this: ```ruby # yaffle/lib/yaffle/acts_as_yaffle.rb diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index ac82ff6633..23fdf03b05 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -69,7 +69,7 @@ module Rails def version_control if !options[:skip_git] && !options[:pretend] - run "git init" + run "git init", capture: options[:quiet] end end @@ -164,7 +164,7 @@ module Rails require_relative "../master_key/master_key_generator" after_bundle do - Rails::Generators::MasterKeyGenerator.new.add_master_key_file + Rails::Generators::MasterKeyGenerator.new([], quiet: options[:quiet]).add_master_key_file end end @@ -174,7 +174,7 @@ module Rails require_relative "../credentials/credentials_generator" after_bundle do - Rails::Generators::CredentialsGenerator.new.add_credentials_file_silently + Rails::Generators::CredentialsGenerator.new([], quiet: options[:quiet]).add_credentials_file_silently end end diff --git a/railties/lib/rails/generators/rails/master_key/master_key_generator.rb b/railties/lib/rails/generators/rails/master_key/master_key_generator.rb index e49d3b39e0..395687974a 100644 --- a/railties/lib/rails/generators/rails/master_key/master_key_generator.rb +++ b/railties/lib/rails/generators/rails/master_key/master_key_generator.rb @@ -13,15 +13,15 @@ module Rails unless MASTER_KEY_PATH.exist? key = ActiveSupport::EncryptedFile.generate_key - say "Adding #{MASTER_KEY_PATH} to store the master encryption key: #{key}" - say "" - say "Save this in a password manager your team can access." - say "" - say "If you lose the key, no one, including you, can access anything encrypted with it." + log "Adding #{MASTER_KEY_PATH} to store the master encryption key: #{key}" + log "" + log "Save this in a password manager your team can access." + log "" + log "If you lose the key, no one, including you, can access anything encrypted with it." - say "" + log "" create_file MASTER_KEY_PATH, key - say "" + log "" ignore_master_key_file end @@ -31,15 +31,15 @@ module Rails def ignore_master_key_file if File.exist?(".gitignore") unless File.read(".gitignore").include?(key_ignore) - say "Ignoring #{MASTER_KEY_PATH} so it won't end up in Git history:" - say "" + log "Ignoring #{MASTER_KEY_PATH} so it won't end up in Git history:" + log "" append_to_file ".gitignore", key_ignore - say "" + log "" end else - say "IMPORTANT: Don't commit #{MASTER_KEY_PATH}. Add this to your ignore file:" - say key_ignore, :on_green - say "" + log "IMPORTANT: Don't commit #{MASTER_KEY_PATH}. Add this to your ignore file:" + log key_ignore, :on_green + log "" end end diff --git a/railties/test/application/middleware/cookies_test.rb b/railties/test/application/middleware/cookies_test.rb index 092f7a1099..ecb4ee3446 100644 --- a/railties/test/application/middleware/cookies_test.rb +++ b/railties/test/application/middleware/cookies_test.rb @@ -52,14 +52,6 @@ module ApplicationTests end test "signed cookies with SHA512 digest and rotated out SHA256 and SHA1 digests" do - skip "@kaspth will fix this" - - key_gen_sha1 = ActiveSupport::KeyGenerator.new("legacy sha1 secret", iterations: 1000) - key_gen_sha256 = ActiveSupport::KeyGenerator.new("legacy sha256 secret", iterations: 1000) - - verifer_sha1 = ActiveSupport::MessageVerifier.new(key_gen_sha1.generate_key("sha1 salt"), digest: :SHA1) - verifer_sha256 = ActiveSupport::MessageVerifier.new(key_gen_sha256.generate_key("sha256 salt"), digest: :SHA256) - app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get ':controller(/:action)' @@ -72,12 +64,12 @@ module ApplicationTests protect_from_forgery with: :null_session def write_raw_cookie_sha1 - cookies[:signed_cookie] = "#{verifer_sha1.generate("signed cookie")}" + cookies[:signed_cookie] = TestVerifiers.sha1.generate("signed cookie") head :ok end def write_raw_cookie_sha256 - cookies[:signed_cookie] = "#{verifer_sha256.generate("signed cookie")}" + cookies[:signed_cookie] = TestVerifiers.sha256.generate("signed cookie") head :ok end @@ -92,44 +84,43 @@ module ApplicationTests RUBY add_to_config <<-RUBY - config.action_dispatch.cookies_rotations.rotate :signed, - digest: "SHA1", secret: "legacy sha1 secret", salt: "sha1 salt" + sha1_secret = Rails.application.key_generator.generate_key("sha1") + sha256_secret = Rails.application.key_generator.generate_key("sha256") - config.action_dispatch.cookies_rotations.rotate :signed, - digest: "SHA256", secret: "legacy sha256 secret", salt: "sha256 salt" + ::TestVerifiers = Class.new do + class_attribute :sha1, default: ActiveSupport::MessageVerifier.new(sha1_secret, digest: "SHA1") + class_attribute :sha256, default: ActiveSupport::MessageVerifier.new(sha256_secret, digest: "SHA256") + end config.action_dispatch.signed_cookie_digest = "SHA512" config.action_dispatch.signed_cookie_salt = "sha512 salt" + + config.action_dispatch.cookies_rotations.tap do |cookies| + cookies.rotate :signed, sha1_secret, digest: "SHA1" + cookies.rotate :signed, sha256_secret, digest: "SHA256" + end RUBY require "#{app_path}/config/environment" - verifer_sha512 = ActiveSupport::MessageVerifier.new(app.key_generator.generate_key("sha512 salt"), digest: :SHA512) + verifier_sha512 = ActiveSupport::MessageVerifier.new(app.key_generator.generate_key("sha512 salt"), digest: :SHA512) get "/foo/write_raw_cookie_sha1" get "/foo/read_signed" assert_equal "signed cookie".inspect, last_response.body get "/foo/read_raw_cookie" - assert_equal "signed cookie", verifer_sha512.verify(last_response.body) + assert_equal "signed cookie", verifier_sha512.verify(last_response.body) get "/foo/write_raw_cookie_sha256" get "/foo/read_signed" assert_equal "signed cookie".inspect, last_response.body get "/foo/read_raw_cookie" - assert_equal "signed cookie", verifer_sha512.verify(last_response.body) + assert_equal "signed cookie", verifier_sha512.verify(last_response.body) end - test "encrypted cookies with multiple rotated out ciphers" do - skip "@kaspth will fix this" - - key_gen_one = ActiveSupport::KeyGenerator.new("legacy secret one", iterations: 1000) - key_gen_two = ActiveSupport::KeyGenerator.new("legacy secret two", iterations: 1000) - - encryptor_one = ActiveSupport::MessageEncryptor.new(key_gen_one.generate_key("salt one", 32), cipher: "aes-256-gcm") - encryptor_two = ActiveSupport::MessageEncryptor.new(key_gen_two.generate_key("salt two", 32), cipher: "aes-256-gcm") - + test "encrypted cookies rotating multiple encryption keys" do app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get ':controller(/:action)' @@ -142,12 +133,12 @@ module ApplicationTests protect_from_forgery with: :null_session def write_raw_cookie_one - cookies[:encrypted_cookie] = "#{encryptor_one.encrypt_and_sign("encrypted cookie")}" + cookies[:encrypted_cookie] = TestEncryptors.first_gcm.encrypt_and_sign("encrypted cookie") head :ok end def write_raw_cookie_two - cookies[:encrypted_cookie] = "#{encryptor_two.encrypt_and_sign("encrypted cookie")}" + cookies[:encrypted_cookie] = TestEncryptors.second_gcm.encrypt_and_sign("encrypted cookie") head :ok end @@ -162,15 +153,22 @@ module ApplicationTests RUBY add_to_config <<-RUBY + first_secret = Rails.application.key_generator.generate_key("first", 32) + second_secret = Rails.application.key_generator.generate_key("second", 32) + + ::TestEncryptors = Class.new do + class_attribute :first_gcm, default: ActiveSupport::MessageEncryptor.new(first_secret, cipher: "aes-256-gcm") + class_attribute :second_gcm, default: ActiveSupport::MessageEncryptor.new(second_secret, cipher: "aes-256-gcm") + end + config.action_dispatch.use_authenticated_cookie_encryption = true config.action_dispatch.encrypted_cookie_cipher = "aes-256-gcm" config.action_dispatch.authenticated_encrypted_cookie_salt = "salt" - config.action_dispatch.cookies_rotations.rotate :encrypted, - cipher: "aes-256-gcm", secret: "legacy secret one", salt: "salt one" - - config.action_dispatch.cookies_rotations.rotate :encrypted, - cipher: "aes-256-gcm", secret: "legacy secret two", salt: "salt two" + config.action_dispatch.cookies_rotations.tap do |cookies| + cookies.rotate :encrypted, first_secret + cookies.rotate :encrypted, second_secret + end RUBY require "#{app_path}/config/environment" diff --git a/railties/test/application/middleware/session_test.rb b/railties/test/application/middleware/session_test.rb index 36d1bf5bf2..a17988235a 100644 --- a/railties/test/application/middleware/session_test.rb +++ b/railties/test/application/middleware/session_test.rb @@ -301,8 +301,6 @@ module ApplicationTests end test "session upgrading from AES-CBC-HMAC encryption to AES-GCM encryption" do - skip "@kaspth will fix this" - app_file "config/routes.rb", <<-RUBY Rails.application.routes.draw do get ':controller(/:action)' diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 904e2a5c84..20f593f25c 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -560,6 +560,11 @@ class AppGeneratorTest < Rails::Generators::TestCase assert_no_match(/run git init/, output) end + def test_quiet_option + output = run_generator [File.join(destination_root, "myapp"), "--quiet"] + assert_empty output + end + def test_application_name_with_spaces path = File.join(destination_root, "foo bar") @@ -737,7 +742,7 @@ class AppGeneratorTest < Rails::Generators::TestCase sequence = ["git init", "install", "exec spring binstub --all", "echo ran after_bundle"] @sequence_step ||= 0 - ensure_bundler_first = -> command do + ensure_bundler_first = -> command, options = nil do assert_equal sequence[@sequence_step], command, "commands should be called in sequence #{sequence}" @sequence_step += 1 end |