mk9-prebid
Version:
Header Bidding Management Library
178 lines (162 loc) • 5.45 kB
JavaScript
/**
* This module adds SharedId to the User ID module
* The {@link module:modules/userId} module is required
* @module modules/sharedIdSystem
* @requires module:modules/userId
*/
import * as utils from '../src/utils.js';
import {submodule} from '../src/hook.js';
import { coppaDataHandler } from '../src/adapterManager.js';
import {getStorageManager} from '../src/storageManager.js';
const GVLID = 887;
const storage = getStorageManager(GVLID, 'pubCommonId');
const COOKIE = 'cookie';
const LOCAL_STORAGE = 'html5';
const OPTOUT_NAME = '_pubcid_optout';
const PUB_COMMON_ID = 'PublisherCommonId';
/**
* Read a value either from cookie or local storage
* @param {string} name Name of the item
* @param {string} type storage type override
* @returns {string|null} a string if item exists
*/
function readValue(name, type) {
if (type === COOKIE) {
return storage.getCookie(name);
} else if (type === LOCAL_STORAGE) {
if (storage.hasLocalStorage()) {
const expValue = storage.getDataFromLocalStorage(`${name}_exp`);
if (!expValue) {
return storage.getDataFromLocalStorage(name);
} else if ((new Date(expValue)).getTime() - Date.now() > 0) {
return storage.getDataFromLocalStorage(name)
}
}
}
}
function getIdCallback(pubcid, pixelCallback) {
return function (callback) {
if (typeof pixelCallback === 'function') {
pixelCallback();
}
callback(pubcid);
}
}
function queuePixelCallback(pixelUrl, id = '', callback) {
if (!pixelUrl) {
return;
}
// Use pubcid as a cache buster
const urlInfo = utils.parseUrl(pixelUrl);
urlInfo.search.id = encodeURIComponent('pubcid:' + id);
const targetUrl = utils.buildUrl(urlInfo);
return function () {
utils.triggerPixel(targetUrl);
};
}
function hasOptedOut() {
return !!((storage.cookiesAreEnabled() && readValue(OPTOUT_NAME, COOKIE)) ||
(storage.hasLocalStorage() && readValue(OPTOUT_NAME, LOCAL_STORAGE)));
}
export const sharedIdSystemSubmodule = {
/**
* used to link submodule with config
* @type {string}
*/
name: 'sharedId',
aliasName: 'pubCommonId',
/**
* Vendor id of prebid
* @type {Number}
*/
gvlid: GVLID,
/**
* decode the stored id value for passing to bid requests
* @function
* @param {string} value
* @param {SubmoduleConfig} config
* @returns {{pubcid:string}}
*/
decode(value, config) {
if (hasOptedOut()) {
utils.logInfo('PubCommonId decode: Has opted-out');
return undefined;
}
utils.logInfo(' Decoded value PubCommonId ' + value);
const idObj = {'pubcid': value};
return idObj;
},
/**
* performs action to obtain id
* @function
* @param {SubmoduleConfig} [config] Config object with params and storage properties
* @param {Object} consentData
* @param {string} storedId Existing pubcommon id
* @returns {IdResponse}
*/
getId: function (config = {}, consentData, storedId) {
if (hasOptedOut()) {
utils.logInfo('PubCommonId: Has opted-out');
return;
}
const coppa = coppaDataHandler.getCoppa();
if (coppa) {
utils.logInfo('PubCommonId: IDs not provided for coppa requests, exiting PubCommonId');
return;
}
const {params: {create = true, pixelUrl} = {}} = config;
let newId = storedId;
if (!newId) {
try {
if (typeof window[PUB_COMMON_ID] === 'object') {
// If the page includes its own pubcid module, then save a copy of id.
newId = window[PUB_COMMON_ID].getId();
}
} catch (e) {
}
if (!newId) newId = (create && utils.hasDeviceAccess()) ? utils.generateUUID() : undefined;
}
const pixelCallback = queuePixelCallback(pixelUrl, newId);
return {id: newId, callback: getIdCallback(newId, pixelCallback)};
},
/**
* performs action to extend an id. There are generally two ways to extend the expiration time
* of stored id: using pixelUrl or return the id and let main user id module write it again with
* the new expiration time.
*
* PixelUrl, if defined, should point back to a first party domain endpoint. On the server
* side, there is either a plugin, or customized logic to read and write back the pubcid cookie.
* The extendId function itself should return only the callback, and not the id itself to avoid
* having the script-side overwriting server-side. This applies to both pubcid and sharedid.
*
* On the other hand, if there is no pixelUrl, then the extendId should return storedId so that
* its expiration time is updated.
*
* @function
* @param {SubmoduleParams} [config]
* @param {ConsentData|undefined} consentData
* @param {Object} storedId existing id
* @returns {IdResponse|undefined}
*/
extendId: function(config = {}, consentData, storedId) {
if (hasOptedOut()) {
utils.logInfo('PubCommonId: Has opted-out');
return {id: undefined};
}
const coppa = coppaDataHandler.getCoppa();
if (coppa) {
utils.logInfo('PubCommonId: IDs not provided for coppa requests, exiting PubCommonId');
return;
}
const {params: {extend = false, pixelUrl} = {}} = config;
if (extend) {
if (pixelUrl) {
const callback = queuePixelCallback(pixelUrl, storedId);
return {callback: callback};
} else {
return {id: storedId};
}
}
}
};
submodule('userId', sharedIdSystemSubmodule);