Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 44 additions & 4 deletions middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,33 @@ import arcjet, { detectBot, shield, tokenBucket } from "@arcjet/next";

const publicPaths = ["/sign-in", "/sign-up"];

// Arcjet
// Arcjet - Updated to allow OpenGraph crawlers
const aj = arcjet({
key: process.env.ARCJET_KEY!,
characteristics: ["ip.src"],
rules: [
shield({ mode: "LIVE" }),
detectBot({
mode: "LIVE",
allow: ["CATEGORY:SEARCH_ENGINE"],
allow: [
// Search engines
"CATEGORY:SEARCH_ENGINE",

// OpenGraph/Social Media Crawlers
"FACEBOOK_CRAWLER",
"FACEBOOK_CRAWLER",
"TWITTER_CRAWLER",
"LINKEDIN_CRAWLER",
"DISCORD_CRAWLER",
"SLACK_CRAWLER",
"TELEGRAM_CRAWLER",
"WHATSAPP_CRAWLER",
"PINTREST_CRAWLER",
"REDDIT_CRAWLER",

// Meta (Facebook) specific crawlers
"FACEBOOK_CRAWLER",
],
}),
tokenBucket({
mode: "LIVE",
Expand All @@ -28,6 +46,26 @@ const aj = arcjet({
});

export async function middleware(request: NextRequest) {
// Skip Arcjet for static assets and OpenGraph images
const pathname = request.nextUrl.pathname;

// Don't apply Arcjet to these paths
if (
pathname.startsWith("/_next") ||
pathname.startsWith("/favicon") ||
pathname.startsWith("/og-image") ||
pathname.startsWith("/twitter-image") ||
pathname.startsWith("/apple-touch-icon") ||
pathname.endsWith(".png") ||
pathname.endsWith(".jpg") ||
pathname.endsWith(".jpeg") ||
pathname.endsWith(".svg") ||
pathname.endsWith(".ico") ||
pathname.endsWith(".webp")
) {
return NextResponse.next();
}

// 1. Arcjet
const decision = await aj.protect(request, { requested: 1 });

Expand Down Expand Up @@ -69,7 +107,9 @@ export async function middleware(request: NextRequest) {
return NextResponse.next();
}

// exceptions for api routes and static files
// Updated matcher to exclude image files
export const config = {
matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
matcher: [
"/((?!api|_next/static|_next/image|favicon.ico|.*\\.png|.*\\.jpg|.*\\.jpeg|.*\\.svg|.*\\.ico|.*\\.webp).*)",
],
};
17 changes: 9 additions & 8 deletions next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ const getCspHeader = () => {
"'unsafe-inline'",
],

// Image sources
// Image sources - Allow any HTTPS source to prevent blocking OG crawlers
"img-src": [
"'self'",
"data:", // Base64 encoded images
"https:", // Allow all HTTPS images for OG crawlers
"https://via.placeholder.com", // Placeholder images
],

Expand All @@ -50,7 +51,7 @@ const getCspHeader = () => {
// Web workers
"worker-src": ["'self'", "blob:"],

// Embedding in frames
// Embedding in frames - Allow same origin for better compatibility
"frame-src": ["'self'"],

// Block all objects/embeds
Expand All @@ -59,8 +60,8 @@ const getCspHeader = () => {
// Form submission
"form-action": ["'self'"],

// Block iframe embedding of our site
"frame-ancestors": ["'none'"],
// Don't block iframe embedding by crawlers - remove this restriction
// "frame-ancestors": ["'none'"], // Commented out to allow OG crawlers

// Force HTTPS (only in production)
...(process.env.NODE_ENV === "production" ? { "upgrade-insecure-requests": [] } : {}),
Expand Down Expand Up @@ -96,8 +97,8 @@ const nextConfig = {
images: {
formats: ["image/webp"],
contentDispositionType: "attachment",
// CSP for Next.js image optimization (separate from main CSP)
contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
// Relaxed CSP for Next.js image optimization
contentSecurityPolicy: "default-src 'self'; script-src 'self' 'unsafe-inline'; img-src 'self' data: https:;",
},

// URL redirects
Expand Down Expand Up @@ -128,9 +129,9 @@ const nextConfig = {
value: "nosniff",
},
{
// Block iframe embedding
// Allow iframe embedding for OG crawlers - use SAMEORIGIN instead of DENY
key: "X-Frame-Options",
value: "DENY",
value: "SAMEORIGIN",
},
{
// Enable XSS protection (legacy)
Expand Down