All files / bintra/controllers pfilter.js

90.56% Statements 48/53
85.71% Branches 30/35
100% Functions 7/7
90.38% Lines 47/52

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 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118                  1x 1x 1x 1x     49x 49x 1x   49x       4x 4x 1x   4x       5x 5x     5x       2x 1x   1x 1x       7x                   11x 11x 1x   11x                     1x 80x 80x 77x 79x 79x           7x 7x           49x 49x   11x 11x   4x 4x       5x 5x   2x 2x   1x 1x     77x   3x 3x      
'use strict';
 
/**
 * API controller for parameter filtering.
 * @module controllers/usepfilterrs
 * @license MIT
 * @author Kai KRETSCHMANN <kai@kretschmann.consulting>
 */
 
const log4js = require('log4js');
const logger = log4js.getLogger('CONTROLLERS');
logger.level = process.env.LOGLEVEL_CONTROLLERS || process.env.LOGLEVEL || /* istanbul ignore next */ 'warn';
logger.error(`Local loglevel for CONTROLLERS is ${logger.level}`);
 
function cleanupString (s) {
  const sNew = s.replaceAll(/[^a-z0-9\-._ ~:+]/gi, '');
  if (sNew !== s) {
    logger.warn('Filtered invalid chars');
  }
  return sNew;
}
 
function cleanupName (s) {
  const sNew = s.replaceAll(/[^a-z0-9\-.]/gi, '');
  if (sNew !== s) {
    logger.warn('Filtered invalid chars');
  }
  return sNew;
}
 
function cleanupWord (s) {
  const sNew = s.replaceAll(/[^a-z]/gi, '');
  Iif (sNew !== s) {
    logger.warn('Filtered invalid chars');
  }
  return sNew;
}
 
function cleanupStatus (s) {
  if (s.match(/^(register|active|disabled|deleted)$/)) {
    return s;
  } // if
  logger.warn('Filtered invalid status');
  return 'disabled'; // set to default value if in doubt
}
 
function cleanupNumber (s) {
  Eif (typeof s === "number") return s;
 
  const sNew = s.replaceAll(/[^0-9]/g, '');
  if (sNew !== s) {
    logger.warn('Filtered invalid number chars');
  }
  return sNew;
}
 
function cleanupStringHex (s) {
  const sNew = s.replaceAll(/[^a-f0-9]/gi, '');
  if (sNew !== s) {
    logger.warn('Filtered invalid chars');
  }
  return sNew;
}
 
/**
 * Filter URL per attribute name and type.
 * @function pfilter
 * @public
 * @param {object} req The web request object
 * @param {object} _res The web response object
 * @param {object} next The web next object
 */
module.exports = function pfilter (req, _res, next) {
  logger.info(`In pfilter: ${req.url}`);
  if (req.url.startsWith('/v1/')) {
    for (const [key, value] of Object.entries(req.query)) {
      logger.debug(`${key}:${value}`);
      switch (key) {
        case 'count':
        case 'skip':
        case 'page':
        case 'rand':
        case 'size':
          req.query[key] = cleanupNumber(value);
          break;
        case 'packageName':
        case 'packageArch':
        case 'packageVersion':
        case 'packageFamily':
        case 'packageSubFamily':
          req.query[key] = cleanupString(value);
          break;
        case 'packageHash':
          req.query[key] = cleanupStringHex(value);
          break;
        case 'name':
          req.query[key] = cleanupName(value);
          break;
        case 'sort':
        case 'sorters':
        case 'direction':
          req.query[key] = cleanupWord(value);
          break;
        case 'status':
          req.query[key] = cleanupStatus(value);
          break;
        default:
          logger.warn(`Don't know about ${key}`);
          break;
      }
    }
    next();
  } else {
    logger.debug('Ignore non API stuff');
    next();
  } // if
};