@privacyportal.org/privacy-kit
Version:
Lightweight and FOSS browser library bringing Privacy Portal features to your website users
6 lines (5 loc) • 12.8 kB
JavaScript
/*
MIT License - Copyright (c) 2025 Privacy Portal.
See full license at https://github.com/privacyportal/privacy-kit/LICENSE.
*/
;var K=Object.defineProperty;var W=(e,t,n)=>t in e?K(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var g=(e,t,n)=>W(e,typeof t!="symbol"?t+"":t,n);const G={VITE_AUTHORIZATION_URL:"https://app.privacyportal.org/oauth/authorize",VITE_TOKEN_URL:"https://api.privacyportal.org/oauth/token"},{VITE_AUTHORIZATION_URL:T,VITE_TOKEN_URL:J}=G,m={SCOPE:["openid","email"],RESPONSE_TYPE:"code",RESPONSE_MODE:"web_message"},Y="Please try again later.";class l extends Error{constructor({message:t}){super(t)}}function y(e){if(e instanceof l)switch(d.onError){case"ignore":break;case"alert":{alert(e.message);break}default:X(d.onError)&&d.onError.error(e.message)}}function X(e){return e!=null&&typeof e=="object"&&typeof e.error=="function"}class Q{constructor(){g(this,"_client_id");g(this,"_name_scope_required");g(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(T).origin}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[...m.SCOPE,...this.getNameScopeRequired(t)?["name"]:[]].join(" ")}createAuthorizationURL(t,n,i){if(!this.client_id)throw new l({message:"OAuth client_id not configured."});const r=new URLSearchParams;r.set("client_id",this.client_id),r.set("scope",this.getScope(i)),r.set("response_type",m.RESPONSE_TYPE),r.set("response_mode",m.RESPONSE_MODE),r.set("nonce",crypto.randomUUID().substring(4,18)),r.set("redirect_uri",this.redirect_uri),r.set("state",t),r.set("code_challenge",n),r.set("code_challenge_method","S256");const o=new URL(T);return o.search=r.toString(),o.toString()}}const d=new Q;function A(e,t){return n=>i=>{var o;const r=t!=null&&t.shadow?(o=i==null?void 0:i.composedPath())==null?void 0:o[0]:i==null?void 0:i.target;if(r)return r[t!=null&&t.closest?"closest":"matches"](e)&&n(r)}}function L(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 b(e){return e.offsetWidth!==0||e.offsetHeight!==0}function E(e){return e.map(t=>`${t}:not(:disabled)`).join(", ")}function O(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 r=document.createElement("slot");n.append(i,r)}catch{}if(n)return{ancestor:t,shadowRoot:n};t=t.parentElement}throw new Error("Failed to attach HME DOM.")}function U(e,t,n){let i=0;const r=()=>{cancelAnimationFrame(i),i=requestAnimationFrame(n)},o=new ResizeObserver(r);o.observe(e),o.observe(t);const a=new FinalizationRegistry(s=>{s.unobserve(e),s.unobserve(t),s.disconnect()}),c=new WeakRef(e);a.register(c,o)}function h(e,t){return(t!=null&&t.toFixed?e.toFixed(t.toFixed):e)+"px"}function ee(e){const t=e.split(".",3)[1];return{...JSON.parse(atob(t))}}function te(e){const t=e instanceof Uint8Array?e:new Uint8Array(e);return btoa(String.fromCharCode(...t))}function B(e){return ne(te(e))}function ne(e){return e.replace(/\//g,"_").replace(/\+/g,"-").replace(/=+$/,"")}function x(e){return typeof e=="string"||e instanceof String}const j=["Authentication failed.",Y].join(" ");function ie(e=16){const t=new Uint8Array(e);return crypto.getRandomValues(t),Array.from(t,n=>n.toString(16).padStart(2,"0")).join("")}function re(e=32){const t=new Uint8Array(e);return crypto.getRandomValues(t),B(t)}async function oe(e){const n=new TextEncoder().encode(e),i=await crypto.subtle.digest("SHA-256",n);return B(i)}async function ae(e,t){try{if(!e)throw new l({message:"code missing."});if(!d.client_id)throw new l({message:"OAuth client_id not configured"});const n=new URLSearchParams;return n.set("client_id",d.client_id),n.set("grant_type","authorization_code"),n.set("code",e),n.set("redirect_uri",d.redirect_uri),n.set("code_verifier",t),(await fetch(J,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:n})).json()}catch(n){throw n instanceof l?n:new l({message:j})}}async function ce({id_token:e,access_token:t}){if(!e||!t||!x(e)||!x(t))throw new l({message:j});return{id_token:e,access_token:t}}async function se(e){try{const t=ie(),n=re(),i=await oe(n),r=d.createAuthorizationURL(t,i,e),o=window.open(r,"PrivacyPortalSSO","top=0");if(!o)throw new l({message:"Popup blocked. Please allow popups for this site."});let a,c;return await Promise.race([new Promise((s,f)=>{window.addEventListener("message",async v=>{if(v.origin!==d.authorization_origin)return{};clearTimeout(a),clearInterval(c);const{code:$,state:Z}=v.data;if(t!==Z)return f(new l({message:"Authentication failed."}));const{id_token:C,access_token:R}=await ae($,n).catch(f);await ce({id_token:C,access_token:R}).catch(f),s({id_token:C,access_token:R})},!1)}),new Promise(s=>{c=setInterval(()=>{o.closed&&(clearTimeout(a),clearInterval(c),s(void 0))},1e3)}),new Promise((s,f)=>{a=setTimeout(()=>{clearInterval(c),f(new l({message:"Authorization timed out."}))},18e4)})])}catch(t){y(t)}}async function q(e){const t=await se(e);if(t!=null&&t.id_token){const{email:n,name:i}=ee(t.id_token);return{email:n,name:i}}return{}}function de(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 r of t)i.appendChild(r);return i}function P(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 le(){return de({width:"100%",height:"100%",viewBox:"0 0 150 150"},[P("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"}),P("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 z="firefox",ue="android";function H(e,t){const n=e.userAgent.toLowerCase();for(const i of t)if(n.indexOf(i)===-1)return!1;return!0}function fe(e){return H(e,[z,ue])}function he(e){return H(e,[z])}let N;const F="*****@pportal.io",_="Hide my Email",u="input[type=text]",V=["input[type=email]",`${u}[id*="email" i]`,`${u}[name*="email" i]`,`${u}[name*="username" i]`,`${u}[name*="login" i]`,`${u}[placeholder*="email" i]`,`${u}[placeholder*="e-mail" i]`],S=V.map(e=>`${e}:not([data-pp])`).join(", "),ye=A(S),ge=A(S,{shadow:!0});async function w(e){e.value="",N=e;const{email:t}=await q();L(N,t)}async function p(e){const t=`pp-${window.crypto.randomUUID().substring(0,8)}`;if(fe(navigator)){const{ancestor:n,shadowRoot:i}=await I(e),r=document.createElement("li");r.innerText=_,r.style.padding="3px",r.style.cursor="pointer";const o=document.createElement("ul");o.id=t,o.style.display="block",o.style.position="absolute",o.style.maxHeight="300px",o.style.overflowY="auto",o.style.listStyle="none",o.style.backgroundColor="Canvas",o.style.color="CanvasText",o.style.colorScheme="light dark",o.style.boxShadow="0 2px 2px #999",o.style.fontSize="small",o.style.zIndex="1000",o.style.opacity="0",o.style.padding=o.style.margin="0px",o.appendChild(r);const a=document.createElement("style");a.textContent="li:hover{background-color:ButtonFace;color:ButtonText;}",i.append(a,o),U(e,n,()=>{const c=e.getBoundingClientRect(),s=n.getBoundingClientRect();o.style.width=h(c.width),o.style.top=h(c.bottom-s.top,{toFixed:2}),o.style.left=h(c.left-s.left,{toFixed:2})}),e.setAttribute("data-pp",""),r.onmousedown=c=>{c.preventDefault()},r.onclick=async()=>{o.style.opacity="0",await w(e).catch(y)},O(e,o)}else{const n=document.createElement("option");n.setAttribute("id","new-privacy-addr"),n.setAttribute("value",F),n.textContent=_;let i;if(e.hasAttribute("list")){const r=e.getAttribute("list");r&&(i=document.getElementById(r))}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",""),he(navigator)){const{ancestor:r,shadowRoot:o}=await I(e),a=document.createElement("button");a.title=_,a.ariaLabel=_,Object.assign(a.style,{position:"absolute",border:"none",borderRadius:"15px",cursor:"pointer",padding:"0",margin:"0",zIndex:"1000",pointerEvents:"auto",right:"8px",opacity:"0"}),a.appendChild(le()),o.append(a),U(e,r,()=>{const c=e.getBoundingClientRect(),s=r.getBoundingClientRect(),f=parseFloat(window.getComputedStyle(e).getPropertyValue("padding-right"))||0;a.style.height=a.style.width=h(c.height*.7,{toFixed:2}),a.style.top=h(c.top-s.top+c.height*.15,{toFixed:2}),a.style.right=h(s.right-c.right+Math.max(f,c.height*.15),{toFixed:2})}),a.onmousedown=c=>{c.preventDefault()},a.onclick=async()=>{try{a.disabled=!0,await w(e)}catch(c){y(c)}finally{a.disabled=!1}},O(e,a)}}e.addEventListener("input",async()=>{try{(e.value==="@"||e.value===F)&&await w(e)}catch(n){y(n)}})}function k(){for(const e of Array.from(document.querySelectorAll(S)))b(e)&&p(e).catch(console.error)}function _e(e){e!=null&&e.addEventListener&&e.addEventListener("focusin",ye(t=>{p(t).catch(console.error)}),!0)}function D(){document.addEventListener("click",ge(e=>{p(e).catch(console.error)}),!0)}function M(){[...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&&_e(n)}catch{}})}function me(){window.addEventListener("load",()=>{k(),D(),M()}),document.readyState==="complete"&&(k(),D(),M())}const we=["form button[data-pp-action=subscribe-anonymously]"],Le=E(we),be=E(V),Ae=E([`${u}[id*="name" i]`,`${u}[name*="name" i]`]),Ee=A(Le,{closest:!0});async function Se(e){try{const t=e.closest("form");if(!t)return;const n=[...Array.from(t.querySelectorAll(be))].find(b);if(!n)return;const i=[...Array.from(t.querySelectorAll(Ae))].find(b);let r;i!=null&&i.required&&(r={name_scope_required:!0});const{email:o,name:a}=await q(r);L(n,o)&&(!i||!a||L(i,a))&&t.dispatchEvent(new Event("submit",{cancelable:!0}))&&t.submit()}catch(t){y(t)}}function pe(e){e!=null&&e.addEventListener&&e.addEventListener("click",Ee(t=>{Se(t)}),!0)}function ve(){window.addEventListener("load",()=>{pe(document)})}function Ce(e){return typeof e=="object"&&e!==null}const Re={hide_my_email:!0,subscribe_anonymously:!0,on_error:"alert"};class Te{static run(t){const{client_id:n,hide_my_email:i,subscribe_anonymously:r,on_error:o}={...Re,...t};d.client_id=n,d.onError=o,i&&me(),r&&(Ce(r)&&(d.name_scope_required=r.set_name_field),ve())}}module.exports=Te;