Files
plex-docker/Freeloader/plex_relay/tests/test_tunnel.py
T
benjamin 72f4661bdc Replace patchelf crack with Freeloader LD_PRELOAD approach
- Multi-stage Dockerfile: discover patterns from PMS binary (capstone),
  compile .so with zig (musl), layer onto lscr.io/linuxserver/plex
- Uses LD_PRELOAD instead of patchelf (which corrupts Plex's musl loader)
- Auto-discovery: broad structural patterns with string-anchored fallback
  (//feature) and relationship-based fallback (BITSET_REF within BS_INIT)
- hook.cpp uses __has_include for generated patterns with hardcoded fallbacks
- Custom wrapper.sh (no traffic_logger preload)
- Vendored Freeloader source (github.com/authrequest/Freeloader, AGPL-3.0)
- Removed stale plexmediaserver_crack.so binary
- Supports Plex 1.43.3+ (verified against 1.43.2 and 1.43.3)
2026-08-19 22:33:42 +02:00

92 lines
2.6 KiB
Python

# SPDX-License-Identifier: AGPL-3.0-or-later
from pathlib import Path
import pytest
from plex_relay.config import RelayConfig
from plex_relay.errors import TunnelError
from plex_relay.tunnel import SubprocessTunnel, SubprocessTunnelFactory, build_ssh_argv
def cfg(**kw):
base = dict(token="secret", ssh_user="machineid", local_host="127.0.0.1", local_port=32400)
base.update(kw)
return RelayConfig(**base)
def test_argv_matches_binary_layout():
argv = build_ssh_argv(cfg(), "relay.example", 443, Path("/data/relayHostKey.txt"))
assert argv == [
"ssh", "-p", "443", "-N", "-R", "0:127.0.0.1:32400",
"-o", "UserKnownHostsFile=/data/relayHostKey.txt",
"-o", "LogLevel=VERBOSE",
"-o", "PreferredAuthentications=password",
"-o", "PubkeyAuthentication=no",
"-l", "machineid", "-F", "/dev/null", "relay.example",
]
def test_argv_honours_port_and_target():
argv = build_ssh_argv(cfg(local_host="10.0.0.5", local_port=32500), "h", 2222, Path("/k"))
assert "0:10.0.0.5:32500" in argv
assert argv[argv.index("-p") + 1] == "2222"
class FakeProc:
def __init__(self):
self.alive = True
self.terminated = False
def poll(self):
return None if self.alive else 0
def terminate(self):
self.terminated = True
self.alive = False
def kill(self):
self.alive = False
def wait(self, timeout=None):
self.alive = False
return 0
def test_tunnel_start_sets_secret_env_and_cleans_askpass():
captured = {}
def spawner(argv, env):
captured["argv"] = argv
captured["env"] = dict(env)
return FakeProc()
t = SubprocessTunnel(cfg(), "relay.example", 443, Path("/k"), spawner)
t.start()
assert t.is_alive()
assert captured["env"]["PLEXTOKEN"] == "secret"
assert "SSH_ASKPASS" in captured["env"]
askpass = Path(captured["env"]["SSH_ASKPASS"])
assert askpass.exists()
assert "secret" not in captured["argv"] # never on the command line
t.stop()
assert not t.is_alive()
assert not askpass.exists() # helper removed on stop
def test_tunnel_start_wraps_spawn_failure():
def boom(argv, env):
raise OSError("ssh not found")
t = SubprocessTunnel(cfg(), "h", 443, Path("/k"), boom)
with pytest.raises(TunnelError):
t.start()
assert not t.is_alive()
def test_factory_builds_tunnel():
factory = SubprocessTunnelFactory(cfg(), spawner=lambda a, e: FakeProc())
t = factory("h", 443, Path("/k"))
assert t.host == "h"
t.start()
assert t.is_alive()
t.stop()