lib/symmetric_encryption/config.rb in symmetric-encryption-3.9.1 vs lib/symmetric_encryption/config.rb in symmetric-encryption-4.0.0.beta3
- old
+ new
@@ -1,74 +1,96 @@
+require 'erb'
+require 'yaml'
module SymmetricEncryption
- module Config
- # Load the Encryption Configuration from a YAML file
- # filename:
- # Name of file to read.
- # Mandatory for non-Rails apps
- # Default: Rails.root/config/symmetric-encryption.yml
- # environment:
- # Which environments config to load. Usually: production, development, etc.
- # Default: Rails.env
- def self.load!(filename=nil, environment=nil)
- config = read_config(filename, environment)
- ciphers = extract_ciphers(config)
+ class Config
+ attr_reader :file_name, :env
+ # 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'
+ 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
- private
+ # Reads the entire configuration for all environments from the supplied file name.
+ 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
- # Returns [Hash] the configuration for the supplied environment
- def self.read_config(filename=nil, environment=nil)
- config_filename = filename || File.join(Rails.root, 'config', 'symmetric-encryption.yml')
- cfg = YAML.load(ERB.new(File.new(config_filename).read).result)[environment || Rails.env]
- extract_config(cfg)
+ # Write the entire configuration for all environments to the supplied file name.
+ def self.write_file(file_name, config)
+ config = deep_stringify_keys(config)
+ 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
- # Returns [ private_rsa_key, ciphers ] config
- def self.extract_config(config)
- config = deep_symbolize_keys(config)
+ # Load the Encryption Configuration from a YAML file.
+ #
+ # See: `.load!` for parameters.
+ def initialize(file_name: nil, env: nil)
+ unless env
+ env = defined?(Rails) ? Rails.env : ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development'
+ end
- # Old format?
- unless config.has_key?(:ciphers)
- config = {
- private_rsa_key: config.delete(:private_rsa_key),
- ciphers: [config]
- }
+ 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
- # Old format cipher name?
- config[:ciphers] = config[:ciphers].collect do |cipher|
- if old_key_name_cipher = cipher.delete(:cipher)
- cipher[:cipher_name] = old_key_name_cipher
+ @env = env
+ @file_name = file_name
+ end
+
+ # Returns [Hash] the configuration for the supplied environment.
+ def config
+ @config ||= begin
+ raise(ConfigError, "Cannot find config file: #{file_name}") unless File.exist?(file_name)
+ unless env_config = YAML.load(ERB.new(File.new(file_name).read).result)[env]
+ raise(ConfigError, "Cannot find environment: #{env} in config file: #{file_name}")
end
- cipher
+ env_config = self.class.deep_symbolize_keys(env_config)
+ self.class.migrate_old_formats!(env_config)
end
- config
end
- # Returns [Array(SymmetricEncrytion::Cipher)] ciphers specified in the configuration file
- #
- # Read the configuration from the YAML file and return in the latest format
- #
- # filename:
- # Name of file to read.
- # Mandatory for non-Rails apps
- # Default: Rails.root/config/symmetric-encryption.yml
- # environment:
- # Which environments config to load. Usually: production, development, etc.
- def self.extract_ciphers(config)
- private_rsa_key = config[:private_rsa_key]
-
- config[:ciphers].collect do |cipher_config|
- Cipher.new({private_rsa_key: private_rsa_key}.merge(cipher_config))
- end
+ # Returns [Array(SymmetricEncrytion::Cipher)] ciphers specified in the configuration file.
+ def ciphers
+ @ciphers ||= config[:ciphers].collect { |cipher_config| Cipher.from_config(cipher_config) }
end
- # Iterate through the Hash symbolizing all keys
+ private
+
+ # Iterate through the Hash symbolizing all keys.
def self.deep_symbolize_keys(x)
case x
when Hash
result = {}
x.each_pair do |key, value|
@@ -79,9 +101,65 @@
when Array
x.collect { |i| deep_symbolize_keys(i) }
else
x
end
+ end
+
+ # Iterate through the Hash symbolizing all keys.
+ def self.deep_stringify_keys(x)
+ case x
+ when Hash
+ result = {}
+ x.each_pair do |key, value|
+ key = key.to_s if key.is_a?(Symbol)
+ result[key] = deep_stringify_keys(value)
+ end
+ result
+ when Array
+ x.collect { |i| deep_stringify_keys(i) }
+ else
+ x
+ end
+ end
+
+ # Migrate old configuration format for this environment
+ def self.migrate_old_formats!(config)
+ # Inline single cipher before :ciphers
+ unless config.has_key?(:ciphers)
+ cipher = {}
+ config.keys.each { |key| cipher[key] = config.delete(key) }
+ config[:ciphers] = [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
+ if cipher[:key_encrypting_key].is_a?(String)
+ cipher[:private_rsa_key] = cipher.delete(:key_encrypting_key)
+ end
+
+ # Check for a prior env var in encrypted key
+ # Example:
+ # encrypted_key: <%= ENV['VAR'] %>
+ if cipher.has_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
end
end