Conversation
WalkthroughThis pull request implements a custom protocol handler for "flow-utility" in the Electron browser process to serve files based on URL paths, with validations and MIME type resolution. It adds error handling in tab loading by redirecting to a designated error page. New utility functions are introduced for file existence checks and content type determination. Additionally, the Browser class is now exported, dependency versions in the Electron package have been updated, and the Vite project has been enhanced with new routes and React components for a custom error page. Changes
Sequence Diagram(s)sequenceDiagram
participant App as Application
participant PH as Protocol Handler
participant FS as fsPromises
participant UT as getContentType Utility
App->>PH: Request "flow-utility://page/..."
PH->>FS: Check file existence
FS-->>PH: File exists? (Yes/No)
alt File exists
PH->>FS: Read file contents
FS-->>PH: Return file contents
PH->>UT: Determine MIME type
UT-->>PH: Return MIME type
PH->>App: Respond with file content & headers
else File not found
PH->>App: Return error response (404/400)
end
sequenceDiagram
participant Tab as Tab Component
participant WC as WebContents
participant ER as Error Redirect
participant RP as React Error Page
WC->>Tab: Trigger "did-fail-load" event
Tab->>Tab: Validate error conditions (main frame & non-abort)
Tab->>ER: Construct error page URL with query params
Tab->>WC: Execute JS to update window location to error page
ER->>RP: Load and render the error page
RP->>RP: Display error details and provide reload/back options
Poem
Tip ⚡🧪 Multi-step agentic review comment chat (experimental)
📜 Recent review detailsConfiguration used: CodeRabbit UI ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (3)
🔇 Additional comments (1)
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (4)
vite/src/routes/error/index.html (1)
1-11: Clean HTML template for error page.This is a minimal and well-structured HTML template that follows best practices:
- Proper DOCTYPE declaration
- Includes language attribute for accessibility
- Sets appropriate character encoding and viewport meta tags
- Creates a root element for mounting the React application
- Uses module script to load the entry point
Consider adding a title element to improve accessibility and provide context in browser tabs.
<head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Error - Flow Browser</title> </head>electron/browser/tabs.ts (1)
46-46: Consider removing commented code.The commented-out line that uses
loadURLinstead ofexecuteJavaScriptshould be either implemented or removed to maintain clean code.- // this.webContents.loadURL(errorPageURL.toString());electron/browser/utils.ts (1)
12-42: Consider expanding MIME type support for future extensibility.The
getContentTypefunction handles common file types but may need to be expanded as the application grows. Consider adding more file extensions or implementing a more scalable solution like using themime-typespackage.-export function getContentType(filePath: string) { - const fileExtension = path.extname(filePath).toLowerCase(); - let contentType = "text/plain"; - - switch (fileExtension) { - case ".html": - contentType = "text/html"; - break; - case ".js": - contentType = "application/javascript"; - break; - case ".css": - contentType = "text/css"; - break; - case ".json": - contentType = "application/json"; - break; - case ".png": - contentType = "image/png"; - break; - case ".jpg": - case ".jpeg": - contentType = "image/jpeg"; - break; - case ".svg": - contentType = "image/svg+xml"; - break; - } - - return contentType; +import mime from 'mime-types'; + +export function getContentType(filePath: string) { + return mime.lookup(filePath) || 'text/plain'; +}electron/browser/main.ts (1)
489-489: Consider making allowed directories configurable.The
FLOW_UTILITY_ALLOWED_DIRECTORIESarray is hardcoded with just "error". Consider making this configurable or moving it to a constants file for better maintainability as the application grows.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
.DS_Storeis excluded by!**/.DS_Storebun.lockis excluded by!**/*.lock
📒 Files selected for processing (9)
electron/browser/main.ts(4 hunks)electron/browser/tabs.ts(1 hunks)electron/browser/utils.ts(1 hunks)electron/index.ts(1 hunks)electron/package.json(1 hunks)vite/src/lib/url.ts(1 hunks)vite/src/routes/error/index.html(1 hunks)vite/src/routes/error/index.tsx(1 hunks)vite/src/routes/error/page.tsx(1 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
vite/src/routes/error/page.tsx
[error] 99-99: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
🔇 Additional comments (11)
electron/index.ts (1)
1-2: Import style change looks good.The change from default import to named import for Browser aligns with the updated export in the browser/main module. This makes the import declarations more explicit about what's being imported.
vite/src/routes/error/index.tsx (1)
1-13: Well-structured React entry point.This is a clean implementation of a React application entry point following best practices:
- Uses StrictMode for additional checks during development
- Properly incorporates ThemeProvider for theme context
- Follows the standard pattern for mounting a React app to a DOM element
The non-null assertion operator (!) on getElementById suggests you're confident the "root" element will always exist in the DOM, which is fine since it's defined in the corresponding HTML file.
electron/browser/tabs.ts (1)
35-48: Good implementation of error handling for failed page loads.The event listener for "did-fail-load" properly redirects users to a custom error page when a page fails to load, enhancing the user experience. The implementation correctly ignores aborted operations (error code -3) which are typically user-initiated cancellations.
electron/browser/utils.ts (1)
5-10: Good implementation of async file existence check.The
isFileExistsfunction correctly uses fsPromises with async/await pattern and properly handles errors through the Promise chain.vite/src/routes/error/page.tsx (4)
10-53: Well-structured error information object with comprehensive coverage of common error scenarios.The error information mapping provides user-friendly messages for various error codes, which improves the user experience significantly.
66-77: Smart handling of URL parameters in the useEffect hook.The implementation correctly removes the "initial" parameter after first load and handles page reloading appropriately, preventing unnecessary redirects.
79-132: Excellent UI implementation with responsive design and dark mode support.The error page UI is well-designed with responsive layouts, animation effects, and proper dark mode support, providing a good user experience across different environments.
🧰 Tools
🪛 Biome (1.9.4)
[error] 99-99: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
97-100:Details
✅ Verification successful
Security vulnerability with dangerouslySetInnerHTML.
Using
dangerouslySetInnerHTMLwith content that includes URL parameters could expose users to cross-site scripting (XSS) attacks. Consider sanitizing the HTML content before rendering.- <div - className="text-gray-600 dark:text-zinc-400 mb-6 text-center" - dangerouslySetInnerHTML={{ __html: errorInfo.description }} - /> +import DOMPurify from 'dompurify'; + +// Earlier in your component: +const sanitizedDescription = DOMPurify.sanitize(errorInfo.description); + +// Then in your JSX: + <div + className="text-gray-600 dark:text-zinc-400 mb-6 text-center" + dangerouslySetInnerHTML={{ __html: sanitizedDescription }} + />
🌐 Web query:
Is DOMPurify an effective solution for preventing XSS attacks in React applications?💡 Result:
DOMPurify is a highly effective solution for preventing XSS attacks in React applications when implemented correctly. It provides robust sanitization of HTML content by removing malicious elements while preserving safe markup, making it a critical defense layer in scenarios requiring dynamic content rendering.
Key Strengths of DOMPurify in React
Whitelist-Based Sanitization
DOMPurify uses a whitelist approach, allowing only pre-approved HTML elements and attributes (e.g.,hreffor<a>tags) while stripping risky ones like<script>oronerrorhandlers[1][8]. This proactive method outperforms blacklist-based solutions.Integration with
dangerouslySetInnerHTML
React’s default escaping prevents XSS in JSX bindings but offers no protection when usingdangerouslySetInnerHTML. DOMPurify fills this gap:import DOMPurify from 'dompurify'; const cleanHTML = DOMPurify.sanitize(userInput); return <div dangerouslySetInnerHTML={{ __html: cleanHTML }} />;This sanitizes user-generated HTML before rendering[3][4][11].
Context-Aware Filtering
DOMPurify adapts sanitization rules based on the DOM context (e.g., HTML vs. SVG namespaces), reducing bypass risks[2][12]. For example, SVG content requires explicit configuration:// Explicitly set SVG namespace for proper sanitization DOMPurify.sanitize(dirtySVG, { NAMESPACE: 'http://www.w3.org/2000/svg' });Compatibility with Modern Frameworks
DOMPurify works seamlessly in both client-side and server-side React environments (viajsdom)[11][14]. It also supports custom hooks for granular control over allowed elements[1][8].Limitations and Mitigations
SVG/Namespace Bypass Risks
Misconfiguring the namespace (e.g., rendering SVG without proper settings) can bypass protections. Always specify the correctNAMESPACEoption[2].Not a Standalone Solution
Combine DOMPurify with:
- Content Security Policy (CSP) to block unauthorized script execution[1][10].
- Input Validation to reject unexpected formats (e.g., numeric-only fields)[14].
- Linting Rules to enforce sanitization for
dangerouslySetInnerHTML[3][11].Industry Validation
- OWASP Recommendation: DOMPurify is explicitly endorsed for HTML sanitization in the [OWASP XSS Prevention Cheat Sheet][12].
- Adoption by Major Platforms: WordPress VIP, Signal, and others use DOMPurify to secure user-generated content[8][11].
Example Attack Mitigation
Without DOMPurify:
// Vulnerable code <div dangerouslySetInnerHTML={{ __html: '<img src=x onerror=alert(1)>' }} />With DOMPurify:
// Safe output: <img src="x"> const clean = DOMPurify.sanitize('<img src=x onerror=alert(1)>'); return <div dangerouslySetInnerHTML={{ __html: clean }} />;The malicious
onerrorattribute is removed[8][14].For optimal security, keep DOMPurify updated and audit configurations regularly. While no tool is 100% foolproof, DOMPurify remains the gold standard for XSS prevention in React when paired with complementary security practices[1][10][12].
Citations:
- 1: https://blog.openreplay.com/securing-react-with-dompurify/
- 2: https://new-blog.ch4n3.kr/bypassing-dompurify-possibilities/
- 3: https://thomasnguyen.hashnode.dev/preventing-xss-in-react-applications
- 4: https://pragmaticwebsecurity.com/files/cheatsheets/reactxss.pdf
- 5: https://www.youtube.com/watch?v=yN0TgeFVbWg
- 6: https://dev.to/spukas/preventing-xss-in-react-applications-5f5j
- 7: https://www.stackhawk.com/blog/react-xss-guide-examples-and-prevention/
- 8: https://docs.wpvip.com/security/javascript-security-recommendations/
- 9: https://www.dhiwise.com/post/react-xss-advanced-strategies-for-mitigating-security-threats
- 10: https://www.esecurityplanet.com/endpoint/prevent-xss-attacks/
- 11: https://pragmaticwebsecurity.com/articles/spasecurity/react-xss-part2
- 12: https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html
- 13: https://github.com/cure53/DOMPurify
- 14: https://vercel.com/guides/understanding-xss-attacks
- 15: https://blog.objektkultur.de/preventing-dom-based-cross-site-scripting-xss-in-react/
- 16: https://www.measurethat.net/Benchmarks/Show/14241/0/dompurify-vs-sanitize-html-vs-js-xss
Please sanitize HTML content using DOMPurify to mitigate XSS risks.
After reviewing the security concerns and verifying via the web query, it's confirmed that DOMPurify is a highly effective solution for sanitizing HTML in React. Replace the unsanitized use of
dangerouslySetInnerHTMLinvite/src/routes/error/page.tsx(lines 97–100) by importing and utilizing DOMPurify to sanitizeerrorInfo.description. For example:- <div - className="text-gray-600 dark:text-zinc-400 mb-6 text-center" - dangerouslySetInnerHTML={{ __html: errorInfo.description }} - /> +import DOMPurify from 'dompurify'; + +// Sanitize the HTML content before rendering +const sanitizedDescription = DOMPurify.sanitize(errorInfo.description); + + <div + className="text-gray-600 dark:text-zinc-400 mb-6 text-center" + dangerouslySetInnerHTML={{ __html: sanitizedDescription }} + />Be sure to keep DOMPurify updated and review its configuration if any specialized content (like SVG) is rendered. This change significantly improves the protection against potential XSS attacks.
🧰 Tools
🪛 Biome (1.9.4)
[error] 99-99: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
electron/browser/main.ts (2)
147-147: Good addition of export to the Browser class.Making the Browser class exportable improves modularity and allows it to be used in other parts of the application.
488-549: Well-implemented protocol handler for custom file serving.The protocol handler for "flow-utility" is well-structured with:
- Proper path validation and sanitization
- Directory access restrictions
- Appropriate error handling
- Content type detection for served files
- Smart handling of directory requests with index.html resolution
electron/package.json (1)
16-18: Pinned Dependency Versions for Stability.
The updated dependency entries now explicitly require fixed versions, which is excellent for ensuring reproducible builds and minimizing surprises from upstream changes. Please verify these version updates are fully compatible with the rest of your Electron setup, particularly with the new protocol handler enhancements.
Summary by CodeRabbit
New Features
Chores