diff --git a/packages/ra-data-local-forage/src/index.ts b/packages/ra-data-local-forage/src/index.ts index 80adc5301c3..275d3092745 100644 --- a/packages/ra-data-local-forage/src/index.ts +++ b/packages/ra-data-local-forage/src/index.ts @@ -166,6 +166,7 @@ export default (params?: LocalForageDataProviderParams): DataProvider => { resource: string, params: UpdateParams ) => { + checkResource(resource); await initialize(); if (!data) { throw new Error('The dataProvider is not initialized.'); @@ -185,6 +186,7 @@ export default (params?: LocalForageDataProviderParams): DataProvider => { return baseDataProvider.update(resource, params); }, updateMany: async (resource: string, params: UpdateManyParams) => { + checkResource(resource); await initialize(); if (!baseDataProvider) { throw new Error('The dataProvider is not initialized.'); @@ -209,6 +211,7 @@ export default (params?: LocalForageDataProviderParams): DataProvider => { resource: string, params: CreateParams ) => { + checkResource(resource); await initialize(); if (!baseDataProvider) { throw new Error('The dataProvider is not initialized.'); @@ -232,6 +235,7 @@ export default (params?: LocalForageDataProviderParams): DataProvider => { resource: string, params: DeleteParams ) => { + checkResource(resource); await initialize(); if (!baseDataProvider) { throw new Error('The dataProvider is not initialized.'); @@ -247,6 +251,7 @@ export default (params?: LocalForageDataProviderParams): DataProvider => { return baseDataProvider.delete(resource, params); }, deleteMany: async (resource: string, params: DeleteManyParams) => { + checkResource(resource); await initialize(); if (!baseDataProvider) { throw new Error('The dataProvider is not initialized.'); @@ -269,6 +274,13 @@ export default (params?: LocalForageDataProviderParams): DataProvider => { }; }; +const checkResource = resource => { + if (['__proto__', 'constructor', 'prototype'].includes(resource)) { + // protection against prototype pollution + throw new Error(`Invalid resource key: ${resource}`); + } +}; + export interface LocalForageDataProviderParams { defaultData?: any; prefixLocalForageKey?: string; diff --git a/packages/ra-data-local-storage/src/index.ts b/packages/ra-data-local-storage/src/index.ts index ff26fce4861..99d23261ccc 100644 --- a/packages/ra-data-local-storage/src/index.ts +++ b/packages/ra-data-local-storage/src/index.ts @@ -98,6 +98,7 @@ export default (params?: LocalStorageDataProviderParams): DataProvider => { // update methods need to persist changes in localStorage update: (resource, params) => { + checkResource(resource); updateLocalStorage(() => { const index = data[resource]?.findIndex( record => record.id == params.id @@ -110,6 +111,7 @@ export default (params?: LocalStorageDataProviderParams): DataProvider => { return baseDataProvider.update(resource, params); }, updateMany: (resource, params) => { + checkResource(resource); updateLocalStorage(() => { params.ids.forEach(id => { const index = data[resource]?.findIndex( @@ -127,6 +129,7 @@ export default (params?: LocalStorageDataProviderParams): DataProvider => { resource, params ) => { + checkResource(resource); // we need to call the fakerest provider first to get the generated id return baseDataProvider .create(resource, params) @@ -141,6 +144,7 @@ export default (params?: LocalStorageDataProviderParams): DataProvider => { }); }, delete: (resource, params) => { + checkResource(resource); updateLocalStorage(() => { const index = data[resource]?.findIndex( record => record.id == params.id @@ -150,6 +154,7 @@ export default (params?: LocalStorageDataProviderParams): DataProvider => { return baseDataProvider.delete(resource, params); }, deleteMany: (resource, params) => { + checkResource(resource); updateLocalStorage(() => { const indexes = params.ids.map(id => data[resource]?.findIndex(record => record.id == id) @@ -161,6 +166,13 @@ export default (params?: LocalStorageDataProviderParams): DataProvider => { }; }; +const checkResource = resource => { + if (['__proto__', 'constructor', 'prototype'].includes(resource)) { + // protection against prototype pollution + throw new Error(`Invalid resource key: ${resource}`); + } +}; + export interface LocalStorageDataProviderParams { defaultData?: any; localStorageKey?: string;