Files
time_to_leave/apps/web/src/app/api/geocode/route.ts
T
fegger 35971596b3 Add API security guards, rate limiter, and manual test checklist
Implement strict CORS enforcement and per-IP rate limiting in the Next.js middleware. Add input validation helpers for
coordinates and request body size limits. Introduce SSRF protection for calendar URL fetching. Update mobile settings to
support new transport options and arrival buffers. Include a comprehensive manual testing checklist for integration
verification.
2026-05-12 14:42:11 +02:00

57 lines
1.8 KiB
TypeScript

import { randomUUID } from "crypto";
import { NextRequest, NextResponse } from "next/server";
import { GeocodingClient } from "@/lib/geocoding-client";
// Module-level singleton — cache persists across requests
const client = new GeocodingClient();
/**
* Maximum allowed query length. Station/place names are typically
* < 100 characters. This prevents abuse with extremely long inputs.
*/
const MAX_QUERY_LENGTH = 256;
/**
* Allowed country codes for narrowing the search.
* Two-letter ISO 3166-1 alpha-2 codes.
*/
const ALLOWED_COUNTRY_CODES = /^[a-z]{2}(,[a-z]{2}){0,4}$/;
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const name = searchParams.get("name");
const countrycodes = searchParams.get("countrycodes");
if (!name) {
return NextResponse.json({ error: "Missing 'name' parameter" }, { status: 400 });
}
if (name.length > MAX_QUERY_LENGTH) {
return NextResponse.json(
{ error: "Query too long (max 256 characters)" },
{ status: 400 },
);
}
if (countrycodes && !ALLOWED_COUNTRY_CODES.test(countrycodes.toLowerCase())) {
return NextResponse.json(
{ error: "Invalid countrycodes (use up to 5 two-letter codes, comma-separated)" },
{ status: 400 },
);
}
const results = await client.geocode(name, countrycodes || undefined);
if (results.length === 0) {
return NextResponse.json({ error: "No results found" }, { status: 404 });
}
return NextResponse.json(results[0]);
} catch (error) {
const corrId = randomUUID().slice(0, 8);
console.error(`[${corrId}] Geocode API error:`, error);
return NextResponse.json({ error: "Internal server error", correlationId: corrId }, { status: 500 });
}
}