Skip to content

Commit c2901eb

Browse files
skipkayhilp8
andcommitted
Restore some config.secret_key_base functionality
The [deprecated secrets removal][1] ended up removing a bit of non-deprecated functionality related to config.secret_key_base: - the original implementation prioritized the value of config.secret_key_base over other sources in all environments - if unset, the value of config.secret_key_base would be updated to whichever fallback value was found The new implementation only sets config.secret_key_base to a fallback value when Rails.env.local?, and never considers it at all in production. This commit aims to restore this missing functionality as well as simplify the implementation: - Rails.application.secret_key_base now always delegates to config.secret_key_base (like the pre-secret-removal implementation) - secret_key_base validation was moved from the reader to the writer - config.secret_key_base now handles setting itself to a fallback value when unset - In addition, generate_local_secret was simplified because it previously did 3 things: file manipulation, setting config.secret_key_base, and returning a value. Now it only creates the file if necessary and returns the value stored in it The new implementation has an additional benefit, which is that manually set config.secret_key_base values are now validated, whereas previously only fallback values were validated. [1]: 0c76f17 Co-authored-by: Petrik <[email protected]>
1 parent 8d416d0 commit c2901eb

File tree

3 files changed

+38
-38
lines changed

3 files changed

+38
-38
lines changed

railties/lib/rails/application.rb

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -462,13 +462,7 @@ def config # :nodoc:
462462
# then +credentials.secret_key_base+. For most applications, the correct place to store it is in the
463463
# encrypted credentials file.
464464
def secret_key_base
465-
if Rails.env.local? || ENV["SECRET_KEY_BASE_DUMMY"]
466-
config.secret_key_base ||= generate_local_secret
467-
else
468-
validate_secret_key_base(
469-
ENV["SECRET_KEY_BASE"] || credentials.secret_key_base
470-
)
471-
end
465+
config.secret_key_base
472466
end
473467

474468
# Returns an ActiveSupport::EncryptedConfiguration instance for the
@@ -621,39 +615,12 @@ def default_middleware_stack # :nodoc:
621615
default_stack.build_stack
622616
end
623617

624-
def validate_secret_key_base(secret_key_base)
625-
if secret_key_base.is_a?(String) && secret_key_base.present?
626-
secret_key_base
627-
elsif secret_key_base
628-
raise ArgumentError, "`secret_key_base` for #{Rails.env} environment must be a type of String`"
629-
else
630-
raise ArgumentError, "Missing `secret_key_base` for '#{Rails.env}' environment, set this string with `bin/rails credentials:edit`"
631-
end
632-
end
633-
634618
def ensure_generator_templates_added
635619
configured_paths = config.generators.templates
636620
configured_paths.unshift(*(paths["lib/templates"].existent - configured_paths))
637621
end
638622

639623
private
640-
def generate_local_secret
641-
if config.secret_key_base.nil?
642-
key_file = Rails.root.join("tmp/local_secret.txt")
643-
644-
if File.exist?(key_file)
645-
config.secret_key_base = File.binread(key_file)
646-
else
647-
random_key = SecureRandom.hex(64)
648-
FileUtils.mkdir_p(key_file.dirname)
649-
File.binwrite(key_file, random_key)
650-
config.secret_key_base = File.binread(key_file)
651-
end
652-
end
653-
654-
config.secret_key_base
655-
end
656-
657624
def build_request(env)
658625
req = super
659626
env["ORIGINAL_FULLPATH"] = req.fullpath

railties/lib/rails/application/configuration.rb

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class Configuration < ::Rails::Engine::Configuration
1515
:cache_classes, :cache_store, :consider_all_requests_local, :console,
1616
:eager_load, :exceptions_app, :file_watcher, :filter_parameters, :precompile_filter_parameters,
1717
:force_ssl, :helpers_paths, :hosts, :host_authorization, :logger, :log_formatter,
18-
:log_tags, :railties_order, :relative_url_root, :secret_key_base,
18+
:log_tags, :railties_order, :relative_url_root,
1919
:ssl_options, :public_file_server,
2020
:session_options, :time_zone, :reload_classes_only_on_change,
2121
:beginning_of_week, :filter_redirect, :x,
@@ -500,6 +500,26 @@ def colorize_logging=(val)
500500
generators.colorize_logging = val
501501
end
502502

503+
def secret_key_base
504+
@secret_key_base || begin
505+
self.secret_key_base = if Rails.env.local? || ENV["SECRET_KEY_BASE_DUMMY"]
506+
generate_local_secret
507+
else
508+
ENV["SECRET_KEY_BASE"] || Rails.application.credentials.secret_key_base
509+
end
510+
end
511+
end
512+
513+
def secret_key_base=(new_secret_key_base)
514+
if new_secret_key_base.is_a?(String) && new_secret_key_base.present?
515+
@secret_key_base = new_secret_key_base
516+
elsif new_secret_key_base
517+
raise ArgumentError, "`secret_key_base` for #{Rails.env} environment must be a type of String`"
518+
else
519+
raise ArgumentError, "Missing `secret_key_base` for '#{Rails.env}' environment, set this string with `bin/rails credentials:edit`"
520+
end
521+
end
522+
503523
# Specifies what class to use to store the session. Possible values
504524
# are +:cache_store+, +:cookie_store+, +:mem_cache_store+, a custom
505525
# store, or +:disabled+. +:disabled+ tells \Rails not to deal with
@@ -605,6 +625,18 @@ def credentials_defaults
605625

606626
{ content_path: content_path, key_path: key_path }
607627
end
628+
629+
def generate_local_secret
630+
key_file = root.join("tmp/local_secret.txt")
631+
632+
unless File.exist?(key_file)
633+
random_key = SecureRandom.hex(64)
634+
FileUtils.mkdir_p(key_file.dirname)
635+
File.binwrite(key_file, random_key)
636+
end
637+
638+
File.binread(key_file)
639+
end
608640
end
609641
end
610642
end

railties/test/application/configuration_test.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -919,7 +919,7 @@ def index
919919
end
920920

921921

922-
test "secret_key_base is copied from config.secret_key_base when set" do
922+
test "app.secret_key_base uses config.secret_key_base in development" do
923923
app_file "config/initializers/secret_token.rb", <<-RUBY
924924
Rails.application.config.secret_key_base = "3b7cd727ee24e8444053437c36cc66c3"
925925
RUBY
@@ -928,12 +928,13 @@ def index
928928
assert_equal "3b7cd727ee24e8444053437c36cc66c3", app.secret_key_base
929929
end
930930

931-
test "config.secret_key_base over-writes a blank app.secret_key_base" do
931+
test "app.secret_key_base uses config.secret_key_base in production" do
932+
remove_file "config/credentials.yml.enc"
932933
app_file "config/initializers/secret_token.rb", <<-RUBY
933934
Rails.application.config.secret_key_base = "iaminallyoursecretkeybase"
934935
RUBY
935936

936-
app "development"
937+
app "production"
937938

938939
assert_equal "iaminallyoursecretkeybase", app.secret_key_base
939940
end

0 commit comments

Comments
 (0)