fix: enhance security by enclosing html in code blocks and csp (#2604)

This commit is contained in:
Zane
2025-05-21 08:01:11 -07:00
committed by GitHub
parent e317153380
commit f4ae801d97
4 changed files with 71 additions and 170 deletions
+32 -3
View File
@@ -1,7 +1,6 @@
import React, { useState } from 'react';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import rehypeRaw from 'rehype-raw';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism';
import { Check, Copy } from './icons';
@@ -77,12 +76,42 @@ const MarkdownCode = React.forwardRef(function MarkdownCode(
);
});
// Detect if content contains HTML
const containsHTML = (str: string) => {
const htmlRegex = /<[^>]*>/;
return htmlRegex.test(str);
};
// Wrap HTML content in code blocks
const wrapHTMLInCodeBlock = (content: string) => {
if (containsHTML(content)) {
// Split content by code blocks to preserve existing ones
const parts = content.split(/(```[\s\S]*?```)/g);
return parts
.map((part) => {
// If part is already a code block, leave it as is
if (part.startsWith('```') && part.endsWith('```')) {
return part;
}
// If part contains HTML, wrap it in HTML code block
if (containsHTML(part)) {
return `\`\`\`html\n${part}\n\`\`\``;
}
return part;
})
.join('\n');
}
return content;
};
export default function MarkdownContent({ content, className = '' }: MarkdownContentProps) {
// Process content before rendering
const processedContent = wrapHTMLInCodeBlock(content);
return (
<div className="w-full overflow-x-hidden">
<ReactMarkdown
remarkPlugins={[remarkGfm]}
rehypePlugins={[rehypeRaw]}
className={`prose prose-sm text-textStandard dark:prose-invert w-full max-w-full word-break
prose-pre:p-0 prose-pre:m-0 !p-0
prose-code:break-all prose-code:whitespace-pre-wrap
@@ -105,7 +134,7 @@ export default function MarkdownContent({ content, className = '' }: MarkdownCon
code: MarkdownCode,
}}
>
{content}
{processedContent}
</ReactMarkdown>
</div>
);
+38
View File
@@ -762,6 +762,44 @@ const registerGlobalHotkey = (accelerator: string) => {
};
app.whenReady().then(async () => {
// Add CSP headers to all sessions
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
callback({
responseHeaders: {
...details.responseHeaders,
'Content-Security-Policy': [
"default-src 'self';" +
// Allow inline styles since we use them in our React components
"style-src 'self' 'unsafe-inline';" +
// Scripts only from our app
"script-src 'self';" +
// Images from our app and data: URLs (for base64 images)
"img-src 'self' data: https:;" +
// Connect to our local API and specific external services
"connect-src 'self' http://127.0.0.1:*" +
// Don't allow any plugins
"object-src 'none';" +
// Don't allow any frames
"frame-src 'none';" +
// Font sources
"font-src 'self';" +
// Media sources
"media-src 'none';" +
// Form actions
"form-action 'none';" +
// Base URI restriction
"base-uri 'self';" +
// Manifest files
"manifest-src 'self';" +
// Worker sources
"worker-src 'self';" +
// Upgrade insecure requests
'upgrade-insecure-requests;',
],
},
});
});
// Register the default global hotkey
registerGlobalHotkey('CommandOrControl+Alt+Shift+G');