Skip to content

Commit 97aae11

Browse files
authored
Merge pull request #202 from internetee/fix/whois-invalid-encoding-crash
Fix JSON serialization crash on invalid UTF-8 input
2 parents c93120e + 04258c5 commit 97aae11

File tree

8 files changed

+56
-24
lines changed

8 files changed

+56
-24
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
fail-fast: false
2424
matrix:
2525
os: [ubuntu-24.04]
26-
ruby: ['3.4.4']
26+
ruby: ['3.4.5']
2727
runs-on: ${{ matrix.os }}
2828
env:
2929
PG_DATABASE: postgres

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,8 @@ config/deploy.rb
2929

3030
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
3131
.rvmrc
32+
.DS_Store
33+
app/.DS_Store
34+
test/.DS_Store
35+
.bash_history
36+
.claude

.ruby-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.4.4
1+
3.4.5

Gemfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
source 'https://rubygems.org'
22

3-
ruby '3.4.4'
3+
ruby '3.4.5'
44

55
# core
66
gem 'eventmachine', '~> 1.2.7'

Gemfile.lock

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,56 +19,58 @@ GEM
1919
minitest (>= 5.1)
2020
securerandom (>= 0.3)
2121
tzinfo (~> 2.0, >= 2.0.5)
22-
ast (2.4.2)
22+
ast (2.4.3)
2323
base64 (0.3.0)
2424
benchmark (0.4.1)
25-
bigdecimal (3.2.2)
25+
bigdecimal (3.3.1)
2626
coderay (1.1.3)
2727
concurrent-ruby (1.3.5)
28-
connection_pool (2.5.3)
28+
connection_pool (2.5.4)
2929
daemons (1.4.1)
3030
docile (1.4.1)
3131
dotenv (3.1.8)
3232
drb (2.2.3)
3333
eventmachine (1.2.7)
3434
i18n (1.14.7)
3535
concurrent-ruby (~> 1.0)
36-
json (2.10.2)
37-
language_server-protocol (3.17.0.4)
36+
json (2.15.1)
37+
language_server-protocol (3.17.0.5)
3838
lint_roller (1.1.0)
3939
logger (1.7.0)
4040
method_source (1.1.0)
4141
mina (1.2.5)
4242
rake
43-
minitest (5.25.5)
43+
minitest (5.26.0)
4444
mocha (2.7.1)
4545
ruby2_keywords (>= 0.0.5)
4646
ostruct (0.6.3)
47-
parallel (1.26.3)
48-
parser (3.3.7.1)
47+
parallel (1.27.0)
48+
parser (3.3.9.0)
4949
ast (~> 2.4.1)
5050
racc
5151
pg (1.5.9)
52+
prism (1.6.0)
5253
pry (0.15.2)
5354
coderay (~> 1.1)
5455
method_source (~> 1.0)
5556
racc (1.8.1)
5657
rainbow (3.1.1)
57-
rake (13.2.1)
58-
regexp_parser (2.10.0)
59-
rubocop (1.73.2)
58+
rake (13.3.0)
59+
regexp_parser (2.11.3)
60+
rubocop (1.81.1)
6061
json (~> 2.3)
6162
language_server-protocol (~> 3.17.0.2)
6263
lint_roller (~> 1.1.0)
6364
parallel (~> 1.10)
6465
parser (>= 3.3.0.2)
6566
rainbow (>= 2.2.2, < 4.0)
6667
regexp_parser (>= 2.9.3, < 3.0)
67-
rubocop-ast (>= 1.38.0, < 2.0)
68+
rubocop-ast (>= 1.47.1, < 2.0)
6869
ruby-progressbar (~> 1.7)
6970
unicode-display_width (>= 2.4.0, < 4.0)
70-
rubocop-ast (1.38.1)
71-
parser (>= 3.3.1.0)
71+
rubocop-ast (1.47.1)
72+
parser (>= 3.3.7.2)
73+
prism (~> 1.4)
7274
ruby-progressbar (1.13.0)
7375
ruby2_keywords (0.0.5)
7476
securerandom (0.4.1)
@@ -81,9 +83,9 @@ GEM
8183
timeout (0.4.3)
8284
tzinfo (2.0.6)
8385
concurrent-ruby (~> 1.0)
84-
unicode-display_width (3.1.4)
85-
unicode-emoji (~> 4.0, >= 4.0.4)
86-
unicode-emoji (4.0.4)
86+
unicode-display_width (3.2.0)
87+
unicode-emoji (~> 4.1)
88+
unicode-emoji (4.1.0)
8789

8890
PLATFORMS
8991
aarch64-linux
@@ -105,7 +107,7 @@ DEPENDENCIES
105107
simpleidn (~> 0.2.1)
106108

107109
RUBY VERSION
108-
ruby 3.4.4p34
110+
ruby 3.4.5p51
109111

110112
BUNDLED WITH
111113
2.6.9

app/validators/unicode_validator.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def valid?
2222
private
2323

2424
def valid_utf8_encoding?(string)
25-
string.force_encoding(UTF8_ENCODING).valid_encoding?
25+
string.dup.force_encoding(UTF8_ENCODING).valid_encoding?
2626
end
2727

2828
def prepare_string(input)

lib/logging.rb

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,28 @@ def logger
1212

1313
def log_json(payload)
1414
base_log = build_base_log(payload)
15-
logger.info(base_log.to_json)
15+
safe_log = sanitize_for_json(base_log)
16+
logger.info(safe_log.to_json)
17+
rescue JSON::GeneratorError, Encoding::UndefinedConversionError => e
18+
logger.error("[ERROR] JSON serialization failed: #{e.class} - #{e.message}")
19+
logger.error("[CONTEXT] Original payload: #{payload.inspect}")
1620
end
1721

1822
private
1923

24+
def sanitize_for_json(value)
25+
case value
26+
when String
27+
value.dup.encode('UTF-8', invalid: :replace, undef: :replace, replace: '�').scrub('�')
28+
when Array
29+
value.map { |item| sanitize_for_json(item) }
30+
when Hash
31+
value.transform_values { |item| sanitize_for_json(item) }
32+
else
33+
value
34+
end
35+
end
36+
2037
# rubocop:disable Metrics/MethodLength
2138
def build_base_log(payload)
2239
{

lib/whois_server.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,15 @@ def invalid_data?(data, ip)
8181

8282
def process_whois_request(data, ip)
8383
cleaned_data = data.strip
84-
name = SimpleIDN.to_unicode(cleaned_data.downcase)
84+
utf8_data = cleaned_data.force_encoding('UTF-8')
85+
86+
unless utf8_data.valid_encoding?
87+
log_invalid_encoding(ip, data)
88+
send_data(invalid_encoding_msg)
89+
return
90+
end
91+
92+
name = SimpleIDN.to_unicode(utf8_data.downcase)
8593
unless domain_valid_format?(name)
8694
log_policy_error(ip, cleaned_data, name)
8795
send_data(policy_error_msg)

0 commit comments

Comments
 (0)