From 6cad72cbb419beb52e2ffc4ab8e1b28d2a2c66c4 Mon Sep 17 00:00:00 2001 From: Codex Date: Sat, 23 May 2026 09:43:29 -0300 Subject: [PATCH] fix: redact sensitive auth and bridge logs --- src/pages/auth/Auth.tsx | 34 +++++++---------- supabase/functions/crm-db-bridge/index.ts | 28 +++++++------- .../functions/external-db-bridge/index.ts | 38 ++++++++++++------- 3 files changed, 53 insertions(+), 47 deletions(-) diff --git a/src/pages/auth/Auth.tsx b/src/pages/auth/Auth.tsx index 417d39336..113bde147 100644 --- a/src/pages/auth/Auth.tsx +++ b/src/pages/auth/Auth.tsx @@ -1,7 +1,6 @@ import React, { useState, useEffect, useRef, useCallback } from 'react'; import { PageSEO } from '@/components/seo/PageSEO'; import { useNavigate, useSearchParams, useLocation } from 'react-router-dom'; -import { consumePostLoginRedirect } from '@/lib/auth/post-login-redirect'; import { resolveRedirectTarget } from '@/lib/auth/resolve-redirect-target'; import { resolveOAuthError, type OAuthErrorCopy } from '@/lib/auth/oauth-error-messages'; @@ -11,7 +10,6 @@ import { Eye, EyeOff, Loader2, - Gift, Mail, Lock, ShieldAlert, @@ -27,7 +25,7 @@ import { Rocket, } from 'lucide-react'; import { motion, AnimatePresence } from 'framer-motion'; -import { AuthBrandingPanel, Starfield, SpaceScene } from "@/pages/auth/AuthBranding"; +import { AuthBrandingPanel, SpaceScene } from "@/pages/auth/AuthBranding"; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; @@ -184,7 +182,7 @@ export default function Auth() { } else { setDbStatus(prev => ({ ...prev, external: { ok: false, loading: false } })); } - } catch (err) { + } catch { setDbStatus(prev => ({ ...prev, external: { ok: false, loading: false } })); } }; @@ -240,8 +238,8 @@ export default function Auth() { navigate(resolveRedirectTargetCb(), { replace: true }); }, 600); return true; - } catch (error) { - console.error('Validation error:', error); + } catch { + console.warn('Validation failed during post-login access checks; continuing with fail-open redirect'); navigate(resolveRedirectTargetCb(), { replace: true }); // Fail-open return true; } @@ -252,11 +250,10 @@ export default function Auth() { setIpBlocked(false); try { - console.log(`[AUTH_START] Tentativa de login para: ${data.email}`); - const { error, data: signInData } = await signIn(data.email, data.password); + const { error } = await signIn(data.email, data.password); if (error) { - console.error(`[AUTH_FAILED] Erro de autenticação para ${data.email}:`, error); + console.warn('[AUTH_FAILED] Authentication failed', { status: error.status ?? 'unknown' }); await logLoginAttempt(data.email, null, false, error.message); let description = error.message; @@ -307,8 +304,6 @@ export default function Auth() { return; } - console.log(`[AUTH_OK] Login bem-sucedido para ${data.email}. Validando sessão...`); - // Credential Management API — pede ao navegador para salvar email/senha // após login bem-sucedido (Chrome/Edge/Brave). Silencioso se não suportado. try { @@ -319,8 +314,8 @@ export default function Auth() { const cred = new CredCtor({ id: data.email, password: data.password, name: data.email }); await navigator.credentials.store(cred); } - } catch (credErr) { - console.warn('[AUTH_CRED_STORE] Não foi possível salvar credenciais:', credErr); + } catch { + console.warn('[AUTH_CRED_STORE] Credential store failed'); } @@ -340,7 +335,6 @@ export default function Auth() { } // 1. Verificação detalhada de Perfil (is_active) - console.log(`[AUTH_SESSION] Sessão iniciada para ${userId}. Carregando perfil...`); const { data: profileData, error: profileError } = await supabase .from('profiles') .select('is_active, role') @@ -348,7 +342,9 @@ export default function Auth() { .single(); if (profileError) { - console.error(`[AUTH_PROFILE_FAILED] Erro ao buscar perfil para ${userId}:`, profileError); + console.error('[AUTH_PROFILE_FAILED] Failed to load authenticated profile', { + code: profileError.code ?? 'unknown', + }); const isRLSError = profileError.code === 'PGRST301' || profileError.code === '42501'; toast({ variant: 'destructive', @@ -382,17 +378,15 @@ export default function Auth() { .eq('user_id', userId); if (rolesError || !rolesData || rolesData.length === 0) { - console.warn(`[AUTH_RBAC_WARN] Usuário ${userId} sem papéis (roles) atribuídos.`); - } else { - console.log(`[AUTH_RBAC_OK] Usuário ${userId} possui ${rolesData.length} roles.`); + console.warn('[AUTH_RBAC_WARN] Authenticated user has no assigned roles'); } // 3. Validação final de IP e Redirecionamento await validateAndRedirect(userId, data.email); - } catch (err) { - console.error('Login exception:', err); + } catch { + console.error('Login exception'); toast({ variant: 'destructive', title: 'Erro inesperado', diff --git a/supabase/functions/crm-db-bridge/index.ts b/supabase/functions/crm-db-bridge/index.ts index 4467b4a6f..a41c9238e 100644 --- a/supabase/functions/crm-db-bridge/index.ts +++ b/supabase/functions/crm-db-bridge/index.ts @@ -384,7 +384,6 @@ export function logInsertResultIfAnomalous( shape: diagnostic.shape, rowCount: diagnostic.rowCount, errorMessage: diagnostic.errorMessage, - preview: diagnostic.preview, }; const icon = diagnostic.shape === "generic-string-error" ? "🚨" : "⚠️"; @@ -464,7 +463,7 @@ async function authenticateRequest(req: Request): Promise { .from("user_roles").select("role").eq("user_id", user.id).single(); const userRole = roleData?.role || "vendedor"; - console.log(`Request from user: ${user.id}, role: ${userRole}`); + console.log(`Authenticated CRM request role=${userRole}`); return { userId: user.id, userRole }; } @@ -667,7 +666,7 @@ async function handleInsert(crm: SupabaseClient, body: CrmQuery): Promise { evt: "crm-creds-resolved", url_source: urlRes.source, url_via_alias: urlRes.resolved_name !== "EXTERNAL_CRM_URL", - url_prefix: CRM_URL.substring(0, 30), using, key_source: keySource, - key_len: CRM_KEY.length, - anon_len: CRM_ANON.length, keys_match: CRM_SERVICE_KEY === CRM_ANON, - svc_last4: CRM_KEY.slice(-4), - anon_last4: CRM_ANON.slice(-4), })); } @@ -996,4 +996,4 @@ Deno.serve((req) => { return jsonResponse({ error: error instanceof Error ? error.message : "Internal error" }, 500); } }); -}); \ No newline at end of file +}); diff --git a/supabase/functions/external-db-bridge/index.ts b/supabase/functions/external-db-bridge/index.ts index 28e62a10f..867124f33 100644 --- a/supabase/functions/external-db-bridge/index.ts +++ b/supabase/functions/external-db-bridge/index.ts @@ -156,6 +156,12 @@ function safeStringify(v: unknown): string { try { return JSON.stringify(v); } catch { return String(v); } } +function summarizeFilterViolations( + violations: Array<{ field: string; reason: string; receivedType: string }>, +) { + return violations.map(({ field, reason, receivedType }) => ({ field, reason, receivedType })); +} + export function applyFilters( query: any, filters: Record, @@ -590,7 +596,10 @@ async function handleBatch(body: any, req: Request, corsHeaders: Record 0) { - console.warn(`[batch] Query ${idx} (${qTable}) rejected — invalid filters:`, batchFilterViolations); + console.warn( + `[batch] Query ${idx} (${qTable}) rejected — invalid filters:`, + summarizeFilterViolations(batchFilterViolations), + ); return { success: false, error: 'Invalid filter values', @@ -722,7 +731,7 @@ async function handleRpc(body: any, corsHeaders: Record) { const externalSupabase = await getExternalClient(corsHeaders); if (externalSupabase instanceof Response) return externalSupabase; - console.log(`RPC: ${rpcName}`, rpcParams); + console.log(`RPC: ${rpcName} params_keys=${Object.keys(rpcParams || {}).length}`); const rpcStart = performance.now(); const { data: rpcDataRaw, error: rpcError } = await externalSupabase.rpc(rpcName, rpcParams || {}); const rpcDuration = Math.round(performance.now() - rpcStart); @@ -990,7 +999,10 @@ async function handleSelect(externalSupabase: any, table: string, opts: any) { // Reject malformed filters (objects, NaN, functions) BEFORE building the query. const filterViolations = validateFilters(filters as Record | undefined); if (filterViolations.length > 0) { - console.warn(`[external-db-bridge] Rejecting select on "${table}" — ${filterViolations.length} invalid filter(s):`, filterViolations); + console.warn( + `[external-db-bridge] Rejecting select on "${table}" — ${filterViolations.length} invalid filter(s):`, + summarizeFilterViolations(filterViolations), + ); return jsonResponse({ error: 'Invalid filter values', details: filterViolations, @@ -1232,7 +1244,7 @@ async function handleSelect(externalSupabase: any, table: string, opts: any) { console.warn( `[external-db-bridge] orderBy fallback: column "${orderColumn}" failed on table "${table}" ` + `(code=${errCode || 'n/a'}, msg="${errMsg}"). Retrying without orderBy. ` + - `Caller origin: select="${effectiveSelect.slice(0, 80)}..." filters=${JSON.stringify(filters ?? {}).slice(0, 200)}` + `Caller origin: select_fields=${effectiveSelect.split(',').length} filters_keys=${Object.keys(filters ?? {}).length}` ); const retryStart = performance.now(); @@ -1333,7 +1345,7 @@ async function handleInsert(externalSupabase: any, table: string, opts: any) { const virtualRecord = buildVirtualRecords(productId, updatedAreas) .find((r) => r.area_id === areaId && r.technique_id === techniqueId); const result = virtualRecord || { id: `${productId}::${areaId}::${techniqueId}`, product_id: productId, area_id: areaId, technique_id: techniqueId }; - console.log(`${alreadyLinked ? 'Already linked' : 'Inserted virtual record'} in ${table}:`, (result as any).id); + console.log(`${alreadyLinked ? 'Already linked' : 'Inserted virtual record'} in ${table}`); return result; } @@ -1346,7 +1358,7 @@ async function handleInsert(externalSupabase: any, table: string, opts: any) { }); if (canInjectCreatedAt && !insertData.created_at) insertData.created_at = new Date().toISOString(); - console.log(`Inserting into ${table}:`, JSON.stringify(insertData).substring(0, 500)); + console.log(`Inserting into ${table}: field_count=${Object.keys(insertData).length}`); const { data: insertResult, error: insertError } = await externalSupabase.from(table).insert(insertData).select().single(); if (insertError) { @@ -1354,7 +1366,7 @@ async function handleInsert(externalSupabase: any, table: string, opts: any) { return jsonResponse({ error: insertError.message, details: insertError.details, hint: insertError.hint }, 400, corsHeaders); } - console.log(`Inserted record in ${table}:`, insertResult?.id); + console.log(`Inserted record in ${table}`); return insertResult; } @@ -1377,7 +1389,7 @@ async function handleUpdate(externalSupabase: any, table: string, opts: any) { ...(canInjectUpdatedAt ? { updated_at: new Date().toISOString() } : {}), }); - console.log(`Updating ${table} id=${id}:`, JSON.stringify(updateData).substring(0, 500)); + console.log(`Updating ${table}: field_count=${Object.keys(updateData).length}`); const { data: updateResult, error: updateError } = await externalSupabase.from(table).update(updateData).eq('id', id).select().maybeSingle(); if (updateError) { @@ -1386,7 +1398,7 @@ async function handleUpdate(externalSupabase: any, table: string, opts: any) { } if (!updateResult) return jsonResponse({ error: `Registro não encontrado em '${table}' com id='${id}'` }, 404, corsHeaders); - console.log(`Updated record in ${table}:`, id); + console.log(`Updated record in ${table}`); return updateResult; } @@ -1419,7 +1431,7 @@ async function handleDelete(externalSupabase: any, table: string, opts: any) { if (updateError) return jsonResponse({ error: updateError.message, details: updateError.details }, 400, corsHeaders); if (!updatedProduct) return jsonResponse({ error: `Produto '${parsedId.productId}' não encontrado para atualização` }, 404, corsHeaders); - console.log(`Deleted virtual record from ${table}:`, id); + console.log(`Deleted virtual record from ${table}`); return { success: true, deleted_id: id }; } @@ -1432,7 +1444,7 @@ async function handleDelete(externalSupabase: any, table: string, opts: any) { } if (!deleteResult) return jsonResponse({ error: `Registro não encontrado em '${table}' com id='${id}'` }, 404, corsHeaders); - console.log(`Deleted record from ${table}:`, id); + console.log(`Deleted record from ${table}`); return { success: true, deleted_id: id }; } @@ -1455,7 +1467,7 @@ async function handleUpsert(externalSupabase: any, table: string, opts: any) { // Default merge on 'sku' for products, 'id' for others const onConflict = table === 'products' ? 'sku' : 'id'; - console.log(`Upserting into ${table} (onConflict=${onConflict}):`, JSON.stringify(upsertData).substring(0, 500)); + console.log(`Upserting into ${table} (onConflict=${onConflict}): field_count=${Object.keys(upsertData).length}`); const { data: result, error } = await externalSupabase .from(table) .upsert(upsertData, { onConflict }) @@ -1467,7 +1479,7 @@ async function handleUpsert(externalSupabase: any, table: string, opts: any) { return jsonResponse({ error: error.message, details: error.details, hint: error.hint }, 400, corsHeaders); } - console.log(`Upserted record in ${table}:`, result?.id); + console.log(`Upserted record in ${table}`); return result; }