Conversation
…ty and performance
…ction for improved clarity and maintainability
…n row_generator service
Cherry-pick features from main: TMDB language-aware image fetching for posters/logos/backgrounds, and translation fix that preserves item titles in catalog names instead of translating them word-by-word. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
| e.preventDefault(); | ||
| e.stopPropagation(); | ||
| const url = document.getElementById('addonUrl').textContent; | ||
| window.location.href = `stremio://${url.replace(/^https?:\/\//, '')}`; |
Check failure
Code scanning / CodeQL
DOM text reinterpreted as HTML High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 4 days ago
General fix: When reading data from the DOM and reusing it in another sensitive context (here, as a URL for navigation), validate and normalize it rather than trusting the raw string. Ensure that only expected schemes, hostnames, and path characters are allowed, and avoid interpreting arbitrary text as a protocol URL.
Best specific fix here: Validate the url read from addonUrl before using it to build the stremio:// URL. A robust approach is:
- Trim the string and ensure it is non-empty.
- Normalize it as an HTTP(S) URL first via the
URLconstructor to ensure it has the expected scheme and structure. - Extract the host and path from the normalized URL, and reconstruct the
stremio://URL from those parts, rather than doing a naive stringreplace. - If parsing fails or the scheme is not
httporhttps, abort (or show an error) instead of navigating.
This preserves functionality (it still converts an HTTP(S) addon URL into a stremio:// URL) but prevents arbitrary text from becoming an unchecked custom-protocol URL. All changes are confined to app/static/js/modules/form-success.js, specifically around lines 25–27. No new imports are needed.
Concretely, we will replace:
const url = document.getElementById('addonUrl').textContent;
window.location.href = `stremio://${url.replace(/^https?:\/\//, '')}`;with logic that:
- Reads and trims the text;
- Uses
new URL(...)to parse it (falling back tohttps://if no scheme is provided); - Verifies the protocol is
http:orhttps:; - Builds
stremio://usingurlObj.host + urlObj.pathname + urlObj.search + urlObj.hash; - Handles parsing errors by not redirecting (optionally using
showErrorif we want minimal behavior change; to avoid new behavior we can just silently return).
| @@ -22,8 +22,31 @@ | ||
| installDesktopBtn.addEventListener('click', (e) => { | ||
| e.preventDefault(); | ||
| e.stopPropagation(); | ||
| const url = document.getElementById('addonUrl').textContent; | ||
| window.location.href = `stremio://${url.replace(/^https?:\/\//, '')}`; | ||
| const rawText = document.getElementById('addonUrl').textContent || ''; | ||
| const trimmed = rawText.trim(); | ||
| if (!trimmed) { | ||
| return; | ||
| } | ||
|
|
||
| let normalizedUrl; | ||
| try { | ||
| // Ensure we have an absolute HTTP(S) URL before converting to the stremio:// protocol | ||
| if (/^https?:\/\//i.test(trimmed)) { | ||
| normalizedUrl = new URL(trimmed); | ||
| } else { | ||
| normalizedUrl = new URL(`https://${trimmed}`); | ||
| } | ||
| } catch (_) { | ||
| // If the URL is not valid, do not attempt to navigate | ||
| return; | ||
| } | ||
|
|
||
| if (normalizedUrl.protocol !== 'http:' && normalizedUrl.protocol !== 'https:') { | ||
| return; | ||
| } | ||
|
|
||
| const addonTarget = `${normalizedUrl.host}${normalizedUrl.pathname}${normalizedUrl.search}${normalizedUrl.hash}`; | ||
| window.location.href = `stremio://${addonTarget}`; | ||
| }); | ||
| } | ||
|
|
| username = user_info.get("user", {}).get("username") or user_info.get("username", "Unknown") | ||
| except Exception as e: | ||
| logger.error(f"Trakt OAuth callback failed: {e}") | ||
| return HTMLResponse(_oauth_error_page("Trakt", str(e))) |
Check warning
Code scanning / CodeQL
Information exposure through an exception Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 5 days ago
In general, the fix is to stop exposing raw exception messages (str(e)) to the user and instead return a generic, non-sensitive error message while logging the detailed error server-side. The logging preserves debuggability; the user sees only a high-level explanation like “Trakt authorization failed. Please try again.”
Concretely for this file:
- Keep logging the exception using
logger.error(...)(possibly withexc_info=Trueif desired), so developers still get full details. - Change
_oauth_error_pageso it no longer accepts or renders an arbitrary error string. Instead, have it generate a static, generic error page for the given provider. - Update the call at line 52 from
_oauth_error_page("Trakt", str(e))to simply_oauth_error_page("Trakt"). - Adjust
_oauth_error_page’s signature and body accordingly: remove theerrorparameter and the<p>{error}</p>line, perhaps replace it with a generic message like “An error occurred while communicating with Trakt.”
All needed functionality is already available; no new imports or helpers are required. All changes are within app/api/endpoints/oauth.py at the shown locations.
| @@ -49,7 +49,7 @@ | ||
| username = user_info.get("user", {}).get("username") or user_info.get("username", "Unknown") | ||
| except Exception as e: | ||
| logger.error(f"Trakt OAuth callback failed: {e}") | ||
| return HTMLResponse(_oauth_error_page("Trakt", str(e))) | ||
| return HTMLResponse(_oauth_error_page("Trakt")) | ||
|
|
||
| return HTMLResponse( | ||
| _oauth_success_page( | ||
| @@ -159,11 +159,11 @@ | ||
| </body></html>""" | ||
|
|
||
|
|
||
| def _oauth_error_page(provider: str, error: str) -> str: | ||
| def _oauth_error_page(provider: str) -> str: | ||
| return f"""<!DOCTYPE html> | ||
| <html><head><title>{provider.title()} Error</title></head> | ||
| <body> | ||
| <h2>{provider.title()} login failed</h2> | ||
| <p>{error}</p> | ||
| <p>An error occurred while communicating with {provider.title()}. Please try again.</p> | ||
| <p>Please close this window and try again.</p> | ||
| </body></html>""" |
| username = user_info.get("user", {}).get("name") or user_info.get("account", {}).get("id", "Unknown") | ||
| except Exception as e: | ||
| logger.error(f"Simkl OAuth callback failed: {e}") | ||
| return HTMLResponse(_oauth_error_page("Simkl", str(e))) |
Check warning
Code scanning / CodeQL
Information exposure through an exception Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 5 days ago
In general, to fix information exposure through exceptions, you should log full exception details on the server and return only a high-level, user-friendly, generic error message to the client. Do not interpolate raw exception messages, stack traces, or internal configuration values into responses.
For this specific code, the best minimal change is to stop passing str(e) into _oauth_error_page and instead pass a generic message such as "An internal error occurred while connecting to Simkl." (or similar). This avoids changing the function signature or overall behavior of the endpoint: the user still gets an error page, but without internal details. The server-side logging with logger.error remains, so you still have all diagnostic detail in logs.
Concretely:
- In
app/api/endpoints/oauth.py, within thesimkl_callbackfunction’sexceptblock, replacereturn HTMLResponse(_oauth_error_page("Simkl", str(e)))with a call that uses a static, non-sensitive message string. - No additional imports or helper methods are required; we reuse
_oauth_error_pageas-is. _oauth_error_pageitself remains unchanged; it will receive the safe message string and render it.
| @@ -126,7 +126,7 @@ | ||
| username = user_info.get("user", {}).get("name") or user_info.get("account", {}).get("id", "Unknown") | ||
| except Exception as e: | ||
| logger.error(f"Simkl OAuth callback failed: {e}") | ||
| return HTMLResponse(_oauth_error_page("Simkl", str(e))) | ||
| return HTMLResponse(_oauth_error_page("Simkl", "An internal error occurred while connecting to Simkl.")) | ||
|
|
||
| return HTMLResponse( | ||
| _oauth_success_page( |
There was a problem hiding this comment.
Code Review
This pull request introduces significant architectural changes, including the addition of OAuth support for Trakt and Simkl, a refactored token management system, and a new unified library/history model. While these changes expand functionality, several critical issues were identified: an AttributeError in the profile service due to incorrect attribute access on Pydantic models, a security vulnerability in the OAuth callback using a wildcard origin for postMessage, a missing import for the caching decorator in the TMDB service, and a breaking change to the health check endpoint's response format.
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
No description provided.