BigW Consortium Gitlab

secret_token.rb 2.84 KB
Newer Older
gitlabhq committed
1 2
# Be sure to restart your server when you modify this file.

3 4
require 'securerandom'

5 6 7 8 9 10 11 12 13 14 15
# Transition material in .secret to the secret_key_base key in config/secrets.yml.
# Historically, ENV['SECRET_KEY_BASE'] takes precedence over .secret, so we maintain that
# behavior.
#
# It also used to be the case that the key material in ENV['SECRET_KEY_BASE'] or .secret
# was used to encrypt OTP (two-factor authentication) data so if present, we copy that key
# material into config/secrets.yml under otp_key_base.
#
# Finally, if we have successfully migrated all secrets to config/secrets.yml, delete the
# .secret file to avoid confusion.
#
16 17
def create_tokens
  secret_file = Rails.root.join('.secret')
18 19
  file_secret_key = File.read(secret_file).chomp if File.exist?(secret_file)
  env_secret_key = ENV['SECRET_KEY_BASE']
20

21
  # Ensure environment variable always overrides secrets.yml.
22
  Rails.application.secrets.secret_key_base = env_secret_key if env_secret_key.present?
23

24
  defaults = {
25 26
    secret_key_base: file_secret_key || generate_new_secure_token,
    otp_key_base: env_secret_key || file_secret_key || generate_new_secure_token,
27 28
    db_key_base: generate_new_secure_token
  }
29

30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
  missing_secrets = set_missing_keys(defaults)
  write_secrets_yml(missing_secrets) unless missing_secrets.empty?

  begin
    File.delete(secret_file) if file_secret_key
  rescue => e
    warn "Error deleting useless .secret file: #{e}"
  end
end

def generate_new_secure_token
  SecureRandom.hex(64)
end

def warn_missing_secret(secret)
  warn "Missing Rails.application.secrets.#{secret} for #{Rails.env} environment. The secret will be generated and stored in config/secrets.yml."
end

def set_missing_keys(defaults)
  defaults.stringify_keys.each_with_object({}) do |(key, default), missing|
50 51
    if Rails.application.secrets[key].blank?
      warn_missing_secret(key)
52

53
      missing[key] = Rails.application.secrets[key] = default
54
    end
55
  end
56
end
57

58 59 60 61 62 63 64 65 66 67 68 69 70 71
def write_secrets_yml(missing_secrets)
  secrets_yml = Rails.root.join('config/secrets.yml')
  rails_env = Rails.env.to_s
  secrets = YAML.load_file(secrets_yml) if File.exist?(secrets_yml)
  secrets ||= {}
  secrets[rails_env] ||= {}

  secrets[rails_env].merge!(missing_secrets) do |key, old, new|
    # Previously, it was possible this was set to the literal contents of an Erb
    # expression that evaluated to an empty value. We don't want to support that
    # specifically, just ensure we don't break things further.
    #
    if old.present?
      warn <<EOM
72 73 74 75 76 77
Rails.application.secrets.#{key} was blank, but the literal value in config/secrets.yml was:
  #{old}

This probably isn't the expected value for this secret. To keep using a literal Erb string in config/secrets.yml, replace `<%` with `<%%`.
EOM

78
      exit 1 # rubocop:disable Rails/Exit
79
    end
80

81
    new
82
  end
83

84
  File.write(secrets_yml, YAML.dump(secrets), mode: 'w', perm: 0600)
85
end
86 87

create_tokens