ruby
47 lines · 7 steps
Recursively scrubbing secrets from JSON
A scrubber walks any nested payload, redacting sensitive keys and partially masking emails before serializing.
Explained by
highlit
1require 'json'
2require 'set'
3
4class SensitiveScrubber
5 DEFAULT_KEYS = %w[
6 password password_confirmation token access_token refresh_token
7 secret api_key ssn credit_card cvv authorization
8 ].freeze
9
10 EMAIL_PATTERN = /\A[^@\s]+@[^@\s]+\z/
11
12 def initialize(keys: DEFAULT_KEYS, mask: '[FILTERED]')
13 @keys = Set.new(keys.map(&:to_s).map(&:downcase))
14 @mask = mask
15 end
16
17 def to_json(payload, **opts)
18 JSON.generate(scrub(payload), **opts)
19 end
20
21 private
22
23 def scrub(value)
24 case value
25 when Hash
26 value.each_with_object({}) do |(key, val), acc|
27 acc[key] = sensitive?(key) ? @mask : scrub(val)
28 end
29 when Array
30 value.map { |item| scrub(item) }
31 when String
32 value.match?(EMAIL_PATTERN) ? mask_email(value) : value
33 else
34 value
35 end
36 end
37
38 def sensitive?(key)
39 @keys.include?(key.to_s.downcase)
40 end
41
42 def mask_email(email)
43 local, domain = email.split('@', 2)
44 visible = local[0, 2]
45 "#{visible}#{'*' * [local.length - 2, 1].max}@#{domain}"
46 end
47end
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1A recursive case-by-type walk handles arbitrarily nested hashes and arrays uniformly.
- 2Normalizing keys into a downcased Set makes sensitivity checks fast and case-insensitive.
- 3Partial masking preserves enough of a value to stay recognizable without exposing it fully.
Related explainers
ruby
require "csv" class SalesReport def initialize(path)
Aggregating CSV sales data in Ruby
data-aggregation
memoization
group_by
Intermediate
6 steps
python
from collections.abc import Mapping from typing import Any, Iterator
Flattening nested config into dotted keys
recursion
generators
tree-traversal
Intermediate
7 steps
ruby
module DurationFormatter UNITS = [ ['week', 604_800], ['day', 86_400],
Turning seconds into human-readable durations in Ruby
greedy-decomposition
modular-arithmetic
formatting
Intermediate
7 steps
php
<?php class ImageUploadService {
Validating file uploads safely in PHP
file-upload
input-validation
security
Intermediate
8 steps
ruby
class Comment < ApplicationRecord belongs_to :post belongs_to :author, class_name: "User"
Live-updating comments with Turbo in Rails
turbo-streams
callbacks
associations
Intermediate
8 steps
go
package model import ( "encoding/json"
Custom JSON marshaling in Go
json
serialization
interfaces
Intermediate
5 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/recursively-scrubbing-secrets-from-json-explained-ruby-005c/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.