Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LOC-524 Make Plugin More Secure With Configurable Populate Max Depth Parameter #39

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
## Quick Installation

```
npx @localazy/strapi-plugin
npm install @localazy/strapi-plugin@latest && npx @localazy/strapi-plugin
```

## The Official Strapi Localization Plugin by Localazy
Expand All @@ -22,11 +22,28 @@ The plugin is available on [NPM](https://www.npmjs.com/package/@localazy/strapi-
You can also follow the installation commands located in your Strapi project Marketplace or [Strapi Marketplace > Localazy](https://market.strapi.io/plugins/@localazy-strapi-plugin) itself. This is the recommended approach.

```
npx @localazy/strapi-plugin
npm install @localazy/strapi-plugin@latest && npx @localazy/strapi-plugin
```

Note: Localazy plugin requires an updated Webpack configuration of your Strapi project. Follow the instructions in the console output during the installation process. Steps are also available in the [Install plugin via NPM](https://localazy.com/docs/strapi/strapi-plugin-introduction-installation#install-plugin-via-npm) section of the Localazy Docs.

## Configuration

Additional configuration object may be provided in the `plugins.js` file. The following options are available:

```js
localazy: {
config: {
/**
* both options may help guard against DoS attacks
* if `populateMaxDepth` < 5; the Localazy Strapi Plugin may not work as expected
*/
populateDefaultDepth?: number, // default is 5
populateMaxDepth?: number, // default is 10
},
},
```

## Additional Resources

- Localazy Docs: [Introduction to Strapi](https://localazy.com/docs/strapi/strapi-plugin-introduction-installation)
Expand Down
4 changes: 2 additions & 2 deletions admin/src/modules/localazy-download/locale/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ export default {
ui_languages: "Select languages to download",
ui_languages_info: "Select translations of which languages wil be downloaded from Localazy",
ui_languages_placeholder: "Download all languages",
download_in_progress: "Download in progress...",
to_see_to_progress: "To see the progress information, do not leave this page.",
download_in_progress: "Download in progress: Please do not close or refresh this page if you wish to see the progress information.",
to_see_to_progress: "The operation will continue running in the background even if you close the page, but you will lose access to the status report.",
};
4 changes: 2 additions & 2 deletions admin/src/modules/localazy-upload/locale/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ export default {
upload_success: "Content successfully imported to the Localazy project.",
upload_failed:
"Upload partially failed, please check the report for details...",
upload_in_progress: "Upload in progress...",
to_see_to_progress: "To see the progress information, do not leave this page.",
upload_in_progress: "Upload in progress: Please do not close or refresh this page if you wish to see the progress information.",
to_see_to_progress: "The operation will continue running in the background even if you close the page, but you will lose access to the status report.",
};
7 changes: 4 additions & 3 deletions server/lifecycles/deep-populate-hook.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
const getFullPopulateObject = require('../utils/get-full-populate-object');
const { getFullPopulateObject, DEFAULT_POPULATE_DEPTH } = require('../utils/get-full-populate-object');

module.exports = (event) => {
const populate = event.params?.populate;

if (populate && populate[0] === 'deep') {
const depth = populate[1] ?? 5
const populateDefaultDepth = strapi.plugin("localazy")?.config('populateDefaultDepth') ?? DEFAULT_POPULATE_DEPTH;
const depth = populate[1] ?? populateDefaultDepth;
const modelObject = getFullPopulateObject(event.model.uid, depth);
event.params.populate = modelObject.populate
event.params.populate = modelObject.populate;
}
}
22 changes: 16 additions & 6 deletions server/utils/get-full-populate-object.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

const isEmpty = require("lodash/isEmpty");
const merge = require("lodash/merge");
const DEFAULT_MAX_POPULATE_DEPTH = 10;
const DEFAULT_POPULATE_DEPTH = 5;

const getModelPopulationAttributes = (model) => {
if (model.uid === "plugin::upload.file") {
Expand All @@ -15,13 +17,18 @@ const getModelPopulationAttributes = (model) => {
return model.attributes;
};

const getFullPopulateObject = (modelUid, maxDepth = 20) => {
if (maxDepth <= 1) {
const getFullPopulateObject = (modelUid, depth = DEFAULT_POPULATE_DEPTH) => {
let localDepth = depth;
if (localDepth <= 1) {
return true;
}
if (modelUid === "admin::user") {
return undefined;
}
const populateMaxDepth = strapi.plugin("localazy")?.config("populateMaxDepth") ?? DEFAULT_MAX_POPULATE_DEPTH;
if (Number.isInteger(populateMaxDepth) && localDepth > populateMaxDepth) {
localDepth = populateMaxDepth;
}

const populate = {};
const model = strapi.getModel(modelUid);
Expand All @@ -30,17 +37,17 @@ const getFullPopulateObject = (modelUid, maxDepth = 20) => {
)) {
if (value) {
if (value.type === "component") {
populate[key] = getFullPopulateObject(value.component, maxDepth - 1);
populate[key] = getFullPopulateObject(value.component, localDepth - 1);
} else if (value.type === "dynamiczone") {
const dynamicPopulate = value.components.reduce((prev, cur) => {
const curPopulate = getFullPopulateObject(cur, maxDepth - 1);
const curPopulate = getFullPopulateObject(cur, localDepth - 1);
return curPopulate === true ? prev : merge(prev, curPopulate);
}, {});
populate[key] = isEmpty(dynamicPopulate) ? true : dynamicPopulate;
} else if (value.type === "relation") {
const relationPopulate = getFullPopulateObject(
value.target,
maxDepth - 1
localDepth - 1
);
if (relationPopulate) {
populate[key] = relationPopulate;
Expand All @@ -53,4 +60,7 @@ const getFullPopulateObject = (modelUid, maxDepth = 20) => {
return isEmpty(populate) ? true : { populate };
};

module.exports = getFullPopulateObject;
module.exports = {
getFullPopulateObject,
DEFAULT_POPULATE_DEPTH
};
Loading