From 6e2eb6d6ac16e233ee2c5a58806951cfc0bdcf6b Mon Sep 17 00:00:00 2001 From: multipleof4 Date: Wed, 10 Sep 2025 13:19:45 -0700 Subject: [PATCH] refactor --- src/index.js | 82 ++++++++++++---------------------------------------- 1 file changed, 18 insertions(+), 64 deletions(-) diff --git a/src/index.js b/src/index.js index 5fd9221..bf8bacf 100644 --- a/src/index.js +++ b/src/index.js @@ -1,78 +1,32 @@ - -// Helper function for CORS headers -const corsHeaders = { - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Methods': 'POST, OPTIONS', - 'Access-Control-Allow-Headers': 'Content-Type', -}; - -// Handler for CORS preflight OPTIONS requests -function handleOptions(request) { - if ( - request.headers.get('Origin') !== null && - request.headers.get('Access-Control-Request-Method') !== null && - request.headers.get('Access-Control-Request-Headers') !== null - ) { - // Handle CORS pre-flight request. - return new Response(null, { - headers: { - ...corsHeaders, - 'Access-Control-Max-Age': '86400', - } - }); - } else { - // Handle standard OPTIONS request. - return new Response(null, { headers: { 'Allow': 'POST, OPTIONS' } }); - } -} +// Define shared headers for responses. +const headers = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': 'Content-Type' }; export default { - async fetch(request, env, ctx) { - if (request.method === 'OPTIONS') { - return handleOptions(request); - } + async fetch(request, env) { + // Handle CORS preflight requests. + if (request.method === 'OPTIONS') return new Response(null, { headers: { ...headers, 'Access-Control-Allow-Methods': 'POST', 'Access-Control-Max-Age': '86400' }}); - if (request.method !== 'POST') { - return new Response('Method Not Allowed. This proxy only accepts POST requests.', { status: 405, headers: corsHeaders }); - } - - if (request.headers.get('content-type') !== 'application/json') { - return new Response(JSON.stringify({ error: 'Request must be application/json' }), { status: 400, headers: corsHeaders }); - } + // Enforce POST and JSON content-type. + if (request.method !== 'POST') return new Response('Method Not Allowed', { status: 405, headers }); + if (!request.headers.get('content-type')?.includes('application/json')) return new Response(JSON.stringify({ error: 'Request must be application/json' }), { status: 400, headers }); try { const { query, params = [] } = await request.json(); - if (!query || typeof query !== 'string') { - return new Response(JSON.stringify({ error: 'Invalid request: "query" property must be a non-empty string.' }), { status: 400, headers: corsHeaders }); - } + // Basic query validation and security checks. + if (!query || typeof query !== 'string' || query.trim().includes(';')) return new Response(JSON.stringify({ error: 'Invalid or forbidden query provided.' }), { status: 400, headers }); + if (!['select', 'insert', 'explain'].some(verb => query.trim().toLowerCase().startsWith(verb))) return new Response(JSON.stringify({ error: 'Forbidden: Only SELECT, INSERT, and EXPLAIN are permitted.' }), { status: 403, headers }); - // --- CRITICAL: Sanitize and validate the query --- - const sanitizedQuery = query.trim().toLowerCase(); + // Execute the prepared statement against D1. + const result = await env.D1_SUNE.prepare(query).bind(...params).all(); - // 1. Disallow multiple statements - if (query.trim().includes(';')) { - return new Response(JSON.stringify({ error: 'Forbidden: Multiple SQL statements are not allowed.' }), { status: 403, headers: corsHeaders }); - } - - // 2. Only allow approved starting verbs - const allowedVerbs = ['select', 'insert', 'update', 'explain']; - const isAllowedVerb = allowedVerbs.some(verb => sanitizedQuery.startsWith(verb)); - - if (!isAllowedVerb) { - return new Response(JSON.stringify({ error: 'Forbidden: Operation not allowed. Only SELECT, INSERT, UPDATE, and EXPLAIN are permitted.' }), { status: 403, headers: corsHeaders }); - } - - // --- Execute the query --- - const stmt = env.DB.prepare(query).bind(...params); - const result = await stmt.all(); - - return new Response(JSON.stringify(result, null, 2), { headers: corsHeaders }); + // Return results with correct content-type. + return new Response(JSON.stringify(result, null, 2), { headers: { ...headers, 'Content-Type': 'application/json' } }); } catch (e) { - // Catch D1 errors and other exceptions - const errorMsg = e.cause ? e.cause.message : e.message; - return new Response(JSON.stringify({ error: 'Database Error', details: errorMsg }), { status: 500, headers: corsHeaders }); + // Catch and format any runtime errors. + const errorMsg = e.cause?.message ?? e.message; + return new Response(JSON.stringify({ error: 'Database Error', details: errorMsg }), { status: 500, headers }); } }, };