Aplicativos de Atrair Leads
This commit is contained in:
@@ -0,0 +1,373 @@
|
||||
// ============================================================================
|
||||
// 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<any> {
|
||||
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<ResultadoFerramenta> {
|
||||
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<ResultadoFerramenta> {
|
||||
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<ResultadoFerramenta> {
|
||||
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<ResultadoFerramenta> {
|
||||
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<ResultadoFerramenta> {
|
||||
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<ResultadoFerramenta> {
|
||||
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<ResultadoFerramenta> {
|
||||
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,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user