-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathproxy.ts
More file actions
116 lines (102 loc) · 4.41 KB
/
proxy.ts
File metadata and controls
116 lines (102 loc) · 4.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import { NextRequest, NextResponse } from 'next/server'
import { checkBotId } from 'botid/server'
export async function proxy(request: NextRequest) {
const hostname = request.headers.get('host') || ''
const pathname = request.nextUrl.pathname
// Check if we're on the old domain
const isOldDomain =
hostname.includes('farcaster-mini-app-umber') ||
(hostname.includes('vercel.app') && !hostname.includes('miniapp.decleanup.net'))
// Redirect all old domain traffic (including manifest) to new domain
if (isOldDomain) {
const newUrl = new URL(pathname, 'https://miniapp.decleanup.net')
newUrl.search = request.nextUrl.search
return NextResponse.redirect(newUrl, 301) // Permanent redirect
}
// Bot Protection: Protect sensitive routes from bot traffic
// Skip bot protection for static files, images, and public assets
if (
!pathname.startsWith('/_next') &&
!pathname.startsWith('/api/og') &&
!pathname.startsWith('/og') &&
!pathname.startsWith('/.well-known') &&
!pathname.match(/\.(ico|png|jpg|jpeg|svg|gif|webp|woff|woff2|ttf|eot)$/)
) {
// Protect sensitive routes (verifier page excluded: UI-only; /api/cleanup/verify stays protected)
const protectedRoutes = [
'/api/cleanup/submit',
'/api/cleanup/verify',
'/api/points',
]
const isProtectedRoute = protectedRoutes.some(route =>
pathname.startsWith(route)
)
if (isProtectedRoute) {
try {
// Check user agent for legitimate browsers: mobile (Safari, Chrome), Farcaster/Base in-app WebViews
const userAgent = request.headers.get('user-agent') || ''
const isSafariIOS = /iPhone|iPad|iPod/i.test(userAgent) && /Safari/i.test(userAgent) && !/CriOS|FxiOS|OPiOS/i.test(userAgent)
const isChromeMobile = /Android.*Chrome|CriOS/i.test(userAgent)
const isFarcasterOrBase = /(?:Farcaster|Warpcast|Base)/i.test(userAgent)
const isLegitimateMobile = isSafariIOS || isChromeMobile || isFarcasterOrBase
// Allow legitimate mobile and in-app browsers without bot check (Bot ID often unavailable in WebViews)
if (isLegitimateMobile) {
console.log(`[Bot Protection] Allowing legitimate mobile browser: ${userAgent.substring(0, 50)}...`)
return NextResponse.next()
}
// Verify request using Vercel Bot ID
// This checks the x-vercel-bot-score header automatically
const result = await checkBotId({
developmentOptions: {
isDevelopment: process.env.NODE_ENV !== 'production',
},
})
// Only block if it's clearly a bot AND not human
// Be more lenient - allow if there's any uncertainty or if isHuman is true
if (result.isBot && !result.isHuman) {
// Bot detected - block the request
console.warn(`[Bot Protection] Blocked bot request to ${pathname}`)
return new NextResponse(
JSON.stringify({
error: 'Access denied: Bot activity detected',
message: 'Please ensure you are using a supported browser and try again.'
}),
{
status: 403,
headers: {
'Content-Type': 'application/json',
},
}
)
}
} catch (error) {
// If verification fails (e.g., in development), log and allow request
// In production, you may want to be more strict
console.error('[Bot Protection] Verification error:', error)
// In development, allow requests to proceed
if (process.env.NODE_ENV === 'development') {
console.warn('[Bot Protection] Allowing request in development mode')
} else {
// In production, be more cautious but still allow on error
// Better to allow legitimate users than block them
console.warn('[Bot Protection] Allowing request due to verification error')
}
}
}
}
return NextResponse.next()
}
export const config = {
matcher: [
/*
* Match all request paths except for the ones starting with:
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico (favicon file)
* - static file extensions
*
* Note: We include API routes here so Bot Protection can work on them
*/
'/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico|woff|woff2|ttf|eot)).*)',
],
}