mirror of
https://github.com/rommapp/romm.git
synced 2026-06-28 06:46:00 +00:00
fix(screenscraper): inject user credentials for cover, manual, and screenshot downloads
Standard media fields (url_cover, url_manual, url_screenshots) were downloaded using the stored credential-less URLs, causing them to count against the anonymous IP quota instead of the user's SS account. Apply add_ss_auth_to_url() at each download call site in the scan and ROM update paths. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> fix(screenscraper): guard add_ss_auth_to_url against non-SS URLs Only inject ssid/sspassword into screenscraper.fr URLs to prevent leaking user credentials to third-party sources (IGDB, LaunchBox, etc.) when url_cover/url_manual/url_screenshots originate from other providers. Add tests for the non-SS no-op and empty-string edge cases. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> test(screenscraper): verify SS credentials injected for all media download paths - TestAddSsAuthToUrl: add guards for non-SS URLs (IGDB, LaunchBox) and empty string inputs - test_update_rom: verify ssid/sspassword appear in url_cover and url_manual args passed to get_cover/get_manual for screenscraper.fr URLs; verify IGDB URLs are NOT decorated with SS credentials - TestScanCredentialInjection: verify the scan-path ternary pattern correctly applies add_ss_auth_to_url to cover and screenshot URLs, and that a None cover URL passes through without error Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> test(screenscraper): empirical audit — every SS request carries ssid/sspassword Intercepts both HTTP clients at the transport/session level to verify that every outgoing screenscraper.fr request is decorated with the user's ssid and sspassword credentials: aiohttp (API calls via auth_middleware): - jeuInfos.php, jeuRecherche.php, ssinfraInfos.php, ssuserInfos.php httpx (media downloads via FSResourcesHandler): - get_cover → url_cover - get_manual → url_manual - get_rom_screenshots → url_screenshots (each URL) - store_media_file → extra media (fanart, bezel, etc.) Also verifies the domain guard: IGDB URLs passed through add_ss_auth_to_url are NOT decorated with SS credentials. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1282,7 +1282,7 @@ async def update_rom(
|
||||
path_screenshots = await fs_resource_handler.get_rom_screenshots(
|
||||
rom=rom,
|
||||
overwrite=bool(screenshots_changed),
|
||||
url_screenshots=cleaned_data.get("url_screenshots", []),
|
||||
url_screenshots=[add_ss_auth_to_url(u) for u in url_screenshots],
|
||||
)
|
||||
cleaned_data.update(
|
||||
{"path_screenshots": path_screenshots, "url_screenshots": []}
|
||||
@@ -1353,7 +1353,7 @@ async def update_rom(
|
||||
path_cover_s, path_cover_l = await fs_resource_handler.get_cover(
|
||||
entity=rom,
|
||||
overwrite=url_cover != rom.url_cover,
|
||||
url_cover=str(url_cover),
|
||||
url_cover=add_ss_auth_to_url(str(url_cover)),
|
||||
)
|
||||
cleaned_data.update(
|
||||
{
|
||||
@@ -1373,7 +1373,7 @@ async def update_rom(
|
||||
path_manual = await fs_resource_handler.get_manual(
|
||||
rom=rom,
|
||||
overwrite=url_manual != rom.url_manual,
|
||||
url_manual=str(url_manual) if url_manual else None,
|
||||
url_manual=add_ss_auth_to_url(str(url_manual)) if url_manual else None,
|
||||
)
|
||||
cleaned_data.update(
|
||||
{
|
||||
|
||||
@@ -396,13 +396,21 @@ async def _identify_rom(
|
||||
path_cover_s, path_cover_l = await fs_resource_handler.get_cover(
|
||||
entity=_added_rom,
|
||||
overwrite=_added_rom.url_cover != rom.url_cover,
|
||||
url_cover=_added_rom.url_cover,
|
||||
url_cover=(
|
||||
add_ss_auth_to_url(_added_rom.url_cover)
|
||||
if _added_rom.url_cover
|
||||
else _added_rom.url_cover
|
||||
),
|
||||
)
|
||||
|
||||
path_manual = await fs_resource_handler.get_manual(
|
||||
rom=_added_rom,
|
||||
overwrite=_added_rom.url_manual != rom.url_manual,
|
||||
url_manual=_added_rom.url_manual,
|
||||
url_manual=(
|
||||
add_ss_auth_to_url(_added_rom.url_manual)
|
||||
if _added_rom.url_manual
|
||||
else _added_rom.url_manual
|
||||
),
|
||||
)
|
||||
|
||||
screenshots_changed = pydash.xor(
|
||||
@@ -411,7 +419,9 @@ async def _identify_rom(
|
||||
path_screenshots = await fs_resource_handler.get_rom_screenshots(
|
||||
rom=_added_rom,
|
||||
overwrite=bool(screenshots_changed),
|
||||
url_screenshots=_added_rom.url_screenshots,
|
||||
url_screenshots=[
|
||||
add_ss_auth_to_url(u) for u in (_added_rom.url_screenshots or [])
|
||||
],
|
||||
)
|
||||
|
||||
_added_rom.path_cover_s = path_cover_s
|
||||
|
||||
@@ -34,8 +34,17 @@ from .base_handler import (
|
||||
SENSITIVE_KEYS = {"ssid", "sspassword"}
|
||||
|
||||
|
||||
SS_DOMAIN = "screenscraper.fr"
|
||||
|
||||
|
||||
def add_ss_auth_to_url(url: str) -> str:
|
||||
"""Re-add SS user credentials to a media URL at download time (never stored)."""
|
||||
"""Re-add SS user credentials to a media URL at download time (never stored).
|
||||
|
||||
Only injects credentials for screenscraper.fr URLs; returns other URLs
|
||||
unchanged to avoid leaking credentials to third-party sources.
|
||||
"""
|
||||
if not url or SS_DOMAIN not in url:
|
||||
return url
|
||||
if not SCREENSCRAPER_USER or not SCREENSCRAPER_PASSWORD:
|
||||
return url
|
||||
|
||||
|
||||
@@ -1045,7 +1045,7 @@ async def scan_rom(
|
||||
extra=LOGGER_MODULE_NAME,
|
||||
)
|
||||
|
||||
if rom.has_nested_single_file or rom.has_multiple_files:
|
||||
if fs_rom["nested"]:
|
||||
for file in fs_rom["files"]:
|
||||
log.info(
|
||||
f"\t · {hl(file.file_name, color=LIGHTYELLOW)}",
|
||||
|
||||
Reference in New Issue
Block a user