Files
derp/patches/apply_pymumble_ssl.py
user 8b504364a9 fix: patch pymumble protocol version and harden mumble connections
- Update reported protocol version from 1.2.4 to 1.5.0 so modern
  Murmur servers treat PyMumble as a compatible client
- Fix OS string to report actual platform instead of "PyMumble 1.6.1"
  (was shown as [Invalid] by Murmur)
- Raise pymumble reconnect retry interval to 15s to prevent autoban
  when running multiple bots from the same IP
- Enable TCP keepalive on control socket (10s idle) to prevent NAT
  gateways from dropping long-lived connections

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 22:28:57 +01:00

95 lines
3.3 KiB
Python

"""Patch pymumble deps for Python 3.13+ / musl (Alpine).
1. pymumble: ssl.wrap_socket was removed in 3.13
2. opuslib: ctypes.util.find_library fails on musl-based distros
3. pymumble: protocol version 1.2.4 is rejected by modern servers
"""
import pathlib
import sysconfig
site = sysconfig.get_path("purelib")
# -- pymumble: replace ssl.wrap_socket with SSLContext --
p = pathlib.Path(f"{site}/pymumble_py3/mumble.py")
src = p.read_text()
old = """\
try:
self.control_socket = ssl.wrap_socket(std_sock, certfile=self.certfile, keyfile=self.keyfile, ssl_version=ssl.PROTOCOL_TLS)
except AttributeError:
self.control_socket = ssl.wrap_socket(std_sock, certfile=self.certfile, keyfile=self.keyfile, ssl_version=ssl.PROTOCOL_TLSv1)
try:"""
new = """\
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
if self.certfile:
ctx.load_cert_chain(certfile=self.certfile, keyfile=self.keyfile)
self.control_socket = ctx.wrap_socket(std_sock, server_hostname=self.host)
try:"""
assert old in src, "pymumble ssl patch target not found"
p.write_text(src.replace(old, new))
print("pymumble ssl patch applied")
# -- opuslib: find_library fails on musl, use direct CDLL fallback --
p = pathlib.Path(f"{site}/opuslib/api/__init__.py")
src = p.read_text()
old_opus = "lib_location = find_library('opus')"
new_opus = "lib_location = find_library('opus') or 'libopus.so.0'"
assert old_opus in src, "opuslib find_library patch target not found"
p.write_text(src.replace(old_opus, new_opus))
print("opuslib musl patch applied")
# -- pymumble: close old socket before reconnecting --
# init_connection() drops control_socket reference without closing it.
# The lingering TCP connection causes Murmur to kick the new session
# with "You connected to the server from another device".
p = pathlib.Path(f"{site}/pymumble_py3/mumble.py")
src = p.read_text()
old_init = """\
self.connected = PYMUMBLE_CONN_STATE_NOT_CONNECTED
self.control_socket = None"""
new_init = """\
self.connected = PYMUMBLE_CONN_STATE_NOT_CONNECTED
if getattr(self, 'control_socket', None) is not None:
try:
self.control_socket.close()
except Exception:
pass
self.control_socket = None"""
assert old_init in src, "pymumble init_connection socket patch target not found"
src = src.replace(old_init, new_init)
print("pymumble reconnect socket patch applied")
p.write_text(src)
# -- pymumble: report modern protocol version --
# PyMumble 1.6.1 reports protocol version 1.2.4, which modern Murmur
# (1.5.x) treats as an invalid/legacy client. Update to 1.5.0 so the
# server enables full feature set and stops sending warnings.
p = pathlib.Path(f"{site}/pymumble_py3/constants.py")
src = p.read_text()
old_ver = "PYMUMBLE_PROTOCOL_VERSION = (1, 2, 4)"
new_ver = "PYMUMBLE_PROTOCOL_VERSION = (1, 5, 0)"
assert old_ver in src, "pymumble version patch target not found"
src = src.replace(old_ver, new_ver)
old_os = 'PYMUMBLE_OS_STRING = "PyMumble %s" % PYMUMBLE_VERSION'
new_os = 'PYMUMBLE_OS_STRING = platform.system()'
assert old_os in src, "pymumble OS string patch target not found"
src = src.replace(old_os, new_os)
p.write_text(src)
print("pymumble version patch applied (1.5.0, native OS string)")