Module: Legion::Data::AuditLogHashChain

Defined in:
lib/legion/data/audit_log_hash_chain.rb

Constant Summary collapse

GENESIS_HASH =
('0' * 64).freeze
CANONICAL_FIELDS =
%i[
  principal_id action resource source status detail created_at previous_hash
].freeze

Class Method Summary collapse

Class Method Details

.canonical_payload(record) ⇒ Object



34
35
36
37
38
# File 'lib/legion/data/audit_log_hash_chain.rb', line 34

def canonical_payload(record)
  CANONICAL_FIELDS.map do |field|
    "#{field}:#{canonical_value(value_for(record, field))}"
  end.join('|')
end

.compute_hash(record) ⇒ Object



16
17
18
# File 'lib/legion/data/audit_log_hash_chain.rb', line 16

def compute_hash(record)
  Digest::SHA256.hexdigest(canonical_payload(record))
end

.verify(records) ⇒ Object



20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/legion/data/audit_log_hash_chain.rb', line 20

def verify(records)
  previous_hash = GENESIS_HASH
  records.each do |record|
    return invalid(record, :parent_mismatch) unless value_for(record, :previous_hash).to_s == previous_hash

    expected = compute_hash(record)
    return invalid(record, :hash_mismatch) unless value_for(record, :record_hash).to_s == expected

    previous_hash = expected
  end

  { valid: true, length: records.size }
end