Skip to content

Commit 39c4ca2

Browse files
Fix arrays (#4)
* Fix encryption/decryption of arrays * Add subitems to specs * Remove pp * Diff arrays correctly * PR comments * Fix test versions --------- Co-authored-by: Matjaz Kavcic <[email protected]>
1 parent 8b854c2 commit 39c4ca2

File tree

2 files changed

+36
-6
lines changed

2 files changed

+36
-6
lines changed

lib/diffcrypt/encryptor.rb

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,21 @@ def decrypt(contents)
3434

3535
# @param [Hash] data
3636
# @return [Hash]
37+
# rubocop:disable Metrics/MethodLength
3738
def decrypt_hash(data)
3839
data.each do |key, value|
39-
data[key] = if value.is_a?(Hash) || value.is_a?(Array)
40+
data[key] = case value
41+
when Hash
4042
decrypt_hash(value)
43+
when Array
44+
value.map { |v| decrypt_hash(v) }
4145
else
4246
decrypt_string value
4347
end
4448
end
4549
data
4650
end
51+
# rubocop:enable Metrics/MethodLength
4752

4853
# @param [String] contents The raw YAML string to be encrypted
4954
# @param [String, nil] original_encrypted_contents The original (encrypted) content to determine which keys have changed
@@ -73,14 +78,18 @@ def encrypt_string(value)
7378
end
7479

7580
# TODO: Fix the complexity of this method
76-
# rubocop:disable Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/CyclomaticComplexity
81+
# rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
7782
# @param [Hash] keys
7883
# @return [Hash]
7984
def encrypt_values(data, original_data = nil)
8085
data.each do |key, value|
81-
original_encrypted_value = original_data ? original_data[key] : nil
82-
data[key] = if value.is_a?(Hash) || value.is_a?(Array)
86+
original_encrypted_value = original_data&.dig(key)
87+
88+
data[key] = case value
89+
when Hash
8390
encrypt_values(value, original_encrypted_value)
91+
when Array
92+
value.map.with_index { |v, i| encrypt_values(v, original_encrypted_value&.dig(i)) }
8493
else
8594
original_decrypted_value = original_encrypted_value ? decrypt_string(original_encrypted_value) : nil
8695
key_changed = original_decrypted_value.nil? || original_decrypted_value != value
@@ -89,7 +98,7 @@ def encrypt_values(data, original_data = nil)
8998
end
9099
data.sort.to_h
91100
end
92-
# rubocop:enable Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/CyclomaticComplexity
101+
# rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
93102

94103
# @param [String] value The encrypted value that needs decrypting
95104
# @return [String]

test/diffcrypt/encryptor_test.rb

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,21 @@ def test_it_encrypts_root_values
4646
def test_it_decrypts_nested_structures
4747
encrypted_content = <<~CONTENT
4848
data:
49+
array:
50+
- item1: 7HJjrwQ6KqH+jvu1pOZGqQ==--E2ipnCNCszD6oixM--QZapG/8wrPtwbUVDe9evsw==
51+
subitem: oNNLBGwL45VvOv7elkRTHZTcNQ==--iFBc53R3F26zsvTK--6iEtqH7TR7TSS6fJOHwfPg==
52+
- item2: IvwdxcAV+38MvNsKYdNCEg==--6y7Aj4nmFLOTGrx3--rRH8ni3yks2eid91jde2hg==
4953
secret_key_base: 88Ry6HESUoXBr6QUFXmni9zzfCIYt9qGNFvIWFcN--4xoecI5mqbNRBibI--62qPJbkzzh5h8lhFEFOSaQ==
5054
aws:
5155
access_key_id: Ot/uCTEL+8kp61EPctnxNlg=--Be6sg7OdvjZlfxgR--7qRbbf0lA4VgjnUGUrrFwg==
56+
5257
CONTENT
5358
expected = <<~CONTENT
5459
---
60+
array:
61+
- item1: value1
62+
subitem: value sub
63+
- item2: value2
5564
secret_key_base: secret_key_base_test
5665
aws:
5766
access_key_id: AKIAXXX
@@ -66,8 +75,12 @@ def test_it_encrypts_nested_structures
6675
secret_key_base: secret_key_base_test
6776
aws:
6877
access_key_id: AKIAXXX
78+
array:
79+
- item1: value1
80+
subitem: value sub
81+
- item2: value2
6982
CONTENT
70-
expected_pattern = /---\naws:\n access_key_id: #{ENCRYPTED_VALUE_PATTERN}\nsecret_key_base: #{ENCRYPTED_VALUE_PATTERN}\n/
83+
expected_pattern = /---\narray:\n- item1: #{ENCRYPTED_VALUE_PATTERN}\n subitem: #{ENCRYPTED_VALUE_PATTERN}\n- item2: #{ENCRYPTED_VALUE_PATTERN}\naws:\n access_key_id: #{ENCRYPTED_VALUE_PATTERN}\nsecret_key_base: #{ENCRYPTED_VALUE_PATTERN}/
7184

7285
assert_match expected_pattern, Diffcrypt::Encryptor.new(TEST_KEY_128, cipher: 'aes-128-gcm').encrypt_data(content).to_yaml
7386
end
@@ -82,6 +95,14 @@ def test_it_only_updates_changed_values
8295
assert_match expected_pattern, Diffcrypt::Encryptor.new(TEST_KEY_128, cipher: 'aes-128-gcm').encrypt_data(updated_content, original_encrypted_content).to_yaml
8396
end
8497

98+
def test_it_only_updates_changed_values_for_arrays
99+
original_encrypted_content = "---\ndata:\n array:\n - item1: 7HJjrwQ6KqH+jvu1pOZGqQ==--E2ipnCNCszD6oixM--QZapG/8wrPtwbUVDe9evsw==\n - item2: IvwdxcAV+38MvNsKYdNCEg==--6y7Aj4nmFLOTGrx3--rRH8ni3yks2eid91jde2hg==\n"
100+
updated_content = "---\narray:\n - item1: value1\n - item2: value2"
101+
expected_pattern = %r{---\narray:\n- item1: 7HJjrwQ6KqH\+jvu1pOZGqQ==--E2ipnCNCszD6oixM--QZapG/8wrPtwbUVDe9evsw==\n- item2: IvwdxcAV\+38MvNsKYdNCEg==--6y7Aj4nmFLOTGrx3--rRH8ni3yks2eid91jde2hg==\n}
102+
103+
assert_match expected_pattern, Diffcrypt::Encryptor.new(TEST_KEY_128, cipher: 'aes-128-gcm').encrypt_data(updated_content, original_encrypted_content).to_yaml
104+
end
105+
85106
def test_it_assumes_changed_when_no_original_value
86107
original_encrypted_content = "---\ndata:\n secret_key_base_1: 88Ry6HESUoXBr6QUFXmni9zzfCIYt9qGNFvIWFcN--4xoecI5mqbNRBibI--62qPJbkzzh5h8lhFEFOSaQ==\n"
87108
updated_content = "---\nsecret_key_base_1: secret_key_base_test\naws:\n access_key_id: new_value\n"

0 commit comments

Comments
 (0)