Skip to content

Commit 2b9a47a

Browse files
committed
fix: add a check for the property key name #1
When creating a schema, the function needs to check the keys specified by the user so that they are not on the list of forbidden simovolves.
1 parent fa490df commit 2b9a47a

File tree

2 files changed

+60
-10
lines changed

2 files changed

+60
-10
lines changed

src/lib/createSchema.ts

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export function createSchema<SRaw extends RawSchema>(
6262

6363
const store = useHandlerStore()
6464
const _rawSchema = isArray(rawSchema)
65-
? generateRawSchemaByPaths(rawSchema)
65+
? generateRawSchemaByPaths(rawSchema, store)
6666
: (rawSchema as RawSchemaAsObject)
6767

6868
const result = parseSchemaObject(_rawSchema, store)
@@ -161,6 +161,9 @@ const parseSchemaProperty = (
161161
key: PropertyKey,
162162
store: HandlerStore
163163
) => {
164+
const keyError = validateSchemaPropertyKey(key)
165+
if (keyError) return handler.error(store, keyError)
166+
164167
const property = readonlyObject[key]
165168

166169
if (isUndefined(property) || isConstructors(property)) {
@@ -202,7 +205,8 @@ const parseSchemaProperty = (
202205
* @internal
203206
*/
204207
const generateRawSchemaByPaths = (
205-
rawArraySchema: RawSchemaAsArray
208+
rawArraySchema: RawSchemaAsArray,
209+
store: HandlerStore
206210
): RawSchemaAsObject => {
207211
const rawObjectSchema = {}
208212

@@ -211,14 +215,21 @@ const generateRawSchemaByPaths = (
211215
let objectLink = rawObjectSchema
212216

213217
for (let i = 0; i < arrayPath.length; i++) {
214-
const key = arrayPath[i]
215-
const isObj = isObject(objectLink[key])
216-
217-
if (i === arrayPath.length - 1) {
218-
if (!isObj) objectLink[key] = null
219-
} else {
220-
if (!isObj) objectLink[key] = {}
221-
objectLink = objectLink[key]
218+
const propertyKey = arrayPath[i]
219+
const propertyKeyError = validateSchemaPropertyKey(propertyKey)
220+
const isLastProperty = i === arrayPath.length - 1
221+
222+
if (propertyKeyError) {
223+
handler.error(store, propertyKeyError)
224+
break
225+
}
226+
227+
if (!isObject(objectLink[propertyKey])) {
228+
objectLink[propertyKey] = isLastProperty ? null : {}
229+
}
230+
231+
if (!isLastProperty) {
232+
objectLink = objectLink[propertyKey]
222233
}
223234
}
224235
}
@@ -230,10 +241,36 @@ const generateRawSchemaByPaths = (
230241
* Validate the schema object by a circular structure.
231242
*
232243
* @param schema The schema object.
244+
* @returns Object error.
245+
* @internal
233246
*/
234247
const validateSchemaObject = (
235248
schema: RawSchemaAsObject
236249
): ObjectError | undefined => {
237250
if (handler.isHandled(schema))
238251
return createObjectError(`detected a circular structure`)
239252
}
253+
254+
/**
255+
* Validate the name of the schema property key.
256+
*
257+
* When creating a schema, the function needs to check
258+
* the keys specified by the user so that they are not
259+
* on the list of forbidden simovolves.
260+
*
261+
* @param schema The schema object.
262+
* @returns Object error.
263+
* @internal
264+
*/
265+
const validateSchemaPropertyKey = (
266+
propertyKey: PropertyKey
267+
): ObjectError | undefined => {
268+
if (
269+
propertyKey === '__proto__' ||
270+
propertyKey === 'constructor' ||
271+
propertyKey === 'prototype'
272+
)
273+
return createObjectError(
274+
`The property key has a forbidden name: "__proto__", "constructor" or "prototype".`
275+
)
276+
}

test/unit/schema.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ describe('combine schemas', () => {
5151
})
5252

5353
describe('error handling', () => {
54+
const forbiddenNames = ['__proto__', 'prototype', 'constructor']
55+
5456
it('should throw when detect cycle objects', () => {
5557
const obj: any = {}
5658
obj.a1 = obj
@@ -73,4 +75,15 @@ describe('error handling', () => {
7375
expect(() => delete schema['a1']).toThrow()
7476
expect(() => Object.defineProperty(schema, 'b1', { value: {} })).toThrow()
7577
})
78+
79+
it.each(forbiddenNames)(
80+
'should throw when detect forbidden name: %s',
81+
(name: string) => {
82+
expect(() => schemaFn([`${name}`])).toThrow()
83+
expect(() => schemaFn([`a1.${name}`])).toThrow()
84+
expect(() => schemaFn([`a1.${name}.b2`])).toThrow()
85+
expect(() => schemaFn({ [name]: null })).toThrow()
86+
expect(() => schemaFn({ a1: { [name]: null } })).toThrow()
87+
}
88+
)
7689
})

0 commit comments

Comments
 (0)