From f079fb2e00e952ad37cb4ba9dcb0144e5857e4fc Mon Sep 17 00:00:00 2001
From: TerribleDev <1020010-TerribleDev@users.noreply.replit.com>
Date: Sat, 15 Feb 2025 18:25:02 +0000
Subject: [PATCH] Agent query: Could you check if the newsletter tiles are
loading properly now, without any AWS WAF integration code?
Improve image handling and add security headers. Addresses image loading errors and enhances security by implementing Content-Security-Policy, X-Content-Type-Options, and X-XSS-Protection headers.
Screenshot: https://storage.googleapis.com/screenshot-production-us-central1/9dda30b6-4149-4bce-89dc-76333005952c/8166d521-ab6d-49dc-bd03-63e0c10a9767.jpg
---
client/src/pages/home.tsx | 150 ++++++++++++++++++++++----------------
server/index.ts | 18 +++--
2 files changed, 98 insertions(+), 70 deletions(-)
diff --git a/client/src/pages/home.tsx b/client/src/pages/home.tsx
index fe74f79..41f8d63 100644
--- a/client/src/pages/home.tsx
+++ b/client/src/pages/home.tsx
@@ -11,11 +11,10 @@ import {
Calendar,
RefreshCw,
Share2,
- Twitter,
- Facebook,
- Rss,
Bell,
- BellOff
+ BellOff,
+ Rss,
+ ImageOff
} from "lucide-react";
import { useNewsletters, useNewsletterSearch } from "@/lib/newsletter-data";
import { useToast } from "@/hooks/use-toast";
@@ -25,6 +24,34 @@ import { motion, AnimatePresence } from "framer-motion";
const ITEMS_PER_PAGE = 20;
+function NewsletterImage({ src, alt, onError }: { src: string | null, alt: string, onError: () => void }) {
+ const [error, setError] = useState(false);
+
+ const handleError = () => {
+ setError(true);
+ onError();
+ };
+
+ if (!src || error) {
+ return (
+
+
+
+ );
+ }
+
+ return (
+
+ );
+}
+
export default function Home() {
const [searchQuery, setSearchQuery] = useState("");
const [isImporting, setIsImporting] = useState(false);
@@ -236,66 +263,61 @@ export default function Home() {
exit={{ opacity: 0, y: -20 }}
layout
>
-
-
-
-
- {newsletter.title}
-
-
-
-
-
-
-
- {format(new Date(newsletter.date), 'MMMM d, yyyy')}
-
-
- {(newsletter.thumbnail || newsletter.description) && (
-
- {newsletter.thumbnail && (
-
- )}
- {newsletter.description && (
-
- {newsletter.description}
-
- )}
-
- )}
-
-
+
+
+
+ {newsletter.title}
+
+
+
+
+
+
+
+ {format(new Date(newsletter.date), 'MMMM d, yyyy')}
+
+
+ {(newsletter.thumbnail || newsletter.description) && (
+
+ {newsletter.thumbnail && (
+ {
+ console.warn(`Failed to load image for newsletter: ${newsletter.id}`);
+ }}
+ />
+ )}
+ {newsletter.description && (
+
+ {newsletter.description}
+
+ )}
+
+ )}
+
))
) : (
diff --git a/server/index.ts b/server/index.ts
index 5a97cc7..71f11f1 100644
--- a/server/index.ts
+++ b/server/index.ts
@@ -6,6 +6,17 @@ const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
+// Add security headers to prevent script injection
+app.use((req, res, next) => {
+ // Prevent content injection
+ res.setHeader('Content-Security-Policy', "default-src 'self'; img-src 'self' https: data:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';");
+ // Prevent browsers from MIME-sniffing
+ res.setHeader('X-Content-Type-Options', 'nosniff');
+ // XSS protection
+ res.setHeader('X-XSS-Protection', '1; mode=block');
+ next();
+});
+
app.use((req, res, next) => {
const start = Date.now();
const path = req.path;
@@ -47,19 +58,14 @@ app.use((req, res, next) => {
throw err;
});
- // importantly only setup vite in development and after
- // setting up all the other routes so the catch-all route
- // doesn't interfere with the other routes
if (app.get("env") === "development") {
await setupVite(app, server);
} else {
serveStatic(app);
}
- // ALWAYS serve the app on port 5000
- // this serves both the API and the client
const PORT = 5000;
server.listen(PORT, "0.0.0.0", () => {
log(`serving on port ${PORT}`);
});
-})();
+})();
\ No newline at end of file