fix(security): harden auth, tenant scoping, and scrub secrets
Require session on APIs, scope KPIs/activos/simulate to the user tenant, strip real JWTs from .env.example, and add health/smoke/docs for 4Ventures ops. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,9 +1,28 @@
|
||||
import { NextRequest } from 'next/server';
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { createClient } from '@/lib/supabase/server';
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL || 'https://supabase.4ventures.es';
|
||||
const serviceKey = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || '';
|
||||
const tenantId = process.env.DEFAULT_TENANT_ID || '0b3c5fc0-6901-4caf-b26a-b6a0201d8541';
|
||||
const serviceKey = process.env.SUPABASE_SERVICE_ROLE_KEY?.trim() || '';
|
||||
|
||||
const supabase = await createClient();
|
||||
const {
|
||||
data: { user },
|
||||
} = await supabase.auth.getUser();
|
||||
if (!user) {
|
||||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
||||
}
|
||||
|
||||
const tenantId =
|
||||
user.app_metadata?.tenant_id || user.user_metadata?.tenant_id || null;
|
||||
if (!tenantId) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Usuario sin tenant_id' },
|
||||
{ status: 403 }
|
||||
);
|
||||
}
|
||||
|
||||
const keyForRpc = serviceKey || process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || '';
|
||||
|
||||
try {
|
||||
const body = await req.json();
|
||||
@@ -13,25 +32,25 @@ export async function POST(req: NextRequest) {
|
||||
const res = await fetch(`${supabaseUrl}/rest/v1/rpc/simulate_budget`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
apikey: serviceKey,
|
||||
Authorization: `Bearer ${serviceKey}`,
|
||||
'Content-Type': 'application/json'
|
||||
apikey: keyForRpc,
|
||||
Authorization: `Bearer ${keyForRpc}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
p_tenant_id: tenantId,
|
||||
p_additional_spend: spend,
|
||||
p_target_channel: channel === 'blended' ? null : channel
|
||||
})
|
||||
p_target_channel: channel === 'blended' ? null : channel,
|
||||
}),
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
return Response.json(data);
|
||||
} else {
|
||||
const err = await res.text();
|
||||
return Response.json({ error: err }, { status: 500 });
|
||||
return NextResponse.json(data);
|
||||
}
|
||||
} catch (e: any) {
|
||||
return Response.json({ error: e.message }, { status: 500 });
|
||||
const err = await res.text();
|
||||
return NextResponse.json({ error: err }, { status: 500 });
|
||||
} catch (e: unknown) {
|
||||
const message = e instanceof Error ? e.message : 'Error';
|
||||
return NextResponse.json({ error: message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user