Commit Graph

9574 Commits

Author SHA1 Message Date
Georges-Antoine Assi
2b0ed2296b cleanup 2026-05-27 09:29:21 -04:00
Georges-Antoine Assi
3ae7f998b9 run fmt 2026-05-27 09:20:23 -04:00
Claude
009d358175 fix(security): resolve hostnames in SSRF URL validator
validate_url_for_http_request previously skipped DNS resolution, so
attacker-controlled domains that resolve to private/loopback/link-local
addresses (e.g. 127.0.0.1.nip.io) passed validation and the subsequent
httpx GET hit internal services. Resolve the hostname via getaddrinfo
and reject any result whose IP is private, loopback, link-local,
reserved, multicast, or unspecified. Unresolvable hostnames are
rejected as well.

https://claude.ai/code/session_01T335ZvA825YhuzPctmYzUy
2026-05-27 12:33:36 +00:00
Georges-Antoine Assi
84f9dd2e2d Merge pull request #3434 from rommapp/copilot/fix-region-specific-release-date
Use region-prioritized release dates from ScreenScraper
2026-05-26 21:14:21 -04:00
Georges-Antoine Assi
29ce936c7d Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-26 20:45:41 -04:00
copilot-swe-agent[bot]
511f5e4272 Revert IGDB handler and test changes
Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-05-27 00:06:50 +00:00
Georges-Antoine Assi
830902c21e Merge pull request #3438 from Spinnich/fix/screenscraper-std-media-credentials
fix(screenscraper): inject user credentials for all standard media downloads
2026-05-26 19:58:22 -04:00
Georges-Antoine Assi
f5b1d44313 changes from bot review 2026-05-26 19:52:16 -04:00
Georges-Antoine Assi
04241169d7 fix 2026-05-26 19:36:38 -04:00
Georges-Antoine Assi
e013ee78e1 fix 2026-05-26 19:26:52 -04:00
Georges-Antoine Assi
09aecc81bf cleanup 2026-05-26 18:22:12 -04:00
Spinnich
3c2f421dbb 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>
2026-05-26 20:50:18 +00:00
Georges-Antoine Assi
6bc3d58d8a Merge pull request #3437 from rommapp/claude/gallant-bell-qLNfe
Upgrade FastAPI to 0.134.0 and Starlette to 1.0.1
2026-05-26 16:08:31 -04:00
Claude
8b21487099 fix(deps): bump starlette to 1.0.1 for CVE-2026-48710
Starlette versions 0.8.3-1.0.0 are vulnerable to improper Host header
validation when reconstructing request.url, which can cause
request.url.path to differ from the actual requested path and bypass
path-based security checks. Patched in 1.0.1.

Bumps fastapi to 0.134.0 since 0.121.x pins starlette<0.50.0.

https://claude.ai/code/session_01P9NtqqFN9dVW1c5Uno6oRC
2026-05-26 19:22:31 +00:00
copilot-swe-agent[bot]
536f6ac815 fix: use region-aware release dates for SS and IGDB metadata
Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-05-26 13:21:39 +00:00
copilot-swe-agent[bot]
9f2e8da964 Initial plan 2026-05-26 13:05:58 +00:00
Georges-Antoine Assi
c261d5eeea Merge pull request #3432 from rommapp/claude/awesome-gates-NUpke
perf(roms): avoid hydrating full Rom rows for siblings on list endpoint
2026-05-25 12:26:57 -04:00
Georges-Antoine Assi
fb3cc1da87 perf 2026-05-25 12:00:14 -04:00
Georges-Antoine Assi
9e9a282286 fix(roms): dedupe and sort sibling IDs for stable API output
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 11:35:16 -04:00
Georges-Antoine Assi
5e8fac36a7 Merge branch 'master' into claude/awesome-gates-NUpke 2026-05-25 11:10:04 -04:00
Georges-Antoine Assi
b9b82c751b more cleanup 2026-05-25 11:07:03 -04:00
Georges-Antoine Assi
9a87348c22 cleanup 2026-05-25 11:02:35 -04:00
Georges-Antoine Assi
37bddd4b17 Merge pull request #3431 from rommapp/copilot/fix-fullscreen-emulation-ios
Add iOS pseudo-fullscreen shim for EmulatorJS player
2026-05-25 10:45:38 -04:00
Georges-Antoine Assi
31e6d995a6 simplify 2026-05-25 10:38:54 -04:00
Georges-Antoine Assi
d4bc2418a5 Merge pull request #3428 from Spinnich/fix/m3u-crc-non-ascii-filenames
fix(nginx): use Buffer for binary-safe base64 decode in m3u endpoint
2026-05-25 08:34:03 -04:00
copilot-swe-agent[bot]
ce7ffaf552 fix: add ios fullscreen shim for emulatorjs
Co-authored-by: gantoine <3247106+gantoine@users.noreply.github.com>
2026-05-25 12:02:08 +00:00
copilot-swe-agent[bot]
667672bba5 Initial plan 2026-05-25 11:54:20 +00:00
Spinnich
e943cc7e2d fix(nginx): use Buffer for binary-safe base64 decode in m3u endpoint
atob() decodes base64 to a JS string, which r.return() then re-encodes
as UTF-8. For filenames with non-ASCII characters (e.g. Pokémon), bytes
above 0x7F get double-encoded — serving different content than what the
backend computed the CRC32 over, causing mod_zip to report CRC failure
on the .m3u file.

Buffer.from(value, 'base64') decodes directly to a byte array and
r.return() sends it verbatim, matching the CRC exactly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 00:16:23 +00:00
Claude
95b1a99f2a perf(roms): avoid hydrating full Rom rows for siblings on list endpoint
The paginated ROM list eager-loaded sibling_roms via selectinload, which
hydrated full Rom ORM instances (including heavy JSON metadata columns)
for every sibling even though only an existence/count check was needed
on the frontend. On large collections this dominated request latency.

Split sibling handling by response shape:
- SimpleRomSchema (list): siblings is now list[int]; populated per page
  by a single SELECT against the sibling_roms view projecting only
  (rom_id, sibling_rom_id) — no Rom row hydration.
- DetailedRomSchema (detail): keeps full SiblingRomSchema objects, with
  load_only on (id, name, fs_name_no_tags, fs_name_no_ext) so sibling
  rows stop dragging in JSON metadata.

Frontend usage already only consumes siblings.length on list views; the
detail-page VersionSwitcher continues to receive the richer schema.
2026-05-24 23:17:34 +00:00
Georges-Antoine Assi
9b97e32f54 Merge pull request #3425 from rommapp/claude/ecstatic-dirac-dFQQO
Denormalize ROM file stats for efficient gallery rendering
2026-05-24 19:04:12 -04:00
Georges-Antoine Assi
1a560d3660 cleanup 2026-05-24 18:57:38 -04:00
Georges-Antoine Assi
fb13f54f48 cleanup 2026-05-24 17:43:01 -04:00
Claude
8fcc16bad2 refactor(roms): replace denormalized columns with deferred column_property
Drop the migration and the multi_file / top_level_file_count columns on
roms; express both as deferred column_property correlated subqueries
against rom_files instead. The gallery list and detail queries opt in
via undefer, so they get the values computed in the same SELECT via
indexed subqueries (rom_id index already in place); other code paths
that don't read the flags pay nothing.

This keeps the gallery perf win (no rom_files load for cards) without
introducing schema state that has to stay in sync with rom_files at
write time.
2026-05-24 20:41:44 +00:00
Georges-Antoine Assi
63644d0c6f Merge pull request #3426 from rommapp/claude/loving-darwin-pveIr
Defer optional handler initialization with lazy factories
2026-05-24 16:18:24 -04:00
Georges-Antoine Assi
bb2b99099b fix(sync): isolate SSH handler init errors to per-device failure
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 16:12:10 -04:00
Georges-Antoine Assi
5342f96863 remove comment 2026-05-24 16:04:10 -04:00
Georges-Antoine Assi
0eec8b0e47 Merge pull request #3424 from rommapp/copilot/fix-csrf-token-issue
Refresh CSRF cookie on OIDC session authentication changes
2026-05-24 15:57:30 -04:00
Georges-Antoine Assi
be476cb7dc Only set CSRF cookie on http.response.start
ASGI spec only allows headers on the http.response.start message;
appending Set-Cookie to body messages is out-of-spec and may break on
some servers. Early-return for non-start messages.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 15:46:50 -04:00
Georges-Antoine Assi
79127696e5 Merge pull request #3423 from rommapp/copilot/fix-boot-loop-opentelemetry
Guard init startup against OpenTelemetry boot-loop conditions
2026-05-24 15:29:51 -04:00
Georges-Antoine Assi
354207d683 Drop redundant out_arr reset in otel_prefix
All callers declare a fresh `local -a wrap=()` before invoking, so the
in-function reset is unnecessary.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 15:17:42 -04:00
Georges-Antoine Assi
a4f1f516bc Simplify OTEL wrapper helper and fix shell quoting
Collapse `otel_prefix` and `otel_prefix_str` into a single nameref-based
helper. Watchfiles call sites embed the array as a shell-quoted prefix
via `${wrap[*]@Q}`, which also fixes a quoting bug where an
`OTEL_SERVICE_NAME_PREFIX` containing a single quote would produce an
invalid command string and break the watcher.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 14:57:52 -04:00
Claude
f434fde772 Refactor OTEL wrapping into shared helpers
Collapse the duplicated OTEL_SDK_DISABLED / opentelemetry-instrument
branches in run_startup, start_bin_gunicorn, start_bin_watcher, and
start_bin_sync_watcher into two small helpers:

- otel_prefix: emits the wrapper as NUL-delimited argv tokens (for
  direct process invocation).
- otel_prefix_str: emits the wrapper as a shell-string prefix (for
  embedding inside `watchfiles --target-type command`).

Each call site becomes a single command instead of a 2- or 3-way
branch with a fully duplicated command body. As a side effect, the
watcher functions now also gain the `command -v opentelemetry-instrument`
fallback that the gunicorn/startup paths added.
2026-05-24 18:21:40 +00:00
Georges-Antoine Assi
98d03a5720 Merge pull request #3422 from rommapp/copilot/fix-folder-tag-import-issue
Support `<folder>` entries in gamelist.xml metadata import
2026-05-24 14:14:14 -04:00
Georges-Antoine Assi
8af556ee46 run fmt 2026-05-24 14:07:45 -04:00
Georges-Antoine Assi
acc1e630b7 Apply suggestions from code review
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-05-24 14:05:58 -04:00
Georges-Antoine Assi
4d8c2ef54b Merge branch 'master' into copilot/fix-folder-tag-import-issue 2026-05-24 13:33:36 -04:00
Georges-Antoine Assi
ae09707197 Merge pull request #3421 from rommapp/copilot/fix-gamelist-xml-import
Handle malformed ES-DE `<alternativeEmulator>` tags during gamelist.xml import
2026-05-24 13:31:32 -04:00
Georges-Antoine Assi
e7bde8a190 simplify 2026-05-24 13:13:11 -04:00
Georges-Antoine Assi
5fdb69d53c fixes 2026-05-24 13:09:07 -04:00
Claude
5adffeca71 perf(roms): skip rom_files load on gallery list endpoint
The gallery list endpoint was eager-loading every rom_file row for each
paginated ROM via selectinload, then re-joining each row back to its
parent rom for the is_top_level computation. For platforms with extracted
multi-file ROMs (Xbox 360 ~1394 files/ROM, Switch ~199 files/ROM), this
made /api/roms time out at 120s even with a rom_id index.

Cards never displayed individual files — only the has_simple_single_file
/ has_nested_single_file / has_multiple_files booleans that derive from
the file list. Denormalize the underlying state onto roms as multi_file
(folder-based vs single-file) and top_level_file_count, recompute the
booleans from those columns, drop the selectinload from filter_roms, and
move the files field from SimpleRomSchema to DetailedRomSchema so the
gallery payload no longer ships file rows.

Also drop the redundant joinedload(RomFile.rom) and switch the relation
to lazy="select" so subsequent file.rom accesses resolve from the
session identity map instead of re-JOINing the parent rom per file row.

ShowQRCode.vue's folder-based DS/3DS fallback now fetches the detailed
rom on demand, since SimpleRom no longer carries files.
2026-05-24 15:02:02 +00:00