From dcf1224a172927eefbd042e0f2cc21e12c078941 Mon Sep 17 00:00:00 2001 From: Christopher Kolstad Date: Fri, 5 Feb 2021 14:07:46 +0100 Subject: [PATCH] fix: Add validation of required parameters --- lib/services/addon-service.js | 24 ++++++++++++++++ lib/services/addon-service.test.js | 45 +++++++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/lib/services/addon-service.js b/lib/services/addon-service.js index e5ad6b02e1..807eb4e956 100644 --- a/lib/services/addon-service.js +++ b/lib/services/addon-service.js @@ -1,6 +1,7 @@ 'use strict'; const memoize = require('memoizee'); +const { ValidationError } = require('joi'); const addonProvidersClasses = require('../addons'); const events = require('../event-type'); const { addonSchema } = require('./addon-schema'); @@ -147,6 +148,7 @@ class AddonService { async createAddon(data, userName) { const addonConfig = await addonSchema.validateAsync(data); await this.validateKnownProvider(addonConfig); + await this.validateRequiredParameters(addonConfig); const createdAddon = await this.addonStore.insert(addonConfig); await this.addTagTypes(createdAddon.provider); @@ -166,6 +168,7 @@ class AddonService { async updateAddon(id, data, userName) { const addonConfig = await addonSchema.validateAsync(data); + await this.validateRequiredParameters(addonConfig); if (this.sensitiveParams[addonConfig.provider].length > 0) { const existingConfig = await this.addonStore.get(id); addonConfig.parameters = Object.keys(addonConfig.parameters).reduce( @@ -208,6 +211,27 @@ class AddonService { return true; } } + + async validateRequiredParameters({ provider, parameters }) { + const providerDefinition = this.addonProviders[provider].definition; + + const requiredParamsMissing = providerDefinition.parameters + .filter(p => p.required) + .map(p => p.name) + .filter( + requiredParam => + !Object.keys(parameters).includes(requiredParam), + ); + if (requiredParamsMissing.length > 0) { + throw new ValidationError( + `Missing required parameters: ${requiredParamsMissing.join( + ',', + )} `, + '', + ); + } + return true; + } } module.exports = AddonService; diff --git a/lib/services/addon-service.test.js b/lib/services/addon-service.test.js index f9750ad360..c741be5850 100644 --- a/lib/services/addon-service.test.js +++ b/lib/services/addon-service.test.js @@ -2,7 +2,7 @@ const test = require('ava'); const proxyquire = require('proxyquire').noCallThru(); - +const { ValidationError } = require('joi'); const Addon = require('../addons/addon'); const store = require('../../test/fixtures/store'); @@ -319,3 +319,46 @@ test('should not overwrite masked values when updating', async t => { t.is(updatedConfig.parameters.url, 'http://localhost/wh'); t.is(updatedConfig.parameters.var, 'some-new-value'); }); + +test('should reject addon config with missing required parameter when creating', async t => { + const { addonService } = getSetup(); + + const config = { + provider: 'simple', + enabled: true, + parameters: { + var: 'some-value', + }, + events: [FEATURE_CREATED], + }; + + await t.throwsAsync( + async () => addonService.createAddon(config, 'me@mail.com'), + { instanceOf: ValidationError }, + ); +}); + +test('should reject updating addon config with missing required parameter', async t => { + const { addonService } = getSetup(); + + const addonConfig = { + provider: 'simple', + enabled: true, + parameters: { + url: 'https://some.site/api', + var: 'some-value', + }, + events: [FEATURE_CREATED], + }; + + const config = await addonService.createAddon(addonConfig, 'me@mail.com'); + const updated = { + ...config, + parameters: { var: 'some-new-value' }, + description: 'test', + }; + await t.throwsAsync( + async () => addonService.updateAddon(config.id, updated, 'me@mail.com'), + { instanceOf: ValidationError }, + ); +});