Skip to content

Commit 8a38a4f

Browse files
committed
Truncate summaries to 100,000 characters in the query command
This avoids a DOS vector where incredibly large summary strings would hang rubygems due to taking forever in Gem::Text.clean_text
1 parent 1bcbc7f commit 8a38a4f

File tree

4 files changed

+55
-1
lines changed

4 files changed

+55
-1
lines changed

lib/rubygems/commands/query_command.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,8 @@ def spec_platforms entry, platforms
353353
end
354354

355355
def spec_summary entry, spec
356-
entry << "\n\n" << format_text(spec.summary, 68, 4)
356+
summary = truncate_text(spec.summary, "the summary for #{spec.full_name}")
357+
entry << "\n\n" << format_text(summary, 68, 4)
357358
end
358359

359360
end

lib/rubygems/text.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ def clean_text(text)
1313
text.gsub(/[\000-\b\v-\f\016-\037\177]/, ".".freeze)
1414
end
1515

16+
def truncate_text(text, description, max_length = 100_000)
17+
raise ArgumentError, "max_length must be positive" unless max_length > 0
18+
return text if text.size <= max_length
19+
"Truncating #{description} to #{max_length.to_s.reverse.gsub(/...(?=.)/,'\&,').reverse} characters:\n" + text[0, max_length]
20+
end
21+
1622
##
1723
# Wraps +text+ to +wrap+ characters and optionally indents by +indent+
1824
# characters

test/rubygems/test_gem_commands_query_command.rb

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,46 @@ def test_execute_details_cleans_text
156156
This is a lot of text. This is a lot of text. This is a lot of text.
157157
This is a lot of text.
158158
159+
pl (1)
160+
Platform: i386-linux
161+
Author: A User
162+
Homepage: http://example.com
163+
164+
this is a summary
165+
EOF
166+
167+
assert_equal expected, @ui.output
168+
assert_equal '', @ui.error
169+
end
170+
171+
def test_execute_details_truncates_summary
172+
spec_fetcher do |fetcher|
173+
fetcher.spec 'a', 2 do |s|
174+
s.summary = 'This is a lot of text. ' * 10_000
175+
s.authors = ["Abraham Lincoln \x01", "\x02 Hirohito"]
176+
s.homepage = "http://a.example.com/\x03"
177+
end
178+
179+
fetcher.legacy_platform
180+
end
181+
182+
@cmd.handle_options %w[-r -d]
183+
184+
use_ui @ui do
185+
@cmd.execute
186+
end
187+
188+
expected = <<-EOF
189+
190+
*** REMOTE GEMS ***
191+
192+
a (2)
193+
Authors: Abraham Lincoln ., . Hirohito
194+
Homepage: http://a.example.com/.
195+
196+
Truncating the summary for a-2 to 100,000 characters:
197+
#{" This is a lot of text. This is a lot of text. This is a lot of text.\n" * 1449} This is a lot of te
198+
159199
pl (1)
160200
Platform: i386-linux
161201
Author: A User

test/rubygems/test_gem_text.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,11 @@ def test_levenshtein_distance_replace
7878
assert_equal 7, levenshtein_distance("xxxxxxx", "ZenTest")
7979
assert_equal 7, levenshtein_distance("zentest", "xxxxxxx")
8080
end
81+
82+
def test_truncate_text
83+
assert_equal "abc", truncate_text("abc", "desc")
84+
assert_equal "Truncating desc to 2 characters:\nab", truncate_text("abc", "desc", 2)
85+
s = "ab" * 500_001
86+
assert_equal "Truncating desc to 1,000,000 characters:\n#{s[0, 1_000_000]}", truncate_text(s, "desc", 1_000_000)
87+
end
8188
end

0 commit comments

Comments
 (0)