class Diffcrypt::Rails::EncryptedConfiguration
Attributes
Public Class Methods
# File lib/diffcrypt/rails/encrypted_configuration.rb, line 25 def initialize(config_path:, key_path:, env_key:, raise_if_missing_key:) @content_path = Pathname.new(::File.absolute_path(config_path)).yield_self do |path| path.symlink? ? path.realpath : path end @diffcrypt_file = Diffcrypt::File.new(@content_path) @key_path = Pathname.new(key_path) @env_key = env_key @raise_if_missing_key = raise_if_missing_key end
Public Instance Methods
# File lib/diffcrypt/rails/encrypted_configuration.rb, line 69 def change(&block) writing read, &block end
# File lib/diffcrypt/rails/encrypted_configuration.rb, line 59 def config @config ||= deserialize(read).deep_symbolize_keys end
Determines if file is using the diffable format, or still encrypted using default rails credentials format @return [Boolean]
# File lib/diffcrypt/rails/encrypted_configuration.rb, line 38 def content_path_diffable? content_path.binread.index('---')&.zero? end
@raise [MissingKeyError] Will raise if key is not set @return [String]
# File lib/diffcrypt/rails/encrypted_configuration.rb, line 65 def key read_env_key || read_key_file || handle_missing_key end
Allow a config to be started without a file present @return [String] Returns decryped content or a blank string
# File lib/diffcrypt/rails/encrypted_configuration.rb, line 44 def read raise MissingContentError, content_path unless !key.nil? && content_path.exist? decrypt content_path.binread rescue MissingContentError '' end
# File lib/diffcrypt/rails/encrypted_configuration.rb, line 52 def write(contents, original_encrypted_contents = nil) deserialize(contents) IO.binwrite "#{content_path}.tmp", encrypt(contents, original_encrypted_contents) ::FileUtils.mv "#{content_path}.tmp", content_path end
Protected Instance Methods
Rails
applications with an existing credentials file, the inbuilt active support encryptor should be used @return [ActiveSupport::MessageEncryptor]
# File lib/diffcrypt/rails/encrypted_configuration.rb, line 117 def active_support_encryptor @active_support_encryptor ||= ActiveSupport::MessageEncryptor.new( [key].pack('H*'), cipher: 'aes-128-gcm', ) end
@param [String] contents @return [String]
# File lib/diffcrypt/rails/encrypted_configuration.rb, line 107 def decrypt(contents) if rails_native_credentials?(contents) active_support_encryptor.decrypt_and_verify contents else encryptor.decrypt contents end end
# File lib/diffcrypt/rails/encrypted_configuration.rb, line 147 def deserialize(config) YAML.safe_load(config).presence || {} end
@param [String] contents The new content to be encrypted @param [String] diff_against The original (encrypted) content to determine which keys have changed @return [String] Encrypted content to commit
# File lib/diffcrypt/rails/encrypted_configuration.rb, line 101 def encrypt(contents, original_encrypted_contents = nil) encryptor.encrypt contents, original_encrypted_contents end
@return [Encryptor]
# File lib/diffcrypt/rails/encrypted_configuration.rb, line 125 def encryptor @encryptor ||= Encryptor.new key, cipher: @diffcrypt_file.cipher end
@raise [MissingKeyError] @return [void]
# File lib/diffcrypt/rails/encrypted_configuration.rb, line 139 def handle_missing_key raise MissingKeyError.new(key_path: key_path, env_key: env_key) if raise_if_missing_key end
# File lib/diffcrypt/rails/encrypted_configuration.rb, line 143 def options @options ||= ActiveSupport::InheritableOptions.new(config) end
Standard rails credentials encrypt the entire file. We need to detect this to use the correct data interface @return [Boolean]
# File lib/diffcrypt/rails/encrypted_configuration.rb, line 94 def rails_native_credentials?(contents) contents.index('---').nil? end
# File lib/diffcrypt/rails/encrypted_configuration.rb, line 129 def read_env_key ENV[env_key] end
# File lib/diffcrypt/rails/encrypted_configuration.rb, line 133 def read_key_file key_path.binread.strip if key_path.exist? end
rubocop:disable Metrics/AbcSize
# File lib/diffcrypt/rails/encrypted_configuration.rb, line 76 def writing(contents) tmp_file = "#{Process.pid}.#{content_path.basename.to_s.chomp('.enc')}" tmp_path = Pathname.new ::File.join(Dir.tmpdir, tmp_file) tmp_path.binwrite contents yield tmp_path updated_contents = tmp_path.binread write(updated_contents, content_path_diffable? && content_path.binread) ensure ::FileUtils.rm(tmp_path) if tmp_path&.exist? end