schema.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.checkSchema = void 0;
  4. exports.createCheckSchema = createCheckSchema;
  5. const _ = require("lodash");
  6. const chain_1 = require("../chain");
  7. const utils_1 = require("../utils");
  8. const check_1 = require("./check");
  9. const validLocations = ['body', 'cookies', 'headers', 'params', 'query'];
  10. const protectedNames = ['errorMessage', 'in', 'optional'];
  11. /**
  12. * Factory for a {@link checkSchema()} function which can have extension validators and sanitizers.
  13. *
  14. * @see {@link checkSchema()}
  15. */
  16. function createCheckSchema(createChain, extraValidators = [], extraSanitizers = []) {
  17. /** Type guard for an object entry for a standard validator. */
  18. function isStandardValidator(entry) {
  19. return (
  20. // #664 - explicitly exclude properties which should be set per validator
  21. !['not', 'withMessage'].includes(entry[0]) &&
  22. (entry[0] in chain_1.ValidatorsImpl.prototype || extraValidators.includes(entry[0])) &&
  23. entry[1]);
  24. }
  25. /** Type guard for an object entry for a standard sanitizer. */
  26. function isStandardSanitizer(entry) {
  27. return ((entry[0] in chain_1.SanitizersImpl.prototype || extraSanitizers.includes(entry[0])) &&
  28. entry[1]);
  29. }
  30. /** Type guard for an object entry for a custom validator. */
  31. function isCustomValidator(entry) {
  32. return (!isStandardValidator(entry) &&
  33. !isStandardSanitizer(entry) &&
  34. typeof entry[1] === 'object' &&
  35. entry[1] &&
  36. typeof entry[1].custom === 'function');
  37. }
  38. /** Type guard for an object entry for a custom sanitizer. */
  39. function isCustomSanitizer(entry) {
  40. return (!isStandardValidator(entry) &&
  41. !isStandardSanitizer(entry) &&
  42. typeof entry[1] === 'object' &&
  43. entry[1] &&
  44. typeof entry[1].customSanitizer === 'function');
  45. }
  46. return (schema, defaultLocations = validLocations) => {
  47. const chains = Object.keys(schema).map(field => {
  48. const config = schema[field];
  49. const chain = createChain(field, ensureLocations(config, defaultLocations), config.errorMessage);
  50. // optional doesn't matter where it happens in the chain
  51. if (config.optional) {
  52. chain.optional(config.optional === true ? true : config.optional.options);
  53. }
  54. for (const entry of Object.entries(config)) {
  55. if (protectedNames.includes(entry[0]) || !entry[1]) {
  56. continue;
  57. }
  58. if (!isStandardValidator(entry) &&
  59. !isStandardSanitizer(entry) &&
  60. !isCustomValidator(entry) &&
  61. !isCustomSanitizer(entry)) {
  62. console.warn(`express-validator: schema of "${field}" has unknown validator/sanitizer "${entry[0]}"`);
  63. continue;
  64. }
  65. // For validators, stuff that must come _before_ the validator itself in the chain.
  66. if ((isStandardValidator(entry) || isCustomValidator(entry)) && entry[1] !== true) {
  67. const [, validatorConfig] = entry;
  68. validatorConfig.if && chain.if(validatorConfig.if);
  69. validatorConfig.negated && chain.not();
  70. }
  71. if (isStandardValidator(entry) || isStandardSanitizer(entry)) {
  72. const options = entry[1] ? (entry[1] === true ? [] : _.castArray(entry[1].options)) : [];
  73. chain[entry[0]](...options);
  74. }
  75. if (isCustomValidator(entry)) {
  76. chain.custom(entry[1].custom);
  77. }
  78. if (isCustomSanitizer(entry)) {
  79. chain.customSanitizer(entry[1].customSanitizer);
  80. }
  81. // For validators, stuff that must come _after_ the validator itself in the chain.
  82. if ((isStandardValidator(entry) || isCustomValidator(entry)) && entry[1] !== true) {
  83. const [, validatorConfig] = entry;
  84. validatorConfig.bail &&
  85. chain.bail(validatorConfig.bail === true ? {} : validatorConfig.bail);
  86. validatorConfig.errorMessage && chain.withMessage(validatorConfig.errorMessage);
  87. }
  88. }
  89. return chain;
  90. });
  91. const run = async (req) => (0, utils_1.runAllChains)(req, chains);
  92. return Object.assign(chains, { run });
  93. };
  94. }
  95. /**
  96. * Creates an express middleware with validations for multiple fields at once in the form of
  97. * a schema object.
  98. *
  99. * @param schema the schema to validate.
  100. * @param defaultLocations
  101. * @returns
  102. */
  103. exports.checkSchema = createCheckSchema(check_1.check);
  104. function ensureLocations(config, defaults) {
  105. // .filter(Boolean) is done because in can be undefined -- which is not going away from the type
  106. // See https://github.com/Microsoft/TypeScript/pull/29955 for details
  107. const locations = Array.isArray(config.in)
  108. ? config.in
  109. : [config.in].filter(Boolean);
  110. const actualLocations = locations.length ? locations : defaults;
  111. return actualLocations.filter(location => validLocations.includes(location));
  112. }