All files / utils sanitize.js

33.82% Statements 23/68
100% Branches 1/1
20% Functions 1/5
33.82% Lines 23/68

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 711x 1x 1x                 1x 1x               1x 1x           1x 1x                                         1x 1x 2x 2x           2x 2x 1x 1x 1x 1x 1x 1x 1x 1x      
const allowedVehiculoTipos = new Set(['carro', 'moto', 'bici']);
 
// Valida y normaliza enteros seguros (por ejemplo, page, pageSize, limit, offsets)
function toSafeInt(value, { min = 0, max = 100000, fallback = 0 } = {}) {
  const n = Number(value);
  if (!Number.isFinite(n)) return fallback;
  const i = Math.trunc(n);
  if (i < min) return min;
  if (i > max) return max;
  return i;
}
 
// Normaliza texto para LIKE (escapa % y _), opcionalmente mayúsculas
function toSafeLike(value, { uppercase = true } = {}) {
  if (typeof value !== 'string') return null;
  const v = uppercase ? value.toUpperCase() : value;
  // Escapar comodines SQL
  const escaped = v.replace(/[%_]/g, ch => `\\${ch}`);
  return `%${escaped}%`;
}
 
// Valida tipo de vehículo contra lista blanca
function toSafeTipoVehiculo(value) {
  if (typeof value !== 'string') return null;
  const v = value.toLowerCase();
  return allowedVehiculoTipos.has(v) ? v : null;
}
 
// Middleware generador para filtros comunes de reportes
function sanitizeReportFilters(req, res, next) {
  try {
    const q = req.query || {};
    const desde = typeof q.desde === 'string' && q.desde.length >= 8 ? q.desde : new Date().toISOString().slice(0, 10);
    const hasta = typeof q.hasta === 'string' && q.hasta.length >= 8 ? q.hasta : new Date().toISOString().slice(0, 10);
    const estado = q.estado === 'activo' ? 'activo' : (q.estado === 'finalizado' ? 'finalizado' : null);
    const tipo = toSafeTipoVehiculo(q.tipo);
    const placaLike = q.placa ? toSafeLike(String(q.placa)) : null;
    const page = toSafeInt(q.page, { min: 0, max: 100000, fallback: 0 });
    const pageSize = toSafeInt(q.pageSize, { min: 1, max: 100, fallback: 20 });
    const limit = toSafeInt(q.limit, { min: 1, max: 5000, fallback: 1000 });

    req.sanitized = Object.assign({}, req.sanitized, {
      desde, hasta, estado, tipo, placaLike, page, pageSize, limit
    });
    next();
  } catch (e) {
    return res.status(400).json({ success: false, message: 'Parámetros inválidos' });
  }
}
 
// Middleware para params numéricos :id
function sanitizeIdParam(paramName = 'id') {
  return function (req, res, next) {
    const raw = req.params && req.params[paramName];
    const id = toSafeInt(raw, { min: 1, max: Number.MAX_SAFE_INTEGER, fallback: 0 });
    if (!id) return res.status(400).json({ success: false, message: `${paramName} inválido` });
    req.params[paramName] = id;
    next();
  };
}
 
module.exports = {
  toSafeInt,
  toSafeLike,
  toSafeTipoVehiculo,
  sanitizeReportFilters,
  sanitizeIdParam,
};