From 1b1464ff40e779a2204172bba125d17b2056214c Mon Sep 17 00:00:00 2001 From: Stefan Bohacek Date: Mon, 29 Jul 2024 08:22:37 -0400 Subject: [PATCH] Added privacy law compliance mechanism. --- README.md | 21 ++++++++++++++++++--- fediverse-share-button/script.js | 14 ++++++++++---- fediverse-share-button/script.min.js | 2 +- index.html | 1 - 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index bd2eca2..c268839 100644 --- a/README.md +++ b/README.md @@ -68,11 +68,26 @@ My sharing button [detects the software](https://github.com/stefanbohacek/fedive Threads are *technically* supported, but they don't currently provide software information, so the URL won't be recognized. -### Q: Does this button or the fediverse-info server collect any information? +### Q: Does this widget or the fediverse-info server collect any information? Does it comply with data privacy laws? (eg GDPR) -None at all. The [fediverse-info](https://github.com/stefanbohacek/fediverse-info) server is only needed to cache the software information for each domain as not to overwhelm the original server with too many requests. +The sharing widget uses [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) to store two pieces of information: -The last domain used in the domain input field and the fediverse software it's running are both stored in the [site visitor's browser](https://en.wikipedia.org/wiki/Web_storage) so that when they view another page, or visit the site again later, this information can be reused. +- `fsb-domain`: used to store the last **domain name** used in the sharing widget (eg. "mastodon.social", "pixelfed.social", etc) +- `fsb-software`: used to store the **software** used by the selected fediverse server (eg. "mastodon", "pixelfed") + +When stored, this information is used to prefill the widget form upon next visit. + +To prevent this information from being stored, you can set the value of `fsb-consent-given` to `"false"` before loading the main JavaScript file. + +```html + +``` + +Using any other value, or the lack of presence of it, will be interpreted as a consent to store and retrieve the information detailed above. Please consult any applicable laws to determine whether consent is required for this functionality. + +The [fediverse-info](https://github.com/stefanbohacek/fediverse-info) server is only needed to cache the software information for each domain as not to overwhelm the original server with too many requests. This information is not tied specifically to your site's visitor. ### Q: Are there any similar projects? diff --git a/fediverse-share-button/script.js b/fediverse-share-button/script.js index 6ef289f..427ab30 100644 --- a/fediverse-share-button/script.js +++ b/fediverse-share-button/script.js @@ -1,4 +1,8 @@ (async () => { + // Privacy law compliance. + + const canUseLocalStorage = localStorage.getItem("fsb-consent-given") !== "false" ? true : false; + // List of suported fediverse software. const knownSoftware = [ @@ -111,7 +115,7 @@ el.dataset.software = software; - if (software) { + if (software && canUseLocalStorage) { localStorage.setItem("fsb-software", software); } @@ -173,8 +177,8 @@ let typingTimer; const doneTypingInterval = 1300; - const savedDomain = localStorage.getItem("fsb-domain"); - const savedSoftware = localStorage.getItem("fsb-software"); + const savedDomain = canUseLocalStorage ? localStorage.getItem("fsb-domain") : false; + const savedSoftware = canUseLocalStorage ? localStorage.getItem("fsb-software") : false; [...document.getElementsByClassName("fsb-prompt")].forEach((fsbPrompt) => { const domainInput = fsbPrompt.getElementsByClassName("fsb-domain")[0]; @@ -209,7 +213,9 @@ if (domain?.length) { const shareText = getSelectedText() || getPageTitle(); - localStorage.setItem("fsb-domain", domain); + if (canUseLocalStorage){ + localStorage.setItem("fsb-domain", domain); + } let shareURL = `https://${domain}/share?text=${ // getPageTitle() + " " + getPageURL() diff --git a/fediverse-share-button/script.min.js b/fediverse-share-button/script.min.js index 0bfee73..f31c468 100644 --- a/fediverse-share-button/script.min.js +++ b/fediverse-share-button/script.min.js @@ -1 +1 @@ -(async()=>{const knownSoftware=["calckey","diaspora","ecko","firefish","friendica","glitch-soc","gnu_social","gotosocial","groundpolis","hometown","hubzilla","kepi","lemmy","mastodon","misskey","misty","osada","peertube","pixelfed","pleroma","sharkey","socialhome","threads","wordpress","xmpp","zap"];const supportedSoftware=["diaspora","firefish","friendica","glitch-soc","hometown","hubzilla","lemmy","mastodon","misskey","sharkey","threads"];const getFSBPath=()=>{var scripts=document.getElementsByClassName("fsb-script")[0];src=scripts.src;return src.replace("/script.min.js","")};const updateTheIcon=(iconElement,software)=>{const domainInput=iconElement.parentElement.parentElement.parentElement.getElementsByClassName("fsb-domain")[0];const supportNote=iconElement.parentElement.parentElement.parentElement.getElementsByClassName("fsb-support-note")[0];const supportNoteLink=iconElement.parentElement.parentElement.parentElement.getElementsByClassName("fsb-support-note-link")[0];iconElement.src=`${getFSBPath()}/icons/${software}.svg`;iconElement.alt=`${software} platform logo`;supportNote.classList.add("fsb-d-none");if(domainInput.value&&domainInput.value.trim().length>0&&!supportedSoftware.includes(software)){supportNoteLink.href=`https://${domainInput.value}`;supportNoteLink.innerHTML=domainInput.value;supportNote.classList.remove("fsb-d-none")}};const updateIcon=async domainInput=>{clearTimeout(typingTimer);if(domainInput.value){typingTimer=setTimeout((()=>{doneTyping(domainInput)}),doneTypingInterval)}else{const iconEl=domainInput.parentElement.getElementsByClassName("fsb-icon")[0];updateTheIcon(iconEl,"mastodon")}};const doneTyping=async el=>{const shareBtn=el.parentElement.getElementsByClassName("fsb-button")[0];const domain=getDomain(el.value);shareBtn.disabled=true;const resp=await fetch(`https://fediverse-info.stefanbohacek.dev/node-info?domain=${domain}`);const respJSON=await resp.json();const software=respJSON?.software?.name;const iconEl=el.parentElement.getElementsByClassName("fsb-icon")[0];el.dataset.software=software;if(software){localStorage.setItem("fsb-software",software)}if(software&&knownSoftware.includes(software)){updateTheIcon(iconEl,software)}else{updateTheIcon(iconEl,"question")}shareBtn.disabled=false};const getPageTitle=()=>{let pageTitle=document.title;try{pageTitle=document.querySelector("meta[property='og:title']").getAttribute("content")}catch(error){}return encodeURIComponent(pageTitle)};const getPageDescription=()=>{let pageDescription="";const metaDescription=document.querySelector("meta[name='description']")||document.querySelector("meta[property='og:description']")||null;if(metaDescription&&metaDescription.getAttribute){pageDescription=metaDescription.getAttribute("content")}return encodeURIComponent(pageDescription)};const getPageURL=()=>encodeURIComponent(window.location.href);const getDomain=str=>str.replace(/(^\w+:|^)\/\//,"");const truncate=input=>input.length>5?`${input.substring(0,450)}...`:input;const getSelectedText=()=>{let text="";if(window.getSelection){text=window.getSelection().toString()}else if(document.selection&&document.selection.type!="Control"){text=document.selection.createRange().text}return truncate(text)};let typingTimer;const doneTypingInterval=1300;const savedDomain=localStorage.getItem("fsb-domain");const savedSoftware=localStorage.getItem("fsb-software");[...document.getElementsByClassName("fsb-prompt")].forEach((fsbPrompt=>{const domainInput=fsbPrompt.getElementsByClassName("fsb-domain")[0];const shareBtn=fsbPrompt.getElementsByClassName("fsb-button")[0];if(savedDomain){domainInput.value=savedDomain;if(savedSoftware){domainInput.dataset.software=savedSoftware;const iconEl=domainInput.parentElement.getElementsByClassName("fsb-icon")[0];updateTheIcon(iconEl,savedSoftware)}else{updateIcon(domainInput)}}domainInput.addEventListener("input",(()=>{updateIcon(domainInput)}));domainInput.addEventListener("change",(()=>{}));fsbPrompt.addEventListener("submit",(ev=>{ev.preventDefault();const domain=getDomain(domainInput?.value?.trim());if(domain?.length){const shareText=getSelectedText()||getPageTitle();localStorage.setItem("fsb-domain",domain);let shareURL=`https://${domain}/share?text=${shareText+"%0A%0A"+getPageURL()}`;if(domainInput?.dataset?.software){if(["diaspora","friendica"].includes(domainInput.dataset.software)){shareURL=`https://${domain}/bookmarklet?url=${getPageURL()}&title=${shareText}¬e=${getPageDescription()}`}else if(domainInput.dataset.software==="hubzilla"){shareURL=`https://${domain}/rpost?url=${getPageURL()}&body=${shareText}[br][br]`}else if(domainInput.dataset.software==="threads"){shareURL=`https://${domain}/intent/post?text=${shareText+"%0A%0A"+getPageURL()}`}}window.location.assign(shareURL)}}))}))})(); +(async()=>{const canUseLocalStorage=localStorage.getItem("fsb-consent-given")!=="false"?true:false;const knownSoftware=["calckey","diaspora","ecko","firefish","friendica","glitch-soc","gnu_social","gotosocial","groundpolis","hometown","hubzilla","kepi","lemmy","mastodon","misskey","misty","osada","peertube","pixelfed","pleroma","sharkey","socialhome","threads","wordpress","xmpp","zap"];const supportedSoftware=["diaspora","firefish","friendica","glitch-soc","hometown","hubzilla","lemmy","mastodon","misskey","sharkey","threads"];const getFSBPath=()=>{var scripts=document.getElementsByClassName("fsb-script")[0];src=scripts.src;return src.replace("/script.min.js","")};const updateTheIcon=(iconElement,software)=>{const domainInput=iconElement.parentElement.parentElement.parentElement.getElementsByClassName("fsb-domain")[0];const supportNote=iconElement.parentElement.parentElement.parentElement.getElementsByClassName("fsb-support-note")[0];const supportNoteLink=iconElement.parentElement.parentElement.parentElement.getElementsByClassName("fsb-support-note-link")[0];iconElement.src=`${getFSBPath()}/icons/${software}.svg`;iconElement.alt=`${software} platform logo`;supportNote.classList.add("fsb-d-none");if(domainInput.value&&domainInput.value.trim().length>0&&!supportedSoftware.includes(software)){supportNoteLink.href=`https://${domainInput.value}`;supportNoteLink.innerHTML=domainInput.value;supportNote.classList.remove("fsb-d-none")}};const updateIcon=async domainInput=>{clearTimeout(typingTimer);if(domainInput.value){typingTimer=setTimeout((()=>{doneTyping(domainInput)}),doneTypingInterval)}else{const iconEl=domainInput.parentElement.getElementsByClassName("fsb-icon")[0];updateTheIcon(iconEl,"mastodon")}};const doneTyping=async el=>{const shareBtn=el.parentElement.getElementsByClassName("fsb-button")[0];const domain=getDomain(el.value);shareBtn.disabled=true;const resp=await fetch(`https://fediverse-info.stefanbohacek.dev/node-info?domain=${domain}`);const respJSON=await resp.json();const software=respJSON?.software?.name;const iconEl=el.parentElement.getElementsByClassName("fsb-icon")[0];el.dataset.software=software;if(software&&canUseLocalStorage){localStorage.setItem("fsb-software",software)}if(software&&knownSoftware.includes(software)){updateTheIcon(iconEl,software)}else{updateTheIcon(iconEl,"question")}shareBtn.disabled=false};const getPageTitle=()=>{let pageTitle=document.title;try{pageTitle=document.querySelector("meta[property='og:title']").getAttribute("content")}catch(error){}return encodeURIComponent(pageTitle)};const getPageDescription=()=>{let pageDescription="";const metaDescription=document.querySelector("meta[name='description']")||document.querySelector("meta[property='og:description']")||null;if(metaDescription&&metaDescription.getAttribute){pageDescription=metaDescription.getAttribute("content")}return encodeURIComponent(pageDescription)};const getPageURL=()=>encodeURIComponent(window.location.href);const getDomain=str=>str.replace(/(^\w+:|^)\/\//,"");const truncate=input=>input.length>5?`${input.substring(0,450)}...`:input;const getSelectedText=()=>{let text="";if(window.getSelection){text=window.getSelection().toString()}else if(document.selection&&document.selection.type!="Control"){text=document.selection.createRange().text}return truncate(text)};let typingTimer;const doneTypingInterval=1300;const savedDomain=canUseLocalStorage?localStorage.getItem("fsb-domain"):false;const savedSoftware=canUseLocalStorage?localStorage.getItem("fsb-software"):false;[...document.getElementsByClassName("fsb-prompt")].forEach((fsbPrompt=>{const domainInput=fsbPrompt.getElementsByClassName("fsb-domain")[0];const shareBtn=fsbPrompt.getElementsByClassName("fsb-button")[0];if(savedDomain){domainInput.value=savedDomain;if(savedSoftware){domainInput.dataset.software=savedSoftware;const iconEl=domainInput.parentElement.getElementsByClassName("fsb-icon")[0];updateTheIcon(iconEl,savedSoftware)}else{updateIcon(domainInput)}}domainInput.addEventListener("input",(()=>{updateIcon(domainInput)}));domainInput.addEventListener("change",(()=>{}));fsbPrompt.addEventListener("submit",(ev=>{ev.preventDefault();const domain=getDomain(domainInput?.value?.trim());if(domain?.length){const shareText=getSelectedText()||getPageTitle();if(canUseLocalStorage){localStorage.setItem("fsb-domain",domain)}let shareURL=`https://${domain}/share?text=${shareText+"%0A%0A"+getPageURL()}`;if(domainInput?.dataset?.software){if(["diaspora","friendica"].includes(domainInput.dataset.software)){shareURL=`https://${domain}/bookmarklet?url=${getPageURL()}&title=${shareText}¬e=${getPageDescription()}`}else if(domainInput.dataset.software==="hubzilla"){shareURL=`https://${domain}/rpost?url=${getPageURL()}&body=${shareText}[br][br]`}else if(domainInput.dataset.software==="threads"){shareURL=`https://${domain}/intent/post?text=${shareText+"%0A%0A"+getPageURL()}`}}window.location.assign(shareURL)}}))}))})(); diff --git a/index.html b/index.html index ff3ae60..ed4908a 100644 --- a/index.html +++ b/index.html @@ -82,7 +82,6 @@ href="https://stefanbohacek.com/">Stefan Bohacek. -