Module: Legion::Audit::HashChain
- Defined in:
- lib/legion/audit/hash_chain.rb
Constant Summary collapse
- ALGORITHM =
'SHA256'- GENESIS_HASH =
('0' * 64).freeze
- CANONICAL_FIELDS =
%i[seq principal_id action resource source status detail created_at previous_hash].freeze
Class Method Summary collapse
Class Method Details
.canonical_payload(record) ⇒ Object
19 20 21 |
# File 'lib/legion/audit/hash_chain.rb', line 19 def canonical_payload(record) CANONICAL_FIELDS.map { |f| "#{f}:#{record[f]}" }.join('|') end |
.compute_hash(record) ⇒ Object
14 15 16 17 |
# File 'lib/legion/audit/hash_chain.rb', line 14 def compute_hash(record) payload = canonical_payload(record) OpenSSL::Digest.new(ALGORITHM).hexdigest(payload) end |
.verify_chain(records) ⇒ Object
23 24 25 26 27 28 29 30 31 32 |
# File 'lib/legion/audit/hash_chain.rb', line 23 def verify_chain(records) broken = [] records.each_cons(2) do |prev, curr| unless curr[:previous_hash] == prev[:record_hash] broken << { id: curr[:id], type: :broken_link, expected: prev[:record_hash], got: curr[:previous_hash] } end broken << { id: curr[:id], type: :gap, expected_seq: prev[:seq] + 1, got_seq: curr[:seq] } if prev[:seq] && curr[:seq] && curr[:seq] != prev[:seq] + 1 end { valid: broken.empty?, broken_links: broken, records_checked: records.size } end |