Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
"identity-obj-proxy": "^3.0.0",
"jest": "^22.2.1",
"json-loader": "^0.5.4",
"less": "^3.0.0-alpha.3",
"less": "^3.7.1",
"less-loader": "^4.0.3",
"mkdirp": "^0.5.1",
"ncp": "^2.0.0",
Expand Down Expand Up @@ -117,7 +117,7 @@
"query-string": "^5.0.1",
"react-codemirror2": "^4.0.0",
"react-router-dom": "^4.2.2",
"serve": "^6.0.0",
"serve": "^9.2.0",
"whatwg-fetch": "^2.0.3"
}
}
7 changes: 7 additions & 0 deletions serve.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"cleanUrls": false,
"rewrites": [
{ "source": "/", "destination": "/index.html" },
{ "source": "/docs", "destination": "/docs/index.html" }
]
}
13 changes: 13 additions & 0 deletions src/docs/components/docs/configuration.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,19 @@ export default class CmpApi extends Component {
by pubvendors.json.
</span>
</span>
<span class={style.argument}>
Copy link
Copy Markdown

@danielrussellLA danielrussellLA Aug 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is the spacing so large in these files?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nvm it's an upstream merge i see

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

project is using tabs I guess this is how github renders the tabs, indentation looks right on my IDE though

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, even if it's not conforming to our standard, i'd leave this as is so it's easier to manage upstream changes in the cmp (trying to touch as little of the core of the project as possible)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

<span class={style.argumentType}>gdprApplies (Boolean)</span>:
<span class={style.argumentDescription}>
Indicates that the publisher has configured the CMP to apply GDPR. This flag does not change the behavior of the CMP.
</span>
</span>
<span class={style.argument}>
<span class={style.argumentType}>gdprAppliesGlobally (Boolean)</span>:
<span class={style.argumentDescription}>
Indicates that the publisher has configured the CMP to apply GDPR to all (including non-EU) visitors.
This flag does not change the behavior of the CMP.
</span>
</span>
<span class={style.argument}>
<span class={style.argumentType}>theme (Object)</span>:
<span class={style.argumentDescription}>
Expand Down
2 changes: 1 addition & 1 deletion src/docs/lib/stub.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ function buildScript(config, cmpLocation='../cmp.bundle.js') {
if (command === 'ping') {
if (callback) {
callback({
gdprAppliesGlobally: !!(window.__cmp && window.__cmp.config && window.__cmp.config.storeConsentGlobally),
gdprAppliesGlobally: !!(window.__cmp && window.__cmp.config && window.__cmp.config.gdprAppliesGlobally),
cmpLoaded: false
});
}
Expand Down
76 changes: 53 additions & 23 deletions src/lib/cmp.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import log from './log';
import config from './config';
import { encodeVendorConsentData } from './cookie/cookie';
import {
encodeVendorConsentData,
encodePublisherConsentData
} from './cookie/cookie';
encodeVendorCookieValue,
encodePublisherCookieValue
} from "./cookie/cookieutils";

export const CMP_GLOBAL_NAME = '__cmp';
export const CMP_CALL_NAME = CMP_GLOBAL_NAME + 'Call';
Expand All @@ -30,17 +31,26 @@ export default class Cmp {
const {
persistedPublisherConsentData,
persistedVendorConsentData,
vendorList,
customPurposeList
} = this.store;

// Encode limited fields for "metadata"
const metadata = encodePublisherCookieValue({
...persistedPublisherConsentData,
...persistedVendorConsentData,
}, [
'cookieVersion',
'created',
'lastUpdated',
'cmpId',
'cmpVersion',
'consentScreen',
'consentLanguage',
'vendorListVersion',
'publisherPurposeVersion'
]);

const consent = {
metadata: encodePublisherConsentData({
...persistedPublisherConsentData,
...persistedVendorConsentData,
vendorList,
customPurposeList
}),
metadata,
gdprApplies: config.gdprApplies,
hasGlobalScope: config.storeConsentGlobally,
...this.store.getPublisherConsentsObject()
Expand All @@ -53,8 +63,22 @@ export default class Cmp {
* @param {Array} vendorIds Array of vendor IDs to retrieve. If empty return all vendors.
*/
getVendorConsents: (vendorIds, callback = () => {}) => {

// Encode limited fields for "metadata"
const { persistedVendorConsentData } = this.store;
const metadata = persistedVendorConsentData && encodeVendorCookieValue(persistedVendorConsentData, [
'cookieVersion',
'created',
'lastUpdated',
'cmpId',
'cmpVersion',
'consentScreen',
'consentLanguage',
'vendorListVersion',
]);

const consent = {
metadata: this.generateConsentString(),
metadata,
gdprApplies: config.gdprApplies,
hasGlobalScope: config.storeConsentGlobally,
...this.store.getVendorConsentsObject(vendorIds)
Expand All @@ -79,8 +103,8 @@ export default class Cmp {
* Get the entire vendor list
*/
getVendorList: (vendorListVersion, callback = () => {}) => {
const {vendorList} = this.store;
const {vendorListVersion: listVersion} = vendorList || {};
const { vendorList } = this.store;
const { vendorListVersion: listVersion } = vendorList || {};
if (!vendorListVersion || vendorListVersion === listVersion) {
callback(vendorList, true);
}
Expand All @@ -91,7 +115,7 @@ export default class Cmp {

ping: (_, callback = () => {}) => {
const result = {
gdprAppliesGlobally: config.storeConsentGlobally,
gdprAppliesGlobally: config.gdprAppliesGlobally,
cmpLoaded: true
};
callback(result, true);
Expand All @@ -108,10 +132,10 @@ export default class Cmp {

// Trigger load events immediately if they have already occurred
if (event === 'isLoaded' && this.isLoaded) {
callback({event});
callback({ event });
}
if (event === 'cmpReady' && this.cmpReady) {
callback({event});
callback({ event });
}
},

Expand Down Expand Up @@ -182,7 +206,7 @@ export default class Cmp {
if (queue.length) {
log.info(`Process ${queue.length} queued commands`);
this.commandQueue = [];
queue.forEach(({callId, command, parameter, callback, event}) => {
queue.forEach(({ callId, command, parameter, callback, event }) => {
// If command is queued with an event we will relay its result via postMessage
if (event) {
this.processCommand(command, parameter, returnValue =>
Expand All @@ -205,12 +229,18 @@ export default class Cmp {
* Handle a message event sent via postMessage to
* call `processCommand`
*/
receiveMessage = ({data, origin, source}) => {
const {[CMP_CALL_NAME]: cmp} = data;
receiveMessage = ({ data, origin, source }) => {
const { [CMP_CALL_NAME]: cmp } = data;
if (cmp) {
const {callId, command, parameter} = cmp;
const { callId, command, parameter } = cmp;
this.processCommand(command, parameter, returnValue =>
source.postMessage({[CMP_RETURN_NAME]: {callId, command, returnValue}}, origin));
source.postMessage({
[CMP_RETURN_NAME]: {
callId,
command,
returnValue
}
}, origin));
}
};

Expand Down Expand Up @@ -251,7 +281,7 @@ export default class Cmp {
log.info(`Notify event: ${event}`);
const eventSet = this.eventListeners[event] || new Set();
eventSet.forEach(listener => {
listener({event, data});
listener({ event, data });
});

// Process any queued commands that were waiting for consent data
Expand Down
1 change: 1 addition & 0 deletions src/lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const defaultConfig = {
localization: {},
forceLocale: null,
gdprApplies: true,
gdprAppliesGlobally: false,
allowedVendorIds: null,
theme: {}
};
Expand Down
34 changes: 22 additions & 12 deletions src/lib/cookie/cookieutils.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ function decodeFields({ input, fields, startPosition = 0 }) {
* either `selectedVendorIds` or the `vendorRangeList` depending on
* the value of the `isRange` flag.
*/
function encodeDataToBits(data, definitionMap) {
function encodeDataToBits(data, definitionMap, includeFields) {
const { cookieVersion } = data;

if (typeof cookieVersion !== 'number') {
Expand All @@ -218,7 +218,12 @@ function encodeDataToBits(data, definitionMap) {
log.error(`Could not find definition to encode cookie version ${cookieVersion}`);
}
else {
const cookieFields = definitionMap[cookieVersion].fields;
let cookieFields = definitionMap[cookieVersion].fields;

// Filter the set of fields to encode if "includeFields" is provided
if (includeFields && includeFields instanceof Array) {
cookieFields = cookieFields.filter(({name}) => includeFields.indexOf(name) > -1);
}
return encodeFields({ input: data, fields: cookieFields });
}
}
Expand All @@ -227,8 +232,8 @@ function encodeDataToBits(data, definitionMap) {
* Take all fields required to encode the cookie and produce the
* URL safe Base64 encoded value.
*/
function encodeCookieValue(data, definitionMap) {
const binaryValue = encodeDataToBits(data, definitionMap);
function encodeCookieValue(data, definitionMap, includeFields) {
const binaryValue = encodeDataToBits(data, definitionMap, includeFields);
if (binaryValue) {

// Pad length to multiple of 8
Expand All @@ -248,8 +253,8 @@ function encodeCookieValue(data, definitionMap) {
}
}

function encodeVendorCookieValue(vendorData) {
return encodeCookieValue(vendorData, vendorVersionMap);
function encodeVendorCookieValue(vendorData, includeFields) {
return encodeCookieValue(vendorData, vendorVersionMap, includeFields);
}

function encodePublisherCookieValue(publisherData) {
Expand All @@ -260,7 +265,7 @@ function encodePublisherCookieValue(publisherData) {
/**
* Decode the (URL safe Base64) value of a cookie into an object.
*/
function decodeCookieValue(cookieValue, definitionMap) {
function decodeCookieValue(cookieValue, definitionMap, includeFields) {

// Replace safe characters
const unsafe = cookieValue
Expand All @@ -275,10 +280,10 @@ function decodeCookieValue(cookieValue, definitionMap) {
inputBits += padLeft(bitString, 8 - bitString.length);
}

return decodeCookieBitValue(inputBits, definitionMap);
return decodeCookieBitValue(inputBits, definitionMap, includeFields);
}

function decodeCookieBitValue(bitString, definitionMap) {
function decodeCookieBitValue(bitString, definitionMap, includeFields) {
const cookieVersion = decodeBitsToInt(bitString, 0, NUM_BITS_VERSION);
if (typeof cookieVersion !== 'number') {
log.error('Could not find cookieVersion to decode');
Expand All @@ -288,14 +293,19 @@ function decodeCookieBitValue(bitString, definitionMap) {
log.error(`Could not find definition to decode cookie version ${cookieVersion}`);
return {};
}
const cookieFields = definitionMap[cookieVersion].fields;
let cookieFields = definitionMap[cookieVersion].fields;

// Filter the set of fields to decode if "includeFields" is provided
if (includeFields && includeFields instanceof Array) {
cookieFields = cookieFields.filter(({name}) => includeFields.indexOf(name) > -1);
}
const { decodedObject } = decodeFields({ input: bitString, fields: cookieFields });
return decodedObject;
}


function decodeVendorCookieValue(cookieValue) {
return decodeCookieValue(cookieValue, vendorVersionMap);
function decodeVendorCookieValue(cookieValue, includeFields) {
return decodeCookieValue(cookieValue, vendorVersionMap, includeFields);
}

function decodePublisherCookieValue(cookieValue) {
Expand Down
40 changes: 40 additions & 0 deletions src/lib/cookie/cookieutils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -265,4 +265,44 @@ describe('cookieutils', () => {

expect(decoded).to.deep.equal(consentData);
});


it('encodes and decodes only a subset of vendor fields', () => {

const aDate = new Date('2018-07-15 PDT');

const consentData = {
cookieVersion: 1,
created: aDate,
lastUpdated: aDate,
cmpId: 1,
cmpVersion: 1,
consentScreen: 1,
consentLanguage: 'EN',
vendorListVersion: 1,
purposeIdBitString: '000000001010101010001100',
maxVendorId: 5,
isRange: false,
vendorIdBitString: '10011',
};

const includeFields = [
'cookieVersion',
'created',
'lastUpdated',
'cmpId',
'vendorListVersion'
];

const bitString = encodeVendorCookieValue(consentData, includeFields);
const decoded = decodeVendorCookieValue(bitString, includeFields);

expect(decoded).to.deep.equal({
cookieVersion: 1,
created: aDate,
lastUpdated: aDate,
cmpId: 1,
vendorListVersion: 1
});
});
});
Loading