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)
This commit is contained in:
1 parent
4399a8288d
commit
72f4661bdc
72 files changed
+77927
-17
No files matched your search
@@ -0,0 +1,157 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from plex_relay.config import RelayConfig
|
||||
from plex_relay.controller import RelayController
|
||||
from plex_relay.errors import RelayError, TunnelError
|
||||
from plex_relay.models import HostKey, RelayKey, known_hosts_endpoint
|
||||
|
||||
|
||||
class FakeTunnel:
|
||||
def __init__(self, host, fail=False):
|
||||
self._host = host
|
||||
self._fail = fail
|
||||
self.alive = False
|
||||
self.stopped = False
|
||||
|
||||
@property
|
||||
def host(self):
|
||||
return self._host
|
||||
|
||||
def start(self):
|
||||
if self._fail:
|
||||
raise TunnelError("spawn failed")
|
||||
self.alive = True
|
||||
|
||||
def is_alive(self):
|
||||
return self.alive
|
||||
|
||||
def stop(self, timeout=None):
|
||||
self.stopped = True
|
||||
self.alive = False
|
||||
|
||||
|
||||
class FakeFactory:
|
||||
def __init__(self):
|
||||
self.fail = False
|
||||
self.created = []
|
||||
|
||||
def __call__(self, host, port, known_hosts_path):
|
||||
t = FakeTunnel(host, fail=self.fail)
|
||||
self.created.append(t)
|
||||
return t
|
||||
|
||||
|
||||
class FakeTrust:
|
||||
def __init__(self):
|
||||
self.calls = []
|
||||
|
||||
def ensure_trusted(self, host, port=443, *, force=False):
|
||||
self.calls.append((host, port))
|
||||
return HostKey.for_endpoint(known_hosts_endpoint(host, port), RelayKey("ssh-ed25519", "k"))
|
||||
|
||||
@property
|
||||
def known_hosts_path(self):
|
||||
return Path("/k")
|
||||
|
||||
|
||||
def build(**cfgkw):
|
||||
cfg = RelayConfig(token="t", ssh_user="u", reap_interval_seconds=999.0, **cfgkw)
|
||||
trust, factory = FakeTrust(), FakeFactory()
|
||||
return RelayController(cfg, trust, factory), trust, factory
|
||||
|
||||
|
||||
def test_connect_tracks_and_trusts():
|
||||
ctrl, trust, factory = build()
|
||||
try:
|
||||
assert ctrl.connect("relay.example", 443) is True
|
||||
assert ctrl.active_hosts == ["relay.example"]
|
||||
assert trust.calls == [("relay.example", 443)]
|
||||
assert len(factory.created) == 1
|
||||
finally:
|
||||
ctrl.stop()
|
||||
|
||||
|
||||
def test_connect_dedup_when_alive():
|
||||
ctrl, _, factory = build()
|
||||
try:
|
||||
assert ctrl.connect("h") is True
|
||||
assert ctrl.connect("h") is False
|
||||
assert len(factory.created) == 1
|
||||
finally:
|
||||
ctrl.stop()
|
||||
|
||||
|
||||
def test_reconnect_after_death():
|
||||
ctrl, _, factory = build()
|
||||
try:
|
||||
ctrl.connect("h")
|
||||
factory.created[0].alive = False # tunnel died
|
||||
assert ctrl.connect("h") is True
|
||||
assert len(factory.created) == 2
|
||||
finally:
|
||||
ctrl.stop()
|
||||
|
||||
|
||||
def test_connect_raises_on_tunnel_failure():
|
||||
ctrl, _, factory = build()
|
||||
factory.fail = True
|
||||
with pytest.raises(RelayError):
|
||||
ctrl.connect("h")
|
||||
assert ctrl.active_hosts == []
|
||||
ctrl.stop()
|
||||
|
||||
|
||||
def test_start_relay_blocked_by_gating():
|
||||
for kw in ({"relay_enabled": False}, {"published": False}, {"signed_in": False}):
|
||||
ctrl, trust, _ = build(**kw)
|
||||
assert ctrl.start_relay("h") is False
|
||||
assert trust.calls == []
|
||||
ctrl.stop()
|
||||
|
||||
|
||||
def test_start_relay_is_resilient_to_failure():
|
||||
ctrl, _, factory = build()
|
||||
factory.fail = True
|
||||
assert ctrl.start_relay("h") is False # logs + swallows, does not raise
|
||||
ctrl.stop()
|
||||
|
||||
|
||||
def test_start_relay_ok():
|
||||
ctrl, _, _ = build()
|
||||
try:
|
||||
assert ctrl.start_relay("h", 443) is True
|
||||
assert ctrl.active_hosts == ["h"]
|
||||
finally:
|
||||
ctrl.stop()
|
||||
|
||||
|
||||
def test_reaper_removes_dead():
|
||||
ctrl, _, factory = build()
|
||||
try:
|
||||
ctrl.connect("a")
|
||||
ctrl.connect("b")
|
||||
factory.created[0].alive = False
|
||||
assert ctrl.reap_once() == ["a"]
|
||||
assert ctrl.active_hosts == ["b"]
|
||||
assert factory.created[0].stopped is True
|
||||
finally:
|
||||
ctrl.stop()
|
||||
|
||||
|
||||
def test_stop_terminates_all_and_closes():
|
||||
ctrl, _, factory = build()
|
||||
ctrl.connect("a")
|
||||
ctrl.connect("b")
|
||||
ctrl.stop()
|
||||
assert ctrl.active_hosts == []
|
||||
assert all(t.stopped for t in factory.created)
|
||||
with pytest.raises(RelayError):
|
||||
ctrl.connect("c")
|
||||
|
||||
|
||||
def test_from_config_builds_controller(tmp_path):
|
||||
cfg = RelayConfig(token="t", ssh_user="u", data_dir=tmp_path)
|
||||
assert isinstance(RelayController.from_config(cfg), RelayController)
|
||||
Reference in new issue
Block a user