Module: Legion::Extensions::Privatecore::Helpers::Redactor

Defined in:
lib/legion/extensions/privatecore/helpers/redactor.rb

Constant Summary collapse

REDACTION_MARKER =
'[REDACTED]'

Class Method Summary collapse

Class Method Details

.build_replacement(detection, mode, type_counters, mapping) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/legion/extensions/privatecore/helpers/redactor.rb', line 32

def build_replacement(detection, mode, type_counters, mapping)
  case mode
  when :placeholder
    type_counters[detection[:type]] += 1
    tag = "[#{detection[:type].upcase}_#{type_counters[detection[:type]]}]"
    mapping[tag] = detection[:match]
    tag
  when :mask
    mask_value(detection[:match])
  when :synthetic
    fake = generate_synthetic(detection[:type], detection[:match])
    mapping[fake] = detection[:match]
    fake
  else
    REDACTION_MARKER
  end
end

.generate_luhn_number(length) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
# File 'lib/legion/extensions/privatecore/helpers/redactor.rb', line 77

def generate_luhn_number(length)
  digits = Array.new(length - 1) { rand(0..9) }
  sum = 0
  digits.reverse.each_with_index do |d, i|
    v = i.even? ? d * 2 : d
    v -= 9 if v > 9
    sum += v
  end
  check = (10 - (sum % 10)) % 10
  (digits << check).join
end

.generate_synthetic(type, original) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/legion/extensions/privatecore/helpers/redactor.rb', line 54

def generate_synthetic(type, original)
  case type
  when :ssn, :itin
    "#{rand(100..999)}-#{rand(10..99)}-#{rand(1000..9999)}"
  when :phone
    "#{rand(200..999)}-#{rand(200..999)}-#{rand(1000..9999)}"
  when :email
    "user#{rand(1000..9999)}@example.net"
  when :credit_card
    generate_luhn_number(16)
  when :ip
    "#{rand(1..254)}.#{rand(0..255)}.#{rand(0..255)}.#{rand(1..254)}"
  when :aadhaar
    "#{rand(2000..9999)} #{rand(1000..9999)} #{rand(1000..9999)}"
  when :passport
    "#{('A'..'Z').to_a.sample}#{rand(10_000_000..99_999_999)}"
  when :aws_key
    "AKIA#{Array.new(16) { (('0'..'9').to_a + ('A'..'Z').to_a).sample }.join}"
  else
    SecureRandom.hex([((original.length + 1) / 2), 1].max)
  end
end

.mask_value(original) ⇒ Object



50
51
52
# File 'lib/legion/extensions/privatecore/helpers/redactor.rb', line 50

def mask_value(original)
  original.gsub(/[A-Za-z]/, '*').gsub(/\d/, '*')
end

.persist_mapping(mapping:, key:, ttl:) ⇒ Object



97
98
99
100
101
# File 'lib/legion/extensions/privatecore/helpers/redactor.rb', line 97

def persist_mapping(mapping:, key:, ttl:)
  actual_key = key || SecureRandom.uuid
  Legion::Cache.set("privatecore:mapping:#{actual_key}", mapping, ttl: ttl) if defined?(Legion::Cache) # rubocop:disable Legion/HelperMigration/DirectCache
  actual_key
end

.redact(text, detections:, mode:) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/legion/extensions/privatecore/helpers/redactor.rb', line 14

def redact(text, detections:, mode:)
  return { cleaned: text, mapping: {}, detections: detections } unless text.is_a?(String)
  return { cleaned: text, mapping: {}, detections: detections } if detections.empty?

  mapping = {}
  type_counters = Hash.new(0)
  cleaned = text.dup

  sorted = detections.sort_by { |d| -d[:start] }

  sorted.each do |detection|
    replacement = build_replacement(detection, mode, type_counters, mapping)
    cleaned[detection[:start]...detection[:end]] = replacement
  end

  { cleaned: cleaned, mapping: mapping, detections: detections }
end

.restore(text:, mapping:) ⇒ Object



89
90
91
92
93
94
95
# File 'lib/legion/extensions/privatecore/helpers/redactor.rb', line 89

def restore(text:, mapping:)
  return text if mapping.nil? || mapping.empty?

  result = text.dup
  mapping.each { |placeholder, original| result.gsub!(placeholder, original) }
  result
end

.retrieve_mapping(key:) ⇒ Object



103
104
105
106
107
# File 'lib/legion/extensions/privatecore/helpers/redactor.rb', line 103

def retrieve_mapping(key:)
  return nil unless defined?(Legion::Cache)

  Legion::Cache.get("privatecore:mapping:#{key}") # rubocop:disable Legion/HelperMigration/DirectCache
end