Skip to content

Commit

Permalink
fixed lint
Browse files Browse the repository at this point in the history
fixed coverage

added test cases

fixed lint

fixed test
  • Loading branch information
Shivanshu-07 committed Feb 14, 2025
1 parent 7417f54 commit d833c07
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 28 deletions.
28 changes: 1 addition & 27 deletions packages/config/src/defaults.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { merge } from './utils/index.js';
import { merge, sanitizeObject } from './utils/index.js';
import { getSchema } from './validate.js';

const { isArray } = Array;
Expand All @@ -16,9 +16,6 @@ function getDefaultsFromSchema(schema) {
} else if (schema.type === 'object' && schema.properties) {
// return an object of default properties
return entries(schema.properties).reduce((acc, [prop, schema]) => {
if(!isSafeKey(prop)){
return acc;
}
let def = getDefaultsFromSchema(schema);
return def != null ? assign(acc || {}, { [prop]: def }) : acc;
}, undefined);
Expand All @@ -27,29 +24,6 @@ function getDefaultsFromSchema(schema) {
}
}

// Utility function to prevent prototype pollution
function isSafeKey(key) {
const unsafeKeys = ['__proto__', 'constructor', 'prototype', 'toString', 'valueOf',
'__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__'];
return !unsafeKeys.includes(key);
}


function sanitizeObject(obj) {
if (!obj || typeof obj !== 'object' || isArray(obj)) {
return obj;
}

const sanitized = {};
for (const key in obj) {
if (isSafeKey(key)) {
sanitized[key] = sanitizeObject(obj[key]);
}
}

return sanitized;
}

export function getDefaults(overrides = {}) {
const sanitizedOverrides = sanitizeObject(overrides);
return merge([getDefaultsFromSchema(), sanitizedOverrides], (path, prev, next) => {
Expand Down
23 changes: 23 additions & 0 deletions packages/config/src/utils/normalize.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import merge from './merge.js';
import { getSchema } from '../validate.js';

const { isArray } = Array;

// Edge case camelizations
const CAMELCASE_MAP = new Map([
['css', 'CSS'],
Expand Down Expand Up @@ -66,4 +68,25 @@ export function normalize(object, options) {
});
}

// Utility function to prevent prototype pollution
export function isSafeKey(key) {
const unsafeKeys = ['__proto__', 'constructor', 'prototype', 'toString', 'valueOf',
'__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__'];
return !unsafeKeys.includes(key);
}

export function sanitizeObject(obj) {
if (!obj || typeof obj !== 'object' || isArray(obj)) {
return obj;
}
const sanitized = {};
for (const key in obj) {
if (isSafeKey(key)) {
sanitized[key] = sanitizeObject(obj[key]);
}
}

return sanitized;
}

export default normalize;
22 changes: 21 additions & 1 deletion packages/config/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,15 +195,35 @@ describe('PercyConfig', () => {
const pollutedKey = 'pollutedKey';
const overrides = JSON.parse('{"__proto__":{"pollutedKey":123}}');
const result = PercyConfig.getDefaults(overrides);
expect(result).not.toHaveProperty(pollutedKey);
expect({}).not.toHaveProperty(pollutedKey);
expect(result).toEqual({
version: 2,
test: { value: 'foo' }
});
});

it('does not allow prototype pollution via __proto__ for nested key', () => {
const pollutedKey = 'pollutedKey';
const overrides = JSON.parse('{"pollutedKey":{"__proto__":123}}');
const result = PercyConfig.getDefaults(overrides);
expect(result).not.toHaveProperty(pollutedKey);
expect({}).not.toHaveProperty(pollutedKey);

expect(result).toEqual({
version: 2,
test: { value: 'foo' }
});
});

it('does allow safe key', () => {
const overrides = JSON.parse('{"key":{"key1":123}}');
const result = PercyConfig.getDefaults(overrides);
expect(result).toEqual({
version: 2,
test: { value: 'foo' },
key: { key1: 123 }
});
});
});

describe('.validate()', () => {
Expand Down

0 comments on commit d833c07

Please sign in to comment.