@privacyportal.org/privacy-kit
Version:
Lightweight and FOSS browser library bringing Privacy Portal features to your website users
6 lines (5 loc) • 13.3 kB
JavaScript
/*
MIT License - Copyright (c) 2025 Privacy Portal.
See full license at https://github.com/privacyportal/privacy-kit/LICENSE.
*/
(function(u,s){typeof exports=="object"&&typeof module<"u"?module.exports=s():typeof define=="function"&&define.amd?define(s):(u=typeof globalThis<"u"?globalThis:u||self,u.PrivacyKit=s())})(this,function(){"use strict";var xe=Object.defineProperty;var Pe=(u,s,_)=>s in u?xe(u,s,{enumerable:!0,configurable:!0,writable:!0,value:_}):u[s]=_;var b=(u,s,_)=>Pe(u,typeof s!="symbol"?s+"":s,_);const u={VITE_AUTHORIZATION_URL:"https://app.privacyportal.org/oauth/authorize",VITE_TOKEN_URL:"https://api.privacyportal.org/oauth/token"},{VITE_AUTHORIZATION_URL:s,VITE_TOKEN_URL:_}=u,A={SCOPE:["openid","email"],RESPONSE_TYPE:"code",RESPONSE_MODE:"web_message"},K="Please try again later.";class f extends Error{constructor({message:t}){super(t)}}function g(e){if(e instanceof f)switch(l.onError){case"ignore":break;case"alert":{alert(e.message);break}default:W(l.onError)&&l.onError.error(e.message)}}function W(e){return e!=null&&typeof e=="object"&&typeof e.error=="function"}class G{constructor(){b(this,"_client_id");b(this,"_name_scope_required");b(this,"_onError")}get client_id(){return this._client_id}set client_id(t){this._client_id=t}get onError(){return this._onError}set onError(t){this._onError=t}get name_scope_required(){return this._name_scope_required||!1}set name_scope_required(t){this._name_scope_required=t}get redirect_uri(){return window.location.origin}get authorization_origin(){return new URL(s).origin}get authorization_url_placeholder(){return`${s}?loading`}getNameScopeRequired(t){return(t==null?void 0:t.name_scope_required)!==void 0?t==null?void 0:t.name_scope_required:this.name_scope_required}getScope(t){return[...A.SCOPE,...this.getNameScopeRequired(t)?["name"]:[]].join(" ")}createAuthorizationURL(t,n,i){if(!this.client_id)throw new f({message:"OAuth client_id not configured."});const o=new URLSearchParams;o.set("client_id",this.client_id),o.set("scope",this.getScope(i)),o.set("response_type",A.RESPONSE_TYPE),o.set("response_mode",A.RESPONSE_MODE),o.set("nonce",crypto.randomUUID().substring(4,18)),o.set("redirect_uri",this.redirect_uri),o.set("state",t),o.set("code_challenge",n),o.set("code_challenge_method","S256");const r=new URL(s);return r.search=o.toString(),r.toString()}}const l=new G;function S(e,t){return n=>i=>{var r;const o=t!=null&&t.shadow?(r=i==null?void 0:i.composedPath())==null?void 0:r[0]:i==null?void 0:i.target;if(o)return o[t!=null&&t.closest?"closest":"matches"](e)&&n(o)}}function E(e,t){return e&&t?(e.value=t,e.dispatchEvent(new Event("paste",{bubbles:!0})),e.dispatchEvent(new Event("change",{bubbles:!0})),!0):!1}function p(e){return e.offsetWidth!==0||e.offsetHeight!==0}function R(e){return e.map(t=>`${t}:not(:disabled)`).join(", ")}function U(e,t){e.addEventListener("focusin",()=>{t.style.opacity="1"}),e.addEventListener("focusout",()=>{t.style.opacity="0"}),document.addEventListener("click",()=>{t.style.opacity=document.activeElement===e?"1":"0"},!0)}async function I(e){let t=e.parentElement,n;for(;t;){try{n=t.shadowRoot||t.attachShadow({mode:"open"});const i=document.createElement("style");i.textContent=":host{position:relative;display:block;box-sizing:border-box;margin:0;padding:0;}";const o=document.createElement("slot");n.append(i,o)}catch{}if(n)return{ancestor:t,shadowRoot:n};t=t.parentElement}throw new Error("Failed to attach HME DOM.")}function x(e,t,n){let i=0;const o=()=>{cancelAnimationFrame(i),i=requestAnimationFrame(n)},r=new ResizeObserver(o);r.observe(e),r.observe(t);const c=new FinalizationRegistry(d=>{d.unobserve(e),d.unobserve(t),d.disconnect()}),a=new WeakRef(e);c.register(a,r)}function y(e,t){return(t!=null&&t.toFixed?e.toFixed(t.toFixed):e)+"px"}function m(e){const t=window.open(l.authorization_url_placeholder,"PrivacyPortalSSO","top=0");t?e(t):g(new f({message:"Please allow popups in order to use Hide-my-Email."}))}function J(e){const t=e.split(".",3)[1];return{...JSON.parse(atob(t))}}function Y(e){const t=e instanceof Uint8Array?e:new Uint8Array(e);return btoa(String.fromCharCode(...t))}function P(e){return X(Y(e))}function X(e){return e.replace(/\//g,"_").replace(/\+/g,"-").replace(/=+$/,"")}function N(e){return typeof e=="string"||e instanceof String}const F=["Authentication failed.",K].join(" ");function Q(e=16){const t=new Uint8Array(e);return crypto.getRandomValues(t),Array.from(t,n=>n.toString(16).padStart(2,"0")).join("")}function ee(e=32){const t=new Uint8Array(e);return crypto.getRandomValues(t),P(t)}async function te(e){const n=new TextEncoder().encode(e),i=await crypto.subtle.digest("SHA-256",n);return P(i)}async function ne(e,t){try{if(!e)throw new f({message:"code missing."});if(!l.client_id)throw new f({message:"OAuth client_id not configured"});const n=new URLSearchParams;return n.set("client_id",l.client_id),n.set("grant_type","authorization_code"),n.set("code",e),n.set("redirect_uri",l.redirect_uri),n.set("code_verifier",t),(await fetch(_,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:n})).json()}catch(n){throw n instanceof f?n:new f({message:F})}}async function ie({id_token:e,access_token:t}){if(!e||!t||!N(e)||!N(t))throw new f({message:F});return{id_token:e,access_token:t}}async function oe(e,t){try{const n=Q(),i=ee(),o=await te(i);e.location.href=l.createAuthorizationURL(n,o,t);let r,c;return await Promise.race([new Promise((a,d)=>{window.addEventListener("message",async L=>{if(L.origin!==l.authorization_origin)return{};clearTimeout(r),clearInterval(c);const{code:Ue,state:Ie}=L.data;if(n!==Ie)return d(new f({message:"Authentication failed."}));const{id_token:V,access_token:Z}=await ne(Ue,i).catch(d);await ie({id_token:V,access_token:Z}).catch(d),a({id_token:V,access_token:Z})},!1)}),new Promise(a=>{c=setInterval(()=>{e.closed&&(clearTimeout(r),clearInterval(c),a(void 0))},1e3)}),new Promise((a,d)=>{r=setTimeout(()=>{clearInterval(c),d(new f({message:"Authorization timed out."}))},18e4)})])}catch(n){g(n)}}async function M(e,t){const n=await oe(e,t);if(n!=null&&n.id_token){const{email:i,name:o}=J(n.id_token);return{email:i,name:o}}return{}}function re(e,t,n){const i=document.createElementNS("http://www.w3.org/2000/svg","svg");e!=null&&e.width&&i.setAttribute("width",e.width),e!=null&&e.height&&i.setAttribute("height",e.height),e!=null&&e.viewBox&&i.setAttribute("viewBox",e.viewBox),n!=null&&n.fillRule&&(i.style.fillRule=n.fillRule),n!=null&&n.clipRule&&(i.style.clipRule=n.clipRule),n!=null&&n.strokeLinejoin&&(i.style.strokeLinejoin=n.strokeLinejoin),n!=null&&n.strokeMiterlimit&&(i.style.strokeMiterlimit=n.strokeMiterlimit);for(const o of t)i.appendChild(o);return i}function D(e,t){const n=document.createElementNS("http://www.w3.org/2000/svg","path");return n.setAttribute("d",e),t!=null&&t.fill&&(n.style.fill=t.fill),n}function ae(){return re({width:"100%",height:"100%",viewBox:"0 0 150 150"},[D("M150,22.5C150,10.082 139.918,0 127.5,0L22.5,0C10.082,0 0,10.082 0,22.5L0,127.5C0,139.918 10.082,150 22.5,150L127.5,150C139.918,150 150,139.918 150,127.5L150,22.5Z",{fill:"#333"}),D("M112.979,124.728C120.977,123.051 126.993,115.921 126.993,107.39C126.993,102.517 125.03,98.101 121.857,94.897L126.44,90.314L126.45,90.324C130.816,94.695 133.518,100.73 133.518,107.39C133.518,119.687 124.308,129.85 112.414,131.351L114.651,133.588L110.239,138L100.561,128.322L110.239,118.644L114.651,123.056L112.979,124.728ZM106.337,83.425L104.103,81.191L108.515,76.779L118.192,86.457L108.515,96.135L104.103,91.723L105.781,90.045C97.768,91.71 91.737,98.848 91.737,107.39C91.737,112.261 93.698,116.675 96.87,119.879L96.873,119.882L92.391,124.363L92.293,124.469L92.29,124.465C87.918,120.093 85.212,114.055 85.212,107.39C85.212,95.085 94.434,84.916 106.337,83.425ZM78.539,116.812L30.658,116.812C22.834,116.812 16.482,110.46 16.482,102.636L16.482,36.484C16.482,28.661 22.834,22.309 30.658,22.309L117.06,22.309C124.884,22.309 131.236,28.661 131.236,36.484L131.236,82.065C128.437,79.412 125.165,77.253 121.561,75.728L121.561,36.128C121.561,36.128 86.535,62.757 76.366,70.488C74.751,71.716 72.513,71.711 70.903,70.475C60.81,62.728 26.158,36.128 26.158,36.128L26.158,107.005L76.571,107.005C76.719,110.44 77.402,113.736 78.539,116.812ZM109.365,86.454L109.365,86.461L109.369,86.457L109.365,86.454ZM73.627,59.885L111.21,31.984L36.508,31.984L73.627,59.885Z",{fill:"#fff"})],{fillRule:"evenodd",clipRule:"evenodd",strokeLinejoin:"round",strokeMiterlimit:"2"})}const k="firefox",ce="android",se="safari",de="chrome",le="chromium",ue="criOS";function C(e,t){const n=e.userAgent.toLowerCase();for(const i of t)if(n.indexOf(i)===-1)return!1;return!0}function fe(e,t){const n=e.userAgent.toLowerCase();for(const i of t)if(n.indexOf(i)>-1)return!0;return!1}function he(e){return C(e,[k,ce])}function _e(e){return C(e,[k])}function ge(e){return C(e,[se])&&!fe(e,[de,le,ue])}let B;const j="*****@pportal.io",w="Hide my Email",h="input[type=text]",q=["input[type=email]",`${h}[id*="email" i]`,`${h}[name*="email" i]`,`${h}[name*="username" i]`,`${h}[name*="login" i]`,`${h}[placeholder*="email" i]`,`${h}[placeholder*="e-mail" i]`],v=q.map(e=>`${e}:not([data-pp])`).join(", "),ye=S(v),me=S(v,{shadow:!0});async function T(e,t){e.value="",B=e;const{email:n}=await M(t);E(B,n)}async function O(e){const t=`pp-${window.crypto.randomUUID().substring(0,8)}`;if(he(navigator)||ge(navigator)){const{ancestor:n,shadowRoot:i}=await I(e),o=document.createElement("li");o.innerText=w,o.style.padding="3px",o.style.cursor="pointer";const r=document.createElement("ul");r.id=t,r.style.display="block",r.style.position="absolute",r.style.maxHeight="300px",r.style.overflowY="auto",r.style.listStyle="none",r.style.backgroundColor="Canvas",r.style.color="CanvasText",r.style.colorScheme="light dark",r.style.boxShadow="0 2px 2px #999",r.style.fontSize="small",r.style.zIndex="1000",r.style.opacity="0",r.style.padding=r.style.margin="0px",r.appendChild(o);const c=document.createElement("style");c.textContent="li:hover{background-color:ButtonFace;color:ButtonText;}",i.append(c,r),x(e,n,()=>{const a=e.getBoundingClientRect(),d=n.getBoundingClientRect();r.style.width=y(a.width),r.style.top=y(a.bottom-d.top,{toFixed:2}),r.style.left=y(a.left-d.left,{toFixed:2})}),e.setAttribute("data-pp",""),o.onmousedown=a=>{a.preventDefault()},o.onclick=()=>{m(a=>{r.style.opacity="0",T(e,a).catch(g)})},U(e,r)}else{const n=document.createElement("option");n.setAttribute("id","new-privacy-addr"),n.setAttribute("value",j),n.textContent=w;let i;if(e.hasAttribute("list")){const o=e.getAttribute("list");o&&(i=document.getElementById(o))}if(i||(i=document.createElement("datalist"),i.setAttribute("id",t),e.setAttribute("list",t),e.insertAdjacentElement("afterend",i)),i.appendChild(n),e.setAttribute("data-pp",""),_e(navigator)){const{ancestor:o,shadowRoot:r}=await I(e),c=document.createElement("button");c.title=w,c.ariaLabel=w,Object.assign(c.style,{position:"absolute",border:"none",borderRadius:"15px",cursor:"pointer",padding:"0",margin:"0",zIndex:"1000",pointerEvents:"auto",right:"8px",opacity:"0"}),c.appendChild(ae()),r.append(c),x(e,o,()=>{const a=e.getBoundingClientRect(),d=o.getBoundingClientRect(),L=parseFloat(window.getComputedStyle(e).getPropertyValue("padding-right"))||0;c.style.height=c.style.width=y(a.height*.7,{toFixed:2}),c.style.top=y(a.top-d.top+a.height*.15,{toFixed:2}),c.style.right=y(d.right-a.right+Math.max(L,a.height*.15),{toFixed:2})}),c.onmousedown=a=>{a.preventDefault()},c.onclick=()=>{m(a=>{c.disabled=!0,T(e,a).catch(g).finally(()=>{c.disabled=!1})})},U(e,c)}}e.addEventListener("input",()=>{(e.value==="@"||e.value===j)&&m(n=>{T(e,n).catch(g)})})}function z(){for(const e of Array.from(document.querySelectorAll(v)))p(e)&&O(e).catch(console.error)}function we(e){e!=null&&e.addEventListener&&e.addEventListener("focusin",ye(t=>{O(t).catch(console.error)}),!0)}function H(){document.addEventListener("click",me(e=>{O(e).catch(console.error)}),!0)}function $(){[...Array.from(document.querySelectorAll("iframe"))].map(e=>{var t;try{const n=(e==null?void 0:e.contentDocument)||((t=e==null?void 0:e.contentWindow)==null?void 0:t.document);n!=null&&n.addEventListener&&we(n)}catch{}})}function Le(){window.addEventListener("load",()=>{z(),H(),$()}),document.readyState==="complete"&&(z(),H(),$())}const be=R(["form button[data-pp-action=subscribe-anonymously]"]),Ae=R(q),Se=R([`${h}[id*="name" i]`,`${h}[name*="name" i]`]),Ee=S(be,{closest:!0});async function pe(e,t){try{const n=e.closest("form");if(!n)return;const i=[...Array.from(n.querySelectorAll(Ae))].find(p);if(!i)return;const o=[...Array.from(n.querySelectorAll(Se))].find(p);let r;o!=null&&o.required&&(r={name_scope_required:!0});const{email:c,name:a}=await M(t,r);E(i,c)&&(!o||!a||E(o,a))&&n.dispatchEvent(new Event("submit",{cancelable:!0}))&&n.submit()}catch(n){g(n)}}function Re(e){e!=null&&e.addEventListener&&e.addEventListener("click",Ee(t=>{m(n=>{pe(t,n)})}),!0)}function Ce(){window.addEventListener("load",()=>{Re(document)})}function ve(e){return typeof e=="object"&&e!==null}const Te={hide_my_email:!0,subscribe_anonymously:!0,on_error:"alert"};class Oe{static run(t){const{client_id:n,hide_my_email:i,subscribe_anonymously:o,on_error:r}={...Te,...t};l.client_id=n,l.onError=r,i&&Le(),o&&(ve(o)&&(l.name_scope_required=o.set_name_field),Ce())}}return Oe});