Added controller for the native world helper.
This commit is contained in:
66
ptlinux/world_fix.py
Normal file
66
ptlinux/world_fix.py
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
"""Exact-profile selection for the post-login V21 world-transition helper."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
V21_BINARY_HASHES = {
|
||||||
|
"Game.exe": "2bc3edd26c5f6d7ae9bbdc23967c5aefd374bdf934fcdfa2ed42c6442e550837",
|
||||||
|
"game.dll": "4b4e5c28e2bfdaa8d36c8341fad27becfd03faf63aa8ea874f5d43c5b1961868",
|
||||||
|
}
|
||||||
|
WORLD_FIX_HELPER_FILENAME = "pt-world-fix.exe"
|
||||||
|
# Filled from the reproducible stripped PE after the native helper is built.
|
||||||
|
WORLD_FIX_HELPER_SHA256 = (
|
||||||
|
"d5bdf655f62dae429eff627cf8960f670ec59c12a9759dcd14342786f53e4019"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class WorldFixError(RuntimeError):
|
||||||
|
"""Raised when an exact client needs a missing or untrusted helper."""
|
||||||
|
|
||||||
|
|
||||||
|
def packaged_world_fix_helper() -> Path:
|
||||||
|
return Path(__file__).resolve().parent / "native" / WORLD_FIX_HELPER_FILENAME
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_world_fix_helper(
|
||||||
|
game_directory: Path,
|
||||||
|
*,
|
||||||
|
helper: Path | None = None,
|
||||||
|
) -> Path | None:
|
||||||
|
"""Return the verified helper only for the exact publisher V21 pair."""
|
||||||
|
|
||||||
|
game = game_directory.expanduser().resolve(strict=False)
|
||||||
|
hashes = {
|
||||||
|
name: _sha256(game / name)
|
||||||
|
for name in V21_BINARY_HASHES
|
||||||
|
if (game / name).is_file()
|
||||||
|
}
|
||||||
|
if hashes != V21_BINARY_HASHES:
|
||||||
|
return None
|
||||||
|
requested = packaged_world_fix_helper() if helper is None else helper.expanduser()
|
||||||
|
if requested.is_symlink():
|
||||||
|
raise WorldFixError(
|
||||||
|
"the post-login world-fix helper must not be a symbolic link"
|
||||||
|
)
|
||||||
|
candidate = requested.resolve()
|
||||||
|
if not candidate.is_file():
|
||||||
|
raise WorldFixError(
|
||||||
|
"the verified post-login world-fix helper is missing; reinstall the launcher"
|
||||||
|
)
|
||||||
|
digest = _sha256(candidate)
|
||||||
|
if digest != WORLD_FIX_HELPER_SHA256:
|
||||||
|
raise WorldFixError(
|
||||||
|
"the post-login world-fix helper failed its launcher integrity check"
|
||||||
|
)
|
||||||
|
return candidate
|
||||||
|
|
||||||
|
|
||||||
|
def _sha256(path: Path) -> str:
|
||||||
|
digest = hashlib.sha256()
|
||||||
|
with path.open("rb") as handle:
|
||||||
|
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
|
||||||
|
digest.update(chunk)
|
||||||
|
return digest.hexdigest()
|
||||||
Reference in New Issue
Block a user