用于转义 html 标签的 Joi 扩展

Joi extension for escaping html tags

我想创建扩展程序来清理字符串输入并剥离 html 标签。

为此,我使用 sanitize-html npm 包。

这是我目前尝试过的方法。

const sanitizeHtml = require('sanitize-html');

module.exports = function htmlStrip(joi) {
  return {
    type: 'htmlStrip',
    base: joi.string(),
    messages: {
      htmlStrip: 'Should not contain any html tags.',
    },
    validate(value, helpers) {
      const clean = sanitizeHtml(value, {
        allowedTags: [],
        allowedAttributes: {},
      });
      if (clean) {
        return clean;
      }
      return { value, errors: helpers.error('htmlStrip') };
    },
  };
};

但是我遇到了以下错误。

TypeError: Joi.string(...).trim(...).htmlStrip is not a function

我也试过如下传递规则对象,但仍然出现同样的错误。

const sanitizeHtml = require('sanitize-html');

module.exports = function htmlStrip(joi) {
  return {
    type: 'htmlStrip',
    base: joi.string(),
    messages: {
      htmlStrip: 'Should not contain any html tags.',
    },
    rules: {
      htmlStrip: {
        validate(params, value, state, options) {
          const clean = sanitizeHtml(value, {
            allowedTags: [],
            allowedAttributes: {},
          });
          if (clean) {
            return clean;
          }
          return this.createError('string.htmlStrip', { value }, state, options);
        },
      },
    },
  };
};

我正在关注提到的文档 here

这就是我使用扩展验证器的方式。

const Joi = require('@hapi/joi').extend(require('@hapi/joi-date')).extend(require('../utils/sanitize-html-joi'));

const validateAddressCreateData = (data) => {
  const schema = Joi.object({
    address: Joi.string().trim().htmlStrip().required(),
    label: Joi.string()
      .required(),
  });
  return schema.validate(data);
};

不确定为什么你假设 Joi.string().trim() 的类型将与 Joi 相同,考虑到你扩展了 Joi 对象,但期望 htmlStripJoi.string().trim() 个结果可用。

两种类型的简单 console.log 表明它们是不同的类型。

console.log(Object.keys(Joi)):

[ '_types',
  'alternatives',
  'any',
  'array',
  'boolean',
  ...
  'htmlStrip' ]

console.log(Object.keys(Joi.string().trim());:

[ 'type',
  '$_root',
  '$_temp',
  '_ids',
  '_preferences',
  '_valids',
  '_invalids',
  '_rules',
  '_singleRules',
  '_refs',
  '_flags',
  '_cache',
  '$_terms',
  '$_super' ]

trim 的结果 $_super 似乎不包含任何键,因此它们并不真正相关。

我相信如果你想pre-process你的输入然后然后使用你的htmlStrip,你必须做这样的事情:

const sanitizeHtml = require('sanitize-html');

module.exports = function htmlStrip(joi) {
  return {
    type: 'htmlStrip',
    base: joi.string(),
    messages: {
      htmlStrip: 'Should not contain any html tags.',
    },
    validate(value, helpers) {
      const clean = sanitizeHtml(value, {
        allowedTags: [],
        allowedAttributes: {},
      });
      if (clean == value) {
        return { clean, errors: [] };
      }
      return { value, errors: helpers.error('htmlStrip') };
    },
  };
};

以下是我的使用方法:

const Joi = require('@hapi/joi').extend(require('@hapi/joi-date')).extend(require('./san'));

const validateAddressCreateData = (data) => {
  const schema = Joi.object({
    address: Joi.htmlStrip(Joi.string().trim()).required(),
    label: Joi.string().required(),
  });
  return schema.validate(data);
};

console.log(validateAddressCreateData({ address: "<body>test</body>", label: "abc"}));

但我不确定输出是否如您预期的那样:

{ value: { address: '<body>test</body>', label: 'abc' },
  error:
   { ValidationError: Should not contain any html tags.
     _original: { address: '<body>test</body>', label: 'abc' },
     details: [ [Object] ] } }

所以,它似乎根据定义的验证消息来验证输入。或者您真的想 修改 正在传递的地址 html 吗?

编辑 现在明白您的意思了,相应地修改了 htmlStrip。请看比较if(value == clean)。如果消毒剂不需要 trim 任何东西,则意味着输入字符串不包含任何 html 标签。 Return 其他情况错误。

使用自定义验证导出 Joi 将解决此问题(custom_joi.js

const sanitizeHtml = require('sanitize-html');
const Joi = require('@hapi/joi')

module.exports = Joi.extend((joi) => ({
 type: "string",
 base: joi.string(),
 messages: {
    "string.htmlStrip": "{{#label}} not contain any html tags"
 },
 rules: {
 htmlStrip: {
  validate(value, helpers) {
    const clean = sanitizeHtml(value, {
      allowedTags: [],
      allowedAttributes: {},
    });
    if (clean == value) {
      return clean;
    }
    return helpers.error("string.htmlStrip")
  }
} } } ) )

并在控制器中导入我们的自定义文件

const Joi = require('../../_helpers/custom_joi');

然后创建验证架构

const schema = Joi.object().keys({
notes: Joi.string().htmlStrip().allow('', null),
specialInstructions: Joi.string().htmlStrip()
});
const { error, value } = schema.validate(req.body);