import { NextRequest, NextResponse } from 'next/server'; export async function POST(request: NextRequest) { return handleProxy(request); } export async function GET(request: NextRequest) { return handleProxy(request); } export async function PUT(request: NextRequest) { return handleProxy(request); } export async function DELETE(request: NextRequest) { return handleProxy(request); } export async function PATCH(request: NextRequest) { return handleProxy(request); } const ALLOWED_HOST = 'backend.composio.dev'; async function handleProxy(request: NextRequest) { try { const url = new URL(request.url); const targetUrl = url.searchParams.get('url'); if (!targetUrl) { return NextResponse.json({ error: 'Missing url parameter' }, { status: 400 }); } // Validate the target URL to prevent SSRF let parsedTarget: URL; try { parsedTarget = new URL(targetUrl); } catch { return NextResponse.json({ error: 'Invalid URL' }, { status: 400 }); } if (parsedTarget.hostname !== ALLOWED_HOST) { return NextResponse.json({ error: 'URL not allowed' }, { status: 403 }); } if (parsedTarget.protocol !== 'https:') { return NextResponse.json({ error: 'Only HTTPS allowed' }, { status: 403 }); } // Get request body for non-GET requests let body: string | undefined; if (request.method !== 'GET' && request.method !== 'HEAD') { body = await request.text(); } // Forward headers (excluding host and other problematic headers) const headers = new Headers(); request.headers.forEach((value, key) => { const lowerKey = key.toLowerCase(); if (!['host', 'connection', 'content-length'].includes(lowerKey)) { headers.set(key, value); } }); const response = await fetch(targetUrl, { method: request.method, headers, body, }); const responseBody = await response.text(); return new NextResponse(responseBody, { status: response.status, headers: { 'Content-Type': response.headers.get('Content-Type') || 'application/json', 'Access-Control-Allow-Origin': '*', }, }); } catch (error) { console.error('Proxy error:', error); return NextResponse.json( { error: 'Proxy request failed' }, { status: 500 } ); } } export async function OPTIONS() { return new NextResponse(null, { status: 200, headers: { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, Authorization, x-api-key', }, }); }