Skip to content

Commit

Permalink
remove cookies when consent is revoked #65
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonas Eberle committed Jan 10, 2020
1 parent ddef031 commit e1650d6
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 23 deletions.
2 changes: 1 addition & 1 deletion Documentation/Index.rst
Expand Up @@ -32,7 +32,7 @@ Cookieman

A GDPR tracking consent popup. It asks for approval to include tracking objects (cookies, images or any HTML) and includes the objects when consented.
It enables tracking from the very first page (including referrer). Consents are shown in groups and saved to a cookie.
It provides a stable API to read out consents with JavaScript.
It provides a stable API to read out consents with JavaScript. From version 2.3.9+ it removes configured tracking cookies when the user revokes consent.

**TYPO3**

Expand Down
13 changes: 7 additions & 6 deletions Documentation/Introduction/Index.rst
Expand Up @@ -14,6 +14,7 @@ What does it do?
A GDPR tracking consent popup. It asks for approval to include tracking objects (cookies, images or any HTML) and includes the objects when consented.
It enables tracking from the very first page (including referrer). Consents are shown in groups and saved to a cookie.
It provides a stable API to read out consents with JavaScript.
From version 2.3.9+ it removes configured tracking cookies when the user revokes consent.


.. _when-is-it-shown:
Expand All @@ -36,13 +37,13 @@ The page UIDs can be set in TypoScript. This also allows to link to these pages
Features
--------

* Cookies: **Render detailed information** about your cookies: Name, Purpose, Lifetime, Type, Provider
* Cookies: Commonly used cookies are **already supported** with configuration and information text
* Cookies: **Add, sort or remove cookies** as needed
* Groups: **Sort your cookies into groups** (e.g. "Mandatory", "Marketing", "Analytics")
* Groups: **Add or remove groups** as needed
* Tracking objects: Render detailed information about your cookies, tracking pixels, LocalStorage entries...: Name, Purpose, Lifetime, Type, Provider
* Tracking objects: Commonly used tracking objects are already supported with configuration and information text
* Tracking objects: Extendable as needed
* Tracking objects: HTML Cookies will be removed from the user's browser
* Groups: **Group your tracking objects** (e.g. "Mandatory", "Marketing", "Analytics")
* Groups: **Preselect and/or disable groups**, e.g. the group for mandatory technical cookies
* A note about the **"Do-not-track"** setting can be shown inside the popup
* A note about the **"Do-not-track"** setting can be shown inside the popup and this setting can also be respected (configurable on a per-group level)

* The extension includes **3 ready-made themes** based on Bootstrap
* **Customization:** Fluid templates and all texts can be adjusted to your needs
Expand Down
86 changes: 72 additions & 14 deletions Resources/Public/Js/cookieman.js
Expand Up @@ -49,6 +49,16 @@ var cookieman = (function () {
}
}

function hasConsented(groupKey) {
var consented = consentedSelectionsRespectDnt()
for (var i = 0; i < consented.length; i++) {
if (consented[i] === groupKey) {
return true
}
}
return false
}

function consentedSelectionsAll() {
var cookie = Cookies.get(cookieName)
return cookie ? cookie.split('|') : []
Expand Down Expand Up @@ -81,6 +91,7 @@ var cookieman = (function () {
e.preventDefault()
saveSelections()
cookieman.hide()
removeDisabledTrackingObjects()
injectNewTrackingObjects()
}

Expand All @@ -101,7 +112,7 @@ var cookieman = (function () {
/**
* inject the HTML for a given tracking object
* @param trackingObjectKey string e.g. 'Matomo'
* @param trackingObjectSettings array (e.g. the array plugin.tx_cookieman.settings.trackingObjects.Matomo
* @param trackingObjectSettings object (e.g. the array plugin.tx_cookieman.settings.trackingObjects.Matomo
* from TypoScript)
*/
function injectTrackingObject(trackingObjectKey, trackingObjectSettings) {
Expand Down Expand Up @@ -162,15 +173,70 @@ var cookieman = (function () {
}
}

/**
* remove tracking objects that are not consented.
* See removeTrackingObjectItem() for supported types.
*/
function removeDisabledTrackingObjects() {
for (var groupKey in settings.groups) {
if (!Object.prototype.hasOwnProperty.call(settings.groups, groupKey)) {
continue
}

if (!hasConsented(groupKey)) {
var oGroup = settings.groups[groupKey]
for (var _j = 0; _j < oGroup.trackingObjects.length; _j++) {
var trackingObjectKey = oGroup.trackingObjects[_j]
removeTrackingObject(trackingObjectKey, settings.trackingObjects[trackingObjectKey])
}
}
}
}

/**
* remove a given tracking object
* See removeTrackingObjectItem() for supported types.
* @param trackingObjectKey string e.g. 'Matomo'
* @param trackingObjectSettings object (e.g. the array plugin.tx_cookieman.settings.trackingObjects.Matomo
* from TypoScript)
*/
function removeTrackingObject(trackingObjectKey, trackingObjectSettings) {
for (var itemKey in trackingObjectSettings.show) {
if (!Object.prototype.hasOwnProperty.call(trackingObjectSettings.show, itemKey)) {
continue
}
var oItem = trackingObjectSettings.show[itemKey]

removeTrackingObjectItem(itemKey, oItem)
}
}

/**
* remove a given single tracking object item
* Supported types: cookie_http+html
* @param itemKey string, e.g. '_ga'
* @param oItem object the settings for a single item (e.g. the array
* plugin.tx_cookieman.settings.trackingObjects.GoogleAnalytics.show._ga from TypoScript)
* @return boolean successful?
*/
function removeTrackingObjectItem(itemKey, oItem) {
if (oItem.type === 'cookie_http+html') {
Cookies.remove(itemKey)
return true
}
// unsupported type
return false
}

/**
* inject not-yet-injected tracking objects if consented and matching DNT constraints
*/
function injectNewTrackingObjects() {
var consenteds = consentedSelectionsRespectDnt()
for (var _i = 0; _i < consenteds.length; _i++) {
var aGroup = settings.groups[consenteds[_i]]
for (var _j = 0; _j < aGroup.trackingObjects.length; _j++) {
var trackingObjectKey = aGroup.trackingObjects[_j]
var oGroup = settings.groups[consenteds[_i]]
for (var _j = 0; _j < oGroup.trackingObjects.length; _j++) {
var trackingObjectKey = oGroup.trackingObjects[_j]
if (injectedTrackingObjects.indexOf(trackingObjectKey) === -1) {
injectTrackingObject(trackingObjectKey, settings.trackingObjects[trackingObjectKey])
}
Expand Down Expand Up @@ -251,15 +317,7 @@ var cookieman = (function () {
* @param {string} groupKey
* @returns {boolean}
*/
hasConsented: function (groupKey) {
var consented = consentedSelectionsRespectDnt()
for (var i = 0; i < consented.length; i++) {
if (consented[i] === groupKey) {
return true
}
}
return false
},
hasConsented: hasConsented,
/**
* @api
*/
Expand All @@ -280,7 +338,7 @@ var cookieman = (function () {
// attach ourselves to the "scriptLoaded" event
eventsEl.addEventListener(
'scriptLoaded',
function(ev) {
function (ev) {
if (ev.detail.trackingObjectKey === trackingObjectKey && ev.detail.scriptId === scriptId) {
callback(ev.detail.trackingObjectKey, ev.detail.scriptId)
}
Expand Down
2 changes: 1 addition & 1 deletion Resources/Public/Js/cookieman.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 15 additions & 1 deletion Tests/Acceptance/Frontend/PopupInteractionsCest.php
Expand Up @@ -180,8 +180,19 @@ public function reopenAndRevoke(AcceptanceTester $I)
),
['path' => self::PATH_ROOT]
);

// set a cookie that is configured as tracking object and of type HTML
$I->setCookie(
self::COOKIE_TITLE_IN_2ND_GROUP,
'someValue',
[
'path' => self::PATH_ROOT,
'httpOnly' => false,
]
);
$I->reloadPage();
$I->wait(0.5);
$I->seeCookie(self::COOKIE_TITLE_IN_2ND_GROUP);
$I->dontSeeElement(self::SELECTOR_MODAL);
$I->executeJS(self::JS_SHOWONCE_COOKIEMAN);
$I->wait(0.5);
Expand All @@ -199,7 +210,10 @@ public function reopenAndRevoke(AcceptanceTester $I)
$I->dontSeeCheckboxIsChecked('[name=' . self::GROUP_KEY_2ND . ']');
$I->click('Save');
$I->waitForElementNotVisible(self::SELECTOR_MODAL);
$I->seeCookie(self::COOKIENAME);

// cookieman should have deleted this non-consented cookie
$I->dontSeeCookie(self::COOKIE_TITLE_IN_2ND_GROUP);

$I->assertEquals(
$this->cookieValueForGroups([self::GROUP_KEY_MANDATORY]),
$I->grabCookie(self::COOKIENAME, ['path' => self::PATH_ROOT])
Expand Down

0 comments on commit e1650d6

Please sign in to comment.