aboutsummaryrefslogtreecommitdiff
path: root/internal/net/conn.go
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-09-18 17:48:26 -0400
committerhistoria <[not public]>2026-09-18 17:48:26 -0400
commit8fe9e3c3fef0049df82281a62afe35dda516dfe2 (patch)
treedd269f2c0710f334e19f00a191260ebc46284a90 /internal/net/conn.go
parent194164a77eb4f2479b94c19e6f0e1278ab608781 (diff)
downloadthehouseoficarus-8fe9e3c3fef0049df82281a62afe35dda516dfe2.tar.gz
fix: close combat ghost, admin traversal, login throttle, journal double-pay, and quality/economy gaps
Diffstat (limited to 'internal/net/conn.go')
-rw-r--r--internal/net/conn.go28
1 files changed, 28 insertions, 0 deletions
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)
}