diff --git a/hooks/templatedataformatter.js b/hooks/templatedataformatter.js index 5b3c1a338..3324b6a8a 100644 --- a/hooks/templatedataformatter.js +++ b/hooks/templatedataformatter.js @@ -1,3 +1,5 @@ +const getCleanedJamboInjectedData = require('../static/webpack/getCleanedJamboInjectedData'); + /** * Formats the data sent to the handlebars templates during Jambo builds. * @@ -26,6 +28,9 @@ module.exports = function (pageMetadata, siteLevelAttributes, pageNameToConfig) JAMBO_INJECTED_DATA: env.JAMBO_INJECTED_DATA } }; + if (globalConfig.useJWT) { + return getCleanedTemplateData(templateData); + } return templateData; } @@ -50,4 +55,25 @@ function getLocalizedGlobalConfig(globalConfig, currentLocaleConfig, locale) { localizedGlobalConfig.locale = locale; } return localizedGlobalConfig; +} + +/** + * Returns the provided template data without the API Key + * + * @param {Object} templateData + * @returns {Object} + */ +function getCleanedTemplateData(templateData) { + const jamboInjectedData = templateData.env.JAMBO_INJECTED_DATA; + const globalConfig = templateData.global_config; + return { + ...templateData, + global_config: { + ...globalConfig, + apiKey: undefined + }, + env: { + JAMBO_INJECTED_DATA: getCleanedJamboInjectedData(jamboInjectedData) + } + } } \ No newline at end of file diff --git a/static/webpack-config.js b/static/webpack-config.js index 1501ab018..6a436d52d 100644 --- a/static/webpack-config.js +++ b/static/webpack-config.js @@ -5,6 +5,7 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const HtmlPlugin = require('html-webpack-plugin'); const RemovePlugin = require('remove-files-webpack-plugin'); const { merge } = require('webpack-merge'); +const { parse } = require('comment-json'); module.exports = function () { const jamboConfig = require('./jambo.json'); @@ -25,11 +26,29 @@ module.exports = function () { }); } + const globalConfigPath = `./${jamboConfig.dirs.config}/global_config.json`; + let globalConfig = {}; + if (fs.existsSync(globalConfigPath)) { + globalConfigRaw = fs.readFileSync(globalConfigPath, 'utf-8'); + globalConfig = parse(globalConfigRaw); + } + + const { useJWT } = globalConfig; + + let jamboInjectedData = process.env.JAMBO_INJECTED_DATA || null; + if (useJWT && jamboInjectedData) { + const getCleanedJamboInjectedData = + require(`./${jamboConfig.dirs.output}/static/webpack/getCleanedJamboInjectedData.js`); + jamboInjectedData = JSON.parse(jamboInjectedData) + jamboInjectedData = getCleanedJamboInjectedData(jamboInjectedData) + jamboInjectedData = JSON.stringify(jamboInjectedData) + } + const plugins = [ new MiniCssExtractPlugin({ filename: '[name].css' }), ...htmlPlugins, - new webpack.EnvironmentPlugin({ - JAMBO_INJECTED_DATA: null + new webpack.DefinePlugin({ + 'process.env.JAMBO_INJECTED_DATA': JSON.stringify(jamboInjectedData) }), new RemovePlugin({ after: { diff --git a/static/webpack/getCleanedJamboInjectedData.js b/static/webpack/getCleanedJamboInjectedData.js new file mode 100644 index 000000000..6ccb51c7c --- /dev/null +++ b/static/webpack/getCleanedJamboInjectedData.js @@ -0,0 +1,31 @@ +const _ = require('lodash'); + +/** + * Returns JAMBO_INJECTED_DATA with instances of the global config's apiKey removed + * + * @param {Object} data JAMBO_INJECTED_DATA + * @returns {Object} + */ +function getCleanedJamboInjectedData (data) { + if (!data || !data.answers || !data.answers.experiences) { + return; + } + const updatedData = _.cloneDeep(data); + const experiences = updatedData.answers.experiences; + + const removeApiKeyFromConfig = config => { + if ('apiKey' in config) { + delete config['apiKey']; + } + } + + Object.values(experiences).forEach(config => { + removeApiKeyFromConfig(config); + if ('configByLabel' in config) { + Object.values(config.configByLabel).forEach(removeApiKeyFromConfig); + } + }); + return updatedData; +} + +module.exports = getCleanedJamboInjectedData; \ No newline at end of file diff --git a/tests/static/webpack/getCleanedJamboInjectedData.js b/tests/static/webpack/getCleanedJamboInjectedData.js new file mode 100644 index 000000000..5b0b44b1e --- /dev/null +++ b/tests/static/webpack/getCleanedJamboInjectedData.js @@ -0,0 +1,34 @@ +import getCleanedJamboInjectedData from '../../../static/webpack/getCleanedJamboInjectedData'; + +describe('secures the injected data', () => { + const sampleConfig = { + apiKey: 999, + verticals: { + KM: { + displayName: 'Locations', + source: 'KNOWLEDGE_MANAGER' + } + } + }; + + const mockInjectedData = { + businessId: 999, + answers: { + experiences: { + test_experience: { + ...sampleConfig, + configByLabel: { + PRODUCTION: sampleConfig, + STAGING: sampleConfig + } + } + } + } + }; + + it('removes instances of the apiKey', () => { + const securedInjectedData = getCleanedJamboInjectedData(mockInjectedData); + expect(securedInjectedData).toEqual(expect.not.objectContaining({apiKey: 999})); + }); +}); +