diff options
Diffstat (limited to 'railties/lib/rails/application.rb')
-rw-r--r-- | railties/lib/rails/application.rb | 89 |
1 files changed, 53 insertions, 36 deletions
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index b01196e3ed..abfec90b6d 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -1,9 +1,13 @@ +# frozen_string_literal: true + require "yaml" require "active_support/core_ext/hash/keys" require "active_support/core_ext/object/blank" require "active_support/key_generator" require "active_support/message_verifier" -require "rails/engine" +require "active_support/encrypted_configuration" +require_relative "engine" +require_relative "secrets" module Rails # An Engine with the responsibility of coordinating the whole boot process. @@ -72,7 +76,7 @@ module Rails # on one of the applications to create a copy of the application which shares # the configuration. # - # If you decide to define rake tasks, runners, or initializers in an + # If you decide to define Rake tasks, runners, or initializers in an # application other than +Rails.application+, then you must run them manually. class Application < Engine autoload :Bootstrap, "rails/application/bootstrap" @@ -168,12 +172,9 @@ module Rails # number of iterations selected based on consultation with the google security # team. Details at https://github.com/rails/rails/pull/6952#issuecomment-7661220 @caching_key_generator ||= - if secrets.secret_key_base - unless secrets.secret_key_base.kind_of?(String) - raise ArgumentError, "`secret_key_base` for #{Rails.env} environment must be a type of String, change this value in `config/secrets.yml`" - end - key_generator = ActiveSupport::KeyGenerator.new(secrets.secret_key_base, iterations: 1000) - ActiveSupport::CachingKeyGenerator.new(key_generator) + if secret_key_base + ActiveSupport::CachingKeyGenerator.new \ + ActiveSupport::KeyGenerator.new(secret_key_base, iterations: 1000) else ActiveSupport::LegacyKeyGenerator.new(secrets.secret_token) end @@ -243,13 +244,11 @@ module Rails # will be used by middlewares and engines to configure themselves. def env_config @app_env_config ||= begin - validate_secret_key_config! - super.merge( "action_dispatch.parameter_filter" => config.filter_parameters, "action_dispatch.redirect_filter" => config.filter_redirect, "action_dispatch.secret_token" => secrets.secret_token, - "action_dispatch.secret_key_base" => secrets.secret_key_base, + "action_dispatch.secret_key_base" => secret_key_base, "action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions, "action_dispatch.show_detailed_exceptions" => config.consider_all_requests_local, "action_dispatch.logger" => Rails.logger, @@ -259,14 +258,15 @@ module Rails "action_dispatch.signed_cookie_salt" => config.action_dispatch.signed_cookie_salt, "action_dispatch.encrypted_cookie_salt" => config.action_dispatch.encrypted_cookie_salt, "action_dispatch.encrypted_signed_cookie_salt" => config.action_dispatch.encrypted_signed_cookie_salt, + "action_dispatch.authenticated_encrypted_cookie_salt" => config.action_dispatch.authenticated_encrypted_cookie_salt, "action_dispatch.cookies_serializer" => config.action_dispatch.cookies_serializer, "action_dispatch.cookies_digest" => config.action_dispatch.cookies_digest ) end end - # If you try to define a set of rake tasks on the instance, these will get - # passed up to the rake tasks defined on the application's class. + # If you try to define a set of Rake tasks on the instance, these will get + # passed up to the Rake tasks defined on the application's class. def rake_tasks(&block) self.class.rake_tasks(&block) end @@ -274,7 +274,7 @@ module Rails # Sends the initializers to the +initializer+ method defined in the # Rails::Initializable module. Each Rails::Application class has its own # set of initializers, as defined by the Initializable module. - def initializer(name, opts={}, &block) + def initializer(name, opts = {}, &block) self.class.initializer(name, opts, &block) end @@ -347,7 +347,7 @@ module Rails # Initialize the application passing the given group. By default, the # group is :default - def initialize!(group=:default) #:nodoc: + def initialize!(group = :default) #:nodoc: raise "Application has been already initialized." if @initialized run_initializers(group, self) @initialized = true @@ -385,18 +385,9 @@ module Rails def secrets @secrets ||= begin secrets = ActiveSupport::OrderedOptions.new - yaml = config.paths["config/secrets"].first - - if File.exist?(yaml) - require "erb" - - all_secrets = YAML.load(ERB.new(IO.read(yaml)).result) || {} - shared_secrets = all_secrets["shared"] - env_secrets = all_secrets[Rails.env] - - secrets.merge!(shared_secrets.symbolize_keys) if shared_secrets - secrets.merge!(env_secrets.symbolize_keys) if env_secrets - end + files = config.paths["config/secrets"].existent + files = files.reject { |path| path.end_with?(".enc") } unless config.read_encrypted_secrets + secrets.merge! Rails::Secrets.parse(files, env: Rails.env) # Fallback to config.secret_key_base if secrets.secret_key_base isn't set secrets.secret_key_base ||= config.secret_key_base @@ -411,6 +402,33 @@ module Rails @secrets = secrets end + # The secret_key_base is used as the input secret to the application's key generator, which in turn + # is used to create all MessageVerifiers/MessageEncryptors, including the ones that sign and encrypt cookies. + # + # In test and development, this is simply derived as a MD5 hash of the application's name. + # + # In all other environments, we look for it first in ENV["SECRET_KEY_BASE"], + # then credentials.secret_key_base, and finally secrets.secret_key_base. For most applications, + # the correct place to store it is in the encrypted credentials file. + def secret_key_base + if Rails.env.test? || Rails.env.development? + Digest::MD5.hexdigest self.class.name + else + validate_secret_key_base \ + ENV["SECRET_KEY_BASE"] || credentials.secret_key_base || secrets.secret_key_base + end + end + + # Decrypts the credentials hash as kept in `config/credentials.yml.enc`. This file is encrypted with + # the Rails master key, which is either taken from ENV["RAILS_MASTER_KEY"] or from loading + # `config/master.key`. + def credentials + @credentials ||= ActiveSupport::EncryptedConfiguration.new \ + config_path: Rails.root.join("config/credentials.yml.enc"), + key_path: Rails.root.join("config/master.key"), + env_key: "RAILS_MASTER_KEY" + end + def to_app #:nodoc: self end @@ -446,7 +464,7 @@ module Rails def run_tasks_blocks(app) #:nodoc: railties.each { |r| r.run_tasks_blocks(app) } super - require "rails/tasks" + require_relative "tasks" task :environment do ActiveSupport.on_load(:before_initialize) { config.eager_load = false } @@ -509,14 +527,13 @@ module Rails default_stack.build_stack end - def validate_secret_key_config! #:nodoc: - if secrets.secret_key_base.blank? - ActiveSupport::Deprecation.warn "You didn't set `secret_key_base`. " + - "Read the upgrade documentation to learn more about this new config option." - - if secrets.secret_token.blank? - raise "Missing `secret_key_base` for '#{Rails.env}' environment, set this value in `config/secrets.yml`" - end + def validate_secret_key_base(secret_key_base) + if secret_key_base.is_a?(String) && secret_key_base.present? + secret_key_base + elsif secret_key_base + raise ArgumentError, "`secret_key_base` for #{Rails.env} environment must be a type of String`" + elsif secrets.secret_token.blank? + raise ArgumentError, "Missing `secret_key_base` for '#{Rails.env}' environment, set this string with `rails credentials:edit`" end end |