Class: SymmetricEncryption::Utils::ReEncryptFiles

Inherits:
Object
  • Object
show all
Defined in:
lib/symmetric_encryption/utils/re_encrypt_files.rb

Overview

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"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(version: SymmetricEncryption.cipher.version) ⇒ ReEncryptFiles

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 )

Raises:

  • (ArgumentError)


34
35
36
37
38
# 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

Instance Attribute Details

#cipherObject

Returns the value of attribute cipher.



28
29
30
# File 'lib/symmetric_encryption/utils/re_encrypt_files.rb', line 28

def cipher
  @cipher
end

#versionObject

Returns the value of attribute version.



28
29
30
# File 'lib/symmetric_encryption/utils/re_encrypt_files.rb', line 28

def version
  @version
end

Instance Method Details

#process_directory(path) ⇒ Object

Process a directory of files.

Parameters:

path: [String]
  Search path to look for files in.
  Example: '../../**/*.yml'


105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# 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) ⇒ Object

Re-encrypt the supplied encrypted value with the new cipher



41
42
43
44
45
46
47
# 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) ⇒ Object

Process a single file.

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



52
53
54
55
56
57
58
59
60
# 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) ⇒ Object

Re Encrypt an entire file



87
88
89
90
91
92
93
94
95
96
97
# 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) ⇒ Object

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



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# 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