// ============================================================================ // DNS/SSL API - Consultas via APIs publicas // ============================================================================ // Usa APIs gratuitas para consultar registros DNS, SSL, MX, SPF, DKIM, DMARC // ============================================================================ import type { ResultadoFerramenta } from './FerramentaLayout'; // Helper para chamar a API do Google DNS async function queryDNS(name: string, type: string): Promise { try { const res = await fetch(`https://dns.google/resolve?name=${encodeURIComponent(name)}&type=${type}`); return await res.json(); } catch { return { Status: 2, Answer: [] }; } } // Verificar SPF export async function checkSPF(dominio: string): Promise { const data = await queryDNS(dominio, 'TXT'); const records = (data.Answer || []).filter((r: any) => r.data && r.data.includes('v=spf1')); if (records.length === 0) { return { status: 'error', titulo: 'SPF Nao Encontrado', mensagem: `O dominio ${dominio} nao possui um registro SPF configurado. Sem SPF, qualquer pessoa pode enviar e-mails em nome do seu dominio, o que facilita ataques de phishing e spoofing.`, detalhes: { Dominio: dominio, Registro: 'Nao encontrado' }, recomendacoes: [ 'Crie um registro TXT no DNS com a politica SPF', 'Exemplo: v=spf1 include:_spf.google.com ~all (para Microsoft 365/Google Workspace)', 'Use o mecanismo ~all (softfail) inicialmente para testes', 'Monitore os logs antes de usar -all (hardfail)', 'Consulte a Avanzato para configuracao personalizada', ], score: 0, }; } const spf = records[0].data.replace(/"/g, ''); const hasAll = spf.includes('-all') || spf.includes('~all') || spf.includes('?all'); const isHardFail = spf.includes('-all'); const includes = spf.match(/include:[^\s]+/g) || []; const ip4 = spf.match(/ip4:[^\s]+/g) || []; const ip6 = spf.match(/ip6:[^\s]+/g) || []; let status: 'success' | 'warning' | 'error' = 'warning'; let score = 60; let recomendacoes: string[] = []; if (isHardFail) { status = 'success'; score = 90; } else if (spf.includes('~all')) { status = 'warning'; score = 70; recomendacoes.push('Considere mudar ~all para -all para protecao mais forte'); } else if (!hasAll) { status = 'error'; score = 30; recomendacoes.push('Adicione ~all ou -all ao final do seu SPF'); } if (includes.length > 10) { score -= 20; recomendacoes.push('Voce tem muitos includes. Mais de 10 lookups pode quebrar o SPF'); } return { status, titulo: status === 'success' ? 'SPF Configurado Corretamente' : 'SPF Configurado com Ressalvas', mensagem: `O dominio ${dominio} possui um registro SPF ${isHardFail ? 'com protecao rigida (-all)' : hasAll ? 'mas sem protecao rigida' : 'mas sem mecanismo de falha'}.`, detalhes: { Dominio: dominio, Registro: spf.substring(0, 100), Mecanismo: isHardFail ? '-all (hardfail)' : spf.includes('~all') ? '~all (softfail)' : 'Sem all', Includes: String(includes.length), 'IPs v4': String(ip4.length), 'IPs v6': String(ip6.length), }, recomendacoes: recomendacoes.length > 0 ? recomendacoes : ['Seu SPF esta bem configurado!', 'Monitore regularmente para garantir que todos os servidores legitimos estejam incluidos'], score, }; } // Verificar DKIM export async function checkDKIM(dominio: string): Promise { const selectors = ['default', 'google', 'selector1', 'selector2', 'mail', 'dkim']; let found = false; let validSelector = ''; let dkimRecord = ''; for (const selector of selectors) { const data = await queryDNS(`${selector}._domainkey.${dominio}`, 'TXT'); if (data.Answer && data.Answer.length > 0) { const record = data.Answer[0].data; if (record.includes('v=DKIM1') || record.includes('k=rsa')) { found = true; validSelector = selector; dkimRecord = record.replace(/"/g, '').substring(0, 80); break; } } } if (!found) { return { status: 'warning', titulo: 'DKIM Nao Encontrado', mensagem: `Nao foi possivel encontrar um registro DKIM valido para ${dominio} com os selectors comuns. Isso nao significa que nao existe, mas pode indicar que nao esta configurado ou usa um selector personalizado.`, detalhes: { Dominio: dominio, 'Selectors testados': selectors.join(', ') }, recomendacoes: [ 'Verifique qual selector seu servidor de e-mail usa', 'Para Microsoft 365: selector1 e selector2', 'Para Google Workspace: google', 'Entre em contato com seu administrador de e-mail', 'A Avanzato pode configurar DKIM para seu dominio', ], score: 30, }; } return { status: 'success', titulo: 'DKIM Configurado', mensagem: `DKIM encontrado com o selector "${validSelector}". Seu dominio possui assinatura digital para autenticacao de e-mails.`, detalhes: { Dominio: dominio, Selector: validSelector, Registro: dkimRecord + '...', }, recomendacoes: [ 'DKIM esta configurado corretamente!', 'Certifique-se de que todos os servidores de e-mail assinam com DKIM', 'Renove as chaves DKIM periodicamente', ], score: 85, }; } // Verificar DMARC export async function checkDMARC(dominio: string): Promise { const data = await queryDNS(`_dmarc.${dominio}`, 'TXT'); const records = (data.Answer || []).filter((r: any) => r.data && r.data.includes('v=DMARC1')); if (records.length === 0) { return { status: 'error', titulo: 'DMARC Nao Encontrado', mensagem: `O dominio ${dominio} nao possui DMARC configurado. Sem DMARC, voce nao recebe relatorios sobre falhas de autenticacao e nao pode instruir provedores a rejeitar e-mails falsos.`, detalhes: { Dominio: dominio, Registro: 'Nao encontrado' }, recomendacoes: [ 'Crie um registro TXT em _dmarc.seudominio.com', 'Exemplo: v=DMARC1; p=quarantine; rua=mailto:dmarc@seudominio.com', 'Comece com p=none para monitorar, depois mude para quarantine ou reject', 'Configure rua para receber relatorios agregados', 'Consulte a Avanzato para configuracao completa', ], score: 0, }; } const dmarc = records[0].data.replace(/"/g, ''); const policy = dmarc.match(/p=(\w+)/)?.[1] || 'none'; const rua = dmarc.match(/rua=([^;]+)/)?.[1] || 'Nao configurado'; let status: 'success' | 'warning' | 'error' = 'warning'; let score = 50; if (policy === 'reject') { status = 'success'; score = 100; } else if (policy === 'quarantine') { status = 'warning'; score = 75; } else { status = 'error'; score = 40; } return { status, titulo: policy === 'reject' ? 'DMARC com Protecao Maxima' : 'DMARC Configurado', mensagem: `DMARC encontrado com politica "${policy}". ${policy === 'reject' ? 'E-mails que falham na autenticacao serao rejeitados.' : policy === 'quarantine' ? 'E-mails suspeitos vao para spam.' : 'Apenas monitorando, sem acao sobre e-mails falsos.'}`, detalhes: { Dominio: dominio, Politica: policy, 'Relatorios (rua)': rua, Registro: dmarc.substring(0, 80) + '...', }, recomendacoes: policy === 'reject' ? ['Excelente! Sua protecao DMARC esta no nivel maximo'] : [`Considere mudar p=${policy} para p=reject para protecao total`, 'Monitore os relatorios rua antes de mudar para reject'], score, }; } // MX Lookup export async function checkMX(dominio: string): Promise { const data = await queryDNS(dominio, 'MX'); const records = (data.Answer || []).sort((a: any, b: any) => a.preference - b.preference); if (records.length === 0) { return { status: 'error', titulo: 'Registros MX Nao Encontrados', mensagem: `O dominio ${dominio} nao possui registros MX. Sem MX, o dominio nao pode receber e-mails.`, detalhes: { Dominio: dominio, Status: 'Sem MX' }, recomendacoes: [ 'Configure registros MX no DNS do seu dominio', 'Para Microsoft 365: siga o assistente de configuracao', 'Para Google Workspace: adicione os MX do Google', ], score: 0, }; } const mxProviders = records.map((r: any) => r.data).join(', '); const isMicrosoft = mxProviders.toLowerCase().includes('microsoft') || mxProviders.toLowerCase().includes('outlook') || mxProviders.toLowerCase().includes('protection'); const isGoogle = mxProviders.toLowerCase().includes('google') || mxProviders.toLowerCase().includes('aspmx'); const provider = isMicrosoft ? 'Microsoft 365 / Exchange Online' : isGoogle ? 'Google Workspace' : 'Outro / Servidor Proprio'; return { status: 'success', titulo: `${records.length} Servidor(es) MX Encontrado(s)`, mensagem: `O dominio ${dominio} esta configurado para receber e-mails via ${provider}.`, detalhes: { Dominio: dominio, 'Servidores MX': String(records.length), Provedor: provider, 'Prioridade mais alta': records[0].data, }, recomendacoes: [ 'Sua infraestrutura de e-mail esta configurada', `Voce esta usando: ${provider}`, 'Mantenha pelo menos 2 servidores MX para redundancia', ], score: 90, }; } // SSL Checker export async function checkSSL(dominio: string): Promise { try { // Usar a API do crt.sh para verificar certificados const res = await fetch(`https://crt.sh/?q=${encodeURIComponent(dominio)}&output=json`); const data = await res.json(); if (!data || data.length === 0) { return { status: 'warning', titulo: 'Certificado SSL Nao Encontrado', mensagem: `Nao foi possivel encontrar informacoes de certificado SSL para ${dominio} no banco de dados publico. Isso pode significar que o site nao usa HTTPS ou o certificado nao e publico.`, score: 30, }; } const cert = data[0]; const issuer = cert.issuer_name || 'Desconhecido'; const notAfter = cert.not_after ? new Date(cert.not_after) : null; const diasRestantes = notAfter ? Math.floor((notAfter.getTime() - Date.now()) / (1000 * 60 * 60 * 24)) : 0; const isExpired = diasRestantes < 0; const isExpiringSoon = diasRestantes < 30 && diasRestantes > 0; let status: 'success' | 'warning' | 'error' = 'success'; let score = 90; if (isExpired) { status = 'error'; score = 0; } else if (isExpiringSoon) { status = 'warning'; score = 50; } return { status, titulo: isExpired ? 'Certificado SSL Expirado!' : isExpiringSoon ? 'Certificado SSL Vence em Breve' : 'Certificado SSL Valido', mensagem: isExpired ? `O certificado SSL de ${dominio} EXPIROU em ${notAfter?.toLocaleDateString('pt-BR')}. Seu site esta inseguro!` : `Certificado SSL de ${dominio} emitido por ${issuer.split('=').pop()}. ${isExpiringSoon ? `Vence em ${diasRestantes} dias.` : `Valido ate ${notAfter?.toLocaleDateString('pt-BR')}.`}`, detalhes: { Dominio: dominio, Emissor: issuer.split('=').pop() || issuer, 'Valido ate': notAfter?.toLocaleDateString('pt-BR') || 'Desconhecido', 'Dias restantes': String(diasRestantes), }, recomendacoes: isExpired ? ['RENOVE IMEDIATAMENTE seu certificado SSL', 'Use Let\'s Encrypt (gratuito) ou contrate um certificado pago', 'Entre em contato com a Avanzato para renovacao urgente'] : isExpiringSoon ? [`Renove seu certificado nos proximos ${diasRestantes} dias`, 'Configure renovacao automatica', 'Considere usar Let\'s Encrypt com auto-renew'] : ['Seu certificado SSL esta valido!', 'Configure renovacao automatica para evitar expiracao', 'Monitore a data de vencimento'], score, }; } catch { return { status: 'info', titulo: 'Verificacao de SSL', mensagem: `Nao foi possivel verificar o SSL de ${dominio} externamente. Verifique diretamente no navegador clicando no cadeado ao lado da URL.`, score: 50, }; } } // Email Security Score export async function checkEmailSecurity(dominio: string): Promise { const [spf, dkim, dmarc, mx] = await Promise.all([ checkSPF(dominio), checkDKIM(dominio), checkDMARC(dominio), checkMX(dominio), ]); const scores = [spf.score || 0, dkim.score || 0, dmarc.score || 0, mx.score || 0]; const media = Math.floor(scores.reduce((a, b) => a + b, 0) / scores.length); let status: 'success' | 'warning' | 'error' = 'success'; if (media < 50) status = 'error'; else if (media < 80) status = 'warning'; return { status, titulo: `Email Security Score: ${media}/100`, mensagem: media >= 80 ? `A seguranca de e-mail de ${dominio} esta boa! Score: ${media}/100.` : media >= 50 ? `A seguranca de e-mail de ${dominio} precisa de atencao. Score: ${media}/100.` : `A seguranca de e-mail de ${dominio} esta critica! Score: ${media}/100.`, detalhes: { Dominio: dominio, 'Score Total': `${media}/100`, 'SPF': `${spf.score}/100 (${spf.status === 'success' ? 'OK' : 'Problema'})`, 'DKIM': `${dkim.score}/100 (${dkim.status === 'success' ? 'OK' : 'Atenção'})`, 'DMARC': `${dmarc.score}/100 (${dmarc.status === 'success' ? 'OK' : 'Problema'})`, 'MX': `${mx.score}/100 (${mx.status === 'success' ? 'OK' : 'Problema'})`, }, recomendacoes: [ ...spf.recomendacoes || [], ...dmarc.recomendacoes || [], ...(dkim.score && dkim.score < 80 ? dkim.recomendacoes || [] : []), ].filter((v, i, a) => a.indexOf(v) === i).slice(0, 6), score: media, }; } // Microsoft 365 Analyzer export async function checkMicrosoft365(dominio: string): Promise { const [mx, spf, dmarc, dkim] = await Promise.all([ checkMX(dominio), checkSPF(dominio), checkDMARC(dominio), checkDKIM(dominio), ]); const isMicrosoft365 = mx.detalhes?.Provedor?.includes('Microsoft'); const m365Score = isMicrosoft365 ? 40 : 0; const spfScore = spf.score || 0; const dmarcScore = dmarc.score || 0; const dkimScore = dkim.score || 0; const total = Math.min(100, m365Score + Math.floor((spfScore + dmarcScore + dkimScore) / 3 * 0.6)); let status: 'success' | 'warning' | 'error' = 'success'; if (total < 40) status = 'error'; else if (total < 70) status = 'warning'; return { status, titulo: `Microsoft 365 Analyzer: ${total}/100`, mensagem: isMicrosoft365 ? `O dominio ${dominio} esta configurado com Microsoft 365. Score de seguranca: ${total}/100.` : `O dominio ${dominio} nao parece usar Microsoft 365 como servidor de e-mail principal. Score de seguranca: ${total}/100.`, detalhes: { Dominio: dominio, 'Usa Microsoft 365': isMicrosoft365 ? 'Sim' : 'Nao detectado', 'Score Total': `${total}/100`, 'SPF': `${spfScore}/100`, 'DKIM': `${dkimScore}/100`, 'DMARC': `${dmarcScore}/100`, }, recomendacoes: isMicrosoft365 ? [ ...(total < 80 ? ['Configure DKIM corretamente para Microsoft 365'] : []), ...(dmarcScore < 80 ? ['Fortaleca a politica DMARC'] : []), 'Habilite ATP (Advanced Threat Protection) no Microsoft 365', 'Configure regras de anti-spam e anti-malware', 'Ative a autenticacao de dois fatores para todos os usuarios', ] : [ 'Se voce usa Microsoft 365, verifique se os registros MX estao corretos', 'Configure SPF com include:_spf.microsoft.com', 'Ative DKIM no portal do Microsoft 365', 'Configure DMARC para monitoramento', ], score: total, }; }