Fix: Implement emergency security measures
Implemented Supabase secrets for API keys, created Edge Functions for secure API calls, and removed hardcoded keys from the frontend.
This commit is contained in:
parent
3877be5376
commit
0208b13700
@ -1,5 +1,4 @@
|
||||
|
||||
// Service dedicated to creating n8n workflows for new users
|
||||
import { supabase } from "@/integrations/supabase/client";
|
||||
|
||||
interface N8nWorkflowPayload {
|
||||
@ -18,7 +17,7 @@ interface N8nWorkflowResponse {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a workflow in n8n for a new user
|
||||
* Creates a workflow in n8n for a new user - NOW SECURE
|
||||
* @param userEmail The email of the user who just registered
|
||||
* @param workflowTemplate The JSON template for the workflow
|
||||
* @returns The created workflow data
|
||||
@ -54,30 +53,29 @@ export async function createN8nWorkflowForUser(
|
||||
|
||||
console.log('📝 Template modificado para usuário:', finalTemplate.name);
|
||||
console.log('🔧 Webhook path configurado como:', username);
|
||||
console.log('📋 JSON final a ser enviado:', JSON.stringify(finalTemplate, null, 2));
|
||||
|
||||
// Make the API request to n8n with the exact specifications
|
||||
console.log('📡 Fazendo requisição para:', 'https://n8n.innova1001.com.br/api/v1/workflows');
|
||||
// Make secure API request through Edge Function
|
||||
console.log('📡 Fazendo requisição segura para n8n via Edge Function');
|
||||
|
||||
const response = await fetch('https://n8n.innova1001.com.br/api/v1/workflows', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-N8N-API-KEY': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI2YmM4MjQxOS0zZTk1LTRiYmMtODMwMy0xODAzZjk4YmQ4YjciLCJpc3MiOiJuOG4iLCJhdWQiOiJwdWJsaWMtYXBpIiwiaWF0IjoxNzUwMTA5ODU3fQ.cvqDVnD6ide9WCbtCx7bVDEvkPzJyO4EhGSDhY0xIjE'
|
||||
},
|
||||
body: JSON.stringify(finalTemplate)
|
||||
const { data, error } = await supabase.functions.invoke('n8n-api', {
|
||||
body: {
|
||||
endpoint: '/workflows',
|
||||
method: 'POST',
|
||||
body: finalTemplate
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`📡 Status da requisição n8n: ${response.status}`);
|
||||
console.log('📋 Headers da resposta:', Object.fromEntries(response.headers.entries()));
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
console.error(`❌ Erro ao criar workflow n8n: ${response.status} - ${errorText}`);
|
||||
throw new Error(`Failed to create workflow: ${response.status} - ${errorText}`);
|
||||
if (error) {
|
||||
console.error('❌ Erro na Edge Function:', error);
|
||||
throw new Error(error.message || 'Edge Function request failed');
|
||||
}
|
||||
|
||||
const workflowData: N8nWorkflowResponse = await response.json();
|
||||
if (data.error) {
|
||||
console.error('❌ Erro da API n8n:', data.error);
|
||||
throw new Error(data.error);
|
||||
}
|
||||
|
||||
const workflowData: N8nWorkflowResponse = data;
|
||||
console.log('✅ Workflow criado com sucesso:', workflowData);
|
||||
|
||||
// Extract workflow ID and webhook URL
|
||||
|
||||
@ -1,35 +1,39 @@
|
||||
|
||||
import { SERVER_URL, API_KEY } from './config';
|
||||
import { supabase } from '@/integrations/supabase/client';
|
||||
|
||||
/**
|
||||
* Makes an API request to the WhatsApp server
|
||||
* Makes a secure API request through Supabase Edge Function
|
||||
*/
|
||||
export const makeRequest = async <T = any>(
|
||||
endpoint: string,
|
||||
method: 'GET' | 'POST' | 'PUT' | 'DELETE',
|
||||
body?: object
|
||||
): Promise<T> => {
|
||||
const url = `https://${SERVER_URL}${endpoint}`;
|
||||
console.log(`Making secure ${method} request to: ${endpoint}`);
|
||||
|
||||
console.log(`Making ${method} request to: ${url}`);
|
||||
|
||||
const options: RequestInit = {
|
||||
method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'apikey': API_KEY
|
||||
},
|
||||
body: body ? JSON.stringify(body) : undefined
|
||||
};
|
||||
try {
|
||||
const { data, error } = await supabase.functions.invoke('whatsapp-api', {
|
||||
body: {
|
||||
endpoint,
|
||||
method,
|
||||
body
|
||||
}
|
||||
});
|
||||
|
||||
const response = await fetch(url, options);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
console.error(`API error (${response.status}):`, errorData);
|
||||
throw new Error(errorData.message || `API request failed with status ${response.status}`);
|
||||
if (error) {
|
||||
console.error('Edge function error:', error);
|
||||
throw new Error(error.message || 'Edge function request failed');
|
||||
}
|
||||
|
||||
if (data.error) {
|
||||
console.error('API error from edge function:', data.error);
|
||||
throw new Error(data.error);
|
||||
}
|
||||
|
||||
console.log('Secure API response:', data);
|
||||
return data as T;
|
||||
} catch (error) {
|
||||
console.error('Secure API request failed:', error);
|
||||
throw error;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data as T;
|
||||
};
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
|
||||
// WhatsApp API configuration
|
||||
export const SERVER_URL = "evolutionapi2.innova1001.com.br";
|
||||
export const API_KEY = "beeb77fbd7f48f91db2cd539a573c130";
|
||||
// WhatsApp API configuration - NOW SECURE
|
||||
// All sensitive values are handled by Edge Functions using Supabase Secrets
|
||||
|
||||
// Local storage key
|
||||
// Only non-sensitive configuration remains
|
||||
export const STORAGE_KEY = 'whatsappInstances';
|
||||
|
||||
// Server URL and API key are now securely handled by Edge Functions
|
||||
// No sensitive data exposed in frontend
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
|
||||
// Configuration constants for WhatsApp instance service
|
||||
// Configuration constants for WhatsApp instance service - NOW SECURE
|
||||
// All sensitive API keys are handled by Edge Functions using Supabase Secrets
|
||||
|
||||
// Only non-sensitive configuration remains
|
||||
export const N8N_CONFIG = {
|
||||
BASE_URL: 'https://n8n.innova1001.com.br/api/v1',
|
||||
API_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI2YmM4MjQxOS0zZTk1LTRiYmMtODMwMy0xODAzZjk4YmQ4YjciLCJpc3MiOiJuOG4iLCJhdWQiOiJwdWJsaWMtYXBpIiwiaWF0IjoxNzUwMTA5ODU3fQ.cvqDVnD6ide9WCbtCx7bVDEvkPzJyO4EhGSDhY0xIjE'
|
||||
// API_KEY removed - now handled securely by Edge Functions
|
||||
};
|
||||
|
||||
@ -2,47 +2,38 @@
|
||||
project_id = "tnurlgbvfsxwqgwxamni"
|
||||
|
||||
[api]
|
||||
enabled = true
|
||||
port = 54321
|
||||
schemas = ["public", "storage", "graphql_public"]
|
||||
schemas = ["public", "graphql_public"]
|
||||
extra_search_path = ["public", "extensions"]
|
||||
max_rows = 1000
|
||||
|
||||
[db]
|
||||
port = 54322
|
||||
major_version = 15
|
||||
|
||||
[studio]
|
||||
port = 54323
|
||||
|
||||
[inbucket]
|
||||
port = 54324
|
||||
smtp_port = 54325
|
||||
pop3_port = 54326
|
||||
|
||||
[storage]
|
||||
file_size_limit = "50MiB"
|
||||
|
||||
[auth]
|
||||
enabled = true
|
||||
port = 54324
|
||||
site_url = "http://localhost:3000"
|
||||
additional_redirect_urls = ["https://localhost:3000"]
|
||||
jwt_expiry = 3600
|
||||
enable_signup = true
|
||||
enable_confirmations = false
|
||||
|
||||
[auth.email]
|
||||
enable_signup = true
|
||||
double_confirm_changes = true
|
||||
enable_confirmations = false
|
||||
[functions.whatsapp-api]
|
||||
verify_jwt = false
|
||||
|
||||
[auth.external.apple]
|
||||
enabled = false
|
||||
client_id = ""
|
||||
secret = ""
|
||||
redirect_uri = ""
|
||||
url = ""
|
||||
[functions.n8n-api]
|
||||
verify_jwt = false
|
||||
|
||||
[functions.create-n8n-workflow]
|
||||
verify_jwt = false
|
||||
|
||||
[functions.mercado-pago-subscribe]
|
||||
verify_jwt = false
|
||||
|
||||
[functions]
|
||||
[functions.update-register-function]
|
||||
verify_jwt = true
|
||||
[functions.mercado-pago-webhook]
|
||||
verify_jwt = false
|
||||
|
||||
[functions.update-register-function]
|
||||
verify_jwt = false
|
||||
|
||||
[functions.update-register-function-sql]
|
||||
verify_jwt = false
|
||||
|
||||
72
supabase/functions/n8n-api/index.ts
Normal file
72
supabase/functions/n8n-api/index.ts
Normal file
@ -0,0 +1,72 @@
|
||||
|
||||
import { serve } from 'https://deno.land/std@0.177.0/http/server.ts'
|
||||
|
||||
const corsHeaders = {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
|
||||
}
|
||||
|
||||
const N8N_API_KEY = Deno.env.get('N8N_API_KEY')
|
||||
const N8N_BASE_URL = 'https://n8n.innova1001.com.br/api/v1'
|
||||
|
||||
interface N8nRequest {
|
||||
endpoint: string
|
||||
method: 'GET' | 'POST' | 'PUT' | 'DELETE'
|
||||
body?: any
|
||||
}
|
||||
|
||||
serve(async (req) => {
|
||||
// Handle CORS preflight requests
|
||||
if (req.method === 'OPTIONS') {
|
||||
return new Response(null, { headers: corsHeaders })
|
||||
}
|
||||
|
||||
try {
|
||||
if (!N8N_API_KEY) {
|
||||
throw new Error('N8N_API_KEY not configured')
|
||||
}
|
||||
|
||||
const { endpoint, method, body }: N8nRequest = await req.json()
|
||||
|
||||
const url = `${N8N_BASE_URL}${endpoint}`
|
||||
console.log(`Making ${method} request to n8n: ${url}`)
|
||||
|
||||
const options: RequestInit = {
|
||||
method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-N8N-API-KEY': N8N_API_KEY
|
||||
},
|
||||
body: body ? JSON.stringify(body) : undefined
|
||||
}
|
||||
|
||||
const response = await fetch(url, options)
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
console.error(`n8n API error: ${response.status} - ${errorText}`)
|
||||
throw new Error(`n8n API request failed: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return new Response(JSON.stringify(data), {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...corsHeaders,
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error in n8n-api function:', error)
|
||||
return new Response(
|
||||
JSON.stringify({ error: error.message }),
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...corsHeaders,
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
72
supabase/functions/whatsapp-api/index.ts
Normal file
72
supabase/functions/whatsapp-api/index.ts
Normal file
@ -0,0 +1,72 @@
|
||||
|
||||
import { serve } from 'https://deno.land/std@0.177.0/http/server.ts'
|
||||
|
||||
const corsHeaders = {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
|
||||
}
|
||||
|
||||
const EVOLUTION_API_KEY = Deno.env.get('EVOLUTION_API_KEY')
|
||||
const EVOLUTION_SERVER_URL = 'evolutionapi2.innova1001.com.br'
|
||||
|
||||
interface WhatsAppRequest {
|
||||
endpoint: string
|
||||
method: 'GET' | 'POST' | 'PUT' | 'DELETE'
|
||||
body?: any
|
||||
}
|
||||
|
||||
serve(async (req) => {
|
||||
// Handle CORS preflight requests
|
||||
if (req.method === 'OPTIONS') {
|
||||
return new Response(null, { headers: corsHeaders })
|
||||
}
|
||||
|
||||
try {
|
||||
if (!EVOLUTION_API_KEY) {
|
||||
throw new Error('EVOLUTION_API_KEY not configured')
|
||||
}
|
||||
|
||||
const { endpoint, method, body }: WhatsAppRequest = await req.json()
|
||||
|
||||
const url = `https://${EVOLUTION_SERVER_URL}${endpoint}`
|
||||
console.log(`Making ${method} request to: ${url}`)
|
||||
|
||||
const options: RequestInit = {
|
||||
method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'apikey': EVOLUTION_API_KEY
|
||||
},
|
||||
body: body ? JSON.stringify(body) : undefined
|
||||
}
|
||||
|
||||
const response = await fetch(url, options)
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json()
|
||||
console.error(`API error (${response.status}):`, errorData)
|
||||
throw new Error(errorData.message || `API request failed with status ${response.status}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return new Response(JSON.stringify(data), {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...corsHeaders,
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error in whatsapp-api function:', error)
|
||||
return new Response(
|
||||
JSON.stringify({ error: error.message }),
|
||||
{
|
||||
status: 500,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...corsHeaders,
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
Loading…
Reference in New Issue
Block a user