11import { NextResponse } from 'next/server'
22import { isDev } from '@/lib/environment'
33import { createLogger } from '@/lib/logs/console/logger'
4+ import { validateProxyUrl } from '@/lib/security/url-validation'
45import { executeTool } from '@/tools'
56import { getTool , validateRequiredParametersAfterMerge } from '@/tools/utils'
67
@@ -80,6 +81,15 @@ export async function GET(request: Request) {
8081 return createErrorResponse ( "Missing 'url' parameter" , 400 )
8182 }
8283
84+ const urlValidation = validateProxyUrl ( targetUrl )
85+ if ( ! urlValidation . isValid ) {
86+ logger . warn ( `[${ requestId } ] Blocked proxy request` , {
87+ url : targetUrl . substring ( 0 , 100 ) ,
88+ error : urlValidation . error ,
89+ } )
90+ return createErrorResponse ( urlValidation . error || 'Invalid URL' , 403 )
91+ }
92+
8393 const method = url . searchParams . get ( 'method' ) || 'GET'
8494
8595 const bodyParam = url . searchParams . get ( 'body' )
@@ -109,7 +119,6 @@ export async function GET(request: Request) {
109119 logger . info ( `[${ requestId } ] Proxying ${ method } request to: ${ targetUrl } ` )
110120
111121 try {
112- // Forward the request to the target URL with all specified headers
113122 const response = await fetch ( targetUrl , {
114123 method : method ,
115124 headers : {
@@ -119,7 +128,6 @@ export async function GET(request: Request) {
119128 body : body || undefined ,
120129 } )
121130
122- // Get response data
123131 const contentType = response . headers . get ( 'content-type' ) || ''
124132 let data
125133
@@ -129,7 +137,6 @@ export async function GET(request: Request) {
129137 data = await response . text ( )
130138 }
131139
132- // For error responses, include a more descriptive error message
133140 const errorMessage = ! response . ok
134141 ? data && typeof data === 'object' && data . error
135142 ? `${ data . error . message || JSON . stringify ( data . error ) } `
@@ -140,7 +147,6 @@ export async function GET(request: Request) {
140147 logger . error ( `[${ requestId } ] External API error: ${ response . status } ${ response . statusText } ` )
141148 }
142149
143- // Return the proxied response
144150 return formatResponse ( {
145151 success : response . ok ,
146152 status : response . status ,
@@ -166,7 +172,6 @@ export async function POST(request: Request) {
166172 const startTimeISO = startTime . toISOString ( )
167173
168174 try {
169- // Parse request body
170175 let requestBody
171176 try {
172177 requestBody = await request . json ( )
@@ -186,23 +191,20 @@ export async function POST(request: Request) {
186191
187192 logger . info ( `[${ requestId } ] Processing tool: ${ toolId } ` )
188193
189- // Get tool
190194 const tool = getTool ( toolId )
191195
192196 if ( ! tool ) {
193197 logger . error ( `[${ requestId } ] Tool not found: ${ toolId } ` )
194198 throw new Error ( `Tool not found: ${ toolId } ` )
195199 }
196200
197- // Validate the tool and its parameters
198201 try {
199202 validateRequiredParametersAfterMerge ( toolId , tool , params )
200203 } catch ( validationError ) {
201204 logger . warn ( `[${ requestId } ] Tool validation failed for ${ toolId } ` , {
202205 error : validationError instanceof Error ? validationError . message : String ( validationError ) ,
203206 } )
204207
205- // Add timing information even to error responses
206208 const endTime = new Date ( )
207209 const endTimeISO = endTime . toISOString ( )
208210 const duration = endTime . getTime ( ) - startTime . getTime ( )
@@ -214,14 +216,12 @@ export async function POST(request: Request) {
214216 } )
215217 }
216218
217- // Check if tool has file outputs - if so, don't skip post-processing
218219 const hasFileOutputs =
219220 tool . outputs &&
220221 Object . values ( tool . outputs ) . some (
221222 ( output ) => output . type === 'file' || output . type === 'file[]'
222223 )
223224
224- // Execute tool
225225 const result = await executeTool (
226226 toolId ,
227227 params ,
0 commit comments