validator.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. "use strict";
  2. var __importDefault = (this && this.__importDefault) || function (mod) {
  3. return (mod && mod.__esModule) ? mod : { "default": mod };
  4. };
  5. Object.defineProperty(exports, "__esModule", { value: true });
  6. exports.Validator = void 0;
  7. const utils_js_1 = require("ethereum-cryptography/utils.js");
  8. const blake2b_js_1 = require("ethereum-cryptography/blake2b.js");
  9. const is_my_json_valid_1 = __importDefault(require("is-my-json-valid"));
  10. const formats_js_1 = __importDefault(require("./formats.js"));
  11. const errors_js_1 = require("./errors.js");
  12. class Validator {
  13. // eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function
  14. constructor() {
  15. this._schemas = new Map();
  16. }
  17. static factory() {
  18. if (!Validator.validatorInstance) {
  19. Validator.validatorInstance = new Validator();
  20. }
  21. return Validator.validatorInstance;
  22. }
  23. getSchema(key) {
  24. return this._schemas.get(key);
  25. }
  26. addSchema(key, schema) {
  27. this._schemas.set(key, this.createValidator(schema));
  28. }
  29. // eslint-disable-next-line class-methods-use-this
  30. createValidator(schema) {
  31. // eslint-disable-next-line @typescript-eslint/no-unsafe-call
  32. // @ts-expect-error validator params correction
  33. return (0, is_my_json_valid_1.default)(schema, {
  34. formats: formats_js_1.default,
  35. greedy: true,
  36. verbose: true,
  37. additionalProperties: false,
  38. });
  39. }
  40. validate(schema, data, options) {
  41. const localValidate = this.getOrCreateValidator(schema);
  42. if (!localValidate(data)) {
  43. const errors = this.convertErrors(localValidate.errors, schema, data);
  44. if (errors) {
  45. if (options === null || options === void 0 ? void 0 : options.silent) {
  46. return errors;
  47. }
  48. throw new errors_js_1.Web3ValidatorError(errors);
  49. }
  50. }
  51. return undefined;
  52. }
  53. convertErrors(errors, schema, data) {
  54. if (errors && Array.isArray(errors) && errors.length > 0) {
  55. return errors.map((error) => {
  56. let message;
  57. let keyword;
  58. let params;
  59. let schemaPath;
  60. schemaPath = Array.isArray(error.schemaPath)
  61. ? error.schemaPath.slice(1).join('/')
  62. : '';
  63. const { field } = error;
  64. const _instancePath = schemaPath ||
  65. // eslint-disable-next-line no-useless-escape
  66. ((field === null || field === void 0 ? void 0 : field.length) >= 4 ? `${field.slice(4).replace(/\"|\[|\]/g, '')}` : '/');
  67. const instancePath = _instancePath ? `/${_instancePath}` : '';
  68. if ((error === null || error === void 0 ? void 0 : error.message) === 'has less items than allowed') {
  69. // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
  70. const schemaData = this.getObjectValueByPath(schema, schemaPath);
  71. // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
  72. if (schemaData.minItems) {
  73. keyword = 'minItems';
  74. schemaPath = `${schemaPath}/minItems`;
  75. // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
  76. params = { limit: schemaData.minItems };
  77. // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/restrict-template-expressions
  78. message = `must NOT have fewer than ${schemaData.minItems} items`;
  79. }
  80. }
  81. else if ((error === null || error === void 0 ? void 0 : error.message) === 'has more items than allowed') {
  82. // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
  83. const schemaData = this.getObjectValueByPath(schema, schemaPath);
  84. // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
  85. if (schemaData.maxItems) {
  86. keyword = 'maxItems';
  87. schemaPath = `${schemaPath}/maxItems`;
  88. // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
  89. params = { limit: schemaData.maxItems };
  90. // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/restrict-template-expressions
  91. message = `must NOT have more than ${schemaData.maxItems} items`;
  92. }
  93. }
  94. else if ((error === null || error === void 0 ? void 0 : error.message.startsWith('must be')) &&
  95. (error === null || error === void 0 ? void 0 : error.message.endsWith('format'))) {
  96. const formatName = error === null || error === void 0 ? void 0 : error.message.split(' ')[2];
  97. if (formatName) {
  98. message = `must pass "${formatName}" validation`;
  99. }
  100. }
  101. // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
  102. const dataValue = this.getObjectValueByPath(data, instancePath);
  103. return {
  104. keyword: keyword !== null && keyword !== void 0 ? keyword : error.field,
  105. instancePath,
  106. schemaPath: `#${schemaPath}`,
  107. // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
  108. params: params !== null && params !== void 0 ? params : { value: dataValue },
  109. message: message !== null && message !== void 0 ? message : error.message,
  110. };
  111. });
  112. }
  113. return undefined;
  114. }
  115. getOrCreateValidator(schema) {
  116. const key = Validator.getKey(schema);
  117. let _validator = this.getSchema(key);
  118. if (!_validator) {
  119. this.addSchema(key, schema);
  120. _validator = this.getSchema(key);
  121. }
  122. return _validator;
  123. }
  124. static getKey(schema) {
  125. return (0, utils_js_1.toHex)((0, blake2b_js_1.blake2b)((0, utils_js_1.utf8ToBytes)(JSON.stringify(schema))));
  126. }
  127. getObjectValueByPath(obj, pointer, objpath) {
  128. try {
  129. if (typeof obj !== 'object')
  130. throw new Error('Invalid input object');
  131. if (typeof pointer !== 'string')
  132. throw new Error('Invalid JSON pointer');
  133. const parts = pointer.split('/');
  134. if (!['', '#'].includes(parts.shift())) {
  135. throw new Error('Invalid JSON pointer');
  136. }
  137. if (parts.length === 0)
  138. return obj;
  139. let curr = obj;
  140. for (const part of parts) {
  141. if (typeof part !== 'string')
  142. throw new Error('Invalid JSON pointer');
  143. // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument
  144. if (objpath)
  145. objpath.push(curr); // does not include target itself, but includes head
  146. const prop = this.untilde(part);
  147. if (typeof curr !== 'object')
  148. return undefined;
  149. if (!Object.prototype.hasOwnProperty.call(curr, prop))
  150. return undefined;
  151. // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
  152. curr = curr[prop];
  153. }
  154. // eslint-disable-next-line @typescript-eslint/no-unsafe-return
  155. return curr;
  156. }
  157. catch (e) {
  158. return '';
  159. }
  160. }
  161. // eslint-disable-next-line class-methods-use-this
  162. untilde(string) {
  163. if (!string.includes('~'))
  164. return string;
  165. return string.replace(/~[01]/g, match => {
  166. switch (match) {
  167. case '~1':
  168. return '/';
  169. case '~0':
  170. return '~';
  171. default:
  172. throw new Error('Unreachable');
  173. }
  174. });
  175. }
  176. }
  177. exports.Validator = Validator;
  178. //# sourceMappingURL=validator.js.map