all repos — red-anatomia @ main

red-anatomia

test/detection.test.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
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
import { describe, it, expect } from 'vitest';
import type { Observations } from '../src/core/types.js';
import { detectar } from '../src/detection/engine.js';
import { faixaDe } from '../src/detection/confidence.js';
import { montarRelatorio } from '../src/report/model.js';

function obs(patch: Partial<Observations>): Observations {
  return {
    urlSolicitada: 'https://exemplo.com',
    urlFinal: 'https://exemplo.com/',
    modo: 'rapido',
    redirecionamentos: [],
    headers: {},
    cookies: [],
    html: '',
    meta: {},
    scriptSrc: [],
    linksAssets: [],
    globaisJs: [],
    avisos: [],
    ...patch,
  };
}

describe('detecção do WordPress', () => {
  const wp = obs({
    html: '<link rel="https://api.w.org/" href="/wp-json/" /> <img src="/wp-content/uploads/logo.png">',
    meta: { generator: 'WordPress 6.5.2' },
    headers: { link: '<https://exemplo.com/wp-json/>; rel="https://api.w.org/"' },
    scriptSrc: ['/wp-content/themes/x/app.js'],
  });
  const deteccoes = detectar(wp);

  it('reconhece o WordPress com alta confiança', () => {
    const d = deteccoes.find((x) => x.nome === 'WordPress');
    expect(d).toBeDefined();
    expect(d!.confianca).toBeGreaterThanOrEqual(90);
    expect(d!.faixa).toBe('praticamente confirmado');
  });

  it('extrai a versão do meta generator', () => {
    expect(deteccoes.find((x) => x.nome === 'WordPress')?.versao).toBe('6.5.2');
  });

  it('preserva evidências de múltiplas fontes independentes', () => {
    const d = deteccoes.find((x) => x.nome === 'WordPress')!;
    expect(d.evidencias.length).toBeGreaterThan(1);
    expect(d.evidencias.some((e) => e.fonte === 'meta')).toBe(true);
    const fontes = new Set(d.evidencias.map((e) => e.fonte));
    expect(fontes.size).toBeGreaterThanOrEqual(2);
  });

  it('implica PHP e MySQL', () => {
    expect(deteccoes.some((x) => x.nome === 'PHP')).toBe(true);
    expect(deteccoes.some((x) => x.nome === 'MySQL')).toBe(true);
  });
});

describe('detecção do Next.js', () => {
  const next = obs({
    html: '<script id="__NEXT_DATA__" type="application/json">{}</script> <div>/_next/static/</div>',
    headers: { 'x-powered-by': 'Next.js' },
    scriptSrc: ['/_next/static/chunks/main.js'],
  });
  const deteccoes = detectar(next);

  it('reconhece o Next.js e implica React', () => {
    expect(deteccoes.some((x) => x.nome === 'Next.js')).toBe(true);
    expect(deteccoes.some((x) => x.nome === 'React')).toBe(true);
  });
});

describe('faixas de confiança', () => {
  it('mapeia scores para faixas textuais', () => {
    expect(faixaDe(95)).toBe('praticamente confirmado');
    expect(faixaDe(70)).toBe('provável');
    expect(faixaDe(50)).toBe('possível');
    expect(faixaDe(20)).toBe('indício fraco');
  });
});

describe('bloco "não foi possível confirmar"', () => {
  it('lista o banco de dados quando nenhum é detectado', () => {
    const rep = montarRelatorio(obs({ html: '<html></html>' }));
    expect(rep.naoDeterminado.some((i) => i.includes('banco de dados'))).toBe(true);
  });

  it('não afirma HTTP/3 quando não anunciado', () => {
    const rep = montarRelatorio(obs({ protocolo: { http2: true, http3Anunciado: false } }));
    expect(rep.naoDeterminado.some((i) => i.toLowerCase().includes('http/3'))).toBe(true);
  });
});