From 8fe9e3c3fef0049df82281a62afe35dda516dfe2 Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Fri, 18 Sep 2026 17:48:26 -0400 Subject: fix: close combat ghost, admin traversal, login throttle, journal double-pay, and quality/economy gaps --- internal/net/conn.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'internal/net/conn.go') diff --git a/internal/net/conn.go b/internal/net/conn.go index 42b7c41..4aa4db4 100644 --- a/internal/net/conn.go +++ b/internal/net/conn.go @@ -11,6 +11,7 @@ import ( "strings" "sync/atomic" "time" + "unicode/utf8" ) type Conn interface { @@ -72,6 +73,7 @@ func (t *tcpConn) ReadMessage() (string, error) { } text := strings.TrimRight(string(line), "\r\n") text = stripIAC(text) + text = truncateLine(text, maxLineLength) if t.echoOff.Load() { t.conn.Write([]byte("\r\n")) } @@ -82,6 +84,32 @@ func (t *tcpConn) Write(b []byte) (int, error) { return t.conn.Write(b) } +// RemoteAddr reports the peer address for the login throttle. +func (t *tcpConn) RemoteAddr() string { + if t.conn == nil { + return "" + } + return t.conn.RemoteAddr().String() +} + +// truncateLine cuts s to at most max bytes without splitting a UTF-8 rune. +// Both the telnet and websocket paths bound line length, and a byte-boundary +// cut would otherwise emit an invalid trailing rune to the game. +func truncateLine(s string, max int) string { + if max <= 0 || len(s) <= max { + return s + } + s = s[:max] + for len(s) > 0 { + r, size := utf8.DecodeLastRuneInString(s) + if r != utf8.RuneError || size > 1 { + break + } + s = s[:len(s)-1] + } + return s +} + func (t *tcpConn) SetWriteDeadline(ts time.Time) error { return t.conn.SetWriteDeadline(ts) } -- cgit v1.2.3