From 9965e0e654e55d2cfdb13721c41717b49352362b Mon Sep 17 00:00:00 2001 From: mkomorski Date: Thu, 10 Oct 2024 18:56:05 +0200 Subject: [PATCH] Core: New activity control - load external script (#12207) * #11010 New activity control - load external script * improvements * adding module type to load external script * update loadScript stub * Swap moduleType/moduleCode for consistency --------- Co-authored-by: Marcin Komorski Co-authored-by: Marcin Komorski Co-authored-by: Demetrio Girardi --- modules/51DegreesRtdProvider.js | 3 +- modules/a1MediaRtdProvider.js | 2 +- modules/aaxBlockmeterRtdProvider.js | 3 +- modules/adagioRtdProvider.js | 5 ++- modules/adlooxAnalyticsAdapter.js | 3 +- modules/airgridRtdProvider.js | 2 +- modules/arcspanRtdProvider.js | 3 +- modules/azerionedgeRtdProvider.js | 2 +- modules/brandmetricsRtdProvider.js | 3 +- modules/browsiRtdProvider.js | 2 +- modules/cleanioRtdProvider.js | 3 +- modules/confiantRtdProvider.js | 4 ++- modules/contxtfulRtdProvider.js | 2 +- modules/dynamicAdBoostRtdProvider.js | 3 +- modules/ftrackIdSystem.js | 2 +- modules/geoedgeRtdProvider.js | 5 +-- modules/hadronRtdProvider.js | 2 +- modules/id5IdSystem.js | 2 +- modules/improvedigitalBidAdapter.js | 3 +- modules/justIdSystem.js | 3 +- modules/mediafilterRtdProvider.js | 4 ++- modules/medianetRtdProvider.js | 3 +- modules/qortexRtdProvider.js | 3 +- modules/showheroes-bsBidAdapter.js | 3 +- modules/symitriDapRtdProvider.js | 4 ++- modules/tncIdSystem.js | 3 +- modules/wurflRtdProvider.js | 3 +- src/Renderer.js | 3 +- src/activities/activities.js | 5 +++ src/adloader.js | 14 ++++++-- src/debugging.js | 3 +- test/mocks/adloaderStub.js | 4 +-- test/spec/adloader_spec.js | 32 +++++++++++++------ .../modules/adlooxAnalyticsAdapter_spec.js | 2 +- test/spec/modules/cleanioRtdProvider_spec.js | 5 +-- test/spec/modules/justIdSystem_spec.js | 2 +- test/spec/modules/wurflRtdProvider_spec.js | 2 +- 37 files changed, 102 insertions(+), 50 deletions(-) diff --git a/modules/51DegreesRtdProvider.js b/modules/51DegreesRtdProvider.js index 123eeeaddc3..573c79902c6 100644 --- a/modules/51DegreesRtdProvider.js +++ b/modules/51DegreesRtdProvider.js @@ -1,3 +1,4 @@ +import { MODULE_TYPE_RTD } from '../src/activities/modules.js'; import {loadExternalScript} from '../src/adloader.js'; import {submodule} from '../src/hook.js'; import { @@ -263,7 +264,7 @@ export const getBidRequestData = (reqBidsConfigObj, callback, moduleConfig, user } // Inject 51Degrees script, get device data and merge it into the ORTB2 object - loadExternalScript(scriptURL, MODULE_NAME, () => { + loadExternalScript(scriptURL, MODULE_TYPE_RTD, MODULE_NAME, () => { logMessage('Successfully injected 51Degrees script'); const fod = /** @type {Object} */ (window.fod); // Convert and merge device data in the callback diff --git a/modules/a1MediaRtdProvider.js b/modules/a1MediaRtdProvider.js index 445ed47181d..1fbe88ecfa0 100644 --- a/modules/a1MediaRtdProvider.js +++ b/modules/a1MediaRtdProvider.js @@ -39,7 +39,7 @@ function loadLbScript(tagname) { linkback.l = true; const scriptUrl = `${SCRIPT_URL}/${tagname}`; - loadExternalScript(scriptUrl, MODULE_NAME); + loadExternalScript(scriptUrl, MODULE_TYPE_RTD, MODULE_NAME); } } diff --git a/modules/aaxBlockmeterRtdProvider.js b/modules/aaxBlockmeterRtdProvider.js index a3b7b4812a7..0a72e4e36f1 100644 --- a/modules/aaxBlockmeterRtdProvider.js +++ b/modules/aaxBlockmeterRtdProvider.js @@ -1,6 +1,7 @@ import {isEmptyStr, isStr, logError, isFn, logWarn} from '../src/utils.js'; import {submodule} from '../src/hook.js'; import { loadExternalScript } from '../src/adloader.js'; +import { MODULE_TYPE_RTD } from '../src/activities/modules.js'; export const _config = { MODULE: 'aaxBlockmeter', @@ -28,7 +29,7 @@ function loadBlockmeter(_rtdConfig) { } const scriptUrl = `https://${url}&${params.join('&')}`; - loadExternalScript(scriptUrl, _config.MODULE); + loadExternalScript(scriptUrl, MODULE_TYPE_RTD, _config.MODULE); return true; } diff --git a/modules/adagioRtdProvider.js b/modules/adagioRtdProvider.js index 91f446e68fd..7098406be0d 100644 --- a/modules/adagioRtdProvider.js +++ b/modules/adagioRtdProvider.js @@ -211,7 +211,10 @@ function loadAdagioScript(config) { return; } - loadExternalScript(SCRIPT_URL, SUBMODULE_NAME, undefined, undefined, { id: `adagiojs-${getUniqueIdentifierStr()}`, 'data-pid': config.params.organizationId }); + loadExternalScript(SCRIPT_URL, MODULE_TYPE_RTD, SUBMODULE_NAME, undefined, undefined, { + id: `adagiojs-${getUniqueIdentifierStr()}`, + 'data-pid': config.params.organizationId + }); }); } diff --git a/modules/adlooxAnalyticsAdapter.js b/modules/adlooxAnalyticsAdapter.js index f18c9e72337..0a953584e26 100644 --- a/modules/adlooxAnalyticsAdapter.js +++ b/modules/adlooxAnalyticsAdapter.js @@ -28,6 +28,7 @@ import { parseUrl } from '../src/utils.js'; import {getGptSlotInfoForAdUnitCode} from '../libraries/gptUtils/gptUtils.js'; +import { MODULE_TYPE_ANALYTICS } from '../src/activities/modules.js'; const MODULE = 'adlooxAnalyticsAdapter'; @@ -262,7 +263,7 @@ analyticsAdapter[`handle_${EVENTS.BID_WON}`] = function(bid) { [ 'creatype', '%%creatype%%' ] ]); - loadExternalScript(analyticsAdapter.url(`${analyticsAdapter.context.js}#`, params, bid), 'adloox'); + loadExternalScript(analyticsAdapter.url(`${analyticsAdapter.context.js}#`, params, bid), MODULE_TYPE_ANALYTICS, 'adloox'); } adapterManager.registerAnalyticsAdapter({ diff --git a/modules/airgridRtdProvider.js b/modules/airgridRtdProvider.js index 079628c88fc..300744d62fe 100644 --- a/modules/airgridRtdProvider.js +++ b/modules/airgridRtdProvider.js @@ -43,7 +43,7 @@ export function attachScriptTagToDOM(rtdConfig) { edktInitializor.apiKey = rtdConfig.params.apiKey; edktInitializor.invoked = true; const moduleSrc = getModuleUrl(rtdConfig.params.accountId); - loadExternalScript(moduleSrc, SUBMODULE_NAME); + loadExternalScript(moduleSrc, MODULE_TYPE_RTD, SUBMODULE_NAME); } } diff --git a/modules/arcspanRtdProvider.js b/modules/arcspanRtdProvider.js index 8ccf3d160b9..3a9e9b175d8 100644 --- a/modules/arcspanRtdProvider.js +++ b/modules/arcspanRtdProvider.js @@ -1,6 +1,7 @@ import { submodule } from '../src/hook.js'; import { mergeDeep } from '../src/utils.js'; import {loadExternalScript} from '../src/adloader.js'; +import { MODULE_TYPE_RTD } from '../src/activities/modules.js'; /** * @typedef {import('../modules/rtdModule/index.js').RtdSubmodule} RtdSubmodule @@ -28,7 +29,7 @@ function init(config, userConsent) { } else { scriptUrl = 'https://silo' + config.params.silo + '.p7cloud.net/as.js'; } - loadExternalScript(scriptUrl, SUBMODULE_NAME); + loadExternalScript(scriptUrl, MODULE_TYPE_RTD, SUBMODULE_NAME); } return true; } diff --git a/modules/azerionedgeRtdProvider.js b/modules/azerionedgeRtdProvider.js index 852639972c2..7e8a32e6f93 100644 --- a/modules/azerionedgeRtdProvider.js +++ b/modules/azerionedgeRtdProvider.js @@ -50,7 +50,7 @@ function getScriptURL(config) { */ export function attachScript(config, userConsent) { const script = getScriptURL(config); - loadExternalScript(script, SUBREAL_TIME_MODULE, () => { + loadExternalScript(script, MODULE_TYPE_RTD, SUBREAL_TIME_MODULE, () => { if (typeof window.azerionPublisherAudiences === 'function') { const publisherConfig = config.params?.process || {}; window.azerionPublisherAudiences({ diff --git a/modules/brandmetricsRtdProvider.js b/modules/brandmetricsRtdProvider.js index b463a5480f8..7502a579745 100644 --- a/modules/brandmetricsRtdProvider.js +++ b/modules/brandmetricsRtdProvider.js @@ -10,6 +10,7 @@ import { deepAccess, deepSetValue, logError, mergeDeep, generateUUID } from '../ import { loadExternalScript } from '../src/adloader.js'; import * as events from '../src/events.js'; import { EVENTS } from '../src/constants.js'; +import { MODULE_TYPE_RTD } from '../src/activities/modules.js'; /** * @typedef {import('../modules/rtdModule/index.js').RtdSubmodule} RtdSubmodule @@ -140,7 +141,7 @@ function initializeBrandmetrics(scriptId) { const file = scriptId + '.js' const url = path + file - loadExternalScript(url, MODULE_CODE) + loadExternalScript(url, MODULE_TYPE_RTD, MODULE_CODE) } } diff --git a/modules/browsiRtdProvider.js b/modules/browsiRtdProvider.js index 46393b37a05..8f5fea80ffa 100644 --- a/modules/browsiRtdProvider.js +++ b/modules/browsiRtdProvider.js @@ -52,7 +52,7 @@ let _ic = {}; * @param {Object} data */ export function addBrowsiTag(data) { - let script = loadExternalScript(data.u, 'browsi'); + let script = loadExternalScript(data.u, MODULE_TYPE_RTD, 'browsi'); script.async = true; script.setAttribute('data-sitekey', _moduleParams.siteKey); script.setAttribute('data-pubkey', _moduleParams.pubKey); diff --git a/modules/cleanioRtdProvider.js b/modules/cleanioRtdProvider.js index 1a5e64de3cc..35751210878 100644 --- a/modules/cleanioRtdProvider.js +++ b/modules/cleanioRtdProvider.js @@ -11,6 +11,7 @@ import { loadExternalScript } from '../src/adloader.js'; import { logError, generateUUID, insertElement } from '../src/utils.js'; import * as events from '../src/events.js'; import { EVENTS } from '../src/constants.js'; +import { MODULE_TYPE_RTD } from '../src/activities/modules.js'; /** * @typedef {import('../modules/rtdModule/index.js').RtdSubmodule} RtdSubmodule @@ -58,7 +59,7 @@ function pageInitStepPreloadScript(scriptURL) { * @param {string} scriptURL The script URL to add to the page for protection */ function pageInitStepProtectPage(scriptURL) { - loadExternalScript(scriptURL, 'clean.io'); + loadExternalScript(scriptURL, MODULE_TYPE_RTD, 'clean.io'); } /** diff --git a/modules/confiantRtdProvider.js b/modules/confiantRtdProvider.js index 4c5475421bb..7aee63472c9 100644 --- a/modules/confiantRtdProvider.js +++ b/modules/confiantRtdProvider.js @@ -13,6 +13,7 @@ import { logError, generateUUID } from '../src/utils.js'; import { loadExternalScript } from '../src/adloader.js'; import * as events from '../src/events.js'; import { EVENTS } from '../src/constants.js'; +import { MODULE_TYPE_RTD } from '../src/activities/modules.js'; /** * Injects the Confiant Inc. configuration script into the page, based on proprtyId provided @@ -21,7 +22,8 @@ import { EVENTS } from '../src/constants.js'; function injectConfigScript(propertyId) { const scriptSrc = `https://cdn.confiant-integrations.net/${propertyId}/gpt_and_prebid/config.js`; - loadExternalScript(scriptSrc, 'confiant', () => {}); + loadExternalScript(scriptSrc, MODULE_TYPE_RTD, 'confiant', () => { + }); } /** diff --git a/modules/contxtfulRtdProvider.js b/modules/contxtfulRtdProvider.js index d4bcd94ff4a..a0d11328427 100644 --- a/modules/contxtfulRtdProvider.js +++ b/modules/contxtfulRtdProvider.js @@ -147,7 +147,7 @@ function initCustomer(config) { }); addConnectorEventListener(customer, config); - loadExternalScript(CONNECTOR_URL, MODULE_NAME); + loadExternalScript(CONNECTOR_URL, MODULE_TYPE_RTD, MODULE_NAME); } /** diff --git a/modules/dynamicAdBoostRtdProvider.js b/modules/dynamicAdBoostRtdProvider.js index 697bd7340d3..a68567b1ca3 100644 --- a/modules/dynamicAdBoostRtdProvider.js +++ b/modules/dynamicAdBoostRtdProvider.js @@ -8,6 +8,7 @@ import { submodule } from '../src/hook.js' import { loadExternalScript } from '../src/adloader.js'; import { getGlobal } from '../src/prebidGlobal.js'; import { deepAccess, deepSetValue, isEmptyStr } from '../src/utils.js'; +import { MODULE_TYPE_RTD } from '../src/activities/modules.js'; /** * @typedef {import('../modules/rtdModule/index.js').RtdSubmodule} RtdSubmodule @@ -72,7 +73,7 @@ function loadLmScript(keyId) { let viewableAdUnits = Object.keys(dynamicAdBoostAdUnits); let viewableAdUnitsCSV = viewableAdUnits.join(','); const scriptUrl = `${SCRIPT_URL}/${keyId}.js?viewableAdUnits=${viewableAdUnitsCSV}`; - loadExternalScript(scriptUrl, MODULE_NAME); + loadExternalScript(scriptUrl, MODULE_TYPE_RTD, MODULE_NAME); observer.disconnect(); } diff --git a/modules/ftrackIdSystem.js b/modules/ftrackIdSystem.js index 1794c3f76f4..fa6c7d4050c 100644 --- a/modules/ftrackIdSystem.js +++ b/modules/ftrackIdSystem.js @@ -142,7 +142,7 @@ export const ftrackIdSubmodule = { } // Creates an async script element and appends it to the document - loadExternalScript(config.params.url, MODULE_NAME); + loadExternalScript(config.params.url, MODULE_TYPE_UID, MODULE_NAME); } }; }, diff --git a/modules/geoedgeRtdProvider.js b/modules/geoedgeRtdProvider.js index 0291ff12ad2..09e717a112f 100644 --- a/modules/geoedgeRtdProvider.js +++ b/modules/geoedgeRtdProvider.js @@ -23,6 +23,7 @@ import { EVENTS } from '../src/constants.js'; import { loadExternalScript } from '../src/adloader.js'; import { auctionManager } from '../src/auctionManager.js'; import { getRefererInfo } from '../src/refererDetection.js'; +import { MODULE_TYPE_RTD } from '../src/activities/modules.js'; /** * @typedef {import('../modules/rtdModule/index.js').RtdSubmodule} RtdSubmodule @@ -108,7 +109,7 @@ export function preloadClient(key) { insertElement(iframe); iframe.contentWindow.grumi = getInitialParams(key); let url = getClientUrl(key); - loadExternalScript(url, SUBMODULE_NAME, markAsLoaded, iframe.contentDocument); + loadExternalScript(url, MODULE_TYPE_RTD, SUBMODULE_NAME, markAsLoaded, iframe.contentDocument); } /** @@ -259,7 +260,7 @@ function fireBillableEventsForApplicableBids(params) { function setupInPage(params) { window.grumi = params; window.grumi.fromPrebid = true; - loadExternalScript(getInPageUrl(params.key), SUBMODULE_NAME); + loadExternalScript(getInPageUrl(params.key), MODULE_TYPE_RTD, SUBMODULE_NAME); } function init(config, userConsent) { diff --git a/modules/hadronRtdProvider.js b/modules/hadronRtdProvider.js index 930e0922829..f9a2eaed9c9 100644 --- a/modules/hadronRtdProvider.js +++ b/modules/hadronRtdProvider.js @@ -184,7 +184,7 @@ export function getRealTimeData(bidConfig, onDone, rtdConfig, userConsent) { paramOrDefault(hadronIdUrl, HADRON_ID_DEFAULT_URL, userIds), `partner_id=${partnerId}&_it=prebid` ); - loadExternalScript(scriptUrl, 'hadron', () => { + loadExternalScript(scriptUrl, MODULE_TYPE_RTD, 'hadron', () => { logInfo(LOG_PREFIX, 'hadronIdTag loaded', scriptUrl); }) } diff --git a/modules/id5IdSystem.js b/modules/id5IdSystem.js index d08efdcb232..65e9be46a56 100644 --- a/modules/id5IdSystem.js +++ b/modules/id5IdSystem.js @@ -467,7 +467,7 @@ async function loadExternalModule(url) { resolve(); } else { try { - loadExternalScript(url, 'id5', resolve); + loadExternalScript(url, MODULE_TYPE_UID, 'id5', resolve); } catch (error) { reject(error); } diff --git a/modules/improvedigitalBidAdapter.js b/modules/improvedigitalBidAdapter.js index ddf13caa833..f189a3f4ae4 100644 --- a/modules/improvedigitalBidAdapter.js +++ b/modules/improvedigitalBidAdapter.js @@ -12,6 +12,7 @@ import {ortbConverter} from '../libraries/ortbConverter/converter.js'; */ // eslint-disable-next-line no-restricted-imports import {loadExternalScript} from '../src/adloader.js'; +import { MODULE_TYPE_BIDDER } from '../src/activities/modules.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest @@ -396,7 +397,7 @@ const ID_RAZR = { ns.q.push(data); if (!ns.loaded) { - loadExternalScript(ID_RAZR.RENDERER_URL, BIDDER_CODE); + loadExternalScript(ID_RAZR.RENDERER_URL, MODULE_TYPE_BIDDER, BIDDER_CODE); } }); diff --git a/modules/justIdSystem.js b/modules/justIdSystem.js index a5698023020..e4f1828c573 100644 --- a/modules/justIdSystem.js +++ b/modules/justIdSystem.js @@ -9,6 +9,7 @@ import * as utils from '../src/utils.js' import { submodule } from '../src/hook.js' import { loadExternalScript } from '../src/adloader.js' import {includes} from '../src/polyfill.js'; +import { MODULE_TYPE_UID } from '../src/activities/modules.js'; /** * @typedef {import('../modules/userId/index.js').Submodule} Submodule @@ -154,7 +155,7 @@ const CombinedUidProvider = function(configWrapper, consentData, cacheIdObj) { const url = configWrapper.getUrl(); this.getUid = function(idCallback, errCallback) { - const scriptTag = loadExternalScript(url, EXTERNAL_SCRIPT_MODULE_CODE, () => { + const scriptTag = loadExternalScript(url, MODULE_TYPE_UID, EXTERNAL_SCRIPT_MODULE_CODE, () => { utils.logInfo(LOG_PREFIX, 'script loaded', url); const eventDetails = { diff --git a/modules/mediafilterRtdProvider.js b/modules/mediafilterRtdProvider.js index fae5c9e769b..5472c4a6ce0 100644 --- a/modules/mediafilterRtdProvider.js +++ b/modules/mediafilterRtdProvider.js @@ -15,6 +15,7 @@ import { logError, generateUUID } from '../src/utils.js'; import { loadExternalScript } from '../src/adloader.js'; import * as events from '../src/events.js'; import { EVENTS } from '../src/constants.js'; +import { MODULE_TYPE_RTD } from '../src/activities/modules.js'; /** The event type for Media Filter. */ export const MEDIAFILTER_EVENT_TYPE = 'com.mediatrust.pbjs.'; @@ -54,7 +55,8 @@ export const MediaFilter = { * @param {string} configurationHash - The configuration hash. */ setupScript: function(configurationHash) { - loadExternalScript(MEDIAFILTER_BASE_URL.concat(configurationHash), 'mediafilter', () => {}); + loadExternalScript(MEDIAFILTER_BASE_URL.concat(configurationHash), MODULE_TYPE_RTD, 'mediafilter', () => { + }); }, /** diff --git a/modules/medianetRtdProvider.js b/modules/medianetRtdProvider.js index 5a159b39081..42fcffbf576 100644 --- a/modules/medianetRtdProvider.js +++ b/modules/medianetRtdProvider.js @@ -3,6 +3,7 @@ import {loadExternalScript} from '../src/adloader.js'; import {submodule} from '../src/hook.js'; import {getGlobal} from '../src/prebidGlobal.js'; import {includes} from '../src/polyfill.js'; +import { MODULE_TYPE_RTD } from '../src/activities/modules.js'; const MODULE_NAME = 'medianet'; const SOURCE = MODULE_NAME + 'rtd'; @@ -84,7 +85,7 @@ function executeCommand(command) { function loadRtdScript(customerId) { const url = getClientUrl(customerId, window.location.hostname); - loadExternalScript(url, MODULE_NAME) + loadExternalScript(url, MODULE_TYPE_RTD, MODULE_NAME) } function getAdUnits(adUnits, adUnitCodes) { diff --git a/modules/qortexRtdProvider.js b/modules/qortexRtdProvider.js index 88b4339b38e..aaf9b983c78 100644 --- a/modules/qortexRtdProvider.js +++ b/modules/qortexRtdProvider.js @@ -4,6 +4,7 @@ import { logWarn, mergeDeep, logMessage, generateUUID } from '../src/utils.js'; import { loadExternalScript } from '../src/adloader.js'; import * as events from '../src/events.js'; import { EVENTS } from '../src/constants.js'; +import { MODULE_TYPE_RTD } from '../src/activities/modules.js'; let requestUrl; let bidderArray; @@ -136,7 +137,7 @@ export function loadScriptTag(config) { } }) - loadExternalScript(src, code, undefined, undefined, attr); + loadExternalScript(src, MODULE_TYPE_RTD, code, undefined, undefined, attr); } /** diff --git a/modules/showheroes-bsBidAdapter.js b/modules/showheroes-bsBidAdapter.js index 062e567a1c1..026f89c5faa 100644 --- a/modules/showheroes-bsBidAdapter.js +++ b/modules/showheroes-bsBidAdapter.js @@ -16,6 +16,7 @@ import { VIDEO, BANNER } from '../src/mediaTypes.js'; */ // eslint-disable-next-line no-restricted-imports import { loadExternalScript } from '../src/adloader.js'; +import { MODULE_TYPE_BIDDER } from '../src/activities/modules.js'; const PROD_ENDPOINT = 'https://bs.showheroes.com/api/v1/bid'; const STAGE_ENDPOINT = 'https://bid-service.stage.showheroes.com/api/v1/bid'; @@ -338,7 +339,7 @@ function createOutstreamEmbedCode(bid) { const fragment = window.document.createDocumentFragment(); - let script = loadExternalScript(urls.pubTag, 'showheroes-bs', function () { + let script = loadExternalScript(urls.pubTag, MODULE_TYPE_BIDDER, 'showheroes-bs', function () { window.ShowheroesTag = this; }); script.setAttribute('data-player-host', urls.vlHost); diff --git a/modules/symitriDapRtdProvider.js b/modules/symitriDapRtdProvider.js index 1cdef460d9b..7bf523170fe 100644 --- a/modules/symitriDapRtdProvider.js +++ b/modules/symitriDapRtdProvider.js @@ -86,7 +86,9 @@ export function createRtdProvider(moduleName, moduleCode, headerPrefix) { window.dapCalculateEntropy(resolve, reject); } else { if (rtdConfig && rtdConfig.params && dapUtils.isValidHttpsUrl(rtdConfig.params.dapEntropyUrl)) { - loadExternalScript(rtdConfig.params.dapEntropyUrl, MODULE_CODE, () => { dapUtils.dapGetEntropy(resolve, reject) }); + loadExternalScript(rtdConfig.params.dapEntropyUrl, MODULE_TYPE_RTD, MODULE_CODE, () => { + dapUtils.dapGetEntropy(resolve, reject) + }); } else { reject(Error('Please check if dapEntropyUrl is specified and is valid under config.params')); } diff --git a/modules/tncIdSystem.js b/modules/tncIdSystem.js index 59254a9430f..c05e0ce4713 100644 --- a/modules/tncIdSystem.js +++ b/modules/tncIdSystem.js @@ -1,6 +1,7 @@ import { submodule } from '../src/hook.js'; import { logInfo } from '../src/utils.js'; import { loadExternalScript } from '../src/adloader.js'; +import { MODULE_TYPE_UID } from '../src/activities/modules.js'; const MODULE_NAME = 'tncId'; let url = null; @@ -20,7 +21,7 @@ const waitTNCScript = (tncNS) => { const loadRemoteScript = () => { return new Promise((resolve) => { - loadExternalScript(url, MODULE_NAME, resolve); + loadExternalScript(url, MODULE_TYPE_UID, MODULE_NAME, resolve); }) } diff --git a/modules/wurflRtdProvider.js b/modules/wurflRtdProvider.js index 94bb8c6440a..f019d2dbe52 100644 --- a/modules/wurflRtdProvider.js +++ b/modules/wurflRtdProvider.js @@ -5,6 +5,7 @@ import { mergeDeep, prefixLog, } from '../src/utils.js'; +import { MODULE_TYPE_RTD } from '../src/activities/modules.js'; // Constants const REAL_TIME_MODULE = 'realTimeData'; @@ -67,7 +68,7 @@ const getBidRequestData = (reqBidsConfigObj, callback, config, userConsent) => { logger.logMessage('url', url.toString()); try { - loadExternalScript(url.toString(), MODULE_NAME, () => { + loadExternalScript(url.toString(), MODULE_TYPE_RTD, MODULE_NAME, () => { logger.logMessage('script injected'); window.WURFLPromises.complete.then((res) => { logger.logMessage('received data', res); diff --git a/src/Renderer.js b/src/Renderer.js index 2f9b2e025cb..912259206c4 100644 --- a/src/Renderer.js +++ b/src/Renderer.js @@ -4,6 +4,7 @@ import { } from './utils.js'; import {find} from './polyfill.js'; import {getGlobal} from './prebidGlobal.js'; +import { MODULE_TYPE_PREBID } from './activities/modules.js'; const pbjsInstance = getGlobal(); const moduleCode = 'outstream'; @@ -62,7 +63,7 @@ export function Renderer(options) { } else { // we expect to load a renderer url once only so cache the request to load script this.cmd.unshift(runRender) // should render run first ? - loadExternalScript(url, moduleCode, this.callback, this.documentContext); + loadExternalScript(url, MODULE_TYPE_PREBID, moduleCode, this.callback, this.documentContext); } }.bind(this); // bind the function to this object to avoid 'this' errors } diff --git a/src/activities/activities.js b/src/activities/activities.js index 0a17750b0b0..40f43fb9114 100644 --- a/src/activities/activities.js +++ b/src/activities/activities.js @@ -50,3 +50,8 @@ export const ACTIVITY_TRANSMIT_PRECISE_GEO = 'transmitPreciseGeo'; * transmit TID: some component wants access ot (and send along) transaction IDs */ export const ACTIVITY_TRANSMIT_TID = 'transmitTid'; + +/** + * loadExternalScript: adLoader.js is allowed to load external script + */ +export const LOAD_EXTERNAL_SCRIPT = 'loadExternalScript'; diff --git a/src/adloader.js b/src/adloader.js index 5e71b89f284..bf695dd627b 100644 --- a/src/adloader.js +++ b/src/adloader.js @@ -1,5 +1,8 @@ -import {includes} from './polyfill.js'; -import { logError, logWarn, insertElement, setScriptAttributes } from './utils.js'; +import { LOAD_EXTERNAL_SCRIPT } from './activities/activities.js'; +import { activityParams } from './activities/activityParams.js'; +import { isActivityAllowed } from './activities/rules.js'; +import { includes } from './polyfill.js'; +import { insertElement, logError, logWarn, setScriptAttributes } from './utils.js'; const _requestCache = new WeakMap(); // The below list contains modules or vendors whom Prebid allows to load external JS. @@ -45,12 +48,17 @@ const _approvedLoadExternalJSList = [ * Loads external javascript. Can only be used if external JS is approved by Prebid. See https://github.com/prebid/prebid-js-external-js-template#policy * Each unique URL will be loaded at most 1 time. * @param {string} url the url to load + * @param {string} moduleType moduleType of the module requesting this resource * @param {string} moduleCode bidderCode or module code of the module requesting this resource * @param {function} [callback] callback function to be called after the script is loaded * @param {Document} [doc] the context document, in which the script will be loaded, defaults to loaded document * @param {object} attributes an object of attributes to be added to the script with setAttribute by [key] and [value]; Only the attributes passed in the first request of a url will be added. */ -export function loadExternalScript(url, moduleCode, callback, doc, attributes) { +export function loadExternalScript(url, moduleType, moduleCode, callback, doc, attributes) { + if (!isActivityAllowed(LOAD_EXTERNAL_SCRIPT, activityParams(moduleType, moduleCode))) { + return; + } + if (!moduleCode || !url) { logError('cannot load external script without url and moduleCode'); return; diff --git a/src/debugging.js b/src/debugging.js index 045855ccb28..69c129da9a2 100644 --- a/src/debugging.js +++ b/src/debugging.js @@ -5,6 +5,7 @@ import {logMessage, prefixLog} from './utils.js'; import {createBid} from './bidfactory.js'; import {loadExternalScript} from './adloader.js'; import {GreedyPromise} from './utils/promise.js'; +import { MODULE_TYPE_PREBID } from './activities/modules.js'; export const DEBUG_KEY = '__$$PREBID_GLOBAL$$_debugging__'; @@ -14,7 +15,7 @@ function isDebuggingInstalled() { function loadScript(url) { return new GreedyPromise((resolve) => { - loadExternalScript(url, 'debugging', resolve); + loadExternalScript(url, MODULE_TYPE_PREBID, 'debugging', resolve); }); } diff --git a/test/mocks/adloaderStub.js b/test/mocks/adloaderStub.js index 6e7f5756100..24f5781dfc4 100644 --- a/test/mocks/adloaderStub.js +++ b/test/mocks/adloaderStub.js @@ -8,9 +8,7 @@ export let loadExternalScriptStub = createStub(); function createStub() { return sinon.stub(adloader, 'loadExternalScript').callsFake((...args) => { - if (typeof args[2] === 'function') { - args[2](); - } else if (typeof args[3] === 'function') { + if (typeof args[3] === 'function') { args[3](); } return document.createElement('script'); diff --git a/test/spec/adloader_spec.js b/test/spec/adloader_spec.js index fcc388c2d3b..900358a766b 100644 --- a/test/spec/adloader_spec.js +++ b/test/spec/adloader_spec.js @@ -1,5 +1,8 @@ import * as utils from 'src/utils.js'; import * as adLoader from 'test/mocks/adloaderStub.js'; +import { LOAD_EXTERNAL_SCRIPT } from '../../src/activities/activities'; +import { registerActivityControl } from '../../src/activities/rules'; +import { MODULE_TYPE_PREBID } from '../../src/activities/modules'; describe('adLoader', function () { let utilsinsertElementStub; @@ -23,19 +26,19 @@ describe('adLoader', function () { }); it('only allows whitelisted vendors to load scripts', function () { - adLoader.loadExternalScript('someURL', 'debugging'); + adLoader.loadExternalScript('someURL', MODULE_TYPE_PREBID, 'debugging'); expect(utilsLogErrorStub.called).to.be.false; expect(utilsinsertElementStub.called).to.be.true; }); it('should not load cached script again', function() { - adLoader.loadExternalScript('someURL', 'debugging'); + adLoader.loadExternalScript('someURL', 'debugging', MODULE_TYPE_PREBID); expect(utilsinsertElementStub.called).to.be.false; }); it('callback function can be passed to the function', function() { let callback = function() {}; - adLoader.loadExternalScript('someURL1', 'debugging', callback); + adLoader.loadExternalScript('someURL1', MODULE_TYPE_PREBID, 'debugging', callback); expect(utilsinsertElementStub.called).to.be.true; }); @@ -61,11 +64,11 @@ describe('adLoader', function () { } const doc1 = getDocSpec(); const doc2 = getDocSpec(); - adLoader.loadExternalScript('someURL', 'debugging', () => {}, doc1); - adLoader.loadExternalScript('someURL', 'debugging', () => {}, doc1); - adLoader.loadExternalScript('someURL', 'debugging', () => {}, doc1); - adLoader.loadExternalScript('someURL', 'debugging', () => {}, doc2); - adLoader.loadExternalScript('someURL', 'debugging', () => {}, doc2); + adLoader.loadExternalScript('someURL', MODULE_TYPE_PREBID, 'debugging', () => {}, doc1); + adLoader.loadExternalScript('someURL', MODULE_TYPE_PREBID, 'debugging', () => {}, doc1); + adLoader.loadExternalScript('someURL', MODULE_TYPE_PREBID, 'debugging', () => {}, doc1); + adLoader.loadExternalScript('someURL', MODULE_TYPE_PREBID, 'debugging', () => {}, doc2); + adLoader.loadExternalScript('someURL', MODULE_TYPE_PREBID, 'debugging', () => {}, doc2); expect(utilsinsertElementStub.callCount).to.equal(2); }); }); @@ -88,8 +91,19 @@ describe('adLoader', function () { } }, attrs = {'z': 'A', 'y': 2}; - let script = adLoader.loadExternalScript('someUrl', 'debugging', undefined, doc, attrs); + let script = adLoader.loadExternalScript('someUrl', MODULE_TYPE_PREBID, 'debugging', undefined, doc, attrs); expect(script.z).to.equal('A'); expect(script.y).to.equal(2); }); + + it('should disable loading external script for activity rule set', function () { + let unregisterRule; + try { + unregisterRule = registerActivityControl(LOAD_EXTERNAL_SCRIPT, 'loadExternalScript config', () => ({allow: false})); + adLoader.loadExternalScript(null, 'debugging'); + expect(utilsLogErrorStub.called).to.be.false; + } finally { + unregisterRule?.(); + } + }) }); diff --git a/test/spec/modules/adlooxAnalyticsAdapter_spec.js b/test/spec/modules/adlooxAnalyticsAdapter_spec.js index 450dd83f86d..fa8204a9dc5 100644 --- a/test/spec/modules/adlooxAnalyticsAdapter_spec.js +++ b/test/spec/modules/adlooxAnalyticsAdapter_spec.js @@ -169,7 +169,7 @@ describe('Adloox Analytics Adapter', function () { events.emit(EVENTS.BID_WON, bid); - const [urlInserted, moduleCode] = loadExternalScriptStub.getCall(0).args; + const [urlInserted, _, moduleCode] = loadExternalScriptStub.getCall(0).args; expect(urlInserted.substr(0, url.length)).to.equal(url); expect(moduleCode).to.equal(analyticsAdapterName); diff --git a/test/spec/modules/cleanioRtdProvider_spec.js b/test/spec/modules/cleanioRtdProvider_spec.js index 3145108c373..0211a9ae588 100644 --- a/test/spec/modules/cleanioRtdProvider_spec.js +++ b/test/spec/modules/cleanioRtdProvider_spec.js @@ -5,6 +5,7 @@ import * as events from '../../../src/events.js'; import { EVENTS } from '../../../src/constants.js'; import { __TEST__ } from '../../../modules/cleanioRtdProvider.js'; +import {MODULE_TYPE_RTD} from '../../../src/activities/modules.js'; const { readConfig, @@ -70,7 +71,7 @@ describe('clean.io RTD module', function () { pageInitStepProtectPage(fakeScriptURL); sinon.assert.calledOnce(loadExternalScriptStub); - sinon.assert.calledWith(loadExternalScriptStub, fakeScriptURL, 'clean.io'); + sinon.assert.calledWith(loadExternalScriptStub, fakeScriptURL, MODULE_TYPE_RTD, 'clean.io'); }); }); @@ -139,7 +140,7 @@ describe('clean.io RTD module', function () { const { init, onBidResponseEvent } = getModule(); expect(init({ params: { cdnUrl: 'https://abc1234567890.cloudfront.net/script.js', protectionMode: 'full' } }, {})).to.equal(true); sinon.assert.calledOnce(loadExternalScriptStub); - sinon.assert.calledWith(loadExternalScriptStub, 'https://abc1234567890.cloudfront.net/script.js', 'clean.io'); + sinon.assert.calledWith(loadExternalScriptStub, 'https://abc1234567890.cloudfront.net/script.js', MODULE_TYPE_RTD, 'clean.io'); const fakeBidResponse = makeFakeBidResponse(); onBidResponseEvent(fakeBidResponse, {}, {}); diff --git a/test/spec/modules/justIdSystem_spec.js b/test/spec/modules/justIdSystem_spec.js index b6a8cd2d310..95d964d807c 100644 --- a/test/spec/modules/justIdSystem_spec.js +++ b/test/spec/modules/justIdSystem_spec.js @@ -143,7 +143,7 @@ describe('JustIdSystem', function () { var scriptTagCallback; beforeEach(() => { - loadExternalScriptStub.callsFake((url, moduleCode, callback) => { + loadExternalScriptStub.callsFake((url, moduleCode, moduleType, callback) => { scriptTagCallback = callback; return scriptTag; }); diff --git a/test/spec/modules/wurflRtdProvider_spec.js b/test/spec/modules/wurflRtdProvider_spec.js index 5b1cc5b751f..434abfc4e22 100644 --- a/test/spec/modules/wurflRtdProvider_spec.js +++ b/test/spec/modules/wurflRtdProvider_spec.js @@ -164,7 +164,7 @@ describe('wurflRtdProvider', function () { expect(loadExternalScriptStub.calledOnce).to.be.true; const loadExternalScriptCall = loadExternalScriptStub.getCall(0); expect(loadExternalScriptCall.args[0]).to.equal(expectedURL.toString()); - expect(loadExternalScriptCall.args[1]).to.equal('wurfl'); + expect(loadExternalScriptCall.args[2]).to.equal('wurfl'); }); it('onAuctionEndEvent: should send analytics data using navigator.sendBeacon, if available', () => {