Add validation & required check

This commit is contained in:
Alexandre Bodin 2021-09-28 11:43:49 +02:00
parent c610e34c7f
commit f8695e615e
3 changed files with 116 additions and 134 deletions

View File

@ -28,120 +28,3 @@ module.exports = {
favicon,
public: publicStatic,
};
// const requiredMiddlewares = [
// 'auth',
// 'responses',
// 'router',
// 'logger',
// 'error',
// 'cors',
// 'cron',
// 'xframe',
// 'xss',
// 'public',
// 'favicon',
// ];
// module.exports = async function(strapi) {
// /** Utils */
// const middlewareConfig = strapi.config.middleware;
// // check if a middleware exists
// const middlewareExists = key => {
// return !isUndefined(strapi.middleware[key]);
// };
// // check if a middleware is enabled
// const middlewareEnabled = key => {
// return (
// requiredMiddlewares.includes(key) ||
// get(middlewareConfig, ['settings', key, 'enabled'], false) === true
// );
// };
// // list of enabled middlewares
// const enabledMiddlewares = Object.keys(strapi.middleware).filter(middlewareEnabled);
// // Method to initialize middlewares and emit an event.
// const initialize = middlewareKey => {
// if (strapi.middleware[middlewareKey].loaded === true) return;
// const module = strapi.middleware[middlewareKey].load;
// return new Promise((resolve, reject) => {
// const timeout = setTimeout(
// () => reject(`(middleware: ${middlewareKey}) is taking too long to load.`),
// middlewareConfig.timeout || 1000
// );
// strapi.middleware[middlewareKey] = merge(strapi.middleware[middlewareKey], module);
// Promise.resolve()
// .then(() => module.initialize(strapi))
// .then(() => {
// clearTimeout(timeout);
// strapi.middleware[middlewareKey].loaded = true;
// resolve();
// })
// .catch(err => {
// clearTimeout(timeout);
// if (err) {
// return reject(err);
// }
// });
// });
// };
// /**
// * Run init functions
// */
// // Run beforeInitialize of every middleware
// await Promise.all(
// enabledMiddlewares.map(key => {
// const { beforeInitialize } = strapi.middleware[key].load;
// if (typeof beforeInitialize === 'function') {
// return beforeInitialize(strapi);
// }
// })
// );
// // run the initialization of an array of middlewares sequentially
// const initMiddlewaresSeq = async middlewareArr => {
// for (let key of uniq(middlewareArr)) {
// await initialize(key);
// }
// };
// const middlewaresBefore = get(middlewareConfig, 'load.before', [])
// .filter(middlewareExists)
// .filter(middlewareEnabled);
// const middlewaresAfter = get(middlewareConfig, 'load.after', [])
// .filter(middlewareExists)
// .filter(middlewareEnabled);
// const middlewaresOrder = get(middlewareConfig, 'load.order', [])
// .filter(middlewareExists)
// .filter(middlewareEnabled);
// const unspecifiedMiddlewares = difference(
// enabledMiddlewares,
// middlewaresBefore,
// middlewaresOrder,
// middlewaresAfter
// );
// // before
// await initMiddlewaresSeq(middlewaresBefore);
// // ordered // rest of middlewares
// await Promise.all([
// initMiddlewaresSeq(middlewaresOrder),
// Promise.all(unspecifiedMiddlewares.map(initialize)),
// ]);
// // after
// await initMiddlewaresSeq(middlewaresAfter);
// };

View File

@ -91,13 +91,15 @@ const createServer = strapi => {
return this;
},
initRouting() {
registerAllRoutes(strapi);
async initRouting() {
await registerAllRoutes(strapi);
return this;
},
initMiddlewares() {
registerMiddlewares(strapi);
async initMiddlewares() {
await registerMiddlewares(strapi);
return this;
},

View File

@ -1,5 +1,13 @@
'use strict';
const { yup } = require('@strapi/utils');
/**
* @type {import('../../').Strapi} Strapi
* @type {Array<string|{name?: string, resolve?: string, config: any}>} MiddlewaresConfig
* @type {Array<{name: string, hanlder: Function}>} Middlewares
*/
const defaultConfig = [
'strapi::errors',
'strapi::security',
@ -11,19 +19,98 @@ const defaultConfig = [
'strapi::public',
];
const requiredMiddlewares = [
'strapi::errors',
'strapi::security',
'strapi::cors',
'strapi::request',
'strapi::public',
'strapi::favicon',
];
const middlewareConfigSchema = yup.array().of(
yup.lazy(value => {
if (typeof value === 'string') {
return yup.string().required();
}
if (typeof value === 'object') {
return yup
.object({
name: yup.string(),
resolve: yup.string(),
config: yup.mixed(),
})
.required()
.noUnknown();
}
return yup.test(() => false);
})
);
/**
* Register middlewares in router
* @param {import('../../').Strapi} strapi
* @param {Strapi} strapi
*/
module.exports = strapi => {
module.exports = async strapi => {
const middlewareConfig = strapi.config.get('middlewares', defaultConfig);
// must be an array
// verify required middlewares are register
await validateMiddlewareConfig();
const middlewares = await initMiddlewares(middlewareConfig, strapi);
checkRequiredMiddlewares(middlewares);
for (const middleware of middlewares) {
strapi.server.use(middleware.handler);
}
};
/**
*
* @param {MiddlewaresConfig} config
*/
const validateMiddlewareConfig = async config => {
try {
await middlewareConfigSchema.validate(config, { strict: true, abortEarly: false });
} catch (error) {
throw new Error(
'Invalid middleware configuration. Expected Array<string|{name?: string, resolve?: string, config: any}.'
);
}
};
/**
* Check if some required middlewares are missing in configure middlewares
* @param {Middlewares} middlewares
*/
const checkRequiredMiddlewares = middlewares => {
const missingMiddlewares = requiredMiddlewares.filter(name => {
return middlewares.findIndex(mdl => mdl.name === name) === -1;
});
if (missingMiddlewares.length > 0) {
throw new Error(
`Missing required middlewares in configuration. Add the following middlewares: "${missingMiddlewares.join(
', '
)}".`
);
}
return;
};
/**
* Initialize every configured middlewares
* @param {MiddlewaresConfig} config
* @param {Strapi} strapi
* @returns {Middlewares}
*/
const initMiddlewares = async (config, strapi) => {
const middlewares = [];
for (const item of middlewareConfig) {
for (const item of config) {
if (typeof item === 'string') {
const middlewareFactory = strapi.middleware(item);
@ -31,7 +118,11 @@ module.exports = strapi => {
throw new Error(`Middleware ${item} not found.`);
}
middlewares.push(middlewareFactory());
middlewares.push({
name: item,
handler: await middlewareFactory(),
});
continue;
}
@ -40,24 +131,30 @@ module.exports = strapi => {
if (name) {
const middlewareFactory = strapi.middleware(name);
middlewares.push(middlewareFactory(config));
middlewares.push({
name,
handler: await middlewareFactory(config),
});
continue;
}
if (resolve) {
middlewares.push(require(resolve)(config));
middlewares.push({
name: resolve,
handler: await require(resolve)(config),
});
continue;
}
throw new Error('Missing name or resolve');
throw new Error('Invalid middleware configuration. Missing name or resolve properties.');
}
throw new Error(
'Middlware config must either be a string or an object (name?: string, resolve?: string, config: any)'
'Middlware config must either be a string or an object {name?: string, resolve?: string, config: any}.'
);
}
for (const middleware of middlewares) {
strapi.server.use(middleware);
}
return middlewares;
};