New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

openapi-enforcer

Package Overview
Dependencies
Maintainers
1
Versions
131
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

openapi-enforcer - npm Package Compare versions

Comparing version 1.9.0 to 1.10.0

docs-src/changes.md

16

docs-src/api/openapi-enforcer.md

@@ -38,2 +38,3 @@ ---

| requestBodyAllowedMethods | An `object` specifying which request methods to allow (or disallow) a request body for. The object you provide here will merge with the default value. | `object` | ` { post: true, put: true, options: true, head: true, patch: true } `
| production | A `boolean` that when set to `true` will reduce the number of validations run on your OpenAPI document. This will allow your app to load a little faster for production. Do not use this setting if you are not sure that the OpenAPI document is valid otherwise other runtime errors are sure to occur. | `boolean` | `false` |

@@ -109,2 +110,17 @@ **Returns:** A Promise

## Enforcer.config
Set global configuration options for all Enforcer instances.
| Option | Description | Default |
| ------ | ----------- | ------- |
| useNewRefParser | Use the custom built ref parser to resolve multi file discriminator references. This feature is currently in beta. Please report issues on github. https://github.com/byu-oit/openapi-enforcer/issues | `false` |
**Example**
```js
const Enforcer = require('openapi-enforcer');
Enforcer.config.useNewRefParser = true; // use custom ref parser
```
## Enforcer.dereference

@@ -111,0 +127,0 @@

2

docs-src/index.md
---
title: OpenAPI Enforcer
navOrder: guide api
navOrder: guide api contributing changes
toc: false

@@ -5,0 +5,0 @@ ---

@@ -23,3 +23,4 @@ /**

const Exception = require('./src/exception');
const RefParser = require('json-schema-ref-parser');
const NewRefParser = require('./src/ref-parser');
const OldRefParser = require('json-schema-ref-parser');
const Result = require('./src/result');

@@ -35,2 +36,3 @@ const Super = require('./src/super');

* @param {boolean} [options.fullResult=false] Set to true to get back a full result object with the value, warnings, and errors.
* @param {boolean} [options.experimentalDereference=false] A soon to be default option for improved dereferencing.
* @param {object} [options.componentOptions] Options that get sent along to components.

@@ -49,22 +51,32 @@ * @returns {Promise<OpenApi|Swagger>|Promise<Result<OpenApi|Swagger>>}

const refParser = new RefParser();
let exception;
definition = util.copy(definition);
definition = await refParser.dereference(definition);
const useNewRefParser = Enforcer.config.useNewRefParser;
const refParser = useNewRefParser ? new NewRefParser(definition) : new OldRefParser();
if (useNewRefParser) {
const [ dereferenceValue, dereferenceErr ] = await refParser.dereference();
definition = dereferenceValue;
exception = dereferenceErr;
} else {
definition = await refParser.dereference(definition);
}
let exception = Exception('One or more errors exist in the OpenAPI definition');
const hasSwagger = definition.hasOwnProperty('swagger');
if (!hasSwagger && !definition.hasOwnProperty('openapi')) {
exception.message('Missing required "openapi" or "swagger" property');
if (!exception) {
exception = Exception('One or more errors exist in the OpenAPI definition');
const hasSwagger = definition.hasOwnProperty('swagger');
if (!hasSwagger && !definition.hasOwnProperty('openapi')) {
exception.message('Missing required "openapi" or "swagger" property');
} else {
const match = /^(\d+)(?:\.(\d+))(?:\.(\d+))?$/.exec(definition.swagger || definition.openapi);
if (!match) {
exception.at(hasSwagger ? 'swagger' : 'openapi').message('Invalid value');
} else {
const match = /^(\d+)(?:\.(\d+))(?:\.(\d+))?$/.exec(definition.swagger || definition.openapi);
if (!match) {
exception.at(hasSwagger ? 'swagger' : 'openapi').message('Invalid value');
} else {
const major = +match[1];
const validator = major === 2
? Enforcer.v2_0.Swagger
: Enforcer.v3_0.OpenApi;
[ openapi, exception, warnings ] = validator(definition, refParser, options.componentOptions);
} else {
const major = +match[1];
const validator = major === 2
? Enforcer.v2_0.Swagger
: Enforcer.v3_0.OpenApi;
[ openapi, exception, warnings ] = validator(definition, refParser, options.componentOptions);
}
}

@@ -79,5 +91,14 @@ }

Enforcer.config = {
useNewRefParser: false
};
Enforcer.dereference = function (definition) {
const refParser = new RefParser();
return refParser.dereference(definition);
if (Enforcer.config.useNewRefParser) {
const refParser = new NewRefParser(definition);
return refParser.dereference();
} else {
const refParser = new OldRefParser();
return refParser.dereference(definition);
}
};

@@ -84,0 +105,0 @@

{
"name": "openapi-enforcer",
"version": "1.9.0",
"version": "1.10.0",
"description": "Library for validating, parsing, and formatting data against open api schemas.",

@@ -56,4 +56,5 @@ "main": "index.js",

"dependencies": {
"axios": "^0.19.2",
"json-schema-ref-parser": "^6.0.1"
}
}

@@ -27,2 +27,3 @@ /**

const definition = parent.definition[key];
const development = !parent.production;

@@ -45,3 +46,3 @@ const definitionType = util.getDefinitionType(definition);

defToInstanceMap: parent.defToInstanceMap,
exception: parent.exception.at(key),
exception: development ? parent.exception.at(key) : parent.exception,
key,

@@ -55,2 +56,3 @@ major: parent.major,

plugins: parent.plugins,
production: parent.production,
refParser: parent.refParser,

@@ -62,3 +64,3 @@ result,

validator,
warn: parent.warn.at(key),
warn: development ? parent.warn.at(key) : parent.warn,
};

@@ -68,3 +70,3 @@ }

function normalize (data) {
const { definitionType, exception, result } = data;
const { definitionType, exception, production, result } = data;
let definition = data.definition;

@@ -87,159 +89,198 @@

// if enum is invalid then exit
if (validator.enum) {
const matches = fn(validator.enum, data);
if (!matches.includes(definition)) {
matches.length === 1
? exception.message('Value must be ' + util.smart(matches[0]) + '. Received: ' + util.smart(definition))
: exception.message('Value must be one of: ' + matches.join(', ') + '. Received: ' + util.smart(definition));
if (!production) {
// if enum is invalid then exit
if (validator.enum) {
const matches = fn(validator.enum, data);
if (!matches.includes(definition)) {
matches.length === 1
? exception.message('Value must be ' + util.smart(matches[0]) + '. Received: ' + util.smart(definition))
: exception.message('Value must be one of: ' + matches.join(', ') + '. Received: ' + util.smart(definition));
}
}
}
if (definitionType === 'array' && !freeForm) {
definition.forEach((def, i) => {
const child = childData(data, i, validator.items);
result.push(runChildValidator(child));
});
Object.freeze(result);
if (definitionType === 'array' && !freeForm) {
definition.forEach((def, i) => {
const child = childData(data, i, validator.items);
result.push(runChildValidator(child));
});
Object.freeze(result);
} else if (definitionType === 'object' && !freeForm) {
const missingRequired = [];
const notAllowed = [];
const unknownKeys = [];
} else if (definitionType === 'object' && !freeForm) {
const missingRequired = [];
const notAllowed = [];
const unknownKeys = [];
if (validator === true) {
Object.keys(definition).forEach(key => {
Object.defineProperty(result, key, {
configurable: true,
enumerable: true,
value: definition[key]
if (validator === true) {
Object.keys(definition).forEach(key => {
Object.defineProperty(result, key, {
configurable: true,
enumerable: true,
value: definition[key]
});
});
});
// Object.assign(result, util.copy(definition));
// Object.assign(result, util.copy(definition));
} else if (validator === false) {
notAllowed.push.apply(notAllowed, Object.keys(definition));
} else if (validator === false) {
notAllowed.push.apply(notAllowed, Object.keys(definition));
} else if (validator.additionalProperties) {
Object.keys(definition).forEach(key => {
const child = childData(data, key, validator.additionalProperties);
const keyValidator = EnforcerRef.isEnforcerRef(child.validator)
? child.validator.config || {}
: child.validator;
} else if (validator.additionalProperties) {
Object.keys(definition).forEach(key => {
const child = childData(data, key, validator.additionalProperties);
const keyValidator = EnforcerRef.isEnforcerRef(child.validator)
? child.validator.config || {}
: child.validator;
const allowed = keyValidator.hasOwnProperty('allowed') ? fn(keyValidator.allowed, child) : true;
let valueSet = false;
if (child.definition !== undefined) {
if (!allowed) {
notAllowed.push(key);
} else if (!keyValidator.ignored || !fn(keyValidator.ignored, child)) {
const allowed = keyValidator.hasOwnProperty('allowed') ? fn(keyValidator.allowed, child) : true;
let valueSet = false;
if (child.definition !== undefined) {
if (!allowed) {
notAllowed.push(key);
} else if (!keyValidator.ignored || !fn(keyValidator.ignored, child)) {
Object.defineProperty(result, key, {
configurable: true,
enumerable: true,
value: runChildValidator(child)
});
valueSet = true;
}
}
if (valueSet && keyValidator.errors && keyValidator !== child.validator) {
const d = Object.assign({}, child);
d.definition = result[key];
fn(keyValidator.errors, d);
}
});
} else {
// organize definition properties
Object.keys(definition).forEach(key => {
if (rxExtension.test(key)) {
Object.defineProperty(result, key, {
configurable: true,
enumerable: true,
value: runChildValidator(child)
});
valueSet = true;
value: definition[key] });
} else {
unknownKeys.push(key);
}
}
});
if (valueSet && keyValidator.errors && keyValidator !== child.validator) {
const d = Object.assign({}, child);
d.definition = result[key];
fn(keyValidator.errors, d);
}
});
// get sorted array of all properties to use
const properties = mapAndSortValidatorProperties(validator, data);
} else {
// iterate through all known properties
properties.forEach(prop => {
const data = prop.data;
const key = data.key;
const validator = data.validator;
const keyValidator = EnforcerRef.isEnforcerRef(validator)
? validator.config || {}
: validator;
const allowed = keyValidator.hasOwnProperty('allowed') ? fn(keyValidator.allowed, data) : true;
util.arrayRemoveItem(unknownKeys, key);
// organize definition properties
Object.keys(definition).forEach(key => {
if (rxExtension.test(key)) {
Object.defineProperty(result, key, {
configurable: true,
enumerable: true,
value: definition[key] });
} else {
unknownKeys.push(key);
}
});
// set default value
if (data.definition === undefined && allowed && keyValidator.hasOwnProperty('default')) {
data.definition = fn(keyValidator.default, data);
data.usedDefault = true;
data.parent.definition[key] = data.definition;
data.definitionType = util.getDefinitionType(data.definition);
}
// get sorted array of all properties to use
const properties = Object.keys(validator.properties || {})
.map(key => {
const property = validator.properties[key];
util.arrayRemoveItem(unknownKeys, key);
return {
data: childData(data, key, property),
weight: property.weight || 0
if (data.definition !== undefined) {
if (!allowed) {
notAllowed.push(key);
} else if (!keyValidator.ignored || !fn(keyValidator.ignored, data)) {
Object.defineProperty(result, key, {
configurable: true,
enumerable: true,
value: runChildValidator(data)
});
}
} else if (allowed && keyValidator.required && fn(keyValidator.required, data)) {
missingRequired.push(key);
}
});
properties.sort((a, b) => {
if (a.weight < b.weight) return -1;
if (a.weight > b.weight) return 1;
return a.data.key < b.data.key ? -1 : 1;
});
}
// iterate through all known properties
properties.forEach(prop => {
const data = prop.data;
const key = data.key;
const validator = data.validator;
const keyValidator = EnforcerRef.isEnforcerRef(validator)
? validator.config || {}
: validator;
const allowed = keyValidator.hasOwnProperty('allowed') ? fn(keyValidator.allowed, data) : true;
// report any keys that are not allowed
notAllowed.push.apply(notAllowed, unknownKeys);
if (notAllowed.length) {
notAllowed.sort();
exception.message('Propert' + (notAllowed.length === 1 ? 'y' : 'ies') + ' not allowed: ' + notAllowed.join(', '));
}
// set default value
if (data.definition === undefined && allowed && keyValidator.hasOwnProperty('default')) {
data.definition = fn(keyValidator.default, data);
data.usedDefault = true;
data.parent.definition[key] = data.definition;
data.definitionType = util.getDefinitionType(data.definition);
// report missing required properties
if (missingRequired.length) {
missingRequired.sort();
exception.message('Missing required propert' + (missingRequired.length === 1 ? 'y' : 'ies') + ': ' + missingRequired.join(', '));
}
} else if (!freeForm) {
switch (definitionType) {
case 'boolean':
case 'null':
case 'number':
case 'string':
data.result = definition;
mapSetResult(data, definition);
break;
default:
exception.message('Unknown data type provided');
break;
}
} else {
data.result = definition;
mapSetResult(data, definition);
}
} else {
if (definitionType === 'array') {
definition.forEach((def, i) => {
const child = childData(data, i, validator.items);
result.push(runChildValidator(child));
});
Object.freeze(result);
} else if (definitionType === 'object') {
Object.keys(definition).forEach(key => {
let childValidator;
if (typeof validator !== 'object') {
childValidator = validator;
} else if (validator.properties && validator.properties.hasOwnProperty(key)) {
childValidator = validator.properties[key]
} else if (validator.additionalProperties) {
childValidator = validator.additionalProperties;
}
const child = childData(data, key, childValidator);
Object.defineProperty(result, key, {
configurable: true,
enumerable: true,
value: runChildValidator(child)
});
});
if (data.definition !== undefined) {
if (!allowed) {
notAllowed.push(key);
} else if (!keyValidator.ignored || !fn(keyValidator.ignored, data)) {
// set defaults where appropriate
const properties = mapAndSortValidatorProperties(validator, data);
properties.forEach(({ data }) => {
const key = data.key;
if (!result.hasOwnProperty(key)) {
const cValidator = data.validator;
const keyValidator = EnforcerRef.isEnforcerRef(cValidator)
? cValidator.config || {}
: cValidator;
const allowed = keyValidator.hasOwnProperty('allowed') ? fn(keyValidator.allowed, data) : true;
if (allowed && keyValidator.hasOwnProperty('default')) {
const value = fn(keyValidator.default, data);
Object.defineProperty(result, key, {
configurable: true,
enumerable: true,
value: runChildValidator(data)
value
});
}
} else if (allowed && keyValidator.required && fn(keyValidator.required, data)) {
missingRequired.push(key);
}
});
})
} else {
data.result = definition;
mapSetResult(data, definition);
}
// report any keys that are not allowed
notAllowed.push.apply(notAllowed, unknownKeys);
if (notAllowed.length) {
notAllowed.sort();
exception.message('Propert' + (notAllowed.length === 1 ? 'y' : 'ies') + ' not allowed: ' + notAllowed.join(', '));
}
// report missing required properties
if (missingRequired.length) {
missingRequired.sort();
exception.message('Missing required propert' + (missingRequired.length === 1 ? 'y' : 'ies') + ': ' + missingRequired.join(', '));
}
} else if (!freeForm) {
switch (definitionType) {
case 'boolean':
case 'null':
case 'number':
case 'string':
data.result = definition;
mapSetResult(data, definition);
break;
default:
exception.message('Unknown data type provided');
break;
}
} else {
data.result = definition;
mapSetResult(data, definition);
}

@@ -256,3 +297,3 @@

// run custom error validation check
if (validator.errors) {
if (!production && validator.errors) {
const d = Object.assign({}, data);

@@ -292,2 +333,19 @@ d.definition = deserialized;

function mapAndSortValidatorProperties (validator, data) {
const properties = Object.keys(validator.properties || {})
.map(key => {
const property = validator.properties[key];
return {
data: childData(data, key, property),
weight: property.weight || 0
}
});
properties.sort((a, b) => {
if (a.weight < b.weight) return -1;
if (a.weight > b.weight) return 1;
return a.data.key < b.data.key ? -1 : 1;
});
return properties;
}
function mapGetResult (data) {

@@ -340,3 +398,3 @@ const { definition, map, validator } = data;

const validator = fn(data.validator, data);
if (validator.type && definition !== undefined) {
if (!data.production && validator.type && definition !== undefined) {
// get valid types

@@ -343,0 +401,0 @@ let matches = fn(validator.type, data);

@@ -20,2 +20,3 @@ /**

const Exception = require('../exception');
const NewRefParser = require('../ref-parser');
const Result = require('../result');

@@ -242,2 +243,4 @@ const runDeserialize = require('../schema/deserialize');

if (major === 3 && refParser && discriminator && discriminator.mapping) {
const useNewRefParser = refParser instanceof NewRefParser;
const schemaDef = data.definition;
plugins.push(() => {

@@ -247,6 +250,15 @@ const instanceMap = this.enforcerData.defToInstanceMap;

const value = discriminator.mapping[key];
const ref = rxHttp.test(value) || value.indexOf('/') !== -1
? value
: '#/components/schemas/' + value;
const definition = refParser.$refs.get(ref);
let definition;
if (useNewRefParser) {
const ref = rxHttp.test(value) || value.indexOf('/') !== -1
? value
: '#/components/schemas/' + value;
const sourceNode = refParser.getSourceNode(schemaDef);
definition = refParser.resolvePath(sourceNode, ref);
} else {
const ref = rxHttp.test(value) || value.indexOf('/') !== -1
? value
: '#/components/schemas/' + value;
definition = refParser.$refs.get(ref);
}
setProperty(discriminator.mapping, key, instanceMap.get(definition));

@@ -478,9 +490,24 @@ });

let schema;
try {
const ref = rxHttp.test(result) || result.indexOf('/') !== -1
? result
: '#/components/schemas/' + result;
schema = refParser.$refs.get(ref)
} catch (err) {
exception.message('Reference cannot be resolved: ' + result);
if (refParser instanceof NewRefParser) {
try {
const ref = rxHttp.test(result) || result.indexOf('/') !== -1
? result
: '#/components/schemas/' + result;
const sourceNode = refParser.getSourceNode(parent.definition);
schema = refParser.resolvePath(sourceNode, ref);
} catch (err) {
exception.message('Reference cannot be resolved: ' + result);
}
} else {
try {
const ref = rxHttp.test(result) || result.indexOf('/') !== -1
? result
: '#/components/schemas/' + result;
schema = refParser.$refs.get(ref)
} catch (err) {
const extra = '. If you are using multiple files to define your OpenAPI document then this ' +
'may be a limitation of the original dereference function. You can try the ' +
'custom reference parser (in beta) to see if this resolves the issue.';
exception.message('Reference cannot be resolved: ' + result + extra);
}
}

@@ -487,0 +514,0 @@

@@ -79,4 +79,5 @@ /**

function build (result, definition, refParser, options) {
function build (result, definition, refParser, options = {}) {
const isStart = !definitionValidator.isValidatorState(definition);
const needsValidation = true;

@@ -90,2 +91,3 @@ // normalize options

options.apiSuggestions = options.hasOwnProperty('apiSuggestions') ? !!options.apiSuggestions : true;
options.production = !!options.production;
options.exceptionSkipCodes = options.hasOwnProperty('exceptionSkipCodes')

@@ -122,2 +124,3 @@ ? options.exceptionSkipCodes.reduce((p, c) => {

plugins: [],
production: options.production,
refParser,

@@ -151,2 +154,3 @@ result,

if (util.isPlainObject(data.definition)) {
if (!needsValidation) data.validator = true;
definitionValidator(data);

@@ -153,0 +157,0 @@ } else {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc