Fix invalid prioridade filter silently matching P4 instead of nothing

buildLeadFilter used Number(filtro.prioridade) || 4, so an explicit
prioridade=0 or any non-numeric value (both falsy after Number()) matched
P4 leads instead of the requested (invalid) priority. Not reachable via
the UI (its dropdown only offers 1-4) but reachable through a direct API
call. Drops the fallback: an invalid value becomes NaN, which node:sqlite
accepts as a bound parameter and never compares equal to anything, so it
now correctly matches zero rows instead of silently redirecting to P4.

Found via a full-project audit.
This commit is contained in:
Gustavo
2026-07-31 22:30:45 -03:00
parent 61a00e9fc2
commit d6fdfc6e2d
2 changed files with 30 additions and 1 deletions
+8 -1
View File
@@ -71,8 +71,15 @@ export function buildLeadFilter(filtro = {}) {
eq('produto_principal', filtro.produto);
if (filtro.prioridade !== undefined && filtro.prioridade !== '') {
// Number(...) || 4 mapeava um filtro invalido (ex.: prioridade=0, ou
// texto nao numerico) silenciosamente para P4, ja que 0/NaN sao falsy —
// um prioridade=0 explicito (fora do dominio 1-4 da UI, mas alcancavel
// via chamada direta a API) retornava leads de P4 em vez de nao bater
// com nada. Sem o fallback: um valor invalido vira NaN, que o SQLite
// aceita como parametro e nunca compara igual a nada (0 linhas), em vez
// de redirecionar silenciosamente para outra prioridade.
where.push('prioridade = ?');
params.push(Number(filtro.prioridade) || 4);
params.push(Number(filtro.prioridade));
}
if (filtro.score_min !== undefined && filtro.score_min !== '') {
+22
View File
@@ -98,6 +98,28 @@ test('opt-out bloqueia os dois lados de um par 12/13 digitos assimetrico', async
db.close();
});
// Number(...) || 4 tratava prioridade=0 (ou texto nao numerico) como P4,
// ja que 0/NaN sao falsy em JS — um filtro invalido devolvia leads de P4 em
// vez de nao bater com nada.
test('filtro de prioridade invalido nao e silenciosamente tratado como P4', async () => {
const { openDb } = await import('../src/db.mjs');
const { listLeads } = await import('../src/treatment/queries.mjs');
const db = openDb(':memory:');
db.prepare(
`INSERT INTO leads (dedup_key, empresa, whatsapp, prioridade, telefone_valido)
VALUES ('p1', 'Empresa P1', '5511999990001', 1, 1)`
).run();
db.prepare(
`INSERT INTO leads (dedup_key, empresa, whatsapp, prioridade, telefone_valido)
VALUES ('p4', 'Empresa P4', '5511999990004', 4, 1)`
).run();
assert.deepEqual(listLeads(db, { prioridade: '0' }).rows.map((r) => r.empresa), []);
assert.deepEqual(listLeads(db, { prioridade: 'abc' }).rows.map((r) => r.empresa), []);
assert.deepEqual(listLeads(db, { prioridade: '4' }).rows.map((r) => r.empresa), ['Empresa P4']);
db.close();
});
test('listagem e detalhe derivam o estado da verificacao equivalente mais recente', async () => {
const { openDb, saveWhatsAppVerification } = await import('../src/db.mjs');
const { getLead, listLeads } = await import('../src/treatment/queries.mjs');