From 4020a96da6a1dc1e6c424bebbcd66bc9439de56c Mon Sep 17 00:00:00 2001 From: Jamie Howard Date: Fri, 26 May 2023 14:27:44 +0100 Subject: [PATCH] chore: separate validation between webhook service and controller --- .../core/admin/server/controllers/webhooks.js | 32 ++++++++++++++++ .../core/strapi/lib/services/webhook-store.js | 37 ++----------------- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/packages/core/admin/server/controllers/webhooks.js b/packages/core/admin/server/controllers/webhooks.js index fd97f2437b..5b7804185f 100644 --- a/packages/core/admin/server/controllers/webhooks.js +++ b/packages/core/admin/server/controllers/webhooks.js @@ -1,5 +1,33 @@ 'use strict'; +const _ = require('lodash'); +const { yup, validateYupSchema } = require('@strapi/utils'); + +const urlRegex = + /^(?:([a-z0-9+.-]+):\/\/)(?:\S+(?::\S*)?@)?(?:(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9_]-*)*[a-z\u00a1-\uffff0-9_]+)(?:\.(?:[a-z\u00a1-\uffff0-9_]-*)*[a-z\u00a1-\uffff0-9_]+)*\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/; + +const webhookValidator = yup.object({ + name: yup.string().required(), + url: yup.string().matches(urlRegex, 'url must be a valid URL').required(), + headers: yup.lazy((data) => { + if (typeof data !== 'object') { + return yup.object().required(); + } + + return yup + .object( + _.mapValues(data, () => { + yup.string().min(1).required(); + }) + ) + .required(); + }), +}); + +const updateWebhookValidator = webhookValidator.shape({ + isEnabled: yup.boolean(), +}); + module.exports = { async listWebhooks(ctx) { const webhooks = await strapi.webhookStore.findWebhooks(); @@ -20,6 +48,8 @@ module.exports = { async createWebhook(ctx) { const { body } = ctx.request; + await validateYupSchema(webhookValidator)(body); + const webhook = await strapi.webhookStore.createWebhook(body); strapi.webhookRunner.add(webhook); @@ -31,6 +61,8 @@ module.exports = { const { id } = ctx.params; const { body } = ctx.request; + await validateYupSchema(updateWebhookValidator)(body); + const webhook = await strapi.webhookStore.findWebhook(id); if (!webhook) { diff --git a/packages/core/strapi/lib/services/webhook-store.js b/packages/core/strapi/lib/services/webhook-store.js index 90b9bf0bc5..21528fbf24 100644 --- a/packages/core/strapi/lib/services/webhook-store.js +++ b/packages/core/strapi/lib/services/webhook-store.js @@ -4,7 +4,6 @@ 'use strict'; -const { mapValues } = require('lodash/fp'); const { yup, validateYupSchema } = require('@strapi/utils'); const webhookModel = { @@ -50,36 +49,8 @@ const fromDBObject = (row) => { }; }; -const urlRegex = - /^(?:([a-z0-9+.-]+):\/\/)(?:\S+(?::\S*)?@)?(?:(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9_]-*)*[a-z\u00a1-\uffff0-9_]+)(?:\.(?:[a-z\u00a1-\uffff0-9_]-*)*[a-z\u00a1-\uffff0-9_]+)*\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/; - -const webhookValidator = (allowedEvents) => - yup - .object({ - name: yup.string().required(), - url: yup.string().matches(urlRegex, 'url must be a valid URL').required(), - headers: yup.lazy((data) => { - if (typeof data !== 'object') { - return yup.object().required(); - } - - return yup - .object( - mapValues(() => { - yup.string().min(1).required(); - }, data) - ) - .required(); - }), - events: yup.array().of(yup.string().oneOf(Array.from(allowedEvents.values())).required()), - }) - .noUnknown(); - -const updateWebhookValidator = (allowedEvents) => - webhookValidator(allowedEvents).shape({ - id: yup.number().required(), - isEnabled: yup.boolean().required(), - }); +const webhookEventValidator = (allowedEvents) => + yup.array().of(yup.string().oneOf(Array.from(allowedEvents.values())).required()); const createWebhookStore = ({ db }) => { const webhookQueries = db.query('webhook'); @@ -106,7 +77,7 @@ const createWebhookStore = ({ db }) => { }, async createWebhook(data) { - await validateYupSchema(webhookValidator(allowedEvents))(data); + await validateYupSchema(webhookEventValidator(allowedEvents))(data.events); return webhookQueries .create({ @@ -116,7 +87,7 @@ const createWebhookStore = ({ db }) => { }, async updateWebhook(id, data) { - await validateYupSchema(updateWebhookValidator(allowedEvents))(data); + await validateYupSchema(webhookEventValidator(allowedEvents))(data.events); const webhook = await webhookQueries.update({ where: { id },