mirror of
https://github.com/lunchcat/sif.git
synced 2026-07-28 14:37:01 -07:00
fix(scan): truncate shodan banners on rune boundaries (#326)
truncateBanner sliced by byte offset, so a multibyte utf-8 rune landing across the limit was cut mid-sequence and emitted invalid utf-8. shodan banners routinely carry non-ascii bytes, so this corrupted logged and printed output. count runes instead so the cut lands on a boundary.
This commit is contained in:
@@ -260,8 +260,8 @@ func truncateBanner(banner string, maxLen int) string {
|
||||
banner = strings.ReplaceAll(banner, "\r\n", " ")
|
||||
banner = strings.ReplaceAll(banner, "\n", " ")
|
||||
|
||||
if len(banner) > maxLen {
|
||||
return banner[:maxLen] + "..."
|
||||
if runes := []rune(banner); len(runes) > maxLen {
|
||||
return string(runes[:maxLen]) + "..."
|
||||
}
|
||||
return banner
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
func TestResolveHostname_IP(t *testing.T) {
|
||||
@@ -50,6 +51,9 @@ func TestTruncateBanner(t *testing.T) {
|
||||
{"this is a long banner", 10, "this is a ..."},
|
||||
{"with\nnewlines\r\n", 50, "with newlines"},
|
||||
{" trimmed ", 50, "trimmed"},
|
||||
// truncation must land on a rune boundary, not split a multibyte rune
|
||||
{"aaaé", 4, "aaaé"},
|
||||
{"日本語テスト", 3, "日本語..."},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
@@ -57,6 +61,9 @@ func TestTruncateBanner(t *testing.T) {
|
||||
if result != tt.expected {
|
||||
t.Errorf("truncateBanner(%q, %d) = %q, want %q", tt.input, tt.maxLen, result, tt.expected)
|
||||
}
|
||||
if !utf8.ValidString(result) {
|
||||
t.Errorf("truncateBanner(%q, %d) produced invalid UTF-8: %q", tt.input, tt.maxLen, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user