class SymmetricEncryption::Config

Attributes

env[R]
file_name[R]

Public Class Methods

load!(file_name: nil, env: nil) click to toggle source

Load the Encryption Configuration from a YAML file.

file_name:
  Name of configuration file.
  Default: "#{Rails.root}/config/symmetric-encryption.yml"
  Note:
    The Symmetric Encryption config file name can also be set using the `SYMMETRIC_ENCRYPTION_CONFIG`
    environment variable.

env:
  Which environments config to load. Usually: production, development, etc.
  Non-Rails apps can set env vars: RAILS_ENV, or RACK_ENV
  Default: Rails.env || ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development'
# File lib/symmetric_encryption/config.rb, line 20
def self.load!(file_name: nil, env: nil)
  config                                = new(file_name: file_name, env: env)
  ciphers                               = config.ciphers
  SymmetricEncryption.cipher            = ciphers.shift
  SymmetricEncryption.secondary_ciphers = ciphers
  true
end
new(file_name: nil, env: nil) click to toggle source

Load the Encryption Configuration from a YAML file.

See: `.load!` for parameters.

# File lib/symmetric_encryption/config.rb, line 54
def initialize(file_name: nil, env: nil)
  env ||= defined?(Rails) ? Rails.env : ENV["RACK_ENV"] || ENV["RAILS_ENV"] || "development"

  unless file_name
    root      = defined?(Rails) ? Rails.root : "."
    file_name =
      if (env_var = ENV["SYMMETRIC_ENCRYPTION_CONFIG"])
        File.expand_path(env_var)
      else
        File.join(root, "config", "symmetric-encryption.yml")
      end
    raise(ConfigError, "Cannot find config file: #{file_name}") unless File.exist?(file_name)
  end

  @env       = env
  @file_name = file_name
end
read_file(file_name) click to toggle source

Reads the entire configuration for all environments from the supplied file name.

# File lib/symmetric_encryption/config.rb, line 29
def self.read_file(file_name)
  config = YAML.load(ERB.new(File.new(file_name).read).result)
  config = deep_symbolize_keys(config)
  config.each_pair { |_env, cfg| SymmetricEncryption::Config.send(:migrate_old_formats!, cfg) }
  config
end
write_file(file_name, config) click to toggle source

Write the entire configuration for all environments to the supplied file name.

# File lib/symmetric_encryption/config.rb, line 37
def self.write_file(file_name, config)
  config = deep_stringify_keys(config)

  FileUtils.mkdir_p(File.dirname(file_name))
  File.open(file_name, "w") do |f|
    f.puts "# This file was auto generated by symmetric-encryption."
    f.puts "# Recommend using symmetric-encryption to make changes."
    f.puts "# For more info, run:"
    f.puts "#   symmetric-encryption --help"
    f.puts "#"
    f.write(config.to_yaml)
  end
end

Private Class Methods

deep_stringify_keys(object) click to toggle source

Iterate through the Hash symbolizing all keys.

# File lib/symmetric_encryption/config.rb, line 111
def self.deep_stringify_keys(object)
  case object
  when Hash
    result = {}
    object.each_pair do |key, value|
      key         = key.to_s if key.is_a?(Symbol)
      result[key] = deep_stringify_keys(value)
    end
    result
  when Array
    object.collect { |i| deep_stringify_keys(i) }
  else
    object
  end
end
deep_symbolize_keys(object) click to toggle source

Iterate through the Hash symbolizing all keys.

# File lib/symmetric_encryption/config.rb, line 92
def self.deep_symbolize_keys(object)
  case object
  when Hash
    result = {}
    object.each_pair do |key, value|
      key         = key.to_sym if key.is_a?(String)
      result[key] = deep_symbolize_keys(value)
    end
    result
  when Array
    object.collect { |i| deep_symbolize_keys(i) }
  else
    object
  end
end
migrate_old_formats!(config) click to toggle source

Migrate old configuration format for this environment

# File lib/symmetric_encryption/config.rb, line 130
def self.migrate_old_formats!(config)
  # Inline single cipher before :ciphers
  unless config.key?(:ciphers)
    inline_cipher = {}
    config.keys.each { |key| inline_cipher[key] = config.delete(key) }
    config[:ciphers] = [inline_cipher]
  end

  # Copy Old :private_rsa_key into each ciphers config
  # Cipher.from_config replaces it with the RSA Kek
  if config[:private_rsa_key]
    private_rsa_key = config.delete(:private_rsa_key)
    config[:ciphers].each { |cipher| cipher[:private_rsa_key] = private_rsa_key }
  end

  # Old :cipher_name
  config[:ciphers].each do |cipher|
    if (old_key_name_cipher = cipher.delete(:cipher))
      cipher[:cipher_name] = old_key_name_cipher
    end

    # Only temporarily used during v4 Beta process
    cipher[:private_rsa_key] = cipher.delete(:key_encrypting_key) if cipher[:key_encrypting_key].is_a?(String)

    # Check for a prior env var in encrypted key
    # Example:
    #   encrypted_key: <%= ENV['VAR'] %>
    if cipher.key?(:encrypted_key) && cipher[:encrypted_key].nil?
      cipher[:key_env_var] = :placeholder
      puts "WARNING: :encrypted_key resolved to nil. Please see the migrated config file for the new option :key_env_var."
    end
  end
  config
end

Public Instance Methods

ciphers() click to toggle source

Returns [Array(SymmetricEncryption::Cipher)] ciphers specified in the configuration file.

# File lib/symmetric_encryption/config.rb, line 87
def ciphers
  @ciphers ||= config[:ciphers].collect { |cipher_config| Cipher.from_config(**cipher_config) }
end
config() click to toggle source

Returns [Hash] the configuration for the supplied environment.

# File lib/symmetric_encryption/config.rb, line 73
def config
  @config ||=
    begin
      raise(ConfigError, "Cannot find config file: #{file_name}") unless File.exist?(file_name)

      env_config = YAML.load(ERB.new(File.new(file_name).read).result)[env]
      raise(ConfigError, "Cannot find environment: #{env} in config file: #{file_name}") unless env_config

      env_config = self.class.send(:deep_symbolize_keys, env_config)
      self.class.send(:migrate_old_formats!, env_config)
    end
end