fix id field in validate and sanitize

This commit is contained in:
Ben Irvin 2023-08-17 10:35:41 +02:00
parent 85e32e9649
commit 5988f1af8a
3 changed files with 26 additions and 71 deletions

View File

@ -41,7 +41,13 @@ const defaultSanitizeFilters = curry((schema: Model, filters: unknown) => {
({ key, attribute }, { remove }) => {
const isAttribute = !!attribute;
if (!isAttribute && !isOperator(key) && key !== 'id') {
// ID is not an attribute per se, so we need to make
// an extra check to ensure we're not checking it
if (key === 'id') {
return;
}
if (!isAttribute && !isOperator(key)) {
remove(key);
}
},
@ -73,7 +79,7 @@ const defaultSanitizeSort = curry((schema: Model, sort: unknown) => {
traverseQuerySort(
({ key, attribute }, { remove }) => {
// ID is not an attribute per se, so we need to make
// an extra check to ensure we're not removing it
// an extra check to ensure we're not checking it
if (key === 'id') {
return;
}
@ -109,6 +115,11 @@ const defaultSanitizeFields = curry((schema: Model, fields: unknown) => {
// Only keep scalar attributes
traverseQueryFields(
({ key, attribute }, { remove }) => {
// ID is not an attribute per se, so we need to make
// an extra check to ensure we're not checking it
if (key === 'id') {
return;
}
if (isNil(attribute) || !isScalarAttribute(attribute)) {
remove(key);
}

View File

@ -12,7 +12,7 @@ import traversals from '../traverse/traversals';
import { Model } from '../types';
const { traverseQueryFilters, traverseQuerySort, traverseQueryPopulate } = traversals;
const { traverseQueryFilters, traverseQuerySort } = traversals;
export interface Options {
auth?: unknown;
@ -80,7 +80,7 @@ const createContentAPIValidators = () => {
return;
}
const transforms = [validators.defaultSanitizeFilters(schema)];
const transforms = [validators.defaultValidateFilters(schema)];
if (auth) {
transforms.push(traverseQueryFilters(visitors.throwRestrictedRelations(auth), { schema }));
@ -90,7 +90,7 @@ const createContentAPIValidators = () => {
};
const validateSort: ValidateFunc = async (sort, schema: Model, { auth } = {}) => {
const transforms = [validators.defaultSanitizeSort(schema)];
const transforms = [validators.defaultValidateSort(schema)];
if (auth) {
transforms.push(traverseQuerySort(visitors.throwRestrictedRelations(auth), { schema }));
@ -100,28 +100,17 @@ const createContentAPIValidators = () => {
};
const validateFields: ValidateFunc = (fields, schema: Model) => {
const transforms = [validators.defaultSanitizeFields(schema)];
const transforms = [validators.defaultValidateFields(schema)];
return pipeAsync(...transforms)(fields);
};
const validatePopulate: ValidateFunc = async (populate, schema: Model, { auth } = {}) => {
const transforms = [validators.defaultSanitizePopulate(schema)];
if (auth) {
transforms.push(traverseQueryPopulate(visitors.throwRestrictedRelations(auth), { schema }));
}
return pipeAsync(...transforms)(populate);
};
return {
input: validateInput,
query: validateQuery,
filters: validateFilters,
sort: validateSort,
fields: validateFields,
populate: validatePopulate,
};
};

View File

@ -12,25 +12,13 @@ import { isOperator } from '../operators';
import type { Model } from '../types';
import { ValidationError } from '../errors';
const { traverseQueryFilters, traverseQuerySort, traverseQueryPopulate, traverseQueryFields } =
traversals;
const { traverseQueryFilters, traverseQuerySort, traverseQueryFields } = traversals;
const throwPasswords = (schema: Model) => async (entity: Data) => {
return traverseEntity(throwPassword, { schema }, entity);
};
const defaultSanitizeOutput = async (schema: Model, entity: Data) => {
return traverseEntity(
(...args) => {
throwPassword(...args);
throwPrivate(...args);
},
{ schema },
entity
);
};
const defaultSanitizeFilters = curry((schema: Model, filters: unknown) => {
const defaultValidateFilters = curry((schema: Model, filters: unknown) => {
return pipeAsync(
// Remove keys that are not attributes or valid operators
traverseQueryFilters(
@ -63,7 +51,7 @@ const defaultSanitizeFilters = curry((schema: Model, filters: unknown) => {
)(filters);
});
const defaultSanitizeSort = curry((schema: Model, sort: unknown) => {
const defaultValidateSort = curry((schema: Model, sort: unknown) => {
return pipeAsync(
// Remove non attribute keys
traverseQuerySort(
@ -100,11 +88,14 @@ const defaultSanitizeSort = curry((schema: Model, sort: unknown) => {
)(sort);
});
const defaultSanitizeFields = curry((schema: Model, fields: unknown) => {
const defaultValidateFields = curry((schema: Model, fields: unknown) => {
return pipeAsync(
// Only keep scalar attributes
traverseQueryFields(
({ key, attribute }) => {
if (key === 'id') {
return;
}
if (isNil(attribute) || !isScalarAttribute(attribute)) {
throw new ValidationError(`invalid key ${key}`);
}
@ -114,44 +105,8 @@ const defaultSanitizeFields = curry((schema: Model, fields: unknown) => {
// Remove private fields
traverseQueryFields(throwPrivate, { schema }),
// Remove password fields
traverseQueryFields(throwPassword, { schema }),
// Remove nil values from fields array
(value) => (isArray(value) ? value.filter((field) => !isNil(field)) : value)
traverseQueryFields(throwPassword, { schema })
)(fields);
});
const defaultSanitizePopulate = curry((schema: Model, populate: unknown) => {
return pipeAsync(
traverseQueryPopulate(
async ({ key, value, schema, attribute }, { set }) => {
if (attribute) {
return;
}
if (key === 'sort') {
set(key, await defaultSanitizeSort(schema, value));
}
if (key === 'filters') {
set(key, await defaultSanitizeFilters(schema, value));
}
if (key === 'fields') {
set(key, await defaultSanitizeFields(schema, value));
}
},
{ schema }
),
// Remove private fields
traverseQueryPopulate(throwPrivate, { schema })
)(populate);
});
export {
throwPasswords,
defaultSanitizeOutput,
defaultSanitizeFilters,
defaultSanitizeSort,
defaultSanitizeFields,
defaultSanitizePopulate,
};
export { throwPasswords, defaultValidateFilters, defaultValidateSort, defaultValidateFields };