1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2025-03-30 15:26:55 +00:00

Consent banner: Add optional blocking of embedded content until consent granted

This commit is contained in:
jeremy@jermolene.com 2020-07-02 13:14:51 +01:00
parent bd2cf5c464
commit a0db3abe99
10 changed files with 127 additions and 8 deletions

@ -0,0 +1,13 @@
title: $:/plugins/tiddlywiki/consent-banner/blocked-embed-message-wrapper
\define styles()
width:$(width)$;height:$(height)$;
\end
<div class="tc-blocked-embedded-content" style=<<styles>>>
<div class="tc-blocked-embedded-content-inner">
<div class="tc-blocked-embedded-content-inner-inner">
<$transclude tiddler="$:/config/plugins/tiddlywiki/consent-banner/blocked-embed-message" mode="inline"/>
</div>
</div>
</div>

@ -40,3 +40,9 @@ Current status: {{$:/state/consent-banner/accepted}} (blank indicates that conse
<$button message="tm-consent-clear" tooltip={{$:/config/plugins/tiddlywiki/consent-banner/buttons/clear/hint}}>
{{$:/config/plugins/tiddlywiki/consent-banner/buttons/clear/caption}}
</$button>
! Embedded Content Blocking
//Requires page reload//
<$checkbox tiddler="$:/config/plugins/tiddlywiki/consent-banner/block-embedded-content" field="text" checked="yes" unchecked="no" default="no"> Block all embedded content such as &lt;iframe>, &lt;embed> and &lt;object> unless consent has been granted</$checkbox>

@ -0,0 +1,2 @@
title: $:/config/plugins/tiddlywiki/consent-banner/block-embedded-content
text: yes

@ -0,0 +1,7 @@
title: $:/config/plugins/tiddlywiki/consent-banner/blocked-embed-message
Blocked embedded content from<br/><a href=<<url>> class="tc-tiddlylink-external" target="_blank" rel="noopener noreferrer"><$text text=<<url>>/></a>
<hr/>
{{$:/plugins/tiddlywiki/consent-banner/buttons/accept}} cookies to unblock

@ -0,0 +1,4 @@
title: $:/plugins/tiddlywiki/consent-banner/tv-block-embedded-content
tags: $:/tags/Macro
<$set name="tv-block-embedded-content" value={{{ [{$:/config/cookie-consent-required}else[no]match[yes]then{$:/state/consent-banner/accepted}!match[yes]then[yes]] }}}/>

@ -24,6 +24,16 @@ Add these entries to your current colour palette to change the colours used by t
* ''consent-banner-hr-background'' - the background colour of horizontal rules within the consent banner (defaults to {{$:/config/DefaultColourMappings/consent-banner-hr-background}})
* ''consent-banner-link-foreground'' - the foreground colour of tiddler links within the consent banner (defaults to {{$:/config/DefaultColourMappings/consent-banner-link-foreground}})
! Embedded Content Blocking
Unless disabled via the config tab, content embedded via &lt;iframe>, &lt;embed> or &lt;object> is blocked until the user consents to accept cookies.
!! Implementation Details
Embedded content is blocked if the variable `tv-block-embedded-content` is set to `yes`. It is set to the current consent status by a [[global macro|$:/plugins/tiddlywiki/consent-banner/tv-block-embedded-content]]:
<$codeblock code={{$:/plugins/tiddlywiki/consent-banner/tv-block-embedded-content}}/>
! ~YouTube macro
A simple macro for embedding ~YouTube videos is provided to show how to adapt content according to whether consent has been granted. It works by checking the tiddler [[$:/state/consent-banner/accepted]] for the following values:

@ -1,6 +1,10 @@
title: $:/plugins/tiddlywiki/consent-banner/readme
The ''consent-banner'' plugin helps make websites that are compliant with "cookie legislation" such as the [[EU General Data Protection Regulation|https://gdpr.eu/cookies/]].
This plugin presents a banner inviting the user to accept or reject cookies, keeping track of their consent in local storage so that the banner can be hidden on subsequent visits. Consent status is also available via a configuration tiddler so that it is possible to construct content that behaves differently depending upon whether consent has been granted. As an example, a macro is provided for embedding ~YouTube videos that automatically uses the youtube-nocookie.com variant of video URLs unless the user has accepted cookies.
It presents a banner inviting the user to accept or reject cookies, keeping track of their consent in local storage so that the banner can be hidden on subsequent visits.
By default, content embedded with &lt;iframe>, &lt;embed> and &lt;object> is blocked unless the user consents to accept cookies.
Consent status is available via a configuration tiddler so that it is possible to construct content that behaves differently depending upon whether consent has been granted. As an example, a macro is provided for embedding ~YouTube videos that automatically uses the youtube-nocookie.com variant of video URLs unless the user has accepted cookies.
Please note that using this plugin does not guarantee compliance with any particular legislation. You will need to understand the technical issues specific to your situation, and if necessary seek legal advice.

@ -16,16 +16,18 @@ Startup initialisation
exports.name = "consent-banner";
exports.platforms = ["browser"];
exports.after = ["startup"];
exports.before = ["render"];
exports.synchronous = true;
var CHECK_CONSENT_INTERVAL = 1000, // Milliseconds between checking local storage
IS_LOGGED_IN_TITLE = "$:/status/IsLoggedIn",
CONSENT_KEY = "COOKIE_CONSENT", // Local storage keyname
CONSENT_TITLE = "$:/state/consent-banner/accepted"; // "": undeclared, "yes": accepted, "no": declined
CONSENT_TITLE = "$:/state/consent-banner/accepted", // "": undeclared, "yes": accepted, "no": declined
CONFIG_BLOCK_EMBEDDED_CONTENT_TITLE = "$:/config/plugins/tiddlywiki/consent-banner/block-embedded-content",
EMBEDDED_MESSAGE_WRAPPER_TITLE = "$:/plugins/tiddlywiki/consent-banner/blocked-embed-message-wrapper";
exports.startup = function() {
var self = this,
consentState = "",
exports.startup = function() {
var consentState = "",
setConsentStatus = function(state) {
if(consentState !== state) {
consentState = state;
@ -51,9 +53,9 @@ exports.startup = function() {
pollConsentStatus = function() {
setTimeout(checkConsentStatus,CHECK_CONSENT_INTERVAL);
};
// Set the current constant status
// Set the current consent status
checkConsentStatus();
// Listen for tm-clear-browser-storage messages
// Listen for consent messages
$tw.rootWidget.addEventListener("tm-consent-accept",function(event) {
setConsentStatus("yes");
});
@ -63,6 +65,43 @@ exports.startup = function() {
$tw.rootWidget.addEventListener("tm-consent-clear",function(event) {
setConsentStatus("");
});
// Add our element rendering hook
if($tw.wiki.getTiddlerText(CONFIG_BLOCK_EMBEDDED_CONTENT_TITLE,"no") === "yes") {
$tw.hooks.addHook("th-rendering-element",function(parseTreeNodes,widget) {
if(parseTreeNodes) {
return parseTreeNodes;
}
if(["iframe","object","embed"].indexOf(widget.tag) !== -1 && widget.getVariable("tv-block-embedded-content","no") === "yes") {
var url = widget.getAttribute("src"),
addUnitsIfMissing = function(str) {
str = "" + str;
return str + (("" + parseInt(str,10)) === str ? "px" : "");
},
width = addUnitsIfMissing(widget.getAttribute("width","")),
height = addUnitsIfMissing(widget.getAttribute("height",""));
return [
{
type: "vars",
attributes: {
url: {type: "string", value: url},
width: {type: "string", value: width},
height: {type: "string", value: height}
},
children: [
{
type: "transclude",
attributes: {
tiddler: {type: "string", value: EMBEDDED_MESSAGE_WRAPPER_TITLE},
mode: {type: "string", value: "inline"}
}
}
]
}
];
}
return null;
});
}
};
})();

@ -56,9 +56,12 @@ tags: $:/tags/Stylesheet
}
.tc-consent-banner .tc-consent-button {
margin-right: 1em;
}
.tc-consent-button {
border: 1px solid <<colour consent-banner-button-border>>;
margin-right: 1em;
margin-top: 1em;
padding: 0.75em 1.5em;
color: <<colour consent-banner-button-foreground>>;
@ -77,3 +80,32 @@ tags: $:/tags/Stylesheet
color: <<colour consent-banner-button-default-foreground>>;
background: <<colour consent-banner-button-default-background>>;
}
.tc-blocked-embedded-content {
display: inline-block;
overflow: hidden;
color: <<colour background>>;
background: <<colour muted-foreground>>;
border: 1px solid <<colour foreground>>;
<<box-shadow "inset 0 0 8px rgba(0, 0, 0, 0.15)">>
}
.tc-blocked-embedded-content-inner {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
}
.tc-blocked-embedded-content-inner-inner {
display: inline-block;
text-align: center;
}
.tc-blocked-embedded-content-inner-inner hr {
background: <<colour foreground>>;
height: 1px;
width: 80%;
border: none;
}

@ -2,12 +2,14 @@ title: $:/plugins/tiddlywiki/consent-banner/youtube
tags: $:/tags/Macro
\define embed-video-with-consent(code)
<$set name="tv-block-embedded-content" value="no">
<$reveal state="$:/state/consent-banner/accepted" type="match" text="yes" tag="div">
<iframe width="560" height="315" src="https://www.youtube.com/embed/$code$" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
</$reveal>
<$reveal state="$:/state/consent-banner/accepted" type="nomatch" text="yes" tag="div">
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/$code$" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
</$reveal>
</$set>
\end
! Macro source