Skip to content

Commit c60361e

Browse files
committed
🔒 Filter ScramCache#inspect, #to_s, #pretty_print
1 parent 5864820 commit c60361e

2 files changed

Lines changed: 127 additions & 0 deletions

File tree

lib/net/imap/sasl/scram_cache.rb

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,50 @@ def reset(salt: nil, iterations: nil)
5858
self.iterations = iterations
5959
self
6060
end
61+
62+
# Returns a string representation with the cached secrets filtered out.
63+
def inspect
64+
format "#<struct %s %s>", self.class, members
65+
.map { [_1, filtered_inspect(_1)].join("=") }
66+
.join(", ")
67+
end
68+
alias to_s inspect
69+
70+
# Pretty prints a representation with the cached secrets filtered out.
71+
def pretty_print(q)
72+
q.group(1, sprintf("#<struct %s", PP.mcall(self, Kernel, :class).name), '>') {
73+
q.seplist(PP.mcall(self, Struct, :members), lambda { q.text "," }) {|member|
74+
q.breakable
75+
q.text member.to_s
76+
q.text '='
77+
q.group(1) {
78+
q.breakable ''
79+
if secret_member?(member)
80+
q.text filtered_inspect(member)
81+
else
82+
q.pp self[member]
83+
end
84+
}
85+
}
86+
}
87+
end
88+
89+
private
90+
91+
def secret_member?(member)
92+
member in :salted_password | :client_key | :server_key
93+
end
94+
95+
def filtered_inspect(member)
96+
value = self[member]
97+
return value.inspect unless secret_member?(member)
98+
case value
99+
in String then format "#<FILTERED %d bytes>", value.bytesize
100+
in nil then "nil"
101+
else format "#<FILTERED %s>", value.class
102+
end
103+
end
104+
61105
end
62106

63107
end

test/net/imap/sasl/test_scram_cache.rb

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,87 @@ class SASLScamCacheTest < Net::IMAP::TestCase
6565
assert cache.sufficient?
6666
end
6767

68+
%w[inspect to_s].each do |method|
69+
test "##{method}" do
70+
cache = SASL::ScramCache.new
71+
assert_equal(
72+
"#<struct #{SASL::ScramCache} " \
73+
"salt=nil, iterations=nil, salted_password=nil, " \
74+
"client_key=nil, server_key=nil>",
75+
cache.public_send(method)
76+
)
77+
cache.salt = salt = "saltysaltsalt"
78+
cache.iterations = 100_000
79+
assert_equal(
80+
"#<struct #{SASL::ScramCache} " \
81+
"salt=#{salt.inspect}, iterations=100000, " \
82+
"salted_password=nil, client_key=nil, server_key=nil>",
83+
cache.public_send(method)
84+
)
85+
cache.salted_password = "this should be filtered!!"
86+
assert_equal(
87+
"#<struct #{SASL::ScramCache} " \
88+
"salt=#{salt.inspect}, iterations=100000, " \
89+
"salted_password=#<FILTERED 25 bytes>, client_key=nil, server_key=nil>",
90+
cache.public_send(method)
91+
)
92+
cache.client_key = "filter!"
93+
cache.server_key = "this!"
94+
assert_equal(
95+
"#<struct #{SASL::ScramCache} " \
96+
"salt=#{salt.inspect}, iterations=100000, " \
97+
"salted_password=#<FILTERED 25 bytes>, " \
98+
"client_key=#<FILTERED 7 bytes>, " \
99+
"server_key=#<FILTERED 5 bytes>>",
100+
cache.public_send(method)
101+
)
102+
cache.salted_password = nil
103+
assert_equal(
104+
"#<struct #{SASL::ScramCache} " \
105+
"salt=#{salt.inspect}, iterations=100000, " \
106+
"salted_password=nil, " \
107+
"client_key=#<FILTERED 7 bytes>, " \
108+
"server_key=#<FILTERED 5 bytes>>",
109+
cache.public_send(method)
110+
)
111+
end
112+
end
113+
114+
test "#pretty_print" do
115+
width = 80
116+
cache = SASL::ScramCache.new
117+
PP.pp cache, (output = String.new), width
118+
assert_equal(<<~PP, output)
119+
#<struct #{SASL::ScramCache}
120+
salt=nil,
121+
iterations=nil,
122+
salted_password=nil,
123+
client_key=nil,
124+
server_key=nil>
125+
PP
126+
cache.salt = salt = "saltosaltersaltin"
127+
cache.iterations = 100_000
128+
PP.pp cache, (output = String.new), width
129+
assert_equal(<<~PP, output)
130+
#<struct #{SASL::ScramCache}
131+
salt=#{salt.inspect},
132+
iterations=100000,
133+
salted_password=nil,
134+
client_key=nil,
135+
server_key=nil>
136+
PP
137+
cache.salted_password = "this should be filtered!!"
138+
cache.client_key = Object.new
139+
cache.server_key = 123.5
140+
PP.pp cache, (output = String.new), width
141+
assert_equal(<<~PP, output)
142+
#<struct #{SASL::ScramCache}
143+
salt=#{salt.inspect},
144+
iterations=100000,
145+
salted_password=#<FILTERED 25 bytes>,
146+
client_key=#<FILTERED Object>,
147+
server_key=#<FILTERED Float>>
148+
PP
149+
end
150+
68151
end

0 commit comments

Comments
 (0)