Class: Diffcrypt::Encryptor

Inherits:
Object
  • Object
show all
Defined in:
lib/diffcrypt/encryptor.rb

Constant Summary collapse

DEFAULT_CIPHER =
'aes-256-gcm'

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key, cipher: DEFAULT_CIPHER) ⇒ Encryptor



22
23
24
25
26
# File 'lib/diffcrypt/encryptor.rb', line 22

def initialize(key, cipher: DEFAULT_CIPHER)
  @key = key
  @cipher = cipher
  @encryptor ||= ActiveSupport::MessageEncryptor.new([key].pack('H*'), cipher: cipher)
end

Class Method Details

.generate_key(cipher = DEFAULT_CIPHER) ⇒ Object



18
19
20
# File 'lib/diffcrypt/encryptor.rb', line 18

def self.generate_key(cipher = DEFAULT_CIPHER)
  SecureRandom.hex(ActiveSupport::MessageEncryptor.key_len(cipher))
end

Instance Method Details

#decrypt(contents) ⇒ Object



29
30
31
32
33
# File 'lib/diffcrypt/encryptor.rb', line 29

def decrypt(contents)
  yaml = YAML.safe_load contents
  decrypted = decrypt_hash yaml['data']
  YAML.dump decrypted
end

#decrypt_hash(data) ⇒ Hash

rubocop:disable Metrics/MethodLength



38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/diffcrypt/encryptor.rb', line 38

def decrypt_hash(data)
  data.each do |key, value|
    data[key] = case value
                when Hash
                  decrypt_hash(value)
                when Array
                  value.map { |v| decrypt_hash(v) }
                else
                  decrypt_string value
                end
  end
  data
end

#decrypt_string(value) ⇒ String



105
106
107
# File 'lib/diffcrypt/encryptor.rb', line 105

def decrypt_string(value)
  @encryptor.decrypt_and_verify value
end

#encrypt(contents, original_encrypted_contents = nil, cipher: nil) ⇒ String



56
57
58
59
60
61
62
63
# File 'lib/diffcrypt/encryptor.rb', line 56

def encrypt(contents, original_encrypted_contents = nil, cipher: nil)
  data = encrypt_data contents, original_encrypted_contents
  YAML.dump(
    'client' => "diffcrypt-#{Diffcrypt::VERSION}",
    'cipher' => cipher || @cipher,
    'data' => data,
  )
end

#encrypt_data(contents, original_encrypted_contents = nil) ⇒ Hash



68
69
70
71
72
# File 'lib/diffcrypt/encryptor.rb', line 68

def encrypt_data(contents, original_encrypted_contents = nil)
  yaml = YAML.safe_load contents
  original_yaml = original_encrypted_contents ? YAML.safe_load(original_encrypted_contents)['data'] : nil
  encrypt_values yaml, original_yaml
end

#encrypt_string(value) ⇒ String



76
77
78
# File 'lib/diffcrypt/encryptor.rb', line 76

def encrypt_string(value)
  @encryptor.encrypt_and_sign value
end

#encrypt_values(data, original_data = nil) ⇒ Hash

TODO: Fix the complexity of this method rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/diffcrypt/encryptor.rb', line 84

def encrypt_values(data, original_data = nil)
  data.each do |key, value|
    original_encrypted_value = original_data&.dig(key)

    data[key] = case value
                when Hash
                  encrypt_values(value, original_encrypted_value)
                when Array
                  value.map.with_index { |v, i| encrypt_values(v, original_encrypted_value&.dig(i)) }
                else
                  original_decrypted_value = original_encrypted_value ? decrypt_string(original_encrypted_value) : nil
                  key_changed = original_decrypted_value.nil? || original_decrypted_value != value
                  key_changed ? encrypt_string(value) : original_encrypted_value
                end
  end
  data.sort.to_h
end