Skip to content

Commit

Permalink
Merge pull request #562 from m1212e/clear
Browse files Browse the repository at this point in the history
✨ feat: add option for body cleaning
  • Loading branch information
SaltyAom committed Mar 25, 2024
2 parents fbd2022 + b156586 commit 433a224
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 10 deletions.
6 changes: 5 additions & 1 deletion src/compose.ts
Expand Up @@ -159,7 +159,8 @@ const composeValidationFactory = (
: `return new ValidationError('response', response[c.set.status], ${name}).toResponse(c.set.headers)`

return `\n${injectResponse}
response[c.set.status]?.Clean(${name})
response[${name}[ELYSIA_RESPONSE]]?.Clean(${name}.response)
if(typeof ${name} === "object" && ELYSIA_RESPONSE in ${name}) {
if(!(${name} instanceof Response) && response[${name}[ELYSIA_RESPONSE]]?.Check(${name}.response) === false) {
if(!(response instanceof Error)) {
Expand Down Expand Up @@ -328,6 +329,7 @@ export const composeHandler = ({
validator,
handler,
allowMeta = false,
enableCleaning = false,
appInference: { event: eventInference, trace: traceInference }
}: {
app: Elysia<any, any, any, any, any, any, any, any>
Expand All @@ -338,6 +340,7 @@ export const composeHandler = ({
validator: SchemaValidator
handler: unknown | Handler<any, any>
allowMeta?: boolean
enableCleaning?: boolean,
appInference: {
event: Sucrose.Inference
trace: Sucrose.TraceInference
Expand Down Expand Up @@ -914,6 +917,7 @@ export const composeHandler = ({
}

if (validator.body) {
fnLiteral += "body.Clean(c.body);\n"
// @ts-ignore
if (hasProperty('default', validator.body.schema))
fnLiteral += `if(body.Check(c.body) === false) {
Expand Down
15 changes: 11 additions & 4 deletions src/index.ts
Expand Up @@ -406,14 +406,17 @@ export default class Elysia<
})
: undefined

const enableCleaning = this.config.enableCleaning;

const validator =
this.config.precompile === true ||
(typeof this.config.precompile === 'object' &&
this.config.precompile.schema === true)
? {
body: getSchemaValidator(cloned.body, {
dynamic,
models
models,
enableCleaning
}),
headers: getSchemaValidator(cloned.headers, {
dynamic,
Expand All @@ -431,7 +434,8 @@ export default class Elysia<
cookie: cookieValidator(),
response: getResponseSchemaValidator(cloned.response, {
dynamic,
models
models,
enableCleaning
})
}
: ({
Expand All @@ -440,7 +444,8 @@ export default class Elysia<

return (_body = getSchemaValidator(cloned.body, {
dynamic,
models
models,
enableCleaning
}))
},
get headers() {
Expand Down Expand Up @@ -483,7 +488,8 @@ export default class Elysia<
cloned.response,
{
dynamic,
models
models,
enableCleaning
}
))
}
Expand Down Expand Up @@ -546,6 +552,7 @@ export default class Elysia<
hooks,
validator,
handler: handle,
enableCleaning: this.config.enableCleaning,
allowMeta,
appInference: {
event: {
Expand Down
9 changes: 9 additions & 0 deletions src/types.ts
Expand Up @@ -102,6 +102,15 @@ export type ElysiaConfig<
* Enable experimental features
*/
experimental?: {}
/**
* If enabled, the handlers will run a [clean](https://github.com/sinclairzx81/typebox?tab=readme-ov-file#clean) on incoming and outgoing bodies instead of failing directly.
* This allows for sending unknown or disallowed properties in the bodies. These will simply be filtered out instead of failing the request.
* This has no effect when the schemas allow additional properties.
* Since this uses dynamic schema it may have an impact on performance. Use with caution.
*
* @default false
*/
enableCleaning?: boolean
}

export type MaybeArray<T> = T | T[]
Expand Down
32 changes: 27 additions & 5 deletions src/utils.ts
Expand Up @@ -238,11 +238,13 @@ export const getSchemaValidator = (
{
models = {},
additionalProperties = false,
dynamic = false
dynamic = false,
enableCleaning = false
}: {
models?: Record<string, TSchema>
additionalProperties?: boolean
dynamic?: boolean
enableCleaning?: boolean
}
) => {
if (!s) return
Expand All @@ -254,6 +256,12 @@ export const getSchemaValidator = (
if (schema.type === 'object' && 'additionalProperties' in schema === false)
schema.additionalProperties = additionalProperties

const cleaner = (value: unknown) => {
if (enableCleaning && schema.additionalProperties === false) {
Value.Clean(schema, value)
}
}

if (dynamic) {
const validator = {
schema,
Expand All @@ -262,7 +270,8 @@ export const getSchemaValidator = (
code: '',
Check: (value: unknown) => Value.Check(schema, value),
Errors: (value: unknown) => Value.Errors(schema, value),
Code: () => ''
Code: () => '',
Clean: cleaner
} as unknown as TypeCheck<TSchema>

// @ts-ignore
Expand All @@ -280,6 +289,8 @@ export const getSchemaValidator = (
}

const compiled = TypeCompiler.Compile(schema, Object.values(models))

compiled.Clean = cleaner

// @ts-ignore
if (schema.config) {
Expand All @@ -300,11 +311,13 @@ export const getResponseSchemaValidator = (
{
models = {},
additionalProperties = false,
dynamic = false
dynamic = false,
enableCleaning = false
}: {
models?: Record<string, TSchema>
additionalProperties?: boolean
dynamic?: boolean
enableCleaning?: boolean
}
): Record<number, TypeCheck<any>> | undefined => {
if (!s) return
Expand All @@ -313,6 +326,12 @@ export const getResponseSchemaValidator = (
const maybeSchemaOrRecord = typeof s === 'string' ? models[s] : s

const compile = (schema: TSchema, references?: TSchema[]) => {
const cleaner = (value: unknown) => {
if (enableCleaning && schema.additionalProperties === false) {
Value.Clean(schema, value)
}
}

if (dynamic)
return {
schema,
Expand All @@ -321,10 +340,13 @@ export const getResponseSchemaValidator = (
code: '',
Check: (value: unknown) => Value.Check(schema, value),
Errors: (value: unknown) => Value.Errors(schema, value),
Code: () => ''
Code: () => '',
Clean: cleaner
} as unknown as TypeCheck<TSchema>

return TypeCompiler.Compile(schema, references)
const compiledValidator = TypeCompiler.Compile(schema, references)
;(compiledValidator as any).Clean = cleaner
return compiledValidator
}

if (Kind in maybeSchemaOrRecord) {
Expand Down

0 comments on commit 433a224

Please sign in to comment.