src/collectors/tls.ts (view raw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
import tls from 'node:tls';
import type { Observations, CertificadoInfo } from '../core/types.js';
export async function coletarTls(obs: Observations): Promise<void> {
let url: URL;
try {
url = new URL(obs.urlFinal || obs.urlSolicitada);
} catch {
return;
}
if (url.protocol !== 'https:') {
obs.protocolo = { http2: false, http3Anunciado: false };
return;
}
const host = url.hostname;
const porta = url.port ? Number(url.port) : 443;
await new Promise<void>((resolver) => {
// lê o certificado apresentado, mesmo inválido, só para relatá-lo; nenhum corpo é consumido aqui
const socket = tls.connect(
{
host,
port: porta,
servername: host,
ALPNProtocols: ['h2', 'http/1.1'],
rejectUnauthorized: false,
timeout: 8000,
},
() => {
try {
const cert = socket.getPeerCertificate(false);
const cn = txt(cert?.subject?.CN);
const issuerCn = txt(cert?.issuer?.CN);
const issuerO = txt(cert?.issuer?.O);
const info: CertificadoInfo = {
emitidoPara: cn,
emitidoPor: issuerCn ? `${issuerO ? issuerO + ' — ' : ''}${issuerCn}` : issuerO,
validoDe: cert?.valid_from,
validoAte: cert?.valid_to,
san: cert?.subjectaltname
?.split(',')
.map((s) => s.trim().replace(/^DNS:/, ''))
.filter(Boolean),
protocoloTls: socket.getProtocol() ?? undefined,
};
obs.certificado = info;
obs.protocolo = {
http2: socket.alpnProtocol === 'h2',
http3Anunciado: obs.protocolo?.http3Anunciado ?? false,
altSvc: obs.protocolo?.altSvc,
};
} catch (erro) {
obs.avisos.push(`Falha ao ler o certificado: ${(erro as Error).message}`);
} finally {
socket.end();
resolver();
}
},
);
socket.on('error', (erro) => {
obs.avisos.push(`Falha na conexão TLS: ${erro.message}`);
resolver();
});
socket.on('timeout', () => {
socket.destroy();
resolver();
});
});
}
function txt(v: string | string[] | undefined): string | undefined {
if (v == null) return undefined;
return Array.isArray(v) ? v.join(', ') : v;
}
|