Skip to content

Commit

Permalink
Invibes Bid Adapter - cookies update & user sync (prebid#2512)
Browse files Browse the repository at this point in the history
  • Loading branch information
rcheptanariu authored and dluxemburg committed Jul 17, 2018
1 parent 628793c commit b90a63f
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 74 deletions.
182 changes: 121 additions & 61 deletions modules/invibesBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,26 @@ export const spec = {
interpretResponse: function (responseObj, requestParams) {
return handleResponse(responseObj, requestParams != null ? requestParams.bidRequests : null);
},
getUserSyncs: function(syncOptions) {
getUserSyncs: function (syncOptions) {
if (syncOptions.iframeEnabled) {
handlePostMessage();
const syncUrl = buildSyncUrl();

return {
type: 'iframe',
url: CONSTANTS.SYNC_ENDPOINT
url: syncUrl
};
}
}
};

registerBidder(spec);

// some state info is required: cookie info, unique user visit id
const topWin = getTopMostWindow();
let invibes = topWin.invibes = topWin.invibes || {};
let _customUserSync;

function isBidRequestValid(bid) {
if (typeof bid.params !== 'object') {
return false;
Expand All @@ -62,47 +70,53 @@ function isBidRequestValid(bid) {
function buildRequest(bidRequests, auctionStart) {
// invibes only responds to 1 bid request for each user visit
const _placementIds = [];
let _loginId, _customEndpoint, _bidContainerId;
let _loginId, _customEndpoint;
let _ivAuctionStart = auctionStart || Date.now();

bidRequests.forEach(function (bidRequest) {
bidRequest.startTime = new Date().getTime();
_placementIds.push(bidRequest.params.placementId);
_loginId = _loginId || bidRequest.params.loginId;
_customEndpoint = _customEndpoint || bidRequest.params.customEndpoint;
_bidContainerId = _bidContainerId || bidRequest.params.adContainerId || bidRequest.params.bidContainerId;
_customUserSync = _customUserSync || bidRequest.params.customUserSync;
});

const topWin = getTopMostWindow();
const invibes = topWin.invibes = topWin.invibes || {};
invibes.visitId = invibes.visitId || generateRandomId();
invibes.bidContainerId = invibes.bidContainerId || _bidContainerId;

initDomainId(invibes);
cookieDomain = detectTopmostCookieDomain();
invibes.noCookies = invibes.noCookies || invibes.getCookie('ivNoCookie');
invibes.optIn = invibes.optIn || invibes.getCookie('ivOptIn');

initDomainId();

const currentQueryStringParams = parseQueryStringParams();

let data = {
location: getDocumentLocation(topWin),
videoAdHtmlId: generateRandomId(),
showFallback: currentQueryStringParams['advs'] === '0',
ivbsCampIdsLocal: getCookie('IvbsCampIdsLocal'),
ivbsCampIdsLocal: invibes.getCookie('IvbsCampIdsLocal'),
lId: invibes.dom.id,

bidParamsJson: JSON.stringify({
placementIds: _placementIds,
loginId: _loginId,
bidContainerId: _bidContainerId,
auctionStartTime: _ivAuctionStart,
bidVersion: CONSTANTS.PREBID_VERSION
}),
capCounts: getCappedCampaignsAsString(),

vId: invibes.visitId,
width: topWin.innerWidth,
height: topWin.innerHeight
height: topWin.innerHeight,

noc: !cookieDomain
};

if (invibes.optIn) {
data.oi = 1;
}

const parametersToPassForward = 'videoaddebug,advs,bvci,bvid,istop,trybvid,trybvci'.split(',');
for (let key in currentQueryStringParams) {
if (currentQueryStringParams.hasOwnProperty(key)) {
Expand Down Expand Up @@ -143,9 +157,6 @@ function handleResponse(responseObj, bidRequests) {
return [];
}

const topWin = getTopMostWindow();
const invibes = topWin.invibes = topWin.invibes || {};

if (typeof invibes.bidResponse === 'object') {
utils.logInfo('Invibes Adapter - Bid response already received. Invibes only responds to one bid request per user visit');
return [];
Expand Down Expand Up @@ -191,8 +202,7 @@ function handleResponse(responseObj, bidRequests) {
});

const now = Date.now();
invibes.ivLogger = invibes.ivLogger || initLogger();
invibes.ivLogger.info('Bid auction started at ' + bidModel.AuctionStartTime + ' . Invibes registered the bid at ' + now + ' ; bid request took a total of ' + (now - bidModel.AuctionStartTime) + ' ms.');
ivLogger.info('Bid auction started at ' + bidModel.AuctionStartTime + ' . Invibes registered the bid at ' + now + ' ; bid request took a total of ' + (now - bidModel.AuctionStartTime) + ' ms.');
} else {
utils.logInfo('Invibes Adapter - Incorrect Placement Id: ' + bidRequest.params.placementId);
}
Expand Down Expand Up @@ -300,35 +310,69 @@ function getCappedCampaignsAsString() {
.join(',');
}

function initLogger() {
const noop = function () { };
const noop = function () { };

function initLogger() {
if (localStorage && localStorage.InvibesDEBUG) {
return window.console;
}

return { info: noop, error: noop, log: noop, warn: noop, debug: noop };
}

function buildSyncUrl() {
let syncUrl = _customUserSync || CONSTANTS.SYNC_ENDPOINT;
syncUrl += '?visitId=' + invibes.visitId;

if (invibes.optIn) {
syncUrl += '&optIn=1';
}

const did = invibes.getCookie('ivbsdid');
if (did) {
syncUrl += '&ivbsdid=' + encodeURIComponent(did);
}

const bks = invibes.getCookie('ivvbks');
if (bks) {
syncUrl += '&ivvbks=' + encodeURIComponent(bks);
}

return syncUrl;
}

function handlePostMessage() {
try {
if (window.addEventListener) {
window.addEventListener('message', acceptPostMessage);
}
} catch (e) { }
}

function acceptPostMessage(e) {
let msg = e.data || {};
if (msg.ivbscd === 1) {
invibes.setCookie(msg.name, msg.value, msg.exdays, msg.domain);
} else if (msg.ivbscd === 2) {
invibes.dom.graduate();
}
}

const ivLogger = initLogger();

/// Local domain cookie management =====================
let Uid = {
invibes.Uid = {
generate: function () {
let date = new Date().getTime();
if (date > 151 * 10e9) {
let datePart = Math.floor(date / 1000).toString(36);
let maxRand = parseInt('zzzzzz', 36)
let randPart = Math.floor(Math.random() * maxRand).toString(36);
return datePart + '.' + randPart;
}
},
getCrTime: function (s) {
let toks = s.split('.');
return parseInt(toks[0] || 0, 36) * 1e3;
let maxRand = parseInt('zzzzzz', 36)
let mkRand = function () { return Math.floor(Math.random() * maxRand).toString(36); };
let rand1 = mkRand();
let rand2 = mkRand();
return rand1 + rand2;
}
};

let cookieDomain, noCookies;
function getCookie(name) {
let cookieDomain;
invibes.getCookie = function (name) {
let i, x, y;
let cookies = document.cookie.split(';');
for (i = 0; i < cookies.length; i++) {
Expand All @@ -341,8 +385,9 @@ function getCookie(name) {
}
};

function setCookie(name, value, exdays, domain) {
if (noCookies && name != 'ivNoCookie' && (exdays || 0) >= 0) { return; }
invibes.setCookie = function (name, value, exdays, domain) {
let whiteListed = name == 'ivNoCookie' || name == 'IvbsCampIdsLocal';
if (invibes.noCookies && !whiteListed && (exdays || 0) >= 0) { return; }
if (exdays > 365) { exdays = 365; }
domain = domain || cookieDomain;
let exdate = new Date();
Expand All @@ -354,86 +399,101 @@ function setCookie(name, value, exdays, domain) {
};

let detectTopmostCookieDomain = function () {
let testCookie = Uid.generate();
let testCookie = invibes.Uid.generate();
let hostParts = location.host.split('.');
if (hostParts.length === 1) {
return location.host;
}
for (let i = hostParts.length - 1; i >= 0; i--) {
let domain = '.' + hostParts.slice(i).join('.');
setCookie(testCookie, testCookie, 1, domain);
let val = getCookie(testCookie);
invibes.setCookie(testCookie, testCookie, 1, domain);
let val = invibes.getCookie(testCookie);
if (val === testCookie) {
setCookie(testCookie, testCookie, -1, domain);
invibes.setCookie(testCookie, testCookie, -1, domain);
return domain;
}
}
};
cookieDomain = detectTopmostCookieDomain();
noCookies = getCookie('ivNoCookie');

function initDomainId(invibes, persistence) {
if (typeof invibes.dom === 'object') {
return;
}
let initDomainId = function (options) {
if (invibes.dom) { return; }

options = options || {};

let cookiePersistence = {
cname: 'ivbsdid',
load: function () {
let str = getCookie(this.cname) || '';
let str = invibes.getCookie(this.cname) || '';
try {
return JSON.parse(str);
} catch (e) { }
},
save: function (obj) {
setCookie(this.cname, JSON.stringify(obj), 365);
invibes.setCookie(this.cname, JSON.stringify(obj), 365);
}
};

persistence = persistence || cookiePersistence;
let persistence = options.persistence || cookiePersistence;
let state;
const minHC = 5;
let minHC = 7;

let validGradTime = function (d) {
const min = 151 * 10e9;
let yesterday = new Date().getTime() - 864 * 10e4
return d > min && d < yesterday;
let validGradTime = function (state) {
if (!state.cr) { return false; }
let min = 151 * 10e9;
if (state.cr < min) {
return false;
}
let now = new Date().getTime();
let age = now - state.cr;
let minAge = 24 * 60 * 60 * 1000;
return age > minAge;
};

state = persistence.load() || {
id: Uid.generate(),
id: invibes.Uid.generate(),
cr: new Date().getTime(),
hc: 1,
temp: 1
};

if (state.id.match(/\./)) {
state.id = invibes.Uid.generate();
}

let graduate;

let setId = function () {
invibes.dom = {
id: state.temp ? undefined : state.id,
tempId: state.id,
id: !state.cr && invibes.optIn ? state.id : undefined,
tempId: invibes.optIn ? state.id : undefined,
graduate: graduate
};
};

graduate = function () {
if (!state.temp) { return; }
delete state.temp;
if (!state.cr) { return; }
delete state.cr;
delete state.hc;
persistence.save(state);
setId();
}

if (state.temp) {
if (state.cr && !options.noVisit) {
if (state.hc < minHC) {
state.hc++;
}
if (state.hc >= minHC && validGradTime(Uid.getCrTime(state.id))) {
if (state.hc >= minHC && validGradTime(state)) {
graduate();
}
}

persistence.save(state);
setId();
ivLogger.info('Did=' + invibes.dom.id);
};
// =====================

export function resetInvibes() {
invibes.optIn = undefined;
invibes.noCookies = undefined;
invibes.dom = undefined;
invibes.bidResponse = undefined;
}
Loading

0 comments on commit b90a63f

Please sign in to comment.