class SymmetricEncryption::Utils::ReEncryptFiles

ReEncrypt files

If a file is encrypted, it is re-encrypted with the cipher that has the highest version number.
A file that is already encrypted with the specified key version is not re-encrypted.
If an encrypted value cannot be decypted in the current environment it is left unmodified.

If a file is not encrypted, the file is searched for any encrypted values, and those values are re-encrypted.

symmetric_encryption --reencrypt "**/*.yml"

Attributes

cipher[RW]
version[RW]

Public Class Methods

new(version: SymmetricEncryption.cipher.version) click to toggle source

Parameters:

version: [Integer]
  Version of the encryption key to use when re-encrypting the value.
  Default: Default cipher ( first in the list of configured ciphers )
# File lib/symmetric_encryption/utils/re_encrypt_files.rb, line 34
def initialize(version: SymmetricEncryption.cipher.version)
  @version = version || SymmetricEncryption.cipher.version
  @cipher  = SymmetricEncryption.cipher(@version)
  raise(ArgumentError, "Undefined encryption key version: #{version}") if @cipher.nil?
end

Public Instance Methods

process_directory(path) click to toggle source

Process a directory of files.

Parameters:

path: [String]
  Search path to look for files in.
  Example: '../../**/*.yml'
# File lib/symmetric_encryption/utils/re_encrypt_files.rb, line 105
def process_directory(path)
  Dir[path].each do |file_name|
    next if File.directory?(file_name)

    if (v = encrypted_file_version(file_name))
      if v == version
        puts "Skipping already re-encrypted file: #{file_name}"
      else
        puts "Re-encrypting entire file: #{file_name}"
        re_encrypt_file(file_name)
      end
    else
      begin
        count = re_encrypt_contents(file_name)
        puts "Re-encrypted #{count} encrypted value(s) in: #{file_name}" if count.positive?
      rescue StandardError => e
        puts "Failed re-encrypting the file contents of: #{file_name}. #{e.class.name}: #{e.message}"
      end
    end
  end
end
re_encrypt(encrypted) click to toggle source

Re-encrypt the supplied encrypted value with the new cipher

# File lib/symmetric_encryption/utils/re_encrypt_files.rb, line 41
def re_encrypt(encrypted)
  if (unencrypted = SymmetricEncryption.try_decrypt(encrypted))
    cipher.encrypt(unencrypted)
  else
    encrypted
  end
end
re_encrypt_contents(file_name) click to toggle source

Process a single file.

Returns [Integer] number of encrypted values re-encrypted.

# File lib/symmetric_encryption/utils/re_encrypt_files.rb, line 52
def re_encrypt_contents(file_name)
  return 0 if File.size(file_name) > 256 * 1024

  lines              = File.read(file_name)
  hits, output_lines = re_encrypt_lines(lines)

  File.open(file_name, "wb") { |file| file.write(output_lines) } if hits.positive?
  hits
end
re_encrypt_file(file_name) click to toggle source

Re Encrypt an entire file

# File lib/symmetric_encryption/utils/re_encrypt_files.rb, line 87
def re_encrypt_file(file_name)
  temp_file_name = "__re_encrypting_#{file_name}"
  SymmetricEncryption::Reader.open(file_name) do |source|
    SymmetricEncryption::Writer.encrypt(source: source, target: temp_file_name, compress: true, version: version)
  end
  File.delete(file_name)
  File.rename(temp_file_name, file_name)
rescue StandardError
  File.delete(temp_file_name) if temp_file_name && File.exist?(temp_file_name)
  raise
end
re_encrypt_lines(lines) click to toggle source

Replaces instances of encrypted data within lines of text with re-encrypted values

# File lib/symmetric_encryption/utils/re_encrypt_files.rb, line 63
def re_encrypt_lines(lines)
  hits         = 0
  output_lines = ""
  r            = regexp
  lines.each_line do |line|
    line.force_encoding(SymmetricEncryption::UTF8_ENCODING)
    output_lines <<
      if line.valid_encoding? && (result = line.match(r))
        encrypted = result[0]
        new_value = re_encrypt(encrypted)
        if new_value == encrypted
          line
        else
          hits += 1
          line.gsub(encrypted, new_value)
        end
      else
        line
      end
  end
  [hits, output_lines]
end

Private Instance Methods

encrypted_file_version(file_name) click to toggle source

Returns [Integer] encrypted file key version. Returns [nil] if the file is not encrypted or does not have a header.

# File lib/symmetric_encryption/utils/re_encrypt_files.rb, line 135
def encrypted_file_version(file_name)
  ::File.open(file_name, "rb") do |file|
    reader = SymmetricEncryption::Reader.new(file)
    reader.version if reader.header_present?
  end
rescue OpenSSL::Cipher::CipherError
  nil
end
regexp() click to toggle source
# File lib/symmetric_encryption/utils/re_encrypt_files.rb, line 129
def regexp
  @regexp ||= %r{#{SymmetricEncryption.cipher.encoded_magic_header}([A-Za-z0-9+/]+[=\\n]*)}
end