Skip to content

Commit

Permalink
fix: Use objectKeys to prevent prototype pollution
Browse files Browse the repository at this point in the history
  • Loading branch information
Romakita committed Oct 18, 2020
1 parent 6f307a5 commit 1395773
Show file tree
Hide file tree
Showing 9 changed files with 28 additions and 31 deletions.
3 changes: 2 additions & 1 deletion packages/common/src/converters/components/MapConverter.ts
@@ -1,3 +1,4 @@
import {objectKeys} from "@tsed/core";
import {Converter} from "../decorators/converter";
import {IConverter, IDeserializer, ISerializer} from "../interfaces/index";

Expand All @@ -19,7 +20,7 @@ export class MapConverter implements IConverter {
deserialize<T>(data: any, target: any, baseType: T, deserializer: IDeserializer): Map<string, T> {
const obj = new Map<string, T>();

Object.keys(data).forEach((key) => {
objectKeys(data).forEach((key) => {
obj.set(key, deserializer(data[key], baseType) as T);
});

Expand Down
3 changes: 2 additions & 1 deletion packages/common/src/converters/components/SetConverter.ts
@@ -1,3 +1,4 @@
import {objectKeys} from "@tsed/core";
import {Converter} from "../decorators/converter";
import {IConverter, IDeserializer, ISerializer} from "../interfaces/index";

Expand All @@ -19,7 +20,7 @@ export class SetConverter implements IConverter {
deserialize<T>(data: any, target: any, baseType: T, deserializer: IDeserializer): Set<T> {
const obj = new Set<T>();

Object.keys(data).forEach((key) => {
objectKeys(data).forEach((key) => {
obj.add(deserializer(data[key], baseType) as T);
});

Expand Down
6 changes: 3 additions & 3 deletions packages/common/src/converters/services/ConverterService.ts
@@ -1,4 +1,4 @@
import {getClass, isArrayOrArrayClass, isEmpty, isPrimitiveOrPrimitiveClass, Metadata, Type} from "@tsed/core";
import {getClass, isArrayOrArrayClass, isEmpty, isPrimitiveOrPrimitiveClass, Metadata, objectKeys, Type} from "@tsed/core";
import {Configuration, Injectable, InjectorService} from "@tsed/di";
import {IConverterSettings} from "../../config/interfaces/IConverterSettings";
import {PropertyMetadata} from "../../mvc/models/PropertyMetadata";
Expand Down Expand Up @@ -101,7 +101,7 @@ export class ConverterService {

const plainObject: any = {};
const properties = PropertyMetadata.getProperties(options.type || obj, {withIgnoredProps});
const keys = properties.size ? Array.from(properties.keys()) : Object.keys(obj);
const keys = properties.size ? Array.from(properties.keys()) : objectKeys(obj);

keys.forEach((propertyKey) => {
if (typeof obj[propertyKey] !== "function") {
Expand Down Expand Up @@ -179,7 +179,7 @@ export class ConverterService {
const instance = new targetType();
const properties = PropertyMetadata.getProperties(targetType);

Object.keys(obj).forEach((propertyName: string) => {
objectKeys(obj).forEach((propertyName: string) => {
const propertyMetadata = ConverterService.getPropertyMetadata(properties, propertyName);

return this.convertProperty(obj, instance, propertyName, propertyMetadata, options);
Expand Down
24 changes: 13 additions & 11 deletions packages/core/src/utils/cleanObject.ts
@@ -1,17 +1,19 @@
import {isProtectedKey} from "./isProtectedKey";
/**
* Remove undefined value
* @param obj
*/

export function cleanObject(obj: any): any {
return Object.entries(obj).reduce(
(obj, [key, value]) =>
value === undefined
? obj
: {
...obj,
[key]: value
},
{}
);
return Object.entries(obj).reduce((obj, [key, value]) => {
if (isProtectedKey(key)) {
return obj;
}

return value === undefined
? obj
: {
...obj,
[key]: value
};
}, {});
}
3 changes: 2 additions & 1 deletion packages/json-mapper/src/components/MapMapper.ts
@@ -1,3 +1,4 @@
import {objectKeys} from "@tsed/core";
import {JsonMapper} from "../decorators/jsonMapper";
import {JsonMapperCtx, JsonMapperMethods} from "../interfaces/JsonMapperMethods";

Expand All @@ -12,7 +13,7 @@ export class MapMapper implements JsonMapperMethods {
deserialize<T = any, C = Map<string, T>>(data: {[key: string]: any}, ctx: JsonMapperCtx<T, C>): Map<string, T> {
const obj = new Map<string, T>();

Object.keys(data).forEach((key) => {
objectKeys(data).forEach((key) => {
obj.set(key, ctx.next(data[key]) as T);
});

Expand Down
3 changes: 2 additions & 1 deletion packages/json-mapper/src/components/SetMapper.ts
@@ -1,3 +1,4 @@
import {objectKeys} from "@tsed/core";
import {JsonMapper} from "../decorators/jsonMapper";
import {JsonMapperCtx, JsonMapperMethods} from "../interfaces/JsonMapperMethods";

Expand All @@ -12,7 +13,7 @@ export class SetMapper implements JsonMapperMethods {
deserialize<T>(data: any, ctx: JsonMapperCtx): Set<T> {
const obj = new Set<T>();

Object.keys(data).forEach((key) => {
objectKeys(data).forEach((key) => {
obj.add(ctx.next(data[key]));
});

Expand Down
4 changes: 2 additions & 2 deletions packages/json-mapper/src/utils/deserialize.ts
@@ -1,4 +1,4 @@
import {isArray, isEmpty, isNil, MetadataTypes, nameOf, Type} from "@tsed/core";
import {isArray, isEmpty, isNil, MetadataTypes, nameOf, objectKeys, Type} from "@tsed/core";
import {getPropertiesStores, JsonEntityStore, JsonHookContext, JsonSchema} from "@tsed/schema";
import "../components";
import {JsonMapperContext} from "../domain/JsonMapperContext";
Expand Down Expand Up @@ -77,7 +77,7 @@ export function plainObjectToClass<T = any>(src: any, options: JsonDeserializerO
const {type, store = JsonEntityStore.from(type), ...next} = options;
const propertiesMap = getPropertiesStores(store);

let keys = Object.keys(src);
let keys = objectKeys(src);
const additionalProperties = propertiesMap.size ? !!store.schema.get("additionalProperties") || options.additionalProperties : true;
const out: any = new type(src);

Expand Down
8 changes: 0 additions & 8 deletions packages/mongoose/src/utils/cleanProps.ts

This file was deleted.

5 changes: 2 additions & 3 deletions packages/mongoose/src/utils/createSchema.ts
@@ -1,10 +1,9 @@
import {ConverterService, IConverterOptions, JsonSchema, PropertyMetadata} from "@tsed/common";
import {getClass, Store, Type} from "@tsed/core";
import {cleanObject, getClass, Store, Type} from "@tsed/core";
import * as mongoose from "mongoose";
import {SchemaDefinition, SchemaTypeOpts} from "mongoose";
import {MONGOOSE_SCHEMA} from "../constants";
import {MongooseSchemaOptions} from "../interfaces";
import {cleanProps} from "./cleanProps";
import {schemaOptions} from "./schemaOptions";

const MONGOOSE_RESERVED_KEYS = ["_id"];
Expand Down Expand Up @@ -132,7 +131,7 @@ export function createSchemaTypeOptions(propertyMetadata: PropertyMetadata): Sch
schemaTypeOptions = {...schemaTypeOptions, type: getSchema(propertyMetadata.type)};
}

schemaTypeOptions = cleanProps({...schemaTypeOptions, ...rawMongooseSchema});
schemaTypeOptions = cleanObject({...schemaTypeOptions, ...rawMongooseSchema});

if (propertyMetadata.isCollection) {
if (propertyMetadata.isArray) {
Expand Down

0 comments on commit 1395773

Please sign in to comment.