master
go 50 lines 1.45 KB
Raw
1 package cmdutils
2
3 import (
4 "strings"
5 "unicode"
6 )
7
8 const maxRunes = 128
9
10 // CleanAndTrim sanitizes untrusted strings from remote peers to prevent display issues
11 // across web UIs, terminals, and logs. It replaces control characters, format characters,
12 // and surrogates with U+FFFD (�), then enforces a maximum length of 128 runes.
13 //
14 // This follows the libp2p identify specification and RFC 9839 guidance:
15 // replacing problematic code points is preferred over deletion as deletion
16 // is a known security risk.
17 func CleanAndTrim(str string) string {
18 // Build sanitized result
19 var result []rune
20 for _, r := range str {
21 // Replace control characters (Cc) with U+FFFD - prevents terminal escapes, CR, LF, etc.
22 if unicode.Is(unicode.Cc, r) {
23 result = append(result, '\uFFFD')
24 continue
25 }
26 // Replace format characters (Cf) with U+FFFD - prevents RTL/LTR overrides, zero-width chars
27 if unicode.Is(unicode.Cf, r) {
28 result = append(result, '\uFFFD')
29 continue
30 }
31 // Replace surrogate characters (Cs) with U+FFFD - invalid in UTF-8
32 if unicode.Is(unicode.Cs, r) {
33 result = append(result, '\uFFFD')
34 continue
35 }
36 // Private use characters (Co) are preserved per spec
37 result = append(result, r)
38 }
39
40 // Convert to string and trim whitespace
41 sanitized := strings.TrimSpace(string(result))
42
43 // Enforce maximum length (128 runes, not bytes)
44 runes := []rune(sanitized)
45 if len(runes) > maxRunes {
46 return string(runes[:maxRunes])
47 }
48
49 return sanitized
50 }