@sesamy/sesamy-js 1.113.2 → 1.114.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- var capsulePlugin=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function t(e){let t=e.length%4,n=(t?e+`=`.repeat(4-t):e).replace(/-/g,`+`).replace(/_/g,`/`),r=atob(n),i=new Uint8Array(r.length);for(let e=0;e<r.length;e++)i[e]=r.charCodeAt(e);return i}function n(e){let t=``;for(let n=0;n<e.length;n++)t+=String.fromCharCode(e[n]);return btoa(t).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=/g,``)}var r=new Uint8Array([1,0,1]),i=`dca-keys`,a=`keypair`,o=`default`,s=class e{fetchFn;unlockFn;periodKeyCache;clientBound;rsaKeySize;keyDbName;keyPairPromise=null;accessCheck;paywallFn;constructor(e={}){this.fetchFn=e.fetch??globalThis.fetch.bind(globalThis),this.unlockFn=e.unlockFn,this.periodKeyCache=e.periodKeyCache,this.clientBound=e.clientBound??!1,this.rsaKeySize=e.rsaKeySize??2048,this.keyDbName=e.keyDbName??i,this.accessCheck=e.accessCheck,this.paywallFn=e.paywallFn}parsePage(e){let t=e??document,n=t.querySelector(`script.dca-data`);if(!n)throw Error(`DCA: <script class="dca-data"> not found`);let r=JSON.parse(n.textContent??``),i=t.querySelector(`template.dca-sealed-content`),a={};if(i&&i instanceof HTMLTemplateElement){let e=i.content.querySelectorAll(`[data-dca-content-name]`);for(let t of Array.from(e)){let e=t.getAttribute(`data-dca-content-name`);e&&(a[e]=t.textContent?.trim()??``)}}return{dcaData:r,sealedContent:a}}parseJsonResponse(e){let{sealedContent:t,...n}=e;return{dcaData:n,sealedContent:t}}static hasDcaContent(e){return(e??document).querySelector(`script.dca-data`)!==null}async unlock(e,t,n){let r=e.dcaData.issuerData[t];if(!r)throw Error(`DCA: issuer "${t}" not found in issuerData`);let i={resourceJWT:e.dcaData.resourceJWT,contentEncryptionKeys:r.contentEncryptionKeys,...n};if(this.clientBound&&(i.clientPublicKey=await this.getPublicKey()),this.unlockFn)return this.unlockFn(r.unlockUrl,i);let a=await this.fetchFn(r.unlockUrl,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(i)});if(!a.ok)throw Error(`DCA unlock failed: ${a.status} ${a.statusText}`);return a.json()}async unlockWithShareToken(e,t,n,r){return this.unlock(e,t,{...r,shareToken:n})}static getShareTokenFromUrl(e=`share`){if(typeof window>`u`||typeof URL>`u`)return null;try{return new URL(window.location.href).searchParams.get(e)}catch{return null}}async decrypt(e,n,r,i){let a=e.dcaData.contentSealData[n];if(!a)throw Error(`DCA: contentSealData not found for "${n}"`);let o=e.sealedContent[n];if(!o)throw Error(`DCA: sealed content not found for "${n}"`);let s=i??r.contentEncryptionKeys.find(e=>(e.contentName??`default`)===n);if(!s)throw Error(`DCA: no key provided for "${n}"`);let c=r.transport===`client-bound`,l=s.periodKeys?Object.fromEntries(s.periodKeys.map(e=>[e.bucket,e.key])):void 0,u;if(s.contentKey){if(u=c?await this.rsaUnwrapKey(s.contentKey):t(s.contentKey),l&&this.periodKeyCache){let e=c?await this.unwrapPeriodKeyMap(l):l,t=s.keyName??n;await this.cachePeriodKeys(t,e)}}else if(l){let t=c?await this.unwrapPeriodKeyMap(l):l;if(u=await this.unwrapWithPeriodKeys(e.dcaData.sealedContentKeys[n]??[],t),this.periodKeyCache){let e=s.keyName??n;await this.cachePeriodKeys(e,t)}}else{let t=Object.values(e.dcaData.issuerData).flatMap(e=>e.contentEncryptionKeys).find(e=>(e.contentName??`default`)===n)?.keyName??n,r=await this.getCachedPeriodKeys(t,e.dcaData.sealedContentKeys[n]??[]);if(r)u=await this.unwrapWithPeriodKeys(e.dcaData.sealedContentKeys[n]??[],r);else throw Error(`DCA: no contentKey or periodKeys available for "${n}"`)}let d=t(o),f=t(a.nonce),p=new TextEncoder().encode(a.aad),m=await crypto.subtle.importKey(`raw`,u,{name:`AES-GCM`},!1,[`decrypt`]),h=await crypto.subtle.decrypt({name:`AES-GCM`,iv:f,additionalData:p,tagLength:128},m,d);return new TextDecoder().decode(h)}async decryptAll(e,t){let n={},r=new Map(t.contentEncryptionKeys.map(e=>[e.contentName??`default`,e]));for(let[i,a]of r)n[i]=await this.decrypt(e,i,t,a);return n}async processPage(t={}){let n=t.root??document;if(this.accessCheck){let t=e.getPublisherContentId(n);if(!t)return console.warn(`DCA: accessCheck is configured but no publisher-content-id attribute was found on the page. Treating as denied.`),this.paywallFn&&this.paywallFn(t,n),{};let r=await this.accessCheck(t);if(!r||!r.hasAccess)return this.paywallFn&&this.paywallFn(t,n),{}}let r=this.parsePage(n),i=t.issuerName??Object.keys(r.dcaData.issuerData)[0];if(!i)throw Error(`DCA: no issuers found in issuerData`);let a=t.shareToken===void 0?e.getShareTokenFromUrl(t.shareTokenParam):t.shareToken,o=a?await this.unlockWithShareToken(r,i,a,t.additionalBody):await this.unlock(r,i,t.additionalBody);return this.decryptAll(r,o)}renderToPage(e,t){let n=t??document,r=new Set;for(let[t,i]of Object.entries(e)){let e=n.querySelector(`[data-dca-content-name="${CSS.escape(t)}"]`);e&&(e.innerHTML=i,r.add(t))}return r}static getPublisherContentId(e){let t=e??document;if(t instanceof Element){let e=t.closest(`[publisher-content-id]`);if(e)return e.getAttribute(`publisher-content-id`)}let n=t.querySelector(`script.dca-data`);if(n){let e=n.closest(`[publisher-content-id]`);if(e)return e.getAttribute(`publisher-content-id`)}return null}observe(e,t){let n=e??document.body,r=new MutationObserver(e=>{for(let n of e)for(let e of Array.from(n.addedNodes)){if(!(e instanceof HTMLElement))continue;let n=[];if(e.matches(`script.dca-data`)){let t=e.parentElement??e;n.includes(t)||n.push(t)}let r=e.querySelectorAll(`script.dca-data`);for(let t of Array.from(r)){let r=t.parentElement??e;n.includes(r)||n.push(r)}for(let e of n)this.processPage({...t,root:e}).then(t=>{Object.keys(t).length>0&&this.renderToPage(t,e)}).catch(e=>console.error(`DCA auto-process failed:`,e))}});return r.observe(n,{childList:!0,subtree:!0}),r}async unwrapWithPeriodKeys(e,n){for(let r of e){let e=n[r.t];if(!e)continue;let i=t(e),a=t(r.nonce),o=t(r.key),s=await crypto.subtle.importKey(`raw`,i,{name:`AES-GCM`},!1,[`decrypt`]);try{let e=await crypto.subtle.decrypt({name:`AES-GCM`,iv:a,tagLength:128},s,o);return new Uint8Array(e)}catch{continue}}throw Error(`DCA: could not unwrap contentKey — no matching periodKey`)}async cachePeriodKeys(e,t){if(this.periodKeyCache)for(let[n,r]of Object.entries(t))await this.periodKeyCache.set(`dca:pk:${e}:${n}`,r)}async getCachedPeriodKeys(e,t){if(!this.periodKeyCache)return null;let n={},r=!1;for(let i of t){let t=await this.periodKeyCache.get(`dca:pk:${e}:${i.t}`);t&&(n[i.t]=t,r=!0)}return r?n:null}async getPublicKey(){let e=await this.ensureKeyPair(),t=await crypto.subtle.exportKey(`spki`,e.publicKey);return n(new Uint8Array(t))}async hasKeyPair(){try{let e=await this.openKeyDb();return await this.idbGet(e,o)!==void 0}catch{return!1}}ensureKeyPair(){return this.keyPairPromise||=this.loadOrCreateKeyPair(),this.keyPairPromise}async loadOrCreateKeyPair(){try{let e=await this.openKeyDb(),t=await this.idbGet(e,o);if(t?.publicKey&&t?.privateKey)return{publicKey:t.publicKey,privateKey:t.privateKey}}catch{}let e=await crypto.subtle.generateKey({name:`RSA-OAEP`,modulusLength:this.rsaKeySize,publicExponent:r,hash:`SHA-256`},!0,[`encrypt`,`decrypt`]),t=await crypto.subtle.exportKey(`jwk`,e.privateKey),n=await crypto.subtle.importKey(`jwk`,t,{name:`RSA-OAEP`,hash:`SHA-256`},!1,[`decrypt`]),i={publicKey:e.publicKey,privateKey:n};try{let t=await this.openKeyDb();await this.idbPut(t,o,{id:o,publicKey:e.publicKey,privateKey:n,createdAt:Date.now(),keySize:this.rsaKeySize})}catch{}return i}async rsaUnwrapKey(e){let n=await this.ensureKeyPair(),r=t(e),i=await crypto.subtle.decrypt({name:`RSA-OAEP`},n.privateKey,r);return new Uint8Array(i)}async unwrapPeriodKeyMap(e){let t={};for(let[r,i]of Object.entries(e))t[r]=n(await this.rsaUnwrapKey(i));return t}keyDbPromise=null;openKeyDb(){return this.keyDbPromise||=new Promise((e,t)=>{let n=indexedDB.open(this.keyDbName,1);n.onupgradeneeded=()=>{let e=n.result;e.objectStoreNames.contains(a)||e.createObjectStore(a,{keyPath:`id`})},n.onsuccess=()=>e(n.result),n.onerror=()=>t(n.error)}),this.keyDbPromise}idbGet(e,t){return new Promise((n,r)=>{let i=e.transaction(a,`readonly`).objectStore(a).get(t);i.onsuccess=()=>n(i.result),i.onerror=()=>r(i.error)})}idbPut(e,t,n){return new Promise((t,r)=>{let i=e.transaction(a,`readwrite`).objectStore(a).put(n);i.onsuccess=()=>t(),i.onerror=()=>r(i.error)})}};function c(e){return s.hasDcaContent(e)}var l=function(e){return e.AUTH_INITIALIZED=`sesamyJsAuthInitialized`,e.READY=`sesamyJsReady`,e.AUTHENTICATED=`sesamyJsAuthenticated`,e.LOGOUT=`sesamyJsLogout`,e.CLEAR_CACHE=`sesamyJsClearCache`,e.USER_ATTRIBUTE_CHANGED=`sesamyUserAttributeChanged`,e.PURCHASE=`sesamyJsPurchase`,e.CONSENT_CHANGED=`sesamyJsConsentChanged`,e}({}),u=3600*1e3;function d(){let e=null;return{init(t,n){let r=async(e,t)=>{let r=await n.getToken(!1),i=new Headers(t?.headers);return r&&i.set(`Authorization`,`Bearer ${r}`),globalThis.fetch(e,{...t,headers:i,credentials:t?.credentials??`same-origin`})};window.addEventListener(l.LOGOUT,()=>{try{let e=[];for(let t=0;t<sessionStorage.length;t++){let n=sessionStorage.key(t);n?.startsWith(`dca:unlock:`)&&e.push(n)}e.forEach(e=>sessionStorage.removeItem(e))}catch{}}),e=new s({fetch:r,clientBound:t.clientBound??!1,rsaKeySize:t.rsaKeySize??2048,unlockFn:async(e,t)=>{let n=JSON.stringify(t),i=`dca:unlock:${e}:${n}`;try{let e=sessionStorage.getItem(i);if(e){let{ts:t,data:n}=JSON.parse(e);if(Date.now()-t<u)return n;sessionStorage.removeItem(i)}}catch{}let a=await r(e,{method:`POST`,headers:{"Content-Type":`application/json`},body:n});if(!a.ok)throw Error(`DCA unlock failed: ${a.status} ${a.statusText}`);let o=await a.json();try{sessionStorage.setItem(i,JSON.stringify({ts:Date.now(),data:o}))}catch{}return o}})},getDcaClient(){return e},async processPage(){if(!e||!c())return null;let t=await e.processPage();return e.renderToPage(t),t}}}return e.createCapsulePlugin=d,e})({});
1
+ var capsulePlugin=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function t(e){let t=e.length%4,n=(t?e+`=`.repeat(4-t):e).replace(/-/g,`+`).replace(/_/g,`/`),r=atob(n),i=new Uint8Array(r.length);for(let e=0;e<r.length;e++)i[e]=r.charCodeAt(e);return i}function n(e){let t=``;for(let n=0;n<e.length;n++)t+=String.fromCharCode(e[n]);return btoa(t).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=/g,``)}var r=new Uint8Array([1,0,1]),i=`dca-keys`,a=`keypair`,o=`default`,s=`dca-wrap-keys`,c=`wrap-keys`;function l(){let e=null;function t(){return e||=new Promise((e,t)=>{let n=indexedDB.open(s,1);n.onupgradeneeded=()=>{let e=n.result;e.objectStoreNames.contains(c)||e.createObjectStore(c)},n.onsuccess=()=>e(n.result),n.onerror=()=>t(n.error)}),e}return{async get(e){if(typeof indexedDB>`u`)return null;try{let n=await t();return await new Promise(t=>{let r=n.transaction(c,`readonly`).objectStore(c).get(e);r.onsuccess=()=>t(r.result??null),r.onerror=()=>t(null)})}catch{return null}},async set(e,n){if(!(typeof indexedDB>`u`))try{let r=await t();await new Promise((t,i)=>{let a=r.transaction(c,`readwrite`);a.objectStore(c).put(n,e),a.oncomplete=()=>t(),a.onerror=()=>i(a.error)})}catch{}}}}var u=class e{fetchFn;unlockFn;wrapKeyCache;clientBound;rsaKeySize;keyDbName;keyPairPromise=null;accessCheck;paywallFn;constructor(e={}){this.fetchFn=e.fetch??globalThis.fetch.bind(globalThis),this.unlockFn=e.unlockFn,this.wrapKeyCache=e.wrapKeyCache===!1?void 0:e.wrapKeyCache??l(),this.clientBound=e.clientBound??!1,this.rsaKeySize=e.rsaKeySize??2048,this.keyDbName=e.keyDbName??i,this.accessCheck=e.accessCheck,this.paywallFn=e.paywallFn}parsePage(e){let t=(e??document).querySelector(`script.dca-manifest`);if(!t)throw Error(`DCA: <script class="dca-manifest"> not found`);return{manifest:JSON.parse(t.textContent??``)}}parseJsonResponse(e){return{manifest:e}}static hasDcaContent(e){return(e??document).querySelector(`script.dca-manifest`)!==null}async unlock(e,t,n){let r=e.manifest.issuers[t];if(!r)throw Error(`DCA: issuer "${t}" not found in manifest.issuers`);let i={resourceJWT:e.manifest.resourceJWT,keys:r.keys,...n};if(this.clientBound&&(i.clientPublicKey=await this.getPublicKey()),this.unlockFn)return this.unlockFn(r.unlockUrl,i);let a=await this.fetchFn(r.unlockUrl,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(i)});if(!a.ok)throw Error(`DCA unlock failed: ${a.status} ${a.statusText}`);return a.json()}async unlockWithShareToken(e,t,n,r){return this.unlock(e,t,{...r,shareToken:n})}static getShareTokenFromUrl(e=`share`){if(typeof window>`u`||typeof URL>`u`)return null;try{return new URL(window.location.href).searchParams.get(e)}catch{return null}}async decrypt(e,n,r,i){let a=e.manifest.content[n];if(!a)throw Error(`DCA: content entry not found for "${n}"`);let o=i??r.keys.find(e=>(e.contentName??`default`)===n);if(!o)throw Error(`DCA: no key provided for "${n}"`);let s=r.transport===`client-bound`,c=o.wrapKeys?Object.fromEntries(o.wrapKeys.map(e=>[e.kid,e.key])):void 0,l;if(o.contentKey)l=s?await this.rsaUnwrapKey(o.contentKey):t(o.contentKey);else if(c){let t=s?await this.unwrapWrapKeyMap(c):c;if(l=await this.unwrapContentKey(a.wrappedContentKey,t),this.wrapKeyCache){let r=this.resolveScope(e,n,o.scope)??n;await this.cacheWrapKeys(r,t)}}else{let t=this.resolveScope(e,n,o.scope)??n,r=await this.getCachedWrapKeys(t,a.wrappedContentKey);if(r)l=await this.unwrapContentKey(a.wrappedContentKey,r);else throw Error(`DCA: no contentKey or wrapKeys available for "${n}"`)}return this.decryptContentBody(a,l)}async decryptContentBody(e,n){let r=t(e.ciphertext),i=t(e.iv),a=new TextEncoder().encode(e.aad),o=await crypto.subtle.importKey(`raw`,n,{name:`AES-GCM`},!1,[`decrypt`]),s=await crypto.subtle.decrypt({name:`AES-GCM`,iv:i,additionalData:a,tagLength:128},o,r);return new TextDecoder().decode(s)}async tryDecryptFromCache(e,t){let n=e.manifest.content[t];if(!n||n.wrappedContentKey.length===0)return null;let r=this.resolveScope(e,t)??t,i=await this.getCachedWrapKeys(r,n.wrappedContentKey);if(!i)return null;try{let e=await this.unwrapContentKey(n.wrappedContentKey,i);return await this.decryptContentBody(n,e)}catch{return null}}async decryptAll(e,t){let n={},r=new Map(t.keys.map(e=>[e.contentName??`default`,e]));for(let[i,a]of r)n[i]=await this.decrypt(e,i,t,a);return n}async processPage(t={}){let n=t.root??document;if(this.accessCheck){let t=e.getPublisherContentId(n);if(!t)return console.warn(`DCA: accessCheck is configured but no publisher-content-id attribute was found on the page. Treating as denied.`),this.paywallFn&&this.paywallFn(t,n),{};let r=await this.accessCheck(t);if(!r||!r.hasAccess)return this.paywallFn&&this.paywallFn(t,n),{}}let r=this.parsePage(n),i=t.issuerName??Object.keys(r.manifest.issuers)[0];if(!i)throw Error(`DCA: no issuers found in manifest.issuers`);let a={},o=[];for(let e of Object.keys(r.manifest.content)){let t=await this.tryDecryptFromCache(r,e);t===null?o.push(e):a[e]=t}if(o.length===0)return a;let s=t.shareToken===void 0?e.getShareTokenFromUrl(t.shareTokenParam):t.shareToken,c=s?await this.unlockWithShareToken(r,i,s,t.additionalBody):await this.unlock(r,i,t.additionalBody);for(let e of o)a[e]=await this.decrypt(r,e,c);return a}renderToPage(e,t){let n=t??document,r=new Set;for(let[t,i]of Object.entries(e)){let e=n.querySelector(`[data-dca-content-name="${CSS.escape(t)}"]`);e&&(e.innerHTML=i,r.add(t))}return r}static getPublisherContentId(e){let t=e??document;if(t instanceof Element){let e=t.closest(`[publisher-content-id]`);if(e)return e.getAttribute(`publisher-content-id`)}let n=t.querySelector(`script.dca-manifest`);if(n){let e=n.closest(`[publisher-content-id]`);if(e)return e.getAttribute(`publisher-content-id`)}return null}observe(e,t){let n=e??document.body,r=new MutationObserver(e=>{for(let n of e)for(let e of Array.from(n.addedNodes)){if(!(e instanceof HTMLElement))continue;let n=[];if(e.matches(`script.dca-manifest`)){let t=e.parentElement??e;n.includes(t)||n.push(t)}let r=e.querySelectorAll(`script.dca-manifest`);for(let t of Array.from(r)){let r=t.parentElement??e;n.includes(r)||n.push(r)}for(let e of n)this.processPage({...t,root:e}).then(t=>{Object.keys(t).length>0&&this.renderToPage(t,e)}).catch(e=>console.error(`DCA auto-process failed:`,e))}});return r.observe(n,{childList:!0,subtree:!0}),r}resolveScope(e,t,n){if(n)return n;for(let n of Object.values(e.manifest.issuers)){let e=n.keys.find(e=>(e.contentName??`default`)===t);if(e)return e.scope}}async unwrapContentKey(e,n){for(let r of e){let e=n[r.kid];if(!e)continue;let i=t(e),a=t(r.iv),o=t(r.ciphertext),s=await crypto.subtle.importKey(`raw`,i,{name:`AES-GCM`},!1,[`decrypt`]);try{let e=await crypto.subtle.decrypt({name:`AES-GCM`,iv:a,tagLength:128},s,o);return new Uint8Array(e)}catch{continue}}throw Error(`DCA: could not unwrap contentKey — no matching wrapKey`)}async cacheWrapKeys(e,t){if(this.wrapKeyCache)for(let[n,r]of Object.entries(t))await this.wrapKeyCache.set(`dca:wk:${e}:${n}`,r)}async getCachedWrapKeys(e,t){if(!this.wrapKeyCache)return null;let n={},r=!1;for(let i of t){let t=await this.wrapKeyCache.get(`dca:wk:${e}:${i.kid}`);t&&(n[i.kid]=t,r=!0)}return r?n:null}async getPublicKey(){let e=await this.ensureKeyPair(),t=await crypto.subtle.exportKey(`spki`,e.publicKey);return n(new Uint8Array(t))}async hasKeyPair(){try{let e=await this.openKeyDb();return await this.idbGet(e,o)!==void 0}catch{return!1}}ensureKeyPair(){return this.keyPairPromise||=this.loadOrCreateKeyPair(),this.keyPairPromise}async loadOrCreateKeyPair(){try{let e=await this.openKeyDb(),t=await this.idbGet(e,o);if(t?.publicKey&&t?.privateKey)return{publicKey:t.publicKey,privateKey:t.privateKey}}catch{}let e=await crypto.subtle.generateKey({name:`RSA-OAEP`,modulusLength:this.rsaKeySize,publicExponent:r,hash:`SHA-256`},!0,[`encrypt`,`decrypt`]),t=await crypto.subtle.exportKey(`jwk`,e.privateKey),n=await crypto.subtle.importKey(`jwk`,t,{name:`RSA-OAEP`,hash:`SHA-256`},!1,[`decrypt`]),i={publicKey:e.publicKey,privateKey:n};try{let t=await this.openKeyDb();await this.idbPut(t,o,{id:o,publicKey:e.publicKey,privateKey:n,createdAt:Date.now(),keySize:this.rsaKeySize})}catch{}return i}async rsaUnwrapKey(e){let n=await this.ensureKeyPair(),r=t(e),i=await crypto.subtle.decrypt({name:`RSA-OAEP`},n.privateKey,r);return new Uint8Array(i)}async unwrapWrapKeyMap(e){let t={};for(let[r,i]of Object.entries(e))t[r]=n(await this.rsaUnwrapKey(i));return t}keyDbPromise=null;openKeyDb(){return this.keyDbPromise||=new Promise((e,t)=>{let n=indexedDB.open(this.keyDbName,1);n.onupgradeneeded=()=>{let e=n.result;e.objectStoreNames.contains(a)||e.createObjectStore(a,{keyPath:`id`})},n.onsuccess=()=>e(n.result),n.onerror=()=>t(n.error)}),this.keyDbPromise}idbGet(e,t){return new Promise((n,r)=>{let i=e.transaction(a,`readonly`).objectStore(a).get(t);i.onsuccess=()=>n(i.result),i.onerror=()=>r(i.error)})}idbPut(e,t,n){return new Promise((t,r)=>{let i=e.transaction(a,`readwrite`).objectStore(a).put(n);i.onsuccess=()=>t(),i.onerror=()=>r(i.error)})}};function d(e){return u.hasDcaContent(e)}var f=function(e){return e.AUTH_INITIALIZED=`sesamyJsAuthInitialized`,e.READY=`sesamyJsReady`,e.AUTHENTICATED=`sesamyJsAuthenticated`,e.LOGOUT=`sesamyJsLogout`,e.CLEAR_CACHE=`sesamyJsClearCache`,e.USER_ATTRIBUTE_CHANGED=`sesamyUserAttributeChanged`,e.PURCHASE=`sesamyJsPurchase`,e.CONSENT_CHANGED=`sesamyJsConsentChanged`,e}({}),p=3600*1e3,m=`dca:`,h=`${m}unlock:`,g=`${m}wk:`,_=!1;function v(){try{let e=[];for(let t=0;t<sessionStorage.length;t++){let n=sessionStorage.key(t);n?.startsWith(m)&&e.push(n)}e.forEach(e=>sessionStorage.removeItem(e))}catch{}}var y=class{async get(e){try{return sessionStorage.getItem(`${g}${e}`)}catch{return null}}async set(e,t){try{sessionStorage.setItem(`${g}${e}`,t)}catch{}}};function b(){let e=null;return{init(t,n){let r=async(e,t)=>{let r=await n.getToken(!1),i=new Headers(t?.headers);return r&&i.set(`Authorization`,`Bearer ${r}`),globalThis.fetch(e,{...t,headers:i,credentials:t?.credentials??`same-origin`})};_||=(window.addEventListener(f.LOGOUT,v),!0),e=new u({fetch:r,clientBound:t.clientBound??!1,rsaKeySize:t.rsaKeySize??2048,unlockFn:async(e,t)=>{let n=JSON.stringify(t),i=`${h}${e}:${n}`;try{let e=sessionStorage.getItem(i);if(e){let{ts:t,data:n}=JSON.parse(e);if(Date.now()-t<p)return n;sessionStorage.removeItem(i)}}catch{}let a=await r(e,{method:`POST`,headers:{"Content-Type":`application/json`},body:n});if(!a.ok)throw Error(`DCA unlock failed: ${a.status} ${a.statusText}`);let o=await a.json();try{sessionStorage.setItem(i,JSON.stringify({ts:Date.now(),data:o}))}catch{}return o},wrapKeyCache:new y})},getDcaClient(){return e},async processPage(){if(!e||!d())return null;let t=await e.processPage();return e.renderToPage(t),t}}}return e.createCapsulePlugin=b,e})({});
@@ -1,4 +1,4 @@
1
- //#region ../../node_modules/.pnpm/@sesamy+capsule@0.11.0/node_modules/@sesamy/capsule/dist/index.mjs
1
+ //#region ../../node_modules/.pnpm/@sesamy+capsule@0.12.0/node_modules/@sesamy/capsule/dist/index.mjs
2
2
  function e(e) {
3
3
  let t = e.length % 4, n = (t ? e + "=".repeat(4 - t) : e).replace(/-/g, "+").replace(/_/g, "/"), r = atob(n), i = new Uint8Array(r.length);
4
4
  for (let e = 0; e < r.length; e++) i[e] = r.charCodeAt(e);
@@ -13,10 +13,46 @@ var n = new Uint8Array([
13
13
  1,
14
14
  0,
15
15
  1
16
- ]), r = "dca-keys", i = "keypair", a = "default", o = class o {
16
+ ]), r = "dca-keys", i = "keypair", a = "default", o = "dca-wrap-keys", s = "wrap-keys";
17
+ function c() {
18
+ let e = null;
19
+ function t() {
20
+ return e ||= new Promise((e, t) => {
21
+ let n = indexedDB.open(o, 1);
22
+ n.onupgradeneeded = () => {
23
+ let e = n.result;
24
+ e.objectStoreNames.contains(s) || e.createObjectStore(s);
25
+ }, n.onsuccess = () => e(n.result), n.onerror = () => t(n.error);
26
+ }), e;
27
+ }
28
+ return {
29
+ async get(e) {
30
+ if (typeof indexedDB > "u") return null;
31
+ try {
32
+ let n = await t();
33
+ return await new Promise((t) => {
34
+ let r = n.transaction(s, "readonly").objectStore(s).get(e);
35
+ r.onsuccess = () => t(r.result ?? null), r.onerror = () => t(null);
36
+ });
37
+ } catch {
38
+ return null;
39
+ }
40
+ },
41
+ async set(e, n) {
42
+ if (!(typeof indexedDB > "u")) try {
43
+ let r = await t();
44
+ await new Promise((t, i) => {
45
+ let a = r.transaction(s, "readwrite");
46
+ a.objectStore(s).put(n, e), a.oncomplete = () => t(), a.onerror = () => i(a.error);
47
+ });
48
+ } catch {}
49
+ }
50
+ };
51
+ }
52
+ var l = class o {
17
53
  fetchFn;
18
54
  unlockFn;
19
- periodKeyCache;
55
+ wrapKeyCache;
20
56
  clientBound;
21
57
  rsaKeySize;
22
58
  keyDbName;
@@ -24,40 +60,25 @@ var n = new Uint8Array([
24
60
  accessCheck;
25
61
  paywallFn;
26
62
  constructor(e = {}) {
27
- this.fetchFn = e.fetch ?? globalThis.fetch.bind(globalThis), this.unlockFn = e.unlockFn, this.periodKeyCache = e.periodKeyCache, this.clientBound = e.clientBound ?? !1, this.rsaKeySize = e.rsaKeySize ?? 2048, this.keyDbName = e.keyDbName ?? r, this.accessCheck = e.accessCheck, this.paywallFn = e.paywallFn;
63
+ this.fetchFn = e.fetch ?? globalThis.fetch.bind(globalThis), this.unlockFn = e.unlockFn, this.wrapKeyCache = e.wrapKeyCache === !1 ? void 0 : e.wrapKeyCache ?? c(), this.clientBound = e.clientBound ?? !1, this.rsaKeySize = e.rsaKeySize ?? 2048, this.keyDbName = e.keyDbName ?? r, this.accessCheck = e.accessCheck, this.paywallFn = e.paywallFn;
28
64
  }
29
65
  parsePage(e) {
30
- let t = e ?? document, n = t.querySelector("script.dca-data");
31
- if (!n) throw Error("DCA: <script class=\"dca-data\"> not found");
32
- let r = JSON.parse(n.textContent ?? ""), i = t.querySelector("template.dca-sealed-content"), a = {};
33
- if (i && i instanceof HTMLTemplateElement) {
34
- let e = i.content.querySelectorAll("[data-dca-content-name]");
35
- for (let t of Array.from(e)) {
36
- let e = t.getAttribute("data-dca-content-name");
37
- e && (a[e] = t.textContent?.trim() ?? "");
38
- }
39
- }
40
- return {
41
- dcaData: r,
42
- sealedContent: a
43
- };
66
+ let t = (e ?? document).querySelector("script.dca-manifest");
67
+ if (!t) throw Error("DCA: <script class=\"dca-manifest\"> not found");
68
+ return { manifest: JSON.parse(t.textContent ?? "") };
44
69
  }
45
70
  parseJsonResponse(e) {
46
- let { sealedContent: t, ...n } = e;
47
- return {
48
- dcaData: n,
49
- sealedContent: t
50
- };
71
+ return { manifest: e };
51
72
  }
52
73
  static hasDcaContent(e) {
53
- return (e ?? document).querySelector("script.dca-data") !== null;
74
+ return (e ?? document).querySelector("script.dca-manifest") !== null;
54
75
  }
55
76
  async unlock(e, t, n) {
56
- let r = e.dcaData.issuerData[t];
57
- if (!r) throw Error(`DCA: issuer "${t}" not found in issuerData`);
77
+ let r = e.manifest.issuers[t];
78
+ if (!r) throw Error(`DCA: issuer "${t}" not found in manifest.issuers`);
58
79
  let i = {
59
- resourceJWT: e.dcaData.resourceJWT,
60
- contentEncryptionKeys: r.contentEncryptionKeys,
80
+ resourceJWT: e.manifest.resourceJWT,
81
+ keys: r.keys,
61
82
  ...n
62
83
  };
63
84
  if (this.clientBound && (i.clientPublicKey = await this.getPublicKey()), this.unlockFn) return this.unlockFn(r.unlockUrl, i);
@@ -84,39 +105,48 @@ var n = new Uint8Array([
84
105
  }
85
106
  }
86
107
  async decrypt(t, n, r, i) {
87
- let a = t.dcaData.contentSealData[n];
88
- if (!a) throw Error(`DCA: contentSealData not found for "${n}"`);
89
- let o = t.sealedContent[n];
90
- if (!o) throw Error(`DCA: sealed content not found for "${n}"`);
91
- let s = i ?? r.contentEncryptionKeys.find((e) => (e.contentName ?? "default") === n);
92
- if (!s) throw Error(`DCA: no key provided for "${n}"`);
93
- let c = r.transport === "client-bound", l = s.periodKeys ? Object.fromEntries(s.periodKeys.map((e) => [e.bucket, e.key])) : void 0, u;
94
- if (s.contentKey) {
95
- if (u = c ? await this.rsaUnwrapKey(s.contentKey) : e(s.contentKey), l && this.periodKeyCache) {
96
- let e = c ? await this.unwrapPeriodKeyMap(l) : l, t = s.keyName ?? n;
97
- await this.cachePeriodKeys(t, e);
98
- }
99
- } else if (l) {
100
- let e = c ? await this.unwrapPeriodKeyMap(l) : l;
101
- if (u = await this.unwrapWithPeriodKeys(t.dcaData.sealedContentKeys[n] ?? [], e), this.periodKeyCache) {
102
- let t = s.keyName ?? n;
103
- await this.cachePeriodKeys(t, e);
108
+ let a = t.manifest.content[n];
109
+ if (!a) throw Error(`DCA: content entry not found for "${n}"`);
110
+ let o = i ?? r.keys.find((e) => (e.contentName ?? "default") === n);
111
+ if (!o) throw Error(`DCA: no key provided for "${n}"`);
112
+ let s = r.transport === "client-bound", c = o.wrapKeys ? Object.fromEntries(o.wrapKeys.map((e) => [e.kid, e.key])) : void 0, l;
113
+ if (o.contentKey) l = s ? await this.rsaUnwrapKey(o.contentKey) : e(o.contentKey);
114
+ else if (c) {
115
+ let e = s ? await this.unwrapWrapKeyMap(c) : c;
116
+ if (l = await this.unwrapContentKey(a.wrappedContentKey, e), this.wrapKeyCache) {
117
+ let r = this.resolveScope(t, n, o.scope) ?? n;
118
+ await this.cacheWrapKeys(r, e);
104
119
  }
105
120
  } else {
106
- let e = Object.values(t.dcaData.issuerData).flatMap((e) => e.contentEncryptionKeys).find((e) => (e.contentName ?? "default") === n)?.keyName ?? n, r = await this.getCachedPeriodKeys(e, t.dcaData.sealedContentKeys[n] ?? []);
107
- if (r) u = await this.unwrapWithPeriodKeys(t.dcaData.sealedContentKeys[n] ?? [], r);
108
- else throw Error(`DCA: no contentKey or periodKeys available for "${n}"`);
121
+ let e = this.resolveScope(t, n, o.scope) ?? n, r = await this.getCachedWrapKeys(e, a.wrappedContentKey);
122
+ if (r) l = await this.unwrapContentKey(a.wrappedContentKey, r);
123
+ else throw Error(`DCA: no contentKey or wrapKeys available for "${n}"`);
109
124
  }
110
- let d = e(o), f = e(a.nonce), p = new TextEncoder().encode(a.aad), m = await crypto.subtle.importKey("raw", u, { name: "AES-GCM" }, !1, ["decrypt"]), h = await crypto.subtle.decrypt({
125
+ return this.decryptContentBody(a, l);
126
+ }
127
+ async decryptContentBody(t, n) {
128
+ let r = e(t.ciphertext), i = e(t.iv), a = new TextEncoder().encode(t.aad), o = await crypto.subtle.importKey("raw", n, { name: "AES-GCM" }, !1, ["decrypt"]), s = await crypto.subtle.decrypt({
111
129
  name: "AES-GCM",
112
- iv: f,
113
- additionalData: p,
130
+ iv: i,
131
+ additionalData: a,
114
132
  tagLength: 128
115
- }, m, d);
116
- return new TextDecoder().decode(h);
133
+ }, o, r);
134
+ return new TextDecoder().decode(s);
135
+ }
136
+ async tryDecryptFromCache(e, t) {
137
+ let n = e.manifest.content[t];
138
+ if (!n || n.wrappedContentKey.length === 0) return null;
139
+ let r = this.resolveScope(e, t) ?? t, i = await this.getCachedWrapKeys(r, n.wrappedContentKey);
140
+ if (!i) return null;
141
+ try {
142
+ let e = await this.unwrapContentKey(n.wrappedContentKey, i);
143
+ return await this.decryptContentBody(n, e);
144
+ } catch {
145
+ return null;
146
+ }
117
147
  }
118
148
  async decryptAll(e, t) {
119
- let n = {}, r = new Map(t.contentEncryptionKeys.map((e) => [e.contentName ?? "default", e]));
149
+ let n = {}, r = new Map(t.keys.map((e) => [e.contentName ?? "default", e]));
120
150
  for (let [i, a] of r) n[i] = await this.decrypt(e, i, t, a);
121
151
  return n;
122
152
  }
@@ -128,10 +158,17 @@ var n = new Uint8Array([
128
158
  let n = await this.accessCheck(e);
129
159
  if (!n || !n.hasAccess) return this.paywallFn && this.paywallFn(e, t), {};
130
160
  }
131
- let n = this.parsePage(t), r = e.issuerName ?? Object.keys(n.dcaData.issuerData)[0];
132
- if (!r) throw Error("DCA: no issuers found in issuerData");
133
- let i = e.shareToken === void 0 ? o.getShareTokenFromUrl(e.shareTokenParam) : e.shareToken, a = i ? await this.unlockWithShareToken(n, r, i, e.additionalBody) : await this.unlock(n, r, e.additionalBody);
134
- return this.decryptAll(n, a);
161
+ let n = this.parsePage(t), r = e.issuerName ?? Object.keys(n.manifest.issuers)[0];
162
+ if (!r) throw Error("DCA: no issuers found in manifest.issuers");
163
+ let i = {}, a = [];
164
+ for (let e of Object.keys(n.manifest.content)) {
165
+ let t = await this.tryDecryptFromCache(n, e);
166
+ t === null ? a.push(e) : i[e] = t;
167
+ }
168
+ if (a.length === 0) return i;
169
+ let s = e.shareToken === void 0 ? o.getShareTokenFromUrl(e.shareTokenParam) : e.shareToken, c = s ? await this.unlockWithShareToken(n, r, s, e.additionalBody) : await this.unlock(n, r, e.additionalBody);
170
+ for (let e of a) i[e] = await this.decrypt(n, e, c);
171
+ return i;
135
172
  }
136
173
  renderToPage(e, t) {
137
174
  let n = t ?? document, r = /* @__PURE__ */ new Set();
@@ -147,7 +184,7 @@ var n = new Uint8Array([
147
184
  let e = t.closest("[publisher-content-id]");
148
185
  if (e) return e.getAttribute("publisher-content-id");
149
186
  }
150
- let n = t.querySelector("script.dca-data");
187
+ let n = t.querySelector("script.dca-manifest");
151
188
  if (n) {
152
189
  let e = n.closest("[publisher-content-id]");
153
190
  if (e) return e.getAttribute("publisher-content-id");
@@ -159,11 +196,11 @@ var n = new Uint8Array([
159
196
  for (let n of e) for (let e of Array.from(n.addedNodes)) {
160
197
  if (!(e instanceof HTMLElement)) continue;
161
198
  let n = [];
162
- if (e.matches("script.dca-data")) {
199
+ if (e.matches("script.dca-manifest")) {
163
200
  let t = e.parentElement ?? e;
164
201
  n.includes(t) || n.push(t);
165
202
  }
166
- let r = e.querySelectorAll("script.dca-data");
203
+ let r = e.querySelectorAll("script.dca-manifest");
167
204
  for (let t of Array.from(r)) {
168
205
  let r = t.parentElement ?? e;
169
206
  n.includes(r) || n.push(r);
@@ -181,11 +218,18 @@ var n = new Uint8Array([
181
218
  subtree: !0
182
219
  }), r;
183
220
  }
184
- async unwrapWithPeriodKeys(t, n) {
221
+ resolveScope(e, t, n) {
222
+ if (n) return n;
223
+ for (let n of Object.values(e.manifest.issuers)) {
224
+ let e = n.keys.find((e) => (e.contentName ?? "default") === t);
225
+ if (e) return e.scope;
226
+ }
227
+ }
228
+ async unwrapContentKey(t, n) {
185
229
  for (let r of t) {
186
- let t = n[r.t];
230
+ let t = n[r.kid];
187
231
  if (!t) continue;
188
- let i = e(t), a = e(r.nonce), o = e(r.key), s = await crypto.subtle.importKey("raw", i, { name: "AES-GCM" }, !1, ["decrypt"]);
232
+ let i = e(t), a = e(r.iv), o = e(r.ciphertext), s = await crypto.subtle.importKey("raw", i, { name: "AES-GCM" }, !1, ["decrypt"]);
189
233
  try {
190
234
  let e = await crypto.subtle.decrypt({
191
235
  name: "AES-GCM",
@@ -197,17 +241,17 @@ var n = new Uint8Array([
197
241
  continue;
198
242
  }
199
243
  }
200
- throw Error("DCA: could not unwrap contentKey — no matching periodKey");
244
+ throw Error("DCA: could not unwrap contentKey — no matching wrapKey");
201
245
  }
202
- async cachePeriodKeys(e, t) {
203
- if (this.periodKeyCache) for (let [n, r] of Object.entries(t)) await this.periodKeyCache.set(`dca:pk:${e}:${n}`, r);
246
+ async cacheWrapKeys(e, t) {
247
+ if (this.wrapKeyCache) for (let [n, r] of Object.entries(t)) await this.wrapKeyCache.set(`dca:wk:${e}:${n}`, r);
204
248
  }
205
- async getCachedPeriodKeys(e, t) {
206
- if (!this.periodKeyCache) return null;
249
+ async getCachedWrapKeys(e, t) {
250
+ if (!this.wrapKeyCache) return null;
207
251
  let n = {}, r = !1;
208
252
  for (let i of t) {
209
- let t = await this.periodKeyCache.get(`dca:pk:${e}:${i.t}`);
210
- t && (n[i.t] = t, r = !0);
253
+ let t = await this.wrapKeyCache.get(`dca:wk:${e}:${i.kid}`);
254
+ t && (n[i.kid] = t, r = !0);
211
255
  }
212
256
  return r ? n : null;
213
257
  }
@@ -262,7 +306,7 @@ var n = new Uint8Array([
262
306
  let n = await this.ensureKeyPair(), r = e(t), i = await crypto.subtle.decrypt({ name: "RSA-OAEP" }, n.privateKey, r);
263
307
  return new Uint8Array(i);
264
308
  }
265
- async unwrapPeriodKeyMap(e) {
309
+ async unwrapWrapKeyMap(e) {
266
310
  let n = {};
267
311
  for (let [r, i] of Object.entries(e)) n[r] = t(await this.rsaUnwrapKey(i));
268
312
  return n;
@@ -290,15 +334,39 @@ var n = new Uint8Array([
290
334
  });
291
335
  }
292
336
  };
293
- function s(e) {
294
- return o.hasDcaContent(e);
337
+ function u(e) {
338
+ return l.hasDcaContent(e);
295
339
  }
296
340
  //#endregion
297
341
  //#region src/types/Events.ts
298
- var c = /* @__PURE__ */ function(e) {
342
+ var d = /* @__PURE__ */ function(e) {
299
343
  return e.AUTH_INITIALIZED = "sesamyJsAuthInitialized", e.READY = "sesamyJsReady", e.AUTHENTICATED = "sesamyJsAuthenticated", e.LOGOUT = "sesamyJsLogout", e.CLEAR_CACHE = "sesamyJsClearCache", e.USER_ATTRIBUTE_CHANGED = "sesamyUserAttributeChanged", e.PURCHASE = "sesamyJsPurchase", e.CONSENT_CHANGED = "sesamyJsConsentChanged", e;
300
- }({}), l = 3600 * 1e3;
301
- function u() {
344
+ }({}), f = 3600 * 1e3, p = "dca:", m = `${p}unlock:`, h = `${p}wk:`, g = !1;
345
+ function _() {
346
+ try {
347
+ let e = [];
348
+ for (let t = 0; t < sessionStorage.length; t++) {
349
+ let n = sessionStorage.key(t);
350
+ n?.startsWith(p) && e.push(n);
351
+ }
352
+ e.forEach((e) => sessionStorage.removeItem(e));
353
+ } catch {}
354
+ }
355
+ var v = class {
356
+ async get(e) {
357
+ try {
358
+ return sessionStorage.getItem(`${h}${e}`);
359
+ } catch {
360
+ return null;
361
+ }
362
+ }
363
+ async set(e, t) {
364
+ try {
365
+ sessionStorage.setItem(`${h}${e}`, t);
366
+ } catch {}
367
+ }
368
+ };
369
+ function y() {
302
370
  let e = null;
303
371
  return {
304
372
  init(t, n) {
@@ -310,26 +378,17 @@ function u() {
310
378
  credentials: t?.credentials ?? "same-origin"
311
379
  });
312
380
  };
313
- window.addEventListener(c.LOGOUT, () => {
314
- try {
315
- let e = [];
316
- for (let t = 0; t < sessionStorage.length; t++) {
317
- let n = sessionStorage.key(t);
318
- n?.startsWith("dca:unlock:") && e.push(n);
319
- }
320
- e.forEach((e) => sessionStorage.removeItem(e));
321
- } catch {}
322
- }), e = new o({
381
+ g ||= (window.addEventListener(d.LOGOUT, _), !0), e = new l({
323
382
  fetch: r,
324
383
  clientBound: t.clientBound ?? !1,
325
384
  rsaKeySize: t.rsaKeySize ?? 2048,
326
385
  unlockFn: async (e, t) => {
327
- let n = JSON.stringify(t), i = `dca:unlock:${e}:${n}`;
386
+ let n = JSON.stringify(t), i = `${m}${e}:${n}`;
328
387
  try {
329
388
  let e = sessionStorage.getItem(i);
330
389
  if (e) {
331
390
  let { ts: t, data: n } = JSON.parse(e);
332
- if (Date.now() - t < l) return n;
391
+ if (Date.now() - t < f) return n;
333
392
  sessionStorage.removeItem(i);
334
393
  }
335
394
  } catch {}
@@ -347,18 +406,19 @@ function u() {
347
406
  }));
348
407
  } catch {}
349
408
  return o;
350
- }
409
+ },
410
+ wrapKeyCache: new v()
351
411
  });
352
412
  },
353
413
  getDcaClient() {
354
414
  return e;
355
415
  },
356
416
  async processPage() {
357
- if (!e || !s()) return null;
417
+ if (!e || !u()) return null;
358
418
  let t = await e.processPage();
359
419
  return e.renderToPage(t), t;
360
420
  }
361
421
  };
362
422
  }
363
423
  //#endregion
364
- export { u as createCapsulePlugin };
424
+ export { y as createCapsulePlugin };