From 42c149e8bc6fc7c081b55bc0f42125bd01c63a6e Mon Sep 17 00:00:00 2001 From: Alexandre Bodin Date: Mon, 27 Apr 2020 20:39:34 +0200 Subject: [PATCH] Add reserved name check Signed-off-by: Alexandre Bodin --- .../strapi-database/lib/constants/index.js | 11 ++++ .../strapi-database/lib/database-manager.js | 15 +++++- .../before-mounting-models/index.js | 5 -- .../check-duplicated-table-names.js | 2 + .../lib/validation/check-reserved-names.js | 54 +++++++++++++++++++ .../strapi-database/lib/validation/index.js | 13 +++++ .../config/routes.json | 4 +- .../controllers/Builder.js | 17 +----- 8 files changed, 97 insertions(+), 24 deletions(-) create mode 100644 packages/strapi-database/lib/constants/index.js delete mode 100644 packages/strapi-database/lib/validation/before-mounting-models/index.js rename packages/strapi-database/lib/validation/{before-mounting-models => }/check-duplicated-table-names.js (99%) create mode 100644 packages/strapi-database/lib/validation/check-reserved-names.js create mode 100644 packages/strapi-database/lib/validation/index.js diff --git a/packages/strapi-database/lib/constants/index.js b/packages/strapi-database/lib/constants/index.js new file mode 100644 index 0000000000..8233401bae --- /dev/null +++ b/packages/strapi-database/lib/constants/index.js @@ -0,0 +1,11 @@ +'use strict'; + +// contentTypes and components reserved names +const RESERVED_MODEL_NAMES = ['admin']; +// attribute reserved names +const RESERVED_ATTRIBUTE_NAMES = ['_id', 'id', 'length', 'attributes', 'relations', 'changed']; + +module.exports = { + RESERVED_MODEL_NAMES, + RESERVED_ATTRIBUTE_NAMES, +}; diff --git a/packages/strapi-database/lib/database-manager.js b/packages/strapi-database/lib/database-manager.js index 596dc5bbda..d315c27cb0 100644 --- a/packages/strapi-database/lib/database-manager.js +++ b/packages/strapi-database/lib/database-manager.js @@ -4,7 +4,8 @@ const _ = require('lodash'); const requireConnector = require('./require-connector'); const { createQuery } = require('./queries'); -const { checkDuplicatedTableNames } = require('./validation/before-mounting-models'); +const constants = require('./constants'); +const { validateModelSchemas } = require('./validation'); class DatabaseManager { constructor(strapi) { @@ -32,7 +33,7 @@ class DatabaseManager { } } - checkDuplicatedTableNames(this.strapi); + validateModelSchemas(this.strapi); for (const connectorToInitialize of connectorsToInitialize) { const connector = requireConnector(connectorToInitialize)(strapi); @@ -135,6 +136,16 @@ class DatabaseManager { return model.globalId === globalId; }); } + + getRestrictedNames() { + return { + model: constants.RESERVED_MODEL_NAMES, + attributes: [ + ...constants.RESERVED_ATTRIBUTE_NAMES, + ...(strapi.db.getDefaultConnector().defaultTimestamps || []), + ], + }; + } } function createDatabaseManager(strapi) { diff --git a/packages/strapi-database/lib/validation/before-mounting-models/index.js b/packages/strapi-database/lib/validation/before-mounting-models/index.js deleted file mode 100644 index 31db79b722..0000000000 --- a/packages/strapi-database/lib/validation/before-mounting-models/index.js +++ /dev/null @@ -1,5 +0,0 @@ -const checkDuplicatedTableNames = require('./check-duplicated-table-names'); - -module.exports = { - checkDuplicatedTableNames, -}; diff --git a/packages/strapi-database/lib/validation/before-mounting-models/check-duplicated-table-names.js b/packages/strapi-database/lib/validation/check-duplicated-table-names.js similarity index 99% rename from packages/strapi-database/lib/validation/before-mounting-models/check-duplicated-table-names.js rename to packages/strapi-database/lib/validation/check-duplicated-table-names.js index 65990c35ab..3c41d282b7 100644 --- a/packages/strapi-database/lib/validation/before-mounting-models/check-duplicated-table-names.js +++ b/packages/strapi-database/lib/validation/check-duplicated-table-names.js @@ -1,3 +1,5 @@ +'use strict'; + const _ = require('lodash'); const createErrorMessage = ( diff --git a/packages/strapi-database/lib/validation/check-reserved-names.js b/packages/strapi-database/lib/validation/check-reserved-names.js new file mode 100644 index 0000000000..d637654117 --- /dev/null +++ b/packages/strapi-database/lib/validation/check-reserved-names.js @@ -0,0 +1,54 @@ +'use strict'; + +const _ = require('lodash'); +const constants = require('../constants'); + +const checkReservedAttributeNames = model => { + const usedReservedAttributeNames = _.intersection( + Object.keys(model.attributes), + constants.RESERVED_ATTRIBUTE_NAMES + ); + + if (usedReservedAttributeNames.length > 0) { + throw new Error( + `Model "${ + model.modelName + }" is using reserved attribute names "${usedReservedAttributeNames.join(', ')}".` + ); + } +}; + +const checkReservedModelName = model => { + if (constants.RESERVED_MODEL_NAMES.includes(model.modelName)) { + throw new Error( + `"${model.modelName}" is a reserved model name. You need to rename your model and the files associated with it` + ); + } +}; + +/** + * Checks that there are no model using reserved names (content type, component, attributes) + */ +module.exports = strapi => { + Object.keys(strapi.api).forEach(apiName => { + const api = strapi.api[apiName]; + + const models = api.models ? Object.values(api.models) : []; + models.forEach(model => { + checkReservedModelName(model); + checkReservedAttributeNames(model); + }); + }); + + Object.keys(strapi.plugins).forEach(pluginName => { + const plugin = strapi.plugins[pluginName]; + + const models = plugin.models ? Object.values(plugin.models) : []; + models.forEach(model => { + checkReservedModelName(model); + checkReservedAttributeNames(model); + }); + }); + + //TODO: check reserved timestamps per connector when model as timestamps enabled +}; diff --git a/packages/strapi-database/lib/validation/index.js b/packages/strapi-database/lib/validation/index.js new file mode 100644 index 0000000000..214b1b2f2d --- /dev/null +++ b/packages/strapi-database/lib/validation/index.js @@ -0,0 +1,13 @@ +'use strict'; + +const checkDuplicatedTableNames = require('./check-duplicated-table-names'); +const checkReservedNames = require('./check-reserved-names'); + +const validateModelSchemas = strapi => { + checkDuplicatedTableNames(strapi); + checkReservedNames(strapi); +}; + +module.exports = { + validateModelSchemas, +}; diff --git a/packages/strapi-plugin-content-type-builder/config/routes.json b/packages/strapi-plugin-content-type-builder/config/routes.json index 2401786196..7a4f35313e 100644 --- a/packages/strapi-plugin-content-type-builder/config/routes.json +++ b/packages/strapi-plugin-content-type-builder/config/routes.json @@ -2,8 +2,8 @@ "routes": [ { "method": "GET", - "path": "/restricted-names", - "handler": "Builder.getRestrictedNames", + "path": "/reserved-names", + "handler": "Builder.getReservedNames", "config": { "policies": [] } diff --git a/packages/strapi-plugin-content-type-builder/controllers/Builder.js b/packages/strapi-plugin-content-type-builder/controllers/Builder.js index 741f8414f5..0a609ff8bc 100644 --- a/packages/strapi-plugin-content-type-builder/controllers/Builder.js +++ b/packages/strapi-plugin-content-type-builder/controllers/Builder.js @@ -1,20 +1,7 @@ 'use strict'; module.exports = { - getRestrictedNames(ctx) { - const defaultConnectionTimestamps = strapi.db.getDefaultConnector().defaultTimestamps || []; - - ctx.body = { - models: ['admin'], // contentTypes and components - attributes: [ - '_id', - 'id', - 'length', - 'attributes', - 'relations', - 'changed', - ...defaultConnectionTimestamps, - ], - }; + getReservedNames(ctx) { + ctx.body = strapi.db.getRestrictedNames(); }, };