UNPKG

@s4e/jsentinel

Version:

Script integrity and clipboard tamper detection for browsers.

2 lines (1 loc) 5.31 kB
import{_ as e,R as t}from"./index-hwEiSUPx.js";import{emit as n}from"./events-ffa6G8za.js";import{urlMatchesPin as r}from"./manifest-Cuxzry5U.js";const i=new TextEncoder;function o(t){return e(this,void 0,void 0,function*(){const e=yield crypto.subtle.digest("SHA-256",i.encode(t));return"sha256-"+btoa(String.fromCharCode(...new Uint8Array(e)))})}function s(e,t=512){const n=e.slice(0,t),r=e.length>t;let i=0;for(let e=0;e<n.length;e++)i=i+n.charCodeAt(e)>>>0;return{snippet:n,truncated:r,bytes:(new TextEncoder).encode(e).length,snippetChecksum:`xx32-${i.toString(16)}`}}function a(i,a){return e(this,arguments,void 0,function*(e,i,a=[]){try{if(!e.src){const r=e.textContent||"",a=(e.type||"text/javascript").trim().toLowerCase();if(function(e){const t=(e||"").trim().toLowerCase();return"application/json"===t||"application/ld+json"===t}(a)){const t=s(r,512),i={key:"inline",src:null,inline:!0,expected:void 0,got:"",severity:"warn",reason:"unable-to-hash",meta:Object.assign({id:e.id||void 0,type:a},t)};return n({type:"alert",data:i}),!1}let c="",d=!1,l="";try{l=r.trim().replace(/\r\n/g,"\n").replace(/[ \t]+/g," ").replace(/[ \t]*\n[ \t]*/g,"\n"),c=yield o(l),d=!0}catch(e){d=!1}if(d){if(i.inlineHashes.has(c))return!0;const o=function(e,t){return"application/ld+json"===(e.type||"").toLowerCase()||!!/__NEXT_DATA__|self\.__next_|window\.__NUXT__/.test(t)||!!/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z/.test(t)}(e,r),d=s(l||r,512),u=o?"volatile-content":"not-in-manifest",p={key:"inline",src:null,inline:!0,expected:void 0,got:c,severity:o?"warn":"error",reason:u,description:t[u],meta:Object.assign({id:e.id||void 0,type:a},d)};return n({type:"alert",data:p}),!1}{const i=s(r,512),o={key:"inline",src:null,inline:!0,expected:void 0,got:"",severity:"warn",reason:"unable-to-hash",description:t["unable-to-hash"],meta:Object.assign({id:e.id||void 0,type:a},i)};return n({type:"alert",data:o}),!1}}const c=e.src;let d=!1,l="",u="";try{const e=new URL(c,window.location.href);d=e.origin===window.location.origin,l=e.pathname,u=e.host}catch(e){}if(d){const e=new URL(c,window.location.href),r=e.search.length>0,a=e.hash.length>0;let d=i.sameOriginHashes.get(l)||i.sameOriginHashes.get(decodeURIComponent(l))||i.sameOriginHashes.get(c);if(!r&&!a||i.sameOriginHashes.has(c)){if(!d){const e=(l.split("/").pop()||"").toLowerCase();if(e){const t=i.filenameIndex.get(e);t&&(d=t)}}}else d=void 0;let u,p="",f=!1,h="";try{h=yield(yield fetch(c,{cache:"no-store"})).text(),p=yield o(h)}catch(e){f=!0,u=String((null==e?void 0:e.message)||e)}if(f)return n({type:"alert",data:{key:l||c,src:c,inline:!1,expected:d,got:"",severity:"error",reason:"fetch-failed",description:t["fetch-failed"],meta:u?{error:u}:void 0}}),!1;if(d===p)return!0;{const e=s(h,512),r=d?"hash-mismatch":"not-in-manifest",i={key:l||c,src:c,inline:!1,expected:d,got:p,severity:"error",reason:r,description:t[r],meta:Object.assign({},e)};return n({type:"alert",data:i}),!1}}if(!/^https:\/\//i.test(c)){const e={key:c,src:c,inline:!1,expected:void 0,got:"",severity:"warn",reason:"insecure-protocol",description:t["insecure-protocol"],meta:{protocol:new URL(c,window.location.href).protocol}};return n({type:"alert",data:e}),!1}let p="",f=!1,h="";try{h=yield(yield fetch(c,{cache:"no-store"})).text(),p=yield o(h),f=!0}catch(e){}const y=i.versionedPins.has(c),m=r(c,i.dynamicPins),g=u&&a.includes(u);if(y||m||g)return!0;const v={key:c,src:c,inline:!1,expected:void 0,got:f?p:"",severity:"warn",reason:"unpinned-url",description:t["unpinned-url"],meta:f?Object.assign({},s(h,512)):void 0};return n({type:"alert",data:v}),!1}catch(e){return n({type:"error",data:{stage:"check",message:String((null==e?void 0:e.message)||e)}}),!1}})}function c(t){return e(this,void 0,void 0,function*(){return(yield fetch(t,{cache:"no-store"})).json()})}function d(t){return e(this,arguments,void 0,function*(e,t=[]){return Promise.all(Array.from(document.scripts).map(n=>a(n,e,t)))})}function l(e,t=[]){const n=new MutationObserver(n=>{n.forEach(n=>{if("childList"===n.type&&Array.from(n.addedNodes).filter(e=>"SCRIPT"===e.nodeName).forEach(n=>{a(n,e,t)}),"attributes"===n.type&&"src"===n.attributeName){const r=n.target;"SCRIPT"===r.nodeName&&r.src&&a(r,e,t)}if("characterData"===n.type||"childList"===n.type&&"SCRIPT"===n.target.nodeName){const r="SCRIPT"===n.target.nodeName?n.target:n.target.parentElement;r&&"SCRIPT"===r.nodeName&&r.getAttribute&&!r.getAttribute("src")&&a(r,e,t)}})});return n.observe(document.documentElement,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["src"],characterData:!0,characterDataOldValue:!0}),n}function u(t,n=[],r=3e4){const i=new Map;(()=>{e(this,void 0,void 0,function*(){const e=Array.from(document.scripts).filter(e=>e.textContent||e.innerHTML).slice(0,100);for(const t of e){const e=t.textContent||t.innerHTML||"";if(e){const n=yield o(e);i.set(t,n)}}})})();const s=setInterval(()=>e(this,void 0,void 0,function*(){const e=Array.from(document.scripts).filter(e=>e.textContent||e.innerHTML).slice(0,100);for(const r of e){const e=r.textContent||r.innerHTML||"";if(!e)continue;const s=yield o(e),c=i.get(r);void 0!==c?s!==c&&(i.set(r,s),a(r,t,n)):(i.set(r,s),a(r,t,n))}}),r);return()=>clearInterval(s)}export{c as fetchManifest,l as observeNewScripts,d as scanAllScripts,u as startPeriodicScriptMonitor_DEPRECATED};